diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/crypto/pkey_api.c | 652 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.c | 58 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.h | 8 |
3 files changed, 664 insertions, 54 deletions
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index cd7e654bd18e..f76a1d0f54c4 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -30,6 +30,9 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 protected key interface"); +#define KEYBLOBBUFSIZE 8192 /* key buffer size used for internal processing */ +#define MAXAPQNSINLIST 64 /* max 64 apqns within a apqn list */ + /* mask of available pckmo subfunctions, fetched once at module init */ static cpacf_mask_t pckmo_functions; @@ -126,27 +129,39 @@ static int pkey_clr2protkey(u32 keytype, /* * Find card and transform secure key into protected key. */ -static int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *pkey) +static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) { - u16 cardnr, domain; int rc, verify; + u16 cardnr, domain; + struct keytoken_header *hdr = (struct keytoken_header *)key; /* - * The cca_sec2protkey call may fail when a card has been + * The cca_xxx2protkey call may fail when a card has been * addressed where the master key was changed after last fetch * of the mkvp into the cache. Try 3 times: First witout verify * then with verify and last round with verify and old master * key verification pattern match not ignored. */ for (verify = 0; verify < 3; verify++) { - rc = cca_findcard(seckey->seckey, &cardnr, &domain, verify); + rc = cca_findcard(key, &cardnr, &domain, verify); if (rc < 0) continue; if (rc > 0 && verify < 2) continue; - rc = cca_sec2protkey(cardnr, domain, seckey->seckey, - pkey->protkey, &pkey->len, &pkey->type); + switch (hdr->version) { + case TOKVER_CCA_AES: + rc = cca_sec2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + case TOKVER_CCA_VLSC: + rc = cca_cipher2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + default: + return -EINVAL; + } if (rc == 0) break; } @@ -324,14 +339,18 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, case TOKVER_CCA_AES: if (keylen != sizeof(struct secaeskeytoken)) return -EINVAL; - - return pkey_skey2pkey((struct pkey_seckey *)key, - protkey); + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + break; default: DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n", __func__, hdr->version); return -EINVAL; } + + return pkey_skey2pkey(key, protkey); } /* @@ -340,28 +359,394 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { + int rc; struct keytoken_header *hdr = (struct keytoken_header *)key; - if (keylen < sizeof(struct keytoken_header)) + if (keylen < sizeof(struct keytoken_header)) { + DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen); return -EINVAL; + } switch (hdr->type) { case TOKTYPE_NON_CCA: - return pkey_nonccatok2pkey(key, keylen, protkey); + rc = pkey_nonccatok2pkey(key, keylen, protkey); + break; case TOKTYPE_CCA_INTERNAL: - return pkey_ccainttok2pkey(key, keylen, protkey); + rc = pkey_ccainttok2pkey(key, keylen, protkey); + break; default: - DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__, - hdr->type); + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); return -EINVAL; } + + DEBUG_DBG("%s rc=%d\n", __func__, rc); + return rc; + } EXPORT_SYMBOL(pkey_keyblob2pkey); +static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_genseckey(card, dom, ksize, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_gencipherkey(card, dom, ksize, kflags, + keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, const u8 *clrkey, + u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_clr2seckey(card, dom, ksize, + clrkey, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_clr2cipherkey(card, dom, ksize, kflags, + clrkey, keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_verifykey2(const u8 *key, size_t keylen, + u16 *cardnr, u16 *domain, + enum pkey_key_type *ktype, + enum pkey_key_size *ksize, u32 *flags) +{ + int rc; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + rc = cca_check_secaeskeytoken(debug_info, 3, key, 0); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_DATA; + if (ksize) + *ksize = (enum pkey_key_size) t->bitsize; + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX3C, t->mkvp, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX3C, 0, t->mkvp, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else if (hdr->version == TOKVER_CCA_VLSC) { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_CIPHER; + if (ksize) { + *ksize = PKEY_SIZE_UNKNOWN; + if (!t->plfver && t->wpllen == 512) + *ksize = PKEY_SIZE_AES_128; + else if (!t->plfver && t->wpllen == 576) + *ksize = PKEY_SIZE_AES_192; + else if (!t->plfver && t->wpllen == 640) + *ksize = PKEY_SIZE_AES_256; + } + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX6, t->mkvp0, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX6, 0, t->mkvp0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else + rc = -EINVAL; + +out: + kfree(_apqns); + return rc; +} + +static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, size_t keylen, + struct pkey_protkey *pkey) +{ + int i, card, dom, rc; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + if (keylen < sizeof(struct keytoken_header)) + return -EINVAL; + + switch (hdr->type) { + case TOKTYPE_NON_CCA: + return pkey_nonccatok2pkey(key, keylen, pkey); + case TOKTYPE_CCA_INTERNAL: + switch (hdr->version) { + case TOKVER_CCA_AES: + if (keylen != sizeof(struct secaeskeytoken)) + return -EINVAL; + if (cca_check_secaeskeytoken(debug_info, 3, key, 0)) + return -EINVAL; + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1)) + return -EINVAL; + break; + default: + DEBUG_ERR("%s unknown CCA internal token version %d\n", + __func__, hdr->version); + return -EINVAL; + } + break; + default: + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (hdr->version == TOKVER_CCA_AES) + rc = cca_sec2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + else /* TOKVER_CCA_VLSC */ + rc = cca_cipher2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = EINVAL; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL || + flags == 0) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES || hdr->version == TOKVER_CCA_VLSC) { + int minhwtype = ZCRYPT_CEX3C; + u64 cur_mkvp = 0, old_mkvp = 0; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp; + } else { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + minhwtype = ZCRYPT_CEX6; + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp0; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp0; + } + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + +static int pkey_apqns4keytype(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = -EINVAL; + u32 _nr_apqns, *_apqns = NULL; + + if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) { + u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = *((u64 *) cur_mkvp); + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = *((u64 *) alt_mkvp); + if (ktype == PKEY_TYPE_CCA_CIPHER) + minhwtype = ZCRYPT_CEX6; + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + /* * File io functions */ +static void *_copy_key_from_user(void __user *ukey, size_t keylen) +{ + void *kkey; + + if (!ukey || keylen < MINKEYBLOBSIZE || keylen > KEYBLOBBUFSIZE) + return ERR_PTR(-EINVAL); + kkey = kmalloc(keylen, GFP_KERNEL); + if (!kkey) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kkey, ukey, keylen)) { + kfree(kkey); + return ERR_PTR(-EFAULT); + } + + return kkey; +} + +static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns) +{ + void *kapqns = NULL; + size_t nbytes; + + if (uapqns && nr_apqns > 0) { + nbytes = nr_apqns * sizeof(struct pkey_apqn); + kapqns = kmalloc(nbytes, GFP_KERNEL); + if (!kapqns) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kapqns, uapqns, nbytes)) + return ERR_PTR(-EFAULT); + } + + return kapqns; +} + static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -452,7 +837,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey); + rc = pkey_skey2pkey(ksp.seckey.seckey, &ksp.protkey); DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; @@ -502,24 +887,148 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, case PKEY_KBLOB2PROTK: { struct pkey_kblob2pkey __user *utp = (void __user *) arg; struct pkey_kblob2pkey ktp; - u8 __user *ukey; u8 *kkey; if (copy_from_user(&ktp, utp, sizeof(ktp))) return -EFAULT; - if (ktp.keylen < MINKEYBLOBSIZE || - ktp.keylen > MAXKEYBLOBSIZE) - return -EINVAL; - ukey = ktp.key; - kkey = kmalloc(ktp.keylen, GFP_KERNEL); - if (kkey == NULL) + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(utp, &ktp, sizeof(ktp))) + return -EFAULT; + break; + } + case PKEY_GENSECK2: { + struct pkey_genseck2 __user *ugs = (void __user *) arg; + struct pkey_genseck2 kgs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kgs, ugs, sizeof(kgs))) + return -EFAULT; + apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); return -ENOMEM; - if (copy_from_user(kkey, ukey, ktp.keylen)) { + } + rc = pkey_genseckey2(apqns, kgs.apqn_entries, + kgs.type, kgs.size, kgs.keygenflags, + kkey, &klen); + DEBUG_DBG("%s pkey_genseckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { kfree(kkey); + break; + } + if (kgs.key) { + if (kgs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kgs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kgs.keylen = klen; + if (copy_to_user(ugs, &kgs, sizeof(kgs))) + rc = -EFAULT; + kfree(kkey); + break; + } + case PKEY_CLR2SECK2: { + struct pkey_clr2seck2 __user *ucs = (void __user *) arg; + struct pkey_clr2seck2 kcs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; + apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); + return -ENOMEM; } - rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); - DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + rc = pkey_clr2seckey2(apqns, kcs.apqn_entries, + kcs.type, kcs.size, kcs.keygenflags, + kcs.clrkey.clrkey, kkey, &klen); + DEBUG_DBG("%s pkey_clr2seckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { + kfree(kkey); + break; + } + if (kcs.key) { + if (kcs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kcs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kcs.keylen = klen; + if (copy_to_user(ucs, &kcs, sizeof(kcs))) + rc = -EFAULT; + memzero_explicit(&kcs, sizeof(kcs)); + kfree(kkey); + break; + } + case PKEY_VERIFYKEY2: { + struct pkey_verifykey2 __user *uvk = (void __user *) arg; + struct pkey_verifykey2 kvk; + u8 *kkey; + + if (copy_from_user(&kvk, uvk, sizeof(kvk))) + return -EFAULT; + kkey = _copy_key_from_user(kvk.key, kvk.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + rc = pkey_verifykey2(kkey, kvk.keylen, + &kvk.cardnr, &kvk.domain, + &kvk.type, &kvk.size, &kvk.flags); + DEBUG_DBG("%s pkey_verifykey2()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(uvk, &kvk, sizeof(kvk))) + return -EFAULT; + break; + } + case PKEY_KBLOB2PROTK2: { + struct pkey_kblob2pkey2 __user *utp = (void __user *) arg; + struct pkey_kblob2pkey2 ktp; + struct pkey_apqn *apqns = NULL; + u8 *kkey; + + if (copy_from_user(&ktp, utp, sizeof(ktp))) + return -EFAULT; + apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_keyblob2pkey2(apqns, ktp.apqn_entries, + kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc); + kfree(apqns); kfree(kkey); if (rc) break; @@ -527,6 +1036,97 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_APQNS4K: { + struct pkey_apqns4key __user *uak = (void __user *) arg; + struct pkey_apqns4key kak; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + u8 *kkey; + + if (copy_from_user(&kak, uak, sizeof(kak))) + return -EFAULT; + nr_apqns = kak.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + kkey = _copy_key_from_user(kak.key, kak.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_apqns4key(kkey, kak.keylen, kak.flags, + apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4key()=%d\n", __func__, rc); + kfree(kkey); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kak.apqns) { + if (nr_apqns > kak.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kak.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kak.apqn_entries = nr_apqns; + if (copy_to_user(uak, &kak, sizeof(kak))) + rc = -EFAULT; + kfree(apqns); + break; + } + case PKEY_APQNS4KT: { + struct pkey_apqns4keytype __user *uat = (void __user *) arg; + struct pkey_apqns4keytype kat; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + + if (copy_from_user(&kat, uat, sizeof(kat))) + return -EFAULT; + nr_apqns = kat.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + rc = pkey_apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp, + kat.flags, apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4keytype()=%d\n", __func__, rc); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kat.apqns) { + if (nr_apqns > kat.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kat.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kat.apqn_entries = nr_apqns; + if (copy_to_user(uat, &kat, sizeof(kat))) + rc = -EFAULT; + kfree(apqns); + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY; diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 88c5f4a56be7..3b2d3705d2db 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -270,7 +270,7 @@ static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) * Generate (random) CCA AES DATA secure key. */ int cca_genseckey(u16 cardnr, u16 domain, - u32 keytype, u8 seckey[SECKEYBLOBSIZE]) + u32 keybitsize, u8 seckey[SECKEYBLOBSIZE]) { int i, rc, keysize; int seckeysize; @@ -325,22 +325,25 @@ int cca_genseckey(u16 cardnr, u16 domain, preqparm->rule_array_len = sizeof(preqparm->rule_array_len); preqparm->lv1.len = sizeof(struct lv1); memcpy(preqparm->lv1.key_form, "OP ", 8); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: + 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_KEYTYPE_AES_192: + 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_KEYTYPE_AES_256: + 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: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); rc = -EINVAL; goto out; } @@ -408,7 +411,7 @@ EXPORT_SYMBOL(cca_genseckey); /* * Generate an CCA AES DATA secure key with given key value. */ -int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, const u8 *clrkey, u8 seckey[SECKEYBLOBSIZE]) { int rc, keysize, seckeysize; @@ -462,19 +465,22 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, memcpy(preqparm->rule_array, "AES ", 8); preqparm->rule_array_len = sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: + switch (keybitsize) { + case PKEY_SIZE_AES_128: + case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ keysize = 16; break; - case PKEY_KEYTYPE_AES_192: + case PKEY_SIZE_AES_192: + case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ keysize = 24; break; - case PKEY_KEYTYPE_AES_256: + case PKEY_SIZE_AES_256: + case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ keysize = 32; break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); rc = -EINVAL; goto out; } @@ -545,8 +551,7 @@ EXPORT_SYMBOL(cca_clr2seckey); */ int cca_sec2protkey(u16 cardnr, u16 domain, const u8 seckey[SECKEYBLOBSIZE], - u8 *protkey, u32 *protkeylen, - u32 *keytype) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { int rc; u8 *mem; @@ -656,21 +661,21 @@ int cca_sec2protkey(u16 cardnr, u16 domain, switch (prepparm->lv3.keyblock.len) { case 16+32: /* AES 128 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_128; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_128; break; case 24+32: /* AES 192 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_192; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_192; break; case 32+32: /* AES 256 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_256; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_256; break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", + DEBUG_ERR("%s unknown/unsupported keylen %d\n", __func__, prepparm->lv3.keyblock.len); rc = -EIO; goto out; @@ -1645,6 +1650,7 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) { u64 mkvp; + int minhwtype = 0; const struct keytoken_header *hdr = (struct keytoken_header *) key; if (hdr->type != TOKTYPE_CCA_INTERNAL) @@ -1654,11 +1660,15 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) case TOKVER_CCA_AES: mkvp = ((struct secaeskeytoken *)key)->mkvp; break; + case TOKVER_CCA_VLSC: + mkvp = ((struct cipherkeytoken *)key)->mkvp0; + minhwtype = AP_DEVICE_TYPE_CEX6; + break; default: return -EINVAL; } - return findcard(mkvp, pcardnr, pdomain, verify, 0); + return findcard(mkvp, pcardnr, pdomain, verify, minhwtype); } EXPORT_SYMBOL(cca_findcard); diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index e97cda0f61e0..77b6cc7b8f82 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -124,12 +124,12 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, /* * Generate (random) CCA AES DATA secure key. */ -int cca_genseckey(u16 cardnr, u16 domain, u32 keytype, u8 *seckey); +int cca_genseckey(u16 cardnr, u16 domain, u32 keybitsize, u8 *seckey); /* * Generate CCA AES DATA secure key with given clear key value. */ -int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, const u8 *clrkey, u8 *seckey); /* @@ -137,8 +137,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, */ int cca_sec2protkey(u16 cardnr, u16 domain, const u8 seckey[SECKEYBLOBSIZE], - u8 *protkey, u32 *protkeylen, - u32 *protkeytype); + u8 *protkey, u32 *protkeylen, u32 *protkeytype); /* * Generate (random) CCA AES CIPHER secure key. @@ -169,6 +168,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, /* * Search for a matching crypto card based on the Master Key * Verification Pattern provided inside a secure key. + * Works with CCA AES data and cipher keys. * Returns < 0 on failure, 0 if CURRENT MKVP matches and * 1 if OLD MKVP matches. */ |