1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2004 IBM Corporation |
4 | * Copyright (C) 2014 Intel Corporation |
5 | */ |
6 | |
7 | #include <linux/asn1_encoder.h> |
8 | #include <linux/oid_registry.h> |
9 | #include <linux/string.h> |
10 | #include <linux/err.h> |
11 | #include <linux/tpm.h> |
12 | #include <linux/tpm_command.h> |
13 | |
14 | #include <keys/trusted-type.h> |
15 | #include <keys/trusted_tpm.h> |
16 | |
17 | #include <asm/unaligned.h> |
18 | |
19 | #include "tpm2key.asn1.h" |
20 | |
21 | static struct tpm2_hash tpm2_hash_map[] = { |
22 | {HASH_ALGO_SHA1, TPM_ALG_SHA1}, |
23 | {HASH_ALGO_SHA256, TPM_ALG_SHA256}, |
24 | {HASH_ALGO_SHA384, TPM_ALG_SHA384}, |
25 | {HASH_ALGO_SHA512, TPM_ALG_SHA512}, |
26 | {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, |
27 | }; |
28 | |
29 | static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 }; |
30 | |
31 | static int tpm2_key_encode(struct trusted_key_payload *payload, |
32 | struct trusted_key_options *options, |
33 | u8 *src, u32 len) |
34 | { |
35 | const int SCRATCH_SIZE = PAGE_SIZE; |
36 | u8 *scratch = kmalloc(size: SCRATCH_SIZE, GFP_KERNEL); |
37 | u8 *work = scratch, *work1; |
38 | u8 *end_work = scratch + SCRATCH_SIZE; |
39 | u8 *priv, *pub; |
40 | u16 priv_len, pub_len; |
41 | |
42 | priv_len = get_unaligned_be16(p: src) + 2; |
43 | priv = src; |
44 | |
45 | src += priv_len; |
46 | |
47 | pub_len = get_unaligned_be16(p: src) + 2; |
48 | pub = src; |
49 | |
50 | if (!scratch) |
51 | return -ENOMEM; |
52 | |
53 | work = asn1_encode_oid(data: work, end_data: end_work, oid: tpm2key_oid, |
54 | asn1_oid_len(tpm2key_oid)); |
55 | |
56 | if (options->blobauth_len == 0) { |
57 | unsigned char bool[3], *w = bool; |
58 | /* tag 0 is emptyAuth */ |
59 | w = asn1_encode_boolean(data: w, end_data: w + sizeof(bool), val: true); |
60 | if (WARN(IS_ERR(w), "BUG: Boolean failed to encode" )) |
61 | return PTR_ERR(ptr: w); |
62 | work = asn1_encode_tag(data: work, end_data: end_work, tag: 0, string: bool, len: w - bool); |
63 | } |
64 | |
65 | /* |
66 | * Assume both octet strings will encode to a 2 byte definite length |
67 | * |
68 | * Note: For a well behaved TPM, this warning should never |
69 | * trigger, so if it does there's something nefarious going on |
70 | */ |
71 | if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE, |
72 | "BUG: scratch buffer is too small" )) |
73 | return -EINVAL; |
74 | |
75 | work = asn1_encode_integer(data: work, end_data: end_work, integer: options->keyhandle); |
76 | work = asn1_encode_octet_string(data: work, end_data: end_work, string: pub, len: pub_len); |
77 | work = asn1_encode_octet_string(data: work, end_data: end_work, string: priv, len: priv_len); |
78 | |
79 | work1 = payload->blob; |
80 | work1 = asn1_encode_sequence(data: work1, end_data: work1 + sizeof(payload->blob), |
81 | seq: scratch, len: work - scratch); |
82 | if (WARN(IS_ERR(work1), "BUG: ASN.1 encoder failed" )) |
83 | return PTR_ERR(ptr: work1); |
84 | |
85 | return work1 - payload->blob; |
86 | } |
87 | |
88 | struct tpm2_key_context { |
89 | u32 parent; |
90 | const u8 *pub; |
91 | u32 pub_len; |
92 | const u8 *priv; |
93 | u32 priv_len; |
94 | }; |
95 | |
96 | static int tpm2_key_decode(struct trusted_key_payload *payload, |
97 | struct trusted_key_options *options, |
98 | u8 **buf) |
99 | { |
100 | int ret; |
101 | struct tpm2_key_context ctx; |
102 | u8 *blob; |
103 | |
104 | memset(&ctx, 0, sizeof(ctx)); |
105 | |
106 | ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob, |
107 | payload->blob_len); |
108 | if (ret < 0) |
109 | return ret; |
110 | |
111 | if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE) |
112 | return -EINVAL; |
113 | |
114 | blob = kmalloc(size: ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL); |
115 | if (!blob) |
116 | return -ENOMEM; |
117 | |
118 | *buf = blob; |
119 | options->keyhandle = ctx.parent; |
120 | |
121 | memcpy(blob, ctx.priv, ctx.priv_len); |
122 | blob += ctx.priv_len; |
123 | |
124 | memcpy(blob, ctx.pub, ctx.pub_len); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | int tpm2_key_parent(void *context, size_t hdrlen, |
130 | unsigned char tag, |
131 | const void *value, size_t vlen) |
132 | { |
133 | struct tpm2_key_context *ctx = context; |
134 | const u8 *v = value; |
135 | int i; |
136 | |
137 | ctx->parent = 0; |
138 | for (i = 0; i < vlen; i++) { |
139 | ctx->parent <<= 8; |
140 | ctx->parent |= v[i]; |
141 | } |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | int tpm2_key_type(void *context, size_t hdrlen, |
147 | unsigned char tag, |
148 | const void *value, size_t vlen) |
149 | { |
150 | enum OID oid = look_up_OID(data: value, datasize: vlen); |
151 | |
152 | if (oid != OID_TPMSealedData) { |
153 | char buffer[50]; |
154 | |
155 | sprint_oid(value, vlen, buffer, sizeof(buffer)); |
156 | pr_debug("OID is \"%s\" which is not TPMSealedData\n" , |
157 | buffer); |
158 | return -EINVAL; |
159 | } |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | int tpm2_key_pub(void *context, size_t hdrlen, |
165 | unsigned char tag, |
166 | const void *value, size_t vlen) |
167 | { |
168 | struct tpm2_key_context *ctx = context; |
169 | |
170 | ctx->pub = value; |
171 | ctx->pub_len = vlen; |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | int tpm2_key_priv(void *context, size_t hdrlen, |
177 | unsigned char tag, |
178 | const void *value, size_t vlen) |
179 | { |
180 | struct tpm2_key_context *ctx = context; |
181 | |
182 | ctx->priv = value; |
183 | ctx->priv_len = vlen; |
184 | |
185 | return 0; |
186 | } |
187 | |
188 | /** |
189 | * tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. |
190 | * |
191 | * @buf: an allocated tpm_buf instance |
192 | * @session_handle: session handle |
193 | * @nonce: the session nonce, may be NULL if not used |
194 | * @nonce_len: the session nonce length, may be 0 if not used |
195 | * @attributes: the session attributes |
196 | * @hmac: the session HMAC or password, may be NULL if not used |
197 | * @hmac_len: the session HMAC or password length, maybe 0 if not used |
198 | */ |
199 | static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, |
200 | const u8 *nonce, u16 nonce_len, |
201 | u8 attributes, |
202 | const u8 *hmac, u16 hmac_len) |
203 | { |
204 | tpm_buf_append_u32(buf, value: 9 + nonce_len + hmac_len); |
205 | tpm_buf_append_u32(buf, value: session_handle); |
206 | tpm_buf_append_u16(buf, value: nonce_len); |
207 | |
208 | if (nonce && nonce_len) |
209 | tpm_buf_append(buf, new_data: nonce, new_len: nonce_len); |
210 | |
211 | tpm_buf_append_u8(buf, value: attributes); |
212 | tpm_buf_append_u16(buf, value: hmac_len); |
213 | |
214 | if (hmac && hmac_len) |
215 | tpm_buf_append(buf, new_data: hmac, new_len: hmac_len); |
216 | } |
217 | |
218 | /** |
219 | * tpm2_seal_trusted() - seal the payload of a trusted key |
220 | * |
221 | * @chip: TPM chip to use |
222 | * @payload: the key data in clear and encrypted form |
223 | * @options: authentication values and other options |
224 | * |
225 | * Return: < 0 on error and 0 on success. |
226 | */ |
227 | int tpm2_seal_trusted(struct tpm_chip *chip, |
228 | struct trusted_key_payload *payload, |
229 | struct trusted_key_options *options) |
230 | { |
231 | int blob_len = 0; |
232 | struct tpm_buf buf; |
233 | u32 hash; |
234 | u32 flags; |
235 | int i; |
236 | int rc; |
237 | |
238 | for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { |
239 | if (options->hash == tpm2_hash_map[i].crypto_id) { |
240 | hash = tpm2_hash_map[i].tpm_id; |
241 | break; |
242 | } |
243 | } |
244 | |
245 | if (i == ARRAY_SIZE(tpm2_hash_map)) |
246 | return -EINVAL; |
247 | |
248 | if (!options->keyhandle) |
249 | return -EINVAL; |
250 | |
251 | rc = tpm_try_get_ops(chip); |
252 | if (rc) |
253 | return rc; |
254 | |
255 | rc = tpm_buf_init(buf: &buf, tag: TPM2_ST_SESSIONS, ordinal: TPM2_CC_CREATE); |
256 | if (rc) { |
257 | tpm_put_ops(chip); |
258 | return rc; |
259 | } |
260 | |
261 | tpm_buf_append_u32(buf: &buf, value: options->keyhandle); |
262 | tpm2_buf_append_auth(buf: &buf, session_handle: TPM2_RS_PW, |
263 | NULL /* nonce */, nonce_len: 0, |
264 | attributes: 0 /* session_attributes */, |
265 | hmac: options->keyauth /* hmac */, |
266 | TPM_DIGEST_SIZE); |
267 | |
268 | /* sensitive */ |
269 | tpm_buf_append_u16(buf: &buf, value: 4 + options->blobauth_len + payload->key_len); |
270 | |
271 | tpm_buf_append_u16(buf: &buf, value: options->blobauth_len); |
272 | if (options->blobauth_len) |
273 | tpm_buf_append(buf: &buf, new_data: options->blobauth, new_len: options->blobauth_len); |
274 | |
275 | tpm_buf_append_u16(buf: &buf, value: payload->key_len); |
276 | tpm_buf_append(buf: &buf, new_data: payload->key, new_len: payload->key_len); |
277 | |
278 | /* public */ |
279 | tpm_buf_append_u16(buf: &buf, value: 14 + options->policydigest_len); |
280 | tpm_buf_append_u16(buf: &buf, value: TPM_ALG_KEYEDHASH); |
281 | tpm_buf_append_u16(buf: &buf, value: hash); |
282 | |
283 | /* key properties */ |
284 | flags = 0; |
285 | flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH; |
286 | flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | |
287 | TPM2_OA_FIXED_PARENT); |
288 | tpm_buf_append_u32(buf: &buf, value: flags); |
289 | |
290 | /* policy */ |
291 | tpm_buf_append_u16(buf: &buf, value: options->policydigest_len); |
292 | if (options->policydigest_len) |
293 | tpm_buf_append(buf: &buf, new_data: options->policydigest, |
294 | new_len: options->policydigest_len); |
295 | |
296 | /* public parameters */ |
297 | tpm_buf_append_u16(buf: &buf, value: TPM_ALG_NULL); |
298 | tpm_buf_append_u16(buf: &buf, value: 0); |
299 | |
300 | /* outside info */ |
301 | tpm_buf_append_u16(buf: &buf, value: 0); |
302 | |
303 | /* creation PCR */ |
304 | tpm_buf_append_u32(buf: &buf, value: 0); |
305 | |
306 | if (buf.flags & TPM_BUF_OVERFLOW) { |
307 | rc = -E2BIG; |
308 | goto out; |
309 | } |
310 | |
311 | rc = tpm_transmit_cmd(chip, buf: &buf, min_rsp_body_length: 4, desc: "sealing data" ); |
312 | if (rc) |
313 | goto out; |
314 | |
315 | blob_len = be32_to_cpup(p: (__be32 *) &buf.data[TPM_HEADER_SIZE]); |
316 | if (blob_len > MAX_BLOB_SIZE) { |
317 | rc = -E2BIG; |
318 | goto out; |
319 | } |
320 | if (tpm_buf_length(buf: &buf) < TPM_HEADER_SIZE + 4 + blob_len) { |
321 | rc = -EFAULT; |
322 | goto out; |
323 | } |
324 | |
325 | blob_len = tpm2_key_encode(payload, options, |
326 | src: &buf.data[TPM_HEADER_SIZE + 4], |
327 | len: blob_len); |
328 | |
329 | out: |
330 | tpm_buf_destroy(buf: &buf); |
331 | |
332 | if (rc > 0) { |
333 | if (tpm2_rc_value(rc) == TPM2_RC_HASH) |
334 | rc = -EINVAL; |
335 | else |
336 | rc = -EPERM; |
337 | } |
338 | if (blob_len < 0) |
339 | rc = blob_len; |
340 | else |
341 | payload->blob_len = blob_len; |
342 | |
343 | tpm_put_ops(chip); |
344 | return rc; |
345 | } |
346 | |
347 | /** |
348 | * tpm2_load_cmd() - execute a TPM2_Load command |
349 | * |
350 | * @chip: TPM chip to use |
351 | * @payload: the key data in clear and encrypted form |
352 | * @options: authentication values and other options |
353 | * @blob_handle: returned blob handle |
354 | * |
355 | * Return: 0 on success. |
356 | * -E2BIG on wrong payload size. |
357 | * -EPERM on tpm error status. |
358 | * < 0 error from tpm_send. |
359 | */ |
360 | static int tpm2_load_cmd(struct tpm_chip *chip, |
361 | struct trusted_key_payload *payload, |
362 | struct trusted_key_options *options, |
363 | u32 *blob_handle) |
364 | { |
365 | struct tpm_buf buf; |
366 | unsigned int private_len; |
367 | unsigned int public_len; |
368 | unsigned int blob_len; |
369 | u8 *blob, *pub; |
370 | int rc; |
371 | u32 attrs; |
372 | |
373 | rc = tpm2_key_decode(payload, options, buf: &blob); |
374 | if (rc) { |
375 | /* old form */ |
376 | blob = payload->blob; |
377 | payload->old_format = 1; |
378 | } |
379 | |
380 | /* new format carries keyhandle but old format doesn't */ |
381 | if (!options->keyhandle) |
382 | return -EINVAL; |
383 | |
384 | /* must be big enough for at least the two be16 size counts */ |
385 | if (payload->blob_len < 4) |
386 | return -EINVAL; |
387 | |
388 | private_len = get_unaligned_be16(p: blob); |
389 | |
390 | /* must be big enough for following public_len */ |
391 | if (private_len + 2 + 2 > (payload->blob_len)) |
392 | return -E2BIG; |
393 | |
394 | public_len = get_unaligned_be16(p: blob + 2 + private_len); |
395 | if (private_len + 2 + public_len + 2 > payload->blob_len) |
396 | return -E2BIG; |
397 | |
398 | pub = blob + 2 + private_len + 2; |
399 | /* key attributes are always at offset 4 */ |
400 | attrs = get_unaligned_be32(p: pub + 4); |
401 | |
402 | if ((attrs & (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT)) == |
403 | (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT)) |
404 | payload->migratable = 0; |
405 | else |
406 | payload->migratable = 1; |
407 | |
408 | blob_len = private_len + public_len + 4; |
409 | if (blob_len > payload->blob_len) |
410 | return -E2BIG; |
411 | |
412 | rc = tpm_buf_init(buf: &buf, tag: TPM2_ST_SESSIONS, ordinal: TPM2_CC_LOAD); |
413 | if (rc) |
414 | return rc; |
415 | |
416 | tpm_buf_append_u32(buf: &buf, value: options->keyhandle); |
417 | tpm2_buf_append_auth(buf: &buf, session_handle: TPM2_RS_PW, |
418 | NULL /* nonce */, nonce_len: 0, |
419 | attributes: 0 /* session_attributes */, |
420 | hmac: options->keyauth /* hmac */, |
421 | TPM_DIGEST_SIZE); |
422 | |
423 | tpm_buf_append(buf: &buf, new_data: blob, new_len: blob_len); |
424 | |
425 | if (buf.flags & TPM_BUF_OVERFLOW) { |
426 | rc = -E2BIG; |
427 | goto out; |
428 | } |
429 | |
430 | rc = tpm_transmit_cmd(chip, buf: &buf, min_rsp_body_length: 4, desc: "loading blob" ); |
431 | if (!rc) |
432 | *blob_handle = be32_to_cpup( |
433 | p: (__be32 *) &buf.data[TPM_HEADER_SIZE]); |
434 | |
435 | out: |
436 | if (blob != payload->blob) |
437 | kfree(objp: blob); |
438 | tpm_buf_destroy(buf: &buf); |
439 | |
440 | if (rc > 0) |
441 | rc = -EPERM; |
442 | |
443 | return rc; |
444 | } |
445 | |
446 | /** |
447 | * tpm2_unseal_cmd() - execute a TPM2_Unload command |
448 | * |
449 | * @chip: TPM chip to use |
450 | * @payload: the key data in clear and encrypted form |
451 | * @options: authentication values and other options |
452 | * @blob_handle: blob handle |
453 | * |
454 | * Return: 0 on success |
455 | * -EPERM on tpm error status |
456 | * < 0 error from tpm_send |
457 | */ |
458 | static int tpm2_unseal_cmd(struct tpm_chip *chip, |
459 | struct trusted_key_payload *payload, |
460 | struct trusted_key_options *options, |
461 | u32 blob_handle) |
462 | { |
463 | struct tpm_buf buf; |
464 | u16 data_len; |
465 | u8 *data; |
466 | int rc; |
467 | |
468 | rc = tpm_buf_init(buf: &buf, tag: TPM2_ST_SESSIONS, ordinal: TPM2_CC_UNSEAL); |
469 | if (rc) |
470 | return rc; |
471 | |
472 | tpm_buf_append_u32(buf: &buf, value: blob_handle); |
473 | tpm2_buf_append_auth(buf: &buf, |
474 | session_handle: options->policyhandle ? |
475 | options->policyhandle : TPM2_RS_PW, |
476 | NULL /* nonce */, nonce_len: 0, |
477 | attributes: TPM2_SA_CONTINUE_SESSION, |
478 | hmac: options->blobauth /* hmac */, |
479 | hmac_len: options->blobauth_len); |
480 | |
481 | rc = tpm_transmit_cmd(chip, buf: &buf, min_rsp_body_length: 6, desc: "unsealing" ); |
482 | if (rc > 0) |
483 | rc = -EPERM; |
484 | |
485 | if (!rc) { |
486 | data_len = be16_to_cpup( |
487 | p: (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); |
488 | if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) { |
489 | rc = -EFAULT; |
490 | goto out; |
491 | } |
492 | |
493 | if (tpm_buf_length(buf: &buf) < TPM_HEADER_SIZE + 6 + data_len) { |
494 | rc = -EFAULT; |
495 | goto out; |
496 | } |
497 | data = &buf.data[TPM_HEADER_SIZE + 6]; |
498 | |
499 | if (payload->old_format) { |
500 | /* migratable flag is at the end of the key */ |
501 | memcpy(payload->key, data, data_len - 1); |
502 | payload->key_len = data_len - 1; |
503 | payload->migratable = data[data_len - 1]; |
504 | } else { |
505 | /* |
506 | * migratable flag already collected from key |
507 | * attributes |
508 | */ |
509 | memcpy(payload->key, data, data_len); |
510 | payload->key_len = data_len; |
511 | } |
512 | } |
513 | |
514 | out: |
515 | tpm_buf_destroy(buf: &buf); |
516 | return rc; |
517 | } |
518 | |
519 | /** |
520 | * tpm2_unseal_trusted() - unseal the payload of a trusted key |
521 | * |
522 | * @chip: TPM chip to use |
523 | * @payload: the key data in clear and encrypted form |
524 | * @options: authentication values and other options |
525 | * |
526 | * Return: Same as with tpm_send. |
527 | */ |
528 | int tpm2_unseal_trusted(struct tpm_chip *chip, |
529 | struct trusted_key_payload *payload, |
530 | struct trusted_key_options *options) |
531 | { |
532 | u32 blob_handle; |
533 | int rc; |
534 | |
535 | rc = tpm_try_get_ops(chip); |
536 | if (rc) |
537 | return rc; |
538 | |
539 | rc = tpm2_load_cmd(chip, payload, options, blob_handle: &blob_handle); |
540 | if (rc) |
541 | goto out; |
542 | |
543 | rc = tpm2_unseal_cmd(chip, payload, options, blob_handle); |
544 | tpm2_flush_context(chip, handle: blob_handle); |
545 | |
546 | out: |
547 | tpm_put_ops(chip); |
548 | |
549 | return rc; |
550 | } |
551 | |