blob: 8412ed0784f7a3ab45d2b3ae6689039f437e257f [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{
84 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
85 return TPM_SUCCESS;
86}
87
88uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
89 uint8_t *nvlocked)
90{
91 /*
92 * TPM2 does not map directly into these flags TPM1.2 based firmware
93 * expects to be able to retrieve.
94 *
95 * In any case, if any of these conditions are present, the following
96 * firmware flow would be interrupted and will have a chance to report
97 * an error. Let's just hardcode an "All OK" response for now.
98 */
99
100 if (disable)
101 *disable = 0;
102
103 if (nvlocked)
104 *nvlocked = 1;
105
106 if (deactivated)
107 *deactivated = 0;
108
109 return TPM_SUCCESS;
110}
111
112uint32_t tlcl_lib_init(void)
113{
114 /*
115 * This function is called directly by vboot, uses vboot return
116 * types.
117 */
118 if (tis_init())
119 return VB2_ERROR_UNKNOWN;
120 if (tis_open())
121 return VB2_ERROR_UNKNOWN;
122 return VB2_SUCCESS;
123}
124
125uint32_t tlcl_physical_presence_cmd_enable(void)
126{
127 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
128 return TPM_SUCCESS;
129}
130
131uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
132{
133 struct tpm2_nv_read_cmd nv_readc;
134 struct tpm2_response *response;
135
136 memset(&nv_readc, 0, sizeof(nv_readc));
137
138 nv_readc.nvIndex = HR_NV_INDEX + index;
139 nv_readc.size = length;
140
141 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
142
143 /* Need to map tpm error codes into internal values. */
144 if (!response)
145 return TPM_E_READ_FAILURE;
146
147 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
148 __FILE__, __LINE__, index, response->hdr.tpm_code);
149 switch (response->hdr.tpm_code) {
150 case 0:
151 break;
152
153 case 0x28b:
154 return TPM_E_BADINDEX;
155
156 default:
157 return TPM_E_READ_FAILURE;
158 }
159
160 if (length > response->nvr.buffer.t.size)
161 return TPM_E_RESPONSE_TOO_LARGE;
162
163 if (length < response->nvr.buffer.t.size)
164 return TPM_E_READ_EMPTY;
165
166 memcpy(data, response->nvr.buffer.t.buffer, length);
167
168 return TPM_SUCCESS;
169}
170
171uint32_t tlcl_self_test_full(void)
172{
173 struct tpm2_self_test st;
174 struct tpm2_response *response;
175
176 st.yes_no = 1;
177
178 response = tpm_process_command(TPM2_SelfTest, &st);
179 printk(BIOS_INFO, "%s: response is %x\n",
180 __func__, response ? response->hdr.tpm_code : -1);
181 return TPM_SUCCESS;
182}
183
184uint32_t tlcl_set_deactivated(uint8_t flag)
185{
186 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
187 return TPM_SUCCESS;
188}
189
190uint32_t tlcl_set_enable(void)
191{
192 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
193 return TPM_SUCCESS;
194}
195
196uint32_t tlcl_set_global_lock(void)
197{
198 /*
199 * This is where the locking of the RO NVram index is supposed to
200 * happen. The most likely way to achieve it is to extend PCR used for
201 * policy when defining this space.
202 */
203 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
204 return TPM_SUCCESS;
205}
206uint32_t tlcl_set_nv_locked(void)
207{
208 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
209 return TPM_SUCCESS;
210}
211
212uint32_t tlcl_startup(void)
213{
214 struct tpm2_startup startup;
215 struct tpm2_response *response;
216
217 startup.startup_type = TPM_SU_CLEAR;
218 response = tpm_process_command(TPM2_Startup, &startup);
219 if (response && response->hdr.tpm_code &&
220 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
221 printk(BIOS_INFO, "startup return code is %x\n",
222 response->hdr.tpm_code);
223 return TPM_E_IOERROR;
224 }
225 return TPM_SUCCESS;
226}
227
228uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
229{
230 struct tpm2_nv_write_cmd nv_writec;
231 struct tpm2_response *response;
232
233 memset(&nv_writec, 0, sizeof(nv_writec));
234
235 nv_writec.nvIndex = HR_NV_INDEX + index;
236 nv_writec.data.t.size = length;
237 nv_writec.data.t.buffer = data;
238
239 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
240
241 /* Need to map tpm error codes into internal values. */
242 if (!response)
243 return TPM_E_WRITE_FAILURE;
244
245 printk(BIOS_INFO, "%s:%d return code %x\n", __func__, __LINE__,
246 response->hdr.tpm_code);
247
248 return TPM_SUCCESS;
249}
250
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700251uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700252{
253 struct tpm2_nv_define_space_cmd nvds_cmd;
254 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700255 /*
256 * This policy digest was obtained using TPM2_PolicyPCR selecting only
257 * PCR_0 with a value of all zeros.
258 */
259 static const uint8_t pcr0_unchanged_policy[] = {
260 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
261 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
262 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
263 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
264 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700265
266 /* Prepare the define space command structure. */
267 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
268
269 nvds_cmd.publicInfo.dataSize = space_size;
270 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
271 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
272
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700273 /* Attributes common for all NV ram spaces used by firmware. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700274 nvds_cmd.publicInfo.attributes.TPMA_NV_PPWRITE = 1;
275 nvds_cmd.publicInfo.attributes.TPMA_NV_AUTHREAD = 1;
276 nvds_cmd.publicInfo.attributes.TPMA_NV_PPREAD = 1;
277 nvds_cmd.publicInfo.attributes.TPMA_NV_PLATFORMCREATE = 1;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700278 nvds_cmd.publicInfo.attributes.TPMA_NV_WRITE_STCLEAR = 1;
279 nvds_cmd.publicInfo.attributes.TPMA_NV_POLICY_DELETE = 1;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700280
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700281 /*
282 * Use policy digest based on default pcr0 value. This makes sure that
283 * the space can not be deleted as soon as PCR0 value has been
284 * extended from default.
285 */
286 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
287 nvds_cmd.publicInfo.authPolicy.t.size = sizeof(pcr0_unchanged_policy);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700288
289 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
290 printk(BIOS_INFO, "%s: response is %x\n",
291 __func__, response ? response->hdr.tpm_code : -1);
292
293 if (!response)
294 return TPM_E_NO_DEVICE;
295
296 return response->hdr.tpm_code ? TPM_E_INTERNAL_INCONSISTENCY :
297 TPM_SUCCESS;
298}