]> git.ipfire.org Git - people/ms/u-boot.git/blame - lib/tpm.c
include/net.h: add max_speed member in struct eth_pdata
[people/ms/u-boot.git] / lib / tpm.c
CommitLineData
8732b070
CC
1/*
2 * Copyright (c) 2013 The Chromium OS Authors.
be6c1529 3 * Coypright (c) 2013 Guntermann & Drunck GmbH
8732b070 4 *
1a459660 5 * SPDX-License-Identifier: GPL-2.0+
8732b070
CC
6 */
7
8#include <common.h>
c8a8c510 9#include <dm.h>
8732b070
CC
10#include <tpm.h>
11#include <asm/unaligned.h>
c8a8c510 12#include <u-boot/sha1.h>
8732b070
CC
13
14/* Internal error of TPM command library */
15#define TPM_LIB_ERROR ((uint32_t)~0u)
16
17/* Useful constants */
18enum {
19 COMMAND_BUFFER_SIZE = 256,
8732b070
CC
20 TPM_REQUEST_HEADER_LENGTH = 10,
21 TPM_RESPONSE_HEADER_LENGTH = 10,
22 PCR_DIGEST_LENGTH = 20,
be6c1529
RP
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,
8732b070
CC
29};
30
be6c1529
RP
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
37struct 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
44static struct session_data oiap_session = {0, };
45
46#endif /* CONFIG_TPM_AUTH_SESSIONS */
47
8732b070
CC
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 */
63int 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 */
134int 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 */
199static 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 */
211static 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 */
229static uint32_t tpm_sendrecv_command(const void *command,
230 void *response, size_t *size_ptr)
231{
c2b0f600
CR
232 struct udevice *dev;
233 int ret;
8732b070
CC
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 }
c8a8c510
SG
244
245 ret = uclass_first_device(UCLASS_TPM, &dev);
246 if (ret)
247 return ret;
248 err = tpm_xfer(dev, command, tpm_command_size(command),
249 response, &response_length);
c2b0f600 250
c8a8c510 251 if (err < 0)
8732b070 252 return TPM_LIB_ERROR;
be6c1529 253 if (size_ptr)
8732b070
CC
254 *size_ptr = response_length;
255
256 return tpm_return_code(response);
257}
258
c8a8c510 259int tpm_init(void)
8732b070 260{
c8a8c510 261 int err;
c8a8c510
SG
262 struct udevice *dev;
263
264 err = uclass_first_device(UCLASS_TPM, &dev);
265 if (err)
266 return err;
267 return tpm_open(dev);
8732b070
CC
268}
269
270uint32_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
286uint32_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
294uint32_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
302uint32_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
345uint32_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
379uint32_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
409uint32_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
440uint32_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
468uint32_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
484uint32_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
515uint32_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
524uint32_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
533uint32_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
542uint32_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
558uint32_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}
be6c1529 597
2132f971
SG
598uint32_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
620uint32_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
be6c1529
RP
648#ifdef CONFIG_TPM_AUTH_SESSIONS
649
650/**
651 * Fill an authentication block in a request.
652 * This func can create the first as well as the second auth block (for
653 * double authorized commands).
654 *
655 * @param request pointer to the request (w/ uninitialised auth data)
656 * @param request_len0 length of the request without auth data
657 * @param handles_len length of the handles area in request
658 * @param auth_session pointer to the (valid) auth session to be used
659 * @param request_auth pointer to the auth block of the request to be filled
660 * @param auth authentication data (HMAC key)
661 */
662static uint32_t create_request_auth(const void *request, size_t request_len0,
663 size_t handles_len,
664 struct session_data *auth_session,
665 void *request_auth, const void *auth)
666{
667 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
668 sha1_context hash_ctx;
669 const size_t command_code_offset = 6;
670 const size_t auth_nonce_odd_offset = 4;
671 const size_t auth_continue_offset = 24;
672 const size_t auth_auth_offset = 25;
673
674 if (!auth_session || !auth_session->valid)
675 return TPM_LIB_ERROR;
676
677 sha1_starts(&hash_ctx);
678 sha1_update(&hash_ctx, request + command_code_offset, 4);
679 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
680 sha1_update(&hash_ctx,
681 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
682 request_len0 - TPM_REQUEST_HEADER_LENGTH
683 - handles_len);
684 sha1_finish(&hash_ctx, hmac_data);
685
686 sha1_starts(&hash_ctx);
687 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
688 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
689 sha1_finish(&hash_ctx, auth_session->nonce_odd);
690
691 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
692 0, auth_session->handle,
693 auth_nonce_odd_offset, auth_session->nonce_odd,
694 DIGEST_LENGTH,
695 auth_continue_offset, 1))
696 return TPM_LIB_ERROR;
697 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
698 DIGEST_LENGTH,
699 auth_session->nonce_even,
700 DIGEST_LENGTH,
701 2 * DIGEST_LENGTH,
702 request_auth + auth_nonce_odd_offset,
703 DIGEST_LENGTH + 1))
704 return TPM_LIB_ERROR;
705 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
706 request_auth + auth_auth_offset);
707
708 return TPM_SUCCESS;
709}
710
711/**
712 * Verify an authentication block in a response.
713 * Since this func updates the nonce_even in the session data it has to be
714 * called when receiving a succesfull AUTH response.
715 * This func can verify the first as well as the second auth block (for
716 * double authorized commands).
717 *
718 * @param command_code command code of the request
719 * @param response pointer to the request (w/ uninitialised auth data)
720 * @param handles_len length of the handles area in response
721 * @param auth_session pointer to the (valid) auth session to be used
722 * @param response_auth pointer to the auth block of the response to be verified
723 * @param auth authentication data (HMAC key)
724 */
725static uint32_t verify_response_auth(uint32_t command_code,
726 const void *response, size_t response_len0,
727 size_t handles_len,
728 struct session_data *auth_session,
729 const void *response_auth, const void *auth)
730{
731 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
732 uint8_t computed_auth[DIGEST_LENGTH];
733 sha1_context hash_ctx;
734 const size_t return_code_offset = 6;
735 const size_t auth_continue_offset = 20;
736 const size_t auth_auth_offset = 21;
737 uint8_t auth_continue;
738
739 if (!auth_session || !auth_session->valid)
740 return TPM_AUTHFAIL;
741 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
742 0, command_code))
743 return TPM_LIB_ERROR;
744 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
745 return TPM_LIB_ERROR;
746
747 sha1_starts(&hash_ctx);
748 sha1_update(&hash_ctx, response + return_code_offset, 4);
749 sha1_update(&hash_ctx, hmac_data, 4);
750 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
751 sha1_update(&hash_ctx,
752 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
753 response_len0 - TPM_RESPONSE_HEADER_LENGTH
754 - handles_len);
755 sha1_finish(&hash_ctx, hmac_data);
756
757 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
758 auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
759 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
760 DIGEST_LENGTH,
761 response_auth,
762 DIGEST_LENGTH,
763 2 * DIGEST_LENGTH,
764 auth_session->nonce_odd,
765 DIGEST_LENGTH,
766 3 * DIGEST_LENGTH,
767 auth_continue))
768 return TPM_LIB_ERROR;
769
770 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
771 computed_auth);
772
773 if (memcmp(computed_auth, response_auth + auth_auth_offset,
774 DIGEST_LENGTH))
775 return TPM_AUTHFAIL;
776
777 return TPM_SUCCESS;
778}
779
780
781uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
782{
783 const uint8_t command[18] = {
784 0x00, 0xc1, /* TPM_TAG */
785 0x00, 0x00, 0x00, 0x00, /* parameter size */
786 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
787 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
788 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
789 };
790 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
791 uint8_t request[COMMAND_BUFFER_SIZE];
792
793 if (pack_byte_string(request, sizeof(request), "sd",
794 0, command, sizeof(command),
795 req_handle_offset, auth_handle))
796 return TPM_LIB_ERROR;
797 if (oiap_session.valid && oiap_session.handle == auth_handle)
798 oiap_session.valid = 0;
799
800 return tpm_sendrecv_command(request, NULL, NULL);
801}
802
803uint32_t tpm_end_oiap(void)
804{
805 uint32_t err = TPM_SUCCESS;
806 if (oiap_session.valid)
807 err = tpm_terminate_auth_session(oiap_session.handle);
808 return err;
809}
810
811uint32_t tpm_oiap(uint32_t *auth_handle)
812{
813 const uint8_t command[10] = {
814 0x00, 0xc1, /* TPM_TAG */
815 0x00, 0x00, 0x00, 0x0a, /* parameter size */
816 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
817 };
818 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
819 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
820 uint8_t response[COMMAND_BUFFER_SIZE];
821 size_t response_length = sizeof(response);
822 uint32_t err;
823
824 if (oiap_session.valid)
825 tpm_terminate_auth_session(oiap_session.handle);
826
827 err = tpm_sendrecv_command(command, response, &response_length);
828 if (err)
829 return err;
830 if (unpack_byte_string(response, response_length, "ds",
831 res_auth_handle_offset, &oiap_session.handle,
832 res_nonce_even_offset, &oiap_session.nonce_even,
833 (uint32_t)DIGEST_LENGTH))
834 return TPM_LIB_ERROR;
835 oiap_session.valid = 1;
836 if (auth_handle)
837 *auth_handle = oiap_session.handle;
838 return 0;
839}
840
841uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
842 const void *key, size_t key_length,
843 const void *parent_key_usage_auth,
844 uint32_t *key_handle)
845{
846 const uint8_t command[14] = {
847 0x00, 0xc2, /* TPM_TAG */
848 0x00, 0x00, 0x00, 0x00, /* parameter size */
849 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
850 0x00, 0x00, 0x00, 0x00, /* parent handle */
851 };
852 const size_t req_size_offset = 2;
853 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
854 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
855 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
856 uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
857 + TPM_REQUEST_AUTH_LENGTH];
858 uint8_t response[COMMAND_BUFFER_SIZE];
859 size_t response_length = sizeof(response);
860 uint32_t err;
861
862 if (!oiap_session.valid) {
863 err = tpm_oiap(NULL);
864 if (err)
865 return err;
866 }
867 if (pack_byte_string(request, sizeof(request), "sdds",
868 0, command, sizeof(command),
869 req_size_offset,
870 sizeof(command) + key_length
871 + TPM_REQUEST_AUTH_LENGTH,
872 req_parent_handle_offset, parent_handle,
873 req_key_offset, key, key_length
874 ))
875 return TPM_LIB_ERROR;
876
877 err = create_request_auth(request, sizeof(command) + key_length, 4,
878 &oiap_session,
879 request + sizeof(command) + key_length,
880 parent_key_usage_auth);
881 if (err)
882 return err;
883 err = tpm_sendrecv_command(request, response, &response_length);
884 if (err) {
885 if (err == TPM_AUTHFAIL)
886 oiap_session.valid = 0;
887 return err;
888 }
889
890 err = verify_response_auth(0x00000041, response,
891 response_length - TPM_RESPONSE_AUTH_LENGTH,
892 4, &oiap_session,
893 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
894 parent_key_usage_auth);
895 if (err)
896 return err;
897
898 if (key_handle) {
899 if (unpack_byte_string(response, response_length, "d",
900 res_handle_offset, key_handle))
901 return TPM_LIB_ERROR;
902 }
903
904 return 0;
905}
906
907uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
908 void *pubkey, size_t *pubkey_len)
909{
910 const uint8_t command[14] = {
911 0x00, 0xc2, /* TPM_TAG */
912 0x00, 0x00, 0x00, 0x00, /* parameter size */
913 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
914 0x00, 0x00, 0x00, 0x00, /* key handle */
915 };
916 const size_t req_size_offset = 2;
917 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
918 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
919 uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
920 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
921 + TPM_RESPONSE_AUTH_LENGTH];
922 size_t response_length = sizeof(response);
923 uint32_t err;
924
925 if (!oiap_session.valid) {
926 err = tpm_oiap(NULL);
927 if (err)
928 return err;
929 }
930 if (pack_byte_string(request, sizeof(request), "sdd",
931 0, command, sizeof(command),
932 req_size_offset,
933 (uint32_t)(sizeof(command)
934 + TPM_REQUEST_AUTH_LENGTH),
935 req_key_handle_offset, key_handle
936 ))
937 return TPM_LIB_ERROR;
938 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
939 request + sizeof(command), usage_auth);
940 if (err)
941 return err;
942 err = tpm_sendrecv_command(request, response, &response_length);
943 if (err) {
944 if (err == TPM_AUTHFAIL)
945 oiap_session.valid = 0;
946 return err;
947 }
948 err = verify_response_auth(0x00000021, response,
949 response_length - TPM_RESPONSE_AUTH_LENGTH,
950 0, &oiap_session,
951 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
952 usage_auth);
953 if (err)
954 return err;
955
956 if (pubkey) {
957 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
958 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
959 return TPM_LIB_ERROR;
960 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
961 - TPM_RESPONSE_AUTH_LENGTH;
962 memcpy(pubkey, response + res_pubkey_offset,
963 response_length - TPM_RESPONSE_HEADER_LENGTH
964 - TPM_RESPONSE_AUTH_LENGTH);
965 }
966
967 return 0;
968}
969
970#endif /* CONFIG_TPM_AUTH_SESSIONS */