blob: 8eccfa10ece6b241c1b65a2d4b22e3f52e77e841 [file] [log] [blame]
Andrey Pronin9b10e512021-04-13 11:18:53 -07001/* Copyright 2018 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
Andrey Pronincd7bcce2021-04-14 00:54:12 -07006#include <string.h>
7
Andrey Pronin04db55a2021-04-26 22:09:34 -07008#include "pinweaver.h"
9#include "pinweaver_eal.h"
10
Andrey Pronincd7bcce2021-04-14 00:54:12 -070011/* TODO(apronin): get rid of temporary #defines */
12
13#ifndef SHA256_DIGEST_SIZE
14#define SHA256_DIGEST_SIZE (256/8)
15#endif
16
17#ifndef AES256_BLOCK_CIPHER_KEY_SIZE
18#define AES256_BLOCK_CIPHER_KEY_SIZE (256/8)
19#endif
20
21#ifndef EC_SUCCESS
22#define EC_SUCCESS 0
23#endif
24
25#ifndef MIN
26#define MIN(a,b) ((a) < (b) ? (a) : (b))
27#endif
Andrey Pronin9b10e512021-04-13 11:18:53 -070028
29/* Compile time sanity checks. */
30/* Make sure the hash size is consistent with dcrypto. */
31BUILD_ASSERT(PW_HASH_SIZE >= SHA256_DIGEST_SIZE);
32
33/* sizeof(struct leaf_data_t) % 16 should be zero */
34BUILD_ASSERT(sizeof(struct leaf_sensitive_data_t) % PW_WRAP_BLOCK_SIZE == 0);
35
36BUILD_ASSERT(sizeof(((struct merkle_tree_t *)0)->wrap_key) ==
37 AES256_BLOCK_CIPHER_KEY_SIZE);
38
39/* Verify that the nvmem_vars log entries have the correct sizes. */
40BUILD_ASSERT(sizeof(struct pw_long_term_storage_t) +
41 sizeof(struct pw_log_storage_t) <= PW_MAX_VAR_USAGE);
42
43/* Verify that the request structs will fit into the message. */
44BUILD_ASSERT(PW_MAX_MESSAGE_SIZE >=
45 sizeof(struct pw_request_header_t) +
Howard Yangd4d2e7a2022-08-02 17:57:53 +080046 sizeof(union {pw_request_insert_leaf_t insert_leaf;
47 pw_request_remove_leaf_t remove_leaf;
48 pw_request_try_auth_t try_auth;
49 pw_request_reset_auth_t reset_auth;
50 pw_request_get_log_t get_log;
51 pw_request_log_replay_t log_replay; }) +
Andrey Pronin9b10e512021-04-13 11:18:53 -070052 sizeof(struct leaf_public_data_t) +
53 sizeof(struct leaf_sensitive_data_t) +
54 PW_MAX_PATH_SIZE);
55
56#define PW_MAX_RESPONSE_SIZE (sizeof(struct pw_response_header_t) + \
Howard Yangd4d2e7a2022-08-02 17:57:53 +080057 sizeof(union {pw_response_insert_leaf_t insert_leaf; \
58 pw_response_try_auth_t try_auth; \
59 pw_response_reset_auth_t reset_auth; \
60 pw_response_log_replay_t log_replay; }) + \
Andrey Pronin9b10e512021-04-13 11:18:53 -070061 PW_LEAF_PAYLOAD_SIZE)
62#define PW_VALID_PCR_CRITERIA_SIZE \
63 (sizeof(struct valid_pcr_value_t) * PW_MAX_PCR_CRITERIA_COUNT)
64/* Verify that the request structs will fit into the message. */
65BUILD_ASSERT(PW_MAX_MESSAGE_SIZE >= PW_MAX_RESPONSE_SIZE);
Andrey Pronin9b10e512021-04-13 11:18:53 -070066
67/* PW_MAX_PATH_SIZE should not change unless PW_LEAF_MAJOR_VERSION changes too.
68 * Update these statements whenever these constants are changed to remind future
69 * maintainers about this requirement.
70 *
71 * This requirement helps guarantee that forward compatibility across the same
72 * PW_LEAF_MAJOR_VERSION doesn't break because of a path length becoming too
73 * long after new fields are added to struct wrapped_leaf_data_t or its sub
74 * fields.
75 */
76BUILD_ASSERT(PW_LEAF_MAJOR_VERSION == 0);
77BUILD_ASSERT(PW_MAX_PATH_SIZE == 1024);
78
79/* If fields are appended to struct leaf_sensitive_data_t, an encryption
80 * operation should be performed on them reusing the same IV since the prefix
81 * won't change.
82 *
83 * If any data in the original struct leaf_sensitive_data_t changes, a new IV
84 * should be generated and stored as part of the log for a replay to be
85 * possible.
86 */
87BUILD_ASSERT(sizeof(struct leaf_sensitive_data_t) == 3 * PW_SECRET_SIZE);
88
Andrey Pronincd7bcce2021-04-14 00:54:12 -070089#define RESTART_TIMER_THRESHOLD (10 /* seconds */)
Andrey Pronin9b10e512021-04-13 11:18:53 -070090
91/* This var caches the restart count so the nvram log structure doesn't need to
92 * be walked every time try_auth request is made.
93 */
94uint32_t pw_restart_count;
95
96/******************************************************************************/
97/* Struct helper functions.
98 */
99
100void import_leaf(const struct unimported_leaf_data_t *unimported,
101 struct imported_leaf_data_t *imported)
102{
103 imported->head = &unimported->head;
104 imported->hmac = unimported->hmac;
105 imported->iv = unimported->iv;
106 imported->pub = (const struct leaf_public_data_t *)unimported->payload;
107 imported->cipher_text = unimported->payload + unimported->head.pub_len;
108 imported->hashes = (const uint8_t (*)[PW_HASH_SIZE])(
109 imported->cipher_text + unimported->head.sec_len);
110}
111
112/******************************************************************************/
113/* Basic operations required by the Merkle tree.
114 */
115
Andrey Pronin9b10e512021-04-13 11:18:53 -0700116/* Creates an empty merkle_tree with the given parameters. */
117static int create_merkle_tree(struct bits_per_level_t bits_per_level,
118 struct height_t height,
119 struct merkle_tree_t *merkle_tree)
120{
121 uint16_t fan_out = 1 << bits_per_level.v;
122 uint8_t temp_hash[PW_HASH_SIZE] = {};
123 uint8_t hx;
124 uint16_t kx;
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700125 pinweaver_eal_sha256_ctx_t ctx;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700126
127 merkle_tree->bits_per_level = bits_per_level;
128 merkle_tree->height = height;
129
Leo Lai788f41e2021-08-11 00:36:24 +0800130 int ret;
131
Andrey Pronin9b10e512021-04-13 11:18:53 -0700132 /* Initialize the root hash. */
133 for (hx = 0; hx < height.v; ++hx) {
Leo Lai788f41e2021-08-11 00:36:24 +0800134 ret = pinweaver_eal_sha256_init(&ctx);
135 if (ret)
136 return ret;
137 for (kx = 0; kx < fan_out; ++kx) {
138 ret = pinweaver_eal_sha256_update(&ctx, temp_hash,
139 PW_HASH_SIZE);
140 if (ret) {
141 pinweaver_eal_sha256_final(&ctx, temp_hash);
142 return ret;
143 }
144 }
145 ret = pinweaver_eal_sha256_final(&ctx, temp_hash);
146 if (ret)
147 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700148 }
Leo Laidb207912021-08-11 16:41:18 +0800149 ret = pinweaver_eal_memcpy_s(merkle_tree->root,
150 sizeof(merkle_tree->root), temp_hash,
151 PW_HASH_SIZE);
152 if (ret != EC_SUCCESS)
153 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700154
Leo Lai788f41e2021-08-11 00:36:24 +0800155 ret = pinweaver_eal_rand_bytes(
156 merkle_tree->key_derivation_nonce,
157 sizeof(merkle_tree->key_derivation_nonce));
158 if (ret)
159 return ret;
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700160 return pinweaver_eal_derive_keys(merkle_tree);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700161}
162
163/* Computes the HMAC for an encrypted leaf using the key in the merkle_tree. */
Leo Lai788f41e2021-08-11 00:36:24 +0800164static int compute_hmac(const struct merkle_tree_t *merkle_tree,
165 const struct imported_leaf_data_t *imported_leaf_data,
166 uint8_t result[PW_HASH_SIZE])
Andrey Pronin9b10e512021-04-13 11:18:53 -0700167{
Leo Lai788f41e2021-08-11 00:36:24 +0800168 int ret;
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700169 pinweaver_eal_hmac_sha256_ctx_t hmac;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700170
Leo Lai788f41e2021-08-11 00:36:24 +0800171 ret = pinweaver_eal_hmac_sha256_init(&hmac, merkle_tree->hmac_key,
172 sizeof(merkle_tree->hmac_key));
173 if (ret)
174 return ret;
175 ret = pinweaver_eal_hmac_sha256_update(
176 &hmac, imported_leaf_data->head,
177 sizeof(*imported_leaf_data->head));
178 if (ret) {
179 pinweaver_eal_hmac_sha256_final(&hmac, result);
180 return ret;
181 }
182 ret = pinweaver_eal_hmac_sha256_update(&hmac, imported_leaf_data->iv,
183 sizeof(PW_WRAP_BLOCK_SIZE));
184 if (ret) {
185 pinweaver_eal_hmac_sha256_final(&hmac, result);
186 return ret;
187 }
188 ret = pinweaver_eal_hmac_sha256_update(
189 &hmac, imported_leaf_data->pub,
190 imported_leaf_data->head->pub_len);
191 if (ret) {
192 pinweaver_eal_hmac_sha256_final(&hmac, result);
193 return ret;
194 }
195 ret = pinweaver_eal_hmac_sha256_update(
196 &hmac, imported_leaf_data->cipher_text,
197 imported_leaf_data->head->sec_len);
198 if (ret) {
199 pinweaver_eal_hmac_sha256_final(&hmac, result);
200 return ret;
201 }
202 return pinweaver_eal_hmac_sha256_final(&hmac, result);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700203}
204
205/* Computes the root hash for the specified path and child hash. */
Leo Lai788f41e2021-08-11 00:36:24 +0800206static int compute_root_hash(const struct merkle_tree_t *merkle_tree,
207 struct label_t path,
208 const uint8_t hashes[][PW_HASH_SIZE],
209 const uint8_t child_hash[PW_HASH_SIZE],
210 uint8_t new_root[PW_HASH_SIZE])
Andrey Pronin9b10e512021-04-13 11:18:53 -0700211{
212 /* This is one less than the fan out, the number of sibling hashes. */
213 const uint16_t num_aux = (1 << merkle_tree->bits_per_level.v) - 1;
214 const uint16_t path_suffix_mask = num_aux;
215 uint8_t temp_hash[PW_HASH_SIZE];
216 uint8_t hx = 0;
217 uint64_t index = path.v;
Leo Laidb207912021-08-11 16:41:18 +0800218 int ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700219
Leo Lai788f41e2021-08-11 00:36:24 +0800220 if (compute_hash(hashes, num_aux,
221 (struct index_t){ index & path_suffix_mask },
222 child_hash, temp_hash)) {
223 return PW_ERR_CRYPTO_FAILURE;
224 }
Andrey Pronin9b10e512021-04-13 11:18:53 -0700225 for (hx = 1; hx < merkle_tree->height.v; ++hx) {
226 hashes += num_aux;
227 index = index >> merkle_tree->bits_per_level.v;
Leo Lai788f41e2021-08-11 00:36:24 +0800228 if (compute_hash(hashes, num_aux,
229 (struct index_t){ index & path_suffix_mask },
230 temp_hash, temp_hash)) {
231 return PW_ERR_CRYPTO_FAILURE;
232 }
Andrey Pronin9b10e512021-04-13 11:18:53 -0700233 }
Leo Laidb207912021-08-11 16:41:18 +0800234 ret = pinweaver_eal_memcpy_s(new_root, PW_HASH_SIZE, temp_hash,
235 sizeof(temp_hash));
236 if (ret != EC_SUCCESS)
237 return PW_ERR_INTERNAL_FAILURE;
Leo Lai788f41e2021-08-11 00:36:24 +0800238 return EC_SUCCESS;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700239}
240
241/* Checks to see the specified path is valid. The length of the path should be
242 * validated prior to calling this function.
243 *
244 * Returns 0 on success or an error code otherwise.
245 */
246static int authenticate_path(const struct merkle_tree_t *merkle_tree,
247 struct label_t path,
248 const uint8_t hashes[][PW_HASH_SIZE],
249 const uint8_t child_hash[PW_HASH_SIZE])
250{
251 uint8_t parent[PW_HASH_SIZE];
252
Leo Lai788f41e2021-08-11 00:36:24 +0800253 if (compute_root_hash(merkle_tree, path, hashes, child_hash, parent) !=
254 0)
255 return PW_ERR_CRYPTO_FAILURE;
Yi Chouddf3b452021-08-11 13:40:11 +0800256 if (pinweaver_eal_safe_memcmp(parent, merkle_tree->root,
257 sizeof(parent)) != 0)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700258 return PW_ERR_PATH_AUTH_FAILED;
259 return EC_SUCCESS;
260}
261
262static void init_wrapped_leaf_data(
263 struct wrapped_leaf_data_t *wrapped_leaf_data)
264{
265 wrapped_leaf_data->head.leaf_version.major = PW_LEAF_MAJOR_VERSION;
266 wrapped_leaf_data->head.leaf_version.minor = PW_LEAF_MINOR_VERSION;
267 wrapped_leaf_data->head.pub_len = sizeof(wrapped_leaf_data->pub);
268 wrapped_leaf_data->head.sec_len =
269 sizeof(wrapped_leaf_data->cipher_text);
270}
271
272/* Encrypts the leaf meta data. */
273static int encrypt_leaf_data(const struct merkle_tree_t *merkle_tree,
274 const struct leaf_data_t *leaf_data,
275 struct wrapped_leaf_data_t *wrapped_leaf_data)
276{
Leo Laidb207912021-08-11 16:41:18 +0800277 int ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700278 /* Generate a random IV.
279 *
280 * If fields are appended to struct leaf_sensitive_data_t, an encryption
281 * operation should be performed on them reusing the same IV since the
282 * prefix won't change.
283 *
284 * If any data of in the original struct leaf_sensitive_data_t changes,
285 * a new IV should be generated and stored as part of the log for a
286 * replay to be possible.
287 */
Leo Lai788f41e2021-08-11 00:36:24 +0800288 if (pinweaver_eal_rand_bytes(wrapped_leaf_data->iv,
289 sizeof(wrapped_leaf_data->iv))) {
290 return PW_ERR_CRYPTO_FAILURE;
291 }
Leo Laidb207912021-08-11 16:41:18 +0800292 ret = pinweaver_eal_memcpy_s(&wrapped_leaf_data->pub,
293 sizeof(wrapped_leaf_data->pub),
294 &leaf_data->pub, sizeof(leaf_data->pub));
295 if (ret != EC_SUCCESS)
296 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin1197a0d2021-05-14 20:18:05 -0700297 if (pinweaver_eal_aes256_ctr(merkle_tree->wrap_key,
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700298 sizeof(merkle_tree->wrap_key),
299 wrapped_leaf_data->iv,
300 &leaf_data->sec,
301 sizeof(leaf_data->sec),
302 wrapped_leaf_data->cipher_text)) {
Andrey Pronin9b10e512021-04-13 11:18:53 -0700303 return PW_ERR_CRYPTO_FAILURE;
304 }
305 return EC_SUCCESS;
306}
307
308/* Decrypts the leaf meta data. */
309static int decrypt_leaf_data(
310 const struct merkle_tree_t *merkle_tree,
311 const struct imported_leaf_data_t *imported_leaf_data,
312 struct leaf_data_t *leaf_data)
313{
Leo Laidb207912021-08-11 16:41:18 +0800314 int ret;
315 ret = pinweaver_eal_memcpy_s(&leaf_data->pub, sizeof(leaf_data->pub),
316 imported_leaf_data->pub,
317 MIN(imported_leaf_data->head->pub_len,
318 sizeof(struct leaf_public_data_t)));
319 if (ret != EC_SUCCESS)
320 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin1197a0d2021-05-14 20:18:05 -0700321 if (pinweaver_eal_aes256_ctr(merkle_tree->wrap_key,
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700322 sizeof(merkle_tree->wrap_key),
323 imported_leaf_data->iv,
324 imported_leaf_data->cipher_text,
325 sizeof(leaf_data->sec),
326 &leaf_data->sec)) {
Andrey Pronin9b10e512021-04-13 11:18:53 -0700327 return PW_ERR_CRYPTO_FAILURE;
328 }
329 return EC_SUCCESS;
330}
331
332static int handle_leaf_update(
333 const struct merkle_tree_t *merkle_tree,
334 const struct leaf_data_t *leaf_data,
335 const uint8_t hashes[][PW_HASH_SIZE],
336 struct wrapped_leaf_data_t *wrapped_leaf_data,
337 uint8_t new_root[PW_HASH_SIZE],
338 const struct imported_leaf_data_t *optional_old_wrapped_data)
339{
340 int ret;
341 struct imported_leaf_data_t ptrs;
342
343 init_wrapped_leaf_data(wrapped_leaf_data);
344 if (optional_old_wrapped_data == NULL) {
345 ret = encrypt_leaf_data(merkle_tree, leaf_data,
346 wrapped_leaf_data);
347 if (ret != EC_SUCCESS)
348 return ret;
349 } else {
Leo Laidb207912021-08-11 16:41:18 +0800350 ret = pinweaver_eal_memcpy_s(wrapped_leaf_data->iv,
351 sizeof(wrapped_leaf_data->iv),
352 optional_old_wrapped_data->iv,
353 sizeof(wrapped_leaf_data->iv));
354 if (ret != EC_SUCCESS)
355 return PW_ERR_INTERNAL_FAILURE;
356 ret = pinweaver_eal_memcpy_s(&wrapped_leaf_data->pub,
357 sizeof(wrapped_leaf_data->pub),
358 &leaf_data->pub,
359 sizeof(leaf_data->pub));
360 if (ret != EC_SUCCESS)
361 return PW_ERR_INTERNAL_FAILURE;
362 ret = pinweaver_eal_memcpy_s(
363 wrapped_leaf_data->cipher_text,
364 sizeof(wrapped_leaf_data->cipher_text),
365 optional_old_wrapped_data->cipher_text,
366 sizeof(wrapped_leaf_data->cipher_text));
367 if (ret != EC_SUCCESS)
368 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700369 }
370
371 import_leaf((const struct unimported_leaf_data_t *)wrapped_leaf_data,
372 &ptrs);
Leo Lai788f41e2021-08-11 00:36:24 +0800373 ret = compute_hmac(merkle_tree, &ptrs, wrapped_leaf_data->hmac);
374 if (ret)
375 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700376
Leo Lai788f41e2021-08-11 00:36:24 +0800377 ret = compute_root_hash(merkle_tree, leaf_data->pub.label, hashes,
378 wrapped_leaf_data->hmac, new_root);
379 if (ret)
380 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700381
382 return EC_SUCCESS;
383}
384
385/******************************************************************************/
386/* Parameter and state validation functions.
387 */
388
389static int validate_tree_parameters(struct bits_per_level_t bits_per_level,
390 struct height_t height)
391{
392 uint8_t fan_out = 1 << bits_per_level.v;
393
394 if (bits_per_level.v < BITS_PER_LEVEL_MIN ||
395 bits_per_level.v > BITS_PER_LEVEL_MAX)
396 return PW_ERR_BITS_PER_LEVEL_INVALID;
397
398 if (height.v < HEIGHT_MIN ||
399 height.v > HEIGHT_MAX(bits_per_level.v) ||
400 ((fan_out - 1) * height.v) * PW_HASH_SIZE > PW_MAX_PATH_SIZE)
401 return PW_ERR_HEIGHT_INVALID;
402
403 return EC_SUCCESS;
404}
405
406/* Verifies that merkle_tree has been initialized. */
407static int validate_tree(const struct merkle_tree_t *merkle_tree)
408{
409 if (validate_tree_parameters(merkle_tree->bits_per_level,
410 merkle_tree->height) != EC_SUCCESS)
411 return PW_ERR_TREE_INVALID;
412 return EC_SUCCESS;
413}
414
415/* Checks the following conditions:
416 * Extra index fields should be all zero.
417 */
418static int validate_label(const struct merkle_tree_t *merkle_tree,
419 struct label_t path)
420{
421 uint8_t shift_by = merkle_tree->bits_per_level.v *
422 merkle_tree->height.v;
423
424 if ((path.v >> shift_by) == 0)
425 return EC_SUCCESS;
426 return PW_ERR_LABEL_INVALID;
427}
428
429/* Checks the following conditions:
430 * Columns should be strictly increasing.
431 * Zeroes for filler at the end of the delay_schedule are permitted.
432 */
433static int validate_delay_schedule(const struct delay_schedule_entry_t
434 delay_schedule[PW_SCHED_COUNT])
435{
436 size_t x;
437
438 /* The first entry should not be useless. */
Yi Choueed2b652021-08-11 13:47:15 +0800439 if (delay_schedule[0].attempt_count.v == 0 ||
440 delay_schedule[0].time_diff.v == 0)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700441 return PW_ERR_DELAY_SCHEDULE_INVALID;
442
443 for (x = PW_SCHED_COUNT - 1; x > 0; --x) {
444 if (delay_schedule[x].attempt_count.v == 0) {
445 if (delay_schedule[x].time_diff.v != 0)
446 return PW_ERR_DELAY_SCHEDULE_INVALID;
447 } else if (delay_schedule[x].attempt_count.v <=
448 delay_schedule[x - 1].attempt_count.v ||
449 delay_schedule[x].time_diff.v <=
450 delay_schedule[x - 1].time_diff.v) {
451 return PW_ERR_DELAY_SCHEDULE_INVALID;
452 }
453 }
454 return EC_SUCCESS;
455}
456
457static int validate_pcr_value(const struct valid_pcr_value_t
458 valid_pcr_criteria[PW_MAX_PCR_CRITERIA_COUNT])
459{
460 size_t index;
461 uint8_t sha256_of_selected_pcr[SHA256_DIGEST_SIZE];
462
463 for (index = 0; index < PW_MAX_PCR_CRITERIA_COUNT; ++index) {
464 /* The criteria with bitmask[0] = bitmask[1] = 0 is considered
465 * the end of list criteria. If it happens that the first
466 * bitmask is zero, we consider that no criteria has to be
467 * satisfied and return success in that case.
468 */
469 if (valid_pcr_criteria[index].bitmask[0] == 0 &&
470 valid_pcr_criteria[index].bitmask[1] == 0) {
471 if (index == 0)
472 return EC_SUCCESS;
473
474 return PW_ERR_PCR_NOT_MATCH;
475 }
476
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700477 if (pinweaver_eal_get_current_pcr_digest(
478 valid_pcr_criteria[index].bitmask,
479 sha256_of_selected_pcr)) {
480 PINWEAVER_EAL_INFO(
Andrey Pronin9b10e512021-04-13 11:18:53 -0700481 "PinWeaver: Read PCR error, bitmask: %d, %d",
482 valid_pcr_criteria[index].bitmask[0],
483 valid_pcr_criteria[index].bitmask[1]);
484 return PW_ERR_PCR_NOT_MATCH;
485 }
486
487 /* Check if the curent PCR digest is the same as expected by
488 * criteria.
489 */
Yi Chouddf3b452021-08-11 13:40:11 +0800490 if (pinweaver_eal_safe_memcmp(sha256_of_selected_pcr,
491 valid_pcr_criteria[index].digest,
492 SHA256_DIGEST_SIZE) == 0) {
Andrey Pronin9b10e512021-04-13 11:18:53 -0700493 return EC_SUCCESS;
494 }
495 }
496
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700497 PINWEAVER_EAL_INFO("PinWeaver: No criteria matches PCR values");
Andrey Pronin9b10e512021-04-13 11:18:53 -0700498 return PW_ERR_PCR_NOT_MATCH;
499}
500
Leo Lai8c9892c2021-06-22 21:32:02 +0800501static uint32_t expected_payload_len(int minor_version)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700502{
503 switch (minor_version) {
504 case 0:
505 return PW_LEAF_PAYLOAD_SIZE - PW_VALID_PCR_CRITERIA_SIZE;
506 case PW_LEAF_MINOR_VERSION:
507 return PW_LEAF_PAYLOAD_SIZE;
508 default:
509 return 0;
510 }
511}
512
513static int validate_leaf_header(const struct leaf_header_t *head,
514 uint16_t payload_len, uint16_t aux_hash_len)
515{
516 uint32_t leaf_payload_len = head->pub_len + head->sec_len;
517
518 if (head->leaf_version.major != PW_LEAF_MAJOR_VERSION)
519 return PW_ERR_LEAF_VERSION_MISMATCH;
520
521 if (head->leaf_version.minor <= PW_LEAF_MINOR_VERSION &&
522 leaf_payload_len !=
523 expected_payload_len(head->leaf_version.minor)) {
524 return PW_ERR_LENGTH_INVALID;
525 }
526
527 if (payload_len != leaf_payload_len + aux_hash_len * PW_HASH_SIZE)
528 return PW_ERR_LENGTH_INVALID;
529
Yi Choue416ce32021-08-11 19:57:24 +0800530 if (head->sec_len < sizeof(struct leaf_sensitive_data_t))
531 return PW_ERR_LENGTH_INVALID;
532
Andrey Pronin9b10e512021-04-13 11:18:53 -0700533 return EC_SUCCESS;
534}
535
536/* Common validation for requests that include a path to authenticate. */
537static int validate_request_with_path(const struct merkle_tree_t *merkle_tree,
538 struct label_t path,
539 const uint8_t hashes[][PW_HASH_SIZE],
540 const uint8_t hmac[PW_HASH_SIZE])
541{
542 int ret;
543
544 ret = validate_tree(merkle_tree);
545 if (ret != EC_SUCCESS)
546 return ret;
547
548 ret = validate_label(merkle_tree, path);
549 if (ret != EC_SUCCESS)
550 return ret;
551
552 return authenticate_path(merkle_tree, path, hashes, hmac);
553}
554
555/* Common validation for requests that import a leaf. */
556static int validate_request_with_wrapped_leaf(
557 const struct merkle_tree_t *merkle_tree,
558 uint16_t payload_len,
559 const struct unimported_leaf_data_t *unimported_leaf_data,
560 struct imported_leaf_data_t *imported_leaf_data,
561 struct leaf_data_t *leaf_data)
562{
563 int ret;
564 uint8_t hmac[PW_HASH_SIZE];
565
566 ret = validate_leaf_header(&unimported_leaf_data->head, payload_len,
567 get_path_auxiliary_hash_count(merkle_tree));
568 if (ret != EC_SUCCESS)
569 return ret;
570
571 import_leaf(unimported_leaf_data, imported_leaf_data);
572 ret = validate_request_with_path(merkle_tree,
573 imported_leaf_data->pub->label,
574 imported_leaf_data->hashes,
575 imported_leaf_data->hmac);
576 if (ret != EC_SUCCESS)
577 return ret;
578
Leo Lai788f41e2021-08-11 00:36:24 +0800579 ret = compute_hmac(merkle_tree, imported_leaf_data, hmac);
580 if (ret != EC_SUCCESS)
581 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700582 /* Safe memcmp is used here to prevent an attacker from being able to
583 * brute force a valid HMAC for a crafted wrapped_leaf_data.
584 * memcmp provides an attacker a timing side-channel they can use to
585 * determine how much of a prefix is correct.
586 */
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700587 if (pinweaver_eal_safe_memcmp(hmac, unimported_leaf_data->hmac,
588 sizeof(hmac)))
Andrey Pronin9b10e512021-04-13 11:18:53 -0700589 return PW_ERR_HMAC_AUTH_FAILED;
590
591 ret = decrypt_leaf_data(merkle_tree, imported_leaf_data, leaf_data);
592 if (ret != EC_SUCCESS)
593 return ret;
594
595 /* The code below handles version upgrades. */
596 if (unimported_leaf_data->head.leaf_version.minor == 0 &&
597 unimported_leaf_data->head.leaf_version.major == 0) {
598 /* Populate the leaf_data with default pcr value */
599 memset(&leaf_data->pub.valid_pcr_criteria, 0,
600 PW_VALID_PCR_CRITERIA_SIZE);
601 }
602
603 return EC_SUCCESS;
604}
605
606/* Sets the value of ts to the current notion of time. */
607static void update_timestamp(struct pw_timestamp_t *ts)
608{
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700609 ts->timer_value = pinweaver_eal_seconds_since_boot();
Andrey Pronin9b10e512021-04-13 11:18:53 -0700610 ts->boot_count = pw_restart_count;
611}
612
613/* Checks if an auth attempt can be made or not based on the delay schedule.
614 * EC_SUCCESS is returned when a new attempt can be made otherwise
615 * seconds_to_wait will be updated with the remaining wait time required.
616 */
617static int test_rate_limit(struct leaf_data_t *leaf_data,
618 struct time_diff_t *seconds_to_wait)
619{
620 uint64_t ready_time;
621 uint8_t x;
622 struct pw_timestamp_t current_time;
623 struct time_diff_t delay = {0};
624
625 /* This loop ends when x is one greater than the index that applies. */
626 for (x = 0; x < ARRAY_SIZE(leaf_data->pub.delay_schedule); ++x) {
627 /* Stop if a null entry is reached. The first part of the delay
628 * schedule has a list of increasing (attempt_count, time_diff)
629 * pairs with any unused entries zeroed out at the end.
630 */
631 if (leaf_data->pub.delay_schedule[x].attempt_count.v == 0)
632 break;
633
634 /* Stop once a delay schedule entry is reached whose
635 * threshold is greater than the current number of
636 * attempts.
637 */
638 if (leaf_data->pub.attempt_count.v <
639 leaf_data->pub.delay_schedule[x].attempt_count.v)
640 break;
641 }
642
643 /* If the first threshold was greater than the current number of
644 * attempts, there is no delay. Otherwise, grab the delay from the
645 * entry prior to the one that was too big.
646 */
647 if (x > 0)
648 delay = leaf_data->pub.delay_schedule[x - 1].time_diff;
649
650 if (delay.v == 0)
651 return EC_SUCCESS;
652
653 if (delay.v == PW_BLOCK_ATTEMPTS) {
654 seconds_to_wait->v = PW_BLOCK_ATTEMPTS;
655 return PW_ERR_RATE_LIMIT_REACHED;
656 }
657
658 update_timestamp(&current_time);
659
Howard Yang2b189b22022-07-29 11:11:34 +0800660 if (leaf_data->pub.last_access_ts.boot_count == current_time.boot_count)
661 ready_time = delay.v + leaf_data->pub.last_access_ts.timer_value;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700662 else
663 ready_time = delay.v;
664
665 if (current_time.timer_value >= ready_time)
666 return EC_SUCCESS;
667
668 seconds_to_wait->v = ready_time - current_time.timer_value;
669 return PW_ERR_RATE_LIMIT_REACHED;
670}
671
672/******************************************************************************/
673/* Logging implementation.
674 */
675
676/* Once the storage version is incremented, the update code needs to be written
677 * to handle differences in the structs.
678 *
679 * See the two comments "Add storage format updates here." below.
680 */
681BUILD_ASSERT(PW_STORAGE_VERSION == 0);
682
683void force_restart_count(uint32_t mock_value)
684{
685 pw_restart_count = mock_value;
686}
687
688/* Returns EC_SUCCESS if the root hash was found. Sets *index to the first index
689 * of the log entry with a matching root hash, or the index of the last valid
690 * entry.
691 */
692static int find_relevant_entry(const struct pw_log_storage_t *log,
693 const uint8_t root[PW_HASH_SIZE], int *index)
694{
695 /* Find the relevant log entry. */
696 for (*index = 0; *index < PW_LOG_ENTRY_COUNT; ++*index) {
Howard Yangc2f080c2022-07-29 11:28:13 +0800697 if (log->entries[*index].type.v == LOG_PW_MT_INVALID)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700698 break;
Yi Chouddf3b452021-08-11 13:40:11 +0800699 if (pinweaver_eal_safe_memcmp(root, log->entries[*index].root,
700 PW_HASH_SIZE) == 0)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700701 return EC_SUCCESS;
702 }
703 --*index;
704 return PW_ERR_ROOT_NOT_FOUND;
705}
706
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700707/* TODO(apronin): get rid of temporary redirect methods */
708
Andrey Pronin9b10e512021-04-13 11:18:53 -0700709static int load_log_data(struct pw_log_storage_t *log)
710{
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700711 return pinweaver_eal_storage_get_log(log);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700712}
713
714int store_log_data(const struct pw_log_storage_t *log)
715{
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700716 return pinweaver_eal_storage_set_log(log);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700717}
718
719static int load_merkle_tree(struct merkle_tree_t *merkle_tree)
720{
721 int ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700722
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700723 PINWEAVER_EAL_INFO("PinWeaver: Loading Tree!");
Andrey Pronin9b10e512021-04-13 11:18:53 -0700724
725 /* Handle the immutable data. */
726 {
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700727 struct pw_long_term_storage_t tree;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700728
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700729 ret = pinweaver_eal_storage_get_tree_data(&tree);
730 if (ret != EC_SUCCESS)
731 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700732
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700733 merkle_tree->bits_per_level = tree.bits_per_level;
734 merkle_tree->height = tree.height;
Leo Laidb207912021-08-11 16:41:18 +0800735 ret = pinweaver_eal_memcpy_s(
736 merkle_tree->key_derivation_nonce,
737 sizeof(merkle_tree->key_derivation_nonce),
738 tree.key_derivation_nonce,
739 sizeof(tree.key_derivation_nonce));
740 if (ret != EC_SUCCESS)
741 return ret;
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700742 ret = pinweaver_eal_derive_keys(merkle_tree);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700743 if (ret != EC_SUCCESS)
744 return ret;
745 }
746
747 /* Handle the root hash. */
748 {
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700749 ret = pinweaver_eal_storage_init_state(merkle_tree->root,
750 &pw_restart_count);
751 if (ret != EC_SUCCESS)
752 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700753 }
754
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700755 PINWEAVER_EAL_INFO("PinWeaver: Loaded Tree. restart_count = %d",
Andrey Pronin9b10e512021-04-13 11:18:53 -0700756 pw_restart_count);
757
758 return EC_SUCCESS;
759}
760
761/* This should only be called when a new tree is created. */
762int store_merkle_tree(const struct merkle_tree_t *merkle_tree)
763{
764 int ret;
765
766 /* Handle the immutable data. */
767 {
768 struct pw_long_term_storage_t data;
769
770 data.storage_version = PW_STORAGE_VERSION;
771 data.bits_per_level = merkle_tree->bits_per_level;
772 data.height = merkle_tree->height;
Leo Laidb207912021-08-11 16:41:18 +0800773 ret = pinweaver_eal_memcpy_s(data.key_derivation_nonce,
774 sizeof(data.key_derivation_nonce),
775 merkle_tree->key_derivation_nonce,
776 sizeof(data.key_derivation_nonce));
777 if (ret != EC_SUCCESS)
778 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700779
Andrey Pronincd7bcce2021-04-14 00:54:12 -0700780 ret = pinweaver_eal_storage_set_tree_data(&data);
Andrey Pronin9b10e512021-04-13 11:18:53 -0700781 if (ret != EC_SUCCESS)
782 return ret;
783 }
784
785 /* Handle the root hash. */
786 {
787 struct pw_log_storage_t log = {};
788 struct pw_get_log_entry_t *entry = log.entries;
789
790 log.storage_version = PW_STORAGE_VERSION;
Howard Yangc2f080c2022-07-29 11:28:13 +0800791 entry->type.v = LOG_PW_RESET_TREE;
Leo Laidb207912021-08-11 16:41:18 +0800792 ret = pinweaver_eal_memcpy_s(entry->root, sizeof(entry->root),
793 merkle_tree->root,
794 sizeof(merkle_tree->root));
795 if (ret != EC_SUCCESS)
796 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700797
798 ret = store_log_data(&log);
799 if (ret == EC_SUCCESS)
800 pw_restart_count = 0;
801 return ret;
802 }
803
804}
805
806static int log_roll_for_append(struct pw_log_storage_t *log)
807{
808 int ret;
809
810 ret = load_log_data(log);
811 if (ret != EC_SUCCESS)
812 return ret;
813
814 memmove(&log->entries[1], &log->entries[0],
815 sizeof(log->entries[0]) * (PW_LOG_ENTRY_COUNT - 1));
816 memset(&log->entries[0], 0, sizeof(log->entries[0]));
817 return EC_SUCCESS;
818}
819
820int log_insert_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE],
821 const uint8_t hmac[PW_HASH_SIZE])
822{
823 int ret;
824 struct pw_log_storage_t log;
825 struct pw_get_log_entry_t *entry = log.entries;
826
827 ret = log_roll_for_append(&log);
828 if (ret != EC_SUCCESS)
829 return ret;
830
Howard Yangc2f080c2022-07-29 11:28:13 +0800831 entry->type.v = LOG_PW_INSERT_LEAF;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700832 entry->label.v = label.v;
Leo Laidb207912021-08-11 16:41:18 +0800833 ret = pinweaver_eal_memcpy_s(entry->root, sizeof(entry->root), root,
834 sizeof(entry->root));
835 if (ret != EC_SUCCESS)
836 return ret;
837 ret = pinweaver_eal_memcpy_s(entry->leaf_hmac, sizeof(entry->leaf_hmac),
838 hmac, sizeof(entry->leaf_hmac));
839 if (ret != EC_SUCCESS)
840 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700841
842 return store_log_data(&log);
843}
844
845int log_remove_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE])
846{
847 int ret;
848 struct pw_log_storage_t log;
849 struct pw_get_log_entry_t *entry = log.entries;
850
851 ret = log_roll_for_append(&log);
852 if (ret != EC_SUCCESS)
853 return ret;
854
Howard Yangc2f080c2022-07-29 11:28:13 +0800855 entry->type.v = LOG_PW_REMOVE_LEAF;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700856 entry->label.v = label.v;
Leo Laidb207912021-08-11 16:41:18 +0800857 ret = pinweaver_eal_memcpy_s(entry->root, sizeof(entry->root), root,
858 sizeof(entry->root));
859 if (ret != EC_SUCCESS)
860 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700861
862 return store_log_data(&log);
863}
864
865int log_auth(struct label_t label, const uint8_t root[PW_HASH_SIZE], int code,
Howard Yang2b189b22022-07-29 11:11:34 +0800866 struct pw_timestamp_t last_access_ts)
Andrey Pronin9b10e512021-04-13 11:18:53 -0700867{
868 int ret;
869 struct pw_log_storage_t log;
870 struct pw_get_log_entry_t *entry = log.entries;
871
872 ret = log_roll_for_append(&log);
873 if (ret != EC_SUCCESS)
874 return ret;
875
Howard Yangc2f080c2022-07-29 11:28:13 +0800876 entry->type.v = LOG_PW_TRY_AUTH;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700877 entry->label.v = label.v;
Leo Laidb207912021-08-11 16:41:18 +0800878 ret = pinweaver_eal_memcpy_s(entry->root, sizeof(entry->root), root,
879 sizeof(entry->root));
880 if (ret != EC_SUCCESS)
881 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700882 entry->return_code = code;
Howard Yang2b189b22022-07-29 11:11:34 +0800883 ret = pinweaver_eal_memcpy_s(&entry->last_access_ts,
884 sizeof(entry->last_access_ts), &last_access_ts,
885 sizeof(entry->last_access_ts));
Leo Laidb207912021-08-11 16:41:18 +0800886 if (ret != EC_SUCCESS)
887 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700888
889 return store_log_data(&log);
890}
891
892/******************************************************************************/
893/* Per-request-type handler implementations.
894 */
895
896static int pw_handle_reset_tree(struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +0800897 const pw_request_reset_tree_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -0700898 uint16_t req_size)
899{
900 struct merkle_tree_t new_tree = {};
901 int ret;
902
903 if (req_size != sizeof(*request))
904 return PW_ERR_LENGTH_INVALID;
905
906 ret = validate_tree_parameters(request->bits_per_level,
907 request->height);
908 if (ret != EC_SUCCESS)
909 return ret;
910
911 ret = create_merkle_tree(request->bits_per_level, request->height,
912 &new_tree);
913 if (ret != EC_SUCCESS)
914 return ret;
915
916 ret = store_merkle_tree(&new_tree);
917 if (ret != EC_SUCCESS)
918 return ret;
919
Leo Laidb207912021-08-11 16:41:18 +0800920 ret = pinweaver_eal_memcpy_s(merkle_tree, sizeof(*merkle_tree),
921 &new_tree, sizeof(new_tree));
922 if (ret != EC_SUCCESS)
923 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700924 return EC_SUCCESS;
925}
926
927static int pw_handle_insert_leaf(struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +0800928 const pw_request_insert_leaf_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -0700929 uint16_t req_size,
Howard Yangd4d2e7a2022-08-02 17:57:53 +0800930 pw_response_insert_leaf_t *response,
Andrey Pronin9b10e512021-04-13 11:18:53 -0700931 uint16_t *response_size)
932{
933 int ret = EC_SUCCESS;
934 struct leaf_data_t leaf_data = {};
Leo Lai65749082021-08-10 16:32:18 +0800935 struct wrapped_leaf_data_t wrapped_leaf_data = {};
Andrey Pronin9b10e512021-04-13 11:18:53 -0700936 const uint8_t empty_hash[PW_HASH_SIZE] = {};
937 uint8_t new_root[PW_HASH_SIZE];
938
939 if (req_size != sizeof(*request) +
940 get_path_auxiliary_hash_count(merkle_tree) *
941 PW_HASH_SIZE)
942 return PW_ERR_LENGTH_INVALID;
943
944 ret = validate_request_with_path(merkle_tree, request->label,
945 request->path_hashes, empty_hash);
946 if (ret != EC_SUCCESS)
947 return ret;
948
949 ret = validate_delay_schedule(request->delay_schedule);
950 if (ret != EC_SUCCESS)
951 return ret;
952
953 memset(&leaf_data, 0, sizeof(leaf_data));
954 leaf_data.pub.label.v = request->label.v;
Leo Laidb207912021-08-11 16:41:18 +0800955 ret = pinweaver_eal_memcpy_s(&leaf_data.pub.valid_pcr_criteria,
956 sizeof(leaf_data.pub.valid_pcr_criteria),
957 request->valid_pcr_criteria,
958 sizeof(request->valid_pcr_criteria));
959 if (ret != EC_SUCCESS)
960 return PW_ERR_INTERNAL_FAILURE;
961 ret = pinweaver_eal_memcpy_s(&leaf_data.pub.delay_schedule,
962 sizeof(leaf_data.pub.delay_schedule),
963 &request->delay_schedule,
964 sizeof(request->delay_schedule));
965 if (ret != EC_SUCCESS)
966 return PW_ERR_INTERNAL_FAILURE;
967 ret = pinweaver_eal_memcpy_s(&leaf_data.sec.low_entropy_secret,
968 sizeof(leaf_data.sec.low_entropy_secret),
969 &request->low_entropy_secret,
970 sizeof(request->low_entropy_secret));
971 if (ret != EC_SUCCESS)
972 return PW_ERR_INTERNAL_FAILURE;
973 ret = pinweaver_eal_memcpy_s(&leaf_data.sec.high_entropy_secret,
974 sizeof(leaf_data.sec.high_entropy_secret),
975 &request->high_entropy_secret,
976 sizeof(request->high_entropy_secret));
977 if (ret != EC_SUCCESS)
978 return PW_ERR_INTERNAL_FAILURE;
979 ret = pinweaver_eal_memcpy_s(&leaf_data.sec.reset_secret,
980 sizeof(leaf_data.sec.reset_secret),
981 &request->reset_secret,
982 sizeof(request->reset_secret));
983 if (ret != EC_SUCCESS)
984 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -0700985
986 ret = handle_leaf_update(merkle_tree, &leaf_data, request->path_hashes,
987 &wrapped_leaf_data, new_root, NULL);
988 if (ret != EC_SUCCESS)
989 return ret;
990
991 ret = log_insert_leaf(request->label, new_root,
992 wrapped_leaf_data.hmac);
993 if (ret != EC_SUCCESS)
994 return ret;
995
Leo Laidb207912021-08-11 16:41:18 +0800996 ret = pinweaver_eal_memcpy_s(merkle_tree->root,
997 sizeof(merkle_tree->root), new_root,
998 sizeof(new_root));
999 if (ret != EC_SUCCESS)
1000 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001001
Leo Laidb207912021-08-11 16:41:18 +08001002 ret = pinweaver_eal_memcpy_s(&response->unimported_leaf_data,
1003 sizeof(wrapped_leaf_data),
1004 &wrapped_leaf_data,
1005 sizeof(wrapped_leaf_data));
1006 if (ret != EC_SUCCESS)
1007 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001008
1009 *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE;
1010
1011 return ret;
1012}
1013
1014static int pw_handle_remove_leaf(struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001015 const pw_request_remove_leaf_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001016 uint16_t req_size)
1017{
1018 int ret = EC_SUCCESS;
1019 const uint8_t empty_hash[PW_HASH_SIZE] = {};
1020 uint8_t new_root[PW_HASH_SIZE];
1021
1022 if (req_size != sizeof(*request) +
1023 get_path_auxiliary_hash_count(merkle_tree) *
1024 PW_HASH_SIZE)
1025 return PW_ERR_LENGTH_INVALID;
1026
1027 ret = validate_request_with_path(merkle_tree, request->leaf_location,
1028 request->path_hashes,
1029 request->leaf_hmac);
1030 if (ret != EC_SUCCESS)
1031 return ret;
1032
Leo Lai788f41e2021-08-11 00:36:24 +08001033 ret = compute_root_hash(merkle_tree, request->leaf_location,
1034 request->path_hashes, empty_hash, new_root);
1035 if (ret != EC_SUCCESS)
1036 return ret;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001037
1038 ret = log_remove_leaf(request->leaf_location, new_root);
1039 if (ret != EC_SUCCESS)
1040 return ret;
1041
Leo Laidb207912021-08-11 16:41:18 +08001042 ret = pinweaver_eal_memcpy_s(merkle_tree->root,
1043 sizeof(merkle_tree->root), new_root,
1044 sizeof(new_root));
1045 if (ret != EC_SUCCESS)
1046 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001047 return ret;
1048}
1049
1050/* Processes a try_auth request.
1051 *
1052 * The valid fields in response based on return code are:
1053 * EC_SUCCESS -> unimported_leaf_data and high_entropy_secret
1054 * PW_ERR_RATE_LIMIT_REACHED -> seconds_to_wait
1055 * PW_ERR_LOWENT_AUTH_FAILED -> unimported_leaf_data
1056 */
1057static int pw_handle_try_auth(struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001058 const pw_request_try_auth_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001059 uint16_t req_size,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001060 pw_response_try_auth_t *response,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001061 uint16_t *data_length)
1062{
1063 int ret = EC_SUCCESS;
1064 struct leaf_data_t leaf_data = {};
1065 struct imported_leaf_data_t imported_leaf_data;
Andrey Pronin8ec6dc52021-08-12 14:00:09 -07001066 struct wrapped_leaf_data_t wrapped_leaf_data = {};
Andrey Pronin9b10e512021-04-13 11:18:53 -07001067 struct time_diff_t seconds_to_wait;
1068 uint8_t zeros[PW_SECRET_SIZE] = {};
1069 uint8_t new_root[PW_HASH_SIZE];
1070
1071 /* These variables help eliminate the possibility of a timing side
1072 * channel that would allow an attacker to prevent the log write.
1073 */
1074 volatile int auth_result;
1075
1076 volatile struct {
1077 uint32_t attempts;
1078 int ret;
1079 uint8_t *secret;
1080 uint8_t *reset_secret;
1081 } results_table[2] = {
1082 { 0, PW_ERR_LOWENT_AUTH_FAILED, zeros, zeros },
1083 { 0, EC_SUCCESS, leaf_data.sec.high_entropy_secret,
1084 leaf_data.sec.reset_secret },
1085 };
1086
1087 if (req_size < sizeof(*request))
1088 return PW_ERR_LENGTH_INVALID;
1089
1090 ret = validate_request_with_wrapped_leaf(
1091 merkle_tree, req_size - sizeof(*request),
1092 &request->unimported_leaf_data, &imported_leaf_data,
1093 &leaf_data);
1094 if (ret != EC_SUCCESS)
1095 return ret;
1096
1097 /* Check if at least one PCR criteria is satisfied if the leaf is
1098 * bound to PCR.
1099 */
1100 ret = validate_pcr_value(leaf_data.pub.valid_pcr_criteria);
1101 if (ret != EC_SUCCESS)
1102 return ret;
1103
1104 ret = test_rate_limit(&leaf_data, &seconds_to_wait);
1105 if (ret != EC_SUCCESS) {
1106 *data_length = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE;
1107 memset(response, 0, *data_length);
Leo Laidb207912021-08-11 16:41:18 +08001108 pinweaver_eal_memcpy_s(&response->seconds_to_wait,
1109 sizeof(response->seconds_to_wait),
1110 &seconds_to_wait,
1111 sizeof(seconds_to_wait));
Andrey Pronin9b10e512021-04-13 11:18:53 -07001112 return ret;
1113 }
1114
Howard Yang2b189b22022-07-29 11:11:34 +08001115 update_timestamp(&leaf_data.pub.last_access_ts);
Andrey Pronin9b10e512021-04-13 11:18:53 -07001116
1117 /* Precompute the failed attempts. */
1118 results_table[0].attempts = leaf_data.pub.attempt_count.v;
1119 if (results_table[0].attempts != UINT32_MAX)
1120 ++results_table[0].attempts;
1121
1122 /**********************************************************************/
1123 /* After this:
1124 * 1) results_table should not be changed;
1125 * 2) the runtime of the code paths for failed and successful
1126 * authentication attempts should not diverge.
1127 */
Andrey Pronincd7bcce2021-04-14 00:54:12 -07001128 auth_result = pinweaver_eal_safe_memcmp(
1129 request->low_entropy_secret,
1130 leaf_data.sec.low_entropy_secret,
1131 sizeof(request->low_entropy_secret)) == 0;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001132 leaf_data.pub.attempt_count.v = results_table[auth_result].attempts;
1133
1134 /* This has a non-constant time path, but it doesn't convey information
1135 * about whether a PW_ERR_LOWENT_AUTH_FAILED happened or not.
1136 */
1137 ret = handle_leaf_update(merkle_tree, &leaf_data,
1138 imported_leaf_data.hashes, &wrapped_leaf_data,
1139 new_root, &imported_leaf_data);
1140 if (ret != EC_SUCCESS)
1141 return ret;
1142
1143 ret = log_auth(wrapped_leaf_data.pub.label, new_root,
Howard Yang2b189b22022-07-29 11:11:34 +08001144 results_table[auth_result].ret, leaf_data.pub.last_access_ts);
Andrey Pronin9b10e512021-04-13 11:18:53 -07001145 if (ret != EC_SUCCESS) {
Leo Laidb207912021-08-11 16:41:18 +08001146 pinweaver_eal_memcpy_s(new_root, sizeof(new_root),
1147 merkle_tree->root,
1148 sizeof(merkle_tree->root));
Andrey Pronin9b10e512021-04-13 11:18:53 -07001149 return ret;
1150 }
1151 /**********************************************************************/
1152 /* At this point the log should be written so it should be safe for the
1153 * runtime of the code paths to diverge.
1154 */
1155
Leo Laidb207912021-08-11 16:41:18 +08001156 ret = pinweaver_eal_memcpy_s(merkle_tree->root,
1157 sizeof(merkle_tree->root), new_root,
1158 sizeof(new_root));
1159 if (ret != EC_SUCCESS)
1160 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001161
1162 *data_length = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE;
1163 memset(response, 0, *data_length);
1164
Leo Laidb207912021-08-11 16:41:18 +08001165 ret = pinweaver_eal_memcpy_s(&response->unimported_leaf_data,
1166 sizeof(wrapped_leaf_data),
1167 &wrapped_leaf_data,
1168 sizeof(wrapped_leaf_data));
1169 if (ret != EC_SUCCESS)
1170 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001171
Leo Laidb207912021-08-11 16:41:18 +08001172 ret = pinweaver_eal_memcpy_s(&response->high_entropy_secret,
1173 sizeof(response->high_entropy_secret),
1174 results_table[auth_result].secret,
1175 sizeof(response->high_entropy_secret));
1176 if (ret != EC_SUCCESS)
1177 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001178
Leo Laidb207912021-08-11 16:41:18 +08001179 ret = pinweaver_eal_memcpy_s(&response->reset_secret,
1180 sizeof(response->reset_secret),
1181 results_table[auth_result].reset_secret,
1182 sizeof(response->reset_secret));
1183 if (ret != EC_SUCCESS)
1184 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001185
1186 return results_table[auth_result].ret;
1187}
1188
1189static int pw_handle_reset_auth(struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001190 const pw_request_reset_auth_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001191 uint16_t req_size,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001192 pw_response_reset_auth_t *response,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001193 uint16_t *response_size)
1194{
1195 int ret = EC_SUCCESS;
1196 struct leaf_data_t leaf_data = {};
1197 struct imported_leaf_data_t imported_leaf_data;
Andrey Pronin8ec6dc52021-08-12 14:00:09 -07001198 struct wrapped_leaf_data_t wrapped_leaf_data = {};
Andrey Pronin9b10e512021-04-13 11:18:53 -07001199 uint8_t new_root[PW_HASH_SIZE];
1200
1201 if (req_size < sizeof(*request))
1202 return PW_ERR_LENGTH_INVALID;
1203
1204 ret = validate_request_with_wrapped_leaf(
1205 merkle_tree, req_size - sizeof(*request),
1206 &request->unimported_leaf_data, &imported_leaf_data,
1207 &leaf_data);
1208 if (ret != EC_SUCCESS)
1209 return ret;
1210
1211 /* Safe memcmp is used here to prevent an attacker from being able to
1212 * brute force the reset secret and use it to unlock the leaf.
1213 * memcmp provides an attacker a timing side-channel they can use to
1214 * determine how much of a prefix is correct.
1215 */
Andrey Pronincd7bcce2021-04-14 00:54:12 -07001216 if (pinweaver_eal_safe_memcmp(request->reset_secret,
1217 leaf_data.sec.reset_secret,
1218 sizeof(request->reset_secret)) != 0)
Andrey Pronin9b10e512021-04-13 11:18:53 -07001219 return PW_ERR_RESET_AUTH_FAILED;
1220
1221 leaf_data.pub.attempt_count.v = 0;
1222
1223 ret = handle_leaf_update(merkle_tree, &leaf_data,
1224 imported_leaf_data.hashes, &wrapped_leaf_data,
1225 new_root, &imported_leaf_data);
1226 if (ret != EC_SUCCESS)
1227 return ret;
1228
1229 ret = log_auth(leaf_data.pub.label, new_root, ret,
Howard Yang2b189b22022-07-29 11:11:34 +08001230 leaf_data.pub.last_access_ts);
Andrey Pronin9b10e512021-04-13 11:18:53 -07001231 if (ret != EC_SUCCESS)
1232 return ret;
1233
Leo Laidb207912021-08-11 16:41:18 +08001234 ret = pinweaver_eal_memcpy_s(merkle_tree->root,
1235 sizeof(merkle_tree->root), new_root,
1236 sizeof(new_root));
1237 if (ret != EC_SUCCESS)
1238 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001239
Leo Laidb207912021-08-11 16:41:18 +08001240 ret = pinweaver_eal_memcpy_s(&response->unimported_leaf_data,
1241 sizeof(wrapped_leaf_data),
1242 &wrapped_leaf_data,
1243 sizeof(wrapped_leaf_data));
1244 if (ret != EC_SUCCESS)
1245 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001246
Leo Laidb207912021-08-11 16:41:18 +08001247 ret = pinweaver_eal_memcpy_s(response->high_entropy_secret,
1248 sizeof(response->high_entropy_secret),
1249 leaf_data.sec.high_entropy_secret,
1250 sizeof(response->high_entropy_secret));
1251 if (ret != EC_SUCCESS)
1252 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001253
1254 *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE;
1255
1256 return ret;
1257}
1258
1259static int pw_handle_get_log(const struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001260 const pw_request_get_log_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001261 uint16_t req_size,
1262 struct pw_get_log_entry_t response[],
1263 uint16_t *response_size)
1264{
1265 int ret;
1266 int x;
1267 struct pw_log_storage_t log;
1268
1269 if (req_size != sizeof(*request))
1270 return PW_ERR_LENGTH_INVALID;
1271
1272 ret = validate_tree(merkle_tree);
1273 if (ret != EC_SUCCESS)
1274 return ret;
1275
1276 ret = load_log_data(&log);
1277 if (ret != EC_SUCCESS)
1278 return ret;
1279
1280 /* Find the relevant log entry. The return value isn't used because if
1281 * the entry isn't found the entire log is returned. This makes it
1282 * easier to recover when the log is too short.
1283 *
1284 * Here is an example:
1285 * 50 attempts have been made against a leaf that becomes out of sync
1286 * because of a disk flush failing. The copy of the leaf on disk is
1287 * behind by 50 and the log contains less than 50 entries. The CrOS
1288 * implementation can check the public parameters of the local copy with
1289 * the log entry to determine that leaf is out of sync. It can then send
1290 * any valid copy of that leaf with a log replay request that will only
1291 * succeed if the HMAC of the resulting leaf matches the log entry.
1292 */
1293 find_relevant_entry(&log, request->root, &x);
1294 /* If there are no valid entries, return. */
1295 if (x < 0)
1296 return EC_SUCCESS;
1297
1298 /* Copy the entries in reverse order. */
1299 while (1) {
Leo Laidb207912021-08-11 16:41:18 +08001300 ret = pinweaver_eal_memcpy_s(&response[x], sizeof(response[x]),
1301 &log.entries[x],
1302 sizeof(log.entries[x]));
1303 if (ret != EC_SUCCESS)
1304 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001305 *response_size += sizeof(log.entries[x]);
1306 if (x == 0)
1307 break;
1308 --x;
1309 }
1310
1311 return EC_SUCCESS;
1312}
1313
1314static int pw_handle_log_replay(const struct merkle_tree_t *merkle_tree,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001315 const pw_request_log_replay_t *request,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001316 uint16_t req_size,
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001317 pw_response_log_replay_t *response,
Andrey Pronin9b10e512021-04-13 11:18:53 -07001318 uint16_t *response_size)
1319{
1320 int ret;
1321 int x;
1322 struct pw_log_storage_t log;
1323 struct leaf_data_t leaf_data = {};
1324 struct imported_leaf_data_t imported_leaf_data;
Andrey Pronin8ec6dc52021-08-12 14:00:09 -07001325 struct wrapped_leaf_data_t wrapped_leaf_data = {};
Andrey Pronin9b10e512021-04-13 11:18:53 -07001326 uint8_t hmac[PW_HASH_SIZE];
1327 uint8_t root[PW_HASH_SIZE];
1328
1329 if (req_size < sizeof(*request))
1330 return PW_ERR_LENGTH_INVALID;
1331
1332 ret = validate_tree(merkle_tree);
1333 if (ret != EC_SUCCESS)
1334 return ret;
1335
1336 /* validate_request_with_wrapped_leaf() isn't used here because the
1337 * path validation is delayed to allow any valid copy of the same leaf
1338 * to be used in the replay operation as long as the result passes path
1339 * validation.
1340 */
1341 ret = validate_leaf_header(&request->unimported_leaf_data.head,
1342 req_size - sizeof(*request),
1343 get_path_auxiliary_hash_count(merkle_tree));
1344 if (ret != EC_SUCCESS)
1345 return ret;
1346
1347 import_leaf(&request->unimported_leaf_data, &imported_leaf_data);
1348
1349 ret = load_log_data(&log);
1350 if (ret != EC_SUCCESS)
1351 return ret;
1352
1353 /* Find the relevant log entry. */
1354 ret = find_relevant_entry(&log, request->log_root, &x);
1355 if (ret != EC_SUCCESS)
1356 return ret;
1357
1358 /* The other message types don't need to be handled by Cr50. */
Howard Yangc2f080c2022-07-29 11:28:13 +08001359 if (log.entries[x].type.v != LOG_PW_TRY_AUTH)
Andrey Pronin9b10e512021-04-13 11:18:53 -07001360 return PW_ERR_TYPE_INVALID;
1361
Leo Lai788f41e2021-08-11 00:36:24 +08001362 ret = compute_hmac(merkle_tree, &imported_leaf_data, hmac);
1363 if (ret != EC_SUCCESS)
1364 return ret;
Andrey Pronincd7bcce2021-04-14 00:54:12 -07001365 if (pinweaver_eal_safe_memcmp(hmac,
1366 request->unimported_leaf_data.hmac,
1367 sizeof(hmac)))
Andrey Pronin9b10e512021-04-13 11:18:53 -07001368 return PW_ERR_HMAC_AUTH_FAILED;
1369
1370 ret = decrypt_leaf_data(merkle_tree, &imported_leaf_data, &leaf_data);
1371 if (ret != EC_SUCCESS)
1372 return ret;
1373
1374 if (leaf_data.pub.label.v != log.entries[x].label.v)
1375 return PW_ERR_LABEL_INVALID;
1376
1377 /* Update the metadata to match the log. */
1378 if (log.entries[x].return_code == EC_SUCCESS)
1379 leaf_data.pub.attempt_count.v = 0;
1380 else
1381 ++leaf_data.pub.attempt_count.v;
Howard Yang2b189b22022-07-29 11:11:34 +08001382 ret = pinweaver_eal_memcpy_s(&leaf_data.pub.last_access_ts,
1383 sizeof(leaf_data.pub.last_access_ts),
1384 &log.entries[x].last_access_ts,
1385 sizeof(leaf_data.pub.last_access_ts));
Leo Laidb207912021-08-11 16:41:18 +08001386 if (ret != EC_SUCCESS)
1387 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001388
1389 ret = handle_leaf_update(merkle_tree, &leaf_data,
1390 imported_leaf_data.hashes, &wrapped_leaf_data,
1391 root, &imported_leaf_data);
1392 if (ret != EC_SUCCESS)
1393 return ret;
1394
Yi Chouddf3b452021-08-11 13:40:11 +08001395 if (pinweaver_eal_safe_memcmp(root, log.entries[x].root, PW_HASH_SIZE))
Andrey Pronin9b10e512021-04-13 11:18:53 -07001396 return PW_ERR_PATH_AUTH_FAILED;
1397
Leo Laidb207912021-08-11 16:41:18 +08001398 ret = pinweaver_eal_memcpy_s(&response->unimported_leaf_data,
1399 sizeof(wrapped_leaf_data),
1400 &wrapped_leaf_data,
1401 sizeof(wrapped_leaf_data));
1402 if (ret != EC_SUCCESS)
1403 return PW_ERR_INTERNAL_FAILURE;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001404
1405 *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE;
1406
1407 return EC_SUCCESS;
1408}
1409
1410struct merkle_tree_t pw_merkle_tree;
1411
Andrey Pronin9b10e512021-04-13 11:18:53 -07001412/******************************************************************************/
1413/* Non-static functions.
1414 */
1415
1416void pinweaver_init(void)
1417{
1418 load_merkle_tree(&pw_merkle_tree);
1419}
1420
1421int get_path_auxiliary_hash_count(const struct merkle_tree_t *merkle_tree)
1422{
1423 return ((1 << merkle_tree->bits_per_level.v) - 1) *
1424 merkle_tree->height.v;
1425}
1426
1427/* Computes the SHA256 parent hash of a set of child hashes given num_hashes
1428 * sibling hashes in hashes[] and the index of child_hash.
1429 *
1430 * Assumptions:
1431 * num_hashes == fan_out - 1
1432 * ARRAY_SIZE(hashes) == num_hashes
1433 * 0 <= location <= num_hashes
1434 */
Leo Lai788f41e2021-08-11 00:36:24 +08001435int compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes,
1436 struct index_t location,
1437 const uint8_t child_hash[PW_HASH_SIZE],
1438 uint8_t result[PW_HASH_SIZE])
Andrey Pronin9b10e512021-04-13 11:18:53 -07001439{
Leo Lai788f41e2021-08-11 00:36:24 +08001440 int ret;
Andrey Pronincd7bcce2021-04-14 00:54:12 -07001441 pinweaver_eal_sha256_ctx_t ctx;
Andrey Pronin9b10e512021-04-13 11:18:53 -07001442
Leo Lai788f41e2021-08-11 00:36:24 +08001443 ret = pinweaver_eal_sha256_init(&ctx);
1444 if (ret)
1445 return ret;
Yi Chou89f8d532021-08-12 16:36:46 +08001446 if (location.v > 0) {
1447 ret = pinweaver_eal_sha256_update(&ctx, hashes[0],
1448 PW_HASH_SIZE * location.v);
1449 if (ret) {
1450 pinweaver_eal_sha256_final(&ctx, result);
1451 return ret;
1452 }
Leo Lai788f41e2021-08-11 00:36:24 +08001453 }
1454 ret = pinweaver_eal_sha256_update(&ctx, child_hash, PW_HASH_SIZE);
1455 if (ret) {
1456 pinweaver_eal_sha256_final(&ctx, result);
1457 return ret;
1458 }
1459 if (location.v < num_hashes) {
1460 ret = pinweaver_eal_sha256_update(
1461 &ctx, hashes[location.v],
1462 PW_HASH_SIZE * (num_hashes - location.v));
1463 if (ret) {
1464 pinweaver_eal_sha256_final(&ctx, result);
1465 return ret;
1466 }
1467 }
1468 return pinweaver_eal_sha256_final(&ctx, result);
Andrey Pronin9b10e512021-04-13 11:18:53 -07001469}
1470
1471/* If a request from older protocol comes, this method should make it
1472 * compatible with the current request structure.
1473 */
1474int make_compatible_request(struct merkle_tree_t *merkle_tree,
1475 struct pw_request_t *request)
1476{
1477 switch (request->header.version) {
1478 case 0:
1479 /* The switch from protocol version 0 to 1 means all the
1480 * requests have the same format, except insert_leaf.
1481 * Update the request in that case.
1482 */
1483 if (request->header.type.v == PW_INSERT_LEAF) {
1484 unsigned char *src = (unsigned char *)
1485 (&request->data.insert_leaf00.path_hashes);
1486 unsigned char *dest = (unsigned char *)
1487 (&request->data.insert_leaf.path_hashes);
Yi Chouc3901ca2021-08-11 14:11:15 +08001488 const uint16_t src_size =
1489 request->header.data_length -
1490 offsetof(struct pw_request_insert_leaf00_t,
1491 path_hashes);
Howard Yangd4d2e7a2022-08-02 17:57:53 +08001492 if (offsetof(struct pw_request_insert_leaf01_t,
Andrey Proninee44ef02021-08-13 15:11:38 -07001493 path_hashes) + src_size >
1494 PW_MAX_MESSAGE_SIZE) {
Yi Chouc3901ca2021-08-11 14:11:15 +08001495 /* The total length of request overflowed. */
1496 return 0;
1497 }
1498 memmove(dest, src, src_size);
1499 memset(&request->data.insert_leaf.valid_pcr_criteria, 0,
1500 PW_VALID_PCR_CRITERIA_SIZE);
Andrey Pronin9b10e512021-04-13 11:18:53 -07001501 request->header.data_length +=
1502 PW_VALID_PCR_CRITERIA_SIZE;
1503 }
1504 /* Fallthrough to make compatible from next version */
Leo Lai8c9892c2021-06-22 21:32:02 +08001505 __attribute__((fallthrough));
Andrey Pronin9b10e512021-04-13 11:18:53 -07001506 case PW_PROTOCOL_VERSION:
1507 return 1;
1508 }
1509 /* Unsupported version. */
1510 return 0;
1511}
1512
1513/* Converts the response to be understandable by an older protocol.
1514 */
1515void make_compatible_response(int version, int req_type,
1516 struct pw_response_t *response)
1517{
1518 if (version >= PW_PROTOCOL_VERSION)
1519 return;
1520
1521 response->header.version = version;
1522 if (version == 0) {
1523 if (req_type == PW_TRY_AUTH) {
1524 unsigned char *src = (unsigned char *)
1525 (&response->data.try_auth.unimported_leaf_data);
1526 unsigned char *dest = (unsigned char *)
1527 (&response->data.try_auth00.unimported_leaf_data);
1528 memmove(dest, src,
1529 PW_LEAF_PAYLOAD_SIZE +
1530 sizeof(struct unimported_leaf_data_t));
1531 response->header.data_length -= PW_SECRET_SIZE;
1532 }
1533 }
1534}
1535
Andrey Pronincd7bcce2021-04-14 00:54:12 -07001536enum pinweaver_command_res_t pinweaver_command(void *request_buf,
1537 size_t request_size,
1538 void *response_buf,
1539 size_t *response_size) {
1540 struct pw_request_t *request = request_buf;
1541 struct pw_response_t *response = response_buf;
1542
1543 if (request_size < sizeof(request->header)) {
1544 PINWEAVER_EAL_INFO(
1545 "PinWeaver: message smaller than a header (%zd).\n",
1546 request_size);
1547 return PW_CMD_RES_TOO_SMALL;
1548 }
1549
1550 if (request_size != request->header.data_length +
1551 sizeof(request->header)) {
1552 PINWEAVER_EAL_INFO(
1553 "PinWeaver: header size mismatch %zd != %zd.\n",
1554 request_size,
1555 request->header.data_length + sizeof(request->header));
1556 return PW_CMD_RES_SIZE;
1557 }
1558
1559 /* The response_size is validated by compile time checks. */
1560
1561 /* The return value of this function call is intentionally unused. */
1562 pw_handle_request(&pw_merkle_tree, request, response);
1563
1564 *response_size = response->header.data_length +
1565 sizeof(response->header);
1566
1567 /* The response is only sent for EC_SUCCESS so it is used even for
1568 * errors which are reported through header.return_code.
1569 */
1570 return PW_CMD_RES_SUCCESS;
1571}
1572
1573
Andrey Pronin9b10e512021-04-13 11:18:53 -07001574/* Handles the message in request using the context in merkle_tree and writes
1575 * the results to response. The return value captures any error conditions that
1576 * occurred or EC_SUCCESS if there were no errors.
1577 *
1578 * This implementation is written to handle the case where request and response
1579 * exist at the same memory location---are backed by the same buffer. This means
1580 * the implementation requires that no reads are made to request after response
1581 * has been written to.
1582 */
1583int pw_handle_request(struct merkle_tree_t *merkle_tree,
1584 struct pw_request_t *request,
1585 struct pw_response_t *response)
1586{
1587 int32_t ret;
1588 uint16_t resp_length;
1589 /* Store the message type of the request since it may be overwritten
1590 * inside the switch whenever response and request overlap in memory.
1591 */
1592 struct pw_message_type_t type = request->header.type;
1593 int version = request->header.version;
1594
1595 resp_length = 0;
1596
1597 if (!make_compatible_request(merkle_tree, request)) {
1598 ret = PW_ERR_VERSION_MISMATCH;
1599 goto cleanup;
1600 }
1601 switch (type.v) {
1602 case PW_RESET_TREE:
1603 ret = pw_handle_reset_tree(merkle_tree,
1604 &request->data.reset_tree,
1605 request->header.data_length);
1606 break;
1607 case PW_INSERT_LEAF:
1608 ret = pw_handle_insert_leaf(merkle_tree,
1609 &request->data.insert_leaf,
1610 request->header.data_length,
1611 &response->data.insert_leaf,
1612 &resp_length);
1613 break;
1614 case PW_REMOVE_LEAF:
1615 ret = pw_handle_remove_leaf(merkle_tree,
1616 &request->data.remove_leaf,
1617 request->header.data_length);
1618 break;
1619 case PW_TRY_AUTH:
1620 ret = pw_handle_try_auth(merkle_tree, &request->data.try_auth,
1621 request->header.data_length,
1622 &response->data.try_auth,
1623 &resp_length);
1624 break;
1625 case PW_RESET_AUTH:
1626 ret = pw_handle_reset_auth(merkle_tree,
1627 &request->data.reset_auth,
1628 request->header.data_length,
1629 &response->data.reset_auth,
1630 &resp_length);
1631 break;
1632 case PW_GET_LOG:
1633 ret = pw_handle_get_log(merkle_tree, &request->data.get_log,
1634 request->header.data_length,
1635 (void *)&response->data, &resp_length);
1636 break;
1637 case PW_LOG_REPLAY:
1638 ret = pw_handle_log_replay(merkle_tree,
1639 &request->data.log_replay,
1640 request->header.data_length,
1641 &response->data.log_replay,
1642 &resp_length);
1643 break;
1644 default:
1645 ret = PW_ERR_TYPE_INVALID;
1646 break;
1647 }
1648cleanup:
1649 response->header.version = PW_PROTOCOL_VERSION;
1650 response->header.data_length = resp_length;
1651 response->header.result_code = ret;
Leo Laidb207912021-08-11 16:41:18 +08001652 if (pinweaver_eal_memcpy_s(&response->header.root,
1653 sizeof(response->header.root),
1654 merkle_tree->root,
1655 sizeof(merkle_tree->root))) {
1656 ret = PW_ERR_INTERNAL_FAILURE;
1657 }
Andrey Pronin9b10e512021-04-13 11:18:53 -07001658
1659 make_compatible_response(version, type.v, response);
1660
1661 return ret;
1662};