blob: d9f9d37533b43c10784e6c4e899873908a5b1d68 [file] [log] [blame]
Vadim Bendebury245d4572016-04-05 16:01:57 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <console/console.h>
8#include <endian.h>
9#include <lib/tpm2_tlcl_structures.h>
10#include <string.h>
11#include <tpm.h>
12#include <vb2_api.h>
13
14#include "tpm2_marshaling.h"
15
16/*
17 * This file provides interface between firmware and TPM2 device. The TPM1.2
18 * API was copied as is and relevant functions modified to comply with the
19 * TPM2 specification.
20 */
21
22static void *tpm_process_command(TPM_CC command, void *command_body)
23{
24 size_t out_size, in_size;
25 /* Command/response buffer. */
26 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
27
28 out_size = tpm_marshal_command(command, command_body,
29 cr_buffer, sizeof(cr_buffer));
30 if (out_size < 0) {
31 printk(BIOS_ERR, "command %#x, cr size %zd\n",
32 command, out_size);
33 return NULL;
34 }
35
36 in_size = sizeof(cr_buffer);
37 if (tis_sendrecv(cr_buffer, out_size,
38 cr_buffer, &in_size)) {
39 printk(BIOS_ERR, "tpm transaction failed\n");
40 return NULL;
41 }
42
43 return tpm_unmarshal_response(command, cr_buffer, in_size);
44}
45
46
47uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
48{
49 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
50 return TPM_SUCCESS;
51}
52
53uint32_t tlcl_resume(void)
54{
55 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
56 return TPM_SUCCESS;
57}
58
59uint32_t tlcl_assert_physical_presence(void)
60{
61 /*
62 * Nothing to do on TPM2 for this, use platform hierarchy availability
63 * instead.
64 */
65 return TPM_SUCCESS;
66}
67
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070068/*
69 * The caller will provide the digest in a 32 byte buffer, let's consider it a
70 * sha256 digest.
71 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070072uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
73 uint8_t *out_digest)
74{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070075 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
76 struct tpm2_response *response;
77
78 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
79 pcr_ext_cmd.digests.count = 1;
80 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
81 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
82 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
83
84 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
85
86 printk(BIOS_INFO, "%s: response is %x\n",
87 __func__, response ? response->hdr.tpm_code : -1);
88 if (!response || response->hdr.tpm_code)
89 return TPM_E_IOERROR;
90
Vadim Bendebury245d4572016-04-05 16:01:57 -070091 return TPM_SUCCESS;
92}
93
94uint32_t tlcl_finalize_physical_presence(void)
95{
96 /* Nothing needs to be done with tpm2. */
97 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
98 return TPM_SUCCESS;
99}
100
101uint32_t tlcl_force_clear(void)
102{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700103 struct tpm2_response *response;
104
105 response = tpm_process_command(TPM2_Clear, NULL);
106 printk(BIOS_INFO, "%s: response is %x\n",
107 __func__, response ? response->hdr.tpm_code : -1);
108
109 if (!response || response->hdr.tpm_code)
110 return TPM_E_IOERROR;
111
Vadim Bendebury245d4572016-04-05 16:01:57 -0700112 return TPM_SUCCESS;
113}
114
115uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
116 uint8_t *nvlocked)
117{
118 /*
119 * TPM2 does not map directly into these flags TPM1.2 based firmware
120 * expects to be able to retrieve.
121 *
122 * In any case, if any of these conditions are present, the following
123 * firmware flow would be interrupted and will have a chance to report
124 * an error. Let's just hardcode an "All OK" response for now.
125 */
126
127 if (disable)
128 *disable = 0;
129
130 if (nvlocked)
131 *nvlocked = 1;
132
133 if (deactivated)
134 *deactivated = 0;
135
136 return TPM_SUCCESS;
137}
138
139uint32_t tlcl_lib_init(void)
140{
141 /*
142 * This function is called directly by vboot, uses vboot return
143 * types.
144 */
145 if (tis_init())
146 return VB2_ERROR_UNKNOWN;
147 if (tis_open())
148 return VB2_ERROR_UNKNOWN;
149 return VB2_SUCCESS;
150}
151
152uint32_t tlcl_physical_presence_cmd_enable(void)
153{
154 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
155 return TPM_SUCCESS;
156}
157
158uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
159{
160 struct tpm2_nv_read_cmd nv_readc;
161 struct tpm2_response *response;
162
163 memset(&nv_readc, 0, sizeof(nv_readc));
164
165 nv_readc.nvIndex = HR_NV_INDEX + index;
166 nv_readc.size = length;
167
168 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
169
170 /* Need to map tpm error codes into internal values. */
171 if (!response)
172 return TPM_E_READ_FAILURE;
173
174 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
175 __FILE__, __LINE__, index, response->hdr.tpm_code);
176 switch (response->hdr.tpm_code) {
177 case 0:
178 break;
179
180 case 0x28b:
181 return TPM_E_BADINDEX;
182
183 default:
184 return TPM_E_READ_FAILURE;
185 }
186
187 if (length > response->nvr.buffer.t.size)
188 return TPM_E_RESPONSE_TOO_LARGE;
189
190 if (length < response->nvr.buffer.t.size)
191 return TPM_E_READ_EMPTY;
192
193 memcpy(data, response->nvr.buffer.t.buffer, length);
194
195 return TPM_SUCCESS;
196}
197
198uint32_t tlcl_self_test_full(void)
199{
200 struct tpm2_self_test st;
201 struct tpm2_response *response;
202
203 st.yes_no = 1;
204
205 response = tpm_process_command(TPM2_SelfTest, &st);
206 printk(BIOS_INFO, "%s: response is %x\n",
207 __func__, response ? response->hdr.tpm_code : -1);
208 return TPM_SUCCESS;
209}
210
211uint32_t tlcl_set_deactivated(uint8_t flag)
212{
213 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
214 return TPM_SUCCESS;
215}
216
217uint32_t tlcl_set_enable(void)
218{
219 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
220 return TPM_SUCCESS;
221}
222
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700223uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700224{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700225 struct tpm2_response *response;
226 /* TPM Wll reject attempts to write at non-defined index. */
227 struct tpm2_nv_write_lock_cmd nv_wl = {
228 .nvIndex = HR_NV_INDEX + index,
229 };
230
231 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
232
233 printk(BIOS_INFO, "%s: response is %x\n",
234 __func__, response ? response->hdr.tpm_code : -1);
235
236 if (!response || response->hdr.tpm_code)
237 return TPM_E_IOERROR;
238
Vadim Bendebury245d4572016-04-05 16:01:57 -0700239 return TPM_SUCCESS;
240}
241
242uint32_t tlcl_startup(void)
243{
244 struct tpm2_startup startup;
245 struct tpm2_response *response;
246
247 startup.startup_type = TPM_SU_CLEAR;
248 response = tpm_process_command(TPM2_Startup, &startup);
249 if (response && response->hdr.tpm_code &&
250 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
251 printk(BIOS_INFO, "startup return code is %x\n",
252 response->hdr.tpm_code);
253 return TPM_E_IOERROR;
254 }
255 return TPM_SUCCESS;
256}
257
258uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
259{
260 struct tpm2_nv_write_cmd nv_writec;
261 struct tpm2_response *response;
262
263 memset(&nv_writec, 0, sizeof(nv_writec));
264
265 nv_writec.nvIndex = HR_NV_INDEX + index;
266 nv_writec.data.t.size = length;
267 nv_writec.data.t.buffer = data;
268
269 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
270
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700271 printk(BIOS_INFO, "%s: response is %x\n",
272 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700273
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700274 /* Need to map tpm error codes into internal values. */
275 if (!response || response->hdr.tpm_code)
276 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700277
278 return TPM_SUCCESS;
279}
280
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700281uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700282{
283 struct tpm2_nv_define_space_cmd nvds_cmd;
284 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700285 /*
286 * This policy digest was obtained using TPM2_PolicyPCR selecting only
287 * PCR_0 with a value of all zeros.
288 */
289 static const uint8_t pcr0_unchanged_policy[] = {
290 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
291 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
292 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
293 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
294 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700295
296 /* Prepare the define space command structure. */
297 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
298
299 nvds_cmd.publicInfo.dataSize = space_size;
300 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
301 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
302
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700303 /* Attributes common for all NV ram spaces used by firmware. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700304 nvds_cmd.publicInfo.attributes.TPMA_NV_PPWRITE = 1;
305 nvds_cmd.publicInfo.attributes.TPMA_NV_AUTHREAD = 1;
306 nvds_cmd.publicInfo.attributes.TPMA_NV_PPREAD = 1;
307 nvds_cmd.publicInfo.attributes.TPMA_NV_PLATFORMCREATE = 1;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700308 nvds_cmd.publicInfo.attributes.TPMA_NV_WRITE_STCLEAR = 1;
309 nvds_cmd.publicInfo.attributes.TPMA_NV_POLICY_DELETE = 1;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700310
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700311 /*
312 * Use policy digest based on default pcr0 value. This makes sure that
313 * the space can not be deleted as soon as PCR0 value has been
314 * extended from default.
315 */
316 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
317 nvds_cmd.publicInfo.authPolicy.t.size = sizeof(pcr0_unchanged_policy);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700318
319 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
320 printk(BIOS_INFO, "%s: response is %x\n",
321 __func__, response ? response->hdr.tpm_code : -1);
322
323 if (!response)
324 return TPM_E_NO_DEVICE;
325
326 return response->hdr.tpm_code ? TPM_E_INTERNAL_INCONSISTENCY :
327 TPM_SUCCESS;
328}