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