aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2018-10-09 12:48:25 -0400
committerJames Morris <james.morris@microsoft.com>2018-10-26 04:30:46 -0400
commitdff5a61a59614c110d06a5dc1466cdb762b6affd (patch)
tree6e0f3f8a8eab8f510d19831a8454e7d6c1516dba
parentd5e72745ca121459f68c598dac7b374a76322b94 (diff)
KEYS: asym_tpm: Implement pkey_query [ver #2]
This commit implements the pkey_query operation. This is accomplished by utilizing the public key portion to obtain max encryption size information for the operations that utilize the public key (encrypt, verify). The private key size extracted from the TPM_Key data structure is used to fill the information where the private key is used (decrypt, sign). The kernel uses a DER/BER format for public keys and does not support setting the key via the raw binary form. To get around this a simple DER/BER formatter is implemented which stores the DER/BER formatted key and exponent in a temporary buffer for use by the crypto API. The only exponent supported currently is 65537. This holds true for other Linux TPM tools such as 'create_tpm_key' and trousers-openssl_tpm_engine. Signed-off-by: Denis Kenzior <denkenz@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Marcel Holtmann <marcel@holtmann.org> Reviewed-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: James Morris <james.morris@microsoft.com>
-rw-r--r--crypto/asymmetric_keys/asym_tpm.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index 308c51e055a4..837472d107d5 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -7,11 +7,25 @@
7#include <linux/seq_file.h> 7#include <linux/seq_file.h>
8#include <linux/scatterlist.h> 8#include <linux/scatterlist.h>
9#include <linux/tpm.h> 9#include <linux/tpm.h>
10#include <crypto/akcipher.h>
10#include <asm/unaligned.h> 11#include <asm/unaligned.h>
11#include <keys/asymmetric-subtype.h> 12#include <keys/asymmetric-subtype.h>
12#include <crypto/asym_tpm_subtype.h> 13#include <crypto/asym_tpm_subtype.h>
13 14
14/* 15/*
16 * Maximum buffer size for the BER/DER encoded public key. The public key
17 * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048
18 * bit key and e is usually 65537
19 * The encoding overhead is:
20 * - max 4 bytes for SEQUENCE
21 * - max 4 bytes for INTEGER n type/length
22 * - 257 bytes of n
23 * - max 2 bytes for INTEGER e type/length
24 * - 3 bytes of e
25 */
26#define PUB_KEY_BUF_SIZE (4 + 4 + 257 + 2 + 3)
27
28/*
15 * Provide a part of a description of the key for /proc/keys. 29 * Provide a part of a description of the key for /proc/keys.
16 */ 30 */
17static void asym_tpm_describe(const struct key *asymmetric_key, 31static void asym_tpm_describe(const struct key *asymmetric_key,
@@ -38,6 +52,126 @@ static void asym_tpm_destroy(void *payload0, void *payload3)
38 kfree(tk); 52 kfree(tk);
39} 53}
40 54
55/* How many bytes will it take to encode the length */
56static inline uint32_t definite_length(uint32_t len)
57{
58 if (len <= 127)
59 return 1;
60 if (len <= 255)
61 return 2;
62 return 3;
63}
64
65static inline uint8_t *encode_tag_length(uint8_t *buf, uint8_t tag,
66 uint32_t len)
67{
68 *buf++ = tag;
69
70 if (len <= 127) {
71 buf[0] = len;
72 return buf + 1;
73 }
74
75 if (len <= 255) {
76 buf[0] = 0x81;
77 buf[1] = len;
78 return buf + 2;
79 }
80
81 buf[0] = 0x82;
82 put_unaligned_be16(len, buf + 1);
83 return buf + 3;
84}
85
86static uint32_t derive_pub_key(const void *pub_key, uint32_t len, uint8_t *buf)
87{
88 uint8_t *cur = buf;
89 uint32_t n_len = definite_length(len) + 1 + len + 1;
90 uint32_t e_len = definite_length(3) + 1 + 3;
91 uint8_t e[3] = { 0x01, 0x00, 0x01 };
92
93 /* SEQUENCE */
94 cur = encode_tag_length(cur, 0x30, n_len + e_len);
95 /* INTEGER n */
96 cur = encode_tag_length(cur, 0x02, len + 1);
97 cur[0] = 0x00;
98 memcpy(cur + 1, pub_key, len);
99 cur += len + 1;
100 cur = encode_tag_length(cur, 0x02, sizeof(e));
101 memcpy(cur, e, sizeof(e));
102 cur += sizeof(e);
103
104 return cur - buf;
105}
106
107/*
108 * Determine the crypto algorithm name.
109 */
110static int determine_akcipher(const char *encoding, const char *hash_algo,
111 char alg_name[CRYPTO_MAX_ALG_NAME])
112{
113 /* TODO: We don't support hashing yet */
114 if (hash_algo)
115 return -ENOPKG;
116
117 if (strcmp(encoding, "pkcs1") == 0) {
118 strcpy(alg_name, "pkcs1pad(rsa)");
119 return 0;
120 }
121
122 if (strcmp(encoding, "raw") == 0) {
123 strcpy(alg_name, "rsa");
124 return 0;
125 }
126
127 return -ENOPKG;
128}
129
130/*
131 * Query information about a key.
132 */
133static int tpm_key_query(const struct kernel_pkey_params *params,
134 struct kernel_pkey_query *info)
135{
136 struct tpm_key *tk = params->key->payload.data[asym_crypto];
137 int ret;
138 char alg_name[CRYPTO_MAX_ALG_NAME];
139 struct crypto_akcipher *tfm;
140 uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
141 uint32_t der_pub_key_len;
142 int len;
143
144 /* TPM only works on private keys, public keys still done in software */
145 ret = determine_akcipher(params->encoding, params->hash_algo, alg_name);
146 if (ret < 0)
147 return ret;
148
149 tfm = crypto_alloc_akcipher(alg_name, 0, 0);
150 if (IS_ERR(tfm))
151 return PTR_ERR(tfm);
152
153 der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
154 der_pub_key);
155
156 ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
157 if (ret < 0)
158 goto error_free_tfm;
159
160 len = crypto_akcipher_maxsize(tfm);
161
162 info->key_size = tk->key_len;
163 info->max_data_size = tk->key_len / 8;
164 info->max_sig_size = len;
165 info->max_enc_size = len;
166 info->max_dec_size = tk->key_len / 8;
167
168 ret = 0;
169error_free_tfm:
170 crypto_free_akcipher(tfm);
171 pr_devel("<==%s() = %d\n", __func__, ret);
172 return ret;
173}
174
41/* 175/*
42 * Parse enough information out of TPM_KEY structure: 176 * Parse enough information out of TPM_KEY structure:
43 * TPM_STRUCT_VER -> 4 bytes 177 * TPM_STRUCT_VER -> 4 bytes
@@ -194,6 +328,7 @@ struct asymmetric_key_subtype asym_tpm_subtype = {
194 .name_len = sizeof("asym_tpm") - 1, 328 .name_len = sizeof("asym_tpm") - 1,
195 .describe = asym_tpm_describe, 329 .describe = asym_tpm_describe,
196 .destroy = asym_tpm_destroy, 330 .destroy = asym_tpm_destroy,
331 .query = tpm_key_query,
197}; 332};
198EXPORT_SYMBOL_GPL(asym_tpm_subtype); 333EXPORT_SYMBOL_GPL(asym_tpm_subtype);
199 334