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