From 417c3410111766f5d103b7720d7a1026a2488072 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Tue, 19 Jul 2016 08:15:52 -0700 Subject: [PATCH] include/crypto: Crypto abstraction header Adds crypto API interface for interaction between applications and crypto drivers. Encryption/Decryption APIs are defined here. Jira: ZEP-328 Change-Id: I1a534ae2a69c7e1c416fa78a2822c37040b225f6 Signed-off-by: Jithu Joseph --- include/crypto/cipher.h | 281 ++++++++++++++++++++++++++++++++ include/crypto/cipher_structs.h | 263 ++++++++++++++++++++++++++++++ 2 files changed, 544 insertions(+) create mode 100644 include/crypto/cipher.h create mode 100644 include/crypto/cipher_structs.h diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h new file mode 100644 index 00000000000..4dcd26b797c --- /dev/null +++ b/include/crypto/cipher.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Crypto Cipher APIs + * + * This file contains the Crypto Abstraction layer APIs. + * + * [Experimental] Users should note that the APIs can change + * as a part of ongoing development. + */ + +#ifndef __CRYPTO_CIPHER_H__ +#define __CRYPTO_CIPHER_H__ + +#include +#include +#include +#include +#include "cipher_structs.h" + +/* The API a crypto driver should implement */ +struct crypto_driver_api { + int (*query_hw_caps)(struct device *dev); + + /* Setup a crypto session */ + int (*begin_session)(struct device *dev, struct cipher_ctx *ctx, + enum cipher_algo algo, enum cipher_mode mode, + enum cipher_op op_type); + + /* Tear down an established session */ + int (*free_session)(struct device *dev, struct cipher_ctx *ctx); + + /* Register async crypto op completion callback with the driver*/ + int (*crypto_async_callback_set)(struct device *dev, + crypto_completion_cb cb); +}; + +/* Following are the calls an app could make to get cipher stuff done. + * The first two relates to crypto "session" setup / tear down. + * Further we have four mode specific (CTR, CCM, CBC ...) calls to perform the + * actual crypto operation in the context of a session. Also we have an + * API to provide the callback for async operations. + */ + + +/* + * @brief Query the crypto hardware capabilities + * + * This API is used by the app to query the capabilities supported by the + * crypto device. Based on this the app can specify a subset of the supported + * options to be honored for a session during cipher_begin_session() + * + * @param[in] dev Pointer to the device structure for the driver instance. + * + * @return bitmask of supported options. + */ +static inline int cipher_query_hwcaps(struct device *dev) +{ + struct crypto_driver_api *api; + int tmp; + + api = (struct crypto_driver_api *) dev->driver_api; + + tmp = api->query_hw_caps(dev); + + __ASSERT((tmp & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY)) != 0, + "Driver should support atleast one key type: RAW/Opaque"); + + __ASSERT((tmp & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)) != 0, + "Driver should support atleast one IO buf type: Inplace/separate"); + + __ASSERT((tmp & (CAP_SYNC_OPS | CAP_ASYNC_OPS)) != 0, + "Driver should support atleast one op-type: sync/async"); + return tmp; + +} + +/* + * @brief Setup a crypto session + * + * Initializes one time parameters, like the session key, algorithm and cipher + * mode which may remain constant for all operations in the session. The state + * may be cached in hardware and/or driver data state variables. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] ctx Pointer to the context structure. Various one time + * parameters like key, keylength etc are supplied via + * this field. Take a look at the ctx structure definition + * to know which fields are to be populated by the app + * before making this call. + * @param[in] algo The crypto algorithm to be used in this session. e.g AES + * @param[in] mode The cipher mode to be used in this session. e.g CBC, CTR + * @param[in] optype Whether we should encrypt or decrypt in this session + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_begin_session(struct device *dev, + struct cipher_ctx *ctx, + enum cipher_algo algo, + enum cipher_mode mode, + enum cipher_op optype) +{ + struct crypto_driver_api *api; + uint32_t flags; + + api = (struct crypto_driver_api *) dev->driver_api; + ctx->device = dev; + ctx->ops.cipher_mode = mode; + + flags = (ctx->flags & (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY)); + __ASSERT(flags != 0, "Keytype missing: RAW Key or OPAQUE handle"); + __ASSERT(flags != (CAP_OPAQUE_KEY_HNDL | CAP_RAW_KEY), + "conflicting options for keytype"); + + flags = (ctx->flags & (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS)); + __ASSERT(flags != 0, "IO buffer type missing"); + __ASSERT(flags != (CAP_INPLACE_OPS | CAP_SEPARATE_IO_BUFS), + "conflicting options for IO buffer type"); + + flags = (ctx->flags & (CAP_SYNC_OPS | CAP_ASYNC_OPS)); + __ASSERT(flags != 0, "sync/async type missing"); + __ASSERT(flags != (CAP_SYNC_OPS | CAP_ASYNC_OPS), + "conflicting options for sync/async"); + + return api->begin_session(dev, ctx, algo, mode, optype); +} + +/* + * @brief Cleanup a crypto session + * + * Clears the hardware and/or driver state of a previous session. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] ctx Pointer to the crypto context structure, of the session + * to be freed. + * + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_free_session(struct device *dev, + struct cipher_ctx *ctx) +{ + struct crypto_driver_api *api; + + api = (struct crypto_driver_api *) dev->driver_api; + + return api->free_session(dev, ctx); +} + +/* + * @brief Registers an async crypto op completion callback with the driver + * + * The application can register an async crypto op completion callback handler + * to be invoked by the driver, on completion of a prior request submitted via + * crypto_do_op(). Based on crypto device hardware semantics, this is likely to + * be invoked from an ISR context. + * + * @param[in] dev Pointer to the device structure for the driver instance. + * @param[in] cb Pointer to application callback to be called by the driver. + * + * @return 0 on success, -ENOTSUP if the driver does not support async op, + * negative errno code on fail. + */ +static inline int cipher_callback_set(struct device *dev, + crypto_completion_cb cb) +{ + struct crypto_driver_api *api; + + api = (struct crypto_driver_api *) dev->driver_api; + + if (api->crypto_async_callback_set) { + return api->crypto_async_callback_set(dev, cb); + } + + return -ENOTSUP; + +} + +/* + * @brief Perform Single block crypto op. This should not be overloaded to + * operate on multiple blocks for security reasons. + * + * @param[in] ctx Pointer to the crypto context of this op. + * @param[in/out] pkt Structure holding the Input/Output buffer pointers. + * + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_block_op(struct cipher_ctx *ctx, + struct cipher_pkt *pkt) +{ + __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_ECB, "ECB mode " + "session invoking a different mode handler"); + + pkt->ctx = ctx; + return ctx->ops.block_crypt_hndlr(ctx, pkt); +} + +/* + * @brief Perform Cipher Block Chaining (CBC) crypto operation. + * + * @param[in] ctx Pointer to the crypto context of this op. + * @param[in/out] pkt Structure holding the Input/Output buffer pointers. + * @param[in] iv Initialization Vector for the operation. Same + * iv value should not be reused across multiple + * operations (within a session context) for security. + * + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_cbc_op(struct cipher_ctx *ctx, + struct cipher_pkt *pkt, uint8_t *iv) +{ + __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CBC, "CBC mode " + "session invoking a different mode handler"); + + pkt->ctx = ctx; + return ctx->ops.cbc_crypt_hndlr(ctx, pkt, iv); +} + +/* + * @brief Perform Counter (CTR) mode crypto operation. + * + * @param[in] ctx Pointer to the crypto context of this op. + * @param[in/out] pkt Structure holding the Input/Output buffer pointers. + * @param[in] iv Initialization Vector for the operation. We use a + * split counter formed by appending iv and ctr. + * Consequently ivlen = keylen - ctrlen. 'ctrlen' is + * specified during session setup through the + * 'ctx.mode_params.ctr_params.ctr_len' parameter. IV + * should not be reused across multiple operations + * (within a session context) for security. The non-iv + * part of the split counter is transparent to the caller + * and is fully managed by the crypto provider. + * + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_ctr_op(struct cipher_ctx *ctx, + struct cipher_pkt *pkt, uint8_t *iv) +{ + __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CTR, "CTR mode " + "session invoking a different mode handler"); + + pkt->ctx = ctx; + return ctx->ops.ctr_crypt_hndlr(ctx, pkt, iv); +} + +/* + * @brief Perform Counter with CBC-MAC (CCM) mode crypto operation + * + * @param[in] ctx Pointer to the crypto context of this op. + * @param[in/out] pkt Structure holding the Input/Output, Assosciated Data + * and tag buffer pointers. + * @param[in] nonce Nonce for the operation. Same Nonce value should not + * be reused across multiple operations (within a + * session context) for security. + * + * @return 0 on success, negative errno code on fail. + */ +static inline int cipher_ccm_op(struct cipher_ctx *ctx, + struct cipher_aead_pkt *pkt, uint8_t *nonce) +{ + __ASSERT(ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CCM, "CCM mode " + "session invoking a different mode handler"); + + pkt->pkt->ctx = ctx; + return ctx->ops.ccm_crypt_hndlr(ctx, pkt, nonce); +} + +#endif /* __CRYPTO_CIPHER_H__ */ diff --git a/include/crypto/cipher_structs.h b/include/crypto/cipher_structs.h new file mode 100644 index 00000000000..4dc142026c1 --- /dev/null +++ b/include/crypto/cipher_structs.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2016 Intel Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Crypto Cipher structure definitions + * + * This file contains the Crypto Abstraction layer structures. + * + * [Experimental] Users should note that the Structures can change + * as a part of ongoing development. + */ + +#ifndef __CRYPTO_CIPHER_STRUCTS_H__ +#define __CRYPTO_CIPHER_STRUCTS_H__ + +#include +#include + +enum cipher_algo { + CRYPTO_CIPHER_ALGO_AES = 1, +}; + +enum cipher_op { + CRYPTO_CIPHER_OP_DECRYPT = 0, + CRYPTO_CIPHER_OP_ENCRYPT = 1, +}; + +/* Possible cipher mode options. More to be + * added as required. + */ + +enum cipher_mode { + CRYPTO_CIPHER_MODE_ECB = 1, + CRYPTO_CIPHER_MODE_CBC = 2, + CRYPTO_CIPHER_MODE_CTR = 3, + CRYPTO_CIPHER_MODE_CCM = 4, +}; + +/* Forward declarations */ +struct cipher_aead_pkt; +struct cipher_ctx; +struct cipher_pkt; + +typedef int (*block_op_t)(struct cipher_ctx *ctx, struct cipher_pkt *pkt); + +/* Function signatures for encryption/ decryption using standard cipher modes + * like CBC, CTR, CCM. + */ +typedef int (*cbc_op_t)(struct cipher_ctx *ctx, struct cipher_pkt *pkt, + uint8_t *iv); + +typedef int (*ctr_op_t)(struct cipher_ctx *ctx, struct cipher_pkt *pkt, + uint8_t *ctr); + +typedef int (*ccm_op_t)(struct cipher_ctx *ctx, struct cipher_aead_pkt *pkt, + uint8_t *nonce); + +struct cipher_ops { + + enum cipher_mode cipher_mode; + + union { + block_op_t block_crypt_hndlr; + cbc_op_t cbc_crypt_hndlr; + ctr_op_t ctr_crypt_hndlr; + ccm_op_t ccm_crypt_hndlr; + }; +}; + +struct ccm_params { + uint16_t tag_len; + uint16_t nonce_len; +}; + +struct ctr_params { + /* CTR mode counter is a split counter composed of iv and counter + * such that ivlen + ctr_len = keylen + */ + uint32_t ctr_len; +}; + +/* Structure encoding session parameters. Refer to comments for individual + * fields to know the contract in terms of who fills what and when w.r.t + * begin_session() call. + */ +struct cipher_ctx { + + /* Place for driver to return function pointers to be invoked per + * cipher operation. To be populated by crypto driver on return from + * begin_session() based on the algo/mode chosen by the app. + */ + struct cipher_ops ops; + + /* To be populated by the app before calling begin_session() */ + union { + /* Cryptographic key to be used in this session */ + uint8_t *bit_stream; + /* For cases where key is protected and is not + * available to caller + */ + void *handle; + } key; + + /* The device driver instance this crypto context relates to. Will be + * populated by the begin_session() API. + */ + struct device *device; + + /* If the driver supports multiple simultaneously crypto sessions, this + * will identify the specific driver state this crypto session relates + * to. Since dynamic memory allocation is is not possible, it is + * suggested that at build time drivers allocate space for the + * max simultaneous sessions they intend to support. To be populated + * by the driver on return from begin_session() + */ + void *drv_sessn_state; + + /* Place for the app to put info relevant stuff for resuming when + * completion call back happens for async ops. Totally managed by the + * app. + */ + void *app_sessn_state; + + + /* Standard mode parameters, which remain constant for all ops + * in a session. To be populated by the app before calling + * begin_session() + */ + union { + struct ccm_params ccm_info; + struct ctr_params ctr_info; + + } mode_params; + + + /* Cryptographic keylength in bytes. To be populated by the app + * before calling begin_session() + */ + uint16_t keylen; + + + /* How certain fields are to be interpreted for this sesssion. + * To be populated by the app before calling begin_session(). + * An app can obtain the capability flags supported by a hw/driver + * by calling cipher_query_hwcaps(). (A bitmask of CAP_* below) + */ + uint16_t flags; +}; + +/* Various cipher_ctx.flags options. Not all drivers support all flags. + * An app can query the supported hw / driver + * capabilities via provided API (cipher_query_hwcaps()), and choose a + * supported config during the session setup. + */ +#define CAP_OPAQUE_KEY_HNDL BIT(0) +#define CAP_RAW_KEY BIT(1) + +/* TBD to define */ +#define CAP_KEY_LOADING_API BIT(2) + +/* Whether the output is placed in separate buffer or not */ +#define CAP_INPLACE_OPS BIT(3) +#define CAP_SEPARATE_IO_BUFS BIT(4) + +/* These denotes if the output (completion of a cipher_xxx_op) is conveyed + * by the op function returning, or it is conveyed by an async notification + */ +#define CAP_SYNC_OPS BIT(5) +#define CAP_ASYNC_OPS BIT(6) + +/* Whether the hardware/driver supports autononce feature */ +#define CAP_AUTONONCE BIT(7) + + +/* More flags to be added as necessary */ + +/* Structure encoding IO parameters of one cryptographic + * operation like encrypt/decrypt. The fields which has not been explicitly + * called out has to be filled up by the app before making the cipher_xxx_op() + * call + */ +struct cipher_pkt { + + /* Start address of Input buffer */ + uint8_t *in_buf; + + /* Bytes to be operated upon */ + int in_len; + + /* Start of the Output buffer, to be allocated by + * the application. Can be NULL for in place ops. To be populated + * with contents by the driver on return from op / async_callback + */ + uint8_t *out_buf; + + /* Size of the out_buf area allocated by the application. Drivers should + * not write past the size of output buffer + */ + int out_buf_max; + + /* To be populated by driver on return from cipher_xxx_op() and + * holds the size of the actual result + */ + int out_len; + + /* This this field contains additional crypto specific error code, + * in the event of a failure. The cipher_xxx_op()/ async_callback + * returns a first level success / failure status. To be populated + * by the driver on return from op / async_callback. + */ + uint8_t status; + + /* Context this packet relates to. This can be useful to get the + * session details esp for async ops. Will be populated by the + * cipher_xxx_op() API based on the ctx parameter + */ + struct cipher_ctx *ctx; +}; + +/* Structure encoding IO parameters in AEAD (Authenticated Encryption + * with Associated Data) scenario like in CCM. App has to furnish valid + * contents prior to making cipher_ccm_op() call. + */ +struct cipher_aead_pkt { + /* IO buffers for Encryption. This has to be supplied by the app */ + struct cipher_pkt *pkt; + + /* Start address for Associated data. This has to be supplied by app */ + uint8_t *ad; + + /* Size of Associated data. This has to be supplied by the app */ + uint32_t ad_len; + + /* Start address for the Auth hash. For an Encryption op this will + * be populated by the driver when it returns from cipher_ccm_op call. + * For a decryption op this has to be supplied by the app. + */ + uint8_t *tag; +}; + +/* Prototype for the application function to be invoked by the crypto driver + * on completion of an async request. The app may get the session context + * via the pkt->ctx field. For ccm ops the encopassing AEAD packet maybe + * accessed via container_of(). The type of a packet can be determined via + * pkt->ctx.ops.mode + */ +typedef void (*crypto_completion_cb)(struct cipher_pkt *completed, int status); + +#endif /* __CRYPTO_CIPHER_STRUCTS_H__ */