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
dump_options(const struct caam_pkey_info * pkey_info)32 static inline void dump_options(const struct caam_pkey_info *pkey_info)
33 {
34 pr_info("key encryption algo %d\n", pkey_info->key_enc_algo);
35 }
36 #else
dump_options(const struct caam_pkey_info * pkey_info)37 static inline void dump_options(const struct caam_pkey_info *pkey_info)
38 {
39 }
40 #endif
41
get_pkey_options(char * c,struct caam_pkey_info * pkey_info)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
is_key_pkey(char ** datablob)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
trusted_caam_seal(struct trusted_key_payload * p,char * datablob)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
trusted_caam_unseal(struct trusted_key_payload * p,char * datablob)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
trusted_caam_init(void)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
trusted_caam_exit(void)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