]> git.ipfire.org Git - people/ms/u-boot.git/blob - lib/tpm.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[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 <stdarg.h>
10 #include <sha1.h>
11 #include <tpm.h>
12 #include <asm/unaligned.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_PUBEK_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 err = tis_sendrecv(command, tpm_command_size(command),
244 response, &response_length);
245 if (err)
246 return TPM_LIB_ERROR;
247 if (size_ptr)
248 *size_ptr = response_length;
249
250 return tpm_return_code(response);
251 }
252
253 uint32_t tpm_init(void)
254 {
255 uint32_t err;
256
257 err = tis_init();
258 if (err)
259 return err;
260
261 return tis_open();
262 }
263
264 uint32_t tpm_startup(enum tpm_startup_type mode)
265 {
266 const uint8_t command[12] = {
267 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
268 };
269 const size_t mode_offset = 10;
270 uint8_t buf[COMMAND_BUFFER_SIZE];
271
272 if (pack_byte_string(buf, sizeof(buf), "sw",
273 0, command, sizeof(command),
274 mode_offset, mode))
275 return TPM_LIB_ERROR;
276
277 return tpm_sendrecv_command(buf, NULL, NULL);
278 }
279
280 uint32_t tpm_self_test_full(void)
281 {
282 const uint8_t command[10] = {
283 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
284 };
285 return tpm_sendrecv_command(command, NULL, NULL);
286 }
287
288 uint32_t tpm_continue_self_test(void)
289 {
290 const uint8_t command[10] = {
291 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
292 };
293 return tpm_sendrecv_command(command, NULL, NULL);
294 }
295
296 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
297 {
298 const uint8_t command[101] = {
299 0x0, 0xc1, /* TPM_TAG */
300 0x0, 0x0, 0x0, 0x65, /* parameter size */
301 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
302 /* TPM_NV_DATA_PUBLIC->... */
303 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
304 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
305 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
306 0x0, 0x3,
307 0, 0, 0,
308 0x1f,
309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
311 0x0, 0x3,
312 0, 0, 0,
313 0x1f,
314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
315 /* TPM_NV_ATTRIBUTES->... */
316 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
317 0, 0, 0, 0, /* ...->attributes */
318 /* End of TPM_NV_ATTRIBUTES */
319 0, /* bReadSTClear */
320 0, /* bWriteSTClear */
321 0, /* bWriteDefine */
322 0, 0, 0, 0, /* size */
323 };
324 const size_t index_offset = 12;
325 const size_t perm_offset = 70;
326 const size_t size_offset = 77;
327 uint8_t buf[COMMAND_BUFFER_SIZE];
328
329 if (pack_byte_string(buf, sizeof(buf), "sddd",
330 0, command, sizeof(command),
331 index_offset, index,
332 perm_offset, perm,
333 size_offset, size))
334 return TPM_LIB_ERROR;
335
336 return tpm_sendrecv_command(buf, NULL, NULL);
337 }
338
339 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
340 {
341 const uint8_t command[22] = {
342 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
343 };
344 const size_t index_offset = 10;
345 const size_t length_offset = 18;
346 const size_t data_size_offset = 10;
347 const size_t data_offset = 14;
348 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
349 size_t response_length = sizeof(response);
350 uint32_t data_size;
351 uint32_t err;
352
353 if (pack_byte_string(buf, sizeof(buf), "sdd",
354 0, command, sizeof(command),
355 index_offset, index,
356 length_offset, count))
357 return TPM_LIB_ERROR;
358 err = tpm_sendrecv_command(buf, response, &response_length);
359 if (err)
360 return err;
361 if (unpack_byte_string(response, response_length, "d",
362 data_size_offset, &data_size))
363 return TPM_LIB_ERROR;
364 if (data_size > count)
365 return TPM_LIB_ERROR;
366 if (unpack_byte_string(response, response_length, "s",
367 data_offset, data, data_size))
368 return TPM_LIB_ERROR;
369
370 return 0;
371 }
372
373 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
374 {
375 const uint8_t command[256] = {
376 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
377 };
378 const size_t command_size_offset = 2;
379 const size_t index_offset = 10;
380 const size_t length_offset = 18;
381 const size_t data_offset = 22;
382 const size_t write_info_size = 12;
383 const uint32_t total_length =
384 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
385 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
386 size_t response_length = sizeof(response);
387 uint32_t err;
388
389 if (pack_byte_string(buf, sizeof(buf), "sddds",
390 0, command, sizeof(command),
391 command_size_offset, total_length,
392 index_offset, index,
393 length_offset, length,
394 data_offset, data, length))
395 return TPM_LIB_ERROR;
396 err = tpm_sendrecv_command(buf, response, &response_length);
397 if (err)
398 return err;
399
400 return 0;
401 }
402
403 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
404 {
405 const uint8_t command[34] = {
406 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
407 };
408 const size_t index_offset = 10;
409 const size_t in_digest_offset = 14;
410 const size_t out_digest_offset = 10;
411 uint8_t buf[COMMAND_BUFFER_SIZE];
412 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
413 size_t response_length = sizeof(response);
414 uint32_t err;
415
416 if (pack_byte_string(buf, sizeof(buf), "sds",
417 0, command, sizeof(command),
418 index_offset, index,
419 in_digest_offset, in_digest,
420 PCR_DIGEST_LENGTH))
421 return TPM_LIB_ERROR;
422 err = tpm_sendrecv_command(buf, response, &response_length);
423 if (err)
424 return err;
425
426 if (unpack_byte_string(response, response_length, "s",
427 out_digest_offset, out_digest,
428 PCR_DIGEST_LENGTH))
429 return TPM_LIB_ERROR;
430
431 return 0;
432 }
433
434 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
435 {
436 const uint8_t command[14] = {
437 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
438 };
439 const size_t index_offset = 10;
440 const size_t out_digest_offset = 10;
441 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
442 size_t response_length = sizeof(response);
443 uint32_t err;
444
445 if (count < PCR_DIGEST_LENGTH)
446 return TPM_LIB_ERROR;
447
448 if (pack_byte_string(buf, sizeof(buf), "sd",
449 0, command, sizeof(command),
450 index_offset, index))
451 return TPM_LIB_ERROR;
452 err = tpm_sendrecv_command(buf, response, &response_length);
453 if (err)
454 return err;
455 if (unpack_byte_string(response, response_length, "s",
456 out_digest_offset, data, PCR_DIGEST_LENGTH))
457 return TPM_LIB_ERROR;
458
459 return 0;
460 }
461
462 uint32_t tpm_tsc_physical_presence(uint16_t presence)
463 {
464 const uint8_t command[12] = {
465 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
466 };
467 const size_t presence_offset = 10;
468 uint8_t buf[COMMAND_BUFFER_SIZE];
469
470 if (pack_byte_string(buf, sizeof(buf), "sw",
471 0, command, sizeof(command),
472 presence_offset, presence))
473 return TPM_LIB_ERROR;
474
475 return tpm_sendrecv_command(buf, NULL, NULL);
476 }
477
478 uint32_t tpm_read_pubek(void *data, size_t count)
479 {
480 const uint8_t command[30] = {
481 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
482 };
483 const size_t response_size_offset = 2;
484 const size_t data_offset = 10;
485 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
486 uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
487 size_t response_length = sizeof(response);
488 uint32_t data_size;
489 uint32_t err;
490
491 err = tpm_sendrecv_command(command, response, &response_length);
492 if (err)
493 return err;
494 if (unpack_byte_string(response, response_length, "d",
495 response_size_offset, &data_size))
496 return TPM_LIB_ERROR;
497 if (data_size < header_and_checksum_size)
498 return TPM_LIB_ERROR;
499 data_size -= header_and_checksum_size;
500 if (data_size > count)
501 return TPM_LIB_ERROR;
502 if (unpack_byte_string(response, response_length, "s",
503 data_offset, data, data_size))
504 return TPM_LIB_ERROR;
505
506 return 0;
507 }
508
509 uint32_t tpm_force_clear(void)
510 {
511 const uint8_t command[10] = {
512 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
513 };
514
515 return tpm_sendrecv_command(command, NULL, NULL);
516 }
517
518 uint32_t tpm_physical_enable(void)
519 {
520 const uint8_t command[10] = {
521 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
522 };
523
524 return tpm_sendrecv_command(command, NULL, NULL);
525 }
526
527 uint32_t tpm_physical_disable(void)
528 {
529 const uint8_t command[10] = {
530 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
531 };
532
533 return tpm_sendrecv_command(command, NULL, NULL);
534 }
535
536 uint32_t tpm_physical_set_deactivated(uint8_t state)
537 {
538 const uint8_t command[11] = {
539 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
540 };
541 const size_t state_offset = 10;
542 uint8_t buf[COMMAND_BUFFER_SIZE];
543
544 if (pack_byte_string(buf, sizeof(buf), "sb",
545 0, command, sizeof(command),
546 state_offset, state))
547 return TPM_LIB_ERROR;
548
549 return tpm_sendrecv_command(buf, NULL, NULL);
550 }
551
552 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
553 void *cap, size_t count)
554 {
555 const uint8_t command[22] = {
556 0x0, 0xc1, /* TPM_TAG */
557 0x0, 0x0, 0x0, 0x16, /* parameter size */
558 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
559 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
560 0x0, 0x0, 0x0, 0x4, /* subcap size */
561 0x0, 0x0, 0x0, 0x0, /* subcap value */
562 };
563 const size_t cap_area_offset = 10;
564 const size_t sub_cap_offset = 18;
565 const size_t cap_offset = 14;
566 const size_t cap_size_offset = 10;
567 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
568 size_t response_length = sizeof(response);
569 uint32_t cap_size;
570 uint32_t err;
571
572 if (pack_byte_string(buf, sizeof(buf), "sdd",
573 0, command, sizeof(command),
574 cap_area_offset, cap_area,
575 sub_cap_offset, sub_cap))
576 return TPM_LIB_ERROR;
577 err = tpm_sendrecv_command(buf, response, &response_length);
578 if (err)
579 return err;
580 if (unpack_byte_string(response, response_length, "d",
581 cap_size_offset, &cap_size))
582 return TPM_LIB_ERROR;
583 if (cap_size > response_length || cap_size > count)
584 return TPM_LIB_ERROR;
585 if (unpack_byte_string(response, response_length, "s",
586 cap_offset, cap, cap_size))
587 return TPM_LIB_ERROR;
588
589 return 0;
590 }
591
592 #ifdef CONFIG_TPM_AUTH_SESSIONS
593
594 /**
595 * Fill an authentication block in a request.
596 * This func can create the first as well as the second auth block (for
597 * double authorized commands).
598 *
599 * @param request pointer to the request (w/ uninitialised auth data)
600 * @param request_len0 length of the request without auth data
601 * @param handles_len length of the handles area in request
602 * @param auth_session pointer to the (valid) auth session to be used
603 * @param request_auth pointer to the auth block of the request to be filled
604 * @param auth authentication data (HMAC key)
605 */
606 static uint32_t create_request_auth(const void *request, size_t request_len0,
607 size_t handles_len,
608 struct session_data *auth_session,
609 void *request_auth, const void *auth)
610 {
611 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
612 sha1_context hash_ctx;
613 const size_t command_code_offset = 6;
614 const size_t auth_nonce_odd_offset = 4;
615 const size_t auth_continue_offset = 24;
616 const size_t auth_auth_offset = 25;
617
618 if (!auth_session || !auth_session->valid)
619 return TPM_LIB_ERROR;
620
621 sha1_starts(&hash_ctx);
622 sha1_update(&hash_ctx, request + command_code_offset, 4);
623 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
624 sha1_update(&hash_ctx,
625 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
626 request_len0 - TPM_REQUEST_HEADER_LENGTH
627 - handles_len);
628 sha1_finish(&hash_ctx, hmac_data);
629
630 sha1_starts(&hash_ctx);
631 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
632 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
633 sha1_finish(&hash_ctx, auth_session->nonce_odd);
634
635 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
636 0, auth_session->handle,
637 auth_nonce_odd_offset, auth_session->nonce_odd,
638 DIGEST_LENGTH,
639 auth_continue_offset, 1))
640 return TPM_LIB_ERROR;
641 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
642 DIGEST_LENGTH,
643 auth_session->nonce_even,
644 DIGEST_LENGTH,
645 2 * DIGEST_LENGTH,
646 request_auth + auth_nonce_odd_offset,
647 DIGEST_LENGTH + 1))
648 return TPM_LIB_ERROR;
649 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
650 request_auth + auth_auth_offset);
651
652 return TPM_SUCCESS;
653 }
654
655 /**
656 * Verify an authentication block in a response.
657 * Since this func updates the nonce_even in the session data it has to be
658 * called when receiving a succesfull AUTH response.
659 * This func can verify the first as well as the second auth block (for
660 * double authorized commands).
661 *
662 * @param command_code command code of the request
663 * @param response pointer to the request (w/ uninitialised auth data)
664 * @param handles_len length of the handles area in response
665 * @param auth_session pointer to the (valid) auth session to be used
666 * @param response_auth pointer to the auth block of the response to be verified
667 * @param auth authentication data (HMAC key)
668 */
669 static uint32_t verify_response_auth(uint32_t command_code,
670 const void *response, size_t response_len0,
671 size_t handles_len,
672 struct session_data *auth_session,
673 const void *response_auth, const void *auth)
674 {
675 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
676 uint8_t computed_auth[DIGEST_LENGTH];
677 sha1_context hash_ctx;
678 const size_t return_code_offset = 6;
679 const size_t auth_continue_offset = 20;
680 const size_t auth_auth_offset = 21;
681 uint8_t auth_continue;
682
683 if (!auth_session || !auth_session->valid)
684 return TPM_AUTHFAIL;
685 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
686 0, command_code))
687 return TPM_LIB_ERROR;
688 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
689 return TPM_LIB_ERROR;
690
691 sha1_starts(&hash_ctx);
692 sha1_update(&hash_ctx, response + return_code_offset, 4);
693 sha1_update(&hash_ctx, hmac_data, 4);
694 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
695 sha1_update(&hash_ctx,
696 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
697 response_len0 - TPM_RESPONSE_HEADER_LENGTH
698 - handles_len);
699 sha1_finish(&hash_ctx, hmac_data);
700
701 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
702 auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
703 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
704 DIGEST_LENGTH,
705 response_auth,
706 DIGEST_LENGTH,
707 2 * DIGEST_LENGTH,
708 auth_session->nonce_odd,
709 DIGEST_LENGTH,
710 3 * DIGEST_LENGTH,
711 auth_continue))
712 return TPM_LIB_ERROR;
713
714 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
715 computed_auth);
716
717 if (memcmp(computed_auth, response_auth + auth_auth_offset,
718 DIGEST_LENGTH))
719 return TPM_AUTHFAIL;
720
721 return TPM_SUCCESS;
722 }
723
724
725 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
726 {
727 const uint8_t command[18] = {
728 0x00, 0xc1, /* TPM_TAG */
729 0x00, 0x00, 0x00, 0x00, /* parameter size */
730 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
731 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
732 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
733 };
734 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
735 uint8_t request[COMMAND_BUFFER_SIZE];
736
737 if (pack_byte_string(request, sizeof(request), "sd",
738 0, command, sizeof(command),
739 req_handle_offset, auth_handle))
740 return TPM_LIB_ERROR;
741 if (oiap_session.valid && oiap_session.handle == auth_handle)
742 oiap_session.valid = 0;
743
744 return tpm_sendrecv_command(request, NULL, NULL);
745 }
746
747 uint32_t tpm_end_oiap(void)
748 {
749 uint32_t err = TPM_SUCCESS;
750 if (oiap_session.valid)
751 err = tpm_terminate_auth_session(oiap_session.handle);
752 return err;
753 }
754
755 uint32_t tpm_oiap(uint32_t *auth_handle)
756 {
757 const uint8_t command[10] = {
758 0x00, 0xc1, /* TPM_TAG */
759 0x00, 0x00, 0x00, 0x0a, /* parameter size */
760 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
761 };
762 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
763 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
764 uint8_t response[COMMAND_BUFFER_SIZE];
765 size_t response_length = sizeof(response);
766 uint32_t err;
767
768 if (oiap_session.valid)
769 tpm_terminate_auth_session(oiap_session.handle);
770
771 err = tpm_sendrecv_command(command, response, &response_length);
772 if (err)
773 return err;
774 if (unpack_byte_string(response, response_length, "ds",
775 res_auth_handle_offset, &oiap_session.handle,
776 res_nonce_even_offset, &oiap_session.nonce_even,
777 (uint32_t)DIGEST_LENGTH))
778 return TPM_LIB_ERROR;
779 oiap_session.valid = 1;
780 if (auth_handle)
781 *auth_handle = oiap_session.handle;
782 return 0;
783 }
784
785 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
786 const void *key, size_t key_length,
787 const void *parent_key_usage_auth,
788 uint32_t *key_handle)
789 {
790 const uint8_t command[14] = {
791 0x00, 0xc2, /* TPM_TAG */
792 0x00, 0x00, 0x00, 0x00, /* parameter size */
793 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
794 0x00, 0x00, 0x00, 0x00, /* parent handle */
795 };
796 const size_t req_size_offset = 2;
797 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
798 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
799 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
800 uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
801 + TPM_REQUEST_AUTH_LENGTH];
802 uint8_t response[COMMAND_BUFFER_SIZE];
803 size_t response_length = sizeof(response);
804 uint32_t err;
805
806 if (!oiap_session.valid) {
807 err = tpm_oiap(NULL);
808 if (err)
809 return err;
810 }
811 if (pack_byte_string(request, sizeof(request), "sdds",
812 0, command, sizeof(command),
813 req_size_offset,
814 sizeof(command) + key_length
815 + TPM_REQUEST_AUTH_LENGTH,
816 req_parent_handle_offset, parent_handle,
817 req_key_offset, key, key_length
818 ))
819 return TPM_LIB_ERROR;
820
821 err = create_request_auth(request, sizeof(command) + key_length, 4,
822 &oiap_session,
823 request + sizeof(command) + key_length,
824 parent_key_usage_auth);
825 if (err)
826 return err;
827 err = tpm_sendrecv_command(request, response, &response_length);
828 if (err) {
829 if (err == TPM_AUTHFAIL)
830 oiap_session.valid = 0;
831 return err;
832 }
833
834 err = verify_response_auth(0x00000041, response,
835 response_length - TPM_RESPONSE_AUTH_LENGTH,
836 4, &oiap_session,
837 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
838 parent_key_usage_auth);
839 if (err)
840 return err;
841
842 if (key_handle) {
843 if (unpack_byte_string(response, response_length, "d",
844 res_handle_offset, key_handle))
845 return TPM_LIB_ERROR;
846 }
847
848 return 0;
849 }
850
851 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
852 void *pubkey, size_t *pubkey_len)
853 {
854 const uint8_t command[14] = {
855 0x00, 0xc2, /* TPM_TAG */
856 0x00, 0x00, 0x00, 0x00, /* parameter size */
857 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
858 0x00, 0x00, 0x00, 0x00, /* key handle */
859 };
860 const size_t req_size_offset = 2;
861 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
862 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
863 uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
864 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
865 + TPM_RESPONSE_AUTH_LENGTH];
866 size_t response_length = sizeof(response);
867 uint32_t err;
868
869 if (!oiap_session.valid) {
870 err = tpm_oiap(NULL);
871 if (err)
872 return err;
873 }
874 if (pack_byte_string(request, sizeof(request), "sdd",
875 0, command, sizeof(command),
876 req_size_offset,
877 (uint32_t)(sizeof(command)
878 + TPM_REQUEST_AUTH_LENGTH),
879 req_key_handle_offset, key_handle
880 ))
881 return TPM_LIB_ERROR;
882 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
883 request + sizeof(command), usage_auth);
884 if (err)
885 return err;
886 err = tpm_sendrecv_command(request, response, &response_length);
887 if (err) {
888 if (err == TPM_AUTHFAIL)
889 oiap_session.valid = 0;
890 return err;
891 }
892 err = verify_response_auth(0x00000021, response,
893 response_length - TPM_RESPONSE_AUTH_LENGTH,
894 0, &oiap_session,
895 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
896 usage_auth);
897 if (err)
898 return err;
899
900 if (pubkey) {
901 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
902 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
903 return TPM_LIB_ERROR;
904 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
905 - TPM_RESPONSE_AUTH_LENGTH;
906 memcpy(pubkey, response + res_pubkey_offset,
907 response_length - TPM_RESPONSE_HEADER_LENGTH
908 - TPM_RESPONSE_AUTH_LENGTH);
909 }
910
911 return 0;
912 }
913
914 #endif /* CONFIG_TPM_AUTH_SESSIONS */