aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorChe-liang Chiou2013-02-28 03:34:57 -0600
committerSimon Glass2013-04-12 16:13:13 -0500
commit8732b0700d21588b4954d0f1b182f4c60725d228 (patch)
treeb5c693899b28ac13789e8957114b12af4d946769 /lib
parentc1af608f6f22d58ec27b1f6ba9841d1baf12cc98 (diff)
downloadu-boot-8732b0700d21588b4954d0f1b182f4c60725d228.tar.gz
u-boot-8732b0700d21588b4954d0f1b182f4c60725d228.tar.xz
u-boot-8732b0700d21588b4954d0f1b182f4c60725d228.zip
tpm: Add TPM command library
TPM command library implements a subset of TPM commands defined in TCG Main Specification 1.2 that are useful for implementing secure boot. More TPM commands could be added out of necessity. You may exercise these commands through the 'tpm' command. However, the raw TPM commands are too primitive for writing secure boot in command interpreter scripts; so the 'tpm' command also provides helper functions to make scripting easier. For example, to define a counter in TPM non-volatile storage and initialize it to zero: $ tpm init $ tpm startup TPM_ST_CLEAR $ tpm nv_define d 0x1001 0x1 $ tpm nv_write d 0x1001 0 And then increment the counter by one: $ tpm nv_read d 0x1001 i $ setexpr.l i $i + 1 $ tpm nv_write d 0x1001 $i Signed-off-by: Che-Liang Chiou <clchiou@chromium.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile1
-rw-r--r--lib/tpm.c581
2 files changed, 582 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 1bfd3ee124..d57775d7c4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -54,6 +54,7 @@ COBJS-y += qsort.o
54COBJS-$(CONFIG_SHA1) += sha1.o 54COBJS-$(CONFIG_SHA1) += sha1.o
55COBJS-$(CONFIG_SHA256) += sha256.o 55COBJS-$(CONFIG_SHA256) += sha256.o
56COBJS-y += strmhz.o 56COBJS-y += strmhz.o
57COBJS-$(CONFIG_TPM) += tpm.o
57COBJS-$(CONFIG_RBTREE) += rbtree.o 58COBJS-$(CONFIG_RBTREE) += rbtree.o
58endif 59endif
59 60
diff --git a/lib/tpm.c b/lib/tpm.c
new file mode 100644
index 0000000000..42c9bea0f9
--- /dev/null
+++ b/lib/tpm.c
@@ -0,0 +1,581 @@
1/*
2 * Copyright (c) 2013 The Chromium OS Authors.
3 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 */
22
23#include <common.h>
24#include <stdarg.h>
25#include <tpm.h>
26#include <asm/unaligned.h>
27
28/* Internal error of TPM command library */
29#define TPM_LIB_ERROR ((uint32_t)~0u)
30
31/* Useful constants */
32enum {
33 COMMAND_BUFFER_SIZE = 256,
34 TPM_PUBEK_SIZE = 256,
35 TPM_REQUEST_HEADER_LENGTH = 10,
36 TPM_RESPONSE_HEADER_LENGTH = 10,
37 PCR_DIGEST_LENGTH = 20,
38};
39
40/**
41 * Pack data into a byte string. The data types are specified in
42 * the format string: 'b' means unsigned byte, 'w' unsigned word,
43 * 'd' unsigned double word, and 's' byte string. The data are a
44 * series of offsets and values (for type byte string there are also
45 * lengths). The data values are packed into the byte string
46 * sequentially, and so a latter value could over-write a former
47 * value.
48 *
49 * @param str output string
50 * @param size size of output string
51 * @param format format string
52 * @param ... data points
53 * @return 0 on success, non-0 on error
54 */
55int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
56{
57 va_list args;
58 size_t offset = 0, length = 0;
59 uint8_t *data = NULL;
60 uint32_t value = 0;
61
62 va_start(args, format);
63 for (; *format; format++) {
64 switch (*format) {
65 case 'b':
66 offset = va_arg(args, size_t);
67 value = va_arg(args, int);
68 length = 1;
69 break;
70 case 'w':
71 offset = va_arg(args, size_t);
72 value = va_arg(args, int);
73 length = 2;
74 break;
75 case 'd':
76 offset = va_arg(args, size_t);
77 value = va_arg(args, uint32_t);
78 length = 4;
79 break;
80 case 's':
81 offset = va_arg(args, size_t);
82 data = va_arg(args, uint8_t *);
83 length = va_arg(args, uint32_t);
84 break;
85 default:
86 debug("Couldn't recognize format string\n");
87 return -1;
88 }
89
90 if (offset + length > size)
91 return -1;
92
93 switch (*format) {
94 case 'b':
95 str[offset] = value;
96 break;
97 case 'w':
98 put_unaligned_be16(value, str + offset);
99 break;
100 case 'd':
101 put_unaligned_be32(value, str + offset);
102 break;
103 case 's':
104 memcpy(str + offset, data, length);
105 break;
106 }
107 }
108 va_end(args);
109
110 return 0;
111}
112
113/**
114 * Unpack data from a byte string. The data types are specified in
115 * the format string: 'b' means unsigned byte, 'w' unsigned word,
116 * 'd' unsigned double word, and 's' byte string. The data are a
117 * series of offsets and pointers (for type byte string there are also
118 * lengths).
119 *
120 * @param str output string
121 * @param size size of output string
122 * @param format format string
123 * @param ... data points
124 * @return 0 on success, non-0 on error
125 */
126int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
127{
128 va_list args;
129 size_t offset = 0, length = 0;
130 uint8_t *ptr8 = NULL;
131 uint16_t *ptr16 = NULL;
132 uint32_t *ptr32 = NULL;
133
134 va_start(args, format);
135 for (; *format; format++) {
136 switch (*format) {
137 case 'b':
138 offset = va_arg(args, size_t);
139 ptr8 = va_arg(args, uint8_t *);
140 length = 1;
141 break;
142 case 'w':
143 offset = va_arg(args, size_t);
144 ptr16 = va_arg(args, uint16_t *);
145 length = 2;
146 break;
147 case 'd':
148 offset = va_arg(args, size_t);
149 ptr32 = va_arg(args, uint32_t *);
150 length = 4;
151 break;
152 case 's':
153 offset = va_arg(args, size_t);
154 ptr8 = va_arg(args, uint8_t *);
155 length = va_arg(args, uint32_t);
156 break;
157 default:
158 debug("Couldn't recognize format string\n");
159 return -1;
160 }
161
162 if (offset + length > size)
163 return -1;
164
165 switch (*format) {
166 case 'b':
167 *ptr8 = str[offset];
168 break;
169 case 'w':
170 *ptr16 = get_unaligned_be16(str + offset);
171 break;
172 case 'd':
173 *ptr32 = get_unaligned_be32(str + offset);
174 break;
175 case 's':
176 memcpy(ptr8, str + offset, length);
177 break;
178 }
179 }
180 va_end(args);
181
182 return 0;
183}
184
185/**
186 * Get TPM command size.
187 *
188 * @param command byte string of TPM command
189 * @return command size of the TPM command
190 */
191static uint32_t tpm_command_size(const void *command)
192{
193 const size_t command_size_offset = 2;
194 return get_unaligned_be32(command + command_size_offset);
195}
196
197/**
198 * Get TPM response return code, which is one of TPM_RESULT values.
199 *
200 * @param response byte string of TPM response
201 * @return return code of the TPM response
202 */
203static uint32_t tpm_return_code(const void *response)
204{
205 const size_t return_code_offset = 6;
206 return get_unaligned_be32(response + return_code_offset);
207}
208
209/**
210 * Send a TPM command and return response's return code, and optionally
211 * return response to caller.
212 *
213 * @param command byte string of TPM command
214 * @param response output buffer for TPM response, or NULL if the
215 * caller does not care about it
216 * @param size_ptr output buffer size (input parameter) and TPM
217 * response length (output parameter); this parameter
218 * is a bidirectional
219 * @return return code of the TPM response
220 */
221static uint32_t tpm_sendrecv_command(const void *command,
222 void *response, size_t *size_ptr)
223{
224 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
225 size_t response_length;
226 uint32_t err;
227
228 if (response) {
229 response_length = *size_ptr;
230 } else {
231 response = response_buffer;
232 response_length = sizeof(response_buffer);
233 }
234 err = tis_sendrecv(command, tpm_command_size(command),
235 response, &response_length);
236 if (err)
237 return TPM_LIB_ERROR;
238 if (response)
239 *size_ptr = response_length;
240
241 return tpm_return_code(response);
242}
243
244uint32_t tpm_init(void)
245{
246 uint32_t err;
247
248 err = tis_init();
249 if (err)
250 return err;
251
252 return tis_open();
253}
254
255uint32_t tpm_startup(enum tpm_startup_type mode)
256{
257 const uint8_t command[12] = {
258 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
259 };
260 const size_t mode_offset = 10;
261 uint8_t buf[COMMAND_BUFFER_SIZE];
262
263 if (pack_byte_string(buf, sizeof(buf), "sw",
264 0, command, sizeof(command),
265 mode_offset, mode))
266 return TPM_LIB_ERROR;
267
268 return tpm_sendrecv_command(buf, NULL, NULL);
269}
270
271uint32_t tpm_self_test_full(void)
272{
273 const uint8_t command[10] = {
274 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
275 };
276 return tpm_sendrecv_command(command, NULL, NULL);
277}
278
279uint32_t tpm_continue_self_test(void)
280{
281 const uint8_t command[10] = {
282 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
283 };
284 return tpm_sendrecv_command(command, NULL, NULL);
285}
286
287uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
288{
289 const uint8_t command[101] = {
290 0x0, 0xc1, /* TPM_TAG */
291 0x0, 0x0, 0x0, 0x65, /* parameter size */
292 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
293 /* TPM_NV_DATA_PUBLIC->... */
294 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
295 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
296 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
297 0x0, 0x3,
298 0, 0, 0,
299 0x1f,
300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
301 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
302 0x0, 0x3,
303 0, 0, 0,
304 0x1f,
305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
306 /* TPM_NV_ATTRIBUTES->... */
307 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
308 0, 0, 0, 0, /* ...->attributes */
309 /* End of TPM_NV_ATTRIBUTES */
310 0, /* bReadSTClear */
311 0, /* bWriteSTClear */
312 0, /* bWriteDefine */
313 0, 0, 0, 0, /* size */
314 };
315 const size_t index_offset = 12;
316 const size_t perm_offset = 70;
317 const size_t size_offset = 77;
318 uint8_t buf[COMMAND_BUFFER_SIZE];
319
320 if (pack_byte_string(buf, sizeof(buf), "sddd",
321 0, command, sizeof(command),
322 index_offset, index,
323 perm_offset, perm,
324 size_offset, size))
325 return TPM_LIB_ERROR;
326
327 return tpm_sendrecv_command(buf, NULL, NULL);
328}
329
330uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
331{
332 const uint8_t command[22] = {
333 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
334 };
335 const size_t index_offset = 10;
336 const size_t length_offset = 18;
337 const size_t data_size_offset = 10;
338 const size_t data_offset = 14;
339 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
340 size_t response_length = sizeof(response);
341 uint32_t data_size;
342 uint32_t err;
343
344 if (pack_byte_string(buf, sizeof(buf), "sdd",
345 0, command, sizeof(command),
346 index_offset, index,
347 length_offset, count))
348 return TPM_LIB_ERROR;
349 err = tpm_sendrecv_command(buf, response, &response_length);
350 if (err)
351 return err;
352 if (unpack_byte_string(response, response_length, "d",
353 data_size_offset, &data_size))
354 return TPM_LIB_ERROR;
355 if (data_size > count)
356 return TPM_LIB_ERROR;
357 if (unpack_byte_string(response, response_length, "s",
358 data_offset, data, data_size))
359 return TPM_LIB_ERROR;
360
361 return 0;
362}
363
364uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
365{
366 const uint8_t command[256] = {
367 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
368 };
369 const size_t command_size_offset = 2;
370 const size_t index_offset = 10;
371 const size_t length_offset = 18;
372 const size_t data_offset = 22;
373 const size_t write_info_size = 12;
374 const uint32_t total_length =
375 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
376 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
377 size_t response_length = sizeof(response);
378 uint32_t err;
379
380 if (pack_byte_string(buf, sizeof(buf), "sddds",
381 0, command, sizeof(command),
382 command_size_offset, total_length,
383 index_offset, index,
384 length_offset, length,
385 data_offset, data, length))
386 return TPM_LIB_ERROR;
387 err = tpm_sendrecv_command(buf, response, &response_length);
388 if (err)
389 return err;
390
391 return 0;
392}
393
394uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
395{
396 const uint8_t command[34] = {
397 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
398 };
399 const size_t index_offset = 10;
400 const size_t in_digest_offset = 14;
401 const size_t out_digest_offset = 10;
402 uint8_t buf[COMMAND_BUFFER_SIZE];
403 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
404 size_t response_length = sizeof(response);
405 uint32_t err;
406
407 if (pack_byte_string(buf, sizeof(buf), "sds",
408 0, command, sizeof(command),
409 index_offset, index,
410 in_digest_offset, in_digest,
411 PCR_DIGEST_LENGTH))
412 return TPM_LIB_ERROR;
413 err = tpm_sendrecv_command(buf, response, &response_length);
414 if (err)
415 return err;
416
417 if (unpack_byte_string(response, response_length, "s",
418 out_digest_offset, out_digest,
419 PCR_DIGEST_LENGTH))
420 return TPM_LIB_ERROR;
421
422 return 0;
423}
424
425uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
426{
427 const uint8_t command[14] = {
428 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
429 };
430 const size_t index_offset = 10;
431 const size_t out_digest_offset = 10;
432 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
433 size_t response_length = sizeof(response);
434 uint32_t err;
435
436 if (count < PCR_DIGEST_LENGTH)
437 return TPM_LIB_ERROR;
438
439 if (pack_byte_string(buf, sizeof(buf), "sd",
440 0, command, sizeof(command),
441 index_offset, index))
442 return TPM_LIB_ERROR;
443 err = tpm_sendrecv_command(buf, response, &response_length);
444 if (err)
445 return err;
446 if (unpack_byte_string(response, response_length, "s",
447 out_digest_offset, data, PCR_DIGEST_LENGTH))
448 return TPM_LIB_ERROR;
449
450 return 0;
451}
452
453uint32_t tpm_tsc_physical_presence(uint16_t presence)
454{
455 const uint8_t command[12] = {
456 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
457 };
458 const size_t presence_offset = 10;
459 uint8_t buf[COMMAND_BUFFER_SIZE];
460
461 if (pack_byte_string(buf, sizeof(buf), "sw",
462 0, command, sizeof(command),
463 presence_offset, presence))
464 return TPM_LIB_ERROR;
465
466 return tpm_sendrecv_command(buf, NULL, NULL);
467}
468
469uint32_t tpm_read_pubek(void *data, size_t count)
470{
471 const uint8_t command[30] = {
472 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
473 };
474 const size_t response_size_offset = 2;
475 const size_t data_offset = 10;
476 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
477 uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
478 size_t response_length = sizeof(response);
479 uint32_t data_size;
480 uint32_t err;
481
482 err = tpm_sendrecv_command(command, response, &response_length);
483 if (err)
484 return err;
485 if (unpack_byte_string(response, response_length, "d",
486 response_size_offset, &data_size))
487 return TPM_LIB_ERROR;
488 if (data_size < header_and_checksum_size)
489 return TPM_LIB_ERROR;
490 data_size -= header_and_checksum_size;
491 if (data_size > count)
492 return TPM_LIB_ERROR;
493 if (unpack_byte_string(response, response_length, "s",
494 data_offset, data, data_size))
495 return TPM_LIB_ERROR;
496
497 return 0;
498}
499
500uint32_t tpm_force_clear(void)
501{
502 const uint8_t command[10] = {
503 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
504 };
505
506 return tpm_sendrecv_command(command, NULL, NULL);
507}
508
509uint32_t tpm_physical_enable(void)
510{
511 const uint8_t command[10] = {
512 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
513 };
514
515 return tpm_sendrecv_command(command, NULL, NULL);
516}
517
518uint32_t tpm_physical_disable(void)
519{
520 const uint8_t command[10] = {
521 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
522 };
523
524 return tpm_sendrecv_command(command, NULL, NULL);
525}
526
527uint32_t tpm_physical_set_deactivated(uint8_t state)
528{
529 const uint8_t command[11] = {
530 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
531 };
532 const size_t state_offset = 10;
533 uint8_t buf[COMMAND_BUFFER_SIZE];
534
535 if (pack_byte_string(buf, sizeof(buf), "sb",
536 0, command, sizeof(command),
537 state_offset, state))
538 return TPM_LIB_ERROR;
539
540 return tpm_sendrecv_command(buf, NULL, NULL);
541}
542
543uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
544 void *cap, size_t count)
545{
546 const uint8_t command[22] = {
547 0x0, 0xc1, /* TPM_TAG */
548 0x0, 0x0, 0x0, 0x16, /* parameter size */
549 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
550 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
551 0x0, 0x0, 0x0, 0x4, /* subcap size */
552 0x0, 0x0, 0x0, 0x0, /* subcap value */
553 };
554 const size_t cap_area_offset = 10;
555 const size_t sub_cap_offset = 18;
556 const size_t cap_offset = 14;
557 const size_t cap_size_offset = 10;
558 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
559 size_t response_length = sizeof(response);
560 uint32_t cap_size;
561 uint32_t err;
562
563 if (pack_byte_string(buf, sizeof(buf), "sdd",
564 0, command, sizeof(command),
565 cap_area_offset, cap_area,
566 sub_cap_offset, sub_cap))
567 return TPM_LIB_ERROR;
568 err = tpm_sendrecv_command(buf, response, &response_length);
569 if (err)
570 return err;
571 if (unpack_byte_string(response, response_length, "d",
572 cap_size_offset, &cap_size))
573 return TPM_LIB_ERROR;
574 if (cap_size > response_length || cap_size > count)
575 return TPM_LIB_ERROR;
576 if (unpack_byte_string(response, response_length, "s",
577 cap_offset, cap, cap_size))
578 return TPM_LIB_ERROR;
579
580 return 0;
581}