xref: /aosp_15_r20/external/vboot_reference/firmware/lib/tpm_lite/tlcl.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2012 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 
6 /* A lightweight TPM command library.
7  *
8  * The general idea is that TPM commands are array of bytes whose
9  * fields are mostly compile-time constant.  The goal is to build much
10  * of the commands at compile time (or build time) and change some of
11  * the fields at run time as needed.  The code in
12  * utility/tlcl_generator.c builds structures containing the commands,
13  * as well as the offsets of the fields that need to be set at run
14  * time.
15  */
16 
17 #include "2common.h"
18 #include "2hmac.h"
19 #include "2sha.h"
20 #include "2sysincludes.h"
21 #include "tlcl.h"
22 #include "tlcl_internal.h"
23 #include "tlcl_structures.h"
24 
25 /* Sets the size field of a TPM command. */
SetTpmCommandSize(uint8_t * buffer,uint32_t size)26 static inline void SetTpmCommandSize(uint8_t* buffer, uint32_t size)
27 {
28 	ToTpmUint32(buffer + sizeof(uint16_t), size);
29 }
30 
31 /* Gets the size field of a TPM command. */
32 __attribute__((unused))
TpmCommandSize(const uint8_t * buffer)33 static inline int TpmCommandSize(const uint8_t* buffer)
34 {
35 	uint32_t size;
36 	FromTpmUint32(buffer + sizeof(uint16_t), &size);
37 	return (int) size;
38 }
39 
40 /* Gets the size field of a TPM request or response. */
TlclPacketSize(const uint8_t * packet)41 int TlclPacketSize(const uint8_t* packet)
42 {
43 	return TpmCommandSize(packet);
44 }
45 
46 /* Gets the code field of a TPM command. */
TpmCommandCode(const uint8_t * buffer)47 static inline int TpmCommandCode(const uint8_t* buffer)
48 {
49 	uint32_t code;
50 	FromTpmUint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
51 	return code;
52 }
53 
54 /* Gets the return code field of a TPM result. */
TpmReturnCode(const uint8_t * buffer)55 static inline int TpmReturnCode(const uint8_t* buffer)
56 {
57 	return TpmCommandCode(buffer);
58 }
59 
60 /* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or
61  * DOING_SELFTEST errors are returned.
62  */
TlclSendReceiveNoRetry(const uint8_t * request,uint8_t * response,int max_length)63 static uint32_t TlclSendReceiveNoRetry(const uint8_t* request,
64 				       uint8_t* response, int max_length)
65 {
66 
67 	uint32_t response_length = max_length;
68 	uint32_t result;
69 
70 #ifdef EXTRA_LOGGING
71 	VB2_DEBUG("TPM: command: %x%x %x%x%x%x %x%x%x%x\n",
72 		  request[0], request[1],
73 		  request[2], request[3], request[4], request[5],
74 		  request[6], request[7], request[8], request[9]);
75 #endif
76 
77 	result = vb2ex_tpm_send_recv(request, TpmCommandSize(request),
78 				     response, &response_length);
79 	if (TPM_SUCCESS != result) {
80 		/* Communication with TPM failed, so response is garbage */
81 		VB2_DEBUG("TPM: command %#x send/receive failed: %#x\n",
82 			  TpmCommandCode(request), result);
83 		return result;
84 	}
85 	/* Otherwise, use the result code from the response */
86 	result = TpmReturnCode(response);
87 
88 	/* TODO: add paranoia about returned response_length vs. max_length
89 	 * (and possibly expected length from the response header).  See
90 	 * crosbug.com/17017 */
91 
92 #ifdef EXTRA_LOGGING
93 	VB2_DEBUG("TPM: response: %x%x %x%x%x%x %x%x%x%x\n",
94 		  response[0], response[1],
95 		  response[2], response[3], response[4], response[5],
96 		  response[6], response[7], response[8], response[9]);
97 #endif
98 
99 	VB2_DEBUG("TPM: command %#x returned %#x\n",
100 		  TpmCommandCode(request), result);
101 
102 	return result;
103 }
104 
105 /* Sends a TPM command and gets a response.  Returns 0 if success or the TPM
106  * error code if error. In the firmware, waits for the self test to complete
107  * if needed. In the host, reports the first error without retries. */
TlclSendReceive(const uint8_t * request,uint8_t * response,int max_length)108 uint32_t TlclSendReceive(const uint8_t* request, uint8_t* response,
109 			 int max_length)
110 {
111 	uint32_t result = TlclSendReceiveNoRetry(request, response, max_length);
112 	/* When compiling for the firmware, hide command failures due to the
113 	 * self test not having run or completed. */
114 #ifndef CHROMEOS_ENVIRONMENT
115 	/* If the command fails because the self test has not completed, try it
116 	 * again after attempting to ensure that the self test has completed. */
117 	if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) {
118 		result = TlclContinueSelfTest();
119 		if (result != TPM_SUCCESS) {
120 			return result;
121 		}
122 #if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE)
123 		/* Retry only once */
124 		result = TlclSendReceiveNoRetry(request, response, max_length);
125 #else
126 		/* This needs serious testing.  The TPM specification says:
127 		 * "iii. The caller MUST wait for the actions of
128 		 * TPM_ContinueSelfTest to complete before reissuing the
129 		 * command C1."  But, if ContinueSelfTest is non-blocking, how
130 		 * do we know that the actions have completed other than trying
131 		 * again? */
132 		do {
133 			result = TlclSendReceiveNoRetry(request, response,
134 							max_length);
135 		} while (result == TPM_E_DOING_SELFTEST);
136 #endif
137 	}
138 #endif  /* ! defined(CHROMEOS_ENVIRONMENT) */
139 	return result;
140 }
141 
142 /* Sends a command and returns the error code. */
Send(const uint8_t * command)143 static uint32_t Send(const uint8_t* command)
144 {
145 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
146 	return TlclSendReceive(command, response, sizeof(response));
147 }
148 
149 #ifdef CHROMEOS_ENVIRONMENT
150 
151 struct auth_session
152 {
153 	uint32_t handle;
154 	TPM_NONCE nonce_even;
155 	TPM_NONCE nonce_odd;
156 	uint8_t shared_secret[TPM_AUTH_DATA_LEN];
157 	uint8_t valid;
158 };
159 
StartOIAPSession(struct auth_session * session,const uint8_t secret[TPM_AUTH_DATA_LEN])160 static uint32_t StartOIAPSession(struct auth_session* session,
161 				 const uint8_t secret[TPM_AUTH_DATA_LEN])
162 {
163 	session->valid = 0;
164 
165 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
166 	uint32_t result = TlclSendReceive(tpm_oiap_cmd.buffer, response,
167 					  sizeof(response));
168 	if (result != TPM_SUCCESS) {
169 		return result;
170 	}
171 
172 	uint32_t size;
173 	FromTpmUint32(response + sizeof(uint16_t), &size);
174 	if (size < kTpmResponseHeaderLength + sizeof(uint32_t)
175 			+ sizeof(TPM_NONCE)) {
176 		return TPM_E_INVALID_RESPONSE;
177 	}
178 
179 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
180 	session->handle = ReadTpmUint32(&cursor);
181 	memcpy(session->nonce_even.nonce, cursor, sizeof(TPM_NONCE));
182 	cursor += sizeof(TPM_NONCE);
183 	VB2_ASSERT(cursor - response <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
184 
185 	memcpy(session->shared_secret, secret, TPM_AUTH_DATA_LEN);
186 	session->valid = 1;
187 
188 	return result;
189 }
190 
StartOSAPSession(struct auth_session * session,uint16_t entity_type,uint32_t entity_value,const uint8_t entity_usage_auth[TPM_AUTH_DATA_LEN])191 static uint32_t StartOSAPSession(
192 		struct auth_session* session,
193 		uint16_t entity_type,
194 		uint32_t entity_value,
195 		const uint8_t entity_usage_auth[TPM_AUTH_DATA_LEN])
196 {
197 	session->valid = 0;
198 
199 	/* Build OSAP command. */
200 	struct s_tpm_osap_cmd cmd;
201 	memcpy(&cmd, &tpm_osap_cmd, sizeof(cmd));
202 	ToTpmUint16(cmd.buffer + cmd.entityType, entity_type);
203 	ToTpmUint32(cmd.buffer + cmd.entityValue, entity_value);
204 	if (vb2ex_tpm_get_random(cmd.buffer + cmd.nonceOddOSAP,
205 				 sizeof(TPM_NONCE)) != VB2_SUCCESS) {
206 		return TPM_E_INTERNAL_ERROR;
207 	}
208 
209 	/* Send OSAP command. */
210 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
211 	uint32_t result = TlclSendReceive(cmd.buffer, response,
212 					  sizeof(response));
213 	if (result != TPM_SUCCESS) {
214 		return result;
215 	}
216 
217 	/* Parse response. */
218 	uint32_t size;
219 	FromTpmUint32(response + sizeof(uint16_t), &size);
220 	if (size < kTpmResponseHeaderLength + sizeof(uint32_t)
221 			+ 2 * sizeof(TPM_NONCE)) {
222 		return TPM_E_INVALID_RESPONSE;
223 	}
224 
225 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
226 	session->handle = ReadTpmUint32(&cursor);
227 	memcpy(session->nonce_even.nonce, cursor, sizeof(TPM_NONCE));
228 	cursor += sizeof(TPM_NONCE);
229 	const uint8_t* nonce_even_osap = cursor;
230 	cursor += sizeof(TPM_NONCE);
231 	VB2_ASSERT(cursor - response <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
232 
233 	/* Compute shared secret */
234 	uint8_t hmac_input[2 * sizeof(TPM_NONCE)];
235 	memcpy(hmac_input, nonce_even_osap, sizeof(TPM_NONCE));
236 	memcpy(hmac_input + sizeof(TPM_NONCE), cmd.buffer + cmd.nonceOddOSAP,
237 	       sizeof(TPM_NONCE));
238 	struct vb2_hash mac;
239 	if (vb2_hmac_calculate(false, VB2_HASH_SHA1, entity_usage_auth, TPM_AUTH_DATA_LEN,
240 			       hmac_input, sizeof(hmac_input), &mac)) {
241 		return TPM_E_INTERNAL_ERROR;
242 	}
243 
244 	_Static_assert(sizeof(session->shared_secret) == VB2_SHA1_DIGEST_SIZE,
245 		       "The output size should match the sha1 digest size.");
246 	memcpy(session->shared_secret, mac.raw, sizeof(session->shared_secret));
247 
248 	session->valid = 1;
249 
250 	return result;
251 }
252 
253 /* Fills in the authentication block at the end of the command. The command body
254  * should already be initialized in |command_buffer|, and the included command
255  * size should account for the auth block that gets filled in. */
AddRequestAuthBlock(struct auth_session * auth_session,uint8_t * command_buffer,uint32_t command_buffer_size,uint8_t continue_auth_session)256 static uint32_t AddRequestAuthBlock(struct auth_session* auth_session,
257 				    uint8_t* command_buffer,
258 				    uint32_t command_buffer_size,
259 				    uint8_t continue_auth_session)
260 {
261 	if (!auth_session->valid) {
262 		return TPM_E_AUTHFAIL;
263 	}
264 
265 	/* Validity check to make sure the command buffer has sufficient space
266 	 * to add the auth block at the end of the command. */
267 	if (command_buffer_size < kTpmRequestHeaderLength) {
268 		return TPM_E_BUFFER_SIZE;
269 	}
270 	const uint32_t size = TpmCommandSize(command_buffer);
271 	if (size < kTpmResponseHeaderLength + kTpmRequestAuthBlockLength ||
272 	    size > command_buffer_size) {
273 		return TPM_E_INTERNAL_ERROR;
274 	}
275 	const uint32_t auth_offset = size - kTpmRequestAuthBlockLength;
276 
277 	/*
278 	 * The digest of the command is computed over the command buffer, but
279 	 * excluding the leading tag and paramSize fields.
280 	 */
281 	struct vb2_sha1_context sha1_ctx;
282 	vb2_sha1_init(&sha1_ctx);
283 	vb2_sha1_update(&sha1_ctx,
284 			command_buffer + sizeof(uint16_t) + sizeof(uint32_t),
285 			auth_offset - sizeof(uint16_t) - sizeof(uint32_t));
286 	uint8_t buf[TPM_SHA1_160_HASH_LEN + 2 * sizeof(TPM_NONCE) + 1];
287 	vb2_sha1_finalize(&sha1_ctx, buf);
288 
289 	/* Generate a fresh nonce. */
290 	if (vb2ex_tpm_get_random(auth_session->nonce_odd.nonce,
291 				 sizeof(TPM_NONCE)) != VB2_SUCCESS) {
292 		return TPM_E_INTERNAL_ERROR;
293 	}
294 
295 	/* Append the authentication block to the command buffer. */
296 	uint8_t* cursor = command_buffer + auth_offset;
297 	ToTpmUint32(cursor, auth_session->handle);
298 	cursor += sizeof(uint32_t);
299 	memcpy(cursor, auth_session->nonce_odd.nonce, sizeof(TPM_NONCE));
300 	cursor += sizeof(TPM_NONCE);
301 	*cursor++ = continue_auth_session;
302 
303 	/* Compute and append the MAC. */
304 	memcpy(buf + TPM_SHA1_160_HASH_LEN, auth_session->nonce_even.nonce,
305 	       sizeof(TPM_NONCE));
306 	memcpy(buf + TPM_SHA1_160_HASH_LEN + sizeof(TPM_NONCE),
307 	       auth_session->nonce_odd.nonce, sizeof(TPM_NONCE));
308 	buf[TPM_SHA1_160_HASH_LEN + 2 * sizeof(TPM_NONCE)] =
309 			continue_auth_session;
310 	struct vb2_hash mac;
311 	if (vb2_hmac_calculate(false, VB2_HASH_SHA1, auth_session->shared_secret,
312 			       sizeof(auth_session->shared_secret), buf, sizeof(buf), &mac)) {
313 		return TPM_E_AUTHFAIL;
314 	}
315 
316 	memcpy(cursor, mac.sha1, sizeof(mac.sha1));
317 
318 	cursor += sizeof(mac.sha1);
319 
320 	return TPM_SUCCESS;
321 }
322 
CheckResponseAuthBlock(struct auth_session * auth_session,TPM_COMMAND_CODE ordinal,uint8_t * response_buffer,uint32_t response_buffer_size)323 static uint32_t CheckResponseAuthBlock(struct auth_session* auth_session,
324 				       TPM_COMMAND_CODE ordinal,
325 				       uint8_t* response_buffer,
326 				       uint32_t response_buffer_size)
327 {
328 	if (!auth_session->valid) {
329 		return TPM_E_AUTHFAIL;
330 	}
331 
332 	if (response_buffer_size < kTpmResponseHeaderLength) {
333 		return TPM_E_INVALID_RESPONSE;
334 	}
335 
336 	/* Parse and validate the actual response size from the response. */
337 	uint32_t size;
338 	FromTpmUint32(response_buffer + sizeof(uint16_t), &size);
339 	if (size >= response_buffer_size ||
340 	    size < kTpmResponseHeaderLength + kTpmResponseAuthBlockLength) {
341 		return TPM_E_INVALID_RESPONSE;
342 	}
343 	uint32_t auth_offset = size - kTpmResponseAuthBlockLength;
344 
345 	/*
346 	 * The digest of the response is computed over the return code, ordinal,
347 	 * response payload.
348 	 */
349 	struct vb2_sha1_context sha1_ctx;
350 	vb2_sha1_init(&sha1_ctx);
351 	vb2_sha1_update(&sha1_ctx,
352 			response_buffer + sizeof(uint16_t) + sizeof(uint32_t),
353 			sizeof(uint32_t));
354 	uint8_t ordinal_buf[sizeof(ordinal)];
355 	ToTpmUint32(ordinal_buf, ordinal);
356 	vb2_sha1_update(&sha1_ctx, ordinal_buf, sizeof(ordinal_buf));
357 	vb2_sha1_update(&sha1_ctx,
358 			response_buffer + kTpmResponseHeaderLength,
359 			auth_offset - kTpmResponseHeaderLength);
360 	uint8_t hmac_input[TPM_SHA1_160_HASH_LEN + 2 * sizeof(TPM_NONCE) + 1];
361 	vb2_sha1_finalize(&sha1_ctx, hmac_input);
362 
363 	/* Compute the MAC. */
364 	uint8_t* cursor = response_buffer + auth_offset;
365 	memcpy(hmac_input + TPM_SHA1_160_HASH_LEN, cursor, sizeof(TPM_NONCE));
366 	cursor += sizeof(TPM_NONCE);
367 	memcpy(hmac_input + TPM_SHA1_160_HASH_LEN + sizeof(TPM_NONCE),
368 	       auth_session->nonce_odd.nonce, sizeof(TPM_NONCE));
369 	auth_session->valid = *cursor++;
370 	hmac_input[TPM_SHA1_160_HASH_LEN + 2 * sizeof(TPM_NONCE)] =
371 			auth_session->valid;
372 	struct vb2_hash mac;
373 	if (vb2_hmac_calculate(false, VB2_HASH_SHA1, auth_session->shared_secret,
374 			       sizeof(auth_session->shared_secret), hmac_input,
375 			       sizeof(hmac_input), &mac)) {
376 		auth_session->valid = 0;
377 		return TPM_E_AUTHFAIL;
378 	}
379 
380 	/* Check the MAC. */
381 	if (vb2_safe_memcmp(mac.sha1, cursor, sizeof(mac.sha1))) {
382 		auth_session->valid = 0;
383 		return TPM_E_AUTHFAIL;
384 	}
385 
386 	/* Success, save the even nonce. */
387 	memcpy(auth_session->nonce_even.nonce, response_buffer + auth_offset,
388 	       sizeof(TPM_NONCE));
389 
390 	return TPM_SUCCESS;
391 }
392 
393 #endif  /* CHROMEOS_ENVIRONMENT */
394 
395 /* Exported functions. */
396 
TlclLibInit(void)397 uint32_t TlclLibInit(void)
398 {
399 	return vb2ex_tpm_init();
400 }
401 
TlclLibClose(void)402 uint32_t TlclLibClose(void)
403 {
404 	return vb2ex_tpm_close();
405 }
406 
TlclStartup(void)407 uint32_t TlclStartup(void)
408 {
409 	VB2_DEBUG("TPM: Startup\n");
410 	return Send(tpm_startup_cmd.buffer);
411 }
412 
TlclSaveState(void)413 uint32_t TlclSaveState(void)
414 {
415 	VB2_DEBUG("TPM: SaveState\n");
416 	return Send(tpm_savestate_cmd.buffer);
417 }
418 
TlclResume(void)419 uint32_t TlclResume(void)
420 {
421 	VB2_DEBUG("TPM: Resume\n");
422 	return Send(tpm_resume_cmd.buffer);
423 }
424 
TlclSelfTestFull(void)425 uint32_t TlclSelfTestFull(void)
426 {
427 	VB2_DEBUG("TPM: Self test full\n");
428 	return Send(tpm_selftestfull_cmd.buffer);
429 }
430 
TlclContinueSelfTest(void)431 uint32_t TlclContinueSelfTest(void)
432 {
433 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
434 	VB2_DEBUG("TPM: Continue self test\n");
435 	/* Call the No Retry version of SendReceive to avoid recursion. */
436 	return TlclSendReceiveNoRetry(tpm_continueselftest_cmd.buffer,
437 				      response, sizeof(response));
438 }
439 
TlclDefineSpace(uint32_t index,uint32_t perm,uint32_t size)440 uint32_t TlclDefineSpace(uint32_t index, uint32_t perm, uint32_t size)
441 {
442 	VB2_DEBUG("TPM: TlclDefineSpace(%#x, %#x, %d)\n", index, perm, size);
443 	return TlclDefineSpaceEx(NULL, 0, index, perm, size, NULL, 0);
444 }
445 
446 #ifdef CHROMEOS_ENVIRONMENT
447 
TlclUndefineSpace(uint32_t index)448 uint32_t TlclUndefineSpace(uint32_t index)
449 {
450 	VB2_DEBUG("TPM: TlclUndefineSpace(%#x)\n", index);
451 	return TlclUndefineSpaceEx(NULL, 0, index);
452 }
453 
TlclUndefineSpaceEx(const uint8_t * owner_auth,uint32_t owner_auth_size,uint32_t index)454 uint32_t TlclUndefineSpaceEx(const uint8_t* owner_auth,
455 			     uint32_t owner_auth_size,
456 			     uint32_t index)
457 {
458 	return TlclDefineSpaceEx(owner_auth, owner_auth_size,
459 				 index, 0, 0,
460 				 NULL, 0);
461 }
462 
463 #endif  /* CHROMEOS_ENVIRONMENT */
464 
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)465 uint32_t TlclDefineSpaceEx(const uint8_t* owner_auth, uint32_t owner_auth_size,
466 			   uint32_t index, uint32_t perm, uint32_t size,
467 			   const void* auth_policy, uint32_t auth_policy_size)
468 {
469 	uint32_t result;
470 
471 	/* Build the request data. */
472 	uint8_t cmd[sizeof(tpm_nv_definespace_cmd.buffer) +
473 			kTpmRequestAuthBlockLength];
474 	memcpy(cmd, &tpm_nv_definespace_cmd, sizeof(tpm_nv_definespace_cmd));
475 	ToTpmUint32(cmd + tpm_nv_definespace_cmd.index, index);
476 	ToTpmUint32(cmd + tpm_nv_definespace_cmd.perm, perm);
477 	ToTpmUint32(cmd + tpm_nv_definespace_cmd.size, size);
478 	if (auth_policy != NULL) {
479 		if (auth_policy_size != sizeof(TPM_NV_AUTH_POLICY)) {
480 			return TPM_E_BUFFER_SIZE;
481 		}
482 
483 		const TPM_NV_AUTH_POLICY* policy = auth_policy;
484 		memcpy(cmd + tpm_nv_definespace_cmd.pcr_info_read,
485 		       &policy->pcr_info_read, sizeof(policy->pcr_info_read));
486 		memcpy(cmd + tpm_nv_definespace_cmd.pcr_info_write,
487 		       &policy->pcr_info_write, sizeof(policy->pcr_info_write));
488 	}
489 
490 #ifdef CHROMEOS_ENVIRONMENT
491 	struct auth_session auth_session;
492 	if (owner_auth) {
493 		if (owner_auth_size != TPM_AUTH_DATA_LEN) {
494 			return TPM_E_AUTHFAIL;
495 		}
496 
497 		result = StartOSAPSession(&auth_session, TPM_ET_OWNER, 0,
498 					  owner_auth);
499 		if (result != TPM_SUCCESS) {
500 			return result;
501 		}
502 
503 		ToTpmUint32(cmd + sizeof(uint16_t), sizeof(cmd));
504 		ToTpmUint16(cmd, TPM_TAG_RQU_AUTH1_COMMAND);
505 		result = AddRequestAuthBlock(&auth_session, cmd, sizeof(cmd),
506 					     0);
507 		if (result != TPM_SUCCESS) {
508 			return result;
509 		}
510 	}
511 #endif
512 
513 	/* Send the command. */
514 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
515 	result = TlclSendReceive(cmd, response, sizeof(response));
516 	if (result != TPM_SUCCESS) {
517 		return result;
518 	}
519 
520 #ifdef CHROMEOS_ENVIRONMENT
521 	if (owner_auth) {
522 		result = CheckResponseAuthBlock(&auth_session,
523 						TPM_ORD_NV_DefineSpace,
524 						response, sizeof(response));
525 	}
526 #endif
527 
528 	return result;
529 }
530 
TlclInitNvAuthPolicy(uint32_t pcr_selection_bitmap,const uint8_t pcr_values[][TPM_PCR_DIGEST],void * auth_policy,uint32_t * auth_policy_size)531 uint32_t TlclInitNvAuthPolicy(uint32_t pcr_selection_bitmap,
532 			      const uint8_t pcr_values[][TPM_PCR_DIGEST],
533 			      void* auth_policy, uint32_t* auth_policy_size)
534 {
535 	uint32_t buffer_size = *auth_policy_size;
536 	*auth_policy_size = sizeof(TPM_NV_AUTH_POLICY);
537 	if (!auth_policy || buffer_size < sizeof(TPM_NV_AUTH_POLICY)) {
538 		return TPM_E_BUFFER_SIZE;
539 	}
540 	TPM_NV_AUTH_POLICY* policy = auth_policy;
541 
542 	/* Note that although the struct definition allocates space for 3 bytes
543 	 * worth of PCR selection, it is technically a variably-sized field in
544 	 * the TPM structure definition. Since this is part of the policy
545 	 * digest, we need to carefully match our selection sizes. For now, we
546 	 * use 3 bytes, which aligns with TrouSerS behavior. */
547 	TPM_PCR_SELECTION* select = &policy->pcr_info_read.pcrSelection;
548 	ToTpmUint16((uint8_t*)&select->sizeOfSelect, sizeof(select->pcrSelect));
549 	select->pcrSelect[0] = (pcr_selection_bitmap >> 0) & 0xff;
550 	select->pcrSelect[1] = (pcr_selection_bitmap >> 8) & 0xff;
551 	select->pcrSelect[2] = (pcr_selection_bitmap >> 16) & 0xff;
552 	VB2_ASSERT((pcr_selection_bitmap & 0xff000000) == 0);
553 
554 	/* Allow all localities except locality 3. Rationale:
555 	 *
556 	 * We don't actually care about restricting NVRAM access to specific
557 	 * localities. In fact localities aren't used in Chrome OS and locality
558 	 * 0 is used for everything.
559 	 *
560 	 * However, the TPM specification makes an effort to not allow NVRAM
561 	 * spaces that do not have some write access control configured: When
562 	 * defining a space, either at least one of OWNERWRITE, AUTHWRITE,
563 	 * WRITEDEFINE, PPWRITE or a locality restriction must be specified (See
564 	 * TPM_NV_DefineSpace command description in the spec).
565 	 *
566 	 * This complicates matters when defining an NVRAM space that should be
567 	 * writable and lockable (for the remainder of the boot cycle) by the OS
568 	 * even when the TPM is not owned:
569 	 *  * OWNERWRITE doesn't work because there might be no owner.
570 	 *  * PPWRITE restricts writing to firmware only.
571 	 *  * Use of WRITEDEFINE prevents use of WRITE_STCLEAR (i.e. the space
572 	 *    can either not be locked, or it would remain locked until next TPM
573 	 *    clear).
574 	 *  * AUTHWRITE looks workable at first sight (by setting a well-known
575 	 *    auth secret). However writes must use TPM_NV_WriteValueAuth, which
576 	 *    only works when the TPM is owned. Interestingly, the spec admits
577 	 *    to that being a mistake in the TPM_NV_WriteValueAuth comment but
578 	 *    asserts that the behavior is normative.
579 	 *
580 	 * Having ruled out all attributes, we're left with locality restriction
581 	 * as the only option to pass the access control requirement check in
582 	 * TPM_NV_DefineSpace. We choose to disallow locality 3, since that is
583 	 * the most unlikely one to be used in practice, i.e. the spec says
584 	 * locality 3 is for "Auxiliary components. Use of this is optional and,
585 	 * if used, it is implementation dependent."
586 	 */
587 	policy->pcr_info_read.localityAtRelease =
588 		TPM_ALL_LOCALITIES & ~TPM_LOC_THREE;
589 
590 	struct vb2_sha1_context sha1_ctx;
591 	vb2_sha1_init(&sha1_ctx);
592 
593 	vb2_sha1_update(&sha1_ctx,
594 			(const uint8_t*)&policy->pcr_info_read.pcrSelection,
595 			sizeof(policy->pcr_info_read.pcrSelection));
596 
597 	uint32_t num_pcrs = 0;
598 	int i;
599 	for (i = 0; i < sizeof(pcr_selection_bitmap) * 8; ++i) {
600 		if ((1U << i) & pcr_selection_bitmap) {
601 			num_pcrs++;
602 		}
603 	}
604 
605 	uint8_t pcrs_size[sizeof(uint32_t)];
606 	ToTpmUint32(pcrs_size, num_pcrs * TPM_PCR_DIGEST);
607 	vb2_sha1_update(&sha1_ctx, pcrs_size, sizeof(pcrs_size));
608 
609 	for (i = 0; i < num_pcrs; ++i) {
610 		vb2_sha1_update(&sha1_ctx, pcr_values[i], TPM_PCR_DIGEST);
611 	}
612 
613 	vb2_sha1_finalize(&sha1_ctx,
614 			  policy->pcr_info_read.digestAtRelease.digest);
615 
616 	/* Make the write policy an identical copy of the read auth policy. */
617 	memcpy(&policy->pcr_info_write, &policy->pcr_info_read,
618 	       sizeof(policy->pcr_info_read));
619 
620 	return TPM_SUCCESS;
621 }
622 
TlclWrite(uint32_t index,const void * data,uint32_t length)623 uint32_t TlclWrite(uint32_t index, const void* data, uint32_t length)
624 {
625 	struct s_tpm_nv_write_cmd cmd;
626 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
627 	const int total_length =
628 			kTpmRequestHeaderLength + kWriteInfoLength + length;
629 
630 	VB2_DEBUG("TPM: TlclWrite(%#x, %d)\n", index, length);
631 	memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd));
632 	VB2_ASSERT(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
633 	SetTpmCommandSize(cmd.buffer, total_length);
634 
635 	ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.index, index);
636 	ToTpmUint32(cmd.buffer + tpm_nv_write_cmd.length, length);
637 	memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length);
638 
639 	return TlclSendReceive(cmd.buffer, response, sizeof(response));
640 }
641 
TlclRead(uint32_t index,void * data,uint32_t length)642 uint32_t TlclRead(uint32_t index, void* data, uint32_t length)
643 {
644 	struct s_tpm_nv_read_cmd cmd;
645 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
646 	uint32_t result;
647 
648 	VB2_DEBUG("TPM: TlclRead(%#x, %d)\n", index, length);
649 	memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd));
650 	ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.index, index);
651 	ToTpmUint32(cmd.buffer + tpm_nv_read_cmd.length, length);
652 
653 	result = TlclSendReceive(cmd.buffer, response, sizeof(response));
654 	if (result == TPM_SUCCESS && length > 0) {
655 		const uint8_t* nv_read_cursor =
656 				response + kTpmResponseHeaderLength;
657 		uint32_t result_length = ReadTpmUint32(&nv_read_cursor);
658 		if (result_length > length)
659 			result_length = length;  /* Truncate to fit buffer */
660 		memcpy(data, nv_read_cursor, result_length);
661 	}
662 
663 	return result;
664 }
665 
TlclPCRRead(uint32_t index,void * data,uint32_t length)666 uint32_t TlclPCRRead(uint32_t index, void* data, uint32_t length)
667 {
668 	struct s_tpm_pcr_read_cmd cmd;
669 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
670 	uint32_t result;
671 
672 	VB2_DEBUG("TPM: TlclPCRRead(%#x, %d)\n", index, length);
673 	if (length < kPcrDigestLength) {
674 		return TPM_E_IOERROR;
675 	}
676 	memcpy(&cmd, &tpm_pcr_read_cmd, sizeof(cmd));
677 	ToTpmUint32(cmd.buffer + tpm_pcr_read_cmd.pcrNum, index);
678 
679 	result = TlclSendReceive(cmd.buffer, response, sizeof(response));
680 	if (result == TPM_SUCCESS) {
681 		const uint8_t* pcr_read_cursor =
682 				response + kTpmResponseHeaderLength;
683 		memcpy(data, pcr_read_cursor, kPcrDigestLength);
684 	}
685 
686 	return result;
687 }
688 
TlclWriteLock(uint32_t index)689 uint32_t TlclWriteLock(uint32_t index)
690 {
691 	VB2_DEBUG("TPM: Write lock %#x\n", index);
692 	return TlclWrite(index, NULL, 0);
693 }
694 
TlclReadLock(uint32_t index)695 uint32_t TlclReadLock(uint32_t index)
696 {
697 	VB2_DEBUG("TPM: Read lock %#x\n", index);
698 	return TlclRead(index, NULL, 0);
699 }
700 
TlclAssertPhysicalPresence(void)701 uint32_t TlclAssertPhysicalPresence(void)
702 {
703 	VB2_DEBUG("TPM: Asserting physical presence\n");
704 	return Send(tpm_ppassert_cmd.buffer);
705 }
706 
TlclPhysicalPresenceCMDEnable(void)707 uint32_t TlclPhysicalPresenceCMDEnable(void)
708 {
709 	VB2_DEBUG("TPM: Enable the physical presence command\n");
710 	return Send(tpm_ppenable_cmd.buffer);
711 }
712 
TlclFinalizePhysicalPresence(void)713 uint32_t TlclFinalizePhysicalPresence(void)
714 {
715 	VB2_DEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n");
716 	return Send(tpm_finalizepp_cmd.buffer);
717 }
718 
TlclAssertPhysicalPresenceResult(void)719 uint32_t TlclAssertPhysicalPresenceResult(void)
720 {
721 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
722 	return TlclSendReceive(tpm_ppassert_cmd.buffer, response,
723 			       sizeof(response));
724 }
725 
TlclLockPhysicalPresence(void)726 uint32_t TlclLockPhysicalPresence(void)
727 {
728 	VB2_DEBUG("TPM: Lock physical presence\n");
729 	return Send(tpm_pplock_cmd.buffer);
730 }
731 
TlclSetNvLocked(void)732 uint32_t TlclSetNvLocked(void)
733 {
734 	VB2_DEBUG("TPM: Set NV locked\n");
735 	return TlclDefineSpace(TPM_NV_INDEX_LOCK, 0, 0);
736 }
737 
TlclIsOwned(void)738 int TlclIsOwned(void)
739 {
740 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_PUBEK_SIZE];
741 	uint32_t result;
742 	result = TlclSendReceive(tpm_readpubek_cmd.buffer,
743 				 response, sizeof(response));
744 	return (result != TPM_SUCCESS);
745 }
746 
TlclForceClear(void)747 uint32_t TlclForceClear(void)
748 {
749 	VB2_DEBUG("TPM: Force clear\n");
750 	return Send(tpm_forceclear_cmd.buffer);
751 }
752 
TlclSetEnable(void)753 uint32_t TlclSetEnable(void)
754 {
755 	VB2_DEBUG("TPM: Enabling TPM\n");
756 	return Send(tpm_physicalenable_cmd.buffer);
757 }
758 
TlclClearEnable(void)759 uint32_t TlclClearEnable(void)
760 {
761 	VB2_DEBUG("TPM: Disabling TPM\n");
762 	return Send(tpm_physicaldisable_cmd.buffer);
763 }
764 
TlclSetDeactivated(uint8_t flag)765 uint32_t TlclSetDeactivated(uint8_t flag)
766 {
767 	struct s_tpm_physicalsetdeactivated_cmd cmd;
768 	VB2_DEBUG("TPM: SetDeactivated(%d)\n", flag);
769 	memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd));
770 	*(cmd.buffer + cmd.deactivated) = flag;
771 	return Send(cmd.buffer);
772 }
773 
TlclGetPermanentFlags(TPM_PERMANENT_FLAGS * pflags)774 uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags)
775 {
776 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
777 	uint32_t size;
778 	uint32_t result = TlclSendReceive(tpm_getflags_cmd.buffer, response,
779 					  sizeof(response));
780 	if (result != TPM_SUCCESS)
781 		return result;
782 	FromTpmUint32(response + kTpmResponseHeaderLength, &size);
783 	/* TODO(crbug.com/379255): This fails. Find out why.
784 	 * VB2_ASSERT(size == sizeof(TPM_PERMANENT_FLAGS));
785 	 */
786 	memcpy(pflags,
787 	       response + kTpmResponseHeaderLength + sizeof(size),
788 	       sizeof(TPM_PERMANENT_FLAGS));
789 	return result;
790 }
791 
TlclGetSTClearFlags(TPM_STCLEAR_FLAGS * vflags)792 uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS* vflags)
793 {
794 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
795 	uint32_t size;
796 	uint32_t result = TlclSendReceive(tpm_getstclearflags_cmd.buffer,
797 					  response, sizeof(response));
798 	if (result != TPM_SUCCESS)
799 		return result;
800 	FromTpmUint32(response + kTpmResponseHeaderLength, &size);
801 	/* Ugly assertion, but the struct is padded up by one byte. */
802 	/* TODO(crbug.com/379255): This fails. Find out why.
803 	 * VB2_ASSERT(size == 7 && sizeof(TPM_STCLEAR_FLAGS) - 1 == 7);
804 	 */
805 	memcpy(vflags,
806 	       response + kTpmResponseHeaderLength + sizeof(size),
807 	       sizeof(TPM_STCLEAR_FLAGS));
808 	return result;
809 }
810 
TlclGetFlags(uint8_t * disable,uint8_t * deactivated,uint8_t * nvlocked)811 uint32_t TlclGetFlags(uint8_t* disable,
812 		      uint8_t* deactivated,
813 		      uint8_t *nvlocked)
814 {
815 	TPM_PERMANENT_FLAGS pflags;
816 	uint32_t result = TlclGetPermanentFlags(&pflags);
817 	if (result == TPM_SUCCESS) {
818 		if (disable)
819 			*disable = pflags.disable;
820 		if (deactivated)
821 			*deactivated = pflags.deactivated;
822 		if (nvlocked)
823 			*nvlocked = pflags.nvLocked;
824 		VB2_DEBUG("TPM: Got flags disable=%d, deactivated=%d, "
825 			  "nvlocked=%d\n",
826 			  pflags.disable, pflags.deactivated, pflags.nvLocked);
827 	}
828 	return result;
829 }
830 
TlclSetGlobalLock(void)831 uint32_t TlclSetGlobalLock(void)
832 {
833 	uint32_t x;
834 	VB2_DEBUG("TPM: Set global lock\n");
835 	return TlclWrite(TPM_NV_INDEX0, (uint8_t*) &x, 0);
836 }
837 
TlclExtend(int pcr_num,const uint8_t * in_digest,uint8_t * out_digest)838 uint32_t TlclExtend(int pcr_num, const uint8_t* in_digest,
839 		    uint8_t* out_digest)
840 {
841 	struct s_tpm_extend_cmd cmd;
842 	uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength];
843 	uint32_t result;
844 
845 	memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd));
846 	ToTpmUint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
847 	memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
848 
849 	result = TlclSendReceive(cmd.buffer, response, sizeof(response));
850 	if (result != TPM_SUCCESS)
851 		return result;
852 
853 	memcpy(out_digest, response + kTpmResponseHeaderLength,
854 	       kPcrDigestLength);
855 	return result;
856 }
857 
TlclGetPermissions(uint32_t index,uint32_t * permissions)858 uint32_t TlclGetPermissions(uint32_t index, uint32_t* permissions)
859 {
860 	uint32_t dummy_attributes;
861 	TPM_NV_AUTH_POLICY dummy_policy;
862 	uint32_t dummy_policy_size = sizeof(dummy_policy);
863 
864 	return TlclGetSpaceInfo(index, permissions, &dummy_attributes,
865 				&dummy_policy, &dummy_policy_size);
866 }
867 
DecodePCRInfo(const uint8_t ** cursor,const uint8_t * end,TPM_PCR_INFO_SHORT * pcr_info)868 static int DecodePCRInfo(const uint8_t** cursor,
869 			 const uint8_t* end,
870 			 TPM_PCR_INFO_SHORT* pcr_info)
871 {
872 	const size_t available_size = end - *cursor;
873 	if (available_size < sizeof(uint16_t)) {
874 		return 0;
875 	}
876 
877 	uint16_t size_of_select = 0;
878 	FromTpmUint16(*cursor, &size_of_select);
879 
880 	/* Compute the actual size of the encoded PCR selection (which is a
881 	 * variable-length field). */
882 	const size_t encoded_pcr_info_size = sizeof(TPM_PCR_INFO_SHORT) -
883 		sizeof(pcr_info->pcrSelection.pcrSelect) + size_of_select;
884 	if (available_size < encoded_pcr_info_size ||
885 	    size_of_select > sizeof(pcr_info->pcrSelection.pcrSelect)) {
886 		return 0;
887 	}
888 
889 	memset(&pcr_info->pcrSelection, 0, sizeof(pcr_info->pcrSelection));
890 	const size_t pcr_selection_size =
891 		sizeof(size_of_select) + size_of_select;
892 	memcpy(&pcr_info->pcrSelection, *cursor, pcr_selection_size);
893 	*cursor += pcr_selection_size;
894 
895 	pcr_info->localityAtRelease = **cursor;
896 	(*cursor)++;
897 
898 	memcpy(&pcr_info->digestAtRelease, *cursor, sizeof(TPM_COMPOSITE_HASH));
899 	*cursor += sizeof(TPM_COMPOSITE_HASH);
900 
901 	return 1;
902 }
903 
TlclGetSpaceInfo(uint32_t index,uint32_t * attributes,uint32_t * size,void * auth_policy,uint32_t * auth_policy_size)904 uint32_t TlclGetSpaceInfo(uint32_t index, uint32_t *attributes, uint32_t *size,
905 			  void* auth_policy, uint32_t* auth_policy_size)
906 {
907 	TPM_NV_AUTH_POLICY* policy;
908 	uint32_t buffer_size = *auth_policy_size;
909 	*auth_policy_size = sizeof(TPM_NV_AUTH_POLICY);
910 	if (buffer_size < sizeof(TPM_NV_AUTH_POLICY)) {
911 		return TPM_E_BUFFER_SIZE;
912 	}
913 	policy = auth_policy;
914 
915 	struct s_tpm_getspaceinfo_cmd cmd;
916 	memcpy(&cmd, &tpm_getspaceinfo_cmd, sizeof(cmd));
917 	ToTpmUint32(cmd.buffer + tpm_getspaceinfo_cmd.index, index);
918 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
919 	uint32_t result = TlclSendReceive(cmd.buffer, response,
920 					  sizeof(response));
921 	if (result != TPM_SUCCESS) {
922 		return result;
923 	}
924 
925 	uint32_t response_size = TpmCommandSize(response);
926 	if (response_size > sizeof(response)) {
927 		return TPM_E_RESPONSE_TOO_LARGE;
928 	}
929 
930 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
931 	uint32_t cap_size = ReadTpmUint32(&cursor);
932 	if (cap_size >
933 	    response_size - sizeof(cap_size) - kTpmResponseHeaderLength) {
934 		return TPM_E_INVALID_RESPONSE;
935 	}
936 	const uint8_t* end = cursor + cap_size;
937 
938 	cursor += sizeof(uint16_t);  /* skip tag */
939 	uint32_t response_index = ReadTpmUint32(&cursor);
940 	if (index != response_index) {
941 		return TPM_E_INVALID_RESPONSE;
942 	}
943 
944 	if (!DecodePCRInfo(&cursor, end, &policy->pcr_info_read) ||
945 	    !DecodePCRInfo(&cursor, end, &policy->pcr_info_write)) {
946 		return TPM_E_INVALID_RESPONSE;
947 	}
948 
949 	/* Make sure that the remaining data in the buffer matches the size of
950 	 * the remaining fields to decode. */
951 	if (end - cursor !=
952 	    2 * sizeof(uint32_t) + 3 * sizeof(uint8_t) + sizeof(uint16_t)) {
953 		return TPM_E_INVALID_RESPONSE;
954 	}
955 
956 	cursor += sizeof(uint16_t);  /* skip TPM_NV_ATTRIBUTES tag */
957 	*attributes = ReadTpmUint32(&cursor);
958 	cursor += sizeof(uint8_t);  /* skip bReadSTClear */
959 	cursor += sizeof(uint8_t);  /* skip bWriteSTClear */
960 	cursor += sizeof(uint8_t);  /* skip bWriteDefine */
961 	*size = ReadTpmUint32(&cursor);
962 
963 	return TPM_SUCCESS;
964 }
965 
TlclGetOwnership(uint8_t * owned)966 uint32_t TlclGetOwnership(uint8_t* owned)
967 {
968 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
969 	uint32_t size;
970 	uint32_t result = TlclSendReceive(tpm_getownership_cmd.buffer,
971 					  response, sizeof(response));
972 	if (result != TPM_SUCCESS)
973 		return result;
974 	FromTpmUint32(response + kTpmResponseHeaderLength, &size);
975 	/* TODO(crbug.com/379255): This fails. Find out why.
976 	 * VB2_ASSERT(size == sizeof(*owned));
977 	 */
978 	memcpy(owned,
979 	       response + kTpmResponseHeaderLength + sizeof(size),
980 	       sizeof(*owned));
981 	return result;
982 }
983 
TlclGetRandom(uint8_t * data,uint32_t length,uint32_t * size)984 uint32_t TlclGetRandom(uint8_t* data, uint32_t length, uint32_t *size)
985 {
986 	struct s_tpm_get_random_cmd cmd;
987 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
988 	uint32_t result;
989 
990 	VB2_DEBUG("TPM: TlclGetRandom(%d)\n", length);
991 	memcpy(&cmd, &tpm_get_random_cmd, sizeof(cmd));
992 	ToTpmUint32(cmd.buffer + tpm_get_random_cmd.bytesRequested, length);
993 	/* There must be room in the response buffer for the bytes. */
994 	if (length > TPM_LARGE_ENOUGH_COMMAND_SIZE - kTpmResponseHeaderLength
995 	    - sizeof(uint32_t)) {
996 		return TPM_E_IOERROR;
997 	}
998 
999 	result = TlclSendReceive(cmd.buffer, response, sizeof(response));
1000 	if (result == TPM_SUCCESS) {
1001 		const uint8_t* get_random_cursor =
1002 				response + kTpmResponseHeaderLength;
1003 		*size = ReadTpmUint32(&get_random_cursor);
1004 
1005 		/* There must be room in the target buffer for the bytes. */
1006 		if (*size > length) {
1007 			return TPM_E_RESPONSE_TOO_LARGE;
1008 		}
1009 		memcpy(data, get_random_cursor, *size);
1010 	}
1011 
1012 	return result;
1013 }
1014 
TlclGetVersion(uint32_t * vendor,uint64_t * firmware_version,uint8_t * vendor_specific_buf,size_t * vendor_specific_buf_size)1015 uint32_t TlclGetVersion(uint32_t* vendor, uint64_t* firmware_version,
1016 			uint8_t* vendor_specific_buf,
1017 			size_t* vendor_specific_buf_size)
1018 {
1019 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
1020 	uint32_t result = TlclSendReceive(tpm_getversionval_cmd.buffer,
1021 					  response, sizeof(response));
1022 	if (result != TPM_SUCCESS)
1023 		return result;
1024 
1025 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
1026 	uint32_t size = ReadTpmUint32(&cursor);
1027 
1028 	/* Verify size >= sizeof(TPM_CAP_VERSION_INFO). */
1029 	const uint32_t kSizeofCapVersionInfo = 15;
1030 	if (size < kSizeofCapVersionInfo ||
1031 	    kTpmResponseHeaderLength + sizeof(size) + size >
1032 			TPM_LARGE_ENOUGH_COMMAND_SIZE) {
1033 		return TPM_E_IOERROR;
1034 	}
1035 
1036 	cursor += sizeof(uint16_t);  /* tag */
1037 	cursor += sizeof(uint16_t);  /* spec version */
1038 
1039 	*firmware_version = ReadTpmUint16(&cursor);
1040 
1041 	cursor += sizeof(uint16_t);  /* specLevel */
1042 	cursor += sizeof(uint8_t);  /* errataRev */
1043 
1044 	*vendor = ReadTpmUint32(&cursor);
1045 
1046 	if (vendor_specific_buf_size) {
1047 		uint16_t vendor_specific_size = ReadTpmUint16(&cursor);
1048 
1049 		if (size < kSizeofCapVersionInfo + vendor_specific_size) {
1050 			return TPM_E_IOERROR;
1051 		}
1052 		if (vendor_specific_buf) {
1053 			if (vendor_specific_size > *vendor_specific_buf_size) {
1054 				vendor_specific_size =
1055 					*vendor_specific_buf_size;
1056 			}
1057 			memcpy(vendor_specific_buf, cursor,
1058 			       vendor_specific_size);
1059 			cursor += vendor_specific_size;
1060 		}
1061 		*vendor_specific_buf_size = vendor_specific_size;
1062 	}
1063 
1064 	return TPM_SUCCESS;
1065 }
1066 
ParseIFXFirmwarePackage(const uint8_t ** cursor,TPM_IFX_FIRMWAREPACKAGE * firmware_package)1067 static void ParseIFXFirmwarePackage(const uint8_t** cursor,
1068 				    TPM_IFX_FIRMWAREPACKAGE* firmware_package)
1069 {
1070 	firmware_package->FwPackageIdentifier = ReadTpmUint32(cursor);
1071 	firmware_package->Version = ReadTpmUint32(cursor);
1072 	firmware_package->StaleVersion = ReadTpmUint32(cursor);
1073 }
1074 
TlclIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO * info)1075 uint32_t TlclIFXFieldUpgradeInfo(TPM_IFX_FIELDUPGRADEINFO* info)
1076 {
1077 	uint32_t vendor;
1078 	uint64_t firmware_version;
1079 	uint32_t result =
1080 			TlclGetVersion(&vendor, &firmware_version, NULL, NULL);
1081 	if (result != TPM_SUCCESS) {
1082 		return result;
1083 	}
1084 	if (vendor != 0x49465800) {
1085 		return TPM_E_BAD_ORDINAL;
1086 	}
1087 
1088 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
1089 	result = TlclSendReceive(tpm_ifx_fieldupgradeinforequest2_cmd.buffer,
1090 				 response, sizeof(response));
1091 	if (result != TPM_SUCCESS) {
1092 		return result;
1093 	}
1094 
1095 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
1096 	uint16_t size = ReadTpmUint16(&cursor);
1097 
1098 	/* Comments below indicate skipped fields of unknown purpose that are
1099 	 * marked "internal" in the firmware updater source. */
1100 	cursor += sizeof(uint16_t);  /* internal1 */
1101 	info->wMaxDataSize = ReadTpmUint16(&cursor);
1102 	cursor += sizeof(uint16_t);  /* sSecurityModuleLogic.internal1 */
1103 	cursor += sizeof(uint32_t);  /* sSecurityModuleLogic.internal2 */
1104 	cursor += sizeof(uint8_t[34]);  /* sSecurityModuleLogic.internal3 */
1105 	ParseIFXFirmwarePackage(&cursor, &info->sBootloaderFirmwarePackage);
1106 	uint16_t fw_entry_count = ReadTpmUint16(&cursor);
1107 	if (fw_entry_count > ARRAY_SIZE(info->sFirmwarePackages)) {
1108 		return TPM_E_INVALID_RESPONSE;
1109 	}
1110 	uint16_t i;
1111 	for (i = 0; i < fw_entry_count; ++i) {
1112 		ParseIFXFirmwarePackage(&cursor, &info->sFirmwarePackages[i]);
1113 	}
1114 	info->wSecurityModuleStatus = ReadTpmUint16(&cursor);
1115 	ParseIFXFirmwarePackage(&cursor, &info->sProcessFirmwarePackage);
1116 	cursor += sizeof(uint16_t);  /* internal6 */
1117 	cursor += sizeof(uint8_t[6]);  /* internal7 */
1118 	info->wFieldUpgradeCounter = ReadTpmUint16(&cursor);
1119 
1120 	uint32_t parsed_bytes = cursor - response;
1121 	VB2_ASSERT(parsed_bytes <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
1122 	if (parsed_bytes > kTpmResponseHeaderLength + sizeof(size) + size) {
1123 		return TPM_E_INVALID_RESPONSE;
1124 	}
1125 
1126 	return result;
1127 }
1128 
1129 #ifdef CHROMEOS_ENVIRONMENT
1130 
ParseRsaKeyParms(const uint8_t * buffer,const uint8_t * end,uint32_t * key_len,uint32_t * num_primes,uint32_t * exponent)1131 static uint32_t ParseRsaKeyParms(const uint8_t* buffer,
1132 				 const uint8_t* end,
1133 				 uint32_t* key_len,
1134 				 uint32_t* num_primes,
1135 				 uint32_t* exponent)
1136 {
1137 	if (end - buffer < 3 * sizeof(uint32_t)) {
1138 		return TPM_E_INVALID_RESPONSE;
1139 	}
1140 	*key_len = ReadTpmUint32(&buffer);
1141 	*num_primes = ReadTpmUint32(&buffer);
1142 	uint32_t exponent_size = ReadTpmUint32(&buffer);
1143 	if (end - buffer < exponent_size) {
1144 		return TPM_E_INVALID_RESPONSE;
1145 	}
1146 
1147 	if (exponent_size == 0) {
1148 		*exponent = 0x10001;
1149 	} else if (exponent_size <= sizeof(*exponent)) {
1150 		*exponent = 0;
1151 		int i;
1152 		for (i = 0; i < exponent_size; ++i) {
1153 			*exponent |= (*buffer++) << (8 * i);
1154 		}
1155 	} else {
1156 		return TPM_E_INTERNAL_ERROR;
1157 	}
1158 
1159 	return TPM_SUCCESS;
1160 }
1161 
ParseTpmPubKey(const uint8_t ** buffer,const uint8_t * end,uint32_t * algorithm,uint16_t * enc_scheme,uint16_t * sig_scheme,uint32_t * key_len,uint32_t * num_primes,uint32_t * exponent,uint8_t * modulus,uint32_t * modulus_size)1162 static uint32_t ParseTpmPubKey(const uint8_t** buffer,
1163 			       const uint8_t* end,
1164 			       uint32_t* algorithm,
1165 			       uint16_t* enc_scheme,
1166 			       uint16_t* sig_scheme,
1167 			       uint32_t* key_len,
1168 			       uint32_t* num_primes,
1169 			       uint32_t* exponent,
1170 			       uint8_t* modulus,
1171 			       uint32_t* modulus_size)
1172 {
1173 	uint32_t result = TPM_SUCCESS;
1174 
1175 	if (end - *buffer < 2 * sizeof(uint32_t) + 2 * sizeof(uint16_t)) {
1176 		return TPM_E_INVALID_RESPONSE;
1177 	}
1178 
1179 	*algorithm = ReadTpmUint32(buffer);
1180 	*enc_scheme = ReadTpmUint16(buffer);
1181 	*sig_scheme = ReadTpmUint16(buffer);
1182 
1183 	uint32_t parm_size = ReadTpmUint32(buffer);
1184 	if (end - *buffer < parm_size) {
1185 		return TPM_E_INVALID_RESPONSE;
1186 	}
1187 
1188 	if (*algorithm == TPM_ALG_RSA) {
1189 		result = ParseRsaKeyParms(*buffer, *buffer + parm_size,
1190 					  key_len, num_primes, exponent);
1191 		if (result != TPM_SUCCESS) {
1192 			return result;
1193 		}
1194 	} else {
1195 		return TPM_E_INTERNAL_ERROR;
1196 	}
1197 
1198 	*buffer += parm_size;
1199 
1200 	if (end - *buffer < sizeof(uint32_t)) {
1201 		return TPM_E_INVALID_RESPONSE;
1202 	}
1203 
1204 	uint32_t actual_modulus_size = ReadTpmUint32(buffer);
1205 	if (end - *buffer < actual_modulus_size) {
1206 		return TPM_E_INVALID_RESPONSE;
1207 	}
1208 
1209 	if (modulus && *modulus_size >= actual_modulus_size) {
1210 		memcpy(modulus, *buffer, actual_modulus_size);
1211 	} else {
1212 		result = TPM_E_BUFFER_SIZE;
1213 	}
1214 	*modulus_size = actual_modulus_size;
1215 	*buffer += actual_modulus_size;
1216 
1217 	return result;
1218 }
1219 
TlclReadPubek(uint32_t * public_exponent,uint8_t * modulus,uint32_t * modulus_size)1220 uint32_t TlclReadPubek(uint32_t* public_exponent,
1221 		       uint8_t* modulus,
1222 		       uint32_t* modulus_size)
1223 {
1224 	struct s_tpm_readpubek_cmd cmd;
1225 	memcpy(&cmd, &tpm_readpubek_cmd, sizeof(cmd));
1226 	if (vb2ex_tpm_get_random(cmd.buffer + tpm_readpubek_cmd.antiReplay,
1227 				 sizeof(TPM_NONCE)) != VB2_SUCCESS) {
1228 		return TPM_E_INTERNAL_ERROR;
1229 	}
1230 
1231 	/* The response contains the public endorsement key, so use a large
1232 	 * response buffer. */
1233 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_RSA_2048_LEN];
1234 	uint32_t result = TlclSendReceive(cmd.buffer, response,
1235 					  sizeof(response));
1236 	if (result != TPM_SUCCESS) {
1237 		return result;
1238 	}
1239 
1240 	const uint8_t* cursor = response + kTpmResponseHeaderLength;
1241 	const uint8_t* end = response + sizeof(response);
1242 
1243 	/* Parse the key */
1244 	uint32_t algorithm;
1245 	uint16_t enc_scheme;
1246 	uint16_t sig_scheme;
1247 	uint32_t key_len;
1248 	uint32_t num_primes;
1249 	result = ParseTpmPubKey(&cursor, end, &algorithm, &enc_scheme,
1250 				&sig_scheme, &key_len, &num_primes,
1251 				public_exponent, modulus, modulus_size);
1252 	if (result != TPM_SUCCESS) {
1253 		return result;
1254 	}
1255 
1256 	/* Parse the checksum */
1257 	if (end - cursor < TPM_SHA1_160_HASH_LEN) {
1258 		return TPM_E_INVALID_RESPONSE;
1259 	}
1260 	const uint8_t* checksum = cursor;
1261 	cursor += TPM_SHA1_160_HASH_LEN;
1262 
1263 	/* Check the digest */
1264 	struct vb2_sha1_context sha1_ctx;
1265 	vb2_sha1_init(&sha1_ctx);
1266 	vb2_sha1_update(&sha1_ctx, response + kTpmResponseHeaderLength,
1267 			checksum - (response + kTpmResponseHeaderLength));
1268 	vb2_sha1_update(&sha1_ctx, cmd.buffer + tpm_readpubek_cmd.antiReplay,
1269 			sizeof(TPM_NONCE));
1270 	uint8_t digest[TPM_SHA1_160_HASH_LEN];
1271 	vb2_sha1_finalize(&sha1_ctx, digest);
1272 	if (vb2_safe_memcmp(digest, checksum, sizeof(digest))) {
1273 		return TPM_E_AUTHFAIL;
1274 	}
1275 
1276 	/* Validate expectations for the EK. */
1277 	if (algorithm != TPM_ALG_RSA ||
1278 	    enc_scheme != TPM_ES_RSAESOAEP_SHA1_MGF1 ||
1279 	    sig_scheme != TPM_SS_NONE ||
1280 	    key_len != 2048 ||
1281 	    num_primes != 2) {
1282 		return TPM_E_INVALID_RESPONSE;
1283 	}
1284 
1285 	return result;
1286 }
1287 
TlclTakeOwnership(const uint8_t enc_owner_auth[TPM_RSA_2048_LEN],const uint8_t enc_srk_auth[TPM_RSA_2048_LEN],const uint8_t owner_auth[TPM_AUTH_DATA_LEN])1288 uint32_t TlclTakeOwnership(const uint8_t enc_owner_auth[TPM_RSA_2048_LEN],
1289 			   const uint8_t enc_srk_auth[TPM_RSA_2048_LEN],
1290 			   const uint8_t owner_auth[TPM_AUTH_DATA_LEN])
1291 {
1292 	/* Start an OAIP session. */
1293 	struct auth_session auth_session;
1294 	uint32_t result = StartOIAPSession(&auth_session, owner_auth);
1295 	if (result != TPM_SUCCESS) {
1296 		return result;
1297 	}
1298 
1299 	/* Build the TakeOwnership command. */
1300 	struct s_tpm_takeownership_cmd cmd;
1301 	memcpy(&cmd, &tpm_takeownership_cmd, sizeof(cmd));
1302 	memcpy(cmd.buffer + tpm_takeownership_cmd.encOwnerAuth, enc_owner_auth,
1303 	       TPM_RSA_2048_LEN);
1304 	memcpy(cmd.buffer + tpm_takeownership_cmd.encSrkAuth, enc_srk_auth,
1305 	       TPM_RSA_2048_LEN);
1306 	result = AddRequestAuthBlock(&auth_session, cmd.buffer,
1307 				     sizeof(cmd.buffer), 0);
1308 	if (result != TPM_SUCCESS) {
1309 		return result;
1310 	}
1311 
1312 	/* The response buffer needs to be large to hold the public half of the
1313 	 * generated SRK. */
1314 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE + TPM_RSA_2048_LEN];
1315 	result = TlclSendReceive(cmd.buffer, response, sizeof(response));
1316 	if (result != TPM_SUCCESS) {
1317 		return result;
1318 	}
1319 
1320 	/* Check the auth tag on the response. */
1321 	result = CheckResponseAuthBlock(&auth_session, TPM_ORD_TakeOwnership,
1322 					response, sizeof(response));
1323 	if (result != TPM_SUCCESS) {
1324 		return result;
1325 	}
1326 
1327 	return TPM_SUCCESS;
1328 }
1329 
TlclCreateDelegationFamily(uint8_t family_label)1330 uint32_t TlclCreateDelegationFamily(uint8_t family_label)
1331 {
1332 	struct s_tpm_create_delegation_family_cmd cmd;
1333 	memcpy(&cmd, &tpm_create_delegation_family_cmd, sizeof(cmd));
1334 	cmd.buffer[tpm_create_delegation_family_cmd.familyLabel] = family_label;
1335 	return Send(cmd.buffer);
1336 }
1337 
TlclReadDelegationFamilyTable(TPM_FAMILY_TABLE_ENTRY * table,uint32_t * table_size)1338 uint32_t TlclReadDelegationFamilyTable(TPM_FAMILY_TABLE_ENTRY *table,
1339 				       uint32_t* table_size)
1340 {
1341 	uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
1342 	uint32_t result = TlclSendReceive(tpm_delegate_read_table_cmd.buffer,
1343 					  response, sizeof(response));
1344 	if (result != TPM_SUCCESS) {
1345 		return result;
1346 	}
1347 
1348 	uint32_t size;
1349 	FromTpmUint32(response + sizeof(uint16_t), &size);
1350 	if (size < kTpmRequestHeaderLength + sizeof(uint32_t) ||
1351 	    size > sizeof(response)) {
1352 		return TPM_E_INVALID_RESPONSE;
1353 	}
1354 
1355 	const uint8_t* cursor = response + kTpmRequestHeaderLength;
1356 	uint32_t table_bytes = ReadTpmUint32(&cursor);
1357 
1358 	if (table_bytes > size - (cursor - response)) {
1359 		return TPM_E_INVALID_RESPONSE;
1360 	}
1361 
1362 	const uint32_t table_entry_size =
1363 		sizeof(uint16_t) + sizeof(uint8_t) + 3 * sizeof(uint32_t);
1364 	uint32_t table_entries = table_bytes / table_entry_size;
1365 	int i;
1366 	for (i = 0; i < table_entries; ++i) {
1367 		if (i >= *table_size || !table) {
1368 			result = TPM_E_BUFFER_SIZE;
1369 			break;
1370 		}
1371 
1372 		table[i].tag = ReadTpmUint16(&cursor);
1373 		table[i].familyLabel = *cursor++;
1374 		table[i].familyID = ReadTpmUint32(&cursor);
1375 		table[i].verificationCount = ReadTpmUint32(&cursor);
1376 		table[i].flags = ReadTpmUint32(&cursor);
1377 	}
1378 
1379 	*table_size = table_entries;
1380 
1381 	return result;
1382 }
1383 
1384 #endif  /* CHROMEOS_ENVIRONMENT */
1385