2 * Copyright (c) 2013 The Chromium OS Authors.
4 * See file CREDITS for list of people who contributed to this
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.
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.
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,
26 #include <asm/unaligned.h>
28 /* Internal error of TPM command library */
29 #define TPM_LIB_ERROR ((uint32_t)~0u)
31 /* Useful constants */
33 COMMAND_BUFFER_SIZE = 256,
35 TPM_REQUEST_HEADER_LENGTH = 10,
36 TPM_RESPONSE_HEADER_LENGTH = 10,
37 PCR_DIGEST_LENGTH = 20,
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
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
55 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
58 size_t offset = 0, length = 0;
62 va_start(args, format);
63 for (; *format; format++) {
66 offset = va_arg(args, size_t);
67 value = va_arg(args, int);
71 offset = va_arg(args, size_t);
72 value = va_arg(args, int);
76 offset = va_arg(args, size_t);
77 value = va_arg(args, uint32_t);
81 offset = va_arg(args, size_t);
82 data = va_arg(args, uint8_t *);
83 length = va_arg(args, uint32_t);
86 debug("Couldn't recognize format string\n");
90 if (offset + length > size)
98 put_unaligned_be16(value, str + offset);
101 put_unaligned_be32(value, str + offset);
104 memcpy(str + offset, data, length);
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
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
126 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
129 size_t offset = 0, length = 0;
130 uint8_t *ptr8 = NULL;
131 uint16_t *ptr16 = NULL;
132 uint32_t *ptr32 = NULL;
134 va_start(args, format);
135 for (; *format; format++) {
138 offset = va_arg(args, size_t);
139 ptr8 = va_arg(args, uint8_t *);
143 offset = va_arg(args, size_t);
144 ptr16 = va_arg(args, uint16_t *);
148 offset = va_arg(args, size_t);
149 ptr32 = va_arg(args, uint32_t *);
153 offset = va_arg(args, size_t);
154 ptr8 = va_arg(args, uint8_t *);
155 length = va_arg(args, uint32_t);
158 debug("Couldn't recognize format string\n");
162 if (offset + length > size)
170 *ptr16 = get_unaligned_be16(str + offset);
173 *ptr32 = get_unaligned_be32(str + offset);
176 memcpy(ptr8, str + offset, length);
186 * Get TPM command size.
188 * @param command byte string of TPM command
189 * @return command size of the TPM command
191 static uint32_t tpm_command_size(const void *command)
193 const size_t command_size_offset = 2;
194 return get_unaligned_be32(command + command_size_offset);
198 * Get TPM response return code, which is one of TPM_RESULT values.
200 * @param response byte string of TPM response
201 * @return return code of the TPM response
203 static uint32_t tpm_return_code(const void *response)
205 const size_t return_code_offset = 6;
206 return get_unaligned_be32(response + return_code_offset);
210 * Send a TPM command and return response's return code, and optionally
211 * return response to caller.
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
219 * @return return code of the TPM response
221 static uint32_t tpm_sendrecv_command(const void *command,
222 void *response, size_t *size_ptr)
224 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
225 size_t response_length;
229 response_length = *size_ptr;
231 response = response_buffer;
232 response_length = sizeof(response_buffer);
234 err = tis_sendrecv(command, tpm_command_size(command),
235 response, &response_length);
237 return TPM_LIB_ERROR;
239 *size_ptr = response_length;
241 return tpm_return_code(response);
244 uint32_t tpm_init(void)
255 uint32_t tpm_startup(enum tpm_startup_type mode)
257 const uint8_t command[12] = {
258 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
260 const size_t mode_offset = 10;
261 uint8_t buf[COMMAND_BUFFER_SIZE];
263 if (pack_byte_string(buf, sizeof(buf), "sw",
264 0, command, sizeof(command),
266 return TPM_LIB_ERROR;
268 return tpm_sendrecv_command(buf, NULL, NULL);
271 uint32_t tpm_self_test_full(void)
273 const uint8_t command[10] = {
274 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
276 return tpm_sendrecv_command(command, NULL, NULL);
279 uint32_t tpm_continue_self_test(void)
281 const uint8_t command[10] = {
282 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
284 return tpm_sendrecv_command(command, NULL, NULL);
287 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
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 */
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 */
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 */
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];
320 if (pack_byte_string(buf, sizeof(buf), "sddd",
321 0, command, sizeof(command),
325 return TPM_LIB_ERROR;
327 return tpm_sendrecv_command(buf, NULL, NULL);
330 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
332 const uint8_t command[22] = {
333 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
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);
344 if (pack_byte_string(buf, sizeof(buf), "sdd",
345 0, command, sizeof(command),
347 length_offset, count))
348 return TPM_LIB_ERROR;
349 err = tpm_sendrecv_command(buf, response, &response_length);
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;
364 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
366 const uint8_t command[256] = {
367 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
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);
380 if (pack_byte_string(buf, sizeof(buf), "sddds",
381 0, command, sizeof(command),
382 command_size_offset, total_length,
384 length_offset, length,
385 data_offset, data, length))
386 return TPM_LIB_ERROR;
387 err = tpm_sendrecv_command(buf, response, &response_length);
394 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
396 const uint8_t command[34] = {
397 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
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);
407 if (pack_byte_string(buf, sizeof(buf), "sds",
408 0, command, sizeof(command),
410 in_digest_offset, in_digest,
412 return TPM_LIB_ERROR;
413 err = tpm_sendrecv_command(buf, response, &response_length);
417 if (unpack_byte_string(response, response_length, "s",
418 out_digest_offset, out_digest,
420 return TPM_LIB_ERROR;
425 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
427 const uint8_t command[14] = {
428 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
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);
436 if (count < PCR_DIGEST_LENGTH)
437 return TPM_LIB_ERROR;
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);
446 if (unpack_byte_string(response, response_length, "s",
447 out_digest_offset, data, PCR_DIGEST_LENGTH))
448 return TPM_LIB_ERROR;
453 uint32_t tpm_tsc_physical_presence(uint16_t presence)
455 const uint8_t command[12] = {
456 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
458 const size_t presence_offset = 10;
459 uint8_t buf[COMMAND_BUFFER_SIZE];
461 if (pack_byte_string(buf, sizeof(buf), "sw",
462 0, command, sizeof(command),
463 presence_offset, presence))
464 return TPM_LIB_ERROR;
466 return tpm_sendrecv_command(buf, NULL, NULL);
469 uint32_t tpm_read_pubek(void *data, size_t count)
471 const uint8_t command[30] = {
472 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
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);
482 err = tpm_sendrecv_command(command, response, &response_length);
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;
500 uint32_t tpm_force_clear(void)
502 const uint8_t command[10] = {
503 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
506 return tpm_sendrecv_command(command, NULL, NULL);
509 uint32_t tpm_physical_enable(void)
511 const uint8_t command[10] = {
512 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
515 return tpm_sendrecv_command(command, NULL, NULL);
518 uint32_t tpm_physical_disable(void)
520 const uint8_t command[10] = {
521 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
524 return tpm_sendrecv_command(command, NULL, NULL);
527 uint32_t tpm_physical_set_deactivated(uint8_t state)
529 const uint8_t command[11] = {
530 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
532 const size_t state_offset = 10;
533 uint8_t buf[COMMAND_BUFFER_SIZE];
535 if (pack_byte_string(buf, sizeof(buf), "sb",
536 0, command, sizeof(command),
537 state_offset, state))
538 return TPM_LIB_ERROR;
540 return tpm_sendrecv_command(buf, NULL, NULL);
543 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
544 void *cap, size_t count)
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 */
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);
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);
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;