- CAAM supports two types of black keys: -- Plain key encrypted with ECB -- Plain key encrypted with CCM Note: Due to robustness, default encytption used for black key is CCM. - A black key blob is generated, and added to trusted key payload. This is done as part of sealing operation, that was triggered as a result of: -- new key generation -- load key, Signed-off-by: Pankaj Gupta <pankaj.gupta@xxxxxxx> --- drivers/crypto/caam/blob_gen.c | 123 +++++++++++++++++++--- drivers/crypto/caam/desc.h | 8 +- include/soc/fsl/caam-blob.h | 15 +++ security/keys/trusted-keys/trusted_caam.c | 8 ++ 4 files changed, 136 insertions(+), 18 deletions(-) diff --git a/drivers/crypto/caam/blob_gen.c b/drivers/crypto/caam/blob_gen.c index 36683ec9aee0..93e05557dcaa 100644 --- a/drivers/crypto/caam/blob_gen.c +++ b/drivers/crypto/caam/blob_gen.c @@ -8,6 +8,8 @@ #define pr_fmt(fmt) "caam blob_gen: " fmt #include <linux/device.h> +#include <linux/hw_bound_key.h> +#include <keys/trusted-type.h> #include <soc/fsl/caam-blob.h> #include "compat.h" @@ -32,6 +34,9 @@ struct caam_blob_priv { struct device jrdev; + /* Flags: whether generated trusted key, is ECB or CCM encrypted.*/ + uint8_t hbk_flags; + uint8_t rsv[3]; }; struct caam_blob_job_result { @@ -78,8 +83,13 @@ int caam_encap_blob(struct caam_blob_priv *priv, dma_addr_t dma_in, dma_out; int op = OP_PCLID_BLOB; size_t output_len; + dma_addr_t dma_blk; u32 *desc; int ret; + int hwbk_caam_ovhd = 0; + + if (info->output_len < info->input_len + CAAM_BLOB_OVERHEAD) + return -EINVAL; if (info->key_mod_len > CAAM_BLOB_KEYMOD_LENGTH) return -EINVAL; @@ -87,6 +97,21 @@ int caam_encap_blob(struct caam_blob_priv *priv, op |= OP_TYPE_ENCAP_PROTOCOL; output_len = info->input_len + CAAM_BLOB_OVERHEAD; + if (info->is_hw_bound == 1) { + op |= OP_PCL_BLOB_BLACK; + if (priv->hbk_flags & HWBK_FLAGS_CAAM_CCM_ALGO_MASK) { + op |= OP_PCL_BLOB_EKT; + hwbk_caam_ovhd = CCM_OVERHEAD; + } + + if ((info->input_len + hwbk_caam_ovhd) > MAX_KEY_SIZE) + return -EINVAL; + + set_hbk_info(info->hbk_info, + priv->hbk_flags, + info->input_len); + } + desc = kzalloc(CAAM_BLOB_DESC_BYTES_MAX, GFP_KERNEL | GFP_DMA); if (!desc) return -ENOMEM; @@ -99,12 +124,26 @@ int caam_encap_blob(struct caam_blob_priv *priv, goto out_free; } + if (info->is_hw_bound == 1) { + dma_blk = dma_map_single(jrdev, info->input, + info->input_len + hwbk_caam_ovhd, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dma_out)) { + dev_err(jrdev, "unable to map output DMA buffer\n"); + ret = -ENOMEM; + goto out_unmap_in; + } + } + dma_out = dma_map_single(jrdev, info->output, output_len, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, dma_out)) { dev_err(jrdev, "unable to map output DMA buffer\n"); ret = -ENOMEM; - goto out_unmap_in; + if (info->is_hw_bound == 1) + goto out_unmap_blk; + else + goto out_unmap_in; } /* @@ -116,15 +155,40 @@ int caam_encap_blob(struct caam_blob_priv *priv, */ init_job_desc(desc, 0); + + if (info->is_hw_bound == 1) { + /*!1. key command used to load class 1 key register + * from input plain key. + */ + append_key(desc, dma_in, info->input_len, + CLASS_1 | KEY_DEST_CLASS_REG); + + /*!2. Fifostore to store black key from class 1 key register. */ + append_fifo_store(desc, dma_blk, info->input_len, + LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_CCM_JKEK); + + append_jump(desc, JUMP_COND_NOP | 1); + } + /*!3. Load class 2 key with key modifier. */ append_key_as_imm(desc, info->key_mod, info->key_mod_len, info->key_mod_len, CLASS_2 | KEY_DEST_CLASS_REG); - append_seq_in_ptr_intlen(desc, dma_in, info->input_len, 0); + + /*!4. SEQ IN PTR Command. */ + if (info->is_hw_bound == 1) { + append_seq_in_ptr_intlen(desc, dma_blk, info->input_len, 0); + } else { + append_seq_in_ptr_intlen(desc, dma_in, info->input_len, 0); + } + + /*!5. SEQ OUT PTR Command. */ append_seq_out_ptr_intlen(desc, dma_out, output_len, 0); + + /*!6. BlackBlob encapsulation PROTOCOL Command. */ append_operation(desc, op); print_hex_dump_debug("data@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 1, info->input, - info->input_len, false); + info->input_len + hwbk_caam_ovhd, false); print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 1, desc, desc_bytes(desc), false); @@ -140,11 +204,15 @@ int caam_encap_blob(struct caam_blob_priv *priv, DUMP_PREFIX_ADDRESS, 16, 1, info->output, output_len, false); } - - if (ret == 0) + if (ret == 0) { + info->input_len += hwbk_caam_ovhd; info->output_len = output_len; - + } dma_unmap_single(jrdev, dma_out, output_len, DMA_FROM_DEVICE); +out_unmap_blk: + if (info->is_hw_bound == 1) { + dma_unmap_single(jrdev, dma_blk, info->input_len, DMA_TO_DEVICE); + } out_unmap_in: dma_unmap_single(jrdev, dma_in, info->input_len, DMA_TO_DEVICE); out_free: @@ -170,15 +238,35 @@ int caam_decap_blob(struct caam_blob_priv *priv, struct device *jrdev = &priv->jrdev; dma_addr_t dma_in, dma_out; int op = OP_PCLID_BLOB; - size_t output_len; u32 *desc; int ret; + int hwbk_caam_ovhd = 0; + + if (info->input_len < CAAM_BLOB_OVERHEAD) + return -EINVAL; if (info->key_mod_len > CAAM_BLOB_KEYMOD_LENGTH) return -EINVAL; op |= OP_TYPE_DECAP_PROTOCOL; - output_len = info->input_len - CAAM_BLOB_OVERHEAD; + info->output_len = info->input_len - CAAM_BLOB_OVERHEAD; + + if (info->is_hw_bound == 1) { + op |= OP_PCL_BLOB_BLACK; + if (priv->hbk_flags & HWBK_FLAGS_CAAM_CCM_ALGO_MASK) { + op |= OP_PCL_BLOB_EKT; + hwbk_caam_ovhd = CCM_OVERHEAD; + } + + if ((info->output_len + hwbk_caam_ovhd) > MAX_KEY_SIZE) + return -EINVAL; + + set_hbk_info(info->hbk_info, + priv->hbk_flags, + info->output_len); + + info->output_len += hwbk_caam_ovhd; + } desc = kzalloc(CAAM_BLOB_DESC_BYTES_MAX, GFP_KERNEL | GFP_DMA); if (!desc) @@ -192,7 +280,7 @@ int caam_decap_blob(struct caam_blob_priv *priv, goto out_free; } - dma_out = dma_map_single(jrdev, info->output, output_len, + dma_out = dma_map_single(jrdev, info->output, info->output_len, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, dma_out)) { dev_err(jrdev, "unable to map output DMA buffer\n"); @@ -211,8 +299,8 @@ int caam_decap_blob(struct caam_blob_priv *priv, init_job_desc(desc, 0); append_key_as_imm(desc, info->key_mod, info->key_mod_len, info->key_mod_len, CLASS_2 | KEY_DEST_CLASS_REG); - append_seq_in_ptr_intlen(desc, dma_in, info->input_len, 0); - append_seq_out_ptr_intlen(desc, dma_out, output_len, 0); + append_seq_in_ptr(desc, dma_in, info->input_len, 0); + append_seq_out_ptr(desc, dma_out, info->output_len, 0); append_operation(desc, op); print_hex_dump_debug("data@"__stringify(__LINE__)": ", @@ -231,13 +319,10 @@ int caam_decap_blob(struct caam_blob_priv *priv, ret = testres.err; print_hex_dump_debug("output@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 1, info->output, - output_len, false); + info->output_len, false); } - if (ret == 0) - info->output_len = output_len; - - dma_unmap_single(jrdev, dma_out, output_len, DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_out, info->output_len, DMA_FROM_DEVICE); out_unmap_in: dma_unmap_single(jrdev, dma_in, info->input_len, DMA_TO_DEVICE); out_free: @@ -251,6 +336,7 @@ struct caam_blob_priv *caam_blob_gen_init(void) { struct caam_drv_private *ctrlpriv; struct device *jrdev; + struct caam_blob_priv *blob_priv; /* * caam_blob_gen_init() may expectedly fail with -ENODEV, e.g. when @@ -271,7 +357,10 @@ struct caam_blob_priv *caam_blob_gen_init(void) return ERR_PTR(-ENODEV); } - return container_of(jrdev, struct caam_blob_priv, jrdev); + blob_priv = container_of(jrdev, struct caam_blob_priv, jrdev); + blob_priv->hbk_flags = HWBK_FLAGS_CAAM_CCM_ALGO_MASK; + + return blob_priv; } EXPORT_SYMBOL(caam_blob_gen_init); diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index e13470901586..41b2d0226bdf 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -4,7 +4,7 @@ * Definitions to support CAAM descriptor instruction generation * * Copyright 2008-2011 Freescale Semiconductor, Inc. - * Copyright 2018 NXP + * Copyright 2018-2022 NXP */ #ifndef DESC_H @@ -403,6 +403,7 @@ #define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_KEY_CCM_JKEK (0x14 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) @@ -1001,6 +1002,11 @@ #define OP_PCL_TLS12_AES_256_CBC_SHA384 0xff63 #define OP_PCL_TLS12_AES_256_CBC_SHA512 0xff65 +/* Blob protocol protinfo bits */ + +#define OP_PCL_BLOB_BLACK 0x0004 +#define OP_PCL_BLOB_EKT 0x0100 + /* For DTLS - OP_PCLID_DTLS */ #define OP_PCL_DTLS_AES_128_CBC_SHA 0x002f diff --git a/include/soc/fsl/caam-blob.h b/include/soc/fsl/caam-blob.h index de507e2a9555..8d9f6b209418 100644 --- a/include/soc/fsl/caam-blob.h +++ b/include/soc/fsl/caam-blob.h @@ -9,7 +9,19 @@ #include <linux/types.h> #include <linux/errno.h> +#include <linux/hw_bound_key.h> +#define HWBK_FLAGS_CAAM_CCM_ALGO_MASK 0x01 + +/* + * CCM-Black Key will always be at least 12 bytes longer, + * since the encapsulation uses a 6-byte nonce and adds + * a 6-byte ICV. But first, the key is padded as necessary so + * that CCM-Black Key is a multiple of 8 bytes long. + */ +#define NONCE_SIZE 6 +#define ICV_SIZE 6 +#define CCM_OVERHEAD (NONCE_SIZE + ICV_SIZE) #define CAAM_BLOB_KEYMOD_LENGTH 16 #define CAAM_BLOB_OVERHEAD (32 + 16) #define CAAM_BLOB_MAX_LEN 4096 @@ -35,6 +47,9 @@ struct caam_blob_info { const void *key_mod; size_t key_mod_len; + + const char is_hw_bound; + struct hw_bound_key_info *hbk_info; }; /** diff --git a/security/keys/trusted-keys/trusted_caam.c b/security/keys/trusted-keys/trusted_caam.c index e3415c520c0a..60e50bed7014 100644 --- a/security/keys/trusted-keys/trusted_caam.c +++ b/security/keys/trusted-keys/trusted_caam.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2021 Pengutronix, Ahmad Fatoum <kernel@xxxxxxxxxxxxxx> + * Copyright 2022 NXP, Pankaj Gupta <pankaj.gupta@xxxxxxx> */ #include <keys/trusted_caam.h> @@ -23,6 +24,7 @@ static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob) .input = p->key, .input_len = p->key_len, .output = p->blob, .output_len = MAX_BLOB_SIZE, .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, + .is_hw_bound = p->is_hw_bound, .hbk_info = &p->hbk_info, }; ret = caam_encap_blob(blobifier, &info); @@ -30,6 +32,10 @@ static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob) return ret; p->blob_len = info.output_len; + + if (p->is_hw_bound) + p->key_len = info.input_len; + return 0; } @@ -40,6 +46,7 @@ static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob) .input = p->blob, .input_len = p->blob_len, .output = p->key, .output_len = MAX_KEY_SIZE, .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, + .is_hw_bound = p->is_hw_bound, .hbk_info = &p->hbk_info, }; ret = caam_decap_blob(blobifier, &info); @@ -47,6 +54,7 @@ static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob) return ret; p->key_len = info.output_len; + return 0; } -- 2.17.1