// SPDX-License-Identifier: GPL-2.0+ /* * Copyright IBM Corp. 2019 * Author(s): Harald Freudenberger <freude@linux.ibm.com> * Ingo Franzki <ifranzki@linux.ibm.com> * * Collection of CCA misc functions used by zcrypt and pkey
*/
/* Size of parameter block used for all cca requests/replies */ #define PARMBSIZE 512
/* Size of vardata block used for some of the cca requests/replies */ #define VARDATASIZE 4096
/* * Cprb memory pool held for urgent cases where no memory * can be allocated via kmalloc. This pool is only used * when alloc_and_prep_cprbmem() is called with the xflag * ZCRYPT_XFLAG_NOMEMALLOC. The cprb memory needs to hold * space for request AND reply!
*/ #define CPRB_MEMPOOL_ITEM_SIZE (16 * 1024) static mempool_t *cprb_mempool;
/* * This is a pre-allocated memory for the device status array * used within the findcard() functions. It is currently * 128 * 128 * 4 bytes = 64 KB big. Usage of this memory is * controlled via dev_status_mem_mutex. Needs adaption if more * than 128 cards or domains to be are supported.
*/ #define ZCRYPT_DEV_STATUS_CARD_MAX 128 #define ZCRYPT_DEV_STATUS_QUEUE_MAX 128 #define ZCRYPT_DEV_STATUS_ENTRIES (ZCRYPT_DEV_STATUS_CARD_MAX * \
ZCRYPT_DEV_STATUS_QUEUE_MAX) #define ZCRYPT_DEV_STATUS_EXT_SIZE (ZCRYPT_DEV_STATUS_ENTRIES * \ sizeof(struct zcrypt_device_status_ext)) staticvoid *dev_status_mem; static DEFINE_MUTEX(dev_status_mem_mutex);
/* * Simple check if the token is a valid CCA secure AES data key * token. If keybitsize is given, the bitsize of the key is * also checked. Returns 0 on success or errno value on failure.
*/ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, const u8 *token, int keybitsize)
{ struct secaeskeytoken *t = (struct secaeskeytoken *)token;
/* * Simple check if the token is a valid CCA secure AES cipher key * token. If keybitsize is given, the bitsize of the key is * also checked. If checkcpacfexport is enabled, the key is also * checked for the export flag to allow CPACF export. * Returns 0 on success or errno value on failure.
*/ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, const u8 *token, int keybitsize, int checkcpacfexport)
{ struct cipherkeytoken *t = (struct cipherkeytoken *)token; bool keybitsizeok = true;
/* * Simple check if the token is a valid CCA secure ECC private * key token. Returns 0 on success or errno value on failure.
*/ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl, const u8 *token, u32 keysize, int checkcpacfexport)
{ struct eccprivkeytoken *t = (struct eccprivkeytoken *)token;
/* * Free the cprb memory allocated with the function above. * If the scrub value is not zero, the memory is filled * with zeros before freeing (useful if there was some * clear key material in there).
*/ staticvoid free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
{ if (mem && scrub)
memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
mempool_free(mem, cprb_mempool); else
kfree(mem);
}
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* fill request cprb param block with KG request */
preqparm = (struct kgreqparm __force *)preqcblk->req_parmb;
memcpy(preqparm->subfunc_code, "KG", 2);
preqparm->rule_array_len = sizeof(preqparm->rule_array_len);
preqparm->lv1.len = sizeof(struct lv1);
memcpy(preqparm->lv1.key_form, "OP ", 8); switch (keybitsize) { case PKEY_SIZE_AES_128: case PKEY_KEYTYPE_AES_128: /* older ioctls used this */
keysize = 16;
memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); break; case PKEY_SIZE_AES_192: case PKEY_KEYTYPE_AES_192: /* older ioctls used this */
keysize = 24;
memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); break; case PKEY_SIZE_AES_256: case PKEY_KEYTYPE_AES_256: /* older ioctls used this */
keysize = 32;
memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); break; default:
ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
__func__, keybitsize);
rc = -EINVAL; goto out;
}
memcpy(preqparm->lv1.key_type1, "AESDATA ", 8);
preqparm->lv2.len = sizeof(struct lv2); for (i = 0; i < 6; i++) {
preqparm->lv2.keyid[i].len = sizeof(struct keyid);
preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10);
}
preqcblk->req_parml = sizeof(struct kgreqparm);
/* fill xcrb struct */
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = zcrypt_send_cprb(&xcrb, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
__func__, (int)cardnr, (int)domain, rc); goto out;
}
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* fill request cprb param block with CM request */
preqparm = (struct cmreqparm __force *)preqcblk->req_parmb;
memcpy(preqparm->subfunc_code, "CM", 2);
memcpy(preqparm->rule_array, "AES ", 8);
preqparm->rule_array_len = sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); switch (keybitsize) { case PKEY_SIZE_AES_128: case PKEY_KEYTYPE_AES_128: /* older ioctls used this */
keysize = 16; break; case PKEY_SIZE_AES_192: case PKEY_KEYTYPE_AES_192: /* older ioctls used this */
keysize = 24; break; case PKEY_SIZE_AES_256: case PKEY_KEYTYPE_AES_256: /* older ioctls used this */
keysize = 32; break; default:
ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n",
__func__, keybitsize);
rc = -EINVAL; goto out;
}
preqparm->lv1.len = sizeof(struct lv1) + keysize;
memcpy(preqparm->lv1.clrkey, clrkey, keysize);
plv2 = (struct lv2 *)(((u8 *)preqparm) + sizeof(*preqparm) + keysize);
plv2->len = sizeof(struct lv2);
plv2->keyid.len = sizeof(struct keyid);
plv2->keyid.attr = 0x30;
preqcblk->req_parml = sizeof(*preqparm) + keysize + sizeof(*plv2);
/* fill xcrb struct */
prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = zcrypt_send_cprb(&xcrb, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
__func__, (int)cardnr, (int)domain, rc); goto out;
}
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* do some plausibility checks on the key block */ if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) ||
prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) {
ZCRYPT_DBF_ERR("%s reply with invalid or unknown key block\n",
__func__);
rc = -EIO; goto out;
}
/* and some checks on the generated key */
rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR,
prepparm->kb.tlv1.gen_key,
keybitsize, 1); if (rc) {
rc = -EIO; goto out;
}
/* copy the generated vlsc key token */
t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key; if (keybuf) { if (*keybufsize >= t->len)
memcpy(keybuf, t, t->len); else
rc = -EINVAL;
}
*keybufsize = t->len;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* * Build CCA AES CIPHER secure key with a given clear key value.
*/ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, const u8 *clrkey, u8 *keybuf, u32 *keybufsize, u32 xflags)
{ int rc; void *mem; int tokensize;
u8 *token, exorbuf[32]; struct cipherkeytoken *t;
/* fill exorbuf with random data */
get_random_bytes(exorbuf, sizeof(exorbuf));
/* * Allocate space for the key token to build. * Also we only need up to MAXCCAVLSCTOKENSIZE bytes for this * we use the already existing cprb mempool to solve this * short term memory requirement.
*/
mem = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
mempool_alloc_preallocated(cprb_mempool) :
mempool_alloc(cprb_mempool, GFP_KERNEL); if (!mem) return -ENOMEM;
/* prepare the token with the key skeleton */
token = (u8 *)mem;
tokensize = SIZEOF_SKELETON;
memcpy(token, aes_cipher_key_skeleton, tokensize);
/* patch the skeleton key token export flags */ if (keygenflags) {
t = (struct cipherkeytoken *)token;
t->kmf1 |= (u16)(keygenflags & 0x0000FF00);
t->kmf1 &= (u16)~(keygenflags & 0x000000FF);
}
/* * Do the key import with the clear key value in 4 steps: * 1/4 FIRST import with only random data * 2/4 EXOR the clear key * 3/4 EXOR the very same random data again * 4/4 COMPLETE the secure cipher key import
*/
rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART",
exorbuf, keybitsize, token, &tokensize, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc); goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
clrkey, keybitsize, token, &tokensize, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc); goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
exorbuf, keybitsize, token, &tokensize, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc); goto out;
}
rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL,
NULL, keybitsize, token, &tokensize, xflags); if (rc) {
ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
__func__, rc); goto out;
}
/* copy the generated key token */ if (keybuf) { if (tokensize > *keybufsize)
rc = -EINVAL; else
memcpy(keybuf, token, tokensize);
}
*keybufsize = tokensize;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem(parmbsize, &mem,
&preqcblk, &prepcblk, xflags); if (rc) return rc;
/* fill request cprb struct */
preqcblk->domain = domain;
/* * Fetch cca_info values about a CCA queue via * query_crypto_facility from adapter.
*/ int cca_get_info(u16 cardnr, u16 domain, struct cca_info *ci, u32 xflags)
{ void *mem; int rc, found = 0;
size_t rlen, vlen;
u8 *rarray, *varray; struct zcrypt_device_status_ext devstat;
memset(ci, 0, sizeof(*ci));
/* get first info from zcrypt device driver about this apqn */
rc = zcrypt_device_status_ext(cardnr, domain, &devstat); if (rc) return rc;
ci->hwtype = devstat.hwtype;
/* * Prep memory for rule array and var array use. * Use the cprb mempool for this.
*/
mem = (xflags & ZCRYPT_XFLAG_NOMEMALLOC) ?
mempool_alloc_preallocated(cprb_mempool) :
mempool_alloc(cprb_mempool, GFP_KERNEL); if (!mem) return -ENOMEM;
rarray = (u8 *)mem;
varray = (u8 *)mem + PAGE_SIZE / 2;
rlen = vlen = PAGE_SIZE / 2;
int cca_findcard2(u32 *apqns, u32 *nr_apqns, u16 cardnr, u16 domain, int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp,
u32 xflags)
{ struct zcrypt_device_status_ext *device_status; int i, card, dom, curmatch, oldmatch; struct cca_info ci;
u32 _nr_apqns = 0;
/* occupy the device status memory */
mutex_lock(&dev_status_mem_mutex);
memset(dev_status_mem, 0, ZCRYPT_DEV_STATUS_EXT_SIZE);
device_status = (struct zcrypt_device_status_ext *)dev_status_mem;
/* fetch crypto device status into this struct */
zcrypt_device_status_mask_ext(device_status,
ZCRYPT_DEV_STATUS_CARD_MAX,
ZCRYPT_DEV_STATUS_QUEUE_MAX);
/* walk through all the crypto apqnss */ for (i = 0; i < ZCRYPT_DEV_STATUS_ENTRIES; i++) {
card = AP_QID_CARD(device_status[i].qid);
dom = AP_QID_QUEUE(device_status[i].qid); /* check online state */ if (!device_status[i].online) continue; /* check for cca functions */ if (!(device_status[i].functions & 0x04)) continue; /* check cardnr */ if (cardnr != 0xFFFF && card != cardnr) continue; /* check domain */ if (domain != 0xFFFF && dom != domain) continue; /* get cca info on this apqn */ if (cca_get_info(card, dom, &ci, xflags)) continue; /* current master key needs to be valid */ if (mktype == AES_MK_SET && ci.cur_aes_mk_state != '2') continue; if (mktype == APKA_MK_SET && ci.cur_apka_mk_state != '2') continue; /* check min hardware type */ if (minhwtype > 0 && minhwtype > ci.hwtype) continue; if (cur_mkvp || old_mkvp) { /* check mkvps */
curmatch = oldmatch = 0; if (mktype == AES_MK_SET) { if (cur_mkvp && cur_mkvp == ci.cur_aes_mkvp)
curmatch = 1; if (old_mkvp && ci.old_aes_mk_state == '2' &&
old_mkvp == ci.old_aes_mkvp)
oldmatch = 1;
} else { if (cur_mkvp && cur_mkvp == ci.cur_apka_mkvp)
curmatch = 1; if (old_mkvp && ci.old_apka_mk_state == '2' &&
old_mkvp == ci.old_apka_mkvp)
oldmatch = 1;
} if (curmatch + oldmatch < 1) continue;
} /* apqn passed all filtering criterons, add to the array */ if (_nr_apqns < *nr_apqns)
apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
}
*nr_apqns = _nr_apqns;
/* release the device status memory */
mutex_unlock(&dev_status_mem_mutex);
int __init zcrypt_ccamisc_init(void)
{ /* Pre-allocate a small memory pool for cca cprbs. */
cprb_mempool = mempool_create_kmalloc_pool(zcrypt_mempool_threshold,
CPRB_MEMPOOL_ITEM_SIZE); if (!cprb_mempool) return -ENOMEM;
/* Pre-allocate one crypto status card struct used in findcard() */
dev_status_mem = kvmalloc(ZCRYPT_DEV_STATUS_EXT_SIZE, GFP_KERNEL); if (!dev_status_mem) {
mempool_destroy(cprb_mempool); return -ENOMEM;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.