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 CAAM_DEBUG 32 static inline void dump_options(struct caam_pkey_info pkey_info) 33 { 34 pr_info("key encryption algo %d\n", pkey_info.key_enc_algo); 35 } 36 #else 37 static inline void dump_options(struct caam_pkey_info pkey_info) 38 { 39 } 40 #endif 41 42 static int get_pkey_options(char *c, 43 struct caam_pkey_info *pkey_info) 44 { 45 substring_t args[MAX_OPT_ARGS]; 46 unsigned long token_mask = 0; 47 u16 key_enc_algo; 48 char *p = c; 49 int token; 50 int res; 51 52 if (!c) 53 return 0; 54 55 while ((p = strsep(&c, " \t"))) { 56 if (*p == '\0' || *p == ' ' || *p == '\t') 57 continue; 58 token = match_token(p, key_tokens, args); 59 if (test_and_set_bit(token, &token_mask)) 60 return -EINVAL; 61 62 switch (token) { 63 case opt_key_enc_algo: 64 res = kstrtou16(args[0].from, 16, &key_enc_algo); 65 if (res < 0) 66 return -EINVAL; 67 pkey_info->key_enc_algo = key_enc_algo; 68 break; 69 default: 70 return -EINVAL; 71 } 72 } 73 return 0; 74 } 75 76 static bool is_key_pkey(char **datablob) 77 { 78 char *c = NULL; 79 80 do { 81 /* Second argument onwards, 82 * determine if tied to HW 83 */ 84 c = strsep(datablob, " \t"); 85 if (c && (strcmp(c, "pk") == 0)) 86 return true; 87 } while (c); 88 89 return false; 90 } 91 92 static int trusted_caam_seal(struct trusted_key_payload *p, char *datablob) 93 { 94 int ret; 95 struct caam_blob_info info = { 96 .input = p->key, .input_len = p->key_len, 97 .output = p->blob, .output_len = MAX_BLOB_SIZE, 98 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 99 }; 100 101 /* 102 * If it is to be treated as protected key, 103 * read next arguments too. 104 */ 105 if (is_key_pkey(&datablob)) { 106 info.pkey_info.plain_key_sz = p->key_len; 107 info.pkey_info.is_pkey = 1; 108 ret = get_pkey_options(datablob, &info.pkey_info); 109 if (ret < 0) 110 return 0; 111 dump_options(info.pkey_info); 112 } 113 114 ret = caam_encap_blob(blobifier, &info); 115 if (ret) 116 return ret; 117 118 p->blob_len = info.output_len; 119 if (info.pkey_info.is_pkey) { 120 p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 121 memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 122 memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 123 } 124 125 return 0; 126 } 127 128 static int trusted_caam_unseal(struct trusted_key_payload *p, char *datablob) 129 { 130 int ret; 131 struct caam_blob_info info = { 132 .input = p->blob, .input_len = p->blob_len, 133 .output = p->key, .output_len = MAX_KEY_SIZE, 134 .key_mod = KEYMOD, .key_mod_len = sizeof(KEYMOD) - 1, 135 }; 136 137 if (is_key_pkey(&datablob)) { 138 info.pkey_info.plain_key_sz = p->blob_len - CAAM_BLOB_OVERHEAD; 139 info.pkey_info.is_pkey = 1; 140 ret = get_pkey_options(datablob, &info.pkey_info); 141 if (ret < 0) 142 return 0; 143 dump_options(info.pkey_info); 144 145 p->key_len = p->blob_len + sizeof(struct caam_pkey_info); 146 memcpy(p->key, &info.pkey_info, sizeof(struct caam_pkey_info)); 147 memcpy(p->key + sizeof(struct caam_pkey_info), p->blob, p->blob_len); 148 149 return 0; 150 } 151 152 ret = caam_decap_blob(blobifier, &info); 153 if (ret) 154 return ret; 155 156 p->key_len = info.output_len; 157 158 return 0; 159 } 160 161 static int trusted_caam_init(void) 162 { 163 int ret; 164 165 blobifier = caam_blob_gen_init(); 166 if (IS_ERR(blobifier)) 167 return PTR_ERR(blobifier); 168 169 ret = register_key_type(&key_type_trusted); 170 if (ret) 171 caam_blob_gen_exit(blobifier); 172 173 return ret; 174 } 175 176 static void trusted_caam_exit(void) 177 { 178 unregister_key_type(&key_type_trusted); 179 caam_blob_gen_exit(blobifier); 180 } 181 182 struct trusted_key_ops trusted_key_caam_ops = { 183 .migratable = 0, /* non-migratable */ 184 .init = trusted_caam_init, 185 .seal = trusted_caam_seal, 186 .unseal = trusted_caam_unseal, 187 .exit = trusted_caam_exit, 188 }; 189