Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KEYS: trusted: caam based protected key

- CAAM supports two types of protected keys:
-- Plain key encrypted with ECB
-- Plain key encrypted with CCM
Due to robustness, default encryption used for protected key is CCM.

- Generate protected key blob and add it to trusted key payload.
This is done as part of sealing operation, which is triggered
when below two operations are requested:
-- new key generation
-- load key,

Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Signed-off-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Meenakshi Aggarwal and committed by
Herbert Xu
a703a4c2 38f68807

+212 -17
+70 -16
drivers/crypto/caam/blob_gen.c
··· 2 2 /* 3 3 * Copyright (C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de> 4 4 * Copyright (C) 2021 Pengutronix, Ahmad Fatoum <kernel@pengutronix.de> 5 - * Copyright 2024 NXP 5 + * Copyright 2024-2025 NXP 6 6 */ 7 7 8 8 #define pr_fmt(fmt) "caam blob_gen: " fmt 9 9 10 10 #include <linux/bitfield.h> 11 11 #include <linux/device.h> 12 + #include <keys/trusted-type.h> 12 13 #include <soc/fsl/caam-blob.h> 13 14 14 15 #include "compat.h" ··· 61 60 complete(&res->completion); 62 61 } 63 62 63 + static u32 check_caam_state(struct device *jrdev) 64 + { 65 + const struct caam_drv_private *ctrlpriv; 66 + 67 + ctrlpriv = dev_get_drvdata(jrdev->parent); 68 + return FIELD_GET(CSTA_MOO, rd_reg32(&ctrlpriv->jr[0]->perfmon.status)); 69 + } 70 + 64 71 int caam_process_blob(struct caam_blob_priv *priv, 65 72 struct caam_blob_info *info, bool encap) 66 73 { 67 - const struct caam_drv_private *ctrlpriv; 68 74 struct caam_blob_job_result testres; 69 75 struct device *jrdev = &priv->jrdev; 70 76 dma_addr_t dma_in, dma_out; 71 77 int op = OP_PCLID_BLOB; 78 + int hwbk_caam_ovhd = 0; 72 79 size_t output_len; 73 80 u32 *desc; 74 81 u32 moo; 75 82 int ret; 83 + int len; 76 84 77 85 if (info->key_mod_len > CAAM_BLOB_KEYMOD_LENGTH) 78 86 return -EINVAL; ··· 92 82 } else { 93 83 op |= OP_TYPE_DECAP_PROTOCOL; 94 84 output_len = info->input_len - CAAM_BLOB_OVERHEAD; 85 + info->output_len = output_len; 86 + } 87 + 88 + if (encap && info->pkey_info.is_pkey) { 89 + op |= OP_PCL_BLOB_BLACK; 90 + if (info->pkey_info.key_enc_algo == CAAM_ENC_ALGO_CCM) { 91 + op |= OP_PCL_BLOB_EKT; 92 + hwbk_caam_ovhd = CAAM_CCM_OVERHEAD; 93 + } 94 + if ((info->input_len + hwbk_caam_ovhd) > MAX_KEY_SIZE) 95 + return -EINVAL; 96 + 97 + len = info->input_len + hwbk_caam_ovhd; 98 + } else { 99 + len = info->input_len; 95 100 } 96 101 97 102 desc = kzalloc(CAAM_BLOB_DESC_BYTES_MAX, GFP_KERNEL); 98 103 if (!desc) 99 104 return -ENOMEM; 100 105 101 - dma_in = dma_map_single(jrdev, info->input, info->input_len, 102 - DMA_TO_DEVICE); 106 + dma_in = dma_map_single(jrdev, info->input, len, 107 + encap ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); 103 108 if (dma_mapping_error(jrdev, dma_in)) { 104 109 dev_err(jrdev, "unable to map input DMA buffer\n"); 105 110 ret = -ENOMEM; ··· 129 104 goto out_unmap_in; 130 105 } 131 106 132 - ctrlpriv = dev_get_drvdata(jrdev->parent); 133 - moo = FIELD_GET(CSTA_MOO, rd_reg32(&ctrlpriv->jr[0]->perfmon.status)); 107 + moo = check_caam_state(jrdev); 134 108 if (moo != CSTA_MOO_SECURE && moo != CSTA_MOO_TRUSTED) 135 109 dev_warn(jrdev, 136 110 "using insecure test key, enable HAB to use unique device key!\n"); ··· 141 117 * Class 1 Context DWords 0+1+2+3. The random BK is stored in the 142 118 * Class 1 Key Register. Operation Mode is set to AES-CCM. 143 119 */ 144 - 145 120 init_job_desc(desc, 0); 121 + 122 + if (encap && info->pkey_info.is_pkey) { 123 + /*!1. key command used to load class 1 key register 124 + * from input plain key. 125 + */ 126 + append_key(desc, dma_in, info->input_len, 127 + CLASS_1 | KEY_DEST_CLASS_REG); 128 + /*!2. Fifostore to store protected key from class 1 key register. */ 129 + if (info->pkey_info.key_enc_algo == CAAM_ENC_ALGO_CCM) { 130 + append_fifo_store(desc, dma_in, info->input_len, 131 + LDST_CLASS_1_CCB | 132 + FIFOST_TYPE_KEY_CCM_JKEK); 133 + } else { 134 + append_fifo_store(desc, dma_in, info->input_len, 135 + LDST_CLASS_1_CCB | 136 + FIFOST_TYPE_KEY_KEK); 137 + } 138 + /* 139 + * JUMP_OFFSET specifies the offset of the JUMP target from 140 + * the JUMP command's address in the descriptor buffer. 141 + */ 142 + append_jump(desc, JUMP_COND_NOP | BIT(0) << JUMP_OFFSET_SHIFT); 143 + } 144 + 145 + /*!3. Load class 2 key with key modifier. */ 146 146 append_key_as_imm(desc, info->key_mod, info->key_mod_len, 147 - info->key_mod_len, CLASS_2 | KEY_DEST_CLASS_REG); 148 - append_seq_in_ptr_intlen(desc, dma_in, info->input_len, 0); 149 - append_seq_out_ptr_intlen(desc, dma_out, output_len, 0); 147 + info->key_mod_len, CLASS_2 | KEY_DEST_CLASS_REG); 148 + 149 + /*!4. SEQ IN PTR Command. */ 150 + append_seq_in_ptr(desc, dma_in, info->input_len, 0); 151 + 152 + /*!5. SEQ OUT PTR Command. */ 153 + append_seq_out_ptr(desc, dma_out, output_len, 0); 154 + 155 + /*!6. Blob encapsulation/decapsulation PROTOCOL Command. */ 150 156 append_operation(desc, op); 151 157 152 - print_hex_dump_debug("data@"__stringify(__LINE__)": ", 158 + print_hex_dump_debug("data@" __stringify(__LINE__)": ", 153 159 DUMP_PREFIX_ADDRESS, 16, 1, info->input, 154 - info->input_len, false); 155 - print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", 160 + len, false); 161 + print_hex_dump_debug("jobdesc@" __stringify(__LINE__)": ", 156 162 DUMP_PREFIX_ADDRESS, 16, 1, desc, 157 163 desc_bytes(desc), false); 158 164 ··· 193 139 if (ret == -EINPROGRESS) { 194 140 wait_for_completion(&testres.completion); 195 141 ret = testres.err; 196 - print_hex_dump_debug("output@"__stringify(__LINE__)": ", 142 + print_hex_dump_debug("output@" __stringify(__LINE__)": ", 197 143 DUMP_PREFIX_ADDRESS, 16, 1, info->output, 198 144 output_len, false); 199 145 } ··· 203 149 204 150 dma_unmap_single(jrdev, dma_out, output_len, DMA_FROM_DEVICE); 205 151 out_unmap_in: 206 - dma_unmap_single(jrdev, dma_in, info->input_len, DMA_TO_DEVICE); 152 + dma_unmap_single(jrdev, dma_in, len, 153 + encap ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); 207 154 out_free: 208 155 kfree(desc); 209 - 210 156 return ret; 211 157 } 212 158 EXPORT_SYMBOL(caam_process_blob);
+8 -1
drivers/crypto/caam/desc.h
··· 4 4 * Definitions to support CAAM descriptor instruction generation 5 5 * 6 6 * Copyright 2008-2011 Freescale Semiconductor, Inc. 7 - * Copyright 2018 NXP 7 + * Copyright 2018, 2025 NXP 8 8 */ 9 9 10 10 #ifndef DESC_H ··· 162 162 * Enhanced Encryption of Key 163 163 */ 164 164 #define KEY_EKT 0x00100000 165 + #define KEY_EKT_OFFSET 20 165 166 166 167 /* 167 168 * Encrypted with Trusted Key ··· 404 403 #define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) 405 404 #define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) 406 405 #define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) 406 + #define FIFOST_TYPE_KEY_CCM_JKEK (0x14 << FIFOST_TYPE_SHIFT) 407 407 #define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT) 408 408 #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) 409 409 #define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) ··· 1002 1000 #define OP_PCL_TLS12_AES_256_CBC_SHA256 0xff66 1003 1001 #define OP_PCL_TLS12_AES_256_CBC_SHA384 0xff63 1004 1002 #define OP_PCL_TLS12_AES_256_CBC_SHA512 0xff65 1003 + 1004 + /* Blob protocol protinfo bits */ 1005 + 1006 + #define OP_PCL_BLOB_BLACK 0x0004 1007 + #define OP_PCL_BLOB_EKT 0x0100 1005 1008 1006 1009 /* For DTLS - OP_PCLID_DTLS */ 1007 1010
+26
include/soc/fsl/caam-blob.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 2 /* 3 3 * Copyright (C) 2020 Pengutronix, Ahmad Fatoum <kernel@pengutronix.de> 4 + * Copyright 2024-2025 NXP 4 5 */ 5 6 6 7 #ifndef __CAAM_BLOB_GEN ··· 13 12 #define CAAM_BLOB_KEYMOD_LENGTH 16 14 13 #define CAAM_BLOB_OVERHEAD (32 + 16) 15 14 #define CAAM_BLOB_MAX_LEN 4096 15 + #define CAAM_ENC_ALGO_CCM 0x1 16 + #define CAAM_ENC_ALGO_ECB 0x2 17 + #define CAAM_NONCE_SIZE 6 18 + #define CAAM_ICV_SIZE 6 19 + #define CAAM_CCM_OVERHEAD (CAAM_NONCE_SIZE + CAAM_ICV_SIZE) 16 20 17 21 struct caam_blob_priv; 18 22 19 23 /** 24 + * struct caam_pkey_info - information for CAAM protected key 25 + * @is_pkey: flag to identify, if the key is protected. 26 + * @key_enc_algo: identifies the algorithm, ccm or ecb 27 + * @plain_key_sz: size of plain key. 28 + * @key_buf: contains key data 29 + */ 30 + struct caam_pkey_info { 31 + u8 is_pkey; 32 + u8 key_enc_algo; 33 + u16 plain_key_sz; 34 + u8 key_buf[]; 35 + } __packed; 36 + 37 + /* sizeof struct caam_pkey_info */ 38 + #define CAAM_PKEY_HEADER 4 39 + 40 + /** 20 41 * struct caam_blob_info - information for CAAM blobbing 42 + * @pkey_info: pointer to keep protected key information 21 43 * @input: pointer to input buffer (must be DMAable) 22 44 * @input_len: length of @input buffer in bytes. 23 45 * @output: pointer to output buffer (must be DMAable) ··· 50 26 * May not exceed %CAAM_BLOB_KEYMOD_LENGTH 51 27 */ 52 28 struct caam_blob_info { 29 + struct caam_pkey_info pkey_info; 30 + 53 31 void *input; 54 32 size_t input_len; 55 33
+108
security/keys/trusted-keys/trusted_caam.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 3 * Copyright (C) 2021 Pengutronix, Ahmad Fatoum <kernel@pengutronix.de> 4 + * Copyright 2025 NXP 4 5 */ 5 6 6 7 #include <keys/trusted_caam.h> 7 8 #include <keys/trusted-type.h> 8 9 #include <linux/build_bug.h> 9 10 #include <linux/key-type.h> 11 + #include <linux/parser.h> 10 12 #include <soc/fsl/caam-blob.h> 11 13 12 14 static struct caam_blob_priv *blobifier; ··· 17 15 18 16 static_assert(MAX_KEY_SIZE + CAAM_BLOB_OVERHEAD <= CAAM_BLOB_MAX_LEN); 19 17 static_assert(MAX_BLOB_SIZE <= CAAM_BLOB_MAX_LEN); 18 + 19 + enum { 20 + opt_err, 21 + opt_key_enc_algo, 22 + }; 23 + 24 + static const match_table_t key_tokens = { 25 + {opt_key_enc_algo, "key_enc_algo=%s"}, 26 + {opt_err, NULL} 27 + }; 28 + 29 + #ifdef CAAM_DEBUG 30 + static inline void dump_options(struct caam_pkey_info pkey_info) 31 + { 32 + pr_info("key encryption algo %d\n", pkey_info.key_enc_algo); 33 + } 34 + #else 35 + static inline void dump_options(struct caam_pkey_info pkey_info) 36 + { 37 + } 38 + #endif 39 + 40 + static int get_pkey_options(char *c, 41 + struct caam_pkey_info *pkey_info) 42 + { 43 + substring_t args[MAX_OPT_ARGS]; 44 + unsigned long token_mask = 0; 45 + u16 key_enc_algo; 46 + char *p = c; 47 + int token; 48 + int res; 49 + 50 + if (!c) 51 + return 0; 52 + 53 + while ((p = strsep(&c, " \t"))) { 54 + if (*p == '\0' || *p == ' ' || *p == '\t') 55 + continue; 56 + token = match_token(p, key_tokens, args); 57 + if (test_and_set_bit(token, &token_mask)) 58 + return -EINVAL; 59 + 60 + switch (token) { 61 + case opt_key_enc_algo: 62 + res = kstrtou16(args[0].from, 16, &key_enc_algo); 63 + if (res < 0) 64 + return -EINVAL; 65 + pkey_info->key_enc_algo = key_enc_algo; 66 + break; 67 + default: 68 + return -EINVAL; 69 + } 70 + } 71 + return 0; 72 + } 73 + 74 + static bool is_key_pkey(char **datablob) 75 + { 76 + char *c = NULL; 77 + 78 + do { 79 + /* Second argument onwards, 80 + * determine if tied to HW 81 + */ 82 + c = strsep(datablob, " \t"); 83 + if (c && (strcmp(c, "pk") == 0)) 84 + return true; 85 + } while (c); 86 + 87 + return false; 88 + } 20 89 21 90 static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob) 22 91 { ··· 98 25 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 99 26 }; 100 27 28 + /* 29 + * If it is to be treated as protected key, 30 + * read next arguments too. 31 + */ 32 + if (is_key_pkey(&datablob)) { 33 + info.pkey_info.plain_key_sz = p->key_len; 34 + info.pkey_info.is_pkey = 1; 35 + ret = get_pkey_options(datablob, &info.pkey_info); 36 + if (ret < 0) 37 + return 0; 38 + dump_options(info.pkey_info); 39 + } 40 + 101 41 ret = caam_encap_blob(blobifier, &info); 102 42 if (ret) 103 43 return ret; 104 44 105 45 p->blob_len = info.output_len; 46 + if (info.pkey_info.is_pkey) { 47 + p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 48 + memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 49 + memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 50 + } 51 + 106 52 return 0; 107 53 } 108 54 ··· 134 42 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 135 43 }; 136 44 45 + if (is_key_pkey(&datablob)) { 46 + info.pkey_info.plain_key_sz = p->blob_len - CAAM_BLOB_OVERHEAD; 47 + info.pkey_info.is_pkey = 1; 48 + ret = get_pkey_options(datablob, &info.pkey_info); 49 + if (ret < 0) 50 + return 0; 51 + dump_options(info.pkey_info); 52 + 53 + p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 54 + memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 55 + memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 56 + 57 + return 0; 58 + } 59 + 137 60 ret = caam_decap_blob(blobifier, &info); 138 61 if (ret) 139 62 return ret; 140 63 141 64 p->key_len = info.output_len; 65 + 142 66 return 0; 143 67 } 144 68