]> git.ipfire.org Git - thirdparty/u-boot.git/blame - lib/tpm.c
tpm: fix spelling
[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",
c6179187
MR
283 0, command, sizeof(command),
284 mode_offset, mode))
8732b070
CC
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",
c6179187
MR
340 0, command, sizeof(command),
341 index_offset, index,
342 perm_offset, perm,
343 size_offset, size))
8732b070
CC
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",
c6179187
MR
364 0, command, sizeof(command),
365 index_offset, index,
366 length_offset, count))
8732b070
CC
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",
c6179187 372 data_size_offset, &data_size))
8732b070
CC
373 return TPM_LIB_ERROR;
374 if (data_size > count)
375 return TPM_LIB_ERROR;
376 if (unpack_byte_string(response, response_length, "s",
c6179187 377 data_offset, data, data_size))
8732b070
CC
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",
c6179187
MR
400 0, command, sizeof(command),
401 command_size_offset, total_length,
402 index_offset, index,
403 length_offset, length,
404 data_offset, data, length))
8732b070
CC
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",
c6179187
MR
427 0, command, sizeof(command),
428 index_offset, index,
429 in_digest_offset, in_digest,
430 PCR_DIGEST_LENGTH))
8732b070
CC
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",
c6179187
MR
437 out_digest_offset, out_digest,
438 PCR_DIGEST_LENGTH))
8732b070
CC
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",
c6179187
MR
459 0, command, sizeof(command),
460 index_offset, index))
8732b070
CC
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",
c6179187 466 out_digest_offset, data, PCR_DIGEST_LENGTH))
8732b070
CC
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",
c6179187
MR
481 0, command, sizeof(command),
482 presence_offset, presence))
8732b070
CC
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",
c6179187 505 response_size_offset, &data_size))
8732b070
CC
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",
c6179187 513 data_offset, data, data_size))
8732b070
CC
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",
c6179187
MR
555 0, command, sizeof(command),
556 state_offset, state))
8732b070
CC
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",
c6179187
MR
582 0, command, sizeof(command),
583 cap_area_offset, cap_area,
584 sub_cap_offset, sub_cap))
8732b070
CC
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",
c6179187 590 cap_size_offset, &cap_size))
8732b070
CC
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",
c6179187 595 cap_offset, cap, cap_size))
8732b070
CC
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 */
52da18a3 828 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
be6c1529
RP
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,
c6179187
MR
916 &oiap_session,
917 request + sizeof(command) + key_length,
918 parent_key_usage_auth);
be6c1529
RP
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,
c6179187
MR
929 response_length - TPM_RESPONSE_AUTH_LENGTH,
930 4, &oiap_session,
931 response + response_length -
932 TPM_RESPONSE_AUTH_LENGTH,
933 parent_key_usage_auth);
be6c1529
RP
934 if (err)
935 return err;
936
937 if (key_handle) {
938 if (unpack_byte_string(response, response_length, "d",
939 res_handle_offset, key_handle))
940 return TPM_LIB_ERROR;
941 }
942
943 return 0;
944}
945
b9804e5b
MR
946u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey,
947 size_t *pubkey_len)
be6c1529 948{
b9804e5b 949 const u8 command[14] = {
be6c1529
RP
950 0x00, 0xc2, /* TPM_TAG */
951 0x00, 0x00, 0x00, 0x00, /* parameter size */
952 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
953 0x00, 0x00, 0x00, 0x00, /* key handle */
954 };
955 const size_t req_size_offset = 2;
956 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
957 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
b9804e5b
MR
958 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
959 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
960 TPM_RESPONSE_AUTH_LENGTH];
be6c1529 961 size_t response_length = sizeof(response);
b9804e5b 962 u32 err;
be6c1529
RP
963
964 if (!oiap_session.valid) {
965 err = tpm_oiap(NULL);
966 if (err)
967 return err;
968 }
969 if (pack_byte_string(request, sizeof(request), "sdd",
970 0, command, sizeof(command),
971 req_size_offset,
b9804e5b 972 (u32)(sizeof(command)
be6c1529
RP
973 + TPM_REQUEST_AUTH_LENGTH),
974 req_key_handle_offset, key_handle
975 ))
976 return TPM_LIB_ERROR;
977 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
c6179187 978 request + sizeof(command), usage_auth);
be6c1529
RP
979 if (err)
980 return err;
981 err = tpm_sendrecv_command(request, response, &response_length);
982 if (err) {
983 if (err == TPM_AUTHFAIL)
984 oiap_session.valid = 0;
985 return err;
986 }
987 err = verify_response_auth(0x00000021, response,
c6179187
MR
988 response_length - TPM_RESPONSE_AUTH_LENGTH,
989 0, &oiap_session,
990 response + response_length -
991 TPM_RESPONSE_AUTH_LENGTH,
992 usage_auth);
be6c1529
RP
993 if (err)
994 return err;
995
996 if (pubkey) {
997 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
c6179187 998 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
be6c1529
RP
999 return TPM_LIB_ERROR;
1000 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
1001 - TPM_RESPONSE_AUTH_LENGTH;
1002 memcpy(pubkey, response + res_pubkey_offset,
1003 response_length - TPM_RESPONSE_HEADER_LENGTH
1004 - TPM_RESPONSE_AUTH_LENGTH);
1005 }
1006
1007 return 0;
1008}
1009
0f4b2ba1 1010#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
b9804e5b
MR
1011u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
1012 u32 *handle)
0f4b2ba1 1013{
b9804e5b
MR
1014 u16 key_count;
1015 u32 key_handles[10];
1016 u8 buf[288];
1017 u8 *ptr;
1018 u32 err;
1019 u8 digest[20];
0f4b2ba1 1020 size_t buf_len;
1021 unsigned int i;
1022
1023 /* fetch list of already loaded keys in the TPM */
1024 err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
1025 if (err)
1026 return -1;
1027 key_count = get_unaligned_be16(buf);
1028 ptr = buf + 2;
1029 for (i = 0; i < key_count; ++i, ptr += 4)
1030 key_handles[i] = get_unaligned_be32(ptr);
1031
1032 /* now search a(/ the) key which we can access with the given auth */
1033 for (i = 0; i < key_count; ++i) {
1034 buf_len = sizeof(buf);
1035 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
1036 if (err && err != TPM_AUTHFAIL)
1037 return -1;
1038 if (err)
1039 continue;
1040 sha1_csum(buf, buf_len, digest);
1041 if (!memcmp(digest, pubkey_digest, 20)) {
1042 *handle = key_handles[i];
1043 return 0;
1044 }
1045 }
1046 return 1;
1047}
1048#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
1049
be6c1529 1050#endif /* CONFIG_TPM_AUTH_SESSIONS */
3c605027 1051
b9804e5b 1052u32 tpm_get_random(void *data, u32 count)
3c605027 1053{
b9804e5b 1054 const u8 command[14] = {
3c605027
AD
1055 0x0, 0xc1, /* TPM_TAG */
1056 0x0, 0x0, 0x0, 0xe, /* parameter size */
1057 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
1058 };
1059 const size_t length_offset = 10;
1060 const size_t data_size_offset = 10;
1061 const size_t data_offset = 14;
b9804e5b 1062 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
3c605027 1063 size_t response_length = sizeof(response);
b9804e5b
MR
1064 u32 data_size;
1065 u8 *out = data;
3c605027
AD
1066
1067 while (count > 0) {
b9804e5b
MR
1068 u32 this_bytes = min((size_t)count,
1069 sizeof(response) - data_offset);
1070 u32 err;
3c605027
AD
1071
1072 if (pack_byte_string(buf, sizeof(buf), "sd",
1073 0, command, sizeof(command),
1074 length_offset, this_bytes))
1075 return TPM_LIB_ERROR;
1076 err = tpm_sendrecv_command(buf, response, &response_length);
1077 if (err)
1078 return err;
1079 if (unpack_byte_string(response, response_length, "d",
1080 data_size_offset, &data_size))
1081 return TPM_LIB_ERROR;
1082 if (data_size > count)
1083 return TPM_LIB_ERROR;
1084 if (unpack_byte_string(response, response_length, "s",
1085 data_offset, out, data_size))
1086 return TPM_LIB_ERROR;
1087
1088 count -= data_size;
1089 out += data_size;
1090 }
1091
1092 return 0;
1093}