279 lines
8.5 KiB
Diff
279 lines
8.5 KiB
Diff
|
Subject: zkey: Add wrappers for the new IOCTLs with fallback to the old once
|
||
|
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||
|
|
||
|
Summary: zkey: Add support for CCA AES CIPHER keys
|
||
|
Description: With CCA 5 there is a new secure key type, the so called
|
||
|
variable length symmetric cipher key token. This token format
|
||
|
can hold AES keys with size 128, 192 and 256 bits together
|
||
|
with additional attributes cryptographic bound to the key
|
||
|
token. The attributes may limit the usage of the key, for
|
||
|
example restrict export or usability scope. So this key type
|
||
|
is considered to be even more secure than the traditional
|
||
|
secure key token. This key token type is also called "CCA
|
||
|
AES CIPHER key", where the formerly used key token is called
|
||
|
"CCA AES DATA key".
|
||
|
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||
|
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||
|
keys, as well as AES CIPHER keys. The key type must be specified
|
||
|
at key generation time, the default is to generate AED DATA
|
||
|
keys.
|
||
|
Upstream-ID: d4027e6506963fbf995992e32490d56a6f7ea587
|
||
|
Problem-ID: SEC1717
|
||
|
|
||
|
Upstream-Description:
|
||
|
|
||
|
zkey: Add wrappers for the new IOCTLs with fallback to the old once
|
||
|
|
||
|
By default the new pkey IOCTL are used. In case the pkey device does not
|
||
|
support the new IOCTLs (i.e. errno ENOTTY is returned), then the wrapper
|
||
|
falls back to the old IOCTLs. The old IOCTLs only support secure keys of
|
||
|
type CCA-AESDATA.
|
||
|
|
||
|
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||
|
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||
|
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||
|
|
||
|
|
||
|
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||
|
---
|
||
|
zkey/pkey.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
1 file changed, 228 insertions(+)
|
||
|
|
||
|
--- a/zkey/pkey.c
|
||
|
+++ b/zkey/pkey.c
|
||
|
@@ -270,6 +270,234 @@ out:
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+ * Returns the PKEY_KEYTYPE_xxx value for the specified key size.
|
||
|
+ *
|
||
|
+ * @param[in] keysize the key size in bits
|
||
|
+ *
|
||
|
+ * @returns the PKEY_KEYTYPE_xxx value or 0 for an unknown key size
|
||
|
+ */
|
||
|
+static u32 keysize_to_keytype(enum pkey_key_size keysize)
|
||
|
+{
|
||
|
+ switch (keysize) {
|
||
|
+ case PKEY_SIZE_AES_128:
|
||
|
+ return PKEY_KEYTYPE_AES_128;
|
||
|
+ case PKEY_SIZE_AES_192:
|
||
|
+ return PKEY_KEYTYPE_AES_192;
|
||
|
+ case PKEY_SIZE_AES_256:
|
||
|
+ return PKEY_KEYTYPE_AES_256;
|
||
|
+ default:
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Returns the PKEY_SIZE_xxx value for the specified keybits.
|
||
|
+ *
|
||
|
+ * @param[in] keybits the key size in bits
|
||
|
+ *
|
||
|
+ * @returns thePKEY_SIZE_xxx value or 0 for an unknown key size
|
||
|
+ */
|
||
|
+static enum pkey_key_size keybits_to_keysize(u32 keybits)
|
||
|
+{
|
||
|
+ switch (keybits) {
|
||
|
+ case 128:
|
||
|
+ return PKEY_SIZE_AES_128;
|
||
|
+ case 192:
|
||
|
+ return PKEY_SIZE_AES_192;
|
||
|
+ case 256:
|
||
|
+ return PKEY_SIZE_AES_256;
|
||
|
+ default:
|
||
|
+ return PKEY_SIZE_UNKNOWN;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Wrapper for the PKEY_GENSECK/PKEY_GENSECK2 IOCTL to generate a secure
|
||
|
+ * key of any type by random. If the newer PKEY_GENSECK2 IOCTL is not supported
|
||
|
+ * by the pkey device, then it falls back to the older PKEY_GENSECK IOCTL
|
||
|
+ *
|
||
|
+ * @param[in] pkey_fd the pkey file descriptor
|
||
|
+ * @param[in/out] genseck info about key to generate
|
||
|
+ * @param[in] verbose if true, verbose messages are printed
|
||
|
+ *
|
||
|
+ * @returns 0 on success, a negative errno in case of an error
|
||
|
+ */
|
||
|
+static int pkey_genseck2(int pkey_fd, struct pkey_genseck2 *genseck2,
|
||
|
+ bool verbose)
|
||
|
+{
|
||
|
+ struct pkey_genseck genseck;
|
||
|
+ int rc;
|
||
|
+ u32 i;
|
||
|
+
|
||
|
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||
|
+ util_assert(genseck2 != NULL, "Internal error: genseck2 is NULL");
|
||
|
+
|
||
|
+ rc = ioctl(pkey_fd, PKEY_GENSECK2, genseck2);
|
||
|
+ if (rc != 0 && errno != ENOTTY)
|
||
|
+ return -errno;
|
||
|
+ if (rc == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /* New IOCTL is not available, fall back to old one */
|
||
|
+ pr_verbose(verbose, "ioctl PKEY_GENSECK2 not supported, fall back to "
|
||
|
+ "PKEY_GENSECK");
|
||
|
+
|
||
|
+ if (genseck2->type != PKEY_TYPE_CCA_DATA) {
|
||
|
+ warnx("Key-type is not supported");
|
||
|
+ return -ENOTSUP;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (genseck2->keylen < AESDATA_KEY_SIZE)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ memset(&genseck, 0, sizeof(genseck));
|
||
|
+
|
||
|
+ genseck.keytype = keysize_to_keytype(genseck2->size);
|
||
|
+ if (genseck.keytype == 0)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ for (i = 0; i < genseck2->apqn_entries; i++) {
|
||
|
+ genseck.cardnr = genseck2->apqns[i].card;
|
||
|
+ genseck.domain = genseck2->apqns[i].domain;
|
||
|
+
|
||
|
+ rc = ioctl(pkey_fd, PKEY_GENSECK, &genseck);
|
||
|
+ if (rc != 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ memcpy(genseck2->key, &genseck.seckey.seckey, AESDATA_KEY_SIZE);
|
||
|
+ genseck2->keylen = AESDATA_KEY_SIZE;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return -errno;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Wrapper for the PKEY_CLR2SECK/PKEY_CLR2SECK2 IOCTL to generate a secure
|
||
|
+ * key of any type from a clear key. If the newer PKEY_CLR2SECK2 IOCTL is not
|
||
|
+ * supported by the pkey device, then it falls back to the older PKEY_CLR2SECK
|
||
|
+ * IOCTL
|
||
|
+ *
|
||
|
+ * @param[in] pkey_fd the pkey file descriptor
|
||
|
+ * @param[in/out] clr2seck2 info about key to generate
|
||
|
+ * @param[in] verbose if true, verbose messages are printed
|
||
|
+ *
|
||
|
+ * @returns 0 on success, a negative errno in case of an error
|
||
|
+ */
|
||
|
+static int pkey_clr2seck2(int pkey_fd, struct pkey_clr2seck2 *clr2seck2,
|
||
|
+ bool verbose)
|
||
|
+{
|
||
|
+ struct pkey_clr2seck clr2seck;
|
||
|
+ int rc;
|
||
|
+ u32 i;
|
||
|
+
|
||
|
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||
|
+ util_assert(clr2seck2 != NULL, "Internal error: clr2seck2 is NULL");
|
||
|
+
|
||
|
+ rc = ioctl(pkey_fd, PKEY_CLR2SECK2, clr2seck2);
|
||
|
+ if (rc != 0 && errno != ENOTTY)
|
||
|
+ return -errno;
|
||
|
+ if (rc == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /* New IOCTL is not available, fall back to old one */
|
||
|
+ pr_verbose(verbose, "ioctl PKEY_CLR2SECK2 not supported, fall back to "
|
||
|
+ "PKEY_CLR2SECK");
|
||
|
+
|
||
|
+ if (clr2seck2->type != PKEY_TYPE_CCA_DATA) {
|
||
|
+ warnx("Key-type is not supported");
|
||
|
+ return -ENOTSUP;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (clr2seck2->keylen < AESDATA_KEY_SIZE)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ memset(&clr2seck, 0, sizeof(clr2seck));
|
||
|
+ clr2seck.clrkey = clr2seck2->clrkey;
|
||
|
+
|
||
|
+ clr2seck.keytype = keysize_to_keytype(clr2seck2->size);
|
||
|
+ if (clr2seck.keytype == 0)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ for (i = 0; i < clr2seck2->apqn_entries; i++) {
|
||
|
+ clr2seck.cardnr = clr2seck2->apqns[i].card;
|
||
|
+ clr2seck.domain = clr2seck2->apqns[i].domain;
|
||
|
+
|
||
|
+ rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2seck);
|
||
|
+ if (rc != 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ memcpy(clr2seck2->key, &clr2seck.seckey.seckey,
|
||
|
+ AESDATA_KEY_SIZE);
|
||
|
+ clr2seck2->keylen = AESDATA_KEY_SIZE;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return -errno;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Wrapper for the PKEY_VERIFYKEY/PKEY_VERIFYKEY2 IOCTL to verify a secure
|
||
|
+ * key of any type. If the newer PKEY_VERIFYKEY2 IOCTL is not supported
|
||
|
+ * by the pkey device, then it falls back to the older PKEY_VERIFYKEY IOCTL
|
||
|
+ *
|
||
|
+ * @param[in] pkey_fd the pkey file descriptor
|
||
|
+ * @param[in/out] verifykey2 info about key to verify
|
||
|
+ * @param[in] verbose if true, verbose messages are printed
|
||
|
+ *
|
||
|
+ * @returns 0 on success, a negative errno in case of an error
|
||
|
+ */
|
||
|
+static int pkey_verifyseck2(int pkey_fd, struct pkey_verifykey2 *verifykey2,
|
||
|
+ bool verbose)
|
||
|
+{
|
||
|
+ struct pkey_verifykey verifykey;
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||
|
+ util_assert(verifykey2 != NULL, "Internal error: verifyseck2 is NULL");
|
||
|
+
|
||
|
+ rc = ioctl(pkey_fd, PKEY_VERIFYKEY2, verifykey2);
|
||
|
+ if (rc != 0 && errno != ENOTTY)
|
||
|
+ return -errno;
|
||
|
+ if (rc == 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ /* New IOCTL is not available, fall back to old one */
|
||
|
+ pr_verbose(verbose, "ioctl PKEY_VERIFYKEY2 not supported, fall back to "
|
||
|
+ "PKEY_VERIFYKEY");
|
||
|
+
|
||
|
+ if (!is_cca_aes_data_key(verifykey2->key, verifykey2->keylen))
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
+ memset(&verifykey, 0, sizeof(verifykey));
|
||
|
+ memcpy(&verifykey.seckey, verifykey2->key, sizeof(verifykey.seckey));
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Note: the old IOCTL does not support to check a specific card and
|
||
|
+ * domain. If falling back to the old IOCTL, this input is silently
|
||
|
+ * ignored, and all APQNs currently available in the system are used.
|
||
|
+ */
|
||
|
+ rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
|
||
|
+ if (rc != 0)
|
||
|
+ return -errno;
|
||
|
+
|
||
|
+ if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0)
|
||
|
+ return -ENODEV;
|
||
|
+
|
||
|
+ verifykey2->type = PKEY_TYPE_CCA_DATA;
|
||
|
+ verifykey2->cardnr = verifykey.cardnr;
|
||
|
+ verifykey2->domain = verifykey.domain;
|
||
|
+ verifykey2->size = keybits_to_keysize(verifykey.keysize);
|
||
|
+
|
||
|
+ if (verifykey.attributes & PKEY_VERIFY_ATTR_OLD_MKVP)
|
||
|
+ verifykey2->flags = PKEY_FLAGS_MATCH_ALT_MKVP;
|
||
|
+ else
|
||
|
+ verifykey2->flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
* Generate a secure key by random
|
||
|
*
|
||
|
* @param[in] pkey_fd the pkey file descriptor
|