Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * pkey pckmo specific code
4 *
5 * Copyright IBM Corp. 2024
6 */
7
8#define pr_fmt(fmt) "pkey: " fmt
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/cpufeature.h>
13#include <asm/cpacf.h>
14#include <crypto/aes.h>
15#include <linux/random.h>
16
17#include "zcrypt_ccamisc.h"
18#include "pkey_base.h"
19
20MODULE_LICENSE("GPL");
21MODULE_AUTHOR("IBM Corporation");
22MODULE_DESCRIPTION("s390 protected key PCKMO handler");
23
24/*
25 * Check key blob for known and supported here.
26 */
27static bool is_pckmo_key(const u8 *key, u32 keylen)
28{
29 struct keytoken_header *hdr = (struct keytoken_header *)key;
30 struct clearkeytoken *t = (struct clearkeytoken *)key;
31
32 if (keylen < sizeof(*hdr))
33 return false;
34
35 switch (hdr->type) {
36 case TOKTYPE_NON_CCA:
37 switch (hdr->version) {
38 case TOKVER_CLEAR_KEY:
39 if (pkey_keytype_to_size(t->keytype))
40 return true;
41 return false;
42 case TOKVER_PROTECTED_KEY:
43 return true;
44 default:
45 return false;
46 }
47 default:
48 return false;
49 }
50}
51
52static bool is_pckmo_keytype(enum pkey_key_type keytype)
53{
54 switch (keytype) {
55 case PKEY_TYPE_PROTKEY:
56 return true;
57 default:
58 return false;
59 }
60}
61
62/*
63 * Create a protected key from a clear key value via PCKMO instruction.
64 */
65static int pckmo_clr2protkey(u32 keytype, const u8 *clrkey, u32 clrkeylen,
66 u8 *protkey, u32 *protkeylen, u32 *protkeytype)
67{
68 /* mask of available pckmo subfunctions */
69 static cpacf_mask_t pckmo_functions;
70
71 int keysize, rc = -EINVAL;
72 u8 paramblock[160];
73 u32 pkeytype = 0;
74 unsigned int fc;
75
76 switch (keytype) {
77 case PKEY_KEYTYPE_AES_128:
78 fc = CPACF_PCKMO_ENC_AES_128_KEY;
79 break;
80 case PKEY_KEYTYPE_AES_192:
81 fc = CPACF_PCKMO_ENC_AES_192_KEY;
82 break;
83 case PKEY_KEYTYPE_AES_256:
84 fc = CPACF_PCKMO_ENC_AES_256_KEY;
85 break;
86 case PKEY_KEYTYPE_ECC_P256:
87 pkeytype = PKEY_KEYTYPE_ECC;
88 fc = CPACF_PCKMO_ENC_ECC_P256_KEY;
89 break;
90 case PKEY_KEYTYPE_ECC_P384:
91 pkeytype = PKEY_KEYTYPE_ECC;
92 fc = CPACF_PCKMO_ENC_ECC_P384_KEY;
93 break;
94 case PKEY_KEYTYPE_ECC_P521:
95 pkeytype = PKEY_KEYTYPE_ECC;
96 fc = CPACF_PCKMO_ENC_ECC_P521_KEY;
97 break;
98 case PKEY_KEYTYPE_ECC_ED25519:
99 pkeytype = PKEY_KEYTYPE_ECC;
100 fc = CPACF_PCKMO_ENC_ECC_ED25519_KEY;
101 break;
102 case PKEY_KEYTYPE_ECC_ED448:
103 pkeytype = PKEY_KEYTYPE_ECC;
104 fc = CPACF_PCKMO_ENC_ECC_ED448_KEY;
105 break;
106 case PKEY_KEYTYPE_AES_XTS_128:
107 fc = CPACF_PCKMO_ENC_AES_XTS_128_DOUBLE_KEY;
108 break;
109 case PKEY_KEYTYPE_AES_XTS_256:
110 fc = CPACF_PCKMO_ENC_AES_XTS_256_DOUBLE_KEY;
111 break;
112 case PKEY_KEYTYPE_HMAC_512:
113 fc = CPACF_PCKMO_ENC_HMAC_512_KEY;
114 break;
115 case PKEY_KEYTYPE_HMAC_1024:
116 fc = CPACF_PCKMO_ENC_HMAC_1024_KEY;
117 break;
118 default:
119 PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n",
120 __func__, keytype);
121 goto out;
122 }
123
124 keysize = pkey_keytype_to_size(keytype);
125 pkeytype = pkeytype ?: keytype;
126
127 if (clrkeylen && clrkeylen < keysize) {
128 PKEY_DBF_ERR("%s clear key size too small: %u < %d\n",
129 __func__, clrkeylen, keysize);
130 goto out;
131 }
132 if (*protkeylen < keysize + AES_WK_VP_SIZE) {
133 PKEY_DBF_ERR("%s prot key buffer size too small: %u < %d\n",
134 __func__, *protkeylen, keysize + AES_WK_VP_SIZE);
135 goto out;
136 }
137
138 /* Did we already check for PCKMO ? */
139 if (!pckmo_functions.bytes[0]) {
140 /* no, so check now */
141 if (!cpacf_query(CPACF_PCKMO, &pckmo_functions)) {
142 PKEY_DBF_ERR("%s cpacf_query() failed\n", __func__);
143 rc = -ENODEV;
144 goto out;
145 }
146 }
147 /* check for the pckmo subfunction we need now */
148 if (!cpacf_test_func(&pckmo_functions, fc)) {
149 PKEY_DBF_ERR("%s pckmo fc 0x%02x not available\n",
150 __func__, fc);
151 rc = -ENODEV;
152 goto out;
153 }
154
155 /* prepare param block */
156 memset(paramblock, 0, sizeof(paramblock));
157 memcpy(paramblock, clrkey, keysize);
158
159 /* call the pckmo instruction */
160 cpacf_pckmo(fc, paramblock);
161
162 /* copy created protected key to key buffer including the wkvp block */
163 *protkeylen = keysize + AES_WK_VP_SIZE;
164 memcpy(protkey, paramblock, *protkeylen);
165 *protkeytype = pkeytype;
166
167 rc = 0;
168
169out:
170 pr_debug("rc=%d\n", rc);
171 return rc;
172}
173
174/*
175 * Verify a raw protected key blob.
176 */
177static int pckmo_verify_protkey(const u8 *protkey, u32 protkeylen,
178 u32 protkeytype)
179{
180 u8 clrkey[16] = { 0 }, tmpkeybuf[16 + AES_WK_VP_SIZE];
181 u32 tmpkeybuflen, tmpkeytype;
182 int keysize, rc = -EINVAL;
183 u8 *wkvp;
184
185 /* check protkey type and size */
186 keysize = pkey_keytype_to_size(protkeytype);
187 if (!keysize) {
188 PKEY_DBF_ERR("%s unknown/unsupported keytype %u\n", __func__,
189 protkeytype);
190 goto out;
191 }
192 if (protkeylen < keysize + AES_WK_VP_SIZE)
193 goto out;
194
195 /* generate a dummy AES 128 protected key */
196 tmpkeybuflen = sizeof(tmpkeybuf);
197 rc = pckmo_clr2protkey(PKEY_KEYTYPE_AES_128,
198 clrkey, sizeof(clrkey),
199 tmpkeybuf, &tmpkeybuflen, &tmpkeytype);
200 if (rc)
201 goto out;
202 memzero_explicit(tmpkeybuf, 16);
203 wkvp = tmpkeybuf + 16;
204
205 /* compare WK VP from the temp key with that of the given prot key */
206 if (memcmp(wkvp, protkey + keysize, AES_WK_VP_SIZE)) {
207 PKEY_DBF_ERR("%s protected key WK VP mismatch\n", __func__);
208 rc = -EKEYREJECTED;
209 goto out;
210 }
211
212out:
213 pr_debug("rc=%d\n", rc);
214 return rc;
215}
216
217static int pckmo_key2protkey(const u8 *key, u32 keylen,
218 u8 *protkey, u32 *protkeylen, u32 *protkeytype)
219{
220 struct keytoken_header *hdr = (struct keytoken_header *)key;
221 int rc = -EINVAL;
222
223 if (keylen < sizeof(*hdr))
224 return -EINVAL;
225 if (hdr->type != TOKTYPE_NON_CCA)
226 return -EINVAL;
227
228 switch (hdr->version) {
229 case TOKVER_PROTECTED_KEY: {
230 struct protkeytoken *t = (struct protkeytoken *)key;
231 u32 keysize;
232
233 if (keylen < sizeof(*t))
234 goto out;
235 keysize = pkey_keytype_to_size(t->keytype);
236 if (!keysize) {
237 PKEY_DBF_ERR("%s protected key token: unknown keytype %u\n",
238 __func__, t->keytype);
239 goto out;
240 }
241 switch (t->keytype) {
242 case PKEY_KEYTYPE_AES_128:
243 case PKEY_KEYTYPE_AES_192:
244 case PKEY_KEYTYPE_AES_256:
245 if (t->len != keysize + AES_WK_VP_SIZE ||
246 keylen < sizeof(struct protaeskeytoken))
247 goto out;
248 rc = pckmo_verify_protkey(t->protkey, t->len,
249 t->keytype);
250 if (rc)
251 goto out;
252 break;
253 default:
254 if (t->len != keysize + AES_WK_VP_SIZE ||
255 keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE)
256 goto out;
257 break;
258 }
259 memcpy(protkey, t->protkey, t->len);
260 *protkeylen = t->len;
261 *protkeytype = t->keytype;
262 rc = 0;
263 break;
264 }
265 case TOKVER_CLEAR_KEY: {
266 struct clearkeytoken *t = (struct clearkeytoken *)key;
267 u32 keysize;
268
269 if (keylen < sizeof(*t) ||
270 keylen < sizeof(*t) + t->len)
271 goto out;
272 keysize = pkey_keytype_to_size(t->keytype);
273 if (!keysize) {
274 PKEY_DBF_ERR("%s clear key token: unknown keytype %u\n",
275 __func__, t->keytype);
276 goto out;
277 }
278 if (t->len != keysize) {
279 PKEY_DBF_ERR("%s clear key token: invalid key len %u\n",
280 __func__, t->len);
281 goto out;
282 }
283 rc = pckmo_clr2protkey(t->keytype, t->clearkey, t->len,
284 protkey, protkeylen, protkeytype);
285 break;
286 }
287 default:
288 PKEY_DBF_ERR("%s unknown non-CCA token version %d\n",
289 __func__, hdr->version);
290 break;
291 }
292
293out:
294 pr_debug("rc=%d\n", rc);
295 return rc;
296}
297
298/*
299 * Generate a random protected key.
300 */
301static int pckmo_gen_protkey(u32 keytype, u32 subtype,
302 u8 *protkey, u32 *protkeylen, u32 *protkeytype)
303{
304 u8 clrkey[128];
305 int keysize;
306 int rc;
307
308 keysize = pkey_keytype_to_size(keytype);
309 if (!keysize) {
310 PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",
311 __func__, keytype);
312 return -EINVAL;
313 }
314 if (subtype != PKEY_TYPE_PROTKEY) {
315 PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",
316 __func__, subtype);
317 return -EINVAL;
318 }
319
320 switch (keytype) {
321 case PKEY_KEYTYPE_AES_128:
322 case PKEY_KEYTYPE_AES_192:
323 case PKEY_KEYTYPE_AES_256:
324 case PKEY_KEYTYPE_AES_XTS_128:
325 case PKEY_KEYTYPE_AES_XTS_256:
326 case PKEY_KEYTYPE_HMAC_512:
327 case PKEY_KEYTYPE_HMAC_1024:
328 break;
329 default:
330 PKEY_DBF_ERR("%s unsupported keytype %d\n",
331 __func__, keytype);
332 return -EINVAL;
333 }
334
335 /* generate a dummy random clear key */
336 get_random_bytes(clrkey, keysize);
337
338 /* convert it to a dummy protected key */
339 rc = pckmo_clr2protkey(keytype, clrkey, keysize,
340 protkey, protkeylen, protkeytype);
341 if (rc)
342 goto out;
343
344 /* replace the key part of the protected key with random bytes */
345 get_random_bytes(protkey, keysize);
346
347out:
348 pr_debug("rc=%d\n", rc);
349 return rc;
350}
351
352/*
353 * Verify a protected key token blob.
354 */
355static int pckmo_verify_key(const u8 *key, u32 keylen)
356{
357 struct keytoken_header *hdr = (struct keytoken_header *)key;
358 int rc = -EINVAL;
359
360 if (keylen < sizeof(*hdr))
361 return -EINVAL;
362 if (hdr->type != TOKTYPE_NON_CCA)
363 return -EINVAL;
364
365 switch (hdr->version) {
366 case TOKVER_PROTECTED_KEY: {
367 struct protkeytoken *t = (struct protkeytoken *)key;
368 u32 keysize;
369
370 if (keylen < sizeof(*t))
371 goto out;
372 keysize = pkey_keytype_to_size(t->keytype);
373 if (!keysize || t->len != keysize + AES_WK_VP_SIZE)
374 goto out;
375 switch (t->keytype) {
376 case PKEY_KEYTYPE_AES_128:
377 case PKEY_KEYTYPE_AES_192:
378 case PKEY_KEYTYPE_AES_256:
379 if (keylen < sizeof(struct protaeskeytoken))
380 goto out;
381 break;
382 default:
383 if (keylen < sizeof(*t) + keysize + AES_WK_VP_SIZE)
384 goto out;
385 break;
386 }
387 rc = pckmo_verify_protkey(t->protkey, t->len, t->keytype);
388 break;
389 }
390 default:
391 PKEY_DBF_ERR("%s unknown non-CCA token version %d\n",
392 __func__, hdr->version);
393 break;
394 }
395
396out:
397 pr_debug("rc=%d\n", rc);
398 return rc;
399}
400
401/*
402 * Wrapper functions used for the pkey handler struct
403 */
404
405static int pkey_pckmo_key2protkey(const struct pkey_apqn *_apqns,
406 size_t _nr_apqns,
407 const u8 *key, u32 keylen,
408 u8 *protkey, u32 *protkeylen, u32 *keyinfo,
409 u32 _xflags __always_unused)
410{
411 return pckmo_key2protkey(key, keylen,
412 protkey, protkeylen, keyinfo);
413}
414
415static int pkey_pckmo_gen_key(const struct pkey_apqn *_apqns, size_t _nr_apqns,
416 u32 keytype, u32 keysubtype,
417 u32 _keybitsize, u32 _flags,
418 u8 *keybuf, u32 *keybuflen, u32 *keyinfo,
419 u32 _xflags __always_unused)
420{
421 return pckmo_gen_protkey(keytype, keysubtype,
422 keybuf, keybuflen, keyinfo);
423}
424
425static int pkey_pckmo_verifykey(const u8 *key, u32 keylen,
426 u16 *_card, u16 *_dom,
427 u32 *_keytype, u32 *_keybitsize,
428 u32 *_flags, u32 _xflags __always_unused)
429{
430 return pckmo_verify_key(key, keylen);
431}
432
433static struct pkey_handler pckmo_handler = {
434 .module = THIS_MODULE,
435 .name = "PKEY PCKMO handler",
436 .is_supported_key = is_pckmo_key,
437 .is_supported_keytype = is_pckmo_keytype,
438 .key_to_protkey = pkey_pckmo_key2protkey,
439 .gen_key = pkey_pckmo_gen_key,
440 .verify_key = pkey_pckmo_verifykey,
441};
442
443/*
444 * Module init
445 */
446static int __init pkey_pckmo_init(void)
447{
448 cpacf_mask_t func_mask;
449
450 /*
451 * The pckmo instruction should be available - even if we don't
452 * actually invoke it. This instruction comes with MSA 3 which
453 * is also the minimum level for the kmc instructions which
454 * are able to work with protected keys.
455 */
456 if (!cpacf_query(CPACF_PCKMO, &func_mask))
457 return -ENODEV;
458
459 /* register this module as pkey handler for all the pckmo stuff */
460 return pkey_handler_register(&pckmo_handler);
461}
462
463/*
464 * Module exit
465 */
466static void __exit pkey_pckmo_exit(void)
467{
468 /* unregister this module as pkey handler */
469 pkey_handler_unregister(&pckmo_handler);
470}
471
472module_cpu_feature_match(S390_CPU_FEATURE_MSA, pkey_pckmo_init);
473module_exit(pkey_pckmo_exit);