summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/crypto/pkey_api.c33
-rw-r--r--drivers/s390/crypto/zcrypt_ep11misc.c123
-rw-r--r--drivers/s390/crypto/zcrypt_ep11misc.h6
3 files changed, 100 insertions, 62 deletions
diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c
index 7543757c82e2..75d7f0d5f14e 100644
--- a/drivers/s390/crypto/pkey_api.c
+++ b/drivers/s390/crypto/pkey_api.c
@@ -288,10 +288,9 @@ out:
/*
* Find card and transform EP11 secure key into protected key.
*/
-static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
- u32 *protkeylen, u32 *protkeytype)
+static int pkey_ep11key2pkey(const u8 *key, size_t keylen,
+ u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- struct ep11keyblob *kb = (struct ep11keyblob *)key;
u32 nr_apqns, *apqns = NULL;
u16 card, dom;
int i, rc;
@@ -300,7 +299,8 @@ static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
/* build a list of apqns suitable for this key */
rc = ep11_findcard2(&apqns, &nr_apqns, 0xFFFF, 0xFFFF,
- ZCRYPT_CEX7, EP11_API_V, kb->wkvp);
+ ZCRYPT_CEX7, EP11_API_V,
+ ep11_kb_wkvp(key, keylen));
if (rc)
goto out;
@@ -308,7 +308,7 @@ static int pkey_ep11key2pkey(const u8 *key, u8 *protkey,
for (rc = -ENODEV, i = 0; i < nr_apqns; i++) {
card = apqns[i] >> 16;
dom = apqns[i] & 0xFFFF;
- rc = ep11_kblob2protkey(card, dom, key, kb->head.len,
+ rc = ep11_kblob2protkey(card, dom, key, keylen,
protkey, protkeylen, protkeytype);
if (rc == 0)
break;
@@ -496,7 +496,7 @@ try_via_ep11:
tmpbuf, &tmpbuflen);
if (rc)
goto failure;
- rc = pkey_ep11key2pkey(tmpbuf,
+ rc = pkey_ep11key2pkey(tmpbuf, tmpbuflen,
protkey, protkeylen, protkeytype);
if (!rc)
goto out;
@@ -612,7 +612,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1);
if (rc)
goto out;
- rc = pkey_ep11key2pkey(key,
+ rc = pkey_ep11key2pkey(key, keylen,
protkey, protkeylen, protkeytype);
break;
}
@@ -621,7 +621,7 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
rc = ep11_check_aes_key_with_hdr(debug_info, 3, key, keylen, 1);
if (rc)
goto out;
- rc = pkey_ep11key2pkey(key + sizeof(struct ep11kblob_header),
+ rc = pkey_ep11key2pkey(key, keylen,
protkey, protkeylen, protkeytype);
break;
default:
@@ -963,10 +963,12 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
}
} else if (hdr->type == TOKTYPE_NON_CCA) {
if (hdr->version == TOKVER_EP11_AES) {
- if (keylen < sizeof(struct ep11keyblob))
- return -EINVAL;
if (ep11_check_aes_key(debug_info, 3, key, keylen, 1))
return -EINVAL;
+ } else if (hdr->version == TOKVER_EP11_AES_WITH_HEADER) {
+ if (ep11_check_aes_key_with_hdr(debug_info, 3,
+ key, keylen, 1))
+ return -EINVAL;
} else {
return pkey_nonccatok2pkey(key, keylen,
protkey, protkeylen,
@@ -994,10 +996,7 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
protkey, protkeylen,
protkeytype);
} else {
- /* EP11 AES secure key blob */
- struct ep11keyblob *kb = (struct ep11keyblob *)key;
-
- rc = ep11_kblob2protkey(card, dom, key, kb->head.len,
+ rc = ep11_kblob2protkey(card, dom, key, keylen,
protkey, protkeylen,
protkeytype);
}
@@ -1257,12 +1256,14 @@ static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns,
hdr->version == TOKVER_EP11_ECC_WITH_HEADER) &&
is_ep11_keyblob(key + sizeof(struct ep11kblob_header)))
rc = ep11_kblob2protkey(card, dom, key, hdr->len,
- protkey, protkeylen, protkeytype);
+ protkey, protkeylen,
+ protkeytype);
else if (hdr->type == TOKTYPE_NON_CCA &&
hdr->version == TOKVER_EP11_AES &&
is_ep11_keyblob(key))
rc = ep11_kblob2protkey(card, dom, key, hdr->len,
- protkey, protkeylen, protkeytype);
+ protkey, protkeylen,
+ protkeytype);
else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
hdr->version == TOKVER_CCA_AES)
rc = cca_sec2protkey(card, dom, key, protkey,
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.c b/drivers/s390/crypto/zcrypt_ep11misc.c
index 355d30bc0aac..669ad6f5d5b0 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.c
+++ b/drivers/s390/crypto/zcrypt_ep11misc.c
@@ -157,6 +157,65 @@ out:
return rc;
}
+static int ep11_kb_decode(const u8 *kb, size_t kblen,
+ struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
+ struct ep11keyblob **kbpl, size_t *kbplsize)
+{
+ struct ep11kblob_header *tmph, *hdr = NULL;
+ size_t hdrsize = 0, plsize = 0;
+ struct ep11keyblob *pl = NULL;
+ int rc = -EINVAL;
+ u8 *tmpp;
+
+ if (kblen < sizeof(struct ep11kblob_header))
+ goto out;
+ tmph = (struct ep11kblob_header *)kb;
+
+ if (tmph->type != TOKTYPE_NON_CCA &&
+ tmph->len > kblen)
+ goto out;
+
+ if (ep11_kb_split(kb, kblen, tmph->version,
+ &hdr, &hdrsize, &tmpp, &plsize))
+ goto out;
+
+ if (plsize < sizeof(struct ep11keyblob))
+ goto out;
+
+ if (!is_ep11_keyblob(tmpp))
+ goto out;
+
+ pl = (struct ep11keyblob *)tmpp;
+ plsize = hdr->len - hdrsize;
+
+ if (kbhdr)
+ *kbhdr = hdr;
+ if (kbhdrsize)
+ *kbhdrsize = hdrsize;
+ if (kbpl)
+ *kbpl = pl;
+ if (kbplsize)
+ *kbplsize = plsize;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+/*
+ * For valid ep11 keyblobs, returns a reference to the wrappingkey verification
+ * pattern. Otherwise NULL.
+ */
+const u8 *ep11_kb_wkvp(const u8 *keyblob, size_t keybloblen)
+{
+ struct ep11keyblob *kb;
+
+ if (ep11_kb_decode(keyblob, keybloblen, NULL, NULL, &kb, NULL))
+ return NULL;
+ return kb->wkvp;
+}
+EXPORT_SYMBOL(ep11_kb_wkvp);
+
/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
*/
@@ -1170,10 +1229,10 @@ static int ep11_unwrapkey(u16 card, u16 domain,
return 0;
}
-static int ep11_wrapkey(u16 card, u16 domain,
- const u8 *key, size_t keysize,
- u32 mech, const u8 *iv,
- u8 *databuf, size_t *datasize)
+static int _ep11_wrapkey(u16 card, u16 domain,
+ const u8 *key, size_t keysize,
+ u32 mech, const u8 *iv,
+ u8 *databuf, size_t *datasize)
{
struct wk_req_pl {
struct pl_head head;
@@ -1203,20 +1262,10 @@ static int ep11_wrapkey(u16 card, u16 domain,
struct ep11_cprb *req = NULL, *rep = NULL;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
- struct ep11keyblob *kb;
size_t req_pl_size;
int api, rc = -ENOMEM;
- bool has_header = false;
u8 *p;
- /* maybe the session field holds a header with key info */
- kb = (struct ep11keyblob *)key;
- if (kb->head.type == TOKTYPE_NON_CCA &&
- kb->head.version == TOKVER_EP11_AES) {
- has_header = true;
- keysize = min_t(size_t, kb->head.len, keysize);
- }
-
/* request cprb and payload */
req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0)
+ ASN1TAGLEN(keysize) + 4;
@@ -1241,11 +1290,6 @@ static int ep11_wrapkey(u16 card, u16 domain,
}
/* key blob */
p += asn1tag_write(p, 0x04, key, keysize);
- /* maybe the key argument needs the head data cleaned out */
- if (has_header) {
- kb = (struct ep11keyblob *)(p - keysize);
- memset(&kb->head, 0, sizeof(kb->head));
- }
/* empty kek tag */
*p++ = 0x04;
*p++ = 0;
@@ -1366,11 +1410,12 @@ out:
}
EXPORT_SYMBOL(ep11_clr2keyblob);
-int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
+int ep11_kblob2protkey(u16 card, u16 dom,
+ const u8 *keyblob, size_t keybloblen,
u8 *protkey, u32 *protkeylen, u32 *protkeytype)
{
- int rc = -EIO;
- u8 *wkbuf = NULL;
+ struct ep11kblob_header *hdr;
+ struct ep11keyblob *key;
size_t wkbuflen, keylen;
struct wk_info {
u16 version;
@@ -1381,31 +1426,17 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
u8 res2[8];
u8 pkey[];
} __packed * wki;
- const u8 *key;
- struct ep11kblob_header *hdr;
+ u8 *wkbuf = NULL;
+ int rc = -EIO;
- /* key with or without header ? */
- hdr = (struct ep11kblob_header *)keyblob;
- if (hdr->type == TOKTYPE_NON_CCA &&
- (hdr->version == TOKVER_EP11_AES_WITH_HEADER ||
- hdr->version == TOKVER_EP11_ECC_WITH_HEADER) &&
- is_ep11_keyblob(keyblob + sizeof(struct ep11kblob_header))) {
- /* EP11 AES or ECC key with header */
- key = keyblob + sizeof(struct ep11kblob_header);
- keylen = hdr->len - sizeof(struct ep11kblob_header);
- } else if (hdr->type == TOKTYPE_NON_CCA &&
- hdr->version == TOKVER_EP11_AES &&
- is_ep11_keyblob(keyblob)) {
- /* EP11 AES key (old style) */
- key = keyblob;
- keylen = hdr->len;
- } else if (is_ep11_keyblob(keyblob)) {
- /* raw EP11 key blob */
- key = keyblob;
- keylen = keybloblen;
- } else {
+ if (ep11_kb_decode((u8 *)keyblob, keybloblen, &hdr, NULL, &key, &keylen))
return -EINVAL;
+
+ if (hdr->version == TOKVER_EP11_AES) {
+ /* wipe overlayed header */
+ memset(hdr, 0, sizeof(*hdr));
}
+ /* !!! hdr is no longer a valid header !!! */
/* alloc temp working buffer */
wkbuflen = (keylen + AES_BLOCK_SIZE) & (~(AES_BLOCK_SIZE - 1));
@@ -1414,8 +1445,8 @@ int ep11_kblob2protkey(u16 card, u16 dom, const u8 *keyblob, size_t keybloblen,
return -ENOMEM;
/* ep11 secure key -> protected key + info */
- rc = ep11_wrapkey(card, dom, key, keylen,
- 0, def_iv, wkbuf, &wkbuflen);
+ rc = _ep11_wrapkey(card, dom, (u8 *)key, keylen,
+ 0, def_iv, wkbuf, &wkbuflen);
if (rc) {
DEBUG_ERR(
"%s rewrapping ep11 key to pkey failed, rc=%d\n",
diff --git a/drivers/s390/crypto/zcrypt_ep11misc.h b/drivers/s390/crypto/zcrypt_ep11misc.h
index b611cf64231d..a0de1cccebbe 100644
--- a/drivers/s390/crypto/zcrypt_ep11misc.h
+++ b/drivers/s390/crypto/zcrypt_ep11misc.h
@@ -49,6 +49,12 @@ static inline bool is_ep11_keyblob(const u8 *key)
}
/*
+ * For valid ep11 keyblobs, returns a reference to the wrappingkey verification
+ * pattern. Otherwise NULL.
+ */
+const u8 *ep11_kb_wkvp(const u8 *kblob, size_t kbloblen);
+
+/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
* If checkcpacfexport is enabled, the key is also checked for the
* attributes needed to export this key for CPACF use.