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