[PATCH v0 6/8] KEYS: trusted: caam based black key

From: Pankaj Gupta
Date: Thu Oct 06 2022 - 08:04:36 EST


- 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