blob: 06183d34aba0739a1ceeec8e6abd2a58fa750f5c [file] [log] [blame]
Nan Zhou7a337042021-07-26 21:05:21 -07001/*
2 * Copyright 2021 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Nan Zhou7a337042021-07-26 21:05:21 -070016#include <assert.h>
William A. Kennington III5acaca22021-10-28 16:32:33 -070017#include <libcr51sign/libcr51sign.h>
Nan Zhou7a337042021-07-26 21:05:21 -070018#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#ifdef __cplusplus
23extern "C"
24{
25#endif
26
27#ifndef USER_PRINT
William A. Kennington IIIdeb55012021-10-28 17:12:23 -070028#define CPRINTS(ctx, ...) fprintf(stderr, __VA_ARGS__)
Nan Zhou7a337042021-07-26 21:05:21 -070029#endif
30
31#define MEMBER_SIZE(type, field) sizeof(((type*)0)->field)
32
33// True of x is a power of two
34#define POWER_OF_TWO(x) ((x) && !((x) & ((x)-1)))
35
36// Maximum version supported. Major revisions are not backwards compatible.
37#define MAX_MAJOR_VERSION 1
38
Nan Zhou7a337042021-07-26 21:05:21 -070039// Descriptor alignment on the external EEPROM.
40#define DESCRIPTOR_ALIGNMENT (64 * 1024)
41
42// SPS EEPROM sector size is 4KiB, since this is the smallest erasable size.
43#define IMAGE_REGION_ALIGNMENT 4096
44
45#define MAX_READ_SIZE 1024
46
47#ifndef ARRAY_SIZE
48#define ARRAY_SIZE(t) (sizeof(t) / sizeof(t[0]))
49#endif
50
51// Values of SIGNATURE_OFFSET shuold be same for all sig types (2048,3072,4096)
52#define SIGNATURE_OFFSET offsetof(struct signature_rsa3072_pkcs15, modulus)
53
54#ifndef BUILD_ASSERT
55#define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
56#endif
57
58 typedef enum libcr51sign_validation_failure_reason failure_reason;
59
60 // Returns the bytes size of keys used in the given signature_scheme.
61 // Return error if signature_scheme is invalid.
62 //
63 static failure_reason get_key_size(enum signature_scheme signature_scheme,
64 uint16_t* key_size)
65 {
66 switch (signature_scheme)
67 {
68 case SIGNATURE_RSA2048_PKCS15:
69 *key_size = 256;
70 return LIBCR51SIGN_SUCCESS;
71 case SIGNATURE_RSA3072_PKCS15:
72 *key_size = 384;
73 return LIBCR51SIGN_SUCCESS;
74 case SIGNATURE_RSA4096_PKCS15:
75 case SIGNATURE_RSA4096_PKCS15_SHA512:
76 *key_size = 512;
77 return LIBCR51SIGN_SUCCESS;
78 default:
79 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
80 }
81 }
82
83 // Returns the hash_type for a given signature scheme
84 // Returns error if scheme is invalid.
85 failure_reason get_hash_type_from_signature(enum signature_scheme scheme,
86 enum hash_type* type)
87 {
88 switch (scheme)
89 {
90 case SIGNATURE_RSA2048_PKCS15:
91 case SIGNATURE_RSA3072_PKCS15:
92 case SIGNATURE_RSA4096_PKCS15:
93 *type = HASH_SHA2_256;
94 return LIBCR51SIGN_SUCCESS;
95 case SIGNATURE_RSA4096_PKCS15_SHA512:
96 *type = HASH_SHA2_512;
97 return LIBCR51SIGN_SUCCESS;
98 default:
99 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
100 }
101 }
102
103 // Check if the given hash_type is supported.
104 // Returns error if hash_type is not supported.
105 static failure_reason is_hash_type_supported(enum hash_type type)
106 {
107 switch (type)
108 {
109 case HASH_SHA2_256:
110 case HASH_SHA2_512:
111 return LIBCR51SIGN_SUCCESS;
112 default:
113 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
114 }
115 }
116
117 // Determines digest size for a given hash_type.
118 // Returns error if hash_type is not supported.
119 static failure_reason get_hash_digest_size(enum hash_type type,
120 uint32_t* size)
121 {
122 switch (type)
123 {
124 case HASH_SHA2_256:
Willy Tudf800482021-09-17 22:06:18 -0700125 *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
Nan Zhou7a337042021-07-26 21:05:21 -0700126 return LIBCR51SIGN_SUCCESS;
127 case HASH_SHA2_512:
Willy Tudf800482021-09-17 22:06:18 -0700128 *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
Nan Zhou7a337042021-07-26 21:05:21 -0700129 return LIBCR51SIGN_SUCCESS;
130 default:
131 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
132 }
133 }
134
135 // Determines hash struct size for a given hash_type.
136 // Returns error if hash_type is not supported.
137 static failure_reason get_hash_struct_size(enum hash_type type,
138 uint32_t* size)
139 {
140 switch (type)
141 {
142 case HASH_SHA2_256:
143 *size = sizeof(struct hash_sha256);
144 return LIBCR51SIGN_SUCCESS;
145 case HASH_SHA2_512:
146 *size = sizeof(struct hash_sha256);
147 return LIBCR51SIGN_SUCCESS;
148 default:
149 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
150 }
151 }
152
153 // Checks that:
154 // - The signing key is trusted
155 // - The target version is not denylisted
156 // If validating a staged update, also checks that:
157 // - The target image family matches the current image family
158 // - The image type transition is legal (i.e. dev -> *|| prod -> prod) or
159 // alternatively that the hardware ID is allowlisted
160 // Assuming the caller has performed following:
161 // board_get_base_key_index();
162 // board_get_key_array
163 // Possible return codes:
164 // LIBCR51SIGN_SUCCESS = 0,
165 // LIBCR51SIGN_ERROR_RUNTIME_FAILURE = 1,
166 // LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR = 3,
167 // LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY = 4,
168 // LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED = 5,
169
170 static failure_reason
171 validate_transition(const struct libcr51sign_ctx* ctx,
172 const struct libcr51sign_intf* intf,
173 uint32_t signature_struct_offset)
174 {
175 BUILD_ASSERT((offsetof(struct signature_rsa2048_pkcs15, modulus) ==
176 SIGNATURE_OFFSET &&
177 offsetof(struct signature_rsa3072_pkcs15, modulus) ==
178 SIGNATURE_OFFSET &&
179 offsetof(struct signature_rsa4096_pkcs15, modulus) ==
180 SIGNATURE_OFFSET));
181
182 // Read up to the modulus.
Willy Tudf800482021-09-17 22:06:18 -0700183 enum
184 {
185 read_len = SIGNATURE_OFFSET
186 };
Nan Zhou7a337042021-07-26 21:05:21 -0700187 uint8_t buffer[read_len];
188 // "modulus" & "signature" will not be indexed.
189 struct signature_rsa4096_pkcs15* sig_data = (void*)&buffer;
190 int rv;
191 rv = intf->read(ctx, signature_struct_offset, read_len, buffer);
192 if (rv != LIBCR51SIGN_SUCCESS)
193 {
194 CPRINTS(ctx,
195 "validate_transition: failed to read signature struct");
196 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
197 }
198 if (sig_data->signature_magic != SIGNATURE_MAGIC)
199 {
200 CPRINTS(ctx, "validate_transition: bad signature magic");
201 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
202 }
203
204 if (ctx->descriptor.image_family != ctx->current_image_family &&
205 ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
206 ctx->current_image_family != IMAGE_FAMILY_ALL)
207 {
208 CPRINTS(ctx, "validate_transition: invalid image family");
209 return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
210 }
211
Willy Tud2bcdd52021-11-02 19:51:22 -0700212 if (intf->is_production_mode == NULL)
Nan Zhou7a337042021-07-26 21:05:21 -0700213 {
214 CPRINTS(ctx, "validate_transition: missing is_production_mode");
215 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
216 }
217 if (intf->is_production_mode() &&
218 (ctx->descriptor.image_type == IMAGE_DEV))
219 {
220 CPRINTS(ctx, "validate_transition: checking exemption allowlist");
221
Willy Tud2bcdd52021-11-02 19:51:22 -0700222 // If function is NULL or if the function call return false, return
223 // error
224 if (intf->prod_to_dev_downgrade_allowed == NULL ||
225 !intf->prod_to_dev_downgrade_allowed())
Nan Zhou7a337042021-07-26 21:05:21 -0700226 {
227 CPRINTS(ctx, "validate_transition: illegal image type");
228 return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
229 }
230 }
231 return LIBCR51SIGN_SUCCESS;
232 }
233
234 // If caller had provided read_and_hash_update call that, otherwise call
235 // read and then update.
236
237 static failure_reason
238 read_and_hash_update(const struct libcr51sign_ctx* ctx,
239 const struct libcr51sign_intf* intf,
240 uint32_t offset, uint32_t size)
241 {
242 uint8_t read_buffer[MAX_READ_SIZE];
243 int rv;
244 int read_size;
245
246 if (intf->read_and_hash_update)
247 {
248 rv = intf->read_and_hash_update((void*)ctx, offset, size);
249 }
250 else
251 {
252 if (!intf->hash_update)
253 {
254 CPRINTS(ctx, "read_and_hash_update: missing hash_update");
255 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
256 }
257 do
258 {
259 read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
260 rv = intf->read((void*)ctx, offset, read_size, read_buffer);
261 if (rv != LIBCR51SIGN_SUCCESS)
262 {
263 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
264 }
265 rv = intf->hash_update((void*)ctx, read_buffer, read_size);
266 if (rv != LIBCR51SIGN_SUCCESS)
267 {
268 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
269 }
270 offset += read_size;
271 size -= read_size;
272 } while (size > 0);
273 }
274 return rv;
275 }
276
277 // Validates the image_region array, namely that:
278 // - The regions are aligned, contiguous & exhaustive
279 // - That the image descriptor resides in a static region
280 //
281 // If the array is consistent, proceeds to hash the static regions and
282 // validates the hash. d_offset is the absolute image descriptor offset
283
Willy Tudf800482021-09-17 22:06:18 -0700284 static failure_reason validate_payload_regions(
285 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
286 uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
Nan Zhou7a337042021-07-26 21:05:21 -0700287 {
288 // Allocate buffer to accomodate largest supported hash-type(SHA512)
289 uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
Willy Tudf800482021-09-17 22:06:18 -0700290 LIBCR51SIGN_SHA512_DIGEST_SIZE];
291 uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
Nan Zhou7a337042021-07-26 21:05:21 -0700292 uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
William A. Kennington IIIdeb55012021-10-28 17:12:23 -0700293 uint32_t i;
Nan Zhou7a337042021-07-26 21:05:21 -0700294 uint8_t d_region_num = 0;
William A. Kennington IIIdeb55012021-10-28 17:12:23 -0700295 int rv;
Willy Tudf800482021-09-17 22:06:18 -0700296 struct image_region const* region;
297
298 if (image_regions == NULL)
299 {
300 CPRINTS(ctx, "Missing image region input");
301 return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
302 }
Nan Zhou7a337042021-07-26 21:05:21 -0700303
304 BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
305 MEMBER_SIZE(struct hash_sha512, hash_magic)));
306 image_size = ctx->descriptor.image_size;
307 region_count = ctx->descriptor.region_count;
308 hash_offset = d_offset + sizeof(struct image_descriptor) +
309 region_count * sizeof(struct image_region);
310 // Read the image_region array.
Willy Tudf800482021-09-17 22:06:18 -0700311
312 if (region_count > ARRAY_SIZE(image_regions->image_regions))
313 {
314 CPRINTS(ctx, "validate_payload_regions: "
315 "ctx->descriptor.region_count is greater "
316 "than LIBCR51SIGN_MAX_REGION_COUNT");
317 return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
318 }
319
William A. Kennington IIIdeb55012021-10-28 17:12:23 -0700320 rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
321 region_count * sizeof(struct image_region),
322 (uint8_t*)&image_regions->image_regions);
Willy Tudf800482021-09-17 22:06:18 -0700323
324 image_regions->region_count = region_count;
325
Nan Zhou7a337042021-07-26 21:05:21 -0700326 if (rv != LIBCR51SIGN_SUCCESS)
327 {
328 CPRINTS(ctx,
329 "validate_payload_regions: failed to read region array");
330 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
331 }
332
333 // Validate that the regions are contiguous & exhaustive.
334 for (i = 0, byte_count = 0; i < region_count; i++)
335 {
Willy Tudf800482021-09-17 22:06:18 -0700336 region = image_regions->image_regions + i;
337
Nan Zhou7a337042021-07-26 21:05:21 -0700338 CPRINTS(ctx,
339 "validate_payload_regions: region #%d \"%s\" (%x - %x)", i,
William A. Kennington IIIdeb55012021-10-28 17:12:23 -0700340 (const char*)region->region_name, region->region_offset,
Willy Tudf800482021-09-17 22:06:18 -0700341 region->region_offset + region->region_size);
342 if ((region->region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
343 (region->region_size % IMAGE_REGION_ALIGNMENT) != 0)
Nan Zhou7a337042021-07-26 21:05:21 -0700344 {
345 CPRINTS(
346 ctx,
347 "validate_payload_regions: regions must be sector aligned");
348 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
349 }
Willy Tudf800482021-09-17 22:06:18 -0700350 if (region->region_offset != byte_count ||
351 region->region_size > image_size - byte_count)
Nan Zhou7a337042021-07-26 21:05:21 -0700352 {
353 CPRINTS(ctx, "validate_payload_regions: invalid region array");
354 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
355 }
Willy Tudf800482021-09-17 22:06:18 -0700356 byte_count += region->region_size;
Nan Zhou7a337042021-07-26 21:05:21 -0700357 // The image descriptor must be part of a static region.
Willy Tudf800482021-09-17 22:06:18 -0700358 if (d_offset >= region->region_offset && d_offset < byte_count)
Nan Zhou7a337042021-07-26 21:05:21 -0700359 {
360 d_region_num = i;
361 CPRINTS(
362 ctx,
363 "validate_payload_regions: image descriptor in region %d",
364 i);
365 // The descriptor can't span regions.
366 if (ctx->descriptor.descriptor_area_size > byte_count ||
Willy Tudf800482021-09-17 22:06:18 -0700367 !(region->region_attributes & IMAGE_REGION_STATIC))
Nan Zhou7a337042021-07-26 21:05:21 -0700368 {
369 CPRINTS(
370 ctx,
371 "validate_payload_regions: descriptor must reside in "
372 "static region");
373 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
374 }
375 }
376 }
377 if (byte_count != image_size)
378 {
379 CPRINTS(ctx, "validate_payload_regions: invalid image size");
380 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
381 }
382
383 rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
384 if (rv != LIBCR51SIGN_SUCCESS)
385 {
386 return rv;
387 }
388
389 rv = intf->read(ctx, hash_offset,
390 MEMBER_SIZE(struct hash_sha256, hash_magic) +
391 digest_size,
392 magic_and_digest);
393 if (rv != LIBCR51SIGN_SUCCESS)
394 {
395 CPRINTS(ctx,
396 "validate_payload_regions: failed to read hash from flash");
397 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
398 }
399 if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
400 {
401 CPRINTS(ctx, "validate_payload_regions: bad hash magic");
402 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
403 }
404 rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
405 if (rv != LIBCR51SIGN_SUCCESS)
406 {
407 CPRINTS(ctx, "validate_payload_regions: hash_init failed");
408 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
409 }
410 for (i = 0; i < region_count; i++)
411 {
412 uint32_t hash_start, hash_size;
Willy Tudf800482021-09-17 22:06:18 -0700413 region = image_regions->image_regions + i;
414
415 if (!(region->region_attributes & IMAGE_REGION_STATIC))
Nan Zhou7a337042021-07-26 21:05:21 -0700416 {
417 continue;
418 }
Willy Tudf800482021-09-17 22:06:18 -0700419 hash_start = region->region_offset;
420 hash_size = region->region_size;
Nan Zhou7a337042021-07-26 21:05:21 -0700421
422 // Skip the descriptor.
423 do
424 {
425 if (i == d_region_num)
426 {
427 hash_size = d_offset - hash_start;
428 }
429
430 if (!hash_size)
431 {
432 hash_start += ctx->descriptor.descriptor_area_size;
Willy Tudf800482021-09-17 22:06:18 -0700433 hash_size = (region->region_offset + region->region_size -
434 hash_start);
Nan Zhou7a337042021-07-26 21:05:21 -0700435 }
436 CPRINTS("validate_payload_regions: hashing %s (%x - %x)",
William A. Kennington IIIdeb55012021-10-28 17:12:23 -0700437 (const char*)region->region_name, hash_start,
Nan Zhou7a337042021-07-26 21:05:21 -0700438 hash_start + hash_size);
439 // Read the image_region array.
440 rv = read_and_hash_update(ctx, intf, hash_start, hash_size);
441 if (rv != LIBCR51SIGN_SUCCESS)
442 {
443 return rv;
444 }
445 hash_start += hash_size;
Willy Tudf800482021-09-17 22:06:18 -0700446 } while (hash_start != region->region_offset + region->region_size);
Nan Zhou7a337042021-07-26 21:05:21 -0700447 }
448 rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
449
450 if (rv != LIBCR51SIGN_SUCCESS)
451 {
452 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
453 }
454
455 if (memcmp(magic_and_digest +
456 MEMBER_SIZE(struct hash_sha256, hash_magic),
457 dcrypto_digest, digest_size))
458 {
459 CPRINTS(ctx, "validate_payload_regions: invalid hash");
460 return LIBCR51SIGN_ERROR_INVALID_HASH;
461 }
462 // Image is valid.
463 return LIBCR51SIGN_SUCCESS;
464 }
465
Willy Tudf800482021-09-17 22:06:18 -0700466 // Create empty image_regions to pass to validate_payload_regions
467 // Support validate_payload_regions_helper to remove image_regions as a
468 // required input.
469
470 static failure_reason
471 allocate_and_validate_payload_regions(const struct libcr51sign_ctx* ctx,
472 struct libcr51sign_intf* intf,
473 uint32_t d_offset)
474 {
475 struct libcr51sign_validated_regions image_regions;
476 return validate_payload_regions(ctx, intf, d_offset, &image_regions);
477 }
478
479 // Wrapper around validate_payload_regions to allow nullptr for
480 // image_regions. Calls allocate_and_validate_payload_regions when
481 // image_regions is nullptr to create placer holder image_regions.
482
483 static failure_reason validate_payload_regions_helper(
484 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
485 uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
486 {
487 if (image_regions)
488 {
489 return validate_payload_regions(ctx, intf, d_offset, image_regions);
490 }
491
492 return allocate_and_validate_payload_regions(ctx, intf, d_offset);
493 }
494
Nan Zhou7a337042021-07-26 21:05:21 -0700495 // Check if the given signature_scheme is supported.
496 // Returns nonzero on error, zero on success
497
498 static failure_reason
499 is_signature_scheme_supported(enum signature_scheme scheme)
500 {
501 switch (scheme)
502 {
503 case SIGNATURE_RSA2048_PKCS15:
504 case SIGNATURE_RSA3072_PKCS15:
505 case SIGNATURE_RSA4096_PKCS15:
506 case SIGNATURE_RSA4096_PKCS15_SHA512:
507 return LIBCR51SIGN_SUCCESS;
508 default:
509 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
510 }
511 }
512
513 // Returns size of signature struct size in |size|
514 // Returns nonzero on error, zero on success
515
516 static failure_reason
517 get_signature_struct_size(enum signature_scheme scheme, uint32_t* size)
518 {
519 switch (scheme)
520 {
521 case SIGNATURE_RSA2048_PKCS15:
522 *size = sizeof(struct signature_rsa2048_pkcs15);
523 return LIBCR51SIGN_SUCCESS;
524 case SIGNATURE_RSA3072_PKCS15:
525 *size = sizeof(struct signature_rsa3072_pkcs15);
526 return LIBCR51SIGN_SUCCESS;
527 case SIGNATURE_RSA4096_PKCS15:
528 case SIGNATURE_RSA4096_PKCS15_SHA512:
529 *size = sizeof(struct signature_rsa4096_pkcs15);
530 return LIBCR51SIGN_SUCCESS;
531 default:
532 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
533 }
534 }
535
536 static failure_reason
537 get_signature_field_offset(enum signature_scheme scheme,
538 uint32_t* offset)
539 {
540 switch (scheme)
541 {
542 case SIGNATURE_RSA2048_PKCS15:
543 *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
544 return LIBCR51SIGN_SUCCESS;
545 case SIGNATURE_RSA3072_PKCS15:
546 *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
547 return LIBCR51SIGN_SUCCESS;
548 case SIGNATURE_RSA4096_PKCS15:
549 case SIGNATURE_RSA4096_PKCS15_SHA512:
550 *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
551 return LIBCR51SIGN_SUCCESS;
552 default:
553 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
554 }
555 }
556
557 // Validates the signature (of type scheme) read from "device" at
558 //"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
559 // EEPROM area "data_offset:data_size".
560
561 static failure_reason validate_signature(
562 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
563 uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
564 uint32_t raw_signature_offset)
565 {
Willy Tudf800482021-09-17 22:06:18 -0700566 uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
Nan Zhou7a337042021-07-26 21:05:21 -0700567 uint16_t key_size;
568 uint32_t digest_size;
Willy Tudf800482021-09-17 22:06:18 -0700569 uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
Nan Zhou7a337042021-07-26 21:05:21 -0700570 int rv;
571 enum hash_type hash_type;
572
573 if (!intf->hash_init)
574 {
575 CPRINTS(ctx, "validate_signature: missing hash_init");
576 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
577 }
578 rv = get_hash_type_from_signature(scheme, &hash_type);
579 if (rv != LIBCR51SIGN_SUCCESS)
580 {
581 CPRINTS(
582 ctx,
583 "validate_payload_regions: hash_type from signature failed");
584 return rv;
585 }
586 rv = intf->hash_init(ctx, hash_type);
587 if (rv != LIBCR51SIGN_SUCCESS)
588 {
589 CPRINTS(ctx, "validate_payload_regions: hash_init failed");
590 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
591 }
592 rv = read_and_hash_update(ctx, intf, data_offset, data_size);
593 if (rv != LIBCR51SIGN_SUCCESS)
594 {
595 CPRINTS(ctx, "validate_signature: hash_update failed");
596 return rv;
597 }
598 if (!intf->hash_final)
599 {
600 CPRINTS(ctx, "validate_signature: missing hash_final");
601 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
602 }
603 rv = intf->hash_final((void*)ctx, dcrypto_digest);
604 if (rv != LIBCR51SIGN_SUCCESS)
605 {
606 CPRINTS(ctx, "validate_signature: hash_final failed (status = %d)",
607 rv);
608 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
609 }
610 rv = get_key_size(scheme, &key_size);
611 if (rv != LIBCR51SIGN_SUCCESS)
612 {
613 return rv;
614 }
615
616 rv = intf->read(ctx, raw_signature_offset, key_size, signature);
617 if (rv != LIBCR51SIGN_SUCCESS)
618 {
619 CPRINTS(
620 ctx,
621 "validate_signature: failed to read signature (status = %d)",
622 rv);
623 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
624 }
625 if (!intf->verify_signature)
626 {
627 CPRINTS(ctx, "validate_signature: missing verify_signature");
628 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
629 }
630 rv = get_hash_digest_size(hash_type, &digest_size);
631 if (rv != LIBCR51SIGN_SUCCESS)
632 {
633 return rv;
634 }
635 rv = intf->verify_signature(ctx, scheme, signature, key_size,
636 dcrypto_digest, digest_size);
637 if (rv != LIBCR51SIGN_SUCCESS)
638 {
639 CPRINTS(ctx,
640 "validate_signature: verification failed (status = %d)",
641 rv);
642 return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
643 }
644 CPRINTS(ctx, "validate_signature: verification succeeded");
645 return LIBCR51SIGN_SUCCESS;
646 }
647
648 // Sanity checks the image descriptor & validates its signature.
649 // This function does not validate the image_region array or image hash.
650 //
651 //@param[in] ctx context which describes the image and holds opaque private
652 // data for the user of the library
653 //@param[in] intf function pointers which interface to the current system
654 // and environment
655 //@param offset Absolute image descriptor flash offset.
656 //@param relative_offset Image descriptor offset relative to image start.
657 //@param image_size Image size in bytes.
658 //@param descriptor Output pointer to an image_descriptor struct
659
660 static failure_reason validate_descriptor(
661 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
662 uint32_t offset, uint32_t relative_offset, uint32_t image_size)
663 {
664 uint32_t max_descriptor_size, signed_size, signature_scheme,
665 signature_offset;
666 uint32_t signature_struct_offset, signature_struct_size,
667 hash_struct_size;
668 int rv;
669
670 max_descriptor_size = image_size - relative_offset;
671 if (image_size < relative_offset ||
672 max_descriptor_size < sizeof(struct image_descriptor))
673 {
674 CPRINTS(ctx, "validate_descriptor: invalid arguments");
675 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
676 }
677
678 rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
679 (uint8_t*)&ctx->descriptor);
680 if (rv != LIBCR51SIGN_SUCCESS)
681 {
682 CPRINTS(ctx, "validate_descriptor: failed to read descriptor");
683 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
684 }
685 if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
686 ctx->descriptor.descriptor_offset != relative_offset ||
687 ctx->descriptor.region_count == 0 ||
688 ctx->descriptor.descriptor_area_size > max_descriptor_size ||
689 ctx->descriptor.image_size != image_size)
690 {
691 CPRINTS(ctx, "validate_descriptor: invalid descriptor");
692 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
693 }
694 if (ctx->descriptor.image_type != IMAGE_DEV &&
695 ctx->descriptor.image_type != IMAGE_PROD &&
696 ctx->descriptor.image_type != IMAGE_BREAKOUT &&
697 ctx->descriptor.image_type != IMAGE_TEST &&
Willy Tudf800482021-09-17 22:06:18 -0700698 ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
Nan Zhou7a337042021-07-26 21:05:21 -0700699 {
700 CPRINTS(ctx, "validate_descriptor: bad image type");
701 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
702 }
703 // Although the image_descriptor struct supports unauthenticated
704 // images, Haven will not allow it.
705 // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
706
707 signature_scheme = ctx->descriptor.signature_scheme;
708
709 rv = is_signature_scheme_supported(signature_scheme);
710 if (rv != LIBCR51SIGN_SUCCESS)
711 {
712 return rv;
713 }
714 rv = is_hash_type_supported(ctx->descriptor.hash_type);
715 if (rv != LIBCR51SIGN_SUCCESS)
716 {
717 CPRINTS(ctx, "validate_payload_regions: invalid hash type");
718 return rv;
719 }
720 if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
Willy Tudf800482021-09-17 22:06:18 -0700721 ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
Nan Zhou7a337042021-07-26 21:05:21 -0700722 {
723 CPRINTS(ctx, "validate_descriptor: unsupported descriptor");
724 return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
725 }
726 rv =
727 get_signature_struct_size(signature_scheme, &signature_struct_size);
728 if (rv != LIBCR51SIGN_SUCCESS)
729 {
730 return rv;
731 }
732
733 // Compute the size of the signed portion of the image descriptor.
734 signed_size =
735 sizeof(struct image_descriptor) +
736 ctx->descriptor.region_count * sizeof(struct image_region);
737 rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
738 if (rv != LIBCR51SIGN_SUCCESS)
739 {
740 return rv;
741 }
742 signed_size += hash_struct_size;
743 if (ctx->descriptor.denylist_size)
744 {
745 signed_size += sizeof(struct denylist);
746 signed_size +=
747 ctx->descriptor.denylist_size * sizeof(struct denylist_record);
748 }
749 if (ctx->descriptor.blob_size)
750 {
751 signed_size += sizeof(struct blob);
752 // Previous additions are guaranteed not to overflow.
753 if (ctx->descriptor.blob_size >
754 ctx->descriptor.descriptor_area_size - signed_size)
755 {
756 CPRINTS(ctx, "validate_descriptor: invalid blob size (0x%x)",
757 ctx->descriptor.blob_size);
758 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
759 }
760 signed_size += ctx->descriptor.blob_size;
761 }
762 if (signature_struct_size >
763 ctx->descriptor.descriptor_area_size - signed_size)
764 {
765 CPRINTS(ctx,
766 "validate_descriptor: invalid descriptor area size "
767 "(expected = 0x%x, actual = 0x%x)",
768 ctx->descriptor.descriptor_area_size,
769 signed_size + signature_struct_size);
770 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
771 }
772 signature_struct_offset = signed_size;
773 // Omit the actual signature.
774 rv = get_signature_field_offset(signature_scheme, &signature_offset);
775 if (rv != LIBCR51SIGN_SUCCESS)
776 {
777 return rv;
778 }
779 signed_size += signature_offset;
780
781 // Lookup key & validate transition.
782 rv = validate_transition(ctx, intf, offset + signature_struct_offset);
783
784 if (rv != LIBCR51SIGN_SUCCESS)
785 {
786 return rv;
787 }
788 return validate_signature(ctx, intf, offset, signed_size,
789 signature_scheme, offset + signed_size);
790 }
791
792 // Scans the external EEPROM for a magic value at "alignment" boundaries.
793 //
794 //@param device Handle to the external EEPROM.
795 //@param magic 8-byte pattern to search for.
796 //@param start_offset Offset to begin searching at.
797 //@param limit Exclusive address (e.g. EEPROM size).
798 //@param alignment Alignment boundaries (POW2) to search on.
799 //@param header_offset Location to place the new header offset.
800 //@return LIBCR51SIGN_SUCCESS (or non-zero on error).
801
802 int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
803 const struct libcr51sign_intf* intf, uint64_t magic,
804 uint32_t start_offset, uint32_t limit,
805 uint32_t alignment, uint32_t* header_offset)
806 {
807 uint64_t read_data;
808 uint32_t offset;
809 int rv;
810
811 if (limit <= start_offset || limit > ctx->end_offset ||
812 limit < sizeof(magic) || !POWER_OF_TWO(alignment))
813 {
814 return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
815 }
816
817 if (!intf->read)
818 {
819 CPRINTS(ctx, "scan_for_magic_8: missing intf->read");
820 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
821 }
822 // Align start_offset to the next valid boundary.
823 start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
824 for (offset = start_offset; offset < limit - sizeof(magic);
825 offset += alignment)
826 {
827 rv = intf->read((void*)ctx, offset, sizeof(read_data),
828 (uint8_t*)&read_data);
829 if (rv != LIBCR51SIGN_SUCCESS)
830 {
831 return rv;
832 }
833 if (read_data == magic)
834 {
835 if (header_offset)
836 {
837 *header_offset = offset;
838 }
839 return LIBCR51SIGN_SUCCESS;
840 }
841 }
842 // Failed to locate magic.
843 return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
844 }
845
846 // Check whether the signature on the image is valid.
847 // Validates the authenticity of an EEPROM image. Scans for & validates the
848 // signature on the image descriptor. If the descriptor validates, hashes
849 // the rest of the image to verify its integrity.
850 //
851 // @param[in] ctx - context which describes the image and holds opaque
852 // private
853 // data for the user of the library
854 // @param[in] intf - function pointers which interface to the current system
855 // and environment
Willy Tudf800482021-09-17 22:06:18 -0700856 // @param[out] image_regions - image_region pointer to an array for the
857 // output
Nan Zhou7a337042021-07-26 21:05:21 -0700858 //
859 // @return nonzero on error, zero on success
860
Willy Tudf800482021-09-17 22:06:18 -0700861 failure_reason libcr51sign_validate(
862 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
863 struct libcr51sign_validated_regions* image_regions)
Nan Zhou7a337042021-07-26 21:05:21 -0700864 {
865 uint32_t image_limit = 0;
866 int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
867 uint32_t descriptor_offset;
868
869 if (!ctx)
870 {
871 CPRINTS(ctx, "MIssing context");
872 return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
873 }
874 else if (!intf)
875 {
876 CPRINTS(ctx, "Missing interface");
877 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
878 }
879
880 rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
881 ctx->end_offset, DESCRIPTOR_ALIGNMENT,
882 &descriptor_offset);
883 while (rv == LIBCR51SIGN_SUCCESS)
884 {
885 CPRINTS(ctx, "validate: potential image descriptor found @%x ",
886 descriptor_offset);
887 // Validation is split into 2 functions to minimize
888 // stack usage.
889
890 rv = validate_descriptor(ctx, intf, descriptor_offset,
891 descriptor_offset - ctx->start_offset,
892 ctx->end_offset - ctx->start_offset);
893 if (rv != LIBCR51SIGN_SUCCESS)
894 {
895 CPRINTS(ctx, "validate: validate_descriptor() failed ec%d ",
896 rv);
897 }
898
899 if (rv == LIBCR51SIGN_SUCCESS)
900 {
Willy Tudf800482021-09-17 22:06:18 -0700901 rv = validate_payload_regions_helper(
902 ctx, intf, descriptor_offset, image_regions);
Nan Zhou7a337042021-07-26 21:05:21 -0700903 if (rv == LIBCR51SIGN_SUCCESS)
904 {
905 CPRINTS(ctx, "validate: success!");
906 return rv;
907 }
908 CPRINTS(ctx,
909 "validate: validate_payload_regions() failed ec%d ",
910 rv);
911 }
912 // Store the first desc fail reason if any
913 if (rv != LIBCR51SIGN_SUCCESS &&
914 rv_first_desc == LIBCR51SIGN_SUCCESS)
915 rv_first_desc = rv;
916
917 // scan_for_magic_8() will round up to the next aligned boundary.
918 descriptor_offset++;
919 image_limit = ctx->end_offset - ctx->start_offset;
920 rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC,
921 descriptor_offset, image_limit,
922 DESCRIPTOR_ALIGNMENT, &descriptor_offset);
923 }
924 CPRINTS(ctx, "validate: failed to validate image ec%d ", rv);
925 // If desc validation failed for some reason then return that reason
926 if (rv_first_desc != LIBCR51SIGN_SUCCESS)
927 return rv_first_desc;
928 else
929 return rv;
930 }
931
932 // @func to returns the libcr51sign error code as a string
933 // @param[in] ec - Error code
934 // @return error code in string format
935
936 const char* libcr51sign_errorcode_to_string(failure_reason ec)
937 {
938 switch (ec)
939 {
940 case LIBCR51SIGN_SUCCESS:
941 return "Success";
942 case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
943 return "Runtime Error Failure";
944 case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
945 return "Unsupported descriptor";
946 case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
947 return "Invalid descriptor";
948 case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
949 return "Invalid image family";
950 case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
951 return "Image type disallowed";
952 case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
953 return "Dev downgrade disallowed";
954 case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
955 return "Untrusted key";
956 case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
957 return "Invalid signature";
958 case LIBCR51SIGN_ERROR_INVALID_HASH:
959 return "Invalid hash";
960 case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
961 return "Invalid hash type";
962 case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
963 return "Invalid Argument";
964 case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
965 return "Failed to locate descriptor";
966 case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
967 return "Invalid context";
968 case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
969 return "Invalid interface";
970 case LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME:
971 return "Invalid signature scheme";
Willy Tudf800482021-09-17 22:06:18 -0700972 case LIBCR51SIGN_ERROR_INVALID_REGION_INPUT:
973 return "Invalid image region input";
974 case LIBCR51SIGN_ERROR_INVALID_REGION_SIZE:
975 return "Invalid image region size";
Nan Zhou7a337042021-07-26 21:05:21 -0700976 default:
977 return "Unknown error";
978 }
979 }
980
981#ifdef __cplusplus
982} // extern "C"
983#endif