]> git.ipfire.org Git - people/ms/u-boot.git/blob - lib/tpm.c
tpm: add missing va_end
[people/ms/u-boot.git] / lib / tpm.c
1 /*
2 * Copyright (c) 2013 The Chromium OS Authors.
3 * Coypright (c) 2013 Guntermann & Drunck GmbH
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <tpm.h>
11 #include <asm/unaligned.h>
12 #include <u-boot/sha1.h>
13
14 /* Internal error of TPM command library */
15 #define TPM_LIB_ERROR ((uint32_t)~0u)
16
17 /* Useful constants */
18 enum {
19 COMMAND_BUFFER_SIZE = 256,
20 TPM_REQUEST_HEADER_LENGTH = 10,
21 TPM_RESPONSE_HEADER_LENGTH = 10,
22 PCR_DIGEST_LENGTH = 20,
23 DIGEST_LENGTH = 20,
24 TPM_REQUEST_AUTH_LENGTH = 45,
25 TPM_RESPONSE_AUTH_LENGTH = 41,
26 /* some max lengths, valid for RSA keys <= 2048 bits */
27 TPM_KEY12_MAX_LENGTH = 618,
28 TPM_PUBKEY_MAX_LENGTH = 288,
29 };
30
31 #ifdef CONFIG_TPM_AUTH_SESSIONS
32
33 #ifndef CONFIG_SHA1
34 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
35 #endif /* !CONFIG_SHA1 */
36
37 struct session_data {
38 int valid;
39 uint32_t handle;
40 uint8_t nonce_even[DIGEST_LENGTH];
41 uint8_t nonce_odd[DIGEST_LENGTH];
42 };
43
44 static struct session_data oiap_session = {0, };
45
46 #endif /* CONFIG_TPM_AUTH_SESSIONS */
47
48 /**
49 * Pack data into a byte string. The data types are specified in
50 * the format string: 'b' means unsigned byte, 'w' unsigned word,
51 * 'd' unsigned double word, and 's' byte string. The data are a
52 * series of offsets and values (for type byte string there are also
53 * lengths). The data values are packed into the byte string
54 * sequentially, and so a latter value could over-write a former
55 * value.
56 *
57 * @param str output string
58 * @param size size of output string
59 * @param format format string
60 * @param ... data points
61 * @return 0 on success, non-0 on error
62 */
63 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
64 {
65 va_list args;
66 size_t offset = 0, length = 0;
67 uint8_t *data = NULL;
68 uint32_t value = 0;
69
70 va_start(args, format);
71 for (; *format; format++) {
72 switch (*format) {
73 case 'b':
74 offset = va_arg(args, size_t);
75 value = va_arg(args, int);
76 length = 1;
77 break;
78 case 'w':
79 offset = va_arg(args, size_t);
80 value = va_arg(args, int);
81 length = 2;
82 break;
83 case 'd':
84 offset = va_arg(args, size_t);
85 value = va_arg(args, uint32_t);
86 length = 4;
87 break;
88 case 's':
89 offset = va_arg(args, size_t);
90 data = va_arg(args, uint8_t *);
91 length = va_arg(args, uint32_t);
92 break;
93 default:
94 debug("Couldn't recognize format string\n");
95 return -1;
96 }
97
98 if (offset + length > size) {
99 va_end(args);
100 return -1;
101 }
102
103 switch (*format) {
104 case 'b':
105 str[offset] = value;
106 break;
107 case 'w':
108 put_unaligned_be16(value, str + offset);
109 break;
110 case 'd':
111 put_unaligned_be32(value, str + offset);
112 break;
113 case 's':
114 memcpy(str + offset, data, length);
115 break;
116 }
117 }
118 va_end(args);
119
120 return 0;
121 }
122
123 /**
124 * Unpack data from a byte string. The data types are specified in
125 * the format string: 'b' means unsigned byte, 'w' unsigned word,
126 * 'd' unsigned double word, and 's' byte string. The data are a
127 * series of offsets and pointers (for type byte string there are also
128 * lengths).
129 *
130 * @param str output string
131 * @param size size of output string
132 * @param format format string
133 * @param ... data points
134 * @return 0 on success, non-0 on error
135 */
136 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
137 {
138 va_list args;
139 size_t offset = 0, length = 0;
140 uint8_t *ptr8 = NULL;
141 uint16_t *ptr16 = NULL;
142 uint32_t *ptr32 = NULL;
143
144 va_start(args, format);
145 for (; *format; format++) {
146 switch (*format) {
147 case 'b':
148 offset = va_arg(args, size_t);
149 ptr8 = va_arg(args, uint8_t *);
150 length = 1;
151 break;
152 case 'w':
153 offset = va_arg(args, size_t);
154 ptr16 = va_arg(args, uint16_t *);
155 length = 2;
156 break;
157 case 'd':
158 offset = va_arg(args, size_t);
159 ptr32 = va_arg(args, uint32_t *);
160 length = 4;
161 break;
162 case 's':
163 offset = va_arg(args, size_t);
164 ptr8 = va_arg(args, uint8_t *);
165 length = va_arg(args, uint32_t);
166 break;
167 default:
168 va_end(args);
169 debug("Couldn't recognize format string\n");
170 return -1;
171 }
172
173 if (offset + length > size)
174 return -1;
175
176 switch (*format) {
177 case 'b':
178 *ptr8 = str[offset];
179 break;
180 case 'w':
181 *ptr16 = get_unaligned_be16(str + offset);
182 break;
183 case 'd':
184 *ptr32 = get_unaligned_be32(str + offset);
185 break;
186 case 's':
187 memcpy(ptr8, str + offset, length);
188 break;
189 }
190 }
191 va_end(args);
192
193 return 0;
194 }
195
196 /**
197 * Get TPM command size.
198 *
199 * @param command byte string of TPM command
200 * @return command size of the TPM command
201 */
202 static uint32_t tpm_command_size(const void *command)
203 {
204 const size_t command_size_offset = 2;
205 return get_unaligned_be32(command + command_size_offset);
206 }
207
208 /**
209 * Get TPM response return code, which is one of TPM_RESULT values.
210 *
211 * @param response byte string of TPM response
212 * @return return code of the TPM response
213 */
214 static uint32_t tpm_return_code(const void *response)
215 {
216 const size_t return_code_offset = 6;
217 return get_unaligned_be32(response + return_code_offset);
218 }
219
220 /**
221 * Send a TPM command and return response's return code, and optionally
222 * return response to caller.
223 *
224 * @param command byte string of TPM command
225 * @param response output buffer for TPM response, or NULL if the
226 * caller does not care about it
227 * @param size_ptr output buffer size (input parameter) and TPM
228 * response length (output parameter); this parameter
229 * is a bidirectional
230 * @return return code of the TPM response
231 */
232 static uint32_t tpm_sendrecv_command(const void *command,
233 void *response, size_t *size_ptr)
234 {
235 struct udevice *dev;
236 int err, ret;
237 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
238 size_t response_length;
239
240 if (response) {
241 response_length = *size_ptr;
242 } else {
243 response = response_buffer;
244 response_length = sizeof(response_buffer);
245 }
246
247 ret = uclass_first_device_err(UCLASS_TPM, &dev);
248 if (ret)
249 return ret;
250 err = tpm_xfer(dev, command, tpm_command_size(command),
251 response, &response_length);
252
253 if (err < 0)
254 return TPM_LIB_ERROR;
255 if (size_ptr)
256 *size_ptr = response_length;
257
258 return tpm_return_code(response);
259 }
260
261 int tpm_init(void)
262 {
263 int err;
264 struct udevice *dev;
265
266 err = uclass_first_device_err(UCLASS_TPM, &dev);
267 if (err)
268 return err;
269 return tpm_open(dev);
270 }
271
272 uint32_t tpm_startup(enum tpm_startup_type mode)
273 {
274 const uint8_t command[12] = {
275 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
276 };
277 const size_t mode_offset = 10;
278 uint8_t buf[COMMAND_BUFFER_SIZE];
279
280 if (pack_byte_string(buf, sizeof(buf), "sw",
281 0, command, sizeof(command),
282 mode_offset, mode))
283 return TPM_LIB_ERROR;
284
285 return tpm_sendrecv_command(buf, NULL, NULL);
286 }
287
288 uint32_t tpm_self_test_full(void)
289 {
290 const uint8_t command[10] = {
291 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
292 };
293 return tpm_sendrecv_command(command, NULL, NULL);
294 }
295
296 uint32_t tpm_continue_self_test(void)
297 {
298 const uint8_t command[10] = {
299 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
300 };
301 return tpm_sendrecv_command(command, NULL, NULL);
302 }
303
304 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
305 {
306 const uint8_t command[101] = {
307 0x0, 0xc1, /* TPM_TAG */
308 0x0, 0x0, 0x0, 0x65, /* parameter size */
309 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
310 /* TPM_NV_DATA_PUBLIC->... */
311 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
312 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
313 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
314 0x0, 0x3,
315 0, 0, 0,
316 0x1f,
317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
318 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
319 0x0, 0x3,
320 0, 0, 0,
321 0x1f,
322 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
323 /* TPM_NV_ATTRIBUTES->... */
324 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
325 0, 0, 0, 0, /* ...->attributes */
326 /* End of TPM_NV_ATTRIBUTES */
327 0, /* bReadSTClear */
328 0, /* bWriteSTClear */
329 0, /* bWriteDefine */
330 0, 0, 0, 0, /* size */
331 };
332 const size_t index_offset = 12;
333 const size_t perm_offset = 70;
334 const size_t size_offset = 77;
335 uint8_t buf[COMMAND_BUFFER_SIZE];
336
337 if (pack_byte_string(buf, sizeof(buf), "sddd",
338 0, command, sizeof(command),
339 index_offset, index,
340 perm_offset, perm,
341 size_offset, size))
342 return TPM_LIB_ERROR;
343
344 return tpm_sendrecv_command(buf, NULL, NULL);
345 }
346
347 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
348 {
349 const uint8_t command[22] = {
350 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
351 };
352 const size_t index_offset = 10;
353 const size_t length_offset = 18;
354 const size_t data_size_offset = 10;
355 const size_t data_offset = 14;
356 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
357 size_t response_length = sizeof(response);
358 uint32_t data_size;
359 uint32_t err;
360
361 if (pack_byte_string(buf, sizeof(buf), "sdd",
362 0, command, sizeof(command),
363 index_offset, index,
364 length_offset, count))
365 return TPM_LIB_ERROR;
366 err = tpm_sendrecv_command(buf, response, &response_length);
367 if (err)
368 return err;
369 if (unpack_byte_string(response, response_length, "d",
370 data_size_offset, &data_size))
371 return TPM_LIB_ERROR;
372 if (data_size > count)
373 return TPM_LIB_ERROR;
374 if (unpack_byte_string(response, response_length, "s",
375 data_offset, data, data_size))
376 return TPM_LIB_ERROR;
377
378 return 0;
379 }
380
381 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
382 {
383 const uint8_t command[256] = {
384 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
385 };
386 const size_t command_size_offset = 2;
387 const size_t index_offset = 10;
388 const size_t length_offset = 18;
389 const size_t data_offset = 22;
390 const size_t write_info_size = 12;
391 const uint32_t total_length =
392 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
393 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
394 size_t response_length = sizeof(response);
395 uint32_t err;
396
397 if (pack_byte_string(buf, sizeof(buf), "sddds",
398 0, command, sizeof(command),
399 command_size_offset, total_length,
400 index_offset, index,
401 length_offset, length,
402 data_offset, data, length))
403 return TPM_LIB_ERROR;
404 err = tpm_sendrecv_command(buf, response, &response_length);
405 if (err)
406 return err;
407
408 return 0;
409 }
410
411 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
412 {
413 const uint8_t command[34] = {
414 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
415 };
416 const size_t index_offset = 10;
417 const size_t in_digest_offset = 14;
418 const size_t out_digest_offset = 10;
419 uint8_t buf[COMMAND_BUFFER_SIZE];
420 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
421 size_t response_length = sizeof(response);
422 uint32_t err;
423
424 if (pack_byte_string(buf, sizeof(buf), "sds",
425 0, command, sizeof(command),
426 index_offset, index,
427 in_digest_offset, in_digest,
428 PCR_DIGEST_LENGTH))
429 return TPM_LIB_ERROR;
430 err = tpm_sendrecv_command(buf, response, &response_length);
431 if (err)
432 return err;
433
434 if (unpack_byte_string(response, response_length, "s",
435 out_digest_offset, out_digest,
436 PCR_DIGEST_LENGTH))
437 return TPM_LIB_ERROR;
438
439 return 0;
440 }
441
442 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
443 {
444 const uint8_t command[14] = {
445 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
446 };
447 const size_t index_offset = 10;
448 const size_t out_digest_offset = 10;
449 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
450 size_t response_length = sizeof(response);
451 uint32_t err;
452
453 if (count < PCR_DIGEST_LENGTH)
454 return TPM_LIB_ERROR;
455
456 if (pack_byte_string(buf, sizeof(buf), "sd",
457 0, command, sizeof(command),
458 index_offset, index))
459 return TPM_LIB_ERROR;
460 err = tpm_sendrecv_command(buf, response, &response_length);
461 if (err)
462 return err;
463 if (unpack_byte_string(response, response_length, "s",
464 out_digest_offset, data, PCR_DIGEST_LENGTH))
465 return TPM_LIB_ERROR;
466
467 return 0;
468 }
469
470 uint32_t tpm_tsc_physical_presence(uint16_t presence)
471 {
472 const uint8_t command[12] = {
473 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
474 };
475 const size_t presence_offset = 10;
476 uint8_t buf[COMMAND_BUFFER_SIZE];
477
478 if (pack_byte_string(buf, sizeof(buf), "sw",
479 0, command, sizeof(command),
480 presence_offset, presence))
481 return TPM_LIB_ERROR;
482
483 return tpm_sendrecv_command(buf, NULL, NULL);
484 }
485
486 uint32_t tpm_read_pubek(void *data, size_t count)
487 {
488 const uint8_t command[30] = {
489 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
490 };
491 const size_t response_size_offset = 2;
492 const size_t data_offset = 10;
493 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
494 uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
495 size_t response_length = sizeof(response);
496 uint32_t data_size;
497 uint32_t err;
498
499 err = tpm_sendrecv_command(command, response, &response_length);
500 if (err)
501 return err;
502 if (unpack_byte_string(response, response_length, "d",
503 response_size_offset, &data_size))
504 return TPM_LIB_ERROR;
505 if (data_size < header_and_checksum_size)
506 return TPM_LIB_ERROR;
507 data_size -= header_and_checksum_size;
508 if (data_size > count)
509 return TPM_LIB_ERROR;
510 if (unpack_byte_string(response, response_length, "s",
511 data_offset, data, data_size))
512 return TPM_LIB_ERROR;
513
514 return 0;
515 }
516
517 uint32_t tpm_force_clear(void)
518 {
519 const uint8_t command[10] = {
520 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
521 };
522
523 return tpm_sendrecv_command(command, NULL, NULL);
524 }
525
526 uint32_t tpm_physical_enable(void)
527 {
528 const uint8_t command[10] = {
529 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
530 };
531
532 return tpm_sendrecv_command(command, NULL, NULL);
533 }
534
535 uint32_t tpm_physical_disable(void)
536 {
537 const uint8_t command[10] = {
538 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
539 };
540
541 return tpm_sendrecv_command(command, NULL, NULL);
542 }
543
544 uint32_t tpm_physical_set_deactivated(uint8_t state)
545 {
546 const uint8_t command[11] = {
547 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
548 };
549 const size_t state_offset = 10;
550 uint8_t buf[COMMAND_BUFFER_SIZE];
551
552 if (pack_byte_string(buf, sizeof(buf), "sb",
553 0, command, sizeof(command),
554 state_offset, state))
555 return TPM_LIB_ERROR;
556
557 return tpm_sendrecv_command(buf, NULL, NULL);
558 }
559
560 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
561 void *cap, size_t count)
562 {
563 const uint8_t command[22] = {
564 0x0, 0xc1, /* TPM_TAG */
565 0x0, 0x0, 0x0, 0x16, /* parameter size */
566 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
567 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
568 0x0, 0x0, 0x0, 0x4, /* subcap size */
569 0x0, 0x0, 0x0, 0x0, /* subcap value */
570 };
571 const size_t cap_area_offset = 10;
572 const size_t sub_cap_offset = 18;
573 const size_t cap_offset = 14;
574 const size_t cap_size_offset = 10;
575 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
576 size_t response_length = sizeof(response);
577 uint32_t cap_size;
578 uint32_t err;
579
580 if (pack_byte_string(buf, sizeof(buf), "sdd",
581 0, command, sizeof(command),
582 cap_area_offset, cap_area,
583 sub_cap_offset, sub_cap))
584 return TPM_LIB_ERROR;
585 err = tpm_sendrecv_command(buf, response, &response_length);
586 if (err)
587 return err;
588 if (unpack_byte_string(response, response_length, "d",
589 cap_size_offset, &cap_size))
590 return TPM_LIB_ERROR;
591 if (cap_size > response_length || cap_size > count)
592 return TPM_LIB_ERROR;
593 if (unpack_byte_string(response, response_length, "s",
594 cap_offset, cap, cap_size))
595 return TPM_LIB_ERROR;
596
597 return 0;
598 }
599
600 uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
601 {
602 const uint8_t command[22] = {
603 0x0, 0xc1, /* TPM_TAG */
604 0x0, 0x0, 0x0, 0x16, /* parameter size */
605 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
606 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
607 0x0, 0x0, 0x0, 0x4, /* subcap size */
608 0x0, 0x0, 0x1, 0x8, /* subcap value */
609 };
610 uint8_t response[COMMAND_BUFFER_SIZE];
611 size_t response_length = sizeof(response);
612 uint32_t err;
613
614 err = tpm_sendrecv_command(command, response, &response_length);
615 if (err)
616 return err;
617 memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
618
619 return 0;
620 }
621
622 uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
623 {
624 const uint8_t command[22] = {
625 0x0, 0xc1, /* TPM_TAG */
626 0x0, 0x0, 0x0, 0x16, /* parameter size */
627 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
628 0x0, 0x0, 0x0, 0x11,
629 0x0, 0x0, 0x0, 0x4,
630 };
631 const size_t index_offset = 18;
632 const size_t perm_offset = 60;
633 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
634 size_t response_length = sizeof(response);
635 uint32_t err;
636
637 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
638 index_offset, index))
639 return TPM_LIB_ERROR;
640 err = tpm_sendrecv_command(buf, response, &response_length);
641 if (err)
642 return err;
643 if (unpack_byte_string(response, response_length, "d",
644 perm_offset, perm))
645 return TPM_LIB_ERROR;
646
647 return 0;
648 }
649
650 #ifdef CONFIG_TPM_FLUSH_RESOURCES
651 uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type)
652 {
653 const uint8_t command[18] = {
654 0x00, 0xc1, /* TPM_TAG */
655 0x00, 0x00, 0x00, 0x12, /* parameter size */
656 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
657 0x00, 0x00, 0x00, 0x00, /* key handle */
658 0x00, 0x00, 0x00, 0x00, /* resource type */
659 };
660 const size_t key_handle_offset = 10;
661 const size_t resource_type_offset = 14;
662 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
663 size_t response_length = sizeof(response);
664 uint32_t err;
665
666 if (pack_byte_string(buf, sizeof(buf), "sdd",
667 0, command, sizeof(command),
668 key_handle_offset, key_handle,
669 resource_type_offset, resource_type))
670 return TPM_LIB_ERROR;
671
672 err = tpm_sendrecv_command(buf, response, &response_length);
673 if (err)
674 return err;
675 return 0;
676 }
677 #endif /* CONFIG_TPM_FLUSH_RESOURCES */
678
679 #ifdef CONFIG_TPM_AUTH_SESSIONS
680
681 /**
682 * Fill an authentication block in a request.
683 * This func can create the first as well as the second auth block (for
684 * double authorized commands).
685 *
686 * @param request pointer to the request (w/ uninitialised auth data)
687 * @param request_len0 length of the request without auth data
688 * @param handles_len length of the handles area in request
689 * @param auth_session pointer to the (valid) auth session to be used
690 * @param request_auth pointer to the auth block of the request to be filled
691 * @param auth authentication data (HMAC key)
692 */
693 static uint32_t create_request_auth(const void *request, size_t request_len0,
694 size_t handles_len,
695 struct session_data *auth_session,
696 void *request_auth, const void *auth)
697 {
698 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
699 sha1_context hash_ctx;
700 const size_t command_code_offset = 6;
701 const size_t auth_nonce_odd_offset = 4;
702 const size_t auth_continue_offset = 24;
703 const size_t auth_auth_offset = 25;
704
705 if (!auth_session || !auth_session->valid)
706 return TPM_LIB_ERROR;
707
708 sha1_starts(&hash_ctx);
709 sha1_update(&hash_ctx, request + command_code_offset, 4);
710 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
711 sha1_update(&hash_ctx,
712 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
713 request_len0 - TPM_REQUEST_HEADER_LENGTH
714 - handles_len);
715 sha1_finish(&hash_ctx, hmac_data);
716
717 sha1_starts(&hash_ctx);
718 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
719 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
720 sha1_finish(&hash_ctx, auth_session->nonce_odd);
721
722 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
723 0, auth_session->handle,
724 auth_nonce_odd_offset, auth_session->nonce_odd,
725 DIGEST_LENGTH,
726 auth_continue_offset, 1))
727 return TPM_LIB_ERROR;
728 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
729 DIGEST_LENGTH,
730 auth_session->nonce_even,
731 DIGEST_LENGTH,
732 2 * DIGEST_LENGTH,
733 request_auth + auth_nonce_odd_offset,
734 DIGEST_LENGTH + 1))
735 return TPM_LIB_ERROR;
736 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
737 request_auth + auth_auth_offset);
738
739 return TPM_SUCCESS;
740 }
741
742 /**
743 * Verify an authentication block in a response.
744 * Since this func updates the nonce_even in the session data it has to be
745 * called when receiving a succesfull AUTH response.
746 * This func can verify the first as well as the second auth block (for
747 * double authorized commands).
748 *
749 * @param command_code command code of the request
750 * @param response pointer to the request (w/ uninitialised auth data)
751 * @param handles_len length of the handles area in response
752 * @param auth_session pointer to the (valid) auth session to be used
753 * @param response_auth pointer to the auth block of the response to be verified
754 * @param auth authentication data (HMAC key)
755 */
756 static uint32_t verify_response_auth(uint32_t command_code,
757 const void *response, size_t response_len0,
758 size_t handles_len,
759 struct session_data *auth_session,
760 const void *response_auth, const void *auth)
761 {
762 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
763 uint8_t computed_auth[DIGEST_LENGTH];
764 sha1_context hash_ctx;
765 const size_t return_code_offset = 6;
766 const size_t auth_continue_offset = 20;
767 const size_t auth_auth_offset = 21;
768 uint8_t auth_continue;
769
770 if (!auth_session || !auth_session->valid)
771 return TPM_AUTHFAIL;
772 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
773 0, command_code))
774 return TPM_LIB_ERROR;
775 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
776 return TPM_LIB_ERROR;
777
778 sha1_starts(&hash_ctx);
779 sha1_update(&hash_ctx, response + return_code_offset, 4);
780 sha1_update(&hash_ctx, hmac_data, 4);
781 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
782 sha1_update(&hash_ctx,
783 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
784 response_len0 - TPM_RESPONSE_HEADER_LENGTH
785 - handles_len);
786 sha1_finish(&hash_ctx, hmac_data);
787
788 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
789 auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
790 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
791 DIGEST_LENGTH,
792 response_auth,
793 DIGEST_LENGTH,
794 2 * DIGEST_LENGTH,
795 auth_session->nonce_odd,
796 DIGEST_LENGTH,
797 3 * DIGEST_LENGTH,
798 auth_continue))
799 return TPM_LIB_ERROR;
800
801 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
802 computed_auth);
803
804 if (memcmp(computed_auth, response_auth + auth_auth_offset,
805 DIGEST_LENGTH))
806 return TPM_AUTHFAIL;
807
808 return TPM_SUCCESS;
809 }
810
811
812 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
813 {
814 const uint8_t command[18] = {
815 0x00, 0xc1, /* TPM_TAG */
816 0x00, 0x00, 0x00, 0x00, /* parameter size */
817 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
818 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
819 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
820 };
821 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
822 uint8_t request[COMMAND_BUFFER_SIZE];
823
824 if (pack_byte_string(request, sizeof(request), "sd",
825 0, command, sizeof(command),
826 req_handle_offset, auth_handle))
827 return TPM_LIB_ERROR;
828 if (oiap_session.valid && oiap_session.handle == auth_handle)
829 oiap_session.valid = 0;
830
831 return tpm_sendrecv_command(request, NULL, NULL);
832 }
833
834 uint32_t tpm_end_oiap(void)
835 {
836 uint32_t err = TPM_SUCCESS;
837 if (oiap_session.valid)
838 err = tpm_terminate_auth_session(oiap_session.handle);
839 return err;
840 }
841
842 uint32_t tpm_oiap(uint32_t *auth_handle)
843 {
844 const uint8_t command[10] = {
845 0x00, 0xc1, /* TPM_TAG */
846 0x00, 0x00, 0x00, 0x0a, /* parameter size */
847 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
848 };
849 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
850 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
851 uint8_t response[COMMAND_BUFFER_SIZE];
852 size_t response_length = sizeof(response);
853 uint32_t err;
854
855 if (oiap_session.valid)
856 tpm_terminate_auth_session(oiap_session.handle);
857
858 err = tpm_sendrecv_command(command, response, &response_length);
859 if (err)
860 return err;
861 if (unpack_byte_string(response, response_length, "ds",
862 res_auth_handle_offset, &oiap_session.handle,
863 res_nonce_even_offset, &oiap_session.nonce_even,
864 (uint32_t)DIGEST_LENGTH))
865 return TPM_LIB_ERROR;
866 oiap_session.valid = 1;
867 if (auth_handle)
868 *auth_handle = oiap_session.handle;
869 return 0;
870 }
871
872 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
873 const void *key, size_t key_length,
874 const void *parent_key_usage_auth,
875 uint32_t *key_handle)
876 {
877 const uint8_t command[14] = {
878 0x00, 0xc2, /* TPM_TAG */
879 0x00, 0x00, 0x00, 0x00, /* parameter size */
880 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
881 0x00, 0x00, 0x00, 0x00, /* parent handle */
882 };
883 const size_t req_size_offset = 2;
884 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
885 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
886 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
887 uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
888 + TPM_REQUEST_AUTH_LENGTH];
889 uint8_t response[COMMAND_BUFFER_SIZE];
890 size_t response_length = sizeof(response);
891 uint32_t err;
892
893 if (!oiap_session.valid) {
894 err = tpm_oiap(NULL);
895 if (err)
896 return err;
897 }
898 if (pack_byte_string(request, sizeof(request), "sdds",
899 0, command, sizeof(command),
900 req_size_offset,
901 sizeof(command) + key_length
902 + TPM_REQUEST_AUTH_LENGTH,
903 req_parent_handle_offset, parent_handle,
904 req_key_offset, key, key_length
905 ))
906 return TPM_LIB_ERROR;
907
908 err = create_request_auth(request, sizeof(command) + key_length, 4,
909 &oiap_session,
910 request + sizeof(command) + key_length,
911 parent_key_usage_auth);
912 if (err)
913 return err;
914 err = tpm_sendrecv_command(request, response, &response_length);
915 if (err) {
916 if (err == TPM_AUTHFAIL)
917 oiap_session.valid = 0;
918 return err;
919 }
920
921 err = verify_response_auth(0x00000041, response,
922 response_length - TPM_RESPONSE_AUTH_LENGTH,
923 4, &oiap_session,
924 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
925 parent_key_usage_auth);
926 if (err)
927 return err;
928
929 if (key_handle) {
930 if (unpack_byte_string(response, response_length, "d",
931 res_handle_offset, key_handle))
932 return TPM_LIB_ERROR;
933 }
934
935 return 0;
936 }
937
938 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
939 void *pubkey, size_t *pubkey_len)
940 {
941 const uint8_t command[14] = {
942 0x00, 0xc2, /* TPM_TAG */
943 0x00, 0x00, 0x00, 0x00, /* parameter size */
944 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
945 0x00, 0x00, 0x00, 0x00, /* key handle */
946 };
947 const size_t req_size_offset = 2;
948 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
949 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
950 uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
951 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
952 + TPM_RESPONSE_AUTH_LENGTH];
953 size_t response_length = sizeof(response);
954 uint32_t err;
955
956 if (!oiap_session.valid) {
957 err = tpm_oiap(NULL);
958 if (err)
959 return err;
960 }
961 if (pack_byte_string(request, sizeof(request), "sdd",
962 0, command, sizeof(command),
963 req_size_offset,
964 (uint32_t)(sizeof(command)
965 + TPM_REQUEST_AUTH_LENGTH),
966 req_key_handle_offset, key_handle
967 ))
968 return TPM_LIB_ERROR;
969 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
970 request + sizeof(command), usage_auth);
971 if (err)
972 return err;
973 err = tpm_sendrecv_command(request, response, &response_length);
974 if (err) {
975 if (err == TPM_AUTHFAIL)
976 oiap_session.valid = 0;
977 return err;
978 }
979 err = verify_response_auth(0x00000021, response,
980 response_length - TPM_RESPONSE_AUTH_LENGTH,
981 0, &oiap_session,
982 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
983 usage_auth);
984 if (err)
985 return err;
986
987 if (pubkey) {
988 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
989 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
990 return TPM_LIB_ERROR;
991 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
992 - TPM_RESPONSE_AUTH_LENGTH;
993 memcpy(pubkey, response + res_pubkey_offset,
994 response_length - TPM_RESPONSE_HEADER_LENGTH
995 - TPM_RESPONSE_AUTH_LENGTH);
996 }
997
998 return 0;
999 }
1000
1001 #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
1002 uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
1003 pubkey_digest[20], uint32_t *handle)
1004 {
1005 uint16_t key_count;
1006 uint32_t key_handles[10];
1007 uint8_t buf[288];
1008 uint8_t *ptr;
1009 uint32_t err;
1010 uint8_t digest[20];
1011 size_t buf_len;
1012 unsigned int i;
1013
1014 /* fetch list of already loaded keys in the TPM */
1015 err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
1016 if (err)
1017 return -1;
1018 key_count = get_unaligned_be16(buf);
1019 ptr = buf + 2;
1020 for (i = 0; i < key_count; ++i, ptr += 4)
1021 key_handles[i] = get_unaligned_be32(ptr);
1022
1023 /* now search a(/ the) key which we can access with the given auth */
1024 for (i = 0; i < key_count; ++i) {
1025 buf_len = sizeof(buf);
1026 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
1027 if (err && err != TPM_AUTHFAIL)
1028 return -1;
1029 if (err)
1030 continue;
1031 sha1_csum(buf, buf_len, digest);
1032 if (!memcmp(digest, pubkey_digest, 20)) {
1033 *handle = key_handles[i];
1034 return 0;
1035 }
1036 }
1037 return 1;
1038 }
1039 #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
1040
1041 #endif /* CONFIG_TPM_AUTH_SESSIONS */