File: | 3rdparty/vboot/firmware/lib/tpm_lite/tlcl.c |
Warning: | line 637, column 2 Null pointer passed to 2nd parameter expecting 'nonnull' |
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); | |||
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 */ |