File s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch of Package s390-tools.19914

Subject: zkey: Introduce the CCA-AESCIPHER key type
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: ddde3f354f3506521877a4e2a6082c4d597629cb
Problem-ID:  SEC1717

Upstream-Description:

             zkey: Introduce the CCA-AESCIPHER key type

             Add definitions and helper functions to support the new
             CCA-AESCIPHER key type. Also enhance existing helper functions
             to support CCA-AESCIPHER keys.

             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/keystore.c |    2 
 zkey/pkey.c     |   91 +++++++++++++++++++++++++++++----
 zkey/pkey.h     |  150 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 zkey/zkey.1     |   20 ++++---
 zkey/zkey.c     |    4 -
 5 files changed, 235 insertions(+), 32 deletions(-)

--- a/zkey/keystore.c
+++ b/zkey/keystore.c
@@ -341,6 +341,8 @@ static int _keystore_valid_key_type(cons
 {
 	if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0)
 		return 1;
+	if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0)
+		return 1;
 
 	return 0;
 }
--- a/zkey/pkey.c
+++ b/zkey/pkey.c
@@ -782,23 +782,21 @@ out:
 	return rc;
 }
 
-int get_master_key_verification_pattern(const u8 *secure_key,
-					size_t secure_key_size, u64 *mkvp,
-					bool verbose)
+int get_master_key_verification_pattern(const u8 *key, size_t key_size,
+					u64 *mkvp, bool UNUSED(verbose))
 {
-	struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
+	struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key;
+	struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
 
-	util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
+	util_assert(key != NULL, "Internal error: secure_key is NULL");
 	util_assert(mkvp != NULL, "Internal error: mkvp is NULL");
 
-	if (secure_key_size < AESDATA_KEY_SIZE) {
-		pr_verbose(verbose, "Size of secure key is too small: "
-			   "%lu expected %lu", secure_key_size,
-			   AESDATA_KEY_SIZE);
+	if (is_cca_aes_data_key(key, key_size))
+		*mkvp = datakey->mkvp;
+	else if (is_cca_aes_cipher_key(key, key_size))
+		memcpy(mkvp, cipherkey->kvp, sizeof(*mkvp));
+	else
 		return -EINVAL;
-	}
-
-	*mkvp = token->mkvp;
 
 	return 0;
 }
@@ -827,6 +825,56 @@ bool is_cca_aes_data_key(const u8 *key,
 }
 
 /**
+ * Check if the specified key is a CCA AESCIPHER key token.
+ *
+ * @param[in] key           the secure key token
+ * @param[in] key_size      the size of the secure key
+ *
+ * @returns true if the key is an CCA AESCIPHER token type
+ */
+bool is_cca_aes_cipher_key(const u8 *key, size_t key_size)
+{
+	struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
+
+	if (key == NULL || key_size < AESCIPHER_KEY_SIZE)
+		return false;
+
+	if (cipherkey->type != TOKEN_TYPE_CCA_INTERNAL)
+		return false;
+	if (cipherkey->version != TOKEN_VERSION_AESCIPHER)
+		return false;
+	if (cipherkey->length > key_size)
+		return false;
+
+	if (cipherkey->kms != 0x03) /* key wrapped by master key */
+		return false;
+	if (cipherkey->kwm != 0x02) /* key wrapped using AESKW */
+		return false;
+	if (cipherkey->pfv != 0x00 && cipherkey->pfv != 0x01) /* V0 or V1 */
+		return false;
+	if (cipherkey->adv != 0x01) /* Should have ass. data sect. version 1 */
+		return false;
+	if (cipherkey->at != 0x02) /* Algorithm: AES */
+		return false;
+	if (cipherkey->kt != 0x0001) /* Key type: CIPHER */
+		return false;
+	if (cipherkey->adl != 26) /* Ass. data section length should be 26 */
+		return false;
+	if (cipherkey->kll != 0) /* Should have no key label */
+		return false;
+	if (cipherkey->eadl != 0) /* Should have no ext associated data */
+		return false;
+	if (cipherkey->uadl != 0) /* Should have no user associated data */
+		return false;
+	if (cipherkey->kufc != 2) /* Should have 2 KUFs */
+		return false;
+	if (cipherkey->kmfc != 3) /* Should have 3 KMFs */
+		return false;
+
+	return true;
+}
+
+/**
  * Check if the specified key is an XTS type key
  *
  * @param[in] key           the secure key token
@@ -841,6 +889,11 @@ bool is_xts_key(const u8 *key, size_t ke
 		    is_cca_aes_data_key(key + AESDATA_KEY_SIZE,
 					key_size - AESDATA_KEY_SIZE))
 			return true;
+	} else if (is_cca_aes_cipher_key(key, key_size)) {
+		if (key_size == 2 * AESCIPHER_KEY_SIZE &&
+		    is_cca_aes_cipher_key(key + AESCIPHER_KEY_SIZE,
+					  key_size - AESCIPHER_KEY_SIZE))
+			return true;
 	}
 
 	return false;
@@ -860,6 +913,7 @@ bool is_xts_key(const u8 *key, size_t ke
 int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize)
 {
 	struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key;
+	struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
 
 	util_assert(bitsize != NULL, "Internal error: bitsize is NULL");
 
@@ -870,6 +924,17 @@ int get_key_bit_size(const u8 *key, size
 					AESDATA_KEY_SIZE;
 			*bitsize += datakey->bitsize;
 		}
+	} else if (is_cca_aes_cipher_key(key, key_size)) {
+		if (cipherkey->pfv == 0x00) /* V0 payload */
+			*bitsize = cipherkey->pl - 384;
+		else
+			*bitsize = 0; /* Unknown */
+		if (key_size > cipherkey->length) {
+			cipherkey = (struct aescipherkeytoken *)key +
+					cipherkey->length;
+			if (cipherkey->pfv == 0x00) /* V0 payload */
+				*bitsize += cipherkey->pl - 384;
+		}
 	} else {
 		return -EINVAL;
 	}
@@ -889,6 +954,8 @@ const char *get_key_type(const u8 *key,
 {
 	if (is_cca_aes_data_key(key, key_size))
 		return KEY_TYPE_CCA_AESDATA;
+	if (is_cca_aes_cipher_key(key, key_size))
+		return KEY_TYPE_CCA_AESCIPHER;
 
 	return NULL;
 }
--- a/zkey/pkey.h
+++ b/zkey/pkey.h
@@ -29,6 +29,7 @@ struct tokenheader {
 #define TOKEN_TYPE_CCA_INTERNAL	0x01
 
 #define TOKEN_VERSION_AESDATA	0x04
+#define TOKEN_VERSION_AESCIPHER	0x05
 
 struct aesdatakeytoken {
 	u8  type;     /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
@@ -45,10 +46,45 @@ struct aesdatakeytoken {
 	u8  tvv[4];   /* token validation value */
 } __packed;
 
+struct aescipherkeytoken {
+	u8  type;     /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
+	u8  res0;
+	u16 length;   /* length of token */
+	u8  version;  /* should be TOKEN_VERSION_CIPHER (0x05) */
+	u8  res1[3];
+	u8  kms;      /* key material state, should be 0x03 */
+	u8  kvptype;  /* key verification pattern type */
+	u8  kvp[16];  /* key verification pattern */
+	u8  kwm;      /* key wrapping method, should be 0x02 */
+	u8  kwh;      /* key wrapping hash algorithm */
+	u8  pfv;      /* payload format version, should be 0x00*/
+	u8  res2;
+	u8  adv;      /* associated data section version */
+	u8  res3;
+	u16 adl;      /* associated data length */
+	u8  kll;      /* length of optional key label */
+	u8  eadl;     /* extended associated data length */
+	u8  uadl;     /* user associated data length */
+	u8  res4;
+	u16 pl;       /* payload bit length */
+	u8  res5;
+	u8  at;       /* algorithm type, should be 0x02 (AES) */
+	u16 kt;       /* key type, should be 0x001 (CIPHER) */
+	u8  kufc;     /* key usage field count */
+	u16 kuf1;     /* key usage field 1 */
+	u16 kuf2;     /* key usage field 2 */
+	u8  kmfc;     /* key management field count */
+	u16 kmf1;     /* key management field 1 */
+	u16 kmf2;     /* key management field 2 */
+	u16 kmf3;     /* key management field 3 */
+	u8  varpart[80]; /* variable part */
+} __packed;
+
 #define AESDATA_KEY_SIZE	sizeof(struct aesdatakeytoken)
+#define AESCIPHER_KEY_SIZE	sizeof(struct aescipherkeytoken)
 
-#define MAX_SECURE_KEY_SIZE	AESDATA_KEY_SIZE
-#define MIN_SECURE_KEY_SIZE	AESDATA_KEY_SIZE
+#define MAX_SECURE_KEY_SIZE	MAX(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
+#define MIN_SECURE_KEY_SIZE	MIN(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
 
 struct pkey_seckey {
 	u8  seckey[AESDATA_KEY_SIZE];  /* the secure key blob */
@@ -58,12 +94,12 @@ struct pkey_clrkey {
 	u8  clrkey[32]; /* 16, 24, or 32 byte clear key value */
 };
 
-#define PKEY_IOCTL_MAGIC 'p'
-#define AUTOSELECT 0xFFFF
-#define PKEYDEVICE "/dev/pkey"
-#define PKEY_KEYTYPE_AES_128  1
-#define PKEY_KEYTYPE_AES_192  2
-#define PKEY_KEYTYPE_AES_256  3
+#define PKEY_IOCTL_MAGIC	'p'
+#define AUTOSELECT		0xFFFF
+#define PKEYDEVICE		"/dev/pkey"
+#define PKEY_KEYTYPE_AES_128	1
+#define PKEY_KEYTYPE_AES_192	2
+#define PKEY_KEYTYPE_AES_256	3
 
 struct pkey_genseck {
 	u16 cardnr;			/* in: card to use or FFFF for any */
@@ -97,7 +133,99 @@ struct pkey_verifykey {
 
 #define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
 
+enum pkey_key_type {
+	PKEY_TYPE_CCA_DATA   = (u32) 1,
+	PKEY_TYPE_CCA_CIPHER = (u32) 2,
+};
+
+enum pkey_key_size {
+	PKEY_SIZE_AES_128 = (u32) 128,
+	PKEY_SIZE_AES_192 = (u32) 192,
+	PKEY_SIZE_AES_256 = (u32) 256,
+	PKEY_SIZE_UNKNOWN = (u32) 0xFFFFFFFF,
+};
+
+#define PKEY_FLAGS_MATCH_CUR_MKVP  0x00000002
+#define PKEY_FLAGS_MATCH_ALT_MKVP  0x00000004
+
+#define PKEY_KEYGEN_XPRT_SYM	0x00008000
+#define PKEY_KEYGEN_XPRT_UASY	0x00004000
+#define PKEY_KEYGEN_XPRT_AASY	0x00002000
+#define PKEY_KEYGEN_XPRT_RAW	0x00001000
+#define PKEY_KEYGEN_XPRT_CPAC	0x00000800
+#define PKEY_KEYGEN_XPRT_DES	0x00000080
+#define PKEY_KEYGEN_XPRT_AES	0x00000040
+#define PKEY_KEYGEN_XPRT_RSA	0x00000008
+
+struct pkey_apqn {
+	u16 card;
+	u16 domain;
+};
+
+struct pkey_genseck2 {
+	struct pkey_apqn *apqns;	/* in: ptr to list of apqn targets */
+	u32 apqn_entries;		/* in: # of apqn target list entries */
+	enum pkey_key_type type;	/* in: key type to generate */
+	enum pkey_key_size size;	/* in: key size to generate */
+	u32 keygenflags;		/* in: key generation flags */
+	u8 *key;			/* in: pointer to key blob buffer */
+	u32 keylen;			/* in: available key blob buffer size */
+					/* out: actual key blob size */
+};
+
+#define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2)
+
+struct pkey_clr2seck2 {
+	struct pkey_apqn *apqns;	/* in: ptr to list of apqn targets */
+	u32 apqn_entries;		/* in: # of apqn target list entries */
+	enum pkey_key_type type;	/* in: key type to generate */
+	enum pkey_key_size size;	/* in: key size to generate */
+	u32 keygenflags;		/* in: key generation flags */
+	struct pkey_clrkey clrkey;	/* in: the clear key value */
+	u8 *key;			/* in: pointer to key blob buffer */
+	u32 keylen;			/* in: available key blob buffer size */
+					/* out: actual key blob size */
+};
+
+#define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2)
+
+struct pkey_verifykey2 {
+	u8 *key;			/* in: pointer to key blob */
+	u32 keylen;			/* in: key blob size */
+	u16 cardnr;			/* in/out: card number */
+	u16 domain;			/* in/out: domain number */
+	enum pkey_key_type type;	/* out: the key type */
+	enum pkey_key_size size;	/* out: the key size */
+	u32 flags;			/* out: additional key info flags */
+};
+
+#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2)
+
+struct pkey_apqns4key {
+	u8 *key;			/* in: pointer to key blob */
+	u32 keylen;			/* in: key blob size */
+	u32 flags;			/* in: match controlling flags */
+	struct pkey_apqn *apqns;	/* in/out: ptr to list of apqn targets*/
+	u32 apqn_entries;		/* in: max # of apqn entries in list */
+					/* out: # apqns stored into the list */
+};
+
+#define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key)
+
+struct pkey_apqns4keytype {
+	enum pkey_key_type type;	/* in: key type */
+	u8  cur_mkvp[32];		/* in: current mkvp */
+	u8  alt_mkvp[32];		/* in: alternate mkvp */
+	u32 flags;			/* in: match controlling flags */
+	struct pkey_apqn *apqns;	/* in/out: ptr to list of apqn targets*/
+	u32 apqn_entries;		/* in: max # of apqn entries in list */
+					/* out: # apqns stored into the list */
+};
+
+#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype)
+
 #define KEY_TYPE_CCA_AESDATA        "CCA-AESDATA"
+#define KEY_TYPE_CCA_AESCIPHER      "CCA-AESCIPHER"
 
 #define PAES_BLOCK_SIZE             16
 #define ENC_ZERO_LEN                (2 * PAES_BLOCK_SIZE)
@@ -129,11 +257,11 @@ int validate_secure_key(int pkey_fd,
 int generate_key_verification_pattern(const u8 *key, size_t key_size,
 				      char *vp, size_t vp_len, bool verbose);
 
-int get_master_key_verification_pattern(const u8 *secure_key,
-					size_t secure_key_size, u64 *mkvp,
-					bool verbose);
+int get_master_key_verification_pattern(const u8 *key, size_t key_size,
+					u64 *mkvp, bool verbose);
 
 bool is_cca_aes_data_key(const u8 *key, size_t key_size);
+bool is_cca_aes_cipher_key(const u8 *key, size_t key_size);
 bool is_xts_key(const u8 *key, size_t key_size);
 int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
 const char *get_key_type(const u8 *key, size_t key_size);
--- a/zkey/zkey.1
+++ b/zkey/zkey.1
@@ -134,10 +134,14 @@ additional information can be associated
 .B \-\-sector-size
 options.
 .PP
-You can generate different types of secure keys: \fBCCA-AESDATA\fP keys.
-Specify the type of the secure key using the
+You can generate different types of secure keys: \fBCCA-AESDATA\fP keys, and
+\fBCCA-AESCIPHER\fP keys. Specify the type of the secure key using the
 .B \-\-key\-type
 option. The default key type is CCA-AESDATA.
+.PP
+.B Note:
+Secure keys of type \fBCCA-AESCIPHER\fP require an IBM cryptographic
+adapter in CCA coprocessor mode of version 6 or later, e.g. a CEX6C.
 .
 .SS "Validating secure AES keys"
 .
@@ -741,9 +745,11 @@ the default volume type is \fBplain\fP.
 This option is only used for secure keys contained in the secure key repository.
 .TP
 .BR \-K ", " \-\-key-type\~\fItype\fP
-Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
-If this option is omitted, then a secure key of type
-CCA-AESDATA is generated.
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
+and \fBCCA-AESCIPHER\fP. If this option is omitted, then a secure key of type
+CCA-AESDATA is generated. Secure keys of type \fBCCA-AESCIPHER\fP require an
+IBM cryptographic adapter in CCA coprocessor mode of version 6 or later, e.g.
+a CEX6C.
 .
 .
 .
@@ -925,8 +931,8 @@ has been compiled with LUKS2 support ena
 This option is only used for secure keys contained in the secure key repository.
 .TP
 .BR \-K ", " \-\-key-type\~\fItype\fP
-Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
-Only keys with the specified key type are listed.
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
+and \fBCCA-AESCIPHER\fP. Only keys with the specified key type are listed.
 This option is only used for secure keys contained in the secure key repository.
 .
 .
--- a/zkey/zkey.c
+++ b/zkey/zkey.c
@@ -221,7 +221,7 @@ static struct util_opt opt_vec[] = {
 		.option = { "key-type", required_argument, NULL, 'K'},
 		.argument = "type",
 		.desc = "The type of the key. Possible values are '"
-			KEY_TYPE_CCA_AESDATA"'. "
+			KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
 			"When this option is omitted, the default is '"
 			KEY_TYPE_CCA_AESDATA"'",
 		.command = COMMAND_GENERATE,
@@ -446,7 +446,7 @@ static struct util_opt opt_vec[] = {
 		.option = { "key-type", required_argument, NULL, 'K'},
 		.argument = "type",
 		.desc = "The type of the key. Possible values are '"
-			KEY_TYPE_CCA_AESDATA"'. "
+			KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
 			"Use this option to list all keys with the specified "
 			"key type.",
 		.command = COMMAND_LIST,
openSUSE Build Service is sponsored by