- 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 | 132 +++++++++++++++++++++++++++++---- drivers/crypto/caam/desc.h | 8 +- include/soc/fsl/caam-blob.h | 16 ++++ 3 files changed, 140 insertions(+), 16 deletions(-) diff --git a/drivers/crypto/caam/blob_gen.c b/drivers/crypto/caam/blob_gen.c index 5164e62f9596..2354e3c6fc61 100644 --- a/drivers/crypto/caam/blob_gen.c +++ b/drivers/crypto/caam/blob_gen.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "caam blob_gen: " fmt #include <linux/device.h> +#include <keys/trusted-type.h> #include <soc/fsl/caam-blob.h> #include "compat.h" @@ -74,8 +75,16 @@ 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; + u8 *input = info->input; + u8 *blk_out; + size_t input_len = info->input_len; 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; @@ -83,11 +92,33 @@ 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 ((input_len + hwbk_caam_ovhd) > MAX_KEY_SIZE) + return -EINVAL; + + /* create copy of input buffer */ + input = kzalloc(info->input_len, GFP_KERNEL | GFP_DMA); + if (!input) + return -ENOMEM; + memcpy(input, info->input, info->input_len); + + /* create hw bound key on input buffer reference */ + blk_out = info->input; + + info->input_len = input_len + hwbk_caam_ovhd; + } + desc = kzalloc(CAAM_BLOB_DESC_BYTES_MAX, GFP_KERNEL | GFP_DMA); if (!desc) return -ENOMEM; - dma_in = dma_map_single(jrdev, info->input, info->input_len, + dma_in = dma_map_single(jrdev, input, input_len, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, dma_in)) { dev_err(jrdev, "unable to map input DMA buffer\n"); @@ -95,12 +126,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, blk_out, + 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; } /* @@ -112,15 +157,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, 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, 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, input_len, 0); + } else { + append_seq_in_ptr_intlen(desc, dma_in, 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); + DUMP_PREFIX_ADDRESS, 16, 1, input, + input_len + hwbk_caam_ovhd, false); print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 1, desc, desc_bytes(desc), false); @@ -136,15 +206,19 @@ 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->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: kfree(desc); + kfree(input); return ret; } @@ -168,13 +242,41 @@ int caam_decap_blob(struct caam_blob_priv *priv, int op = OP_PCLID_BLOB; size_t output_len; u32 *desc; + u8 *output = info->output; 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 = output_len; + + 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 ((output_len + hwbk_caam_ovhd) > MAX_KEY_SIZE) + return -EINVAL; + + /* In case of HW Bound Key, lengths have different purpose: + * - output_len = HW encrypted key length. + * - info->output_len = Length of HW Bound Key Payload + * (Payload = Header + outlen) + */ + info->output_len = output_len + hwbk_caam_ovhd; + + output_len += hwbk_caam_ovhd; + + output = info->output; + } desc = kzalloc(CAAM_BLOB_DESC_BYTES_MAX, GFP_KERNEL | GFP_DMA); if (!desc) @@ -188,7 +290,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, output, output_len, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, dma_out)) { dev_err(jrdev, "unable to map output DMA buffer\n"); @@ -207,8 +309,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, output_len, 0); append_operation(desc, op); print_hex_dump_debug("data@"__stringify(__LINE__)": ", @@ -226,13 +328,10 @@ int caam_decap_blob(struct caam_blob_priv *priv, wait_for_completion(&testres.completion); ret = testres.err; print_hex_dump_debug("output@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 1, info->output, + DUMP_PREFIX_ADDRESS, 16, 1, output, output_len, false); } - if (ret == 0) - info->output_len = output_len; - dma_unmap_single(jrdev, dma_out, output_len, DMA_FROM_DEVICE); out_unmap_in: dma_unmap_single(jrdev, dma_in, info->input_len, DMA_TO_DEVICE); @@ -267,6 +366,9 @@ struct caam_blob_priv *caam_blob_gen_init(void) return ERR_PTR(-ENODEV); } + ctrlpriv->blob_priv.hbk_flags = HWBK_FLAGS_CAAM_CCM_ALGO_MASK; + ctrlpriv->blob_priv.jrdev = jrdev; + return &ctrlpriv->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 380b0bcb79dc..ae2c2a6c8c23 100644 --- a/include/soc/fsl/caam-blob.h +++ b/include/soc/fsl/caam-blob.h @@ -10,12 +10,26 @@ #include <linux/types.h> #include <linux/errno.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 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]; }; @@ -38,6 +52,8 @@ struct caam_blob_info { const void *key_mod; size_t key_mod_len; + + const char is_hw_bound; }; /** -- 2.17.1