On Thu Mar 7, 2024 at 5:38 PM EET, David Gstir wrote:
> DCP (Data Co-Processor) is able to derive private keys for a fused
> random seed, which can be referenced by handle but not accessed by
> the CPU. Similarly, DCP is able to store arbitrary keys in four
> dedicated key slots located in its secure memory area (internal SRAM).
> These keys can be used to perform AES encryption.
>
> Expose these derived keys and key slots through the crypto API via their
> handle. The main purpose is to add DCP-backed trusted keys. Other
> use cases are possible too (see similar existing paes implementations),
> but these should carefully be evaluated as e.g. enabling AF_ALG will
> give userspace full access to use keys. In scenarios with untrustworthy
> userspace, this will enable en-/decryption oracles.
>
> Co-developed-by: Richard Weinberger <rich...@nod.at>
> Signed-off-by: Richard Weinberger <rich...@nod.at>
> Co-developed-by: David Oberhollenzer <david.oberhollen...@sigma-star.at>
> Signed-off-by: David Oberhollenzer <david.oberhollen...@sigma-star.at>
> Signed-off-by: David Gstir <da...@sigma-star.at>
> Acked-by: Herbert Xu <herb...@gondor.apana.org.au>
> ---
>  drivers/crypto/mxs-dcp.c | 104 ++++++++++++++++++++++++++++++++++-----
>  include/soc/fsl/dcp.h    |  20 ++++++++
>  2 files changed, 113 insertions(+), 11 deletions(-)
>  create mode 100644 include/soc/fsl/dcp.h
>
> diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
> index 2b3ebe0db3a6..057d73c370b7 100644
> --- a/drivers/crypto/mxs-dcp.c
> +++ b/drivers/crypto/mxs-dcp.c
> @@ -15,6 +15,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/stmp_device.h>
>  #include <linux/clk.h>
> +#include <soc/fsl/dcp.h>
>  
>  #include <crypto/aes.h>
>  #include <crypto/sha1.h>
> @@ -101,6 +102,7 @@ struct dcp_async_ctx {
>       struct crypto_skcipher          *fallback;
>       unsigned int                    key_len;
>       uint8_t                         key[AES_KEYSIZE_128];
> +     bool                            key_referenced;
>  };
>  
>  struct dcp_aes_req_ctx {
> @@ -155,6 +157,7 @@ static struct dcp *global_sdcp;
>  #define MXS_DCP_CONTROL0_HASH_TERM           (1 << 13)
>  #define MXS_DCP_CONTROL0_HASH_INIT           (1 << 12)
>  #define MXS_DCP_CONTROL0_PAYLOAD_KEY         (1 << 11)
> +#define MXS_DCP_CONTROL0_OTP_KEY             (1 << 10)
>  #define MXS_DCP_CONTROL0_CIPHER_ENCRYPT              (1 << 8)
>  #define MXS_DCP_CONTROL0_CIPHER_INIT         (1 << 9)
>  #define MXS_DCP_CONTROL0_ENABLE_HASH         (1 << 6)
> @@ -168,6 +171,8 @@ static struct dcp *global_sdcp;
>  #define MXS_DCP_CONTROL1_CIPHER_MODE_ECB     (0 << 4)
>  #define MXS_DCP_CONTROL1_CIPHER_SELECT_AES128        (0 << 0)
>  
> +#define MXS_DCP_CONTROL1_KEY_SELECT_SHIFT    8
> +
>  static int mxs_dcp_start_dma(struct dcp_async_ctx *actx)
>  {
>       int dma_err;
> @@ -224,13 +229,16 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
>       struct dcp *sdcp = global_sdcp;
>       struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
>       struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req);
> +     bool key_referenced = actx->key_referenced;
>       int ret;
>  
> -     key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
> -                               2 * AES_KEYSIZE_128, DMA_TO_DEVICE);
> -     ret = dma_mapping_error(sdcp->dev, key_phys);
> -     if (ret)
> -             return ret;
> +     if (!key_referenced) {
> +             key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key,
> +                                       2 * AES_KEYSIZE_128, DMA_TO_DEVICE);
> +             ret = dma_mapping_error(sdcp->dev, key_phys);
> +             if (ret)
> +                     return ret;
> +     }
>  
>       src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf,
>                                 DCP_BUF_SZ, DMA_TO_DEVICE);
> @@ -255,8 +263,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
>                   MXS_DCP_CONTROL0_INTERRUPT |
>                   MXS_DCP_CONTROL0_ENABLE_CIPHER;
>  
> -     /* Payload contains the key. */
> -     desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
> +     if (key_referenced)
> +             /* Set OTP key bit to select the key via KEY_SELECT. */
> +             desc->control0 |= MXS_DCP_CONTROL0_OTP_KEY;
> +     else
> +             /* Payload contains the key. */
> +             desc->control0 |= MXS_DCP_CONTROL0_PAYLOAD_KEY;
>  
>       if (rctx->enc)
>               desc->control0 |= MXS_DCP_CONTROL0_CIPHER_ENCRYPT;
> @@ -270,6 +282,9 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
>       else
>               desc->control1 |= MXS_DCP_CONTROL1_CIPHER_MODE_CBC;
>  
> +     if (key_referenced)
> +             desc->control1 |= sdcp->coh->aes_key[0] << 
> MXS_DCP_CONTROL1_KEY_SELECT_SHIFT;
> +
>       desc->next_cmd_addr = 0;
>       desc->source = src_phys;
>       desc->destination = dst_phys;
> @@ -284,9 +299,9 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
>  err_dst:
>       dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
>  err_src:
> -     dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
> -                      DMA_TO_DEVICE);
> -
> +     if (!key_referenced)
> +             dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
> +                              DMA_TO_DEVICE);
>       return ret;
>  }
>  
> @@ -453,7 +468,7 @@ static int mxs_dcp_aes_enqueue(struct skcipher_request 
> *req, int enc, int ecb)
>       struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req);
>       int ret;
>  
> -     if (unlikely(actx->key_len != AES_KEYSIZE_128))
> +     if (unlikely(actx->key_len != AES_KEYSIZE_128 && !actx->key_referenced))
>               return mxs_dcp_block_fallback(req, enc);
>  
>       rctx->enc = enc;
> @@ -500,6 +515,7 @@ static int mxs_dcp_aes_setkey(struct crypto_skcipher 
> *tfm, const u8 *key,
>        * there can still be an operation in progress.
>        */
>       actx->key_len = len;
> +     actx->key_referenced = false;
>       if (len == AES_KEYSIZE_128) {
>               memcpy(actx->key, key, len);
>               return 0;
> @@ -516,6 +532,32 @@ static int mxs_dcp_aes_setkey(struct crypto_skcipher 
> *tfm, const u8 *key,
>       return crypto_skcipher_setkey(actx->fallback, key, len);
>  }
>  
> +static int mxs_dcp_aes_setrefkey(struct crypto_skcipher *tfm, const u8 *key,
> +                              unsigned int len)
> +{
> +     struct dcp_async_ctx *actx = crypto_skcipher_ctx(tfm);
> +
> +     if (len != DCP_PAES_KEYSIZE)
> +             return -EINVAL;
> +
> +     switch (key[0]) {
> +     case DCP_PAES_KEY_SLOT0:
> +     case DCP_PAES_KEY_SLOT1:
> +     case DCP_PAES_KEY_SLOT2:
> +     case DCP_PAES_KEY_SLOT3:
> +     case DCP_PAES_KEY_UNIQUE:
> +     case DCP_PAES_KEY_OTP:
> +             memcpy(actx->key, key, len);
> +             actx->key_len = len;
> +             actx->key_referenced = true;
> +             break;
> +     default:
> +             return -EINVAL;
> +     }
> +
> +     return 0;
> +}
> +
>  static int mxs_dcp_aes_fallback_init_tfm(struct crypto_skcipher *tfm)
>  {
>       const char *name = crypto_tfm_alg_name(crypto_skcipher_tfm(tfm));
> @@ -539,6 +581,13 @@ static void mxs_dcp_aes_fallback_exit_tfm(struct 
> crypto_skcipher *tfm)
>       crypto_free_skcipher(actx->fallback);
>  }
>  
> +static int mxs_dcp_paes_init_tfm(struct crypto_skcipher *tfm)
> +{
> +     crypto_skcipher_set_reqsize(tfm, sizeof(struct dcp_aes_req_ctx));
> +
> +     return 0;
> +}
> +
>  /*
>   * Hashing (SHA1/SHA256)
>   */
> @@ -889,6 +938,39 @@ static struct skcipher_alg dcp_aes_algs[] = {
>               .ivsize                 = AES_BLOCK_SIZE,
>               .init                   = mxs_dcp_aes_fallback_init_tfm,
>               .exit                   = mxs_dcp_aes_fallback_exit_tfm,
> +     }, {
> +             .base.cra_name          = "ecb(paes)",
> +             .base.cra_driver_name   = "ecb-paes-dcp",
> +             .base.cra_priority      = 401,
> +             .base.cra_alignmask     = 15,
> +             .base.cra_flags         = CRYPTO_ALG_ASYNC | 
> CRYPTO_ALG_INTERNAL,
> +             .base.cra_blocksize     = AES_BLOCK_SIZE,
> +             .base.cra_ctxsize       = sizeof(struct dcp_async_ctx),
> +             .base.cra_module        = THIS_MODULE,
> +
> +             .min_keysize            = DCP_PAES_KEYSIZE,
> +             .max_keysize            = DCP_PAES_KEYSIZE,
> +             .setkey                 = mxs_dcp_aes_setrefkey,
> +             .encrypt                = mxs_dcp_aes_ecb_encrypt,
> +             .decrypt                = mxs_dcp_aes_ecb_decrypt,
> +             .init                   = mxs_dcp_paes_init_tfm,
> +     }, {
> +             .base.cra_name          = "cbc(paes)",
> +             .base.cra_driver_name   = "cbc-paes-dcp",
> +             .base.cra_priority      = 401,
> +             .base.cra_alignmask     = 15,
> +             .base.cra_flags         = CRYPTO_ALG_ASYNC | 
> CRYPTO_ALG_INTERNAL,
> +             .base.cra_blocksize     = AES_BLOCK_SIZE,
> +             .base.cra_ctxsize       = sizeof(struct dcp_async_ctx),
> +             .base.cra_module        = THIS_MODULE,
> +
> +             .min_keysize            = DCP_PAES_KEYSIZE,
> +             .max_keysize            = DCP_PAES_KEYSIZE,
> +             .setkey                 = mxs_dcp_aes_setrefkey,
> +             .encrypt                = mxs_dcp_aes_cbc_encrypt,
> +             .decrypt                = mxs_dcp_aes_cbc_decrypt,
> +             .ivsize                 = AES_BLOCK_SIZE,
> +             .init                   = mxs_dcp_paes_init_tfm,
>       },
>  };
>  
> diff --git a/include/soc/fsl/dcp.h b/include/soc/fsl/dcp.h
> new file mode 100644
> index 000000000000..3ec335d8ca8b
> --- /dev/null
> +++ b/include/soc/fsl/dcp.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2021 sigma star gmbh
> + *
> + * Specifies paes key slot handles for NXP's DCP (Data Co-Processor) to be 
> used
> + * with the crypto_skcipher_setkey().
> + */
> +
> +#ifndef MXS_DCP_H
> +#define MXS_DCP_H
> +
> +#define DCP_PAES_KEYSIZE 1
> +#define DCP_PAES_KEY_SLOT0 0x00
> +#define DCP_PAES_KEY_SLOT1 0x01
> +#define DCP_PAES_KEY_SLOT2 0x02
> +#define DCP_PAES_KEY_SLOT3 0x03
> +#define DCP_PAES_KEY_UNIQUE 0xfe
> +#define DCP_PAES_KEY_OTP 0xff
> +
> +#endif /* MXS_DCP_H */

Looks to good enough to me:

Reviewed-by: Jarkko Sakkinen <jar...@kernel.org>

BR, Jarkko

Reply via email to