From 70025f84e5b79627a6739533c4fe7cef5b605886 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2018 17:46:51 +0100 Subject: KEYS: Provide key type operations for asymmetric key ops [ver #2] Provide five new operations in the key_type struct that can be used to provide access to asymmetric key operations. These will be implemented for the asymmetric key type in a later patch and may refer to a key retained in RAM by the kernel or a key retained in crypto hardware. int (*asym_query)(const struct kernel_pkey_params *params, struct kernel_pkey_query *info); int (*asym_eds_op)(struct kernel_pkey_params *params, const void *in, void *out); int (*asym_verify_signature)(struct kernel_pkey_params *params, const void *in, const void *in2); Since encrypt, decrypt and sign are identical in their interfaces, they're rolled together in the asym_eds_op() operation and there's an operation ID in the params argument to distinguish them. Verify is different in that we supply the data and the signature instead and get an error value (or 0) as the only result on the expectation that this may well be how a hardware crypto device may work. Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Reviewed-by: Denis Kenzior Tested-by: Denis Kenzior Signed-off-by: James Morris --- include/linux/key-type.h | 11 +++++++++++ include/linux/keyctl.h | 46 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/keyctl.h | 5 +++++ 3 files changed, 62 insertions(+) create mode 100644 include/linux/keyctl.h (limited to 'include') diff --git a/include/linux/key-type.h b/include/linux/key-type.h index 05d8fb5a06c4..bc9af551fc83 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h @@ -17,6 +17,9 @@ #ifdef CONFIG_KEYS +struct kernel_pkey_query; +struct kernel_pkey_params; + /* * key under-construction record * - passed to the request_key actor if supplied @@ -155,6 +158,14 @@ struct key_type { */ struct key_restriction *(*lookup_restriction)(const char *params); + /* Asymmetric key accessor functions. */ + int (*asym_query)(const struct kernel_pkey_params *params, + struct kernel_pkey_query *info); + int (*asym_eds_op)(struct kernel_pkey_params *params, + const void *in, void *out); + int (*asym_verify_signature)(struct kernel_pkey_params *params, + const void *in, const void *in2); + /* internal fields */ struct list_head link; /* link in types list */ struct lock_class_key lock_class; /* key->sem lock class */ diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h new file mode 100644 index 000000000000..c7c48c79ce0e --- /dev/null +++ b/include/linux/keyctl.h @@ -0,0 +1,46 @@ +/* keyctl kernel bits + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef __LINUX_KEYCTL_H +#define __LINUX_KEYCTL_H + +#include + +struct kernel_pkey_query { + __u32 supported_ops; /* Which ops are supported */ + __u32 key_size; /* Size of the key in bits */ + __u16 max_data_size; /* Maximum size of raw data to sign in bytes */ + __u16 max_sig_size; /* Maximum size of signature in bytes */ + __u16 max_enc_size; /* Maximum size of encrypted blob in bytes */ + __u16 max_dec_size; /* Maximum size of decrypted blob in bytes */ +}; + +enum kernel_pkey_operation { + kernel_pkey_encrypt, + kernel_pkey_decrypt, + kernel_pkey_sign, + kernel_pkey_verify, +}; + +struct kernel_pkey_params { + struct key *key; + const char *encoding; /* Encoding (eg. "oaep" or "raw" for none) */ + const char *hash_algo; /* Digest algorithm used (eg. "sha1") or NULL if N/A */ + char *info; /* Modified info string to be released later */ + __u32 in_len; /* Input data size */ + union { + __u32 out_len; /* Output buffer size (enc/dec/sign) */ + __u32 in2_len; /* 2nd input data size (verify) */ + }; + enum kernel_pkey_operation op : 8; +}; + +#endif /* __LINUX_KEYCTL_H */ diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 0f3cb13db8e9..1d1e9f2877af 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h @@ -82,4 +82,9 @@ struct keyctl_kdf_params { __u32 __spare[8]; }; +#define KEYCTL_SUPPORTS_ENCRYPT 0x01 +#define KEYCTL_SUPPORTS_DECRYPT 0x02 +#define KEYCTL_SUPPORTS_SIGN 0x04 +#define KEYCTL_SUPPORTS_VERIFY 0x08 + #endif /* _LINUX_KEYCTL_H */ -- cgit v1.2.3 From 00d60fd3b93219ea854220f0fd264b86398cbc53 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2018 17:46:59 +0100 Subject: KEYS: Provide keyctls to drive the new key type ops for asymmetric keys [ver #2] Provide five keyctl functions that permit userspace to make use of the new key type ops for accessing and driving asymmetric keys. (*) Query an asymmetric key. long keyctl(KEYCTL_PKEY_QUERY, key_serial_t key, unsigned long reserved, struct keyctl_pkey_query *info); Get information about an asymmetric key. The information is returned in the keyctl_pkey_query struct: __u32 supported_ops; A bit mask of flags indicating which ops are supported. This is constructed from a bitwise-OR of: KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY} __u32 key_size; The size in bits of the key. __u16 max_data_size; __u16 max_sig_size; __u16 max_enc_size; __u16 max_dec_size; The maximum sizes in bytes of a blob of data to be signed, a signature blob, a blob to be encrypted and a blob to be decrypted. reserved must be set to 0. This is intended for future use to hand over one or more passphrases needed unlock a key. If successful, 0 is returned. If the key is not an asymmetric key, EOPNOTSUPP is returned. (*) Encrypt, decrypt, sign or verify a blob using an asymmetric key. long keyctl(KEYCTL_PKEY_ENCRYPT, const struct keyctl_pkey_params *params, const char *info, const void *in, void *out); long keyctl(KEYCTL_PKEY_DECRYPT, const struct keyctl_pkey_params *params, const char *info, const void *in, void *out); long keyctl(KEYCTL_PKEY_SIGN, const struct keyctl_pkey_params *params, const char *info, const void *in, void *out); long keyctl(KEYCTL_PKEY_VERIFY, const struct keyctl_pkey_params *params, const char *info, const void *in, const void *in2); Use an asymmetric key to perform a public-key cryptographic operation a blob of data. The parameter block pointed to by params contains a number of integer values: __s32 key_id; __u32 in_len; __u32 out_len; __u32 in2_len; For a given operation, the in and out buffers are used as follows: Operation ID in,in_len out,out_len in2,in2_len ======================= =============== =============== =========== KEYCTL_PKEY_ENCRYPT Raw data Encrypted data - KEYCTL_PKEY_DECRYPT Encrypted data Raw data - KEYCTL_PKEY_SIGN Raw data Signature - KEYCTL_PKEY_VERIFY Raw data - Signature info is a string of key=value pairs that supply supplementary information. The __spare space in the parameter block must be set to 0. This is intended, amongst other things, to allow the passing of passphrases required to unlock a key. If successful, encrypt, decrypt and sign all return the amount of data written into the output buffer. Verification returns 0 on success. Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Reviewed-by: Denis Kenzior Tested-by: Denis Kenzior Signed-off-by: James Morris --- include/uapi/linux/keyctl.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h index 1d1e9f2877af..f45ee0f69c0c 100644 --- a/include/uapi/linux/keyctl.h +++ b/include/uapi/linux/keyctl.h @@ -61,6 +61,11 @@ #define KEYCTL_INVALIDATE 21 /* invalidate a key */ #define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ #define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ +#define KEYCTL_PKEY_QUERY 24 /* Query public key parameters */ +#define KEYCTL_PKEY_ENCRYPT 25 /* Encrypt a blob using a public key */ +#define KEYCTL_PKEY_DECRYPT 26 /* Decrypt a blob using a public key */ +#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */ +#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */ #define KEYCTL_RESTRICT_KEYRING 29 /* Restrict keys allowed to link to a keyring */ /* keyctl structures */ @@ -87,4 +92,24 @@ struct keyctl_kdf_params { #define KEYCTL_SUPPORTS_SIGN 0x04 #define KEYCTL_SUPPORTS_VERIFY 0x08 +struct keyctl_pkey_query { + __u32 supported_ops; /* Which ops are supported */ + __u32 key_size; /* Size of the key in bits */ + __u16 max_data_size; /* Maximum size of raw data to sign in bytes */ + __u16 max_sig_size; /* Maximum size of signature in bytes */ + __u16 max_enc_size; /* Maximum size of encrypted blob in bytes */ + __u16 max_dec_size; /* Maximum size of decrypted blob in bytes */ + __u32 __spare[10]; +}; + +struct keyctl_pkey_params { + __s32 key_id; /* Serial no. of public key to use */ + __u32 in_len; /* Input data size */ + union { + __u32 out_len; /* Output buffer size (encrypt/decrypt/sign) */ + __u32 in2_len; /* 2nd input data size (verify) */ + }; + __u32 __spare[7]; +}; + #endif /* _LINUX_KEYCTL_H */ -- cgit v1.2.3 From 5a30771832aab228e0863e414f9182f86797429e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2018 17:47:07 +0100 Subject: KEYS: Provide missing asymmetric key subops for new key type ops [ver #2] Provide the missing asymmetric key subops for new key type ops. This include query, encrypt, decrypt and create signature. Verify signature already exists. Also provided are accessor functions for this: int query_asymmetric_key(const struct key *key, struct kernel_pkey_query *info); int encrypt_blob(struct kernel_pkey_params *params, const void *data, void *enc); int decrypt_blob(struct kernel_pkey_params *params, const void *enc, void *data); int create_signature(struct kernel_pkey_params *params, const void *data, void *enc); The public_key_signature struct gains an encoding field to carry the encoding for verify_signature(). Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Reviewed-by: Denis Kenzior Tested-by: Denis Kenzior Signed-off-by: James Morris --- include/crypto/public_key.h | 13 +++++++++++-- include/keys/asymmetric-subtype.h | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index e0b681a717ba..3a1047a0195c 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -14,6 +14,8 @@ #ifndef _LINUX_PUBLIC_KEY_H #define _LINUX_PUBLIC_KEY_H +#include + /* * Cryptographic data for the public-key subtype of the asymmetric key type. * @@ -40,6 +42,7 @@ struct public_key_signature { u8 digest_size; /* Number of bytes in digest */ const char *pkey_algo; const char *hash_algo; + const char *encoding; }; extern void public_key_signature_free(struct public_key_signature *sig); @@ -65,8 +68,14 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, const union key_payload *payload, struct key *trusted); -extern int verify_signature(const struct key *key, - const struct public_key_signature *sig); +extern int query_asymmetric_key(const struct kernel_pkey_params *, + struct kernel_pkey_query *); + +extern int encrypt_blob(struct kernel_pkey_params *, const void *, void *); +extern int decrypt_blob(struct kernel_pkey_params *, const void *, void *); +extern int create_signature(struct kernel_pkey_params *, const void *, void *); +extern int verify_signature(const struct key *, + const struct public_key_signature *); int public_key_verify_signature(const struct public_key *pkey, const struct public_key_signature *sig); diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h index e0a9c2368872..9ce2f0fae57e 100644 --- a/include/keys/asymmetric-subtype.h +++ b/include/keys/asymmetric-subtype.h @@ -17,6 +17,8 @@ #include #include +struct kernel_pkey_query; +struct kernel_pkey_params; struct public_key_signature; /* @@ -34,6 +36,13 @@ struct asymmetric_key_subtype { /* Destroy a key of this subtype */ void (*destroy)(void *payload_crypto, void *payload_auth); + int (*query)(const struct kernel_pkey_params *params, + struct kernel_pkey_query *info); + + /* Encrypt/decrypt/sign data */ + int (*eds_op)(struct kernel_pkey_params *params, + const void *in, void *out); + /* Verify the signature on a key of this subtype (optional) */ int (*verify_signature)(const struct key *key, const struct public_key_signature *sig); -- cgit v1.2.3 From f7c4e06e066c3df282e6e3d4e7d8c498be9e1e46 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 9 Oct 2018 17:47:31 +0100 Subject: KEYS: Allow the public_key struct to hold a private key [ver #2] Put a flag in the public_key struct to indicate if the structure is holding a private key. The private key must be held ASN.1 encoded in the format specified in RFC 3447 A.1.2. This is the form required by crypto/rsa.c. The software encryption subtype's verification and query functions then need to select the appropriate crypto function to set the key. Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Reviewed-by: Denis Kenzior Tested-by: Denis Kenzior Signed-off-by: James Morris --- include/crypto/public_key.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 3a1047a0195c..be626eac9113 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -25,6 +25,7 @@ struct public_key { void *key; u32 keylen; + bool key_is_private; const char *id_type; const char *pkey_algo; }; -- cgit v1.2.3 From 903be6bb84c544551150a6f5aab9fda1ed9a6895 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Tue, 9 Oct 2018 17:48:02 +0100 Subject: KEYS: asym_tpm: add skeleton for asym_tpm [ver #2] This patch adds the basic skeleton for the asym_tpm asymmetric key subtype. Signed-off-by: Denis Kenzior Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Signed-off-by: James Morris --- include/crypto/asym_tpm_subtype.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 include/crypto/asym_tpm_subtype.h (limited to 'include') diff --git a/include/crypto/asym_tpm_subtype.h b/include/crypto/asym_tpm_subtype.h new file mode 100644 index 000000000000..03550b850998 --- /dev/null +++ b/include/crypto/asym_tpm_subtype.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _LINUX_ASYM_TPM_SUBTYPE_H +#define _LINUX_ASYM_TPM_SUBTYPE_H + +#include + +struct tpm_key { + void *blob; + u32 blob_len; +}; + +struct tpm_key *tpm_key_create(const void *blob, uint32_t blob_len); + +extern struct asymmetric_key_subtype asym_tpm_subtype; + +#endif /* _LINUX_ASYM_TPM_SUBTYPE_H */ -- cgit v1.2.3 From f8c54e1ac4b82933dfcf88c37892da8ae35ccbe4 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Tue, 9 Oct 2018 17:48:10 +0100 Subject: KEYS: asym_tpm: extract key size & public key [ver #2] The parsed BER/DER blob obtained from user space contains a TPM_Key structure. This structure has some information about the key as well as the public key portion. This patch extracts this information for future use. Signed-off-by: Denis Kenzior Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Signed-off-by: James Morris --- include/crypto/asym_tpm_subtype.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/crypto/asym_tpm_subtype.h b/include/crypto/asym_tpm_subtype.h index 03550b850998..48198c36d6b9 100644 --- a/include/crypto/asym_tpm_subtype.h +++ b/include/crypto/asym_tpm_subtype.h @@ -7,6 +7,9 @@ struct tpm_key { void *blob; u32 blob_len; + uint16_t key_len; /* Size in bits of the key */ + const void *pub_key; /* pointer inside blob to the public key bytes */ + uint16_t pub_key_len; /* length of the public key */ }; struct tpm_key *tpm_key_create(const void *blob, uint32_t blob_len); -- cgit v1.2.3 From 22447981fc050b5f1bdd0e7cbee89b4152a2b2d8 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Tue, 9 Oct 2018 17:48:49 +0100 Subject: KEYS: Move trusted.h to include/keys [ver #2] Signed-off-by: Denis Kenzior Signed-off-by: David Howells Tested-by: Marcel Holtmann Reviewed-by: Marcel Holtmann Signed-off-by: James Morris --- include/keys/trusted.h | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 include/keys/trusted.h (limited to 'include') diff --git a/include/keys/trusted.h b/include/keys/trusted.h new file mode 100644 index 000000000000..adbcb6817826 --- /dev/null +++ b/include/keys/trusted.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TRUSTED_KEY_H +#define __TRUSTED_KEY_H + +/* implementation specific TPM constants */ +#define MAX_BUF_SIZE 1024 +#define TPM_GETRANDOM_SIZE 14 +#define TPM_OSAP_SIZE 36 +#define TPM_OIAP_SIZE 10 +#define TPM_SEAL_SIZE 87 +#define TPM_UNSEAL_SIZE 104 +#define TPM_SIZE_OFFSET 2 +#define TPM_RETURN_OFFSET 6 +#define TPM_DATA_OFFSET 10 + +#define LOAD32(buffer, offset) (ntohl(*(uint32_t *)&buffer[offset])) +#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset]) +#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset])) + +struct tpm_buf { + int len; + unsigned char data[MAX_BUF_SIZE]; +}; + +#define INIT_BUF(tb) (tb->len = 0) + +struct osapsess { + uint32_t handle; + unsigned char secret[SHA1_DIGEST_SIZE]; + unsigned char enonce[TPM_NONCE_SIZE]; +}; + +/* discrete values, but have to store in uint16_t for TPM use */ +enum { + SEAL_keytype = 1, + SRK_keytype = 4 +}; + +int TSS_authhmac(unsigned char *digest, const unsigned char *key, + unsigned int keylen, unsigned char *h1, + unsigned char *h2, unsigned char h3, ...); +int TSS_checkhmac1(unsigned char *buffer, + const uint32_t command, + const unsigned char *ononce, + const unsigned char *key, + unsigned int keylen, ...); + +int trusted_tpm_send(unsigned char *cmd, size_t buflen); +int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce); + +#define TPM_DEBUG 0 + +#if TPM_DEBUG +static inline void dump_options(struct trusted_key_options *o) +{ + pr_info("trusted_key: sealing key type %d\n", o->keytype); + pr_info("trusted_key: sealing key handle %0X\n", o->keyhandle); + pr_info("trusted_key: pcrlock %d\n", o->pcrlock); + pr_info("trusted_key: pcrinfo %d\n", o->pcrinfo_len); + print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE, + 16, 1, o->pcrinfo, o->pcrinfo_len, 0); +} + +static inline void dump_payload(struct trusted_key_payload *p) +{ + pr_info("trusted_key: key_len %d\n", p->key_len); + print_hex_dump(KERN_INFO, "key ", DUMP_PREFIX_NONE, + 16, 1, p->key, p->key_len, 0); + pr_info("trusted_key: bloblen %d\n", p->blob_len); + print_hex_dump(KERN_INFO, "blob ", DUMP_PREFIX_NONE, + 16, 1, p->blob, p->blob_len, 0); + pr_info("trusted_key: migratable %d\n", p->migratable); +} + +static inline void dump_sess(struct osapsess *s) +{ + print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE, + 16, 1, &s->handle, 4, 0); + pr_info("trusted-key: secret:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->secret, SHA1_DIGEST_SIZE, 0); + pr_info("trusted-key: enonce:\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, + 16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0); +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ + int len; + + pr_info("\ntrusted-key: tpm buffer\n"); + len = LOAD32(buf, TPM_SIZE_OFFSET); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0); +} +#else +static inline void dump_options(struct trusted_key_options *o) +{ +} + +static inline void dump_payload(struct trusted_key_payload *p) +{ +} + +static inline void dump_sess(struct osapsess *s) +{ +} + +static inline void dump_tpm_buf(unsigned char *buf) +{ +} +#endif + +static inline void store8(struct tpm_buf *buf, const unsigned char value) +{ + buf->data[buf->len++] = value; +} + +static inline void store16(struct tpm_buf *buf, const uint16_t value) +{ + *(uint16_t *) & buf->data[buf->len] = htons(value); + buf->len += sizeof value; +} + +static inline void store32(struct tpm_buf *buf, const uint32_t value) +{ + *(uint32_t *) & buf->data[buf->len] = htonl(value); + buf->len += sizeof value; +} + +static inline void storebytes(struct tpm_buf *buf, const unsigned char *in, + const int len) +{ + memcpy(buf->data + buf->len, in, len); + buf->len += len; +} +#endif -- cgit v1.2.3