blob: 30034000339ba1f26344e249d1ba21057957bcce [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
68uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
69 uint8_t *out_digest)
70{
71 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
72 return TPM_SUCCESS;
73}
74
75uint32_t tlcl_finalize_physical_presence(void)
76{
77 /* Nothing needs to be done with tpm2. */
78 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
79 return TPM_SUCCESS;
80}
81
82uint32_t tlcl_force_clear(void)
83{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -070084 struct tpm2_response *response;
85
86 response = tpm_process_command(TPM2_Clear, NULL);
87 printk(BIOS_INFO, "%s: response is %x\n",
88 __func__, response ? response->hdr.tpm_code : -1);
89
90 if (!response || response->hdr.tpm_code)
91 return TPM_E_IOERROR;
92
Vadim Bendebury245d4572016-04-05 16:01:57 -070093 return TPM_SUCCESS;
94}
95
96uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
97 uint8_t *nvlocked)
98{
99 /*
100 * TPM2 does not map directly into these flags TPM1.2 based firmware
101 * expects to be able to retrieve.
102 *
103 * In any case, if any of these conditions are present, the following
104 * firmware flow would be interrupted and will have a chance to report
105 * an error. Let's just hardcode an "All OK" response for now.
106 */
107
108 if (disable)
109 *disable = 0;
110
111 if (nvlocked)
112 *nvlocked = 1;
113
114 if (deactivated)
115 *deactivated = 0;
116
117 return TPM_SUCCESS;
118}
119
120uint32_t tlcl_lib_init(void)
121{
122 /*
123 * This function is called directly by vboot, uses vboot return
124 * types.
125 */
126 if (tis_init())
127 return VB2_ERROR_UNKNOWN;
128 if (tis_open())
129 return VB2_ERROR_UNKNOWN;
130 return VB2_SUCCESS;
131}
132
133uint32_t tlcl_physical_presence_cmd_enable(void)
134{
135 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
136 return TPM_SUCCESS;
137}
138
139uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
140{
141 struct tpm2_nv_read_cmd nv_readc;
142 struct tpm2_response *response;
143
144 memset(&nv_readc, 0, sizeof(nv_readc));
145
146 nv_readc.nvIndex = HR_NV_INDEX + index;
147 nv_readc.size = length;
148
149 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
150
151 /* Need to map tpm error codes into internal values. */
152 if (!response)
153 return TPM_E_READ_FAILURE;
154
155 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
156 __FILE__, __LINE__, index, response->hdr.tpm_code);
157 switch (response->hdr.tpm_code) {
158 case 0:
159 break;
160
161 case 0x28b:
162 return TPM_E_BADINDEX;
163
164 default:
165 return TPM_E_READ_FAILURE;
166 }
167
168 if (length > response->nvr.buffer.t.size)
169 return TPM_E_RESPONSE_TOO_LARGE;
170
171 if (length < response->nvr.buffer.t.size)
172 return TPM_E_READ_EMPTY;
173
174 memcpy(data, response->nvr.buffer.t.buffer, length);
175
176 return TPM_SUCCESS;
177}
178
179uint32_t tlcl_self_test_full(void)
180{
181 struct tpm2_self_test st;
182 struct tpm2_response *response;
183
184 st.yes_no = 1;
185
186 response = tpm_process_command(TPM2_SelfTest, &st);
187 printk(BIOS_INFO, "%s: response is %x\n",
188 __func__, response ? response->hdr.tpm_code : -1);
189 return TPM_SUCCESS;
190}
191
192uint32_t tlcl_set_deactivated(uint8_t flag)
193{
194 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
195 return TPM_SUCCESS;
196}
197
198uint32_t tlcl_set_enable(void)
199{
200 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
201 return TPM_SUCCESS;
202}
203
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700204uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700205{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700206 struct tpm2_response *response;
207 /* TPM Wll reject attempts to write at non-defined index. */
208 struct tpm2_nv_write_lock_cmd nv_wl = {
209 .nvIndex = HR_NV_INDEX + index,
210 };
211
212 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
213
214 printk(BIOS_INFO, "%s: response is %x\n",
215 __func__, response ? response->hdr.tpm_code : -1);
216
217 if (!response || response->hdr.tpm_code)
218 return TPM_E_IOERROR;
219
Vadim Bendebury245d4572016-04-05 16:01:57 -0700220 return TPM_SUCCESS;
221}
222
223uint32_t tlcl_startup(void)
224{
225 struct tpm2_startup startup;
226 struct tpm2_response *response;
227
228 startup.startup_type = TPM_SU_CLEAR;
229 response = tpm_process_command(TPM2_Startup, &startup);
230 if (response && response->hdr.tpm_code &&
231 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
232 printk(BIOS_INFO, "startup return code is %x\n",
233 response->hdr.tpm_code);
234 return TPM_E_IOERROR;
235 }
236 return TPM_SUCCESS;
237}
238
239uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
240{
241 struct tpm2_nv_write_cmd nv_writec;
242 struct tpm2_response *response;
243
244 memset(&nv_writec, 0, sizeof(nv_writec));
245
246 nv_writec.nvIndex = HR_NV_INDEX + index;
247 nv_writec.data.t.size = length;
248 nv_writec.data.t.buffer = data;
249
250 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
251
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700252 printk(BIOS_INFO, "%s: response is %x\n",
253 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700254
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700255 /* Need to map tpm error codes into internal values. */
256 if (!response || response->hdr.tpm_code)
257 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700258
259 return TPM_SUCCESS;
260}
261
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700262uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700263{
264 struct tpm2_nv_define_space_cmd nvds_cmd;
265 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700266 /*
267 * This policy digest was obtained using TPM2_PolicyPCR selecting only
268 * PCR_0 with a value of all zeros.
269 */
270 static const uint8_t pcr0_unchanged_policy[] = {
271 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
272 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
273 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
274 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
275 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700276
277 /* Prepare the define space command structure. */
278 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
279
280 nvds_cmd.publicInfo.dataSize = space_size;
281 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
282 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
283
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700284 /* Attributes common for all NV ram spaces used by firmware. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700285 nvds_cmd.publicInfo.attributes.TPMA_NV_PPWRITE = 1;
286 nvds_cmd.publicInfo.attributes.TPMA_NV_AUTHREAD = 1;
287 nvds_cmd.publicInfo.attributes.TPMA_NV_PPREAD = 1;
288 nvds_cmd.publicInfo.attributes.TPMA_NV_PLATFORMCREATE = 1;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700289 nvds_cmd.publicInfo.attributes.TPMA_NV_WRITE_STCLEAR = 1;
290 nvds_cmd.publicInfo.attributes.TPMA_NV_POLICY_DELETE = 1;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700291
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700292 /*
293 * Use policy digest based on default pcr0 value. This makes sure that
294 * the space can not be deleted as soon as PCR0 value has been
295 * extended from default.
296 */
297 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
298 nvds_cmd.publicInfo.authPolicy.t.size = sizeof(pcr0_unchanged_policy);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700299
300 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
301 printk(BIOS_INFO, "%s: response is %x\n",
302 __func__, response ? response->hdr.tpm_code : -1);
303
304 if (!response)
305 return TPM_E_NO_DEVICE;
306
307 return response->hdr.tpm_code ? TPM_E_INTERNAL_INCONSISTENCY :
308 TPM_SUCCESS;
309}