blob: fb520e3d733ca4bfe813efd34827adaae283a2ec [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>
Che-liang Chiou8732b072013-02-28 09:34:57 +000010#include <tpm.h>
11#include <asm/unaligned.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060012#include <u-boot/sha1.h>
Che-liang Chiou8732b072013-02-28 09:34:57 +000013
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,
Che-liang Chiou8732b072013-02-28 09:34:57 +000020 TPM_REQUEST_HEADER_LENGTH = 10,
21 TPM_RESPONSE_HEADER_LENGTH = 10,
22 PCR_DIGEST_LENGTH = 20,
Reinhard Pfaube6c1522013-06-26 15:55:13 +020023 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,
Che-liang Chiou8732b072013-02-28 09:34:57 +000029};
30
Reinhard Pfaube6c1522013-06-26 15:55:13 +020031#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
Che-liang Chiou8732b072013-02-28 09:34:57 +000048/**
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{
Christophe Ricardc2b0f602015-10-06 22:54:43 +0200232 struct udevice *dev;
Tom Rini667d6852017-05-10 15:20:18 -0400233 int err, ret;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000234 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
235 size_t response_length;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000236
237 if (response) {
238 response_length = *size_ptr;
239 } else {
240 response = response_buffer;
241 response_length = sizeof(response_buffer);
242 }
Simon Glassc8a8c512015-08-22 18:31:32 -0600243
Simon Glass3f603cb2016-02-11 13:23:26 -0700244 ret = uclass_first_device_err(UCLASS_TPM, &dev);
Simon Glassc8a8c512015-08-22 18:31:32 -0600245 if (ret)
246 return ret;
247 err = tpm_xfer(dev, command, tpm_command_size(command),
248 response, &response_length);
Christophe Ricardc2b0f602015-10-06 22:54:43 +0200249
Simon Glassc8a8c512015-08-22 18:31:32 -0600250 if (err < 0)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000251 return TPM_LIB_ERROR;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200252 if (size_ptr)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000253 *size_ptr = response_length;
254
255 return tpm_return_code(response);
256}
257
Simon Glassc8a8c512015-08-22 18:31:32 -0600258int tpm_init(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000259{
Simon Glassc8a8c512015-08-22 18:31:32 -0600260 int err;
Simon Glassc8a8c512015-08-22 18:31:32 -0600261 struct udevice *dev;
262
Simon Glass3f603cb2016-02-11 13:23:26 -0700263 err = uclass_first_device_err(UCLASS_TPM, &dev);
264 if (err)
Simon Glassc8a8c512015-08-22 18:31:32 -0600265 return err;
266 return tpm_open(dev);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000267}
268
269uint32_t tpm_startup(enum tpm_startup_type mode)
270{
271 const uint8_t command[12] = {
272 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
273 };
274 const size_t mode_offset = 10;
275 uint8_t buf[COMMAND_BUFFER_SIZE];
276
277 if (pack_byte_string(buf, sizeof(buf), "sw",
278 0, command, sizeof(command),
279 mode_offset, mode))
280 return TPM_LIB_ERROR;
281
282 return tpm_sendrecv_command(buf, NULL, NULL);
283}
284
285uint32_t tpm_self_test_full(void)
286{
287 const uint8_t command[10] = {
288 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
289 };
290 return tpm_sendrecv_command(command, NULL, NULL);
291}
292
293uint32_t tpm_continue_self_test(void)
294{
295 const uint8_t command[10] = {
296 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
297 };
298 return tpm_sendrecv_command(command, NULL, NULL);
299}
300
301uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
302{
303 const uint8_t command[101] = {
304 0x0, 0xc1, /* TPM_TAG */
305 0x0, 0x0, 0x0, 0x65, /* parameter size */
306 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
307 /* TPM_NV_DATA_PUBLIC->... */
308 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
309 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
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_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
316 0x0, 0x3,
317 0, 0, 0,
318 0x1f,
319 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
320 /* TPM_NV_ATTRIBUTES->... */
321 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
322 0, 0, 0, 0, /* ...->attributes */
323 /* End of TPM_NV_ATTRIBUTES */
324 0, /* bReadSTClear */
325 0, /* bWriteSTClear */
326 0, /* bWriteDefine */
327 0, 0, 0, 0, /* size */
328 };
329 const size_t index_offset = 12;
330 const size_t perm_offset = 70;
331 const size_t size_offset = 77;
332 uint8_t buf[COMMAND_BUFFER_SIZE];
333
334 if (pack_byte_string(buf, sizeof(buf), "sddd",
335 0, command, sizeof(command),
336 index_offset, index,
337 perm_offset, perm,
338 size_offset, size))
339 return TPM_LIB_ERROR;
340
341 return tpm_sendrecv_command(buf, NULL, NULL);
342}
343
344uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
345{
346 const uint8_t command[22] = {
347 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
348 };
349 const size_t index_offset = 10;
350 const size_t length_offset = 18;
351 const size_t data_size_offset = 10;
352 const size_t data_offset = 14;
353 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
354 size_t response_length = sizeof(response);
355 uint32_t data_size;
356 uint32_t err;
357
358 if (pack_byte_string(buf, sizeof(buf), "sdd",
359 0, command, sizeof(command),
360 index_offset, index,
361 length_offset, count))
362 return TPM_LIB_ERROR;
363 err = tpm_sendrecv_command(buf, response, &response_length);
364 if (err)
365 return err;
366 if (unpack_byte_string(response, response_length, "d",
367 data_size_offset, &data_size))
368 return TPM_LIB_ERROR;
369 if (data_size > count)
370 return TPM_LIB_ERROR;
371 if (unpack_byte_string(response, response_length, "s",
372 data_offset, data, data_size))
373 return TPM_LIB_ERROR;
374
375 return 0;
376}
377
378uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
379{
380 const uint8_t command[256] = {
381 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
382 };
383 const size_t command_size_offset = 2;
384 const size_t index_offset = 10;
385 const size_t length_offset = 18;
386 const size_t data_offset = 22;
387 const size_t write_info_size = 12;
388 const uint32_t total_length =
389 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
390 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
391 size_t response_length = sizeof(response);
392 uint32_t err;
393
394 if (pack_byte_string(buf, sizeof(buf), "sddds",
395 0, command, sizeof(command),
396 command_size_offset, total_length,
397 index_offset, index,
398 length_offset, length,
399 data_offset, data, length))
400 return TPM_LIB_ERROR;
401 err = tpm_sendrecv_command(buf, response, &response_length);
402 if (err)
403 return err;
404
405 return 0;
406}
407
408uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
409{
410 const uint8_t command[34] = {
411 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
412 };
413 const size_t index_offset = 10;
414 const size_t in_digest_offset = 14;
415 const size_t out_digest_offset = 10;
416 uint8_t buf[COMMAND_BUFFER_SIZE];
417 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
418 size_t response_length = sizeof(response);
419 uint32_t err;
420
421 if (pack_byte_string(buf, sizeof(buf), "sds",
422 0, command, sizeof(command),
423 index_offset, index,
424 in_digest_offset, in_digest,
425 PCR_DIGEST_LENGTH))
426 return TPM_LIB_ERROR;
427 err = tpm_sendrecv_command(buf, response, &response_length);
428 if (err)
429 return err;
430
431 if (unpack_byte_string(response, response_length, "s",
432 out_digest_offset, out_digest,
433 PCR_DIGEST_LENGTH))
434 return TPM_LIB_ERROR;
435
436 return 0;
437}
438
439uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
440{
441 const uint8_t command[14] = {
442 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
443 };
444 const size_t index_offset = 10;
445 const size_t out_digest_offset = 10;
446 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
447 size_t response_length = sizeof(response);
448 uint32_t err;
449
450 if (count < PCR_DIGEST_LENGTH)
451 return TPM_LIB_ERROR;
452
453 if (pack_byte_string(buf, sizeof(buf), "sd",
454 0, command, sizeof(command),
455 index_offset, index))
456 return TPM_LIB_ERROR;
457 err = tpm_sendrecv_command(buf, response, &response_length);
458 if (err)
459 return err;
460 if (unpack_byte_string(response, response_length, "s",
461 out_digest_offset, data, PCR_DIGEST_LENGTH))
462 return TPM_LIB_ERROR;
463
464 return 0;
465}
466
467uint32_t tpm_tsc_physical_presence(uint16_t presence)
468{
469 const uint8_t command[12] = {
470 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
471 };
472 const size_t presence_offset = 10;
473 uint8_t buf[COMMAND_BUFFER_SIZE];
474
475 if (pack_byte_string(buf, sizeof(buf), "sw",
476 0, command, sizeof(command),
477 presence_offset, presence))
478 return TPM_LIB_ERROR;
479
480 return tpm_sendrecv_command(buf, NULL, NULL);
481}
482
483uint32_t tpm_read_pubek(void *data, size_t count)
484{
485 const uint8_t command[30] = {
486 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
487 };
488 const size_t response_size_offset = 2;
489 const size_t data_offset = 10;
490 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
491 uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
492 size_t response_length = sizeof(response);
493 uint32_t data_size;
494 uint32_t err;
495
496 err = tpm_sendrecv_command(command, response, &response_length);
497 if (err)
498 return err;
499 if (unpack_byte_string(response, response_length, "d",
500 response_size_offset, &data_size))
501 return TPM_LIB_ERROR;
502 if (data_size < header_and_checksum_size)
503 return TPM_LIB_ERROR;
504 data_size -= header_and_checksum_size;
505 if (data_size > count)
506 return TPM_LIB_ERROR;
507 if (unpack_byte_string(response, response_length, "s",
508 data_offset, data, data_size))
509 return TPM_LIB_ERROR;
510
511 return 0;
512}
513
514uint32_t tpm_force_clear(void)
515{
516 const uint8_t command[10] = {
517 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
518 };
519
520 return tpm_sendrecv_command(command, NULL, NULL);
521}
522
523uint32_t tpm_physical_enable(void)
524{
525 const uint8_t command[10] = {
526 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
527 };
528
529 return tpm_sendrecv_command(command, NULL, NULL);
530}
531
532uint32_t tpm_physical_disable(void)
533{
534 const uint8_t command[10] = {
535 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
536 };
537
538 return tpm_sendrecv_command(command, NULL, NULL);
539}
540
541uint32_t tpm_physical_set_deactivated(uint8_t state)
542{
543 const uint8_t command[11] = {
544 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
545 };
546 const size_t state_offset = 10;
547 uint8_t buf[COMMAND_BUFFER_SIZE];
548
549 if (pack_byte_string(buf, sizeof(buf), "sb",
550 0, command, sizeof(command),
551 state_offset, state))
552 return TPM_LIB_ERROR;
553
554 return tpm_sendrecv_command(buf, NULL, NULL);
555}
556
557uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
558 void *cap, size_t count)
559{
560 const uint8_t command[22] = {
561 0x0, 0xc1, /* TPM_TAG */
562 0x0, 0x0, 0x0, 0x16, /* parameter size */
563 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
564 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
565 0x0, 0x0, 0x0, 0x4, /* subcap size */
566 0x0, 0x0, 0x0, 0x0, /* subcap value */
567 };
568 const size_t cap_area_offset = 10;
569 const size_t sub_cap_offset = 18;
570 const size_t cap_offset = 14;
571 const size_t cap_size_offset = 10;
572 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
573 size_t response_length = sizeof(response);
574 uint32_t cap_size;
575 uint32_t err;
576
577 if (pack_byte_string(buf, sizeof(buf), "sdd",
578 0, command, sizeof(command),
579 cap_area_offset, cap_area,
580 sub_cap_offset, sub_cap))
581 return TPM_LIB_ERROR;
582 err = tpm_sendrecv_command(buf, response, &response_length);
583 if (err)
584 return err;
585 if (unpack_byte_string(response, response_length, "d",
586 cap_size_offset, &cap_size))
587 return TPM_LIB_ERROR;
588 if (cap_size > response_length || cap_size > count)
589 return TPM_LIB_ERROR;
590 if (unpack_byte_string(response, response_length, "s",
591 cap_offset, cap, cap_size))
592 return TPM_LIB_ERROR;
593
594 return 0;
595}
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200596
Simon Glass2132f972015-08-22 18:31:41 -0600597uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
598{
599 const uint8_t command[22] = {
600 0x0, 0xc1, /* TPM_TAG */
601 0x0, 0x0, 0x0, 0x16, /* parameter size */
602 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
603 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
604 0x0, 0x0, 0x0, 0x4, /* subcap size */
605 0x0, 0x0, 0x1, 0x8, /* subcap value */
606 };
607 uint8_t response[COMMAND_BUFFER_SIZE];
608 size_t response_length = sizeof(response);
609 uint32_t err;
610
611 err = tpm_sendrecv_command(command, response, &response_length);
612 if (err)
613 return err;
614 memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
615
616 return 0;
617}
618
619uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
620{
621 const uint8_t command[22] = {
622 0x0, 0xc1, /* TPM_TAG */
623 0x0, 0x0, 0x0, 0x16, /* parameter size */
624 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
625 0x0, 0x0, 0x0, 0x11,
626 0x0, 0x0, 0x0, 0x4,
627 };
628 const size_t index_offset = 18;
629 const size_t perm_offset = 60;
630 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
631 size_t response_length = sizeof(response);
632 uint32_t err;
633
634 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
635 index_offset, index))
636 return TPM_LIB_ERROR;
637 err = tpm_sendrecv_command(buf, response, &response_length);
638 if (err)
639 return err;
640 if (unpack_byte_string(response, response_length, "d",
641 perm_offset, perm))
642 return TPM_LIB_ERROR;
643
644 return 0;
645}
646
Mario Six7690be32017-01-11 16:00:50 +0100647#ifdef CONFIG_TPM_FLUSH_RESOURCES
648uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type)
649{
650 const uint8_t command[18] = {
651 0x00, 0xc1, /* TPM_TAG */
652 0x00, 0x00, 0x00, 0x12, /* parameter size */
653 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
654 0x00, 0x00, 0x00, 0x00, /* key handle */
655 0x00, 0x00, 0x00, 0x00, /* resource type */
656 };
657 const size_t key_handle_offset = 10;
658 const size_t resource_type_offset = 14;
659 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
660 size_t response_length = sizeof(response);
661 uint32_t err;
662
663 if (pack_byte_string(buf, sizeof(buf), "sdd",
664 0, command, sizeof(command),
665 key_handle_offset, key_handle,
666 resource_type_offset, resource_type))
667 return TPM_LIB_ERROR;
668
669 err = tpm_sendrecv_command(buf, response, &response_length);
670 if (err)
671 return err;
672 return 0;
673}
674#endif /* CONFIG_TPM_FLUSH_RESOURCES */
675
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200676#ifdef CONFIG_TPM_AUTH_SESSIONS
677
678/**
679 * Fill an authentication block in a request.
680 * This func can create the first as well as the second auth block (for
681 * double authorized commands).
682 *
683 * @param request pointer to the request (w/ uninitialised auth data)
684 * @param request_len0 length of the request without auth data
685 * @param handles_len length of the handles area in request
686 * @param auth_session pointer to the (valid) auth session to be used
687 * @param request_auth pointer to the auth block of the request to be filled
688 * @param auth authentication data (HMAC key)
689 */
690static uint32_t create_request_auth(const void *request, size_t request_len0,
691 size_t handles_len,
692 struct session_data *auth_session,
693 void *request_auth, const void *auth)
694{
695 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
696 sha1_context hash_ctx;
697 const size_t command_code_offset = 6;
698 const size_t auth_nonce_odd_offset = 4;
699 const size_t auth_continue_offset = 24;
700 const size_t auth_auth_offset = 25;
701
702 if (!auth_session || !auth_session->valid)
703 return TPM_LIB_ERROR;
704
705 sha1_starts(&hash_ctx);
706 sha1_update(&hash_ctx, request + command_code_offset, 4);
707 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
708 sha1_update(&hash_ctx,
709 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
710 request_len0 - TPM_REQUEST_HEADER_LENGTH
711 - handles_len);
712 sha1_finish(&hash_ctx, hmac_data);
713
714 sha1_starts(&hash_ctx);
715 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
716 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
717 sha1_finish(&hash_ctx, auth_session->nonce_odd);
718
719 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
720 0, auth_session->handle,
721 auth_nonce_odd_offset, auth_session->nonce_odd,
722 DIGEST_LENGTH,
723 auth_continue_offset, 1))
724 return TPM_LIB_ERROR;
725 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
726 DIGEST_LENGTH,
727 auth_session->nonce_even,
728 DIGEST_LENGTH,
729 2 * DIGEST_LENGTH,
730 request_auth + auth_nonce_odd_offset,
731 DIGEST_LENGTH + 1))
732 return TPM_LIB_ERROR;
733 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
734 request_auth + auth_auth_offset);
735
736 return TPM_SUCCESS;
737}
738
739/**
740 * Verify an authentication block in a response.
741 * Since this func updates the nonce_even in the session data it has to be
742 * called when receiving a succesfull AUTH response.
743 * This func can verify the first as well as the second auth block (for
744 * double authorized commands).
745 *
746 * @param command_code command code of the request
747 * @param response pointer to the request (w/ uninitialised auth data)
748 * @param handles_len length of the handles area in response
749 * @param auth_session pointer to the (valid) auth session to be used
750 * @param response_auth pointer to the auth block of the response to be verified
751 * @param auth authentication data (HMAC key)
752 */
753static uint32_t verify_response_auth(uint32_t command_code,
754 const void *response, size_t response_len0,
755 size_t handles_len,
756 struct session_data *auth_session,
757 const void *response_auth, const void *auth)
758{
759 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
760 uint8_t computed_auth[DIGEST_LENGTH];
761 sha1_context hash_ctx;
762 const size_t return_code_offset = 6;
763 const size_t auth_continue_offset = 20;
764 const size_t auth_auth_offset = 21;
765 uint8_t auth_continue;
766
767 if (!auth_session || !auth_session->valid)
768 return TPM_AUTHFAIL;
769 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
770 0, command_code))
771 return TPM_LIB_ERROR;
772 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
773 return TPM_LIB_ERROR;
774
775 sha1_starts(&hash_ctx);
776 sha1_update(&hash_ctx, response + return_code_offset, 4);
777 sha1_update(&hash_ctx, hmac_data, 4);
778 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
779 sha1_update(&hash_ctx,
780 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
781 response_len0 - TPM_RESPONSE_HEADER_LENGTH
782 - handles_len);
783 sha1_finish(&hash_ctx, hmac_data);
784
785 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
786 auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
787 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
788 DIGEST_LENGTH,
789 response_auth,
790 DIGEST_LENGTH,
791 2 * DIGEST_LENGTH,
792 auth_session->nonce_odd,
793 DIGEST_LENGTH,
794 3 * DIGEST_LENGTH,
795 auth_continue))
796 return TPM_LIB_ERROR;
797
798 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
799 computed_auth);
800
801 if (memcmp(computed_auth, response_auth + auth_auth_offset,
802 DIGEST_LENGTH))
803 return TPM_AUTHFAIL;
804
805 return TPM_SUCCESS;
806}
807
808
809uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
810{
811 const uint8_t command[18] = {
812 0x00, 0xc1, /* TPM_TAG */
813 0x00, 0x00, 0x00, 0x00, /* parameter size */
814 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
815 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
816 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
817 };
818 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
819 uint8_t request[COMMAND_BUFFER_SIZE];
820
821 if (pack_byte_string(request, sizeof(request), "sd",
822 0, command, sizeof(command),
823 req_handle_offset, auth_handle))
824 return TPM_LIB_ERROR;
825 if (oiap_session.valid && oiap_session.handle == auth_handle)
826 oiap_session.valid = 0;
827
828 return tpm_sendrecv_command(request, NULL, NULL);
829}
830
831uint32_t tpm_end_oiap(void)
832{
833 uint32_t err = TPM_SUCCESS;
834 if (oiap_session.valid)
835 err = tpm_terminate_auth_session(oiap_session.handle);
836 return err;
837}
838
839uint32_t tpm_oiap(uint32_t *auth_handle)
840{
841 const uint8_t command[10] = {
842 0x00, 0xc1, /* TPM_TAG */
843 0x00, 0x00, 0x00, 0x0a, /* parameter size */
844 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
845 };
846 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
847 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
848 uint8_t response[COMMAND_BUFFER_SIZE];
849 size_t response_length = sizeof(response);
850 uint32_t err;
851
852 if (oiap_session.valid)
853 tpm_terminate_auth_session(oiap_session.handle);
854
855 err = tpm_sendrecv_command(command, response, &response_length);
856 if (err)
857 return err;
858 if (unpack_byte_string(response, response_length, "ds",
859 res_auth_handle_offset, &oiap_session.handle,
860 res_nonce_even_offset, &oiap_session.nonce_even,
861 (uint32_t)DIGEST_LENGTH))
862 return TPM_LIB_ERROR;
863 oiap_session.valid = 1;
864 if (auth_handle)
865 *auth_handle = oiap_session.handle;
866 return 0;
867}
868
869uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
870 const void *key, size_t key_length,
871 const void *parent_key_usage_auth,
872 uint32_t *key_handle)
873{
874 const uint8_t command[14] = {
875 0x00, 0xc2, /* TPM_TAG */
876 0x00, 0x00, 0x00, 0x00, /* parameter size */
877 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
878 0x00, 0x00, 0x00, 0x00, /* parent handle */
879 };
880 const size_t req_size_offset = 2;
881 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
882 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
883 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
884 uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
885 + TPM_REQUEST_AUTH_LENGTH];
886 uint8_t response[COMMAND_BUFFER_SIZE];
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), "sdds",
896 0, command, sizeof(command),
897 req_size_offset,
898 sizeof(command) + key_length
899 + TPM_REQUEST_AUTH_LENGTH,
900 req_parent_handle_offset, parent_handle,
901 req_key_offset, key, key_length
902 ))
903 return TPM_LIB_ERROR;
904
905 err = create_request_auth(request, sizeof(command) + key_length, 4,
906 &oiap_session,
907 request + sizeof(command) + key_length,
908 parent_key_usage_auth);
909 if (err)
910 return err;
911 err = tpm_sendrecv_command(request, response, &response_length);
912 if (err) {
913 if (err == TPM_AUTHFAIL)
914 oiap_session.valid = 0;
915 return err;
916 }
917
918 err = verify_response_auth(0x00000041, response,
919 response_length - TPM_RESPONSE_AUTH_LENGTH,
920 4, &oiap_session,
921 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
922 parent_key_usage_auth);
923 if (err)
924 return err;
925
926 if (key_handle) {
927 if (unpack_byte_string(response, response_length, "d",
928 res_handle_offset, key_handle))
929 return TPM_LIB_ERROR;
930 }
931
932 return 0;
933}
934
935uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
936 void *pubkey, size_t *pubkey_len)
937{
938 const uint8_t command[14] = {
939 0x00, 0xc2, /* TPM_TAG */
940 0x00, 0x00, 0x00, 0x00, /* parameter size */
941 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
942 0x00, 0x00, 0x00, 0x00, /* key handle */
943 };
944 const size_t req_size_offset = 2;
945 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
946 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
947 uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
948 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
949 + TPM_RESPONSE_AUTH_LENGTH];
950 size_t response_length = sizeof(response);
951 uint32_t err;
952
953 if (!oiap_session.valid) {
954 err = tpm_oiap(NULL);
955 if (err)
956 return err;
957 }
958 if (pack_byte_string(request, sizeof(request), "sdd",
959 0, command, sizeof(command),
960 req_size_offset,
961 (uint32_t)(sizeof(command)
962 + TPM_REQUEST_AUTH_LENGTH),
963 req_key_handle_offset, key_handle
964 ))
965 return TPM_LIB_ERROR;
966 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
967 request + sizeof(command), usage_auth);
968 if (err)
969 return err;
970 err = tpm_sendrecv_command(request, response, &response_length);
971 if (err) {
972 if (err == TPM_AUTHFAIL)
973 oiap_session.valid = 0;
974 return err;
975 }
976 err = verify_response_auth(0x00000021, response,
977 response_length - TPM_RESPONSE_AUTH_LENGTH,
978 0, &oiap_session,
979 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
980 usage_auth);
981 if (err)
982 return err;
983
984 if (pubkey) {
985 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
986 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
987 return TPM_LIB_ERROR;
988 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
989 - TPM_RESPONSE_AUTH_LENGTH;
990 memcpy(pubkey, response + res_pubkey_offset,
991 response_length - TPM_RESPONSE_HEADER_LENGTH
992 - TPM_RESPONSE_AUTH_LENGTH);
993 }
994
995 return 0;
996}
997
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100998#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
999uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t
1000 pubkey_digest[20], uint32_t *handle)
1001{
1002 uint16_t key_count;
1003 uint32_t key_handles[10];
1004 uint8_t buf[288];
1005 uint8_t *ptr;
1006 uint32_t err;
1007 uint8_t digest[20];
1008 size_t buf_len;
1009 unsigned int i;
1010
1011 /* fetch list of already loaded keys in the TPM */
1012 err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
1013 if (err)
1014 return -1;
1015 key_count = get_unaligned_be16(buf);
1016 ptr = buf + 2;
1017 for (i = 0; i < key_count; ++i, ptr += 4)
1018 key_handles[i] = get_unaligned_be32(ptr);
1019
1020 /* now search a(/ the) key which we can access with the given auth */
1021 for (i = 0; i < key_count; ++i) {
1022 buf_len = sizeof(buf);
1023 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
1024 if (err && err != TPM_AUTHFAIL)
1025 return -1;
1026 if (err)
1027 continue;
1028 sha1_csum(buf, buf_len, digest);
1029 if (!memcmp(digest, pubkey_digest, 20)) {
1030 *handle = key_handles[i];
1031 return 0;
1032 }
1033 }
1034 return 1;
1035}
1036#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
1037
Reinhard Pfaube6c1522013-06-26 15:55:13 +02001038#endif /* CONFIG_TPM_AUTH_SESSIONS */