diff mbox series

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

Message ID 20221006130837.17587-7-pankaj.gupta@nxp.com (mailing list archive)
State New
Headers show
Series Hardware Bound key added to Trusted Key-Ring | expand

Commit Message

Pankaj Gupta Oct. 6, 2022, 1:08 p.m. UTC
- 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@nxp.com>
---
 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(-)

Comments

Ben Boeckel Oct. 6, 2022, 12:42 p.m. UTC | #1
On Thu, Oct 06, 2022 at 18:38:35 +0530, Pankaj Gupta wrote:
> - CAAM supports two types of black keys:
>   -- Plain key encrypted with ECB
>   -- Plain key encrypted with CCM

What is a "black key"? Is this described in the documentation or local
comments at all? (I know I'm unfamiliar with CAAM, but maybe this should
be mentioned somewhere?).

>   Note: Due to robustness, default encytption used for black key is CCM.
                                     ^^^^^^^^^^ encryption

What "robustness"? Surely there's some more technical details involved
here?

> - 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,

It seems that "black keys" are what the uapi calls "hw". I think this
should be mentioned in the commit message (and CAAM docs).

What do other keytypes do if `hw` is requested and it's not possible
(say, `big_key`)?

Thanks,

--Ben
James Bottomley Oct. 6, 2022, 12:52 p.m. UTC | #2
On Thu, 2022-10-06 at 08:42 -0400, Ben Boeckel wrote:
> On Thu, Oct 06, 2022 at 18:38:35 +0530, Pankaj Gupta wrote:
> > - CAAM supports two types of black keys:
> >   -- Plain key encrypted with ECB
> >   -- Plain key encrypted with CCM
> 
> What is a "black key"? Is this described in the documentation or
> local comments at all? (I know I'm unfamiliar with CAAM, but maybe
> this should be mentioned somewhere?).
> 
> >   Note: Due to robustness, default encytption used for black key is
> > CCM.
>                                      ^^^^^^^^^^ encryption
> 
> What "robustness"? Surely there's some more technical details
> involved here?

The crypto advice for the past decade or more has been never use ECB
it's insecure, so anything could be regarded as robust compared to it
... however that does beg the question of why ECB is even offered in a
modern system?  Surely it's nothing more than a user trap (choose this
secure option only if you don't want security).

James
diff mbox series

Patch

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@pengutronix.de>
+ * Copyright 2022 NXP, Pankaj Gupta <pankaj.gupta@nxp.com>
  */
 
 #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;
 }