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
;