blob: 96900b07a54d5f9841626a2525e17638721a0b71 [file] [log] [blame]
Vadim Bendebury25589e52016-06-28 10:27:16 -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 * Some TPM constants and type definitions for standalone compilation for use
7 * in the firmware
8 */
9
Vadim Bendeburyae703f62016-07-06 09:07:54 -070010#include "rollback_index.h"
Vadim Bendebury25589e52016-06-28 10:27:16 -070011#include "tpm2_marshaling.h"
12#include "utility.h"
Andrey Proninc37f0f82016-07-22 19:33:07 -070013#include "tlcl.h"
Vadim Bendebury25589e52016-06-28 10:27:16 -070014
Vadim Bendebury452973e2016-07-06 08:55:12 -070015static struct tpm2_response *tpm_process_command(TPM_CC command,
16 void *command_body)
Vadim Bendebury25589e52016-06-28 10:27:16 -070017{
18 /* Command/response buffer. */
19 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
20 uint32_t out_size, in_size;
Vadim Bendebury452973e2016-07-06 08:55:12 -070021 struct tpm2_response *response;
Vadim Bendebury25589e52016-06-28 10:27:16 -070022
23 out_size = tpm_marshal_command(command, command_body,
24 cr_buffer, sizeof(cr_buffer));
25 if (out_size < 0) {
26 VBDEBUG(("command %#x, cr size %d\n",
27 command, out_size));
28 return NULL;
29 }
30
31 in_size = sizeof(cr_buffer);
32 if (VbExTpmSendReceive(cr_buffer, out_size,
33 cr_buffer, &in_size) != TPM_SUCCESS) {
Vadim Bendebury452973e2016-07-06 08:55:12 -070034 VBDEBUG(("tpm transaction failed for %#x\n", command));
Vadim Bendebury25589e52016-06-28 10:27:16 -070035 return NULL;
36 }
37
Vadim Bendebury452973e2016-07-06 08:55:12 -070038 response = tpm_unmarshal_response(command, cr_buffer, in_size);
39
40 VBDEBUG(("%s: command %#x, return code %#x\n", __func__, command,
41 response ? response->hdr.tpm_code : -1));
42
43 return response;
Vadim Bendebury25589e52016-06-28 10:27:16 -070044}
45
Andrey Proninc37f0f82016-07-22 19:33:07 -070046static uint32_t tlcl_read_ph_disabled(void)
47{
48 uint32_t rv;
49 TPM_STCLEAR_FLAGS flags;
50
51 rv = TlclGetSTClearFlags(&flags);
52 if (rv != TPM_SUCCESS)
53 return rv;
54
55 tpm_set_ph_disabled(!flags.phEnable);
56
57 return TPM_SUCCESS;
58}
59
Andrey Pronin1becb0d2016-07-06 19:10:46 -070060uint32_t TlclLibInit(void)
61{
Andrey Proninc37f0f82016-07-22 19:33:07 -070062 uint32_t rv;
63
64 rv = VbExTpmInit();
65 if (rv != TPM_SUCCESS)
66 return rv;
67
68 rv = tlcl_read_ph_disabled();
69 if (rv != TPM_SUCCESS) {
70 TlclLibClose();
71 return rv;
72 }
73
74 return TPM_SUCCESS;
Andrey Pronin1becb0d2016-07-06 19:10:46 -070075}
76
77uint32_t TlclLibClose(void)
78{
79 return VbExTpmClose();
80}
81
82uint32_t TlclSendReceive(const uint8_t *request, uint8_t *response,
83 int max_length)
84{
Andrey Pronin5be84672016-07-25 16:28:39 -070085 uint32_t rv, resp_size;
86
87 resp_size = max_length;
88 rv = VbExTpmSendReceive(request, tpm_get_packet_size(request),
89 response, &resp_size);
90
91 return rv ? rv : tpm_get_packet_response_code(response);
Andrey Pronin1becb0d2016-07-06 19:10:46 -070092}
93
94int TlclPacketSize(const uint8_t *packet)
95{
Andrey Pronin5be84672016-07-25 16:28:39 -070096 return tpm_get_packet_size(packet);
Andrey Pronin1becb0d2016-07-06 19:10:46 -070097}
98
99uint32_t TlclStartup(void)
100{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700101 struct tpm2_response *response;
102 struct tpm2_startup_cmd startup;
103
104 startup.startup_type = TPM_SU_CLEAR;
105
106 response = tpm_process_command(TPM2_Startup, &startup);
107 if (!response || response->hdr.tpm_code)
108 return TPM_E_IOERROR;
109
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700110 return TPM_SUCCESS;
111}
112
113uint32_t TlclSaveState(void)
114{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700115 struct tpm2_response *response;
116 struct tpm2_shutdown_cmd shutdown;
117
118 shutdown.shutdown_type = TPM_SU_STATE;
119
120 response = tpm_process_command(TPM2_Shutdown, &shutdown);
121 if (!response || response->hdr.tpm_code)
122 return TPM_E_IOERROR;
123
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700124 return TPM_SUCCESS;
125}
126
127uint32_t TlclResume(void)
128{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700129 struct tpm2_response *response;
130 struct tpm2_startup_cmd startup;
131
132 startup.startup_type = TPM_SU_STATE;
133
134 response = tpm_process_command(TPM2_Startup, &startup);
135 if (!response || response->hdr.tpm_code)
136 return TPM_E_IOERROR;
137
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700138 return TPM_SUCCESS;
139}
140
141uint32_t TlclSelfTestFull(void)
142{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700143 struct tpm2_response *response;
144 struct tpm2_self_test_cmd self_test;
145
146 self_test.full_test = 1;
147
148 response = tpm_process_command(TPM2_SelfTest, &self_test);
149 if (!response || response->hdr.tpm_code)
150 return TPM_E_IOERROR;
151
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700152 return TPM_SUCCESS;
153}
154
155uint32_t TlclContinueSelfTest(void)
156{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700157 struct tpm2_response *response;
158 struct tpm2_self_test_cmd self_test;
159
160 self_test.full_test = 0;
161
162 response = tpm_process_command(TPM2_SelfTest, &self_test);
163 if (!response || response->hdr.tpm_code)
164 return TPM_E_IOERROR;
165
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700166 return TPM_SUCCESS;
167}
168
Andrey Proninc37f0f82016-07-22 19:33:07 -0700169uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700170{
171 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
172 return TPM_SUCCESS;
173}
174
Vadim Bendebury25589e52016-06-28 10:27:16 -0700175/**
176 * Issue a ForceClear. The TPM error code is returned.
177 */
178uint32_t TlclForceClear(void)
179{
Andrey Pronin16cacfa2016-07-25 18:00:47 -0700180 struct tpm2_response *response;
181
182 response = tpm_process_command(TPM2_Clear, NULL);
183 if (!response || response->hdr.tpm_code)
184 return TPM_E_IOERROR;
185
Vadim Bendebury25589e52016-06-28 10:27:16 -0700186 return TPM_SUCCESS;
187}
188
189uint32_t TlclSetDeactivated(uint8_t flag)
190{
191 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
192 return TPM_SUCCESS;
193}
194
195uint32_t TlclSetEnable(void)
196{
197 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
198 return TPM_SUCCESS;
199}
200
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700201uint32_t TlclGetFlags(uint8_t* disable,
202 uint8_t* deactivated,
203 uint8_t *nvlocked)
204{
205 /* For TPM2 the flags are always the same */
206 if (disable)
207 *disable = 0;
208 if (deactivated)
209 *deactivated = 0;
210 if (nvlocked)
211 *nvlocked = 1;
212 return TPM_SUCCESS;
213}
214
215int TlclIsOwned(void)
216{
217 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
218 return 0;
219}
220
221uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
222{
223 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
224 return TPM_SUCCESS;
225}
Vadim Bendebury25589e52016-06-28 10:27:16 -0700226
227/**
228 * Get the permission bits for the NVRAM space with |index|.
229 */
230uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions)
231{
232 *permissions = 0;
233 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
234 return TPM_SUCCESS;
235}
236
Andrey Pronin09606822016-07-22 18:45:07 -0700237static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property,
238 struct get_capability_response **presp)
239{
240 struct tpm2_response *response;
241 struct tpm2_get_capability_cmd getcap;
242
243 getcap.capability = cap;
244 getcap.property = property;
245 getcap.property_count = 1;
246
247 response = tpm_process_command(TPM2_GetCapability, &getcap);
248 if (!response || response->hdr.tpm_code)
249 return TPM_E_IOERROR;
250 *presp = &response->cap;
251
252 return TPM_SUCCESS;
253}
254
255static uint32_t tlcl_get_tpm_property(TPM_PT property, uint32_t *pvalue)
256{
257 uint32_t rv;
258 struct get_capability_response *resp;
259 TPML_TAGGED_TPM_PROPERTY *tpm_prop;
260
261 rv = tlcl_get_capability(TPM_CAP_TPM_PROPERTIES, property, &resp);
262 if (rv != TPM_SUCCESS)
263 return rv;
264
265 if (resp->capability_data.capability != TPM_CAP_TPM_PROPERTIES)
266 return TPM_E_IOERROR;
267
268 tpm_prop = &resp->capability_data.data.tpm_properties;
269
270 if ((tpm_prop->count != 1) ||
271 (tpm_prop->tpm_property[0].property != property))
272 return TPM_E_IOERROR;
273
274 *pvalue = tpm_prop->tpm_property[0].value;
275 return TPM_SUCCESS;
276}
277
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700278uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
279{
Andrey Pronin09606822016-07-22 18:45:07 -0700280 return tlcl_get_tpm_property(TPM_PT_PERMANENT,
281 (uint32_t *)pflags);
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700282}
283
284uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags)
285{
Andrey Pronin09606822016-07-22 18:45:07 -0700286 return tlcl_get_tpm_property(TPM_PT_STARTUP_CLEAR,
287 (uint32_t *)pflags);
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700288}
289
290uint32_t TlclGetOwnership(uint8_t *owned)
291{
Stephen Barber5d996692016-08-04 16:05:01 -0700292 uint32_t rv;
293 TPM_PERMANENT_FLAGS flags;
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700294 *owned = 0;
Stephen Barber5d996692016-08-04 16:05:01 -0700295
296 rv = TlclGetPermanentFlags(&flags);
297 if (rv != TPM_SUCCESS)
298 return rv;
299
300 *owned = flags.ownerAuthSet;
301
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700302 return TPM_SUCCESS;
303}
304
Vadim Bendeburyae703f62016-07-06 09:07:54 -0700305static uint32_t tlcl_lock_nv_write(uint32_t index)
306{
307 struct tpm2_response *response;
308 struct tpm2_nv_write_lock_cmd nv_wl;
309
310 nv_wl.nvIndex = HR_NV_INDEX + index;
311 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
312
313 if (!response || response->hdr.tpm_code)
314 return TPM_E_INTERNAL_INCONSISTENCY;
315
316 return TPM_SUCCESS;
317}
318
319static uint32_t tlcl_disable_platform_hierarchy(void)
320{
321 struct tpm2_response *response;
322 struct tpm2_hierarchy_control_cmd hc;
323
324 hc.enable = TPM_RH_PLATFORM;
325 hc.state = 0;
326
327 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
328
329 if (!response || response->hdr.tpm_code)
330 return TPM_E_INTERNAL_INCONSISTENCY;
331
Andrey Proninc37f0f82016-07-22 19:33:07 -0700332 tpm_set_ph_disabled(1);
Vadim Bendeburyae703f62016-07-06 09:07:54 -0700333 return TPM_SUCCESS;
334}
335
Vadim Bendebury25589e52016-06-28 10:27:16 -0700336/**
Andrey Pronin3e0a3522016-07-22 18:45:37 -0700337 * The name of the function was kept to maintain the existing TPM API, but
338 * TPM2.0 does not use the global lock to protect the FW rollback counter.
339 * Instead it calls WriteLock for the FW NVRAM index to prevent future
340 * writes to it.
341 *
342 * It first checks if the platform hierarchy is already disabled, and does
343 * nothing, if so. Otherwise, WriteLock for the index obviously fails.
344 */
345uint32_t TlclSetGlobalLock(void)
346{
347 if (tpm_is_ph_disabled())
348 return TPM_SUCCESS;
349 else
350 return tlcl_lock_nv_write(FIRMWARE_NV_INDEX);
351}
352
353/**
Vadim Bendebury25589e52016-06-28 10:27:16 -0700354 * Turn off physical presence and locks it off until next reboot. The TPM
355 * error code is returned.
Vadim Bendeburyae703f62016-07-06 09:07:54 -0700356 *
357 * The name of the function was kept to maintain the existing TPM API, but
358 * TPM2.0 does not have to use the Physical Presence concept. Instead it just
359 * removes platform authorization - this makes sure that firmware and kernel
360 * rollback counter spaces can not be modified.
361 *
362 * It also explicitly locks the kernel rollback counter space (the FW rollback
363 * counter space was locked before RW firmware started.)
Vadim Bendebury25589e52016-06-28 10:27:16 -0700364 */
365uint32_t TlclLockPhysicalPresence(void)
366{
Vadim Bendeburyae703f62016-07-06 09:07:54 -0700367 uint32_t rv;
368
Andrey Pronin3e0a3522016-07-22 18:45:37 -0700369 if (tpm_is_ph_disabled())
370 return TPM_SUCCESS;
371
Vadim Bendeburyae703f62016-07-06 09:07:54 -0700372 rv = tlcl_lock_nv_write(KERNEL_NV_INDEX);
373 if (rv == TPM_SUCCESS)
374 rv = tlcl_disable_platform_hierarchy();
375
376 return rv;
Vadim Bendebury25589e52016-06-28 10:27:16 -0700377}
378
379uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
380{
381 struct tpm2_nv_read_cmd nv_readc;
382 struct tpm2_response *response;
383
Randall Spangler664096b2016-10-13 16:16:41 -0700384 memset(&nv_readc, 0, sizeof(nv_readc));
Vadim Bendebury25589e52016-06-28 10:27:16 -0700385
386 nv_readc.nvIndex = HR_NV_INDEX + index;
387 nv_readc.size = length;
388
389 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
390
391 /* Need to map tpm error codes into internal values. */
392 if (!response)
393 return TPM_E_READ_FAILURE;
394
Vadim Bendebury25589e52016-06-28 10:27:16 -0700395 switch (response->hdr.tpm_code) {
396 case 0:
397 break;
398
399 case 0x28b:
400 return TPM_E_BADINDEX;
401
402 default:
403 return TPM_E_READ_FAILURE;
404 }
405
406 if (length > response->nvr.buffer.t.size)
407 return TPM_E_RESPONSE_TOO_LARGE;
408
409 if (length < response->nvr.buffer.t.size)
410 return TPM_E_READ_EMPTY;
411
Randall Spangler664096b2016-10-13 16:16:41 -0700412 memcpy(data, response->nvr.buffer.t.buffer, length);
Vadim Bendebury25589e52016-06-28 10:27:16 -0700413
414 return TPM_SUCCESS;
415}
416
417uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
418{
419 struct tpm2_nv_write_cmd nv_writec;
420 struct tpm2_response *response;
421
Randall Spangler664096b2016-10-13 16:16:41 -0700422 memset(&nv_writec, 0, sizeof(nv_writec));
Vadim Bendebury25589e52016-06-28 10:27:16 -0700423
424 nv_writec.nvIndex = HR_NV_INDEX + index;
425 nv_writec.data.t.size = length;
426 nv_writec.data.t.buffer = data;
427
428 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
429
430 /* Need to map tpm error codes into internal values. */
431 if (!response)
432 return TPM_E_WRITE_FAILURE;
433
Vadim Bendebury25589e52016-06-28 10:27:16 -0700434 return TPM_SUCCESS;
435}
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700436
Andrey Proninc37f0f82016-07-22 19:33:07 -0700437uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length)
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700438{
439 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
440 return TPM_SUCCESS;
441}
442
443uint32_t TlclWriteLock(uint32_t index)
444{
Stephen Barber5d996692016-08-04 16:05:01 -0700445 struct tpm2_nv_write_lock_cmd nv_writelockc;
446 struct tpm2_response *response;
447
Randall Spangler664096b2016-10-13 16:16:41 -0700448 memset(&nv_writelockc, 0, sizeof(nv_writelockc));
Stephen Barber5d996692016-08-04 16:05:01 -0700449
450 nv_writelockc.nvIndex = HR_NV_INDEX | index;
451
452 response = tpm_process_command(TPM2_NV_WriteLock, &nv_writelockc);
453
454 /* Need to map tpm error codes into internal values. */
455 if (!response)
456 return TPM_E_WRITE_FAILURE;
457
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700458 return TPM_SUCCESS;
459}
460
461uint32_t TlclReadLock(uint32_t index)
462{
Stephen Barber5d996692016-08-04 16:05:01 -0700463 struct tpm2_nv_read_lock_cmd nv_readlockc;
464 struct tpm2_response *response;
465
Randall Spangler664096b2016-10-13 16:16:41 -0700466 memset(&nv_readlockc, 0, sizeof(nv_readlockc));
Stephen Barber5d996692016-08-04 16:05:01 -0700467
468 nv_readlockc.nvIndex = HR_NV_INDEX | index;
469
470 response = tpm_process_command(TPM2_NV_ReadLock, &nv_readlockc);
471
472 /* Need to map tpm error codes into internal values. */
473 if (!response)
474 return TPM_E_READ_FAILURE;
475
Andrey Pronin1becb0d2016-07-06 19:10:46 -0700476 return TPM_SUCCESS;
477}
478
479uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size)
480{
481 *size = 0;
482 VBDEBUG(("%s called, NOT YET IMPLEMENTED\n", __func__));
483 return TPM_E_IOERROR;
484}