630 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * pkey cca specific code4 *5 * Copyright IBM Corp. 20246 */7 8#define KMSG_COMPONENT "pkey"9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt10 11#include <linux/init.h>12#include <linux/module.h>13#include <linux/cpufeature.h>14 15#include "zcrypt_api.h"16#include "zcrypt_ccamisc.h"17#include "pkey_base.h"18 19MODULE_LICENSE("GPL");20MODULE_AUTHOR("IBM Corporation");21MODULE_DESCRIPTION("s390 protected key CCA handler");22 23#if IS_MODULE(CONFIG_PKEY_CCA)24static struct ap_device_id pkey_cca_card_ids[] = {25 { .dev_type = AP_DEVICE_TYPE_CEX4 },26 { .dev_type = AP_DEVICE_TYPE_CEX5 },27 { .dev_type = AP_DEVICE_TYPE_CEX6 },28 { .dev_type = AP_DEVICE_TYPE_CEX7 },29 { .dev_type = AP_DEVICE_TYPE_CEX8 },30 { /* end of list */ },31};32MODULE_DEVICE_TABLE(ap, pkey_cca_card_ids);33#endif34 35/*36 * Check key blob for known and supported CCA key.37 */38static bool is_cca_key(const u8 *key, u32 keylen)39{40 struct keytoken_header *hdr = (struct keytoken_header *)key;41 42 if (keylen < sizeof(*hdr))43 return false;44 45 switch (hdr->type) {46 case TOKTYPE_CCA_INTERNAL:47 switch (hdr->version) {48 case TOKVER_CCA_AES:49 case TOKVER_CCA_VLSC:50 return true;51 default:52 return false;53 }54 case TOKTYPE_CCA_INTERNAL_PKA:55 return true;56 default:57 return false;58 }59}60 61static bool is_cca_keytype(enum pkey_key_type key_type)62{63 switch (key_type) {64 case PKEY_TYPE_CCA_DATA:65 case PKEY_TYPE_CCA_CIPHER:66 case PKEY_TYPE_CCA_ECC:67 return true;68 default:69 return false;70 }71}72 73static int cca_apqns4key(const u8 *key, u32 keylen, u32 flags,74 struct pkey_apqn *apqns, size_t *nr_apqns)75{76 struct keytoken_header *hdr = (struct keytoken_header *)key;77 u32 _nr_apqns, *_apqns = NULL;78 int rc;79 80 if (!flags)81 flags = PKEY_FLAGS_MATCH_CUR_MKVP | PKEY_FLAGS_MATCH_ALT_MKVP;82 83 if (keylen < sizeof(struct keytoken_header))84 return -EINVAL;85 86 zcrypt_wait_api_operational();87 88 if (hdr->type == TOKTYPE_CCA_INTERNAL) {89 u64 cur_mkvp = 0, old_mkvp = 0;90 int minhwtype = ZCRYPT_CEX3C;91 92 if (hdr->version == TOKVER_CCA_AES) {93 struct secaeskeytoken *t = (struct secaeskeytoken *)key;94 95 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)96 cur_mkvp = t->mkvp;97 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)98 old_mkvp = t->mkvp;99 } else if (hdr->version == TOKVER_CCA_VLSC) {100 struct cipherkeytoken *t = (struct cipherkeytoken *)key;101 102 minhwtype = ZCRYPT_CEX6;103 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)104 cur_mkvp = t->mkvp0;105 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)106 old_mkvp = t->mkvp0;107 } else {108 /* unknown CCA internal token type */109 return -EINVAL;110 }111 rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,112 minhwtype, AES_MK_SET,113 cur_mkvp, old_mkvp, 1);114 if (rc)115 goto out;116 117 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {118 struct eccprivkeytoken *t = (struct eccprivkeytoken *)key;119 u64 cur_mkvp = 0, old_mkvp = 0;120 121 if (t->secid == 0x20) {122 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)123 cur_mkvp = t->mkvp;124 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)125 old_mkvp = t->mkvp;126 } else {127 /* unknown CCA internal 2 token type */128 return -EINVAL;129 }130 rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,131 ZCRYPT_CEX7, APKA_MK_SET,132 cur_mkvp, old_mkvp, 1);133 if (rc)134 goto out;135 136 } else {137 PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",138 __func__, hdr->type, hdr->version);139 return -EINVAL;140 }141 142 if (apqns) {143 if (*nr_apqns < _nr_apqns)144 rc = -ENOSPC;145 else146 memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));147 }148 *nr_apqns = _nr_apqns;149 150out:151 kfree(_apqns);152 pr_debug("rc=%d\n", rc);153 return rc;154}155 156static int cca_apqns4type(enum pkey_key_type ktype,157 u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,158 struct pkey_apqn *apqns, size_t *nr_apqns)159{160 u32 _nr_apqns, *_apqns = NULL;161 int rc;162 163 zcrypt_wait_api_operational();164 165 if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {166 u64 cur_mkvp = 0, old_mkvp = 0;167 int minhwtype = ZCRYPT_CEX3C;168 169 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)170 cur_mkvp = *((u64 *)cur_mkvp);171 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)172 old_mkvp = *((u64 *)alt_mkvp);173 if (ktype == PKEY_TYPE_CCA_CIPHER)174 minhwtype = ZCRYPT_CEX6;175 rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,176 minhwtype, AES_MK_SET,177 cur_mkvp, old_mkvp, 1);178 if (rc)179 goto out;180 181 } else if (ktype == PKEY_TYPE_CCA_ECC) {182 u64 cur_mkvp = 0, old_mkvp = 0;183 184 if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)185 cur_mkvp = *((u64 *)cur_mkvp);186 if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)187 old_mkvp = *((u64 *)alt_mkvp);188 rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,189 ZCRYPT_CEX7, APKA_MK_SET,190 cur_mkvp, old_mkvp, 1);191 if (rc)192 goto out;193 194 } else {195 PKEY_DBF_ERR("%s unknown/unsupported key type %d",196 __func__, (int)ktype);197 return -EINVAL;198 }199 200 if (apqns) {201 if (*nr_apqns < _nr_apqns)202 rc = -ENOSPC;203 else204 memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));205 }206 *nr_apqns = _nr_apqns;207 208out:209 kfree(_apqns);210 pr_debug("rc=%d\n", rc);211 return rc;212}213 214static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,215 const u8 *key, u32 keylen,216 u8 *protkey, u32 *protkeylen, u32 *protkeytype)217{218 struct keytoken_header *hdr = (struct keytoken_header *)key;219 struct pkey_apqn *local_apqns = NULL;220 int i, rc;221 222 if (keylen < sizeof(*hdr))223 return -EINVAL;224 225 if (hdr->type == TOKTYPE_CCA_INTERNAL &&226 hdr->version == TOKVER_CCA_AES) {227 /* CCA AES data key */228 if (keylen != sizeof(struct secaeskeytoken))229 return -EINVAL;230 if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))231 return -EINVAL;232 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&233 hdr->version == TOKVER_CCA_VLSC) {234 /* CCA AES cipher key */235 if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)236 return -EINVAL;237 if (cca_check_secaescipherkey(pkey_dbf_info,238 3, key, 0, 1))239 return -EINVAL;240 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {241 /* CCA ECC (private) key */242 if (keylen < sizeof(struct eccprivkeytoken))243 return -EINVAL;244 if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))245 return -EINVAL;246 } else {247 PKEY_DBF_ERR("%s unknown/unsupported blob type %d version %d\n",248 __func__, hdr->type, hdr->version);249 return -EINVAL;250 }251 252 zcrypt_wait_api_operational();253 254 if (!apqns || (nr_apqns == 1 &&255 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {256 nr_apqns = MAXAPQNSINLIST;257 local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),258 GFP_KERNEL);259 if (!local_apqns)260 return -ENOMEM;261 rc = cca_apqns4key(key, keylen, 0, local_apqns, &nr_apqns);262 if (rc)263 goto out;264 apqns = local_apqns;265 }266 267 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {268 if (hdr->type == TOKTYPE_CCA_INTERNAL &&269 hdr->version == TOKVER_CCA_AES) {270 rc = cca_sec2protkey(apqns[i].card, apqns[i].domain,271 key, protkey,272 protkeylen, protkeytype);273 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&274 hdr->version == TOKVER_CCA_VLSC) {275 rc = cca_cipher2protkey(apqns[i].card, apqns[i].domain,276 key, protkey,277 protkeylen, protkeytype);278 } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {279 rc = cca_ecc2protkey(apqns[i].card, apqns[i].domain,280 key, protkey,281 protkeylen, protkeytype);282 } else {283 rc = -EINVAL;284 break;285 }286 }287 288out:289 kfree(local_apqns);290 pr_debug("rc=%d\n", rc);291 return rc;292}293 294/*295 * Generate CCA secure key.296 * As of now only CCA AES Data or Cipher secure keys are297 * supported.298 * keytype is one of the PKEY_KEYTYPE_* constants,299 * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,300 * keybitsize is the bit size of the key (may be 0 for301 * keytype PKEY_KEYTYPE_AES_*).302 */303static int cca_gen_key(const struct pkey_apqn *apqns, size_t nr_apqns,304 u32 keytype, u32 subtype,305 u32 keybitsize, u32 flags,306 u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)307{308 struct pkey_apqn *local_apqns = NULL;309 int i, len, rc;310 311 /* check keytype, subtype, keybitsize */312 switch (keytype) {313 case PKEY_KEYTYPE_AES_128:314 case PKEY_KEYTYPE_AES_192:315 case PKEY_KEYTYPE_AES_256:316 len = pkey_keytype_aes_to_size(keytype);317 if (keybitsize && keybitsize != 8 * len) {318 PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",319 __func__, keybitsize);320 return -EINVAL;321 }322 keybitsize = 8 * len;323 switch (subtype) {324 case PKEY_TYPE_CCA_DATA:325 case PKEY_TYPE_CCA_CIPHER:326 break;327 default:328 PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",329 __func__, subtype);330 return -EINVAL;331 }332 break;333 default:334 PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",335 __func__, keytype);336 return -EINVAL;337 }338 339 zcrypt_wait_api_operational();340 341 if (!apqns || (nr_apqns == 1 &&342 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {343 nr_apqns = MAXAPQNSINLIST;344 local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),345 GFP_KERNEL);346 if (!local_apqns)347 return -ENOMEM;348 rc = cca_apqns4type(subtype, NULL, NULL, 0,349 local_apqns, &nr_apqns);350 if (rc)351 goto out;352 apqns = local_apqns;353 }354 355 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {356 if (subtype == PKEY_TYPE_CCA_CIPHER) {357 rc = cca_gencipherkey(apqns[i].card, apqns[i].domain,358 keybitsize, flags,359 keybuf, keybuflen);360 } else {361 /* PKEY_TYPE_CCA_DATA */362 rc = cca_genseckey(apqns[i].card, apqns[i].domain,363 keybitsize, keybuf);364 *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);365 }366 }367 368out:369 kfree(local_apqns);370 pr_debug("rc=%d\n", rc);371 return rc;372}373 374/*375 * Generate CCA secure key with given clear key value.376 * As of now only CCA AES Data or Cipher secure keys are377 * supported.378 * keytype is one of the PKEY_KEYTYPE_* constants,379 * subtype may be 0 or PKEY_TYPE_CCA_DATA or PKEY_TYPE_CCA_CIPHER,380 * keybitsize is the bit size of the key (may be 0 for381 * keytype PKEY_KEYTYPE_AES_*).382 */383static int cca_clr2key(const struct pkey_apqn *apqns, size_t nr_apqns,384 u32 keytype, u32 subtype,385 u32 keybitsize, u32 flags,386 const u8 *clrkey, u32 clrkeylen,387 u8 *keybuf, u32 *keybuflen, u32 *_keyinfo)388{389 struct pkey_apqn *local_apqns = NULL;390 int i, len, rc;391 392 /* check keytype, subtype, clrkeylen, keybitsize */393 switch (keytype) {394 case PKEY_KEYTYPE_AES_128:395 case PKEY_KEYTYPE_AES_192:396 case PKEY_KEYTYPE_AES_256:397 len = pkey_keytype_aes_to_size(keytype);398 if (keybitsize && keybitsize != 8 * len) {399 PKEY_DBF_ERR("%s unknown/unsupported keybitsize %d\n",400 __func__, keybitsize);401 return -EINVAL;402 }403 keybitsize = 8 * len;404 if (clrkeylen != len) {405 PKEY_DBF_ERR("%s invalid clear key len %d != %d\n",406 __func__, clrkeylen, len);407 return -EINVAL;408 }409 switch (subtype) {410 case PKEY_TYPE_CCA_DATA:411 case PKEY_TYPE_CCA_CIPHER:412 break;413 default:414 PKEY_DBF_ERR("%s unknown/unsupported subtype %d\n",415 __func__, subtype);416 return -EINVAL;417 }418 break;419 default:420 PKEY_DBF_ERR("%s unknown/unsupported keytype %d\n",421 __func__, keytype);422 return -EINVAL;423 }424 425 zcrypt_wait_api_operational();426 427 if (!apqns || (nr_apqns == 1 &&428 apqns[0].card == 0xFFFF && apqns[0].domain == 0xFFFF)) {429 nr_apqns = MAXAPQNSINLIST;430 local_apqns = kmalloc_array(nr_apqns, sizeof(struct pkey_apqn),431 GFP_KERNEL);432 if (!local_apqns)433 return -ENOMEM;434 rc = cca_apqns4type(subtype, NULL, NULL, 0,435 local_apqns, &nr_apqns);436 if (rc)437 goto out;438 apqns = local_apqns;439 }440 441 for (rc = -ENODEV, i = 0; rc && i < nr_apqns; i++) {442 if (subtype == PKEY_TYPE_CCA_CIPHER) {443 rc = cca_clr2cipherkey(apqns[i].card, apqns[i].domain,444 keybitsize, flags, clrkey,445 keybuf, keybuflen);446 } else {447 /* PKEY_TYPE_CCA_DATA */448 rc = cca_clr2seckey(apqns[i].card, apqns[i].domain,449 keybitsize, clrkey, keybuf);450 *keybuflen = (rc ? 0 : SECKEYBLOBSIZE);451 }452 }453 454out:455 kfree(local_apqns);456 pr_debug("rc=%d\n", rc);457 return rc;458}459 460static int cca_verifykey(const u8 *key, u32 keylen,461 u16 *card, u16 *dom,462 u32 *keytype, u32 *keybitsize, u32 *flags)463{464 struct keytoken_header *hdr = (struct keytoken_header *)key;465 u32 nr_apqns, *apqns = NULL;466 int rc;467 468 if (keylen < sizeof(*hdr))469 return -EINVAL;470 471 zcrypt_wait_api_operational();472 473 if (hdr->type == TOKTYPE_CCA_INTERNAL &&474 hdr->version == TOKVER_CCA_AES) {475 struct secaeskeytoken *t = (struct secaeskeytoken *)key;476 477 rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);478 if (rc)479 goto out;480 *keytype = PKEY_TYPE_CCA_DATA;481 *keybitsize = t->bitsize;482 rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,483 ZCRYPT_CEX3C, AES_MK_SET,484 t->mkvp, 0, 1);485 if (!rc)486 *flags = PKEY_FLAGS_MATCH_CUR_MKVP;487 if (rc == -ENODEV) {488 rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,489 ZCRYPT_CEX3C, AES_MK_SET,490 0, t->mkvp, 1);491 if (!rc)492 *flags = PKEY_FLAGS_MATCH_ALT_MKVP;493 }494 if (rc)495 goto out;496 497 *card = ((struct pkey_apqn *)apqns)->card;498 *dom = ((struct pkey_apqn *)apqns)->domain;499 500 } else if (hdr->type == TOKTYPE_CCA_INTERNAL &&501 hdr->version == TOKVER_CCA_VLSC) {502 struct cipherkeytoken *t = (struct cipherkeytoken *)key;503 504 rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);505 if (rc)506 goto out;507 *keytype = PKEY_TYPE_CCA_CIPHER;508 *keybitsize = PKEY_SIZE_UNKNOWN;509 if (!t->plfver && t->wpllen == 512)510 *keybitsize = PKEY_SIZE_AES_128;511 else if (!t->plfver && t->wpllen == 576)512 *keybitsize = PKEY_SIZE_AES_192;513 else if (!t->plfver && t->wpllen == 640)514 *keybitsize = PKEY_SIZE_AES_256;515 rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,516 ZCRYPT_CEX6, AES_MK_SET,517 t->mkvp0, 0, 1);518 if (!rc)519 *flags = PKEY_FLAGS_MATCH_CUR_MKVP;520 if (rc == -ENODEV) {521 rc = cca_findcard2(&apqns, &nr_apqns, *card, *dom,522 ZCRYPT_CEX6, AES_MK_SET,523 0, t->mkvp0, 1);524 if (!rc)525 *flags = PKEY_FLAGS_MATCH_ALT_MKVP;526 }527 if (rc)528 goto out;529 530 *card = ((struct pkey_apqn *)apqns)->card;531 *dom = ((struct pkey_apqn *)apqns)->domain;532 533 } else {534 /* unknown/unsupported key blob */535 rc = -EINVAL;536 }537 538out:539 kfree(apqns);540 pr_debug("rc=%d\n", rc);541 return rc;542}543 544/*545 * This function provides an alternate but usually slow way546 * to convert a 'clear key token' with AES key material into547 * a protected key. This is done via an intermediate step548 * which creates a CCA AES DATA secure key first and then549 * derives the protected key from this secure key.550 */551static int cca_slowpath_key2protkey(const struct pkey_apqn *apqns,552 size_t nr_apqns,553 const u8 *key, u32 keylen,554 u8 *protkey, u32 *protkeylen,555 u32 *protkeytype)556{557 const struct keytoken_header *hdr = (const struct keytoken_header *)key;558 const struct clearkeytoken *t = (const struct clearkeytoken *)key;559 u32 tmplen, keysize = 0;560 u8 *tmpbuf;561 int i, rc;562 563 if (keylen < sizeof(*hdr))564 return -EINVAL;565 566 if (hdr->type == TOKTYPE_NON_CCA &&567 hdr->version == TOKVER_CLEAR_KEY)568 keysize = pkey_keytype_aes_to_size(t->keytype);569 if (!keysize || t->len != keysize)570 return -EINVAL;571 572 /* alloc tmp key buffer */573 tmpbuf = kmalloc(SECKEYBLOBSIZE, GFP_ATOMIC);574 if (!tmpbuf)575 return -ENOMEM;576 577 /* try two times in case of failure */578 for (i = 0, rc = -ENODEV; i < 2 && rc; i++) {579 tmplen = SECKEYBLOBSIZE;580 rc = cca_clr2key(NULL, 0, t->keytype, PKEY_TYPE_CCA_DATA,581 8 * keysize, 0, t->clearkey, t->len,582 tmpbuf, &tmplen, NULL);583 pr_debug("cca_clr2key()=%d\n", rc);584 if (rc)585 continue;586 rc = cca_key2protkey(NULL, 0, tmpbuf, tmplen,587 protkey, protkeylen, protkeytype);588 pr_debug("cca_key2protkey()=%d\n", rc);589 }590 591 kfree(tmpbuf);592 pr_debug("rc=%d\n", rc);593 return rc;594}595 596static struct pkey_handler cca_handler = {597 .module = THIS_MODULE,598 .name = "PKEY CCA handler",599 .is_supported_key = is_cca_key,600 .is_supported_keytype = is_cca_keytype,601 .key_to_protkey = cca_key2protkey,602 .slowpath_key_to_protkey = cca_slowpath_key2protkey,603 .gen_key = cca_gen_key,604 .clr_to_key = cca_clr2key,605 .verify_key = cca_verifykey,606 .apqns_for_key = cca_apqns4key,607 .apqns_for_keytype = cca_apqns4type,608};609 610/*611 * Module init612 */613static int __init pkey_cca_init(void)614{615 /* register this module as pkey handler for all the cca stuff */616 return pkey_handler_register(&cca_handler);617}618 619/*620 * Module exit621 */622static void __exit pkey_cca_exit(void)623{624 /* unregister this module as pkey handler */625 pkey_handler_unregister(&cca_handler);626}627 628module_init(pkey_cca_init);629module_exit(pkey_cca_exit);630