File: | 3rdparty/vboot/firmware/lib/tpm_lite/tlcl.c |
Warning: | line 318, column 2 Value stored to 'cursor' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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. */ |
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)) |
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. */ |
41 | int TlclPacketSize(const uint8_t* packet) |
42 | { |
43 | return TpmCommandSize(packet); |
44 | } |
45 | |
46 | /* Gets the code field of a TPM command. */ |
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. */ |
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 | */ |
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",vb2ex_printf(__func__, "TPM: command: %x%x %x%x%x%x %x%x%x%x\n" , request[0], request[1], request[2], request[3], request[4], request[5], request[6], request[7], request[8], request[9]) |
72 | request[0], request[1],vb2ex_printf(__func__, "TPM: command: %x%x %x%x%x%x %x%x%x%x\n" , request[0], request[1], request[2], request[3], request[4], request[5], request[6], request[7], request[8], request[9]) |
73 | request[2], request[3], request[4], request[5],vb2ex_printf(__func__, "TPM: command: %x%x %x%x%x%x %x%x%x%x\n" , request[0], request[1], request[2], request[3], request[4], request[5], request[6], request[7], request[8], request[9]) |
74 | request[6], request[7], request[8], request[9])vb2ex_printf(__func__, "TPM: command: %x%x %x%x%x%x %x%x%x%x\n" , request[0], request[1], request[2], request[3], request[4], request[5], 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((uint32_t) 0x00000000) != result) { |
80 | /* Communication with TPM failed, so response is garbage */ |
81 | VB2_DEBUG("TPM: command %#x send/receive failed: %#x\n",vb2ex_printf(__func__, "TPM: command %#x send/receive failed: %#x\n" , TpmCommandCode(request), result) |
82 | TpmCommandCode(request), result)vb2ex_printf(__func__, "TPM: command %#x send/receive failed: %#x\n" , 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",vb2ex_printf(__func__, "TPM: response: %x%x %x%x%x%x %x%x%x%x\n" , response[0], response[1], response[2], response[3], response [4], response[5], response[6], response[7], response[8], response [9]) |
94 | response[0], response[1],vb2ex_printf(__func__, "TPM: response: %x%x %x%x%x%x %x%x%x%x\n" , response[0], response[1], response[2], response[3], response [4], response[5], response[6], response[7], response[8], response [9]) |
95 | response[2], response[3], response[4], response[5],vb2ex_printf(__func__, "TPM: response: %x%x %x%x%x%x %x%x%x%x\n" , response[0], response[1], response[2], response[3], response [4], response[5], response[6], response[7], response[8], response [9]) |
96 | response[6], response[7], response[8], response[9])vb2ex_printf(__func__, "TPM: response: %x%x %x%x%x%x %x%x%x%x\n" , response[0], response[1], response[2], response[3], response [4], response[5], response[6], response[7], response[8], response [9]); |
97 | #endif |
98 | |
99 | VB2_DEBUG("TPM: command %#x returned %#x\n",vb2ex_printf(__func__, "TPM: command %#x returned %#x\n", TpmCommandCode (request), result) |
100 | TpmCommandCode(request), result)vb2ex_printf(__func__, "TPM: command %#x returned %#x\n", 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. */ |
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_ENVIRONMENT1 |
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((uint32_t) (0x800 + 1)) || result == TPM_E_DOING_SELFTEST((uint32_t) (0x800 + 2))) { |
118 | result = TlclContinueSelfTest(); |
119 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
120 | return result; |
121 | } |
122 | #if defined(TPM_BLOCKING_CONTINUESELFTEST1) || 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((uint32_t) (0x800 + 2))); |
136 | #endif |
137 | } |
138 | #endif /* ! defined(CHROMEOS_ENVIRONMENT) */ |
139 | return result; |
140 | } |
141 | |
142 | /* Sends a command and returns the error code. */ |
143 | static uint32_t Send(const uint8_t* command) |
144 | { |
145 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
146 | return TlclSendReceive(command, response, sizeof(response)); |
147 | } |
148 | |
149 | #ifdef CHROMEOS_ENVIRONMENT1 |
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_LEN0x14]; |
157 | uint8_t valid; |
158 | }; |
159 | |
160 | static uint32_t StartOIAPSession(struct auth_session* session, |
161 | const uint8_t secret[TPM_AUTH_DATA_LEN0x14]) |
162 | { |
163 | session->valid = 0; |
164 | |
165 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
166 | uint32_t result = TlclSendReceive(tpm_oiap_cmd.buffer, response, |
167 | sizeof(response)); |
168 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
169 | return result; |
170 | } |
171 | |
172 | uint32_t size; |
173 | FromTpmUint32(response + sizeof(uint16_t), &size); |
174 | if (size < kTpmResponseHeaderLength10 + sizeof(uint32_t) |
175 | + sizeof(TPM_NONCE)) { |
176 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
177 | } |
178 | |
179 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
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)do { if (!(cursor - response <= 256)) { vb2ex_printf(__func__ , "assertion failed: %s at %s:%d\n", "cursor - response <= TPM_LARGE_ENOUGH_COMMAND_SIZE" , "firmware/lib/tpm_lite/tlcl.c", 183); vb2ex_abort(); for (; ;); } } while (0); |
184 | |
185 | memcpy(session->shared_secret, secret, TPM_AUTH_DATA_LEN0x14); |
186 | session->valid = 1; |
187 | |
188 | return result; |
189 | } |
190 | |
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_LEN0x14]) |
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((uint32_t) 0x0000500d); |
207 | } |
208 | |
209 | /* Send OSAP command. */ |
210 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
211 | uint32_t result = TlclSendReceive(cmd.buffer, response, |
212 | sizeof(response)); |
213 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
214 | return result; |
215 | } |
216 | |
217 | /* Parse response. */ |
218 | uint32_t size; |
219 | FromTpmUint32(response + sizeof(uint16_t), &size); |
220 | if (size < kTpmResponseHeaderLength10 + sizeof(uint32_t) |
221 | + 2 * sizeof(TPM_NONCE)) { |
222 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
223 | } |
224 | |
225 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
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)do { if (!(cursor - response <= 256)) { vb2ex_printf(__func__ , "assertion failed: %s at %s:%d\n", "cursor - response <= TPM_LARGE_ENOUGH_COMMAND_SIZE" , "firmware/lib/tpm_lite/tlcl.c", 231); vb2ex_abort(); for (; ;); } } while (0); |
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(false0, VB2_HASH_SHA1, entity_usage_auth, TPM_AUTH_DATA_LEN0x14, |
240 | hmac_input, sizeof(hmac_input), &mac)) { |
241 | return TPM_E_INTERNAL_ERROR((uint32_t) 0x0000500d); |
242 | } |
243 | |
244 | _Static_assert(sizeof(session->shared_secret) == VB2_SHA1_DIGEST_SIZE20, |
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. */ |
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((uint32_t) 0x00000001); |
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 < kTpmRequestHeaderLength10) { |
268 | return TPM_E_BUFFER_SIZE((uint32_t) 0x0000500f); |
269 | } |
270 | const uint32_t size = TpmCommandSize(command_buffer); |
271 | if (size < kTpmResponseHeaderLength10 + kTpmRequestAuthBlockLength(sizeof(uint32_t) + sizeof(TPM_NONCE) + 1 + 0x14) || |
272 | size > command_buffer_size) { |
273 | return TPM_E_INTERNAL_ERROR((uint32_t) 0x0000500d); |
274 | } |
275 | const uint32_t auth_offset = size - kTpmRequestAuthBlockLength(sizeof(uint32_t) + sizeof(TPM_NONCE) + 1 + 0x14); |
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_LEN0x14 + 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((uint32_t) 0x0000500d); |
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_LEN0x14, auth_session->nonce_even.nonce, |
305 | sizeof(TPM_NONCE)); |
306 | memcpy(buf + TPM_SHA1_160_HASH_LEN0x14 + sizeof(TPM_NONCE), |
307 | auth_session->nonce_odd.nonce, sizeof(TPM_NONCE)); |
308 | buf[TPM_SHA1_160_HASH_LEN0x14 + 2 * sizeof(TPM_NONCE)] = |
309 | continue_auth_session; |
310 | struct vb2_hash mac; |
311 | if (vb2_hmac_calculate(false0, VB2_HASH_SHA1, auth_session->shared_secret, |
312 | sizeof(auth_session->shared_secret), buf, sizeof(buf), &mac)) { |
313 | return TPM_E_AUTHFAIL((uint32_t) 0x00000001); |
314 | } |
315 | |
316 | memcpy(cursor, mac.sha1, sizeof(mac.sha1)); |
317 | |
318 | cursor += sizeof(mac.sha1); |
Value stored to 'cursor' is never read | |
319 | |
320 | return TPM_SUCCESS((uint32_t) 0x00000000); |
321 | } |
322 | |
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((uint32_t) 0x00000001); |
330 | } |
331 | |
332 | if (response_buffer_size < kTpmResponseHeaderLength10) { |
333 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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 < kTpmResponseHeaderLength10 + kTpmResponseAuthBlockLength(sizeof(TPM_NONCE) + 1 + 0x14)) { |
341 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
342 | } |
343 | uint32_t auth_offset = size - kTpmResponseAuthBlockLength(sizeof(TPM_NONCE) + 1 + 0x14); |
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 + kTpmResponseHeaderLength10, |
359 | auth_offset - kTpmResponseHeaderLength10); |
360 | uint8_t hmac_input[TPM_SHA1_160_HASH_LEN0x14 + 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_LEN0x14, cursor, sizeof(TPM_NONCE)); |
366 | cursor += sizeof(TPM_NONCE); |
367 | memcpy(hmac_input + TPM_SHA1_160_HASH_LEN0x14 + sizeof(TPM_NONCE), |
368 | auth_session->nonce_odd.nonce, sizeof(TPM_NONCE)); |
369 | auth_session->valid = *cursor++; |
370 | hmac_input[TPM_SHA1_160_HASH_LEN0x14 + 2 * sizeof(TPM_NONCE)] = |
371 | auth_session->valid; |
372 | struct vb2_hash mac; |
373 | if (vb2_hmac_calculate(false0, 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((uint32_t) 0x00000001); |
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((uint32_t) 0x00000001); |
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((uint32_t) 0x00000000); |
391 | } |
392 | |
393 | #endif /* CHROMEOS_ENVIRONMENT */ |
394 | |
395 | /* Exported functions. */ |
396 | |
397 | uint32_t TlclLibInit(void) |
398 | { |
399 | return vb2ex_tpm_init(); |
400 | } |
401 | |
402 | uint32_t TlclLibClose(void) |
403 | { |
404 | return vb2ex_tpm_close(); |
405 | } |
406 | |
407 | uint32_t TlclStartup(void) |
408 | { |
409 | VB2_DEBUG("TPM: Startup\n")vb2ex_printf(__func__, "TPM: Startup\n"); |
410 | return Send(tpm_startup_cmd.buffer); |
411 | } |
412 | |
413 | uint32_t TlclSaveState(void) |
414 | { |
415 | VB2_DEBUG("TPM: SaveState\n")vb2ex_printf(__func__, "TPM: SaveState\n"); |
416 | return Send(tpm_savestate_cmd.buffer); |
417 | } |
418 | |
419 | uint32_t TlclResume(void) |
420 | { |
421 | VB2_DEBUG("TPM: Resume\n")vb2ex_printf(__func__, "TPM: Resume\n"); |
422 | return Send(tpm_resume_cmd.buffer); |
423 | } |
424 | |
425 | uint32_t TlclSelfTestFull(void) |
426 | { |
427 | VB2_DEBUG("TPM: Self test full\n")vb2ex_printf(__func__, "TPM: Self test full\n"); |
428 | return Send(tpm_selftestfull_cmd.buffer); |
429 | } |
430 | |
431 | uint32_t TlclContinueSelfTest(void) |
432 | { |
433 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
434 | VB2_DEBUG("TPM: Continue self test\n")vb2ex_printf(__func__, "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 | |
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)vb2ex_printf(__func__, "TPM: TlclDefineSpace(%#x, %#x, %d)\n" , index, perm, size); |
443 | return TlclDefineSpaceEx(NULL((void*)0), 0, index, perm, size, NULL((void*)0), 0); |
444 | } |
445 | |
446 | #ifdef CHROMEOS_ENVIRONMENT1 |
447 | |
448 | uint32_t TlclUndefineSpace(uint32_t index) |
449 | { |
450 | VB2_DEBUG("TPM: TlclUndefineSpace(%#x)\n", index)vb2ex_printf(__func__, "TPM: TlclUndefineSpace(%#x)\n", index ); |
451 | return TlclUndefineSpaceEx(NULL((void*)0), 0, index); |
452 | } |
453 | |
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((void*)0), 0); |
461 | } |
462 | |
463 | #endif /* CHROMEOS_ENVIRONMENT */ |
464 | |
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(sizeof(uint32_t) + sizeof(TPM_NONCE) + 1 + 0x14)]; |
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((void*)0)) { |
479 | if (auth_policy_size != sizeof(TPM_NV_AUTH_POLICY)) { |
480 | return TPM_E_BUFFER_SIZE((uint32_t) 0x0000500f); |
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_ENVIRONMENT1 |
491 | struct auth_session auth_session; |
492 | if (owner_auth) { |
493 | if (owner_auth_size != TPM_AUTH_DATA_LEN0x14) { |
494 | return TPM_E_AUTHFAIL((uint32_t) 0x00000001); |
495 | } |
496 | |
497 | result = StartOSAPSession(&auth_session, TPM_ET_OWNER((uint32_t) 0x02), 0, |
498 | owner_auth); |
499 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
500 | return result; |
501 | } |
502 | |
503 | ToTpmUint32(cmd + sizeof(uint16_t), sizeof(cmd)); |
504 | ToTpmUint16(cmd, TPM_TAG_RQU_AUTH1_COMMAND((uint16_t) 0xc2)); |
505 | result = AddRequestAuthBlock(&auth_session, cmd, sizeof(cmd), |
506 | 0); |
507 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
508 | return result; |
509 | } |
510 | } |
511 | #endif |
512 | |
513 | /* Send the command. */ |
514 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
515 | result = TlclSendReceive(cmd, response, sizeof(response)); |
516 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
517 | return result; |
518 | } |
519 | |
520 | #ifdef CHROMEOS_ENVIRONMENT1 |
521 | if (owner_auth) { |
522 | result = CheckResponseAuthBlock(&auth_session, |
523 | TPM_ORD_NV_DefineSpace((uint32_t) 0x000000CC), |
524 | response, sizeof(response)); |
525 | } |
526 | #endif |
527 | |
528 | return result; |
529 | } |
530 | |
531 | uint32_t TlclInitNvAuthPolicy(uint32_t pcr_selection_bitmap, |
532 | const uint8_t pcr_values[][TPM_PCR_DIGEST20], |
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((uint32_t) 0x0000500f); |
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)do { if (!((pcr_selection_bitmap & 0xff000000) == 0)) { vb2ex_printf (__func__, "assertion failed: %s at %s:%d\n", "(pcr_selection_bitmap & 0xff000000) == 0" , "firmware/lib/tpm_lite/tlcl.c", 552); vb2ex_abort(); for (; ;); } } while (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((((uint32_t)1)<<0) | (((uint32_t)1)<<1) | (((uint32_t )1)<<2) | (((uint32_t)1)<<3) | (((uint32_t)1)<< 4)) & ~TPM_LOC_THREE(((uint32_t)1)<<3); |
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_DIGEST20); |
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_DIGEST20); |
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((uint32_t) 0x00000000); |
621 | } |
622 | |
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_SIZE256]; |
627 | const int total_length = |
628 | kTpmRequestHeaderLength10 + kWriteInfoLength + length; |
629 | |
630 | VB2_DEBUG("TPM: TlclWrite(%#x, %d)\n", index, length)vb2ex_printf(__func__, "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)do { if (!(total_length <= 256)) { vb2ex_printf(__func__, "assertion failed: %s at %s:%d\n" , "total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE", "firmware/lib/tpm_lite/tlcl.c" , 632); vb2ex_abort(); for (;;); } } while (0); |
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 | |
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_SIZE256]; |
646 | uint32_t result; |
647 | |
648 | VB2_DEBUG("TPM: TlclRead(%#x, %d)\n", index, length)vb2ex_printf(__func__, "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((uint32_t) 0x00000000) && length > 0) { |
655 | const uint8_t* nv_read_cursor = |
656 | response + kTpmResponseHeaderLength10; |
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 | |
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_SIZE256]; |
670 | uint32_t result; |
671 | |
672 | VB2_DEBUG("TPM: TlclPCRRead(%#x, %d)\n", index, length)vb2ex_printf(__func__, "TPM: TlclPCRRead(%#x, %d)\n", index, length ); |
673 | if (length < kPcrDigestLength20) { |
674 | return TPM_E_IOERROR((uint32_t) 0x0000001f); |
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((uint32_t) 0x00000000)) { |
681 | const uint8_t* pcr_read_cursor = |
682 | response + kTpmResponseHeaderLength10; |
683 | memcpy(data, pcr_read_cursor, kPcrDigestLength20); |
684 | } |
685 | |
686 | return result; |
687 | } |
688 | |
689 | uint32_t TlclWriteLock(uint32_t index) |
690 | { |
691 | VB2_DEBUG("TPM: Write lock %#x\n", index)vb2ex_printf(__func__, "TPM: Write lock %#x\n", index); |
692 | return TlclWrite(index, NULL((void*)0), 0); |
693 | } |
694 | |
695 | uint32_t TlclReadLock(uint32_t index) |
696 | { |
697 | VB2_DEBUG("TPM: Read lock %#x\n", index)vb2ex_printf(__func__, "TPM: Read lock %#x\n", index); |
698 | return TlclRead(index, NULL((void*)0), 0); |
699 | } |
700 | |
701 | uint32_t TlclAssertPhysicalPresence(void) |
702 | { |
703 | VB2_DEBUG("TPM: Asserting physical presence\n")vb2ex_printf(__func__, "TPM: Asserting physical presence\n"); |
704 | return Send(tpm_ppassert_cmd.buffer); |
705 | } |
706 | |
707 | uint32_t TlclPhysicalPresenceCMDEnable(void) |
708 | { |
709 | VB2_DEBUG("TPM: Enable the physical presence command\n")vb2ex_printf(__func__, "TPM: Enable the physical presence command\n" ); |
710 | return Send(tpm_ppenable_cmd.buffer); |
711 | } |
712 | |
713 | uint32_t TlclFinalizePhysicalPresence(void) |
714 | { |
715 | VB2_DEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n")vb2ex_printf(__func__, "TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n" ); |
716 | return Send(tpm_finalizepp_cmd.buffer); |
717 | } |
718 | |
719 | uint32_t TlclAssertPhysicalPresenceResult(void) |
720 | { |
721 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
722 | return TlclSendReceive(tpm_ppassert_cmd.buffer, response, |
723 | sizeof(response)); |
724 | } |
725 | |
726 | uint32_t TlclLockPhysicalPresence(void) |
727 | { |
728 | VB2_DEBUG("TPM: Lock physical presence\n")vb2ex_printf(__func__, "TPM: Lock physical presence\n"); |
729 | return Send(tpm_pplock_cmd.buffer); |
730 | } |
731 | |
732 | uint32_t TlclSetNvLocked(void) |
733 | { |
734 | VB2_DEBUG("TPM: Set NV locked\n")vb2ex_printf(__func__, "TPM: Set NV locked\n"); |
735 | return TlclDefineSpace(TPM_NV_INDEX_LOCK((uint32_t) 0xffffffff), 0, 0); |
736 | } |
737 | |
738 | int TlclIsOwned(void) |
739 | { |
740 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256 + TPM_PUBEK_SIZE256]; |
741 | uint32_t result; |
742 | result = TlclSendReceive(tpm_readpubek_cmd.buffer, |
743 | response, sizeof(response)); |
744 | return (result != TPM_SUCCESS((uint32_t) 0x00000000)); |
745 | } |
746 | |
747 | uint32_t TlclForceClear(void) |
748 | { |
749 | VB2_DEBUG("TPM: Force clear\n")vb2ex_printf(__func__, "TPM: Force clear\n"); |
750 | return Send(tpm_forceclear_cmd.buffer); |
751 | } |
752 | |
753 | uint32_t TlclSetEnable(void) |
754 | { |
755 | VB2_DEBUG("TPM: Enabling TPM\n")vb2ex_printf(__func__, "TPM: Enabling TPM\n"); |
756 | return Send(tpm_physicalenable_cmd.buffer); |
757 | } |
758 | |
759 | uint32_t TlclClearEnable(void) |
760 | { |
761 | VB2_DEBUG("TPM: Disabling TPM\n")vb2ex_printf(__func__, "TPM: Disabling TPM\n"); |
762 | return Send(tpm_physicaldisable_cmd.buffer); |
763 | } |
764 | |
765 | uint32_t TlclSetDeactivated(uint8_t flag) |
766 | { |
767 | struct s_tpm_physicalsetdeactivated_cmd cmd; |
768 | VB2_DEBUG("TPM: SetDeactivated(%d)\n", flag)vb2ex_printf(__func__, "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 | |
774 | uint32_t TlclGetPermanentFlags(TPM_PERMANENT_FLAGS* pflags) |
775 | { |
776 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
777 | uint32_t size; |
778 | uint32_t result = TlclSendReceive(tpm_getflags_cmd.buffer, response, |
779 | sizeof(response)); |
780 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) |
781 | return result; |
782 | FromTpmUint32(response + kTpmResponseHeaderLength10, &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 + kTpmResponseHeaderLength10 + sizeof(size), |
788 | sizeof(TPM_PERMANENT_FLAGS)); |
789 | return result; |
790 | } |
791 | |
792 | uint32_t TlclGetSTClearFlags(TPM_STCLEAR_FLAGS* vflags) |
793 | { |
794 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
795 | uint32_t size; |
796 | uint32_t result = TlclSendReceive(tpm_getstclearflags_cmd.buffer, |
797 | response, sizeof(response)); |
798 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) |
799 | return result; |
800 | FromTpmUint32(response + kTpmResponseHeaderLength10, &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 + kTpmResponseHeaderLength10 + sizeof(size), |
807 | sizeof(TPM_STCLEAR_FLAGS)); |
808 | return result; |
809 | } |
810 | |
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((uint32_t) 0x00000000)) { |
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, "vb2ex_printf(__func__, "TPM: Got flags disable=%d, deactivated=%d, " "nvlocked=%d\n", pflags.disable, pflags.deactivated, pflags. nvLocked) |
825 | "nvlocked=%d\n",vb2ex_printf(__func__, "TPM: Got flags disable=%d, deactivated=%d, " "nvlocked=%d\n", pflags.disable, pflags.deactivated, pflags. nvLocked) |
826 | pflags.disable, pflags.deactivated, pflags.nvLocked)vb2ex_printf(__func__, "TPM: Got flags disable=%d, deactivated=%d, " "nvlocked=%d\n", pflags.disable, pflags.deactivated, pflags. nvLocked); |
827 | } |
828 | return result; |
829 | } |
830 | |
831 | uint32_t TlclSetGlobalLock(void) |
832 | { |
833 | uint32_t x; |
834 | VB2_DEBUG("TPM: Set global lock\n")vb2ex_printf(__func__, "TPM: Set global lock\n"); |
835 | return TlclWrite(TPM_NV_INDEX0((uint32_t) 0x00000000), (uint8_t*) &x, 0); |
836 | } |
837 | |
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[kTpmResponseHeaderLength10 + kPcrDigestLength20]; |
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, kPcrDigestLength20); |
848 | |
849 | result = TlclSendReceive(cmd.buffer, response, sizeof(response)); |
850 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) |
851 | return result; |
852 | |
853 | memcpy(out_digest, response + kTpmResponseHeaderLength10, |
854 | kPcrDigestLength20); |
855 | return result; |
856 | } |
857 | |
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 | |
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 | |
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((uint32_t) 0x0000500f); |
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_SIZE256]; |
919 | uint32_t result = TlclSendReceive(cmd.buffer, response, |
920 | sizeof(response)); |
921 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
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((uint32_t) 0x00005005); |
928 | } |
929 | |
930 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
931 | uint32_t cap_size = ReadTpmUint32(&cursor); |
932 | if (cap_size > |
933 | response_size - sizeof(cap_size) - kTpmResponseHeaderLength10) { |
934 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500e); |
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((uint32_t) 0x00000000); |
964 | } |
965 | |
966 | uint32_t TlclGetOwnership(uint8_t* owned) |
967 | { |
968 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
969 | uint32_t size; |
970 | uint32_t result = TlclSendReceive(tpm_getownership_cmd.buffer, |
971 | response, sizeof(response)); |
972 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) |
973 | return result; |
974 | FromTpmUint32(response + kTpmResponseHeaderLength10, &size); |
975 | /* TODO(crbug.com/379255): This fails. Find out why. |
976 | * VB2_ASSERT(size == sizeof(*owned)); |
977 | */ |
978 | memcpy(owned, |
979 | response + kTpmResponseHeaderLength10 + sizeof(size), |
980 | sizeof(*owned)); |
981 | return result; |
982 | } |
983 | |
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_SIZE256]; |
988 | uint32_t result; |
989 | |
990 | VB2_DEBUG("TPM: TlclGetRandom(%d)\n", length)vb2ex_printf(__func__, "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_SIZE256 - kTpmResponseHeaderLength10 |
995 | - sizeof(uint32_t)) { |
996 | return TPM_E_IOERROR((uint32_t) 0x0000001f); |
997 | } |
998 | |
999 | result = TlclSendReceive(cmd.buffer, response, sizeof(response)); |
1000 | if (result == TPM_SUCCESS((uint32_t) 0x00000000)) { |
1001 | const uint8_t* get_random_cursor = |
1002 | response + kTpmResponseHeaderLength10; |
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((uint32_t) 0x00005005); |
1008 | } |
1009 | memcpy(data, get_random_cursor, *size); |
1010 | } |
1011 | |
1012 | return result; |
1013 | } |
1014 | |
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_SIZE256]; |
1020 | uint32_t result = TlclSendReceive(tpm_getversionval_cmd.buffer, |
1021 | response, sizeof(response)); |
1022 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) |
1023 | return result; |
1024 | |
1025 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
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 | kTpmResponseHeaderLength10 + sizeof(size) + size > |
1032 | TPM_LARGE_ENOUGH_COMMAND_SIZE256) { |
1033 | return TPM_E_IOERROR((uint32_t) 0x0000001f); |
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((uint32_t) 0x0000001f); |
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((uint32_t) 0x00000000); |
1065 | } |
1066 | |
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 | |
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((void*)0), NULL((void*)0)); |
1081 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1082 | return result; |
1083 | } |
1084 | if (vendor != 0x49465800) { |
1085 | return TPM_E_BAD_ORDINAL((uint32_t) 0x0000000a); |
1086 | } |
1087 | |
1088 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
1089 | result = TlclSendReceive(tpm_ifx_fieldupgradeinforequest2_cmd.buffer, |
1090 | response, sizeof(response)); |
1091 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1092 | return result; |
1093 | } |
1094 | |
1095 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
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)(sizeof(info->sFirmwarePackages) / sizeof((info->sFirmwarePackages )[0]))) { |
1108 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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)do { if (!(parsed_bytes <= 256)) { vb2ex_printf(__func__, "assertion failed: %s at %s:%d\n" , "parsed_bytes <= TPM_LARGE_ENOUGH_COMMAND_SIZE", "firmware/lib/tpm_lite/tlcl.c" , 1121); vb2ex_abort(); for (;;); } } while (0); |
1122 | if (parsed_bytes > kTpmResponseHeaderLength10 + sizeof(size) + size) { |
1123 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
1124 | } |
1125 | |
1126 | return result; |
1127 | } |
1128 | |
1129 | #ifdef CHROMEOS_ENVIRONMENT1 |
1130 | |
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((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500d); |
1157 | } |
1158 | |
1159 | return TPM_SUCCESS((uint32_t) 0x00000000); |
1160 | } |
1161 | |
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((uint32_t) 0x00000000); |
1174 | |
1175 | if (end - *buffer < 2 * sizeof(uint32_t) + 2 * sizeof(uint16_t)) { |
1176 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500e); |
1186 | } |
1187 | |
1188 | if (*algorithm == TPM_ALG_RSA((uint16_t)0x0001)) { |
1189 | result = ParseRsaKeyParms(*buffer, *buffer + parm_size, |
1190 | key_len, num_primes, exponent); |
1191 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1192 | return result; |
1193 | } |
1194 | } else { |
1195 | return TPM_E_INTERNAL_ERROR((uint32_t) 0x0000500d); |
1196 | } |
1197 | |
1198 | *buffer += parm_size; |
1199 | |
1200 | if (end - *buffer < sizeof(uint32_t)) { |
1201 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
1202 | } |
1203 | |
1204 | uint32_t actual_modulus_size = ReadTpmUint32(buffer); |
1205 | if (end - *buffer < actual_modulus_size) { |
1206 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500f); |
1213 | } |
1214 | *modulus_size = actual_modulus_size; |
1215 | *buffer += actual_modulus_size; |
1216 | |
1217 | return result; |
1218 | } |
1219 | |
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((uint32_t) 0x0000500d); |
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_SIZE256 + TPM_RSA_2048_LEN0x100]; |
1234 | uint32_t result = TlclSendReceive(cmd.buffer, response, |
1235 | sizeof(response)); |
1236 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1237 | return result; |
1238 | } |
1239 | |
1240 | const uint8_t* cursor = response + kTpmResponseHeaderLength10; |
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((uint32_t) 0x00000000)) { |
1253 | return result; |
1254 | } |
1255 | |
1256 | /* Parse the checksum */ |
1257 | if (end - cursor < TPM_SHA1_160_HASH_LEN0x14) { |
1258 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
1259 | } |
1260 | const uint8_t* checksum = cursor; |
1261 | cursor += TPM_SHA1_160_HASH_LEN0x14; |
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 + kTpmResponseHeaderLength10, |
1267 | checksum - (response + kTpmResponseHeaderLength10)); |
1268 | vb2_sha1_update(&sha1_ctx, cmd.buffer + tpm_readpubek_cmd.antiReplay, |
1269 | sizeof(TPM_NONCE)); |
1270 | uint8_t digest[TPM_SHA1_160_HASH_LEN0x14]; |
1271 | vb2_sha1_finalize(&sha1_ctx, digest); |
1272 | if (vb2_safe_memcmp(digest, checksum, sizeof(digest))) { |
1273 | return TPM_E_AUTHFAIL((uint32_t) 0x00000001); |
1274 | } |
1275 | |
1276 | /* Validate expectations for the EK. */ |
1277 | if (algorithm != TPM_ALG_RSA((uint16_t)0x0001) || |
1278 | enc_scheme != TPM_ES_RSAESOAEP_SHA1_MGF1((uint16_t)0x0003) || |
1279 | sig_scheme != TPM_SS_NONE((uint16_t)0x0001) || |
1280 | key_len != 2048 || |
1281 | num_primes != 2) { |
1282 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
1283 | } |
1284 | |
1285 | return result; |
1286 | } |
1287 | |
1288 | uint32_t TlclTakeOwnership(uint8_t enc_owner_auth[TPM_RSA_2048_LEN0x100], |
1289 | uint8_t enc_srk_auth[TPM_RSA_2048_LEN0x100], |
1290 | uint8_t owner_auth[TPM_AUTH_DATA_LEN0x14]) |
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((uint32_t) 0x00000000)) { |
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_LEN0x100); |
1304 | memcpy(cmd.buffer + tpm_takeownership_cmd.encSrkAuth, enc_srk_auth, |
1305 | TPM_RSA_2048_LEN0x100); |
1306 | result = AddRequestAuthBlock(&auth_session, cmd.buffer, |
1307 | sizeof(cmd.buffer), 0); |
1308 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
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_SIZE256 + TPM_RSA_2048_LEN0x100]; |
1315 | result = TlclSendReceive(cmd.buffer, response, sizeof(response)); |
1316 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1317 | return result; |
1318 | } |
1319 | |
1320 | /* Check the auth tag on the response. */ |
1321 | result = CheckResponseAuthBlock(&auth_session, TPM_ORD_TakeOwnership((uint32_t) 0x0000000D), |
1322 | response, sizeof(response)); |
1323 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1324 | return result; |
1325 | } |
1326 | |
1327 | return TPM_SUCCESS((uint32_t) 0x00000000); |
1328 | } |
1329 | |
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 | |
1338 | uint32_t TlclReadDelegationFamilyTable(TPM_FAMILY_TABLE_ENTRY *table, |
1339 | uint32_t* table_size) |
1340 | { |
1341 | uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE256]; |
1342 | uint32_t result = TlclSendReceive(tpm_delegate_read_table_cmd.buffer, |
1343 | response, sizeof(response)); |
1344 | if (result != TPM_SUCCESS((uint32_t) 0x00000000)) { |
1345 | return result; |
1346 | } |
1347 | |
1348 | uint32_t size; |
1349 | FromTpmUint32(response + sizeof(uint16_t), &size); |
1350 | if (size < kTpmRequestHeaderLength10 + sizeof(uint32_t) || |
1351 | size > sizeof(response)) { |
1352 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
1353 | } |
1354 | |
1355 | const uint8_t* cursor = response + kTpmRequestHeaderLength10; |
1356 | uint32_t table_bytes = ReadTpmUint32(&cursor); |
1357 | |
1358 | if (table_bytes > size - (cursor - response)) { |
1359 | return TPM_E_INVALID_RESPONSE((uint32_t) 0x0000500e); |
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((uint32_t) 0x0000500f); |
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 */ |