xref: /aosp_15_r20/external/vboot_reference/firmware/lib/tpm2_lite/tlcl.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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