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