xref: /linux/security/keys/trusted-keys/trusted_caam.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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