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