1 /* Copyright 2016 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Some TPM constants and type definitions for standalone compilation for use
6 * in the firmware
7 */
8
9 #include "2common.h"
10 #include "2sysincludes.h"
11 #include "tlcl.h"
12 #include "tpm2_marshaling.h"
13
14 /*
15 * TODO(chromium:1032930): Originally accessed by including secdata_tpm.h.
16 * This file moved to depthcharge, and vboot shouldn't need to know the indices
17 * of different TPM spaces anyways. But since the vboot TPM 2.0 implementation
18 * uses TPM 1.2 primitives as its API, TlclSetGlobalLock (TPM 1.2) needs to use
19 * the firmware space index to emulate a TlclWriteLock call (TPM 2.0).
20 */
21 #define FIRMWARE_NV_INDEX 0x1007
22
23 /* Global buffer for deserialized responses. */
24 struct tpm2_response tpm2_resp;
25
26 /*
27 * Serializes and sends the command, gets back the response and
28 * parses it into the provided buffer.
29 *
30 * @command: command code.
31 * @command_body: command-specific payload.
32 * @response: pointer to the buffer to place the parsed response to.
33 *
34 * Returns the result of processing the command:
35 * - if an error happened at marshaling, sending, receiving or unmarshaling
36 * stages, returns the error code;
37 * - if the received response was successfully unmarshaled, returns success
38 * regardless of the received response code.
39 */
tpm_get_response(TPM_CC command,void * command_body,struct tpm2_response * response)40 static uint32_t tpm_get_response(TPM_CC command,
41 void *command_body,
42 struct tpm2_response *response)
43 {
44 /* Command/response buffer. */
45 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
46 int out_size;
47 uint32_t res;
48 uint32_t in_size;
49
50 out_size = tpm_marshal_command(command, command_body,
51 cr_buffer, sizeof(cr_buffer));
52 if (out_size < 0) {
53 VB2_DEBUG("command %#x, failed to serialize\n", command);
54 return TPM_E_WRITE_FAILURE;
55 }
56
57 in_size = sizeof(cr_buffer);
58 res = vb2ex_tpm_send_recv(cr_buffer, out_size, cr_buffer, &in_size);
59 if (res != TPM_SUCCESS) {
60 VB2_DEBUG("tpm transaction failed for %#x with error %#x\n",
61 command, res);
62 return res;
63 }
64
65 if (tpm_unmarshal_response(command, cr_buffer, in_size, response) < 0) {
66 VB2_DEBUG("command %#x, failed to parse response\n", command);
67 return TPM_E_READ_FAILURE;
68 }
69
70 VB2_DEBUG("command %#x, return code %#x\n", command,
71 response->hdr.tpm_code);
72
73 return TPM_SUCCESS;
74 }
75
76 /*
77 * Same as tpm_get_response() but, if the response was successfully received,
78 * returns the received response code. The set of errors returned by the
79 * communication stack doesn't overlap with the set of errors returned by the
80 * TPM, so it's always possible to distinguish the two. In case of communication
81 * errors, the caller should not check other fields of response, as the response
82 * is likely not filled. In any case, it is recommended that callers, who need
83 * to work with response fields even if a non-zero response code was received
84 * from the TPM, use tpm_get_response() and explicitly check the response code
85 * themselves.
86 */
tpm_send_receive(TPM_CC command,void * command_body,struct tpm2_response * response)87 static uint32_t tpm_send_receive(TPM_CC command,
88 void *command_body,
89 struct tpm2_response *response)
90 {
91 uint32_t rv = tpm_get_response(command, command_body, response);
92
93 return rv ? rv : response->hdr.tpm_code;
94 }
95
96 /*
97 * Same as tpm_send_receive() for callers that care only about the return code.
98 */
tpm_get_response_code(TPM_CC command,void * command_body)99 static uint32_t tpm_get_response_code(TPM_CC command, void *command_body)
100 {
101 return tpm_send_receive(command, command_body, &tpm2_resp);
102 }
103
tlcl_read_ph_disabled(void)104 static uint32_t tlcl_read_ph_disabled(void)
105 {
106 uint32_t rv;
107 TPM_STCLEAR_FLAGS flags;
108
109 rv = TlclGetSTClearFlags(&flags);
110 if (rv == TPM_SUCCESS)
111 tpm_set_ph_disabled(!flags.phEnable);
112
113 return rv;
114 }
115
TlclLibInit(void)116 uint32_t TlclLibInit(void)
117 {
118 uint32_t rv;
119
120 rv = vb2ex_tpm_init();
121 if (rv != TPM_SUCCESS)
122 return rv;
123
124 rv = tlcl_read_ph_disabled();
125 if (rv != TPM_SUCCESS)
126 TlclLibClose();
127
128 return rv;
129 }
130
TlclLibClose(void)131 uint32_t TlclLibClose(void)
132 {
133 return vb2ex_tpm_close();
134 }
135
TlclSendReceive(const uint8_t * request,uint8_t * response,int max_length)136 uint32_t TlclSendReceive(const uint8_t *request, uint8_t *response,
137 int max_length)
138 {
139 uint32_t rv, resp_size;
140
141 resp_size = max_length;
142 rv = vb2ex_tpm_send_recv(request, tpm_get_packet_size(request),
143 response, &resp_size);
144
145 return rv ? rv : tpm_get_packet_response_code(response);
146 }
147
TlclPacketSize(const uint8_t * packet)148 int TlclPacketSize(const uint8_t *packet)
149 {
150 return tpm_get_packet_size(packet);
151 }
152
TlclStartup(void)153 uint32_t TlclStartup(void)
154 {
155 struct tpm2_startup_cmd startup;
156
157 startup.startup_type = TPM_SU_CLEAR;
158
159 return tpm_get_response_code(TPM2_Startup, &startup);
160 }
161
TlclSaveState(void)162 uint32_t TlclSaveState(void)
163 {
164 struct tpm2_shutdown_cmd shutdown;
165
166 shutdown.shutdown_type = TPM_SU_STATE;
167
168 return tpm_get_response_code(TPM2_Shutdown, &shutdown);
169 }
170
TlclResume(void)171 uint32_t TlclResume(void)
172 {
173 struct tpm2_startup_cmd startup;
174
175 startup.startup_type = TPM_SU_STATE;
176
177 return tpm_get_response_code(TPM2_Startup, &startup);
178 }
179
TlclSelfTestFull(void)180 uint32_t TlclSelfTestFull(void)
181 {
182 struct tpm2_self_test_cmd self_test;
183
184 self_test.full_test = 1;
185
186 return tpm_get_response_code(TPM2_SelfTest, &self_test);
187 }
188
TlclContinueSelfTest(void)189 uint32_t TlclContinueSelfTest(void)
190 {
191 struct tpm2_self_test_cmd self_test;
192
193 self_test.full_test = 0;
194
195 return tpm_get_response_code(TPM2_SelfTest, &self_test);
196 }
197
TlclDefineSpace(uint32_t index,uint32_t perm,uint32_t size)198 uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
199 {
200 return TlclDefineSpaceEx(NULL, 0, index, perm, size, NULL, 0);
201 }
202
203 #ifdef CHROMEOS_ENVIRONMENT
204
TlclUndefineSpace(uint32_t index)205 uint32_t TlclUndefineSpace(uint32_t index)
206 {
207 return TlclUndefineSpaceEx(NULL, 0, index);
208 }
209
TlclUndefineSpaceEx(const uint8_t * owner_auth,uint32_t owner_auth_size,uint32_t index)210 uint32_t TlclUndefineSpaceEx(const uint8_t* owner_auth,
211 uint32_t owner_auth_size,
212 uint32_t index)
213 {
214 struct tpm2_nv_undefine_space_cmd undefine_space;
215 uint32_t permissions;
216 uint32_t rv;
217
218 /* Authentication support is not implemented. */
219 VB2_ASSERT(owner_auth == NULL && owner_auth_size == 0);
220
221 /* get the publicInfo of index */
222 rv = TlclGetPermissions(index, &permissions);
223 if (rv != TPM_SUCCESS) {
224 return rv;
225 }
226 undefine_space.nvIndex = HR_NV_INDEX + index;
227 undefine_space.use_platform_auth =
228 (permissions & TPMA_NV_PLATFORMCREATE) > 0;
229 return tpm_get_response_code(TPM2_NV_UndefineSpace, &undefine_space);
230 }
231
232 #endif /* CHROMEOS_ENVIRONMENT */
233
TlclDefineSpaceEx(const uint8_t * owner_auth,uint32_t owner_auth_size,uint32_t index,uint32_t perm,uint32_t size,const void * auth_policy,uint32_t auth_policy_size)234 uint32_t TlclDefineSpaceEx(const uint8_t* owner_auth, uint32_t owner_auth_size,
235 uint32_t index, uint32_t perm, uint32_t size,
236 const void* auth_policy, uint32_t auth_policy_size)
237 {
238 struct tpm2_nv_define_space_cmd define_space;
239
240 /* Authentication support is not implemented. */
241 VB2_ASSERT(owner_auth == NULL && owner_auth_size == 0);
242
243 /* For backwards-compatibility, if no READ or WRITE permissions are set,
244 * assume readable/writeable with empty auth value.
245 */
246 if (!(perm & TPMA_NV_MASK_WRITE))
247 perm |= TPMA_NV_AUTHWRITE;
248 if (!(perm & TPMA_NV_MASK_READ))
249 perm |= TPMA_NV_AUTHREAD;
250
251 memset(&define_space, 0, sizeof(define_space));
252 define_space.publicInfo.nvIndex = HR_NV_INDEX + index;
253 define_space.publicInfo.dataSize = size;
254 define_space.publicInfo.attributes = perm;
255 define_space.publicInfo.nameAlg = TPM_ALG_SHA256;
256 if (auth_policy && auth_policy_size > 0) {
257 define_space.publicInfo.authPolicy.size = auth_policy_size;
258 define_space.publicInfo.authPolicy.buffer =
259 (uint8_t*) auth_policy;
260 }
261
262 return tpm_get_response_code(TPM2_NV_DefineSpace, &define_space);
263 }
264
TlclInitNvAuthPolicy(uint32_t pcr_selection_bitmap,const uint8_t pcr_values[][TPM_PCR_DIGEST],void * auth_policy,uint32_t * auth_policy_size)265 uint32_t TlclInitNvAuthPolicy(uint32_t pcr_selection_bitmap,
266 const uint8_t pcr_values[][TPM_PCR_DIGEST],
267 void* auth_policy, uint32_t* auth_policy_size)
268 {
269 /* Actual PCR selection isn't implemented. */
270 VB2_ASSERT(pcr_selection_bitmap == 0);
271 *auth_policy_size = 0;
272 return TPM_SUCCESS;
273 }
274
275 /**
276 * Issue a ForceClear. The TPM error code is returned.
277 */
TlclForceClear(void)278 uint32_t TlclForceClear(void)
279 {
280 return tpm_get_response_code(TPM2_Clear, NULL);
281 }
282
TlclSetDeactivated(uint8_t flag)283 uint32_t TlclSetDeactivated(uint8_t flag)
284 {
285 VB2_DEBUG("NOT YET IMPLEMENTED\n");
286 return TPM_SUCCESS;
287 }
288
TlclSetEnable(void)289 uint32_t TlclSetEnable(void)
290 {
291 VB2_DEBUG("NOT YET IMPLEMENTED\n");
292 return TPM_SUCCESS;
293 }
294
TlclGetFlags(uint8_t * disable,uint8_t * deactivated,uint8_t * nvlocked)295 uint32_t TlclGetFlags(uint8_t* disable,
296 uint8_t* deactivated,
297 uint8_t *nvlocked)
298 {
299 /* For TPM2 the flags are always the same */
300 if (disable)
301 *disable = 0;
302 if (deactivated)
303 *deactivated = 0;
304 if (nvlocked)
305 *nvlocked = 1;
306 return TPM_SUCCESS;
307 }
308
TlclIsOwned(void)309 int TlclIsOwned(void)
310 {
311 VB2_DEBUG("NOT YET IMPLEMENTED\n");
312 return 0;
313 }
314
TlclExtend(int pcr_num,const uint8_t * in_digest,uint8_t * out_digest)315 uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
316 {
317 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
318
319 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
320 pcr_ext_cmd.digests.count = 1;
321 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
322 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
323 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
324
325 return tpm_get_response_code(TPM2_PCR_Extend, &pcr_ext_cmd);
326 }
327
328
tlcl_nv_read_public(uint32_t index,struct nv_read_public_response ** presp)329 static uint32_t tlcl_nv_read_public(uint32_t index,
330 struct nv_read_public_response **presp)
331 {
332 struct tpm2_response *response = &tpm2_resp;
333 struct tpm2_nv_read_public_cmd read_pub;
334 uint32_t rv;
335
336 memset(&read_pub, 0, sizeof(read_pub));
337 read_pub.nvIndex = HR_NV_INDEX + index;
338
339 rv = tpm_send_receive(TPM2_NV_ReadPublic, &read_pub, response);
340 if (rv == TPM_SUCCESS)
341 *presp = &response->nv_read_public;
342
343 return rv;
344 }
345
346 /**
347 * Get the permission bits for the NVRAM space with |index|.
348 */
TlclGetPermissions(uint32_t index,uint32_t * permissions)349 uint32_t TlclGetPermissions(uint32_t index, uint32_t *permissions)
350 {
351 uint32_t rv;
352 struct nv_read_public_response *resp;
353
354 rv = tlcl_nv_read_public(index, &resp);
355 if (rv == TPM_SUCCESS)
356 *permissions = resp->nvPublic.attributes;
357
358 return rv;
359 }
360
TlclGetSpaceInfo(uint32_t index,uint32_t * attributes,uint32_t * size,void * auth_policy,uint32_t * auth_policy_size)361 uint32_t TlclGetSpaceInfo(uint32_t index, uint32_t *attributes, uint32_t *size,
362 void* auth_policy, uint32_t* auth_policy_size)
363 {
364 uint32_t rv;
365 struct nv_read_public_response *resp;
366
367 rv = tlcl_nv_read_public(index, &resp);
368 if (rv != TPM_SUCCESS)
369 return rv;
370
371 *attributes = resp->nvPublic.attributes;
372 *size = resp->nvPublic.dataSize;
373 if (resp->nvPublic.authPolicy.size > *auth_policy_size) {
374 return TPM_E_BUFFER_SIZE;
375 }
376
377 *auth_policy_size = resp->nvPublic.authPolicy.size;
378 memcpy(auth_policy, resp->nvPublic.authPolicy.buffer,
379 *auth_policy_size);
380
381 return TPM_SUCCESS;
382 }
383
tlcl_get_capability(TPM_CAP cap,TPM_PT property,struct get_capability_response ** presp)384 static uint32_t tlcl_get_capability(TPM_CAP cap, TPM_PT property,
385 struct get_capability_response **presp)
386 {
387 struct tpm2_response *response = &tpm2_resp;
388 struct tpm2_get_capability_cmd getcap;
389 uint32_t rv;
390
391 getcap.capability = cap;
392 getcap.property = property;
393 getcap.property_count = 1;
394
395 rv = tpm_send_receive(TPM2_GetCapability, &getcap, response);
396 if (rv == TPM_SUCCESS)
397 *presp = &response->cap;
398
399 return rv;
400 }
401
tlcl_get_tpm_property(TPM_PT property,uint32_t * pvalue)402 static uint32_t tlcl_get_tpm_property(TPM_PT property, uint32_t *pvalue)
403 {
404 uint32_t rv;
405 struct get_capability_response *resp;
406 TPML_TAGGED_TPM_PROPERTY *tpm_prop;
407
408 rv = tlcl_get_capability(TPM_CAP_TPM_PROPERTIES, property, &resp);
409 if (rv != TPM_SUCCESS)
410 return rv;
411
412 if (resp->capability_data.capability != TPM_CAP_TPM_PROPERTIES)
413 return TPM_E_IOERROR;
414
415 tpm_prop = &resp->capability_data.data.tpm_properties;
416
417 if ((tpm_prop->count != 1) ||
418 (tpm_prop->tpm_property[0].property != property))
419 return TPM_E_IOERROR;
420
421 *pvalue = tpm_prop->tpm_property[0].value;
422 return TPM_SUCCESS;
423 }
424
TlclGetPermanentFlags(TPM_PERMANENT_FLAGS * pflags)425 uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS *pflags)
426 {
427 return tlcl_get_tpm_property(TPM_PT_PERMANENT,
428 (uint32_t *)pflags);
429 }
430
TlclGetSTClearFlags(TPM_STCLEAR_FLAGS * pflags)431 uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS *pflags)
432 {
433 return tlcl_get_tpm_property(TPM_PT_STARTUP_CLEAR,
434 (uint32_t *)pflags);
435 }
436
TlclGetOwnership(uint8_t * owned)437 uint32_t TlclGetOwnership(uint8_t *owned)
438 {
439 uint32_t rv;
440 TPM_PERMANENT_FLAGS flags;
441 *owned = 0;
442
443 rv = TlclGetPermanentFlags(&flags);
444 if (rv == TPM_SUCCESS)
445 *owned = flags.ownerAuthSet;
446
447 return rv;
448 }
449
tlcl_lock_nv_write(uint32_t index)450 static uint32_t tlcl_lock_nv_write(uint32_t index)
451 {
452 struct tpm2_nv_write_lock_cmd nv_wl;
453
454 nv_wl.nvIndex = HR_NV_INDEX + index;
455 return tpm_get_response_code(TPM2_NV_WriteLock, &nv_wl);
456 }
457
tlcl_disable_platform_hierarchy(void)458 static uint32_t tlcl_disable_platform_hierarchy(void)
459 {
460 struct tpm2_hierarchy_control_cmd hc;
461 uint32_t rv;
462
463 hc.enable = TPM_RH_PLATFORM;
464 hc.state = 0;
465
466 rv = tpm_get_response_code(TPM2_Hierarchy_Control, &hc);
467 if (rv == TPM_SUCCESS)
468 tpm_set_ph_disabled(1);
469
470 return rv;
471 }
472
473 /**
474 * The name of the function was kept to maintain the existing TPM API, but
475 * TPM2.0 does not use the global lock to protect the FW rollback counter.
476 * Instead it calls WriteLock for the FW NVRAM index to prevent future
477 * writes to it.
478 *
479 * It first checks if the platform hierarchy is already disabled, and does
480 * nothing, if so. Otherwise, WriteLock for the index obviously fails.
481 */
TlclSetGlobalLock(void)482 uint32_t TlclSetGlobalLock(void)
483 {
484 if (tpm_is_ph_disabled())
485 return TPM_SUCCESS;
486 else
487 return tlcl_lock_nv_write(FIRMWARE_NV_INDEX);
488 }
489
490 /**
491 * Turn off physical presence and locks it off until next reboot. The TPM
492 * error code is returned.
493 *
494 * The name of the function was kept to maintain the existing TPM API, but
495 * TPM2.0 does not have to use the Physical Presence concept. Instead it just
496 * removes platform authorization - this makes sure that firmware and kernel
497 * rollback counter spaces can not be modified.
498 *
499 * It also explicitly locks the kernel rollback counter space (the FW rollback
500 * counter space was locked before RW firmware started.)
501 */
TlclLockPhysicalPresence(void)502 uint32_t TlclLockPhysicalPresence(void)
503 {
504 if (tpm_is_ph_disabled())
505 return TPM_SUCCESS;
506
507 return tlcl_disable_platform_hierarchy();
508 }
509
TlclRead(uint32_t index,void * data,uint32_t length)510 uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
511 {
512 struct tpm2_nv_read_cmd nv_readc;
513 struct tpm2_response *response = &tpm2_resp;
514 uint32_t rv;
515
516 memset(&nv_readc, 0, sizeof(nv_readc));
517
518 nv_readc.nvIndex = HR_NV_INDEX + index;
519 nv_readc.size = length;
520
521 rv = tpm_send_receive(TPM2_NV_Read, &nv_readc, response);
522
523 /* Need to map tpm error codes into internal values. */
524 switch (rv) {
525 case TPM_SUCCESS:
526 break;
527
528 /*
529 * 0x14a = RC_NV_UNINITIALIZED (space created but not written)
530 * 0x28b = RC_HANDLE(2) ("unknown handle" = space does not exist)
531 */
532 case 0x14a:
533 case 0x28b:
534 return TPM_E_BADINDEX;
535
536 default:
537 return rv;
538 }
539
540 if (length > response->nvr.buffer.size)
541 return TPM_E_RESPONSE_TOO_LARGE;
542
543 if (length < response->nvr.buffer.size)
544 return TPM_E_READ_EMPTY;
545
546 memcpy(data, response->nvr.buffer.buffer, length);
547
548 return TPM_SUCCESS;
549 }
550
TlclWrite(uint32_t index,const void * data,uint32_t length)551 uint32_t TlclWrite(uint32_t index, const void *data, uint32_t length)
552 {
553 struct tpm2_nv_write_cmd nv_writec;
554
555 memset(&nv_writec, 0, sizeof(nv_writec));
556
557 nv_writec.nvIndex = HR_NV_INDEX + index;
558 nv_writec.data.size = length;
559 nv_writec.data.buffer = data;
560
561 return tpm_get_response_code(TPM2_NV_Write, &nv_writec);
562 }
563
TlclPCRRead(uint32_t index,void * data,uint32_t length)564 uint32_t TlclPCRRead(uint32_t index, void *data, uint32_t length)
565 {
566 VB2_DEBUG("NOT YET IMPLEMENTED\n");
567 return TPM_SUCCESS;
568 }
569
TlclWriteLock(uint32_t index)570 uint32_t TlclWriteLock(uint32_t index)
571 {
572 struct tpm2_nv_write_lock_cmd nv_writelockc;
573
574 memset(&nv_writelockc, 0, sizeof(nv_writelockc));
575
576 nv_writelockc.nvIndex = HR_NV_INDEX | index;
577
578 return tpm_get_response_code(TPM2_NV_WriteLock, &nv_writelockc);
579 }
580
TlclReadLock(uint32_t index)581 uint32_t TlclReadLock(uint32_t index)
582 {
583 struct tpm2_nv_read_lock_cmd nv_readlockc;
584
585 memset(&nv_readlockc, 0, sizeof(nv_readlockc));
586
587 nv_readlockc.nvIndex = HR_NV_INDEX | index;
588
589 return tpm_get_response_code(TPM2_NV_ReadLock, &nv_readlockc);
590 }
591
TlclGetRandom(uint8_t * data,uint32_t length,uint32_t * size)592 uint32_t TlclGetRandom(uint8_t *data, uint32_t length, uint32_t *size)
593 {
594 uint32_t rv;
595 struct tpm2_get_random_cmd random;
596 struct get_random_response *response = &tpm2_resp.random;
597 size_t max_len, offset;
598
599 offset = offsetof(struct tpm2_response, random.random_bytes.buffer);
600 max_len = TPM_BUFFER_SIZE - offset;
601
602 if (length > max_len)
603 return TPM_E_BUFFER_SIZE;
604
605 random.bytes_requested = length;
606
607 rv = tpm_send_receive(TPM2_GetRandom, &random, &tpm2_resp);
608 if (rv != TPM_SUCCESS)
609 return rv;
610
611 *size = response->random_bytes.size;
612 if (*size > length)
613 return TPM_E_RESPONSE_TOO_LARGE;
614
615 memcpy(data, response->random_bytes.buffer, *size);
616
617 return rv;
618 }
619
620 // Converts TPM_PT_VENDOR_STRING_x |value| to an array of bytes in |buf|.
621 // Returns the number of bytes in the array.
622 // |buf| should be at least 4 bytes long.
tlcl_vendor_string_parse(uint32_t value,uint8_t * buf)623 static size_t tlcl_vendor_string_parse(uint32_t value, uint8_t* buf)
624 {
625 size_t len = 0;
626 int shift = 24;
627 for (; len < 4; shift -= 8) {
628 uint8_t byte = (value >> shift) & 0xffu;
629 if (!byte)
630 break;
631 buf[len++] = byte;
632 }
633 return len;
634 }
635
TlclGetVersion(uint32_t * vendor,uint64_t * firmware_version,uint8_t * vendor_specific_buf,size_t * vendor_specific_buf_size)636 uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version,
637 uint8_t* vendor_specific_buf,
638 size_t* vendor_specific_buf_size)
639 {
640 uint32_t result = tlcl_get_tpm_property(TPM_PT_MANUFACTURER, vendor);
641 if (result != TPM_SUCCESS)
642 return result;
643
644 uint32_t version_1;
645 uint32_t version_2;
646 result = tlcl_get_tpm_property(TPM_PT_FIRMWARE_VERSION_1, &version_1);
647 if (result != TPM_SUCCESS)
648 return result;
649 result = tlcl_get_tpm_property(TPM_PT_FIRMWARE_VERSION_2, &version_2);
650 if (result != TPM_SUCCESS)
651 return result;
652
653 *firmware_version = ((uint64_t) version_1 << 32) | version_2;
654
655 if (!vendor_specific_buf_size)
656 return TPM_SUCCESS;
657
658 size_t total_size = 0;
659 uint32_t prop_id;
660 uint8_t prop_string[16];
661 for (prop_id = TPM_PT_VENDOR_STRING_1;
662 prop_id <= TPM_PT_VENDOR_STRING_4;
663 ++prop_id) {
664 uint32_t prop_value;
665 result = tlcl_get_tpm_property(prop_id, &prop_value);
666 if (result != TPM_SUCCESS)
667 break;
668
669 size_t prop_len = tlcl_vendor_string_parse(
670 prop_value, prop_string + total_size);
671 VB2_ASSERT(prop_len <= 4 &&
672 total_size + prop_len <= sizeof(prop_string));
673 total_size += prop_len;
674 if (prop_len < 4)
675 break;
676 }
677 if (vendor_specific_buf) {
678 if (total_size > *vendor_specific_buf_size)
679 total_size = *vendor_specific_buf_size;
680 memcpy(vendor_specific_buf, prop_string, total_size);
681 }
682 *vendor_specific_buf_size = total_size;
683 return TPM_SUCCESS;
684 }
685
TlclIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO * info)686 uint32_t TlclIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO* info)
687 {
688 VB2_DEBUG("NOT YET IMPLEMENTED\n");
689 return TPM_E_IOERROR;
690 }
691
TlclReadPublic(uint32_t handle,uint8_t * data,uint32_t * length)692 uint32_t TlclReadPublic(uint32_t handle, uint8_t *data, uint32_t *length)
693 {
694 struct tpm2_read_public_cmd cmd;
695 struct tpm2_response *response = &tpm2_resp;
696 uint32_t rv;
697
698 memset(&cmd, 0, sizeof(cmd));
699
700 cmd.object_handle = handle;
701
702 rv = tpm_send_receive(TPM2_ReadPublic, &cmd, response);
703
704 /* Need to map tpm error codes into internal values. */
705 switch (rv) {
706 case TPM_SUCCESS:
707 break;
708
709 case 0x8b:
710 case 0x18b:
711 return TPM_E_BADINDEX;
712
713 default:
714 return rv;
715 }
716
717 if (*length < response->read_pub.buffer.size)
718 return TPM_E_RESPONSE_TOO_LARGE;
719
720 *length = response->read_pub.buffer.size;
721
722 memcpy(data, response->read_pub.buffer.buffer, response->read_pub.buffer.size);
723
724 return TPM_SUCCESS;
725 }
726
TlclEvictControl(uint32_t auth_handle,uint32_t object_handle,uint32_t persistent_handle)727 uint32_t TlclEvictControl(uint32_t auth_handle, uint32_t object_handle,
728 uint32_t persistent_handle)
729 {
730 struct tpm2_evict_control_cmd cmd;
731
732 memset(&cmd, 0, sizeof(cmd));
733
734 cmd.auth = auth_handle;
735 cmd.object_handle = object_handle;
736 cmd.persistent_handle = persistent_handle;
737
738 return tpm_get_response_code(TPM2_EvictControl, &cmd);
739 }
740
TlclCreatePrimary(uint32_t primary_handle,const void * tmpl,uint32_t tmpl_length,uint32_t * object_handle)741 uint32_t TlclCreatePrimary(uint32_t primary_handle, const void *tmpl,
742 uint32_t tmpl_length, uint32_t *object_handle)
743 {
744 uint32_t rv;
745 struct tpm2_create_primary_cmd cmd;
746 struct tpm2_response *response = &tpm2_resp;
747 uint8_t in_sensitive[4] = {0, 0, 0, 0};
748
749 memset(&cmd, 0, sizeof(cmd));
750
751 cmd.primary_handle = primary_handle;
752 cmd.in_sensitive.size = sizeof(in_sensitive);
753 cmd.in_sensitive.buffer = in_sensitive;
754 cmd.in_public.size = tmpl_length;
755 cmd.in_public.buffer = tmpl;
756
757 rv = tpm_send_receive(TPM2_CreatePrimary, &cmd, response);
758 if (rv)
759 return rv;
760
761 *object_handle = response->create_primary.object_handle;
762
763 return TPM_SUCCESS;
764 }
765