blob: e743935fd31bc1b8f5f46894192013f0c0580c03 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiouc18f9012013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfau4fece432013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiouc18f9012013-02-28 09:34:57 +00005 */
6
7#include <common.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -06008#include <dm.h>
Che-liang Chiouc18f9012013-02-28 09:34:57 +00009#include <tpm.h>
10#include <asm/unaligned.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060011#include <u-boot/sha1.h>
Che-liang Chiouc18f9012013-02-28 09:34:57 +000012
13/* Internal error of TPM command library */
Miquel Raynald790f552018-05-15 11:56:59 +020014#define TPM_LIB_ERROR ((u32)~0u)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000015
16/* Useful constants */
17enum {
18 COMMAND_BUFFER_SIZE = 256,
Che-liang Chiouc18f9012013-02-28 09:34:57 +000019 TPM_REQUEST_HEADER_LENGTH = 10,
20 TPM_RESPONSE_HEADER_LENGTH = 10,
21 PCR_DIGEST_LENGTH = 20,
Reinhard Pfau4fece432013-06-26 15:55:13 +020022 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,
Che-liang Chiouc18f9012013-02-28 09:34:57 +000028};
29
Reinhard Pfau4fece432013-06-26 15:55:13 +020030#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;
Miquel Raynald790f552018-05-15 11:56:59 +020038 u32 handle;
39 u8 nonce_even[DIGEST_LENGTH];
40 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +020041};
42
43static struct session_data oiap_session = {0, };
44
45#endif /* CONFIG_TPM_AUTH_SESSIONS */
46
Che-liang Chiouc18f9012013-02-28 09:34:57 +000047/**
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 */
Miquel Raynald790f552018-05-15 11:56:59 +020062int pack_byte_string(u8 *str, size_t size, const char *format, ...)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000063{
64 va_list args;
65 size_t offset = 0, length = 0;
Miquel Raynald790f552018-05-15 11:56:59 +020066 u8 *data = NULL;
67 u32 value = 0;
Che-liang Chiouc18f9012013-02-28 09:34:57 +000068
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);
Miquel Raynald790f552018-05-15 11:56:59 +020084 value = va_arg(args, u32);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000085 length = 4;
86 break;
87 case 's':
88 offset = va_arg(args, size_t);
Miquel Raynald790f552018-05-15 11:56:59 +020089 data = va_arg(args, u8 *);
90 length = va_arg(args, u32);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000091 break;
92 default:
93 debug("Couldn't recognize format string\n");
André Draszik3e490f62017-10-03 16:55:54 +010094 va_end(args);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000095 return -1;
96 }
97
xypron.glpk@gmx.deb7af1572017-07-30 21:40:37 +020098 if (offset + length > size) {
99 va_end(args);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000100 return -1;
xypron.glpk@gmx.deb7af1572017-07-30 21:40:37 +0200101 }
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000102
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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200136int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000137{
138 va_list args;
139 size_t offset = 0, length = 0;
Miquel Raynald790f552018-05-15 11:56:59 +0200140 u8 *ptr8 = NULL;
141 u16 *ptr16 = NULL;
142 u32 *ptr32 = NULL;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000143
144 va_start(args, format);
145 for (; *format; format++) {
146 switch (*format) {
147 case 'b':
148 offset = va_arg(args, size_t);
Miquel Raynald790f552018-05-15 11:56:59 +0200149 ptr8 = va_arg(args, u8 *);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000150 length = 1;
151 break;
152 case 'w':
153 offset = va_arg(args, size_t);
Miquel Raynald790f552018-05-15 11:56:59 +0200154 ptr16 = va_arg(args, u16 *);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000155 length = 2;
156 break;
157 case 'd':
158 offset = va_arg(args, size_t);
Miquel Raynald790f552018-05-15 11:56:59 +0200159 ptr32 = va_arg(args, u32 *);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000160 length = 4;
161 break;
162 case 's':
163 offset = va_arg(args, size_t);
Miquel Raynald790f552018-05-15 11:56:59 +0200164 ptr8 = va_arg(args, u8 *);
165 length = va_arg(args, u32);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000166 break;
167 default:
xypron.glpk@gmx.deb7af1572017-07-30 21:40:37 +0200168 va_end(args);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000169 debug("Couldn't recognize format string\n");
170 return -1;
171 }
172
André Draszik3e490f62017-10-03 16:55:54 +0100173 if (offset + length > size) {
174 va_end(args);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000175 return -1;
André Draszik3e490f62017-10-03 16:55:54 +0100176 }
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000177
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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200204static u32 tpm_command_size(const void *command)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000205{
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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200216static u32 tpm_return_code(const void *response)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000217{
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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200234static u32 tpm_sendrecv_command(const void *command, void *response,
235 size_t *size_ptr)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000236{
Christophe Ricard52d309b2015-10-06 22:54:43 +0200237 struct udevice *dev;
Tom Rini6b2d40c2017-05-10 15:20:18 -0400238 int err, ret;
Miquel Raynald790f552018-05-15 11:56:59 +0200239 u8 response_buffer[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000240 size_t response_length;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000241
242 if (response) {
243 response_length = *size_ptr;
244 } else {
245 response = response_buffer;
246 response_length = sizeof(response_buffer);
247 }
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600248
Simon Glassc7298e72016-02-11 13:23:26 -0700249 ret = uclass_first_device_err(UCLASS_TPM, &dev);
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600250 if (ret)
251 return ret;
252 err = tpm_xfer(dev, command, tpm_command_size(command),
253 response, &response_length);
Christophe Ricard52d309b2015-10-06 22:54:43 +0200254
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600255 if (err < 0)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000256 return TPM_LIB_ERROR;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200257 if (size_ptr)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000258 *size_ptr = response_length;
259
260 return tpm_return_code(response);
261}
262
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600263int tpm_init(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000264{
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600265 int err;
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600266 struct udevice *dev;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000267
Simon Glassc7298e72016-02-11 13:23:26 -0700268 err = uclass_first_device_err(UCLASS_TPM, &dev);
269 if (err)
Simon Glass3e4f2fd2015-08-22 18:31:32 -0600270 return err;
271 return tpm_open(dev);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000272}
273
Miquel Raynald790f552018-05-15 11:56:59 +0200274u32 tpm_startup(enum tpm_startup_type mode)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000275{
Miquel Raynald790f552018-05-15 11:56:59 +0200276 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000277 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
278 };
279 const size_t mode_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200280 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000281
282 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200283 0, command, sizeof(command),
284 mode_offset, mode))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000285 return TPM_LIB_ERROR;
286
287 return tpm_sendrecv_command(buf, NULL, NULL);
288}
289
Miquel Raynald790f552018-05-15 11:56:59 +0200290u32 tpm_self_test_full(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000291{
Miquel Raynald790f552018-05-15 11:56:59 +0200292 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000293 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
294 };
295 return tpm_sendrecv_command(command, NULL, NULL);
296}
297
Miquel Raynald790f552018-05-15 11:56:59 +0200298u32 tpm_continue_self_test(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000299{
Miquel Raynald790f552018-05-15 11:56:59 +0200300 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000301 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
302 };
303 return tpm_sendrecv_command(command, NULL, NULL);
304}
305
Miquel Raynald790f552018-05-15 11:56:59 +0200306u32 tpm_nv_define_space(u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000307{
Miquel Raynald790f552018-05-15 11:56:59 +0200308 const u8 command[101] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000309 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200337 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000338
339 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200340 0, command, sizeof(command),
341 index_offset, index,
342 perm_offset, perm,
343 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000344 return TPM_LIB_ERROR;
345
346 return tpm_sendrecv_command(buf, NULL, NULL);
347}
348
Miquel Raynald790f552018-05-15 11:56:59 +0200349u32 tpm_nv_read_value(u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000350{
Miquel Raynald790f552018-05-15 11:56:59 +0200351 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000352 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200358 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000359 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200360 u32 data_size;
361 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000362
363 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200364 0, command, sizeof(command),
365 index_offset, index,
366 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000367 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200372 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000373 return TPM_LIB_ERROR;
374 if (data_size > count)
375 return TPM_LIB_ERROR;
376 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200377 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000378 return TPM_LIB_ERROR;
379
380 return 0;
381}
382
Miquel Raynald790f552018-05-15 11:56:59 +0200383u32 tpm_nv_write_value(u32 index, const void *data, u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000384{
Miquel Raynald790f552018-05-15 11:56:59 +0200385 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000386 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200393 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000394 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200395 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000396 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200397 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000398
399 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200400 0, command, sizeof(command),
401 command_size_offset, total_length,
402 index_offset, index,
403 length_offset, length,
404 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000405 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
Miquel Raynald790f552018-05-15 11:56:59 +0200413u32 tpm_extend(u32 index, const void *in_digest, void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000414{
Miquel Raynald790f552018-05-15 11:56:59 +0200415 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000416 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200421 u8 buf[COMMAND_BUFFER_SIZE];
422 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000423 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200424 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000425
426 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200427 0, command, sizeof(command),
428 index_offset, index,
429 in_digest_offset, in_digest,
430 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000431 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200437 out_digest_offset, out_digest,
438 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000439 return TPM_LIB_ERROR;
440
441 return 0;
442}
443
Miquel Raynald790f552018-05-15 11:56:59 +0200444u32 tpm_pcr_read(u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000445{
Miquel Raynald790f552018-05-15 11:56:59 +0200446 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000447 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200451 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000452 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200453 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000454
455 if (count < PCR_DIGEST_LENGTH)
456 return TPM_LIB_ERROR;
457
458 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200459 0, command, sizeof(command),
460 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000461 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200466 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000467 return TPM_LIB_ERROR;
468
469 return 0;
470}
471
Miquel Raynald790f552018-05-15 11:56:59 +0200472u32 tpm_tsc_physical_presence(u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000473{
Miquel Raynald790f552018-05-15 11:56:59 +0200474 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000475 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
476 };
477 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200478 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000479
480 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200481 0, command, sizeof(command),
482 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000483 return TPM_LIB_ERROR;
484
485 return tpm_sendrecv_command(buf, NULL, NULL);
486}
487
Miquel Raynald790f552018-05-15 11:56:59 +0200488u32 tpm_read_pubek(void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000489{
Miquel Raynald790f552018-05-15 11:56:59 +0200490 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000491 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200496 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000497 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200498 u32 data_size;
499 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000500
501 err = tpm_sendrecv_command(command, response, &response_length);
502 if (err)
503 return err;
504 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200505 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000506 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200513 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000514 return TPM_LIB_ERROR;
515
516 return 0;
517}
518
Miquel Raynald790f552018-05-15 11:56:59 +0200519u32 tpm_force_clear(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000520{
Miquel Raynald790f552018-05-15 11:56:59 +0200521 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000522 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
523 };
524
525 return tpm_sendrecv_command(command, NULL, NULL);
526}
527
Miquel Raynald790f552018-05-15 11:56:59 +0200528u32 tpm_physical_enable(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000529{
Miquel Raynald790f552018-05-15 11:56:59 +0200530 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000531 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
532 };
533
534 return tpm_sendrecv_command(command, NULL, NULL);
535}
536
Miquel Raynald790f552018-05-15 11:56:59 +0200537u32 tpm_physical_disable(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000538{
Miquel Raynald790f552018-05-15 11:56:59 +0200539 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000540 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
541 };
542
543 return tpm_sendrecv_command(command, NULL, NULL);
544}
545
Miquel Raynald790f552018-05-15 11:56:59 +0200546u32 tpm_physical_set_deactivated(u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000547{
Miquel Raynald790f552018-05-15 11:56:59 +0200548 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000549 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
550 };
551 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200552 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000553
554 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200555 0, command, sizeof(command),
556 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000557 return TPM_LIB_ERROR;
558
559 return tpm_sendrecv_command(buf, NULL, NULL);
560}
561
Miquel Raynald790f552018-05-15 11:56:59 +0200562u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000563{
Miquel Raynald790f552018-05-15 11:56:59 +0200564 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000565 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200576 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000577 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200578 u32 cap_size;
579 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000580
581 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200582 0, command, sizeof(command),
583 cap_area_offset, cap_area,
584 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000585 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200590 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000591 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",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200595 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000596 return TPM_LIB_ERROR;
597
598 return 0;
599}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200600
Miquel Raynald790f552018-05-15 11:56:59 +0200601u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600602{
Miquel Raynald790f552018-05-15 11:56:59 +0200603 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600604 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 };
André Draszik1361fbc2017-10-03 16:55:51 +0100611 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200612 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
613 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600614 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200615 u32 err;
616 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600617
618 err = tpm_sendrecv_command(command, response, &response_length);
619 if (err)
620 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100621 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;
Simon Glassff9f04a2015-08-22 18:31:41 -0600629
630 return 0;
631}
632
Miquel Raynald790f552018-05-15 11:56:59 +0200633u32 tpm_get_permissions(u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600634{
Miquel Raynald790f552018-05-15 11:56:59 +0200635 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600636 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200644 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600645 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200646 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600647
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
Mario Six4eceb6c2017-01-11 16:00:50 +0100661#ifdef CONFIG_TPM_FLUSH_RESOURCES
Miquel Raynald790f552018-05-15 11:56:59 +0200662u32 tpm_flush_specific(u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100663{
Miquel Raynald790f552018-05-15 11:56:59 +0200664 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100665 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200673 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100674 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200675 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100676
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
Reinhard Pfau4fece432013-06-26 15:55:13 +0200690#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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200704static 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)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200708{
Miquel Raynald790f552018-05-15 11:56:59 +0200709 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200710 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 */
Miquel Raynald790f552018-05-15 11:56:59 +0200767static 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)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200771{
Miquel Raynald790f552018-05-15 11:56:59 +0200772 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
773 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200774 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200778 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200779
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);
Miquel Raynald790f552018-05-15 11:56:59 +0200799 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200800 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
Miquel Raynald790f552018-05-15 11:56:59 +0200821u32 tpm_terminate_auth_session(u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200822{
Miquel Raynald790f552018-05-15 11:56:59 +0200823 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200824 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 */
Miquel Raynala59aa342018-05-15 11:57:02 +0200828 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200829 };
830 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200831 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200832
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
Miquel Raynald790f552018-05-15 11:56:59 +0200843u32 tpm_end_oiap(void)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200844{
Miquel Raynald790f552018-05-15 11:56:59 +0200845 u32 err = TPM_SUCCESS;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200846 if (oiap_session.valid)
847 err = tpm_terminate_auth_session(oiap_session.handle);
848 return err;
849}
850
Miquel Raynald790f552018-05-15 11:56:59 +0200851u32 tpm_oiap(u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200852{
Miquel Raynald790f552018-05-15 11:56:59 +0200853 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200854 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200860 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200861 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200862 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200863
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,
Miquel Raynald790f552018-05-15 11:56:59 +0200873 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200874 return TPM_LIB_ERROR;
875 oiap_session.valid = 1;
876 if (auth_handle)
877 *auth_handle = oiap_session.handle;
878 return 0;
879}
880
Miquel Raynald790f552018-05-15 11:56:59 +0200881u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length,
882 const void *parent_key_usage_auth, u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200883{
Miquel Raynald790f552018-05-15 11:56:59 +0200884 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200885 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200894 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
895 TPM_REQUEST_AUTH_LENGTH];
896 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200897 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200898 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200899
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,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200916 &oiap_session,
917 request + sizeof(command) + key_length,
918 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200919 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,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200929 response_length - TPM_RESPONSE_AUTH_LENGTH,
930 4, &oiap_session,
931 response + response_length -
932 TPM_RESPONSE_AUTH_LENGTH,
933 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200934 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
Miquel Raynald790f552018-05-15 11:56:59 +0200946u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey,
947 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200948{
Miquel Raynald790f552018-05-15 11:56:59 +0200949 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200950 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;
Miquel Raynald790f552018-05-15 11:56:59 +0200958 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
959 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
960 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200961 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200962 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200963
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,
Miquel Raynald790f552018-05-15 11:56:59 +0200972 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200973 + 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,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200978 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200979 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,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200988 response_length - TPM_RESPONSE_AUTH_LENGTH,
989 0, &oiap_session,
990 response + response_length -
991 TPM_RESPONSE_AUTH_LENGTH,
992 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200993 if (err)
994 return err;
995
996 if (pubkey) {
997 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200998 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200999 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
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +01001010#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Miquel Raynald790f552018-05-15 11:56:59 +02001011u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
1012 u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +01001013{
Miquel Raynald790f552018-05-15 11:56:59 +02001014 u16 key_count;
1015 u32 key_handles[10];
1016 u8 buf[288];
1017 u8 *ptr;
1018 u32 err;
1019 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +01001020 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
Reinhard Pfau4fece432013-06-26 15:55:13 +02001050#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +01001051
Miquel Raynald790f552018-05-15 11:56:59 +02001052u32 tpm_get_random(void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +01001053{
Miquel Raynald790f552018-05-15 11:56:59 +02001054 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +01001055 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;
Miquel Raynald790f552018-05-15 11:56:59 +02001062 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +01001063 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +02001064 u32 data_size;
1065 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +01001066
1067 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +02001068 u32 this_bytes = min((size_t)count,
1069 sizeof(response) - data_offset);
1070 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +01001071
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}