1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021 Pengutronix, Ahmad Fatoum <kernel@pengutronix.de> 4 * Copyright 2025 NXP 5 */ 6 7 #include <keys/trusted_caam.h> 8 #include <keys/trusted-type.h> 9 #include <linux/build_bug.h> 10 #include <linux/key-type.h> 11 #include <linux/parser.h> 12 #include <soc/fsl/caam-blob.h> 13 14 static struct caam_blob_priv *blobifier; 15 16 #define KEYMOD "SECURE_KEY" 17 18 static_assert(MAX_KEY_SIZE + CAAM_BLOB_OVERHEAD <= CAAM_BLOB_MAX_LEN); 19 static_assert(MAX_BLOB_SIZE <= CAAM_BLOB_MAX_LEN); 20 21 enum { 22 opt_err, 23 opt_key_enc_algo, 24 }; 25 26 static const match_table_t key_tokens = { 27 {opt_key_enc_algo, "key_enc_algo=%s"}, 28 {opt_err, NULL} 29 }; 30 31 #ifdef CONFIG_TRUSTED_KEYS_DEBUG 32 static inline void dump_options(const struct caam_pkey_info *pkey_info) 33 { 34 if (!trusted_debug) 35 return; 36 37 pr_debug("key encryption algo %d\n", pkey_info->key_enc_algo); 38 } 39 #else 40 static inline void dump_options(const struct caam_pkey_info *pkey_info) 41 { 42 } 43 #endif 44 45 static int get_pkey_options(char *c, 46 struct caam_pkey_info *pkey_info) 47 { 48 substring_t args[MAX_OPT_ARGS]; 49 unsigned long token_mask = 0; 50 u16 key_enc_algo; 51 char *p = c; 52 int token; 53 int res; 54 55 if (!c) 56 return 0; 57 58 while ((p = strsep(&c, " \t"))) { 59 if (*p == '\0' || *p == ' ' || *p == '\t') 60 continue; 61 token = match_token(p, key_tokens, args); 62 if (test_and_set_bit(token, &token_mask)) 63 return -EINVAL; 64 65 switch (token) { 66 case opt_key_enc_algo: 67 res = kstrtou16(args[0].from, 16, &key_enc_algo); 68 if (res < 0) 69 return -EINVAL; 70 pkey_info->key_enc_algo = key_enc_algo; 71 break; 72 default: 73 return -EINVAL; 74 } 75 } 76 return 0; 77 } 78 79 static bool is_key_pkey(char **datablob) 80 { 81 char *c = NULL; 82 83 do { 84 /* Second argument onwards, 85 * determine if tied to HW 86 */ 87 c = strsep(datablob, " \t"); 88 if (c && (strcmp(c, "pk") == 0)) 89 return true; 90 } while (c); 91 92 return false; 93 } 94 95 static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob) 96 { 97 int ret; 98 struct caam_blob_info info = { 99 .input = p->key, .input_len = p->key_len, 100 .output = p->blob, .output_len = MAX_BLOB_SIZE, 101 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 102 }; 103 104 /* 105 * If it is to be treated as protected key, 106 * read next arguments too. 107 */ 108 if (is_key_pkey(&datablob)) { 109 info.pkey_info.plain_key_sz = p->key_len; 110 info.pkey_info.is_pkey = 1; 111 ret = get_pkey_options(datablob, &info.pkey_info); 112 if (ret < 0) 113 return 0; 114 dump_options(&info.pkey_info); 115 } 116 117 ret = caam_encap_blob(blobifier, &info); 118 if (ret) 119 return ret; 120 121 p->blob_len = info.output_len; 122 if (info.pkey_info.is_pkey) { 123 p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 124 memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 125 memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 126 } 127 128 return 0; 129 } 130 131 static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob) 132 { 133 int ret; 134 struct caam_blob_info info = { 135 .input = p->blob, .input_len = p->blob_len, 136 .output = p->key, .output_len = MAX_KEY_SIZE, 137 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 138 }; 139 140 if (is_key_pkey(&datablob)) { 141 info.pkey_info.plain_key_sz = p->blob_len - CAAM_BLOB_OVERHEAD; 142 info.pkey_info.is_pkey = 1; 143 ret = get_pkey_options(datablob, &info.pkey_info); 144 if (ret < 0) 145 return 0; 146 dump_options(&info.pkey_info); 147 148 p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 149 memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 150 memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 151 152 return 0; 153 } 154 155 ret = caam_decap_blob(blobifier, &info); 156 if (ret) 157 return ret; 158 159 p->key_len = info.output_len; 160 161 return 0; 162 } 163 164 static int trusted_caam_init(void) 165 { 166 int ret; 167 168 blobifier = caam_blob_gen_init(); 169 if (IS_ERR(blobifier)) 170 return PTR_ERR(blobifier); 171 172 ret = register_key_type(&key_type_trusted); 173 if (ret) 174 caam_blob_gen_exit(blobifier); 175 176 return ret; 177 } 178 179 static void trusted_caam_exit(void) 180 { 181 unregister_key_type(&key_type_trusted); 182 caam_blob_gen_exit(blobifier); 183 } 184 185 struct trusted_key_ops trusted_key_caam_ops = { 186 .migratable = 0, /* non-migratable */ 187 .init = trusted_caam_init, 188 .seal = trusted_caam_seal, 189 .unseal = trusted_caam_unseal, 190 .exit = trusted_caam_exit, 191 }; 192