Commit fb1136d6 authored by Ingo Franzki's avatar Ingo Franzki Committed by Martin Schwidefsky
Browse files

s390/pkey: Introduce new API for transforming key blobs



Introduce a new ioctl API and in-kernel API to transform
a variable length key blob of any supported type into a
protected key.

Transforming a secure key blob uses the already existing
function pkey_sec2protk().
Transforming a protected key blob also verifies if the
protected key is still valid. If not, -ENODEV is returned.

Both APIs are described in detail in the header files
arch/s390/include/asm/pkey.h and arch/s390/include/uapi/asm/pkey.h.

Signed-off-by: default avatarIngo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarHendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent cb26b9ff
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -125,4 +125,14 @@ int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey);
 */
int pkey_verifyprotkey(const struct pkey_protkey *protkey);

/*
 * In-kernel API: Transform an key blob (of any type) into a protected key.
 * @param key pointer to a buffer containing the key blob
 * @param keylen size of the key blob in bytes
 * @param protkey pointer to buffer receiving the protected key
 * @return 0 on success, negative errno value on failure
 */
int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
		      struct pkey_protkey *protkey);

#endif /* _KAPI_PKEY_H */
+15 −0
Original line number Diff line number Diff line
@@ -21,9 +21,13 @@
#define PKEY_IOCTL_MAGIC 'p'

#define SECKEYBLOBSIZE	64     /* secure key blob size is always 64 bytes */
#define PROTKEYBLOBSIZE 80  /* protected key blob size is always 80 bytes */
#define MAXPROTKEYSIZE	64  /* a protected key blob may be up to 64 bytes */
#define MAXCLRKEYSIZE	32     /* a clear key value may be up to 32 bytes */

#define MINKEYBLOBSIZE	SECKEYBLOBSIZE	    /* Minimum size of a key blob */
#define MAXKEYBLOBSIZE	PROTKEYBLOBSIZE     /* Maximum size of a key blob */

/* defines for the type field within the pkey_protkey struct */
#define PKEY_KEYTYPE_AES_128  1
#define PKEY_KEYTYPE_AES_192  2
@@ -148,4 +152,15 @@ struct pkey_verifyprotk {

#define PKEY_VERIFYPROTK _IOW(PKEY_IOCTL_MAGIC, 0x09, struct pkey_verifyprotk)

/*
 * Transform an key blob (of any type) into a protected key
 */
struct pkey_kblob2pkey {
	__u8 __user *key;		/* in: the key blob	   */
	__u32 keylen;			/* in: the key blob length */
	struct pkey_protkey protkey;	/* out: the protected key  */
};

#define PKEY_KBLOB2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x0A, struct pkey_kblob2pkey)

#endif /* _UAPI_PKEY_H */
+110 −0
Original line number Diff line number Diff line
@@ -67,6 +67,14 @@ static void __exit pkey_debug_exit(void)
/* For TOKTYPE_CCA_INTERNAL: */
#define TOKVER_CCA_AES		0x04 /* CCA AES key token */

/* header part of a key token */
struct keytoken_header {
	u8  type;     /* one of the TOKTYPE values */
	u8  res0[3];
	u8  version;  /* one of the TOKVER values */
	u8  res1[3];
} __packed;

/* inside view of a secure key token (only type 0x01 version 0x04) */
struct secaeskeytoken {
	u8  type;     /* 0x01 for internal key token */
@@ -1160,6 +1168,80 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey)
}
EXPORT_SYMBOL(pkey_verifyprotkey);

/*
 * Transform a non-CCA key token into a protected key
 */
static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen,
			       struct pkey_protkey *protkey)
{
	struct keytoken_header *hdr = (struct keytoken_header *)key;
	struct protaeskeytoken *t;

	switch (hdr->version) {
	case TOKVER_PROTECTED_KEY:
		if (keylen != sizeof(struct protaeskeytoken))
			return -EINVAL;

		t = (struct protaeskeytoken *)key;
		protkey->len = t->len;
		protkey->type = t->keytype;
		memcpy(protkey->protkey, t->protkey,
		       sizeof(protkey->protkey));

		return pkey_verifyprotkey(protkey);
	default:
		DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
			  __func__, hdr->version);
		return -EINVAL;
	}
}

/*
 * Transform a CCA internal key token into a protected key
 */
static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen,
			       struct pkey_protkey *protkey)
{
	struct keytoken_header *hdr = (struct keytoken_header *)key;

	switch (hdr->version) {
	case TOKVER_CCA_AES:
		if (keylen != sizeof(struct secaeskeytoken))
			return -EINVAL;

		return pkey_skey2pkey((struct pkey_seckey *)key,
				      protkey);
	default:
		DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
			  __func__, hdr->version);
		return -EINVAL;
	}
}

/*
 * Transform a key blob (of any type) into a protected key
 */
int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
		      struct pkey_protkey *protkey)
{
	struct keytoken_header *hdr = (struct keytoken_header *)key;

	if (keylen < sizeof(struct keytoken_header))
		return -EINVAL;

	switch (hdr->type) {
	case TOKTYPE_NON_CCA:
		return pkey_nonccatok2pkey(key, keylen, protkey);
	case TOKTYPE_CCA_INTERNAL:
		return pkey_ccainttok2pkey(key, keylen, protkey);
	default:
		DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__,
			  hdr->type);
		return -EINVAL;
	}
}
EXPORT_SYMBOL(pkey_keyblob2pkey);

/*
 * File io functions
 */
@@ -1300,6 +1382,34 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
		DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
		break;
	}
	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)
			return -ENOMEM;
		if (copy_from_user(kkey, ukey, ktp.keylen)) {
			kfree(kkey);
			return -EFAULT;
		}
		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;
	}
	default:
		/* unknown/unsupported ioctl cmd */
		return -ENOTTY;