Commit | Line | Data |
---|---|---|
903be6bb DK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #define pr_fmt(fmt) "ASYM-TPM: "fmt | |
3 | #include <linux/slab.h> | |
4 | #include <linux/module.h> | |
5 | #include <linux/export.h> | |
6 | #include <linux/kernel.h> | |
7 | #include <linux/seq_file.h> | |
8 | #include <linux/scatterlist.h> | |
9 | #include <linux/tpm.h> | |
0c36264a | 10 | #include <linux/tpm_command.h> |
dff5a61a | 11 | #include <crypto/akcipher.h> |
0c36264a | 12 | #include <crypto/hash.h> |
a24d22b2 | 13 | #include <crypto/sha1.h> |
f8c54e1a | 14 | #include <asm/unaligned.h> |
903be6bb | 15 | #include <keys/asymmetric-subtype.h> |
47f9c279 | 16 | #include <keys/trusted_tpm.h> |
903be6bb | 17 | #include <crypto/asym_tpm_subtype.h> |
e08e6891 | 18 | #include <crypto/public_key.h> |
903be6bb | 19 | |
0c36264a DK |
20 | #define TPM_ORD_FLUSHSPECIFIC 186 |
21 | #define TPM_ORD_LOADKEY2 65 | |
f884fe5a | 22 | #define TPM_ORD_UNBIND 30 |
e73d170f | 23 | #define TPM_ORD_SIGN 60 |
0c36264a DK |
24 | |
25 | #define TPM_RT_KEY 0x00000001 | |
26 | ||
27 | /* | |
28 | * Load a TPM key from the blob provided by userspace | |
29 | */ | |
c6f61e59 | 30 | static int tpm_loadkey2(struct tpm_buf *tb, |
0c36264a DK |
31 | uint32_t keyhandle, unsigned char *keyauth, |
32 | const unsigned char *keyblob, int keybloblen, | |
33 | uint32_t *newhandle) | |
34 | { | |
35 | unsigned char nonceodd[TPM_NONCE_SIZE]; | |
36 | unsigned char enonce[TPM_NONCE_SIZE]; | |
37 | unsigned char authdata[SHA1_DIGEST_SIZE]; | |
38 | uint32_t authhandle = 0; | |
39 | unsigned char cont = 0; | |
40 | uint32_t ordinal; | |
41 | int ret; | |
42 | ||
43 | ordinal = htonl(TPM_ORD_LOADKEY2); | |
44 | ||
45 | /* session for loading the key */ | |
46 | ret = oiap(tb, &authhandle, enonce); | |
47 | if (ret < 0) { | |
48 | pr_info("oiap failed (%d)\n", ret); | |
49 | return ret; | |
50 | } | |
51 | ||
52 | /* generate odd nonce */ | |
53 | ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); | |
54 | if (ret < 0) { | |
55 | pr_info("tpm_get_random failed (%d)\n", ret); | |
56 | return ret; | |
57 | } | |
58 | ||
59 | /* calculate authorization HMAC value */ | |
60 | ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce, | |
61 | nonceodd, cont, sizeof(uint32_t), &ordinal, | |
62 | keybloblen, keyblob, 0, 0); | |
63 | if (ret < 0) | |
64 | return ret; | |
65 | ||
66 | /* build the request buffer */ | |
c6f61e59 SG |
67 | tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_LOADKEY2); |
68 | tpm_buf_append_u32(tb, keyhandle); | |
69 | tpm_buf_append(tb, keyblob, keybloblen); | |
70 | tpm_buf_append_u32(tb, authhandle); | |
71 | tpm_buf_append(tb, nonceodd, TPM_NONCE_SIZE); | |
72 | tpm_buf_append_u8(tb, cont); | |
73 | tpm_buf_append(tb, authdata, SHA1_DIGEST_SIZE); | |
0c36264a DK |
74 | |
75 | ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); | |
76 | if (ret < 0) { | |
77 | pr_info("authhmac failed (%d)\n", ret); | |
78 | return ret; | |
79 | } | |
80 | ||
81 | ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, keyauth, | |
82 | SHA1_DIGEST_SIZE, 0, 0); | |
83 | if (ret < 0) { | |
84 | pr_info("TSS_checkhmac1 failed (%d)\n", ret); | |
85 | return ret; | |
86 | } | |
87 | ||
88 | *newhandle = LOAD32(tb->data, TPM_DATA_OFFSET); | |
89 | return 0; | |
90 | } | |
91 | ||
92 | /* | |
93 | * Execute the FlushSpecific TPM command | |
94 | */ | |
c6f61e59 | 95 | static int tpm_flushspecific(struct tpm_buf *tb, uint32_t handle) |
0c36264a | 96 | { |
c6f61e59 SG |
97 | tpm_buf_reset(tb, TPM_TAG_RQU_COMMAND, TPM_ORD_FLUSHSPECIFIC); |
98 | tpm_buf_append_u32(tb, handle); | |
99 | tpm_buf_append_u32(tb, TPM_RT_KEY); | |
0c36264a DK |
100 | |
101 | return trusted_tpm_send(tb->data, MAX_BUF_SIZE); | |
102 | } | |
103 | ||
f884fe5a DK |
104 | /* |
105 | * Decrypt a blob provided by userspace using a specific key handle. | |
106 | * The handle is a well known handle or previously loaded by e.g. LoadKey2 | |
107 | */ | |
c6f61e59 | 108 | static int tpm_unbind(struct tpm_buf *tb, |
f884fe5a DK |
109 | uint32_t keyhandle, unsigned char *keyauth, |
110 | const unsigned char *blob, uint32_t bloblen, | |
111 | void *out, uint32_t outlen) | |
112 | { | |
113 | unsigned char nonceodd[TPM_NONCE_SIZE]; | |
114 | unsigned char enonce[TPM_NONCE_SIZE]; | |
115 | unsigned char authdata[SHA1_DIGEST_SIZE]; | |
116 | uint32_t authhandle = 0; | |
117 | unsigned char cont = 0; | |
118 | uint32_t ordinal; | |
119 | uint32_t datalen; | |
120 | int ret; | |
121 | ||
122 | ordinal = htonl(TPM_ORD_UNBIND); | |
123 | datalen = htonl(bloblen); | |
124 | ||
125 | /* session for loading the key */ | |
126 | ret = oiap(tb, &authhandle, enonce); | |
127 | if (ret < 0) { | |
128 | pr_info("oiap failed (%d)\n", ret); | |
129 | return ret; | |
130 | } | |
131 | ||
132 | /* generate odd nonce */ | |
133 | ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); | |
134 | if (ret < 0) { | |
135 | pr_info("tpm_get_random failed (%d)\n", ret); | |
136 | return ret; | |
137 | } | |
138 | ||
139 | /* calculate authorization HMAC value */ | |
140 | ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce, | |
141 | nonceodd, cont, sizeof(uint32_t), &ordinal, | |
142 | sizeof(uint32_t), &datalen, | |
143 | bloblen, blob, 0, 0); | |
144 | if (ret < 0) | |
145 | return ret; | |
146 | ||
147 | /* build the request buffer */ | |
c6f61e59 SG |
148 | tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_UNBIND); |
149 | tpm_buf_append_u32(tb, keyhandle); | |
150 | tpm_buf_append_u32(tb, bloblen); | |
151 | tpm_buf_append(tb, blob, bloblen); | |
152 | tpm_buf_append_u32(tb, authhandle); | |
153 | tpm_buf_append(tb, nonceodd, TPM_NONCE_SIZE); | |
154 | tpm_buf_append_u8(tb, cont); | |
155 | tpm_buf_append(tb, authdata, SHA1_DIGEST_SIZE); | |
f884fe5a DK |
156 | |
157 | ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); | |
158 | if (ret < 0) { | |
159 | pr_info("authhmac failed (%d)\n", ret); | |
160 | return ret; | |
161 | } | |
162 | ||
163 | datalen = LOAD32(tb->data, TPM_DATA_OFFSET); | |
164 | ||
165 | ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, | |
166 | keyauth, SHA1_DIGEST_SIZE, | |
167 | sizeof(uint32_t), TPM_DATA_OFFSET, | |
168 | datalen, TPM_DATA_OFFSET + sizeof(uint32_t), | |
169 | 0, 0); | |
170 | if (ret < 0) { | |
171 | pr_info("TSS_checkhmac1 failed (%d)\n", ret); | |
172 | return ret; | |
173 | } | |
174 | ||
175 | memcpy(out, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), | |
176 | min(outlen, datalen)); | |
177 | ||
178 | return datalen; | |
179 | } | |
180 | ||
e73d170f DK |
181 | /* |
182 | * Sign a blob provided by userspace (that has had the hash function applied) | |
183 | * using a specific key handle. The handle is assumed to have been previously | |
184 | * loaded by e.g. LoadKey2. | |
185 | * | |
186 | * Note that the key signature scheme of the used key should be set to | |
187 | * TPM_SS_RSASSAPKCS1v15_DER. This allows the hashed input to be of any size | |
188 | * up to key_length_in_bytes - 11 and not be limited to size 20 like the | |
189 | * TPM_SS_RSASSAPKCS1v15_SHA1 signature scheme. | |
190 | */ | |
c6f61e59 | 191 | static int tpm_sign(struct tpm_buf *tb, |
e73d170f DK |
192 | uint32_t keyhandle, unsigned char *keyauth, |
193 | const unsigned char *blob, uint32_t bloblen, | |
194 | void *out, uint32_t outlen) | |
195 | { | |
196 | unsigned char nonceodd[TPM_NONCE_SIZE]; | |
197 | unsigned char enonce[TPM_NONCE_SIZE]; | |
198 | unsigned char authdata[SHA1_DIGEST_SIZE]; | |
199 | uint32_t authhandle = 0; | |
200 | unsigned char cont = 0; | |
201 | uint32_t ordinal; | |
202 | uint32_t datalen; | |
203 | int ret; | |
204 | ||
205 | ordinal = htonl(TPM_ORD_SIGN); | |
206 | datalen = htonl(bloblen); | |
207 | ||
208 | /* session for loading the key */ | |
209 | ret = oiap(tb, &authhandle, enonce); | |
210 | if (ret < 0) { | |
211 | pr_info("oiap failed (%d)\n", ret); | |
212 | return ret; | |
213 | } | |
214 | ||
215 | /* generate odd nonce */ | |
216 | ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE); | |
217 | if (ret < 0) { | |
218 | pr_info("tpm_get_random failed (%d)\n", ret); | |
219 | return ret; | |
220 | } | |
221 | ||
222 | /* calculate authorization HMAC value */ | |
223 | ret = TSS_authhmac(authdata, keyauth, SHA1_DIGEST_SIZE, enonce, | |
224 | nonceodd, cont, sizeof(uint32_t), &ordinal, | |
225 | sizeof(uint32_t), &datalen, | |
226 | bloblen, blob, 0, 0); | |
227 | if (ret < 0) | |
228 | return ret; | |
229 | ||
230 | /* build the request buffer */ | |
c6f61e59 SG |
231 | tpm_buf_reset(tb, TPM_TAG_RQU_AUTH1_COMMAND, TPM_ORD_SIGN); |
232 | tpm_buf_append_u32(tb, keyhandle); | |
233 | tpm_buf_append_u32(tb, bloblen); | |
234 | tpm_buf_append(tb, blob, bloblen); | |
235 | tpm_buf_append_u32(tb, authhandle); | |
236 | tpm_buf_append(tb, nonceodd, TPM_NONCE_SIZE); | |
237 | tpm_buf_append_u8(tb, cont); | |
238 | tpm_buf_append(tb, authdata, SHA1_DIGEST_SIZE); | |
e73d170f DK |
239 | |
240 | ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE); | |
241 | if (ret < 0) { | |
242 | pr_info("authhmac failed (%d)\n", ret); | |
243 | return ret; | |
244 | } | |
245 | ||
246 | datalen = LOAD32(tb->data, TPM_DATA_OFFSET); | |
247 | ||
248 | ret = TSS_checkhmac1(tb->data, ordinal, nonceodd, | |
249 | keyauth, SHA1_DIGEST_SIZE, | |
250 | sizeof(uint32_t), TPM_DATA_OFFSET, | |
251 | datalen, TPM_DATA_OFFSET + sizeof(uint32_t), | |
252 | 0, 0); | |
253 | if (ret < 0) { | |
254 | pr_info("TSS_checkhmac1 failed (%d)\n", ret); | |
255 | return ret; | |
256 | } | |
257 | ||
258 | memcpy(out, tb->data + TPM_DATA_OFFSET + sizeof(uint32_t), | |
259 | min(datalen, outlen)); | |
260 | ||
261 | return datalen; | |
262 | } | |
f1774cb8 VC |
263 | |
264 | /* Room to fit two u32 zeros for algo id and parameters length. */ | |
265 | #define SETKEY_PARAMS_SIZE (sizeof(u32) * 2) | |
266 | ||
dff5a61a DK |
267 | /* |
268 | * Maximum buffer size for the BER/DER encoded public key. The public key | |
269 | * is of the form SEQUENCE { INTEGER n, INTEGER e } where n is a maximum 2048 | |
270 | * bit key and e is usually 65537 | |
271 | * The encoding overhead is: | |
272 | * - max 4 bytes for SEQUENCE | |
273 | * - max 4 bytes for INTEGER n type/length | |
274 | * - 257 bytes of n | |
275 | * - max 2 bytes for INTEGER e type/length | |
276 | * - 3 bytes of e | |
f1774cb8 | 277 | * - 4+4 of zeros for set_pub_key parameters (SETKEY_PARAMS_SIZE) |
dff5a61a | 278 | */ |
f1774cb8 | 279 | #define PUB_KEY_BUF_SIZE (4 + 4 + 257 + 2 + 3 + SETKEY_PARAMS_SIZE) |
dff5a61a | 280 | |
903be6bb DK |
281 | /* |
282 | * Provide a part of a description of the key for /proc/keys. | |
283 | */ | |
284 | static void asym_tpm_describe(const struct key *asymmetric_key, | |
285 | struct seq_file *m) | |
286 | { | |
287 | struct tpm_key *tk = asymmetric_key->payload.data[asym_crypto]; | |
288 | ||
289 | if (!tk) | |
290 | return; | |
291 | ||
292 | seq_printf(m, "TPM1.2/Blob"); | |
293 | } | |
294 | ||
295 | static void asym_tpm_destroy(void *payload0, void *payload3) | |
296 | { | |
297 | struct tpm_key *tk = payload0; | |
298 | ||
299 | if (!tk) | |
300 | return; | |
301 | ||
302 | kfree(tk->blob); | |
303 | tk->blob_len = 0; | |
304 | ||
305 | kfree(tk); | |
306 | } | |
307 | ||
dff5a61a DK |
308 | /* How many bytes will it take to encode the length */ |
309 | static inline uint32_t definite_length(uint32_t len) | |
310 | { | |
311 | if (len <= 127) | |
312 | return 1; | |
313 | if (len <= 255) | |
314 | return 2; | |
315 | return 3; | |
316 | } | |
317 | ||
318 | static inline uint8_t *encode_tag_length(uint8_t *buf, uint8_t tag, | |
319 | uint32_t len) | |
320 | { | |
321 | *buf++ = tag; | |
322 | ||
323 | if (len <= 127) { | |
324 | buf[0] = len; | |
325 | return buf + 1; | |
326 | } | |
327 | ||
328 | if (len <= 255) { | |
329 | buf[0] = 0x81; | |
330 | buf[1] = len; | |
331 | return buf + 2; | |
332 | } | |
333 | ||
334 | buf[0] = 0x82; | |
335 | put_unaligned_be16(len, buf + 1); | |
336 | return buf + 3; | |
337 | } | |
338 | ||
339 | static uint32_t derive_pub_key(const void *pub_key, uint32_t len, uint8_t *buf) | |
340 | { | |
341 | uint8_t *cur = buf; | |
342 | uint32_t n_len = definite_length(len) + 1 + len + 1; | |
343 | uint32_t e_len = definite_length(3) + 1 + 3; | |
344 | uint8_t e[3] = { 0x01, 0x00, 0x01 }; | |
345 | ||
346 | /* SEQUENCE */ | |
347 | cur = encode_tag_length(cur, 0x30, n_len + e_len); | |
348 | /* INTEGER n */ | |
349 | cur = encode_tag_length(cur, 0x02, len + 1); | |
350 | cur[0] = 0x00; | |
351 | memcpy(cur + 1, pub_key, len); | |
352 | cur += len + 1; | |
353 | cur = encode_tag_length(cur, 0x02, sizeof(e)); | |
354 | memcpy(cur, e, sizeof(e)); | |
355 | cur += sizeof(e); | |
f1774cb8 | 356 | /* Zero parameters to satisfy set_pub_key ABI. */ |
f93274ef | 357 | memzero_explicit(cur, SETKEY_PARAMS_SIZE); |
dff5a61a DK |
358 | |
359 | return cur - buf; | |
360 | } | |
361 | ||
362 | /* | |
363 | * Determine the crypto algorithm name. | |
364 | */ | |
365 | static int determine_akcipher(const char *encoding, const char *hash_algo, | |
366 | char alg_name[CRYPTO_MAX_ALG_NAME]) | |
367 | { | |
dff5a61a | 368 | if (strcmp(encoding, "pkcs1") == 0) { |
e08e6891 DK |
369 | if (!hash_algo) { |
370 | strcpy(alg_name, "pkcs1pad(rsa)"); | |
371 | return 0; | |
372 | } | |
373 | ||
374 | if (snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(rsa,%s)", | |
375 | hash_algo) >= CRYPTO_MAX_ALG_NAME) | |
376 | return -EINVAL; | |
377 | ||
dff5a61a DK |
378 | return 0; |
379 | } | |
380 | ||
381 | if (strcmp(encoding, "raw") == 0) { | |
382 | strcpy(alg_name, "rsa"); | |
383 | return 0; | |
384 | } | |
385 | ||
386 | return -ENOPKG; | |
387 | } | |
388 | ||
389 | /* | |
390 | * Query information about a key. | |
391 | */ | |
392 | static int tpm_key_query(const struct kernel_pkey_params *params, | |
393 | struct kernel_pkey_query *info) | |
394 | { | |
395 | struct tpm_key *tk = params->key->payload.data[asym_crypto]; | |
396 | int ret; | |
397 | char alg_name[CRYPTO_MAX_ALG_NAME]; | |
398 | struct crypto_akcipher *tfm; | |
399 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; | |
400 | uint32_t der_pub_key_len; | |
401 | int len; | |
402 | ||
403 | /* TPM only works on private keys, public keys still done in software */ | |
404 | ret = determine_akcipher(params->encoding, params->hash_algo, alg_name); | |
405 | if (ret < 0) | |
406 | return ret; | |
407 | ||
408 | tfm = crypto_alloc_akcipher(alg_name, 0, 0); | |
409 | if (IS_ERR(tfm)) | |
410 | return PTR_ERR(tfm); | |
411 | ||
412 | der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, | |
413 | der_pub_key); | |
414 | ||
415 | ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); | |
416 | if (ret < 0) | |
417 | goto error_free_tfm; | |
418 | ||
419 | len = crypto_akcipher_maxsize(tfm); | |
420 | ||
421 | info->key_size = tk->key_len; | |
422 | info->max_data_size = tk->key_len / 8; | |
423 | info->max_sig_size = len; | |
424 | info->max_enc_size = len; | |
425 | info->max_dec_size = tk->key_len / 8; | |
426 | ||
a335974a | 427 | info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT | |
e08e6891 | 428 | KEYCTL_SUPPORTS_DECRYPT | |
64ae16df DK |
429 | KEYCTL_SUPPORTS_VERIFY | |
430 | KEYCTL_SUPPORTS_SIGN; | |
ad4b1eb5 | 431 | |
dff5a61a DK |
432 | ret = 0; |
433 | error_free_tfm: | |
434 | crypto_free_akcipher(tfm); | |
435 | pr_devel("<==%s() = %d\n", __func__, ret); | |
436 | return ret; | |
437 | } | |
438 | ||
ad4b1eb5 DK |
439 | /* |
440 | * Encryption operation is performed with the public key. Hence it is done | |
441 | * in software | |
442 | */ | |
443 | static int tpm_key_encrypt(struct tpm_key *tk, | |
444 | struct kernel_pkey_params *params, | |
445 | const void *in, void *out) | |
446 | { | |
447 | char alg_name[CRYPTO_MAX_ALG_NAME]; | |
448 | struct crypto_akcipher *tfm; | |
449 | struct akcipher_request *req; | |
450 | struct crypto_wait cwait; | |
451 | struct scatterlist in_sg, out_sg; | |
452 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; | |
453 | uint32_t der_pub_key_len; | |
454 | int ret; | |
455 | ||
456 | pr_devel("==>%s()\n", __func__); | |
457 | ||
458 | ret = determine_akcipher(params->encoding, params->hash_algo, alg_name); | |
459 | if (ret < 0) | |
460 | return ret; | |
461 | ||
462 | tfm = crypto_alloc_akcipher(alg_name, 0, 0); | |
463 | if (IS_ERR(tfm)) | |
464 | return PTR_ERR(tfm); | |
465 | ||
466 | der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, | |
467 | der_pub_key); | |
468 | ||
469 | ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); | |
470 | if (ret < 0) | |
471 | goto error_free_tfm; | |
472 | ||
bea37414 | 473 | ret = -ENOMEM; |
ad4b1eb5 DK |
474 | req = akcipher_request_alloc(tfm, GFP_KERNEL); |
475 | if (!req) | |
476 | goto error_free_tfm; | |
477 | ||
478 | sg_init_one(&in_sg, in, params->in_len); | |
479 | sg_init_one(&out_sg, out, params->out_len); | |
480 | akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len, | |
481 | params->out_len); | |
482 | crypto_init_wait(&cwait); | |
483 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | |
484 | CRYPTO_TFM_REQ_MAY_SLEEP, | |
485 | crypto_req_done, &cwait); | |
486 | ||
487 | ret = crypto_akcipher_encrypt(req); | |
488 | ret = crypto_wait_req(ret, &cwait); | |
489 | ||
490 | if (ret == 0) | |
491 | ret = req->dst_len; | |
492 | ||
493 | akcipher_request_free(req); | |
494 | error_free_tfm: | |
495 | crypto_free_akcipher(tfm); | |
496 | pr_devel("<==%s() = %d\n", __func__, ret); | |
497 | return ret; | |
498 | } | |
499 | ||
a335974a DK |
500 | /* |
501 | * Decryption operation is performed with the private key in the TPM. | |
502 | */ | |
503 | static int tpm_key_decrypt(struct tpm_key *tk, | |
504 | struct kernel_pkey_params *params, | |
505 | const void *in, void *out) | |
506 | { | |
c6f61e59 | 507 | struct tpm_buf tb; |
a335974a DK |
508 | uint32_t keyhandle; |
509 | uint8_t srkauth[SHA1_DIGEST_SIZE]; | |
510 | uint8_t keyauth[SHA1_DIGEST_SIZE]; | |
511 | int r; | |
512 | ||
513 | pr_devel("==>%s()\n", __func__); | |
514 | ||
515 | if (params->hash_algo) | |
516 | return -ENOPKG; | |
517 | ||
518 | if (strcmp(params->encoding, "pkcs1")) | |
519 | return -ENOPKG; | |
520 | ||
c6f61e59 SG |
521 | r = tpm_buf_init(&tb, 0, 0); |
522 | if (r) | |
523 | return r; | |
a335974a DK |
524 | |
525 | /* TODO: Handle a non-all zero SRK authorization */ | |
526 | memset(srkauth, 0, sizeof(srkauth)); | |
527 | ||
c6f61e59 | 528 | r = tpm_loadkey2(&tb, SRKHANDLE, srkauth, |
a335974a DK |
529 | tk->blob, tk->blob_len, &keyhandle); |
530 | if (r < 0) { | |
531 | pr_devel("loadkey2 failed (%d)\n", r); | |
532 | goto error; | |
533 | } | |
534 | ||
535 | /* TODO: Handle a non-all zero key authorization */ | |
536 | memset(keyauth, 0, sizeof(keyauth)); | |
537 | ||
c6f61e59 | 538 | r = tpm_unbind(&tb, keyhandle, keyauth, |
a335974a DK |
539 | in, params->in_len, out, params->out_len); |
540 | if (r < 0) | |
541 | pr_devel("tpm_unbind failed (%d)\n", r); | |
542 | ||
c6f61e59 | 543 | if (tpm_flushspecific(&tb, keyhandle) < 0) |
a335974a DK |
544 | pr_devel("flushspecific failed (%d)\n", r); |
545 | ||
546 | error: | |
c6f61e59 | 547 | tpm_buf_destroy(&tb); |
a335974a DK |
548 | pr_devel("<==%s() = %d\n", __func__, r); |
549 | return r; | |
550 | } | |
551 | ||
64ae16df DK |
552 | /* |
553 | * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. | |
554 | */ | |
555 | static const u8 digest_info_md5[] = { | |
556 | 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, | |
557 | 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, /* OID */ | |
558 | 0x05, 0x00, 0x04, 0x10 | |
559 | }; | |
560 | ||
561 | static const u8 digest_info_sha1[] = { | |
562 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | |
563 | 0x2b, 0x0e, 0x03, 0x02, 0x1a, | |
564 | 0x05, 0x00, 0x04, 0x14 | |
565 | }; | |
566 | ||
567 | static const u8 digest_info_rmd160[] = { | |
568 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | |
569 | 0x2b, 0x24, 0x03, 0x02, 0x01, | |
570 | 0x05, 0x00, 0x04, 0x14 | |
571 | }; | |
572 | ||
573 | static const u8 digest_info_sha224[] = { | |
574 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | |
575 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | |
576 | 0x05, 0x00, 0x04, 0x1c | |
577 | }; | |
578 | ||
579 | static const u8 digest_info_sha256[] = { | |
580 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | |
581 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | |
582 | 0x05, 0x00, 0x04, 0x20 | |
583 | }; | |
584 | ||
585 | static const u8 digest_info_sha384[] = { | |
586 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | |
587 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | |
588 | 0x05, 0x00, 0x04, 0x30 | |
589 | }; | |
590 | ||
591 | static const u8 digest_info_sha512[] = { | |
592 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | |
593 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | |
594 | 0x05, 0x00, 0x04, 0x40 | |
595 | }; | |
596 | ||
597 | static const struct asn1_template { | |
598 | const char *name; | |
599 | const u8 *data; | |
600 | size_t size; | |
601 | } asn1_templates[] = { | |
602 | #define _(X) { #X, digest_info_##X, sizeof(digest_info_##X) } | |
603 | _(md5), | |
604 | _(sha1), | |
605 | _(rmd160), | |
606 | _(sha256), | |
607 | _(sha384), | |
608 | _(sha512), | |
609 | _(sha224), | |
610 | { NULL } | |
611 | #undef _ | |
612 | }; | |
613 | ||
614 | static const struct asn1_template *lookup_asn1(const char *name) | |
615 | { | |
616 | const struct asn1_template *p; | |
617 | ||
618 | for (p = asn1_templates; p->name; p++) | |
619 | if (strcmp(name, p->name) == 0) | |
620 | return p; | |
621 | return NULL; | |
622 | } | |
623 | ||
624 | /* | |
625 | * Sign operation is performed with the private key in the TPM. | |
626 | */ | |
627 | static int tpm_key_sign(struct tpm_key *tk, | |
628 | struct kernel_pkey_params *params, | |
629 | const void *in, void *out) | |
630 | { | |
c6f61e59 | 631 | struct tpm_buf tb; |
64ae16df DK |
632 | uint32_t keyhandle; |
633 | uint8_t srkauth[SHA1_DIGEST_SIZE]; | |
634 | uint8_t keyauth[SHA1_DIGEST_SIZE]; | |
635 | void *asn1_wrapped = NULL; | |
636 | uint32_t in_len = params->in_len; | |
637 | int r; | |
638 | ||
639 | pr_devel("==>%s()\n", __func__); | |
640 | ||
641 | if (strcmp(params->encoding, "pkcs1")) | |
642 | return -ENOPKG; | |
643 | ||
644 | if (params->hash_algo) { | |
645 | const struct asn1_template *asn1 = | |
646 | lookup_asn1(params->hash_algo); | |
647 | ||
648 | if (!asn1) | |
649 | return -ENOPKG; | |
650 | ||
651 | /* request enough space for the ASN.1 template + input hash */ | |
652 | asn1_wrapped = kzalloc(in_len + asn1->size, GFP_KERNEL); | |
653 | if (!asn1_wrapped) | |
654 | return -ENOMEM; | |
655 | ||
656 | /* Copy ASN.1 template, then the input */ | |
657 | memcpy(asn1_wrapped, asn1->data, asn1->size); | |
658 | memcpy(asn1_wrapped + asn1->size, in, in_len); | |
659 | ||
660 | in = asn1_wrapped; | |
661 | in_len += asn1->size; | |
662 | } | |
663 | ||
664 | if (in_len > tk->key_len / 8 - 11) { | |
665 | r = -EOVERFLOW; | |
666 | goto error_free_asn1_wrapped; | |
667 | } | |
668 | ||
c6f61e59 SG |
669 | r = tpm_buf_init(&tb, 0, 0); |
670 | if (r) | |
64ae16df DK |
671 | goto error_free_asn1_wrapped; |
672 | ||
673 | /* TODO: Handle a non-all zero SRK authorization */ | |
674 | memset(srkauth, 0, sizeof(srkauth)); | |
675 | ||
c6f61e59 | 676 | r = tpm_loadkey2(&tb, SRKHANDLE, srkauth, |
64ae16df DK |
677 | tk->blob, tk->blob_len, &keyhandle); |
678 | if (r < 0) { | |
679 | pr_devel("loadkey2 failed (%d)\n", r); | |
680 | goto error_free_tb; | |
681 | } | |
682 | ||
683 | /* TODO: Handle a non-all zero key authorization */ | |
684 | memset(keyauth, 0, sizeof(keyauth)); | |
685 | ||
c6f61e59 | 686 | r = tpm_sign(&tb, keyhandle, keyauth, in, in_len, out, params->out_len); |
64ae16df DK |
687 | if (r < 0) |
688 | pr_devel("tpm_sign failed (%d)\n", r); | |
689 | ||
c6f61e59 | 690 | if (tpm_flushspecific(&tb, keyhandle) < 0) |
64ae16df DK |
691 | pr_devel("flushspecific failed (%d)\n", r); |
692 | ||
693 | error_free_tb: | |
c6f61e59 | 694 | tpm_buf_destroy(&tb); |
64ae16df DK |
695 | error_free_asn1_wrapped: |
696 | kfree(asn1_wrapped); | |
697 | pr_devel("<==%s() = %d\n", __func__, r); | |
698 | return r; | |
699 | } | |
700 | ||
ad4b1eb5 DK |
701 | /* |
702 | * Do encryption, decryption and signing ops. | |
703 | */ | |
704 | static int tpm_key_eds_op(struct kernel_pkey_params *params, | |
705 | const void *in, void *out) | |
706 | { | |
707 | struct tpm_key *tk = params->key->payload.data[asym_crypto]; | |
708 | int ret = -EOPNOTSUPP; | |
709 | ||
710 | /* Perform the encryption calculation. */ | |
711 | switch (params->op) { | |
712 | case kernel_pkey_encrypt: | |
713 | ret = tpm_key_encrypt(tk, params, in, out); | |
714 | break; | |
a335974a DK |
715 | case kernel_pkey_decrypt: |
716 | ret = tpm_key_decrypt(tk, params, in, out); | |
717 | break; | |
64ae16df DK |
718 | case kernel_pkey_sign: |
719 | ret = tpm_key_sign(tk, params, in, out); | |
720 | break; | |
ad4b1eb5 DK |
721 | default: |
722 | BUG(); | |
723 | } | |
724 | ||
725 | return ret; | |
726 | } | |
727 | ||
e08e6891 DK |
728 | /* |
729 | * Verify a signature using a public key. | |
730 | */ | |
731 | static int tpm_key_verify_signature(const struct key *key, | |
732 | const struct public_key_signature *sig) | |
733 | { | |
734 | const struct tpm_key *tk = key->payload.data[asym_crypto]; | |
735 | struct crypto_wait cwait; | |
736 | struct crypto_akcipher *tfm; | |
737 | struct akcipher_request *req; | |
c7381b01 | 738 | struct scatterlist src_sg[2]; |
e08e6891 DK |
739 | char alg_name[CRYPTO_MAX_ALG_NAME]; |
740 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; | |
741 | uint32_t der_pub_key_len; | |
e08e6891 DK |
742 | int ret; |
743 | ||
744 | pr_devel("==>%s()\n", __func__); | |
745 | ||
746 | BUG_ON(!tk); | |
747 | BUG_ON(!sig); | |
748 | BUG_ON(!sig->s); | |
749 | ||
750 | if (!sig->digest) | |
751 | return -ENOPKG; | |
752 | ||
753 | ret = determine_akcipher(sig->encoding, sig->hash_algo, alg_name); | |
754 | if (ret < 0) | |
755 | return ret; | |
756 | ||
757 | tfm = crypto_alloc_akcipher(alg_name, 0, 0); | |
758 | if (IS_ERR(tfm)) | |
759 | return PTR_ERR(tfm); | |
760 | ||
761 | der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, | |
762 | der_pub_key); | |
763 | ||
764 | ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); | |
765 | if (ret < 0) | |
766 | goto error_free_tfm; | |
767 | ||
768 | ret = -ENOMEM; | |
769 | req = akcipher_request_alloc(tfm, GFP_KERNEL); | |
770 | if (!req) | |
771 | goto error_free_tfm; | |
772 | ||
c7381b01 VC |
773 | sg_init_table(src_sg, 2); |
774 | sg_set_buf(&src_sg[0], sig->s, sig->s_size); | |
83bc0299 | 775 | sg_set_buf(&src_sg[1], sig->digest, sig->digest_size); |
c7381b01 VC |
776 | akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size, |
777 | sig->digest_size); | |
e08e6891 DK |
778 | crypto_init_wait(&cwait); |
779 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | |
780 | CRYPTO_TFM_REQ_MAY_SLEEP, | |
781 | crypto_req_done, &cwait); | |
e08e6891 | 782 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); |
e08e6891 | 783 | |
e08e6891 DK |
784 | akcipher_request_free(req); |
785 | error_free_tfm: | |
786 | crypto_free_akcipher(tfm); | |
787 | pr_devel("<==%s() = %d\n", __func__, ret); | |
788 | if (WARN_ON_ONCE(ret > 0)) | |
789 | ret = -EINVAL; | |
790 | return ret; | |
791 | } | |
792 | ||
f8c54e1a DK |
793 | /* |
794 | * Parse enough information out of TPM_KEY structure: | |
795 | * TPM_STRUCT_VER -> 4 bytes | |
796 | * TPM_KEY_USAGE -> 2 bytes | |
797 | * TPM_KEY_FLAGS -> 4 bytes | |
798 | * TPM_AUTH_DATA_USAGE -> 1 byte | |
799 | * TPM_KEY_PARMS -> variable | |
800 | * UINT32 PCRInfoSize -> 4 bytes | |
801 | * BYTE* -> PCRInfoSize bytes | |
802 | * TPM_STORE_PUBKEY | |
803 | * UINT32 encDataSize; | |
804 | * BYTE* -> encDataSize; | |
805 | * | |
806 | * TPM_KEY_PARMS: | |
807 | * TPM_ALGORITHM_ID -> 4 bytes | |
808 | * TPM_ENC_SCHEME -> 2 bytes | |
809 | * TPM_SIG_SCHEME -> 2 bytes | |
810 | * UINT32 parmSize -> 4 bytes | |
811 | * BYTE* -> variable | |
812 | */ | |
813 | static int extract_key_parameters(struct tpm_key *tk) | |
814 | { | |
815 | const void *cur = tk->blob; | |
816 | uint32_t len = tk->blob_len; | |
817 | const void *pub_key; | |
818 | uint32_t sz; | |
819 | uint32_t key_len; | |
820 | ||
821 | if (len < 11) | |
822 | return -EBADMSG; | |
823 | ||
824 | /* Ensure this is a legacy key */ | |
825 | if (get_unaligned_be16(cur + 4) != 0x0015) | |
826 | return -EBADMSG; | |
827 | ||
828 | /* Skip to TPM_KEY_PARMS */ | |
829 | cur += 11; | |
830 | len -= 11; | |
831 | ||
832 | if (len < 12) | |
833 | return -EBADMSG; | |
834 | ||
835 | /* Make sure this is an RSA key */ | |
836 | if (get_unaligned_be32(cur) != 0x00000001) | |
837 | return -EBADMSG; | |
838 | ||
839 | /* Make sure this is TPM_ES_RSAESPKCSv15 encoding scheme */ | |
840 | if (get_unaligned_be16(cur + 4) != 0x0002) | |
841 | return -EBADMSG; | |
842 | ||
843 | /* Make sure this is TPM_SS_RSASSAPKCS1v15_DER signature scheme */ | |
844 | if (get_unaligned_be16(cur + 6) != 0x0003) | |
845 | return -EBADMSG; | |
846 | ||
847 | sz = get_unaligned_be32(cur + 8); | |
848 | if (len < sz + 12) | |
849 | return -EBADMSG; | |
850 | ||
851 | /* Move to TPM_RSA_KEY_PARMS */ | |
852 | len -= 12; | |
853 | cur += 12; | |
854 | ||
855 | /* Grab the RSA key length */ | |
856 | key_len = get_unaligned_be32(cur); | |
857 | ||
858 | switch (key_len) { | |
859 | case 512: | |
860 | case 1024: | |
861 | case 1536: | |
862 | case 2048: | |
863 | break; | |
864 | default: | |
865 | return -EINVAL; | |
866 | } | |
867 | ||
868 | /* Move just past TPM_KEY_PARMS */ | |
869 | cur += sz; | |
870 | len -= sz; | |
871 | ||
872 | if (len < 4) | |
873 | return -EBADMSG; | |
874 | ||
875 | sz = get_unaligned_be32(cur); | |
876 | if (len < 4 + sz) | |
877 | return -EBADMSG; | |
878 | ||
879 | /* Move to TPM_STORE_PUBKEY */ | |
880 | cur += 4 + sz; | |
881 | len -= 4 + sz; | |
882 | ||
883 | /* Grab the size of the public key, it should jive with the key size */ | |
884 | sz = get_unaligned_be32(cur); | |
885 | if (sz > 256) | |
886 | return -EINVAL; | |
887 | ||
888 | pub_key = cur + 4; | |
889 | ||
890 | tk->key_len = key_len; | |
891 | tk->pub_key = pub_key; | |
892 | tk->pub_key_len = sz; | |
893 | ||
894 | return 0; | |
895 | } | |
896 | ||
903be6bb DK |
897 | /* Given the blob, parse it and load it into the TPM */ |
898 | struct tpm_key *tpm_key_create(const void *blob, uint32_t blob_len) | |
899 | { | |
900 | int r; | |
901 | struct tpm_key *tk; | |
902 | ||
903 | r = tpm_is_tpm2(NULL); | |
904 | if (r < 0) | |
905 | goto error; | |
906 | ||
907 | /* We don't support TPM2 yet */ | |
908 | if (r > 0) { | |
909 | r = -ENODEV; | |
910 | goto error; | |
911 | } | |
912 | ||
913 | r = -ENOMEM; | |
914 | tk = kzalloc(sizeof(struct tpm_key), GFP_KERNEL); | |
915 | if (!tk) | |
916 | goto error; | |
917 | ||
918 | tk->blob = kmemdup(blob, blob_len, GFP_KERNEL); | |
919 | if (!tk->blob) | |
920 | goto error_memdup; | |
921 | ||
922 | tk->blob_len = blob_len; | |
923 | ||
f8c54e1a DK |
924 | r = extract_key_parameters(tk); |
925 | if (r < 0) | |
926 | goto error_extract; | |
927 | ||
903be6bb DK |
928 | return tk; |
929 | ||
f8c54e1a DK |
930 | error_extract: |
931 | kfree(tk->blob); | |
932 | tk->blob_len = 0; | |
903be6bb DK |
933 | error_memdup: |
934 | kfree(tk); | |
935 | error: | |
936 | return ERR_PTR(r); | |
937 | } | |
938 | EXPORT_SYMBOL_GPL(tpm_key_create); | |
939 | ||
940 | /* | |
941 | * TPM-based asymmetric key subtype | |
942 | */ | |
943 | struct asymmetric_key_subtype asym_tpm_subtype = { | |
944 | .owner = THIS_MODULE, | |
945 | .name = "asym_tpm", | |
946 | .name_len = sizeof("asym_tpm") - 1, | |
947 | .describe = asym_tpm_describe, | |
948 | .destroy = asym_tpm_destroy, | |
dff5a61a | 949 | .query = tpm_key_query, |
ad4b1eb5 | 950 | .eds_op = tpm_key_eds_op, |
e08e6891 | 951 | .verify_signature = tpm_key_verify_signature, |
903be6bb DK |
952 | }; |
953 | EXPORT_SYMBOL_GPL(asym_tpm_subtype); | |
954 | ||
955 | MODULE_DESCRIPTION("TPM based asymmetric key subtype"); | |
956 | MODULE_AUTHOR("Intel Corporation"); | |
957 | MODULE_LICENSE("GPL v2"); |