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