blob: b4498e6afc7ee6e38dd08617e6652e72f0c0e2b5 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiou8732b072013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfaube6c1522013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiou8732b072013-02-28 09:34:57 +00005 */
6
Simon Glass6e64ec12018-10-01 12:22:29 -06007#define LOG_CATEGORY UCLASS_TPM
8
Che-liang Chiou8732b072013-02-28 09:34:57 +00009#include <common.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060010#include <dm.h>
Che-liang Chiou8732b072013-02-28 09:34:57 +000011#include <asm/unaligned.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060012#include <u-boot/sha1.h>
Miquel Raynald677bfe2018-05-15 11:57:06 +020013#include <tpm-common.h>
14#include <tpm-v1.h>
15#include "tpm-utils.h"
Che-liang Chiou8732b072013-02-28 09:34:57 +000016
Reinhard Pfaube6c1522013-06-26 15:55:13 +020017#ifdef CONFIG_TPM_AUTH_SESSIONS
18
19#ifndef CONFIG_SHA1
20#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
21#endif /* !CONFIG_SHA1 */
22
23struct session_data {
24 int valid;
Miquel Raynalb9804e52018-05-15 11:56:59 +020025 u32 handle;
26 u8 nonce_even[DIGEST_LENGTH];
27 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +020028};
29
30static struct session_data oiap_session = {0, };
31
32#endif /* CONFIG_TPM_AUTH_SESSIONS */
33
Simon Glassabdc7b82018-11-18 14:22:27 -070034u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode)
Che-liang Chiou8732b072013-02-28 09:34:57 +000035{
Miquel Raynalb9804e52018-05-15 11:56:59 +020036 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000037 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
38 };
39 const size_t mode_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +020040 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +000041
42 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +020043 0, command, sizeof(command),
44 mode_offset, mode))
Che-liang Chiou8732b072013-02-28 09:34:57 +000045 return TPM_LIB_ERROR;
46
Simon Glassabdc7b82018-11-18 14:22:27 -070047 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000048}
49
Simon Glassabdc7b82018-11-18 14:22:27 -070050u32 tpm_resume(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -060051{
Simon Glassabdc7b82018-11-18 14:22:27 -070052 return tpm_startup(dev, TPM_ST_STATE);
Simon Glass6e64ec12018-10-01 12:22:29 -060053}
54
Simon Glassabdc7b82018-11-18 14:22:27 -070055u32 tpm_self_test_full(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +000056{
Miquel Raynalb9804e52018-05-15 11:56:59 +020057 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000058 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
59 };
Simon Glassabdc7b82018-11-18 14:22:27 -070060 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000061}
62
Simon Glassabdc7b82018-11-18 14:22:27 -070063u32 tpm_continue_self_test(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +000064{
Miquel Raynalb9804e52018-05-15 11:56:59 +020065 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000066 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
67 };
Simon Glassabdc7b82018-11-18 14:22:27 -070068 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000069}
70
Simon Glassabdc7b82018-11-18 14:22:27 -070071u32 tpm_clear_and_reenable(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -060072{
73 u32 ret;
74
75 log_info("TPM: Clear and re-enable\n");
Simon Glassabdc7b82018-11-18 14:22:27 -070076 ret = tpm_force_clear(dev);
Simon Glass6e64ec12018-10-01 12:22:29 -060077 if (ret != TPM_SUCCESS) {
78 log_err("Can't initiate a force clear\n");
79 return ret;
80 }
81
Simon Glass0a60a0a2018-11-23 21:29:32 -070082 if (tpm_get_version(dev) == TPM_V1) {
83 ret = tpm_physical_enable(dev);
84 if (ret != TPM_SUCCESS) {
85 log_err("TPM: Can't set enabled state\n");
86 return ret;
87 }
Simon Glass6e64ec12018-10-01 12:22:29 -060088
Simon Glass0a60a0a2018-11-23 21:29:32 -070089 ret = tpm_physical_set_deactivated(dev, 0);
90 if (ret != TPM_SUCCESS) {
91 log_err("TPM: Can't set deactivated state\n");
92 return ret;
93 }
Simon Glass6e64ec12018-10-01 12:22:29 -060094 }
Simon Glass6e64ec12018-10-01 12:22:29 -060095
96 return TPM_SUCCESS;
97}
98
Simon Glassabdc7b82018-11-18 14:22:27 -070099u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000100{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200101 const u8 command[101] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000102 0x0, 0xc1, /* TPM_TAG */
103 0x0, 0x0, 0x0, 0x65, /* parameter size */
104 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
105 /* TPM_NV_DATA_PUBLIC->... */
106 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
107 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
108 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
109 0x0, 0x3,
110 0, 0, 0,
111 0x1f,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
114 0x0, 0x3,
115 0, 0, 0,
116 0x1f,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 /* TPM_NV_ATTRIBUTES->... */
119 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
120 0, 0, 0, 0, /* ...->attributes */
121 /* End of TPM_NV_ATTRIBUTES */
122 0, /* bReadSTClear */
123 0, /* bWriteSTClear */
124 0, /* bWriteDefine */
125 0, 0, 0, 0, /* size */
126 };
127 const size_t index_offset = 12;
128 const size_t perm_offset = 70;
129 const size_t size_offset = 77;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200130 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000131
132 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200133 0, command, sizeof(command),
134 index_offset, index,
135 perm_offset, perm,
136 size_offset, size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000137 return TPM_LIB_ERROR;
138
Simon Glassabdc7b82018-11-18 14:22:27 -0700139 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000140}
141
Simon Glassabdc7b82018-11-18 14:22:27 -0700142u32 tpm_nv_set_locked(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -0600143{
Simon Glassabdc7b82018-11-18 14:22:27 -0700144 return tpm_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glass6e64ec12018-10-01 12:22:29 -0600145}
146
Simon Glassabdc7b82018-11-18 14:22:27 -0700147u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000148{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200149 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000150 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
151 };
152 const size_t index_offset = 10;
153 const size_t length_offset = 18;
154 const size_t data_size_offset = 10;
155 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200156 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000157 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200158 u32 data_size;
159 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000160
161 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200162 0, command, sizeof(command),
163 index_offset, index,
164 length_offset, count))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000165 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700166 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000167 if (err)
168 return err;
169 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200170 data_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000171 return TPM_LIB_ERROR;
172 if (data_size > count)
173 return TPM_LIB_ERROR;
174 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200175 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000176 return TPM_LIB_ERROR;
177
178 return 0;
179}
180
Simon Glassabdc7b82018-11-18 14:22:27 -0700181u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
182 u32 length)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000183{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200184 const u8 command[256] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000185 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
186 };
187 const size_t command_size_offset = 2;
188 const size_t index_offset = 10;
189 const size_t length_offset = 18;
190 const size_t data_offset = 22;
191 const size_t write_info_size = 12;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200192 const u32 total_length =
Che-liang Chiou8732b072013-02-28 09:34:57 +0000193 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200194 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000195 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200196 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000197
198 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynalc6179182018-05-15 11:57:00 +0200199 0, command, sizeof(command),
200 command_size_offset, total_length,
201 index_offset, index,
202 length_offset, length,
203 data_offset, data, length))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000204 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700205 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000206 if (err)
207 return err;
208
209 return 0;
210}
211
Simon Glassabdc7b82018-11-18 14:22:27 -0700212uint32_t tpm_set_global_lock(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -0600213{
Heinrich Schuchardtc7cd4af2019-02-05 01:38:41 +0100214 return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0);
Simon Glass6e64ec12018-10-01 12:22:29 -0600215}
216
Simon Glassabdc7b82018-11-18 14:22:27 -0700217u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
218 void *out_digest)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000219{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200220 const u8 command[34] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000221 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
222 };
223 const size_t index_offset = 10;
224 const size_t in_digest_offset = 14;
225 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200226 u8 buf[COMMAND_BUFFER_SIZE];
227 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000228 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200229 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000230
231 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynalc6179182018-05-15 11:57:00 +0200232 0, command, sizeof(command),
233 index_offset, index,
234 in_digest_offset, in_digest,
235 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000236 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700237 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000238 if (err)
239 return err;
240
241 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200242 out_digest_offset, out_digest,
243 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000244 return TPM_LIB_ERROR;
245
246 return 0;
247}
248
Simon Glassabdc7b82018-11-18 14:22:27 -0700249u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000250{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200251 const u8 command[14] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000252 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
253 };
254 const size_t index_offset = 10;
255 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200256 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000257 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200258 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000259
260 if (count < PCR_DIGEST_LENGTH)
261 return TPM_LIB_ERROR;
262
263 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200264 0, command, sizeof(command),
265 index_offset, index))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000266 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700267 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000268 if (err)
269 return err;
270 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200271 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000272 return TPM_LIB_ERROR;
273
274 return 0;
275}
276
Simon Glassabdc7b82018-11-18 14:22:27 -0700277u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000278{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200279 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000280 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
281 };
282 const size_t presence_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200283 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000284
285 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +0200286 0, command, sizeof(command),
287 presence_offset, presence))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000288 return TPM_LIB_ERROR;
289
Simon Glassabdc7b82018-11-18 14:22:27 -0700290 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000291}
292
Simon Glassabdc7b82018-11-18 14:22:27 -0700293u32 tpm_finalise_physical_presence(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -0600294{
295 const u8 command[12] = {
296 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
297 };
298
Simon Glassabdc7b82018-11-18 14:22:27 -0700299 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glass6e64ec12018-10-01 12:22:29 -0600300}
301
Simon Glassabdc7b82018-11-18 14:22:27 -0700302u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000303{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200304 const u8 command[30] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000305 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
306 };
307 const size_t response_size_offset = 2;
308 const size_t data_offset = 10;
309 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200310 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000311 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200312 u32 data_size;
313 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000314
Simon Glassabdc7b82018-11-18 14:22:27 -0700315 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000316 if (err)
317 return err;
318 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200319 response_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000320 return TPM_LIB_ERROR;
321 if (data_size < header_and_checksum_size)
322 return TPM_LIB_ERROR;
323 data_size -= header_and_checksum_size;
324 if (data_size > count)
325 return TPM_LIB_ERROR;
326 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200327 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000328 return TPM_LIB_ERROR;
329
330 return 0;
331}
332
Simon Glassabdc7b82018-11-18 14:22:27 -0700333u32 tpm_force_clear(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000334{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200335 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000336 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
337 };
338
Simon Glassabdc7b82018-11-18 14:22:27 -0700339 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000340}
341
Simon Glassabdc7b82018-11-18 14:22:27 -0700342u32 tpm_physical_enable(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000343{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200344 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000345 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
346 };
347
Simon Glassabdc7b82018-11-18 14:22:27 -0700348 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000349}
350
Simon Glassabdc7b82018-11-18 14:22:27 -0700351u32 tpm_physical_disable(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000352{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200353 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000354 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
355 };
356
Simon Glassabdc7b82018-11-18 14:22:27 -0700357 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000358}
359
Simon Glassabdc7b82018-11-18 14:22:27 -0700360u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000361{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200362 const u8 command[11] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000363 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
364 };
365 const size_t state_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200366 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000367
368 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynalc6179182018-05-15 11:57:00 +0200369 0, command, sizeof(command),
370 state_offset, state))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000371 return TPM_LIB_ERROR;
372
Simon Glassabdc7b82018-11-18 14:22:27 -0700373 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000374}
375
Simon Glassabdc7b82018-11-18 14:22:27 -0700376u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
377 void *cap, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000378{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200379 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000380 0x0, 0xc1, /* TPM_TAG */
381 0x0, 0x0, 0x0, 0x16, /* parameter size */
382 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
383 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
384 0x0, 0x0, 0x0, 0x4, /* subcap size */
385 0x0, 0x0, 0x0, 0x0, /* subcap value */
386 };
387 const size_t cap_area_offset = 10;
388 const size_t sub_cap_offset = 18;
389 const size_t cap_offset = 14;
390 const size_t cap_size_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200391 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000392 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200393 u32 cap_size;
394 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000395
396 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200397 0, command, sizeof(command),
398 cap_area_offset, cap_area,
399 sub_cap_offset, sub_cap))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000400 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700401 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000402 if (err)
403 return err;
404 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200405 cap_size_offset, &cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000406 return TPM_LIB_ERROR;
407 if (cap_size > response_length || cap_size > count)
408 return TPM_LIB_ERROR;
409 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200410 cap_offset, cap, cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000411 return TPM_LIB_ERROR;
412
413 return 0;
414}
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200415
Simon Glassabdc7b82018-11-18 14:22:27 -0700416u32 tpm_get_permanent_flags(struct udevice *dev,
417 struct tpm_permanent_flags *pflags)
Simon Glass2132f972015-08-22 18:31:41 -0600418{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200419 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600420 0x0, 0xc1, /* TPM_TAG */
421 0x0, 0x0, 0x0, 0x16, /* parameter size */
422 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
423 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
424 0x0, 0x0, 0x0, 0x4, /* subcap size */
425 0x0, 0x0, 0x1, 0x8, /* subcap value */
426 };
André Draszike8155df2017-10-03 16:55:51 +0100427 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200428 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
429 u8 response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600430 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200431 u32 err;
432 u32 data_size;
Simon Glass2132f972015-08-22 18:31:41 -0600433
Simon Glassabdc7b82018-11-18 14:22:27 -0700434 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glass2132f972015-08-22 18:31:41 -0600435 if (err)
436 return err;
André Draszike8155df2017-10-03 16:55:51 +0100437 if (unpack_byte_string(response, response_length, "d",
Simon Glass6e64ec12018-10-01 12:22:29 -0600438 data_size_offset, &data_size)) {
439 log_err("Cannot unpack data size\n");
André Draszike8155df2017-10-03 16:55:51 +0100440 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600441 }
442 if (data_size < sizeof(*pflags)) {
443 log_err("Data size too small\n");
André Draszike8155df2017-10-03 16:55:51 +0100444 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600445 }
André Draszike8155df2017-10-03 16:55:51 +0100446 if (unpack_byte_string(response, response_length, "s",
Simon Glass6e64ec12018-10-01 12:22:29 -0600447 data_offset, pflags, sizeof(*pflags))) {
448 log_err("Cannot unpack pflags\n");
André Draszike8155df2017-10-03 16:55:51 +0100449 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600450 }
Simon Glass2132f972015-08-22 18:31:41 -0600451
452 return 0;
453}
454
Simon Glassabdc7b82018-11-18 14:22:27 -0700455u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glass2132f972015-08-22 18:31:41 -0600456{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200457 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600458 0x0, 0xc1, /* TPM_TAG */
459 0x0, 0x0, 0x0, 0x16, /* parameter size */
460 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
461 0x0, 0x0, 0x0, 0x11,
462 0x0, 0x0, 0x0, 0x4,
463 };
464 const size_t index_offset = 18;
465 const size_t perm_offset = 60;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200466 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600467 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200468 u32 err;
Simon Glass2132f972015-08-22 18:31:41 -0600469
470 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
471 index_offset, index))
472 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700473 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glass2132f972015-08-22 18:31:41 -0600474 if (err)
475 return err;
476 if (unpack_byte_string(response, response_length, "d",
477 perm_offset, perm))
478 return TPM_LIB_ERROR;
479
480 return 0;
481}
482
Mario Six7690be32017-01-11 16:00:50 +0100483#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glassabdc7b82018-11-18 14:22:27 -0700484u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six7690be32017-01-11 16:00:50 +0100485{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200486 const u8 command[18] = {
Mario Six7690be32017-01-11 16:00:50 +0100487 0x00, 0xc1, /* TPM_TAG */
488 0x00, 0x00, 0x00, 0x12, /* parameter size */
489 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
490 0x00, 0x00, 0x00, 0x00, /* key handle */
491 0x00, 0x00, 0x00, 0x00, /* resource type */
492 };
493 const size_t key_handle_offset = 10;
494 const size_t resource_type_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200495 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six7690be32017-01-11 16:00:50 +0100496 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200497 u32 err;
Mario Six7690be32017-01-11 16:00:50 +0100498
499 if (pack_byte_string(buf, sizeof(buf), "sdd",
500 0, command, sizeof(command),
501 key_handle_offset, key_handle,
502 resource_type_offset, resource_type))
503 return TPM_LIB_ERROR;
504
Simon Glassabdc7b82018-11-18 14:22:27 -0700505 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six7690be32017-01-11 16:00:50 +0100506 if (err)
507 return err;
508 return 0;
509}
510#endif /* CONFIG_TPM_FLUSH_RESOURCES */
511
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200512#ifdef CONFIG_TPM_AUTH_SESSIONS
513
514/**
515 * Fill an authentication block in a request.
516 * This func can create the first as well as the second auth block (for
517 * double authorized commands).
518 *
519 * @param request pointer to the request (w/ uninitialised auth data)
520 * @param request_len0 length of the request without auth data
521 * @param handles_len length of the handles area in request
522 * @param auth_session pointer to the (valid) auth session to be used
523 * @param request_auth pointer to the auth block of the request to be filled
524 * @param auth authentication data (HMAC key)
525 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200526static u32 create_request_auth(const void *request, size_t request_len0,
527 size_t handles_len,
528 struct session_data *auth_session,
529 void *request_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200530{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200531 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200532 sha1_context hash_ctx;
533 const size_t command_code_offset = 6;
534 const size_t auth_nonce_odd_offset = 4;
535 const size_t auth_continue_offset = 24;
536 const size_t auth_auth_offset = 25;
537
538 if (!auth_session || !auth_session->valid)
539 return TPM_LIB_ERROR;
540
541 sha1_starts(&hash_ctx);
542 sha1_update(&hash_ctx, request + command_code_offset, 4);
543 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
544 sha1_update(&hash_ctx,
545 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
546 request_len0 - TPM_REQUEST_HEADER_LENGTH
547 - handles_len);
548 sha1_finish(&hash_ctx, hmac_data);
549
550 sha1_starts(&hash_ctx);
551 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
552 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
553 sha1_finish(&hash_ctx, auth_session->nonce_odd);
554
555 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
556 0, auth_session->handle,
557 auth_nonce_odd_offset, auth_session->nonce_odd,
558 DIGEST_LENGTH,
559 auth_continue_offset, 1))
560 return TPM_LIB_ERROR;
561 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
562 DIGEST_LENGTH,
563 auth_session->nonce_even,
564 DIGEST_LENGTH,
565 2 * DIGEST_LENGTH,
566 request_auth + auth_nonce_odd_offset,
567 DIGEST_LENGTH + 1))
568 return TPM_LIB_ERROR;
569 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
570 request_auth + auth_auth_offset);
571
572 return TPM_SUCCESS;
573}
574
575/**
576 * Verify an authentication block in a response.
577 * Since this func updates the nonce_even in the session data it has to be
578 * called when receiving a succesfull AUTH response.
579 * This func can verify the first as well as the second auth block (for
580 * double authorized commands).
581 *
582 * @param command_code command code of the request
583 * @param response pointer to the request (w/ uninitialised auth data)
584 * @param handles_len length of the handles area in response
585 * @param auth_session pointer to the (valid) auth session to be used
586 * @param response_auth pointer to the auth block of the response to be verified
587 * @param auth authentication data (HMAC key)
588 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200589static u32 verify_response_auth(u32 command_code, const void *response,
590 size_t response_len0, size_t handles_len,
591 struct session_data *auth_session,
592 const void *response_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200593{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200594 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
595 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200596 sha1_context hash_ctx;
597 const size_t return_code_offset = 6;
598 const size_t auth_continue_offset = 20;
599 const size_t auth_auth_offset = 21;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200600 u8 auth_continue;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200601
602 if (!auth_session || !auth_session->valid)
603 return TPM_AUTHFAIL;
604 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
605 0, command_code))
606 return TPM_LIB_ERROR;
607 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
608 return TPM_LIB_ERROR;
609
610 sha1_starts(&hash_ctx);
611 sha1_update(&hash_ctx, response + return_code_offset, 4);
612 sha1_update(&hash_ctx, hmac_data, 4);
613 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
614 sha1_update(&hash_ctx,
615 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
616 response_len0 - TPM_RESPONSE_HEADER_LENGTH
617 - handles_len);
618 sha1_finish(&hash_ctx, hmac_data);
619
620 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200621 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200622 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
623 DIGEST_LENGTH,
624 response_auth,
625 DIGEST_LENGTH,
626 2 * DIGEST_LENGTH,
627 auth_session->nonce_odd,
628 DIGEST_LENGTH,
629 3 * DIGEST_LENGTH,
630 auth_continue))
631 return TPM_LIB_ERROR;
632
633 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
634 computed_auth);
635
636 if (memcmp(computed_auth, response_auth + auth_auth_offset,
637 DIGEST_LENGTH))
638 return TPM_AUTHFAIL;
639
640 return TPM_SUCCESS;
641}
642
Simon Glassabdc7b82018-11-18 14:22:27 -0700643u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200644{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200645 const u8 command[18] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200646 0x00, 0xc1, /* TPM_TAG */
647 0x00, 0x00, 0x00, 0x00, /* parameter size */
648 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
649 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynal52da18a2018-05-15 11:57:02 +0200650 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200651 };
652 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200653 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200654
655 if (pack_byte_string(request, sizeof(request), "sd",
656 0, command, sizeof(command),
657 req_handle_offset, auth_handle))
658 return TPM_LIB_ERROR;
659 if (oiap_session.valid && oiap_session.handle == auth_handle)
660 oiap_session.valid = 0;
661
Simon Glassabdc7b82018-11-18 14:22:27 -0700662 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200663}
664
Simon Glassabdc7b82018-11-18 14:22:27 -0700665u32 tpm_end_oiap(struct udevice *dev)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200666{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200667 u32 err = TPM_SUCCESS;
Miquel Raynal96cc4e32018-05-15 11:57:03 +0200668
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200669 if (oiap_session.valid)
Simon Glassabdc7b82018-11-18 14:22:27 -0700670 err = tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200671 return err;
672}
673
Simon Glassabdc7b82018-11-18 14:22:27 -0700674u32 tpm_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200675{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200676 const u8 command[10] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200677 0x00, 0xc1, /* TPM_TAG */
678 0x00, 0x00, 0x00, 0x0a, /* parameter size */
679 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
680 };
681 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
682 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200683 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200684 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200685 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200686
687 if (oiap_session.valid)
Simon Glassabdc7b82018-11-18 14:22:27 -0700688 tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200689
Simon Glassabdc7b82018-11-18 14:22:27 -0700690 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200691 if (err)
692 return err;
693 if (unpack_byte_string(response, response_length, "ds",
694 res_auth_handle_offset, &oiap_session.handle,
695 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200696 (u32)DIGEST_LENGTH))
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200697 return TPM_LIB_ERROR;
698 oiap_session.valid = 1;
699 if (auth_handle)
700 *auth_handle = oiap_session.handle;
701 return 0;
702}
703
Simon Glassabdc7b82018-11-18 14:22:27 -0700704u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
705 size_t key_length, const void *parent_key_usage_auth,
706 u32 *key_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200707{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200708 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200709 0x00, 0xc2, /* TPM_TAG */
710 0x00, 0x00, 0x00, 0x00, /* parameter size */
711 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
712 0x00, 0x00, 0x00, 0x00, /* parent handle */
713 };
714 const size_t req_size_offset = 2;
715 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
716 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
717 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200718 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
719 TPM_REQUEST_AUTH_LENGTH];
720 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200721 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200722 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200723
724 if (!oiap_session.valid) {
Simon Glassabdc7b82018-11-18 14:22:27 -0700725 err = tpm_oiap(dev, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200726 if (err)
727 return err;
728 }
729 if (pack_byte_string(request, sizeof(request), "sdds",
730 0, command, sizeof(command),
731 req_size_offset,
732 sizeof(command) + key_length
733 + TPM_REQUEST_AUTH_LENGTH,
734 req_parent_handle_offset, parent_handle,
735 req_key_offset, key, key_length
736 ))
737 return TPM_LIB_ERROR;
738
739 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynalc6179182018-05-15 11:57:00 +0200740 &oiap_session,
741 request + sizeof(command) + key_length,
742 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200743 if (err)
744 return err;
Simon Glassabdc7b82018-11-18 14:22:27 -0700745 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200746 if (err) {
747 if (err == TPM_AUTHFAIL)
748 oiap_session.valid = 0;
749 return err;
750 }
751
752 err = verify_response_auth(0x00000041, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200753 response_length - TPM_RESPONSE_AUTH_LENGTH,
754 4, &oiap_session,
755 response + response_length -
756 TPM_RESPONSE_AUTH_LENGTH,
757 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200758 if (err)
759 return err;
760
761 if (key_handle) {
762 if (unpack_byte_string(response, response_length, "d",
763 res_handle_offset, key_handle))
764 return TPM_LIB_ERROR;
765 }
766
767 return 0;
768}
769
Simon Glassabdc7b82018-11-18 14:22:27 -0700770u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
771 const void *usage_auth, void *pubkey,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200772 size_t *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200773{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200774 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200775 0x00, 0xc2, /* TPM_TAG */
776 0x00, 0x00, 0x00, 0x00, /* parameter size */
777 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
778 0x00, 0x00, 0x00, 0x00, /* key handle */
779 };
780 const size_t req_size_offset = 2;
781 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
782 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200783 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
784 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
785 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200786 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200787 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200788
789 if (!oiap_session.valid) {
Simon Glassabdc7b82018-11-18 14:22:27 -0700790 err = tpm_oiap(dev, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200791 if (err)
792 return err;
793 }
794 if (pack_byte_string(request, sizeof(request), "sdd",
795 0, command, sizeof(command),
796 req_size_offset,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200797 (u32)(sizeof(command)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200798 + TPM_REQUEST_AUTH_LENGTH),
799 req_key_handle_offset, key_handle
800 ))
801 return TPM_LIB_ERROR;
802 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynalc6179182018-05-15 11:57:00 +0200803 request + sizeof(command), usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200804 if (err)
805 return err;
Simon Glassabdc7b82018-11-18 14:22:27 -0700806 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200807 if (err) {
808 if (err == TPM_AUTHFAIL)
809 oiap_session.valid = 0;
810 return err;
811 }
812 err = verify_response_auth(0x00000021, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200813 response_length - TPM_RESPONSE_AUTH_LENGTH,
814 0, &oiap_session,
815 response + response_length -
816 TPM_RESPONSE_AUTH_LENGTH,
817 usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200818 if (err)
819 return err;
820
821 if (pubkey) {
822 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynalc6179182018-05-15 11:57:00 +0200823 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200824 return TPM_LIB_ERROR;
825 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
826 - TPM_RESPONSE_AUTH_LENGTH;
827 memcpy(pubkey, response + res_pubkey_offset,
828 response_length - TPM_RESPONSE_HEADER_LENGTH
829 - TPM_RESPONSE_AUTH_LENGTH);
830 }
831
832 return 0;
833}
834
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100835#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glassabdc7b82018-11-18 14:22:27 -0700836u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
837 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100838{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200839 u16 key_count;
840 u32 key_handles[10];
841 u8 buf[288];
842 u8 *ptr;
843 u32 err;
844 u8 digest[20];
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100845 size_t buf_len;
846 unsigned int i;
847
848 /* fetch list of already loaded keys in the TPM */
Simon Glassabdc7b82018-11-18 14:22:27 -0700849 err = tpm_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
850 sizeof(buf));
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100851 if (err)
852 return -1;
853 key_count = get_unaligned_be16(buf);
854 ptr = buf + 2;
855 for (i = 0; i < key_count; ++i, ptr += 4)
856 key_handles[i] = get_unaligned_be32(ptr);
857
858 /* now search a(/ the) key which we can access with the given auth */
859 for (i = 0; i < key_count; ++i) {
860 buf_len = sizeof(buf);
861 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
862 if (err && err != TPM_AUTHFAIL)
863 return -1;
864 if (err)
865 continue;
866 sha1_csum(buf, buf_len, digest);
867 if (!memcmp(digest, pubkey_digest, 20)) {
868 *handle = key_handles[i];
869 return 0;
870 }
871 }
872 return 1;
873}
874#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
875
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200876#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik3c605022017-10-03 16:55:52 +0100877
Simon Glassabdc7b82018-11-18 14:22:27 -0700878u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
André Draszik3c605022017-10-03 16:55:52 +0100879{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200880 const u8 command[14] = {
André Draszik3c605022017-10-03 16:55:52 +0100881 0x0, 0xc1, /* TPM_TAG */
882 0x0, 0x0, 0x0, 0xe, /* parameter size */
883 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
884 };
885 const size_t length_offset = 10;
886 const size_t data_size_offset = 10;
887 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200888 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik3c605022017-10-03 16:55:52 +0100889 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200890 u32 data_size;
891 u8 *out = data;
André Draszik3c605022017-10-03 16:55:52 +0100892
893 while (count > 0) {
Miquel Raynalb9804e52018-05-15 11:56:59 +0200894 u32 this_bytes = min((size_t)count,
895 sizeof(response) - data_offset);
896 u32 err;
André Draszik3c605022017-10-03 16:55:52 +0100897
898 if (pack_byte_string(buf, sizeof(buf), "sd",
899 0, command, sizeof(command),
900 length_offset, this_bytes))
901 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700902 err = tpm_sendrecv_command(dev, buf, response,
903 &response_length);
André Draszik3c605022017-10-03 16:55:52 +0100904 if (err)
905 return err;
906 if (unpack_byte_string(response, response_length, "d",
907 data_size_offset, &data_size))
908 return TPM_LIB_ERROR;
909 if (data_size > count)
910 return TPM_LIB_ERROR;
911 if (unpack_byte_string(response, response_length, "s",
912 data_offset, out, data_size))
913 return TPM_LIB_ERROR;
914
915 count -= data_size;
916 out += data_size;
917 }
918
919 return 0;
920}