- 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 <[email protected]>
---
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