blob: 5c41a045bb0610169c03b0bbad983e4251286ef2 [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 */
Willy Tudca92e42023-11-16 23:22:07 -080016#include <assert.h>
17#include <libcr51sign/cr51_image_descriptor.h>
William A. Kennington III5acaca22021-10-28 16:32:33 -070018#include <libcr51sign/libcr51sign.h>
Willy Tudca92e42023-11-16 23:22:07 -080019#include <libcr51sign/libcr51sign_internal.h>
20#include <libcr51sign/libcr51sign_mauv.h>
Dan Zhang027c0422025-06-01 17:36:41 +000021#include <stddef.h>
Willy Tudca92e42023-11-16 23:22:07 -080022#include <stdint.h>
Nan Zhou7a337042021-07-26 21:05:21 -070023#include <stdio.h>
Willy Tudca92e42023-11-16 23:22:07 -080024#include <stdlib.h>
Nan Zhou7a337042021-07-26 21:05:21 -070025#include <string.h>
26
27#ifdef __cplusplus
28extern "C"
29{
30#endif
31
Nan Zhou7a337042021-07-26 21:05:21 -070032// True of x is a power of two
Patrick Williamsc66ebc32024-08-16 15:21:56 -040033#define POWER_OF_TWO(x) ((x) && !((x) & ((x) - 1)))
Nan Zhou7a337042021-07-26 21:05:21 -070034
35// Maximum version supported. Major revisions are not backwards compatible.
36#define MAX_MAJOR_VERSION 1
37
Nan Zhou7a337042021-07-26 21:05:21 -070038// Descriptor alignment on the external EEPROM.
39#define DESCRIPTOR_ALIGNMENT (64 * 1024)
40
41// SPS EEPROM sector size is 4KiB, since this is the smallest erasable size.
42#define IMAGE_REGION_ALIGNMENT 4096
43
44#define MAX_READ_SIZE 1024
45
46#ifndef ARRAY_SIZE
47#define ARRAY_SIZE(t) (sizeof(t) / sizeof(t[0]))
48#endif
49
Dan Zhang027c0422025-06-01 17:36:41 +000050// Values of SIGNATURE_OFFSET should be same for all sig types (2048,3072,4096)
Nan Zhou7a337042021-07-26 21:05:21 -070051#define SIGNATURE_OFFSET offsetof(struct signature_rsa3072_pkcs15, modulus)
52
53#ifndef BUILD_ASSERT
54#define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
55#endif
56
Patrick Williams60849572023-10-20 11:19:52 -050057// Returns the bytes size of keys used in the given signature_scheme.
58// Return error if signature_scheme is invalid.
59//
60static failure_reason get_key_size(enum signature_scheme signature_scheme,
61 uint16_t* key_size)
62{
63 switch (signature_scheme)
Nan Zhou7a337042021-07-26 21:05:21 -070064 {
Patrick Williams60849572023-10-20 11:19:52 -050065 case SIGNATURE_RSA2048_PKCS15:
66 *key_size = 256;
67 return LIBCR51SIGN_SUCCESS;
68 case SIGNATURE_RSA3072_PKCS15:
69 *key_size = 384;
70 return LIBCR51SIGN_SUCCESS;
71 case SIGNATURE_RSA4096_PKCS15:
72 case SIGNATURE_RSA4096_PKCS15_SHA512:
73 *key_size = 512;
74 return LIBCR51SIGN_SUCCESS;
75 default:
76 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
77 }
78}
79
80// Returns the hash_type for a given signature scheme
81// Returns error if scheme is invalid.
82failure_reason get_hash_type_from_signature(enum signature_scheme scheme,
83 enum hash_type* type)
84{
85 switch (scheme)
86 {
87 case SIGNATURE_RSA2048_PKCS15:
88 case SIGNATURE_RSA3072_PKCS15:
89 case SIGNATURE_RSA4096_PKCS15:
90 *type = HASH_SHA2_256;
91 return LIBCR51SIGN_SUCCESS;
92 case SIGNATURE_RSA4096_PKCS15_SHA512:
93 *type = HASH_SHA2_512;
94 return LIBCR51SIGN_SUCCESS;
95 default:
96 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
97 }
98}
99
100// Check if the given hash_type is supported.
101// Returns error if hash_type is not supported.
102static failure_reason is_hash_type_supported(enum hash_type type)
103{
104 switch (type)
105 {
106 case HASH_SHA2_256:
107 case HASH_SHA2_512:
108 return LIBCR51SIGN_SUCCESS;
109 default:
110 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
111 }
112}
113
114// Determines digest size for a given hash_type.
115// Returns error if hash_type is not supported.
116static failure_reason get_hash_digest_size(enum hash_type type, uint32_t* size)
117{
118 switch (type)
119 {
120 case HASH_SHA2_256:
121 *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
122 return LIBCR51SIGN_SUCCESS;
123 case HASH_SHA2_512:
124 *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
125 return LIBCR51SIGN_SUCCESS;
126 default:
127 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
128 }
129}
130
131// Determines hash struct size for a given hash_type.
132// Returns error if hash_type is not supported.
133static failure_reason get_hash_struct_size(enum hash_type type, uint32_t* size)
134{
135 switch (type)
136 {
137 case HASH_SHA2_256:
138 *size = sizeof(struct hash_sha256);
139 return LIBCR51SIGN_SUCCESS;
140 case HASH_SHA2_512:
Willy Tudca92e42023-11-16 23:22:07 -0800141 *size = sizeof(struct hash_sha512);
Patrick Williams60849572023-10-20 11:19:52 -0500142 return LIBCR51SIGN_SUCCESS;
143 default:
144 return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
145 }
146}
147
148// Checks that:
149// - The signing key is trusted
150// - The target version is not denylisted
151// If validating a staged update, also checks that:
152// - The target image family matches the current image family
153// - The image type transition is legal (i.e. dev -> *|| prod -> prod) or
154// alternatively that the hardware ID is allowlisted
155// Assuming the caller has performed following:
156// board_get_base_key_index();
157// board_get_key_array
158// Possible return codes:
159// LIBCR51SIGN_SUCCESS = 0,
160// LIBCR51SIGN_ERROR_RUNTIME_FAILURE = 1,
161// LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR = 3,
162// LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY = 4,
163// LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED = 5,
164
165static failure_reason validate_transition(const struct libcr51sign_ctx* ctx,
166 const struct libcr51sign_intf* intf,
167 uint32_t signature_struct_offset)
168{
169 BUILD_ASSERT((offsetof(struct signature_rsa2048_pkcs15, modulus) ==
170 SIGNATURE_OFFSET &&
171 offsetof(struct signature_rsa3072_pkcs15, modulus) ==
172 SIGNATURE_OFFSET &&
173 offsetof(struct signature_rsa4096_pkcs15, modulus) ==
174 SIGNATURE_OFFSET));
175
176 // Read up to the modulus.
177 enum
178 {
179 read_len = SIGNATURE_OFFSET
180 };
Dan Zhang027c0422025-06-01 17:36:41 +0000181 uint32_t buffer[read_len / sizeof(uint32_t)];
Patrick Williams60849572023-10-20 11:19:52 -0500182 int rv;
Dan Zhang027c0422025-06-01 17:36:41 +0000183 rv = intf->read(ctx, signature_struct_offset, read_len, (uint8_t*)buffer);
Patrick Williams60849572023-10-20 11:19:52 -0500184 if (rv != LIBCR51SIGN_SUCCESS)
185 {
Willy Tudca92e42023-11-16 23:22:07 -0800186 CPRINTS(ctx, "%s: failed to read signature struct\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500187 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
188 }
Dan Zhang027c0422025-06-01 17:36:41 +0000189 if (*buffer != SIGNATURE_MAGIC)
Patrick Williams60849572023-10-20 11:19:52 -0500190 {
Willy Tudca92e42023-11-16 23:22:07 -0800191 CPRINTS(ctx, "%s: bad signature magic\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500192 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
Nan Zhou7a337042021-07-26 21:05:21 -0700193 }
194
Patrick Williams60849572023-10-20 11:19:52 -0500195 if (ctx->descriptor.image_family != ctx->current_image_family &&
196 ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
197 ctx->current_image_family != IMAGE_FAMILY_ALL)
Nan Zhou7a337042021-07-26 21:05:21 -0700198 {
Willy Tudca92e42023-11-16 23:22:07 -0800199 CPRINTS(ctx, "%s: invalid image family\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500200 return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
Nan Zhou7a337042021-07-26 21:05:21 -0700201 }
202
Patrick Williams60849572023-10-20 11:19:52 -0500203 if (intf->is_production_mode == NULL)
Nan Zhou7a337042021-07-26 21:05:21 -0700204 {
Willy Tudca92e42023-11-16 23:22:07 -0800205 CPRINTS(ctx, "%s: missing is_production_mode\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500206 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
207 }
208 if (intf->is_production_mode() && (ctx->descriptor.image_type == IMAGE_DEV))
209 {
Willy Tudca92e42023-11-16 23:22:07 -0800210 CPRINTS(ctx, "%s: checking exemption allowlist\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500211
212 // If function is NULL or if the function call return false, return
213 // error
214 if (intf->prod_to_dev_downgrade_allowed == NULL ||
215 !intf->prod_to_dev_downgrade_allowed())
Nan Zhou7a337042021-07-26 21:05:21 -0700216 {
Willy Tudca92e42023-11-16 23:22:07 -0800217 CPRINTS(ctx, "%s: illegal image type\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500218 return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
Nan Zhou7a337042021-07-26 21:05:21 -0700219 }
220 }
Patrick Williams60849572023-10-20 11:19:52 -0500221 return LIBCR51SIGN_SUCCESS;
222}
Nan Zhou7a337042021-07-26 21:05:21 -0700223
Willy Tudca92e42023-11-16 23:22:07 -0800224// If caller had provided read_and_hash_update call that, otherwise call read
225// and then update.
Patrick Williams60849572023-10-20 11:19:52 -0500226
227static failure_reason read_and_hash_update(const struct libcr51sign_ctx* ctx,
228 const struct libcr51sign_intf* intf,
229 uint32_t offset, uint32_t size)
230{
231 uint8_t read_buffer[MAX_READ_SIZE];
232 int rv;
Dan Zhang027c0422025-06-01 17:36:41 +0000233 uint32_t read_size;
Patrick Williams60849572023-10-20 11:19:52 -0500234
235 if (intf->read_and_hash_update)
Nan Zhou7a337042021-07-26 21:05:21 -0700236 {
Patrick Williams60849572023-10-20 11:19:52 -0500237 rv = intf->read_and_hash_update((void*)ctx, offset, size);
Nan Zhou7a337042021-07-26 21:05:21 -0700238 }
Patrick Williams60849572023-10-20 11:19:52 -0500239 else
Nan Zhou7a337042021-07-26 21:05:21 -0700240 {
Patrick Williams60849572023-10-20 11:19:52 -0500241 if (!intf->hash_update)
Nan Zhou7a337042021-07-26 21:05:21 -0700242 {
Willy Tudca92e42023-11-16 23:22:07 -0800243 CPRINTS(ctx, "%s: missing hash_update\n", __FUNCTION__);
Nan Zhou7a337042021-07-26 21:05:21 -0700244 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
245 }
Patrick Williams60849572023-10-20 11:19:52 -0500246 do
Nan Zhou7a337042021-07-26 21:05:21 -0700247 {
Patrick Williams60849572023-10-20 11:19:52 -0500248 read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
249 rv = intf->read((void*)ctx, offset, read_size, read_buffer);
250 if (rv != LIBCR51SIGN_SUCCESS)
Nan Zhou7a337042021-07-26 21:05:21 -0700251 {
Patrick Williams60849572023-10-20 11:19:52 -0500252 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
Nan Zhou7a337042021-07-26 21:05:21 -0700253 }
Patrick Williams60849572023-10-20 11:19:52 -0500254 rv = intf->hash_update((void*)ctx, read_buffer, read_size);
255 if (rv != LIBCR51SIGN_SUCCESS)
256 {
257 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
258 }
259 offset += read_size;
260 size -= read_size;
261 } while (size > 0);
262 }
263 return rv;
264}
265
266// Validates the image_region array, namely that:
267// - The regions are aligned, contiguous & exhaustive
268// - That the image descriptor resides in a static region
269//
270// If the array is consistent, proceeds to hash the static regions and
271// validates the hash. d_offset is the absolute image descriptor offset
272
273static failure_reason validate_payload_regions(
274 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
275 uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
276{
Dan Zhang027c0422025-06-01 17:36:41 +0000277 // Allocate buffer to accommodate largest supported hash-type(SHA512)
Patrick Williams60849572023-10-20 11:19:52 -0500278 uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
279 LIBCR51SIGN_SHA512_DIGEST_SIZE];
280 uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
281 uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
282 uint32_t i;
Dan Zhang027c0422025-06-01 17:36:41 +0000283 uint32_t d_region_num = 0;
Patrick Williams60849572023-10-20 11:19:52 -0500284 int rv;
Willy Tudca92e42023-11-16 23:22:07 -0800285 struct image_region const* region;
Patrick Williams60849572023-10-20 11:19:52 -0500286
287 if (image_regions == NULL)
288 {
Willy Tudca92e42023-11-16 23:22:07 -0800289 CPRINTS(ctx, "%s: Missing image region input\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500290 return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
Nan Zhou7a337042021-07-26 21:05:21 -0700291 }
292
Patrick Williams60849572023-10-20 11:19:52 -0500293 BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
294 MEMBER_SIZE(struct hash_sha512, hash_magic)));
295 image_size = ctx->descriptor.image_size;
296 region_count = ctx->descriptor.region_count;
297 hash_offset = d_offset + sizeof(struct image_descriptor) +
298 region_count * sizeof(struct image_region);
299 // Read the image_region array.
Nan Zhou7a337042021-07-26 21:05:21 -0700300
Patrick Williams60849572023-10-20 11:19:52 -0500301 if (region_count > ARRAY_SIZE(image_regions->image_regions))
Nan Zhou7a337042021-07-26 21:05:21 -0700302 {
Willy Tudca92e42023-11-16 23:22:07 -0800303 CPRINTS(ctx,
304 "%s: ctx->descriptor.region_count is greater "
305 "than LIBCR51SIGN_MAX_REGION_COUNT\n",
306 __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500307 return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
308 }
Nan Zhou7a337042021-07-26 21:05:21 -0700309
Patrick Williams60849572023-10-20 11:19:52 -0500310 rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
311 region_count * sizeof(struct image_region),
312 (uint8_t*)&image_regions->image_regions);
313
314 image_regions->region_count = region_count;
315
316 if (rv != LIBCR51SIGN_SUCCESS)
317 {
Willy Tudca92e42023-11-16 23:22:07 -0800318 CPRINTS(ctx, "%s: failed to read region array\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500319 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
320 }
321
322 // Validate that the regions are contiguous & exhaustive.
323 for (i = 0, byte_count = 0; i < region_count; i++)
324 {
325 region = image_regions->image_regions + i;
326
Willy Tudca92e42023-11-16 23:22:07 -0800327 CPRINTS(ctx, "%s: region #%d \"%s\" (%x - %x)\n", __FUNCTION__, i,
328 (const char*)region->region_name, region->region_offset,
Patrick Williams60849572023-10-20 11:19:52 -0500329 region->region_offset + region->region_size);
330 if ((region->region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
331 (region->region_size % IMAGE_REGION_ALIGNMENT) != 0)
Nan Zhou7a337042021-07-26 21:05:21 -0700332 {
Willy Tudca92e42023-11-16 23:22:07 -0800333 CPRINTS(ctx, "%s: regions must be sector aligned\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500334 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
Nan Zhou7a337042021-07-26 21:05:21 -0700335 }
Patrick Williams60849572023-10-20 11:19:52 -0500336 if (region->region_offset != byte_count ||
337 region->region_size > image_size - byte_count)
Nan Zhou7a337042021-07-26 21:05:21 -0700338 {
Willy Tudca92e42023-11-16 23:22:07 -0800339 CPRINTS(ctx, "%s: invalid region array\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500340 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
341 }
342 byte_count += region->region_size;
343 // The image descriptor must be part of a static region.
344 if (d_offset >= region->region_offset && d_offset < byte_count)
345 {
346 d_region_num = i;
Willy Tudca92e42023-11-16 23:22:07 -0800347 CPRINTS(ctx, "%s: image descriptor in region %d\n", __FUNCTION__,
Patrick Williams60849572023-10-20 11:19:52 -0500348 i);
349 // The descriptor can't span regions.
Willy Tudca92e42023-11-16 23:22:07 -0800350 if ((ctx->descriptor.descriptor_area_size >
351 (byte_count - d_offset)) ||
Patrick Williams60849572023-10-20 11:19:52 -0500352 !(region->region_attributes & IMAGE_REGION_STATIC))
Nan Zhou7a337042021-07-26 21:05:21 -0700353 {
Patrick Williams60849572023-10-20 11:19:52 -0500354 CPRINTS(ctx,
Willy Tudca92e42023-11-16 23:22:07 -0800355 "%s: descriptor must reside in "
356 "static region\n",
357 __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500358 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
Nan Zhou7a337042021-07-26 21:05:21 -0700359 }
Nan Zhou7a337042021-07-26 21:05:21 -0700360 }
Patrick Williams60849572023-10-20 11:19:52 -0500361 }
362 if (byte_count != image_size)
363 {
Willy Tudca92e42023-11-16 23:22:07 -0800364 CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500365 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
366 }
367
368 rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
369 if (rv != LIBCR51SIGN_SUCCESS)
370 {
Nan Zhou7a337042021-07-26 21:05:21 -0700371 return rv;
372 }
373
Patrick Williams60849572023-10-20 11:19:52 -0500374 rv = intf->read(ctx, hash_offset,
375 MEMBER_SIZE(struct hash_sha256, hash_magic) + digest_size,
376 magic_and_digest);
377 if (rv != LIBCR51SIGN_SUCCESS)
Nan Zhou7a337042021-07-26 21:05:21 -0700378 {
Willy Tudca92e42023-11-16 23:22:07 -0800379 CPRINTS(ctx, "%s: failed to read hash from flash\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500380 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
381 }
382 if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
383 {
Willy Tudca92e42023-11-16 23:22:07 -0800384 CPRINTS(ctx, "%s: bad hash magic\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500385 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
386 }
387 rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
388 if (rv != LIBCR51SIGN_SUCCESS)
389 {
Willy Tudca92e42023-11-16 23:22:07 -0800390 CPRINTS(ctx, "%s: hash_init failed\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500391 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
392 }
393 for (i = 0; i < region_count; i++)
394 {
395 uint32_t hash_start, hash_size;
396 region = image_regions->image_regions + i;
Willy Tudf800482021-09-17 22:06:18 -0700397
Patrick Williams60849572023-10-20 11:19:52 -0500398 if (!(region->region_attributes & IMAGE_REGION_STATIC))
399 {
400 continue;
401 }
402 hash_start = region->region_offset;
403 hash_size = region->region_size;
404
405 // Skip the descriptor.
406 do
407 {
408 if (i == d_region_num)
Nan Zhou7a337042021-07-26 21:05:21 -0700409 {
Patrick Williams60849572023-10-20 11:19:52 -0500410 hash_size = d_offset - hash_start;
Willy Tudca92e42023-11-16 23:22:07 -0800411 if (!hash_size)
412 {
413 hash_start += ctx->descriptor.descriptor_area_size;
414 hash_size = (region->region_offset + region->region_size -
415 hash_start);
416 }
Nan Zhou7a337042021-07-26 21:05:21 -0700417 }
Nan Zhou7a337042021-07-26 21:05:21 -0700418
Willy Tudca92e42023-11-16 23:22:07 -0800419 CPRINTS(ctx, "%s: hashing %s (%x - %x)\n", __FUNCTION__,
Patrick Williams60849572023-10-20 11:19:52 -0500420 (const char*)region->region_name, hash_start,
421 hash_start + hash_size);
422 // Read the image_region array.
423 rv = read_and_hash_update(ctx, intf, hash_start, hash_size);
Nan Zhou7a337042021-07-26 21:05:21 -0700424 if (rv != LIBCR51SIGN_SUCCESS)
425 {
426 return rv;
427 }
Patrick Williams60849572023-10-20 11:19:52 -0500428 hash_start += hash_size;
429 } while (hash_start != region->region_offset + region->region_size);
430 }
431 rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
432
433 if (rv != LIBCR51SIGN_SUCCESS)
434 {
435 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
Nan Zhou7a337042021-07-26 21:05:21 -0700436 }
437
Patrick Williams60849572023-10-20 11:19:52 -0500438 if (memcmp(magic_and_digest + MEMBER_SIZE(struct hash_sha256, hash_magic),
Dan Zhang027c0422025-06-01 17:36:41 +0000439 dcrypto_digest, digest_size) != 0)
Nan Zhou7a337042021-07-26 21:05:21 -0700440 {
Willy Tudca92e42023-11-16 23:22:07 -0800441 CPRINTS(ctx, "%s: invalid hash\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500442 return LIBCR51SIGN_ERROR_INVALID_HASH;
443 }
444 // Image is valid.
445 return LIBCR51SIGN_SUCCESS;
446}
Nan Zhou7a337042021-07-26 21:05:21 -0700447
Patrick Williams60849572023-10-20 11:19:52 -0500448// Create empty image_regions to pass to validate_payload_regions
Willy Tudca92e42023-11-16 23:22:07 -0800449// Support validate_payload_regions_helper to remove image_regions as a required
450// input.
Patrick Williams60849572023-10-20 11:19:52 -0500451
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400452static failure_reason allocate_and_validate_payload_regions(
453 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
454 uint32_t d_offset)
Patrick Williams60849572023-10-20 11:19:52 -0500455{
456 struct libcr51sign_validated_regions image_regions;
457 return validate_payload_regions(ctx, intf, d_offset, &image_regions);
458}
459
Willy Tudca92e42023-11-16 23:22:07 -0800460// Wrapper around validate_payload_regions to allow nullptr for image_regions.
461// Calls allocate_and_validate_payload_regions when image_regions is nullptr to
462// create placer holder image_regions.
Patrick Williams60849572023-10-20 11:19:52 -0500463
464static failure_reason validate_payload_regions_helper(
465 const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
466 uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
467{
468 if (image_regions)
469 {
470 return validate_payload_regions(ctx, intf, d_offset, image_regions);
471 }
472
473 return allocate_and_validate_payload_regions(ctx, intf, d_offset);
474}
475
476// Check if the given signature_scheme is supported.
477// Returns nonzero on error, zero on success
478
Patrick Williams6c41aba2025-02-01 08:23:21 -0500479static failure_reason is_signature_scheme_supported(
480 enum signature_scheme scheme)
Patrick Williams60849572023-10-20 11:19:52 -0500481{
482 switch (scheme)
483 {
484 case SIGNATURE_RSA2048_PKCS15:
485 case SIGNATURE_RSA3072_PKCS15:
486 case SIGNATURE_RSA4096_PKCS15:
487 case SIGNATURE_RSA4096_PKCS15_SHA512:
488 return LIBCR51SIGN_SUCCESS;
489 default:
490 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
491 }
492}
493
494// Returns size of signature struct size in |size|
495// Returns nonzero on error, zero on success
496
Patrick Williams6c41aba2025-02-01 08:23:21 -0500497static failure_reason get_signature_struct_size(enum signature_scheme scheme,
498 uint32_t* size)
Patrick Williams60849572023-10-20 11:19:52 -0500499{
500 switch (scheme)
501 {
502 case SIGNATURE_RSA2048_PKCS15:
503 *size = sizeof(struct signature_rsa2048_pkcs15);
504 return LIBCR51SIGN_SUCCESS;
505 case SIGNATURE_RSA3072_PKCS15:
506 *size = sizeof(struct signature_rsa3072_pkcs15);
507 return LIBCR51SIGN_SUCCESS;
508 case SIGNATURE_RSA4096_PKCS15:
509 case SIGNATURE_RSA4096_PKCS15_SHA512:
510 *size = sizeof(struct signature_rsa4096_pkcs15);
511 return LIBCR51SIGN_SUCCESS;
512 default:
513 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
514 }
515}
516
Patrick Williams6c41aba2025-02-01 08:23:21 -0500517static failure_reason get_signature_field_offset(enum signature_scheme scheme,
518 uint32_t* offset)
Patrick Williams60849572023-10-20 11:19:52 -0500519{
520 switch (scheme)
521 {
522 case SIGNATURE_RSA2048_PKCS15:
523 *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
524 return LIBCR51SIGN_SUCCESS;
525 case SIGNATURE_RSA3072_PKCS15:
526 *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
527 return LIBCR51SIGN_SUCCESS;
528 case SIGNATURE_RSA4096_PKCS15:
529 case SIGNATURE_RSA4096_PKCS15_SHA512:
530 *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
531 return LIBCR51SIGN_SUCCESS;
532 default:
533 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
534 }
535}
536
Dan Zhang027c0422025-06-01 17:36:41 +0000537__attribute__((nonnull)) static bool is_key_in_signature_struct_trusted(
538 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
539 enum signature_scheme scheme, uint32_t raw_signature_offset,
540 void* signature_struct, uint32_t* signature_struct_size)
541{
542 if (!intf->trust_key_in_signature_structure)
543 {
544 CPRINTS(ctx, "%s: trust_key_in_signature_structure is not supported\n",
545 __FUNCTION__);
546 return false;
547 }
548
549 uint32_t signature_field_offset;
550 int rv = get_signature_field_offset(scheme, &signature_field_offset);
551 if (rv != LIBCR51SIGN_SUCCESS)
552 {
553 return false;
554 }
555
556 if (signature_field_offset > raw_signature_offset)
557 {
558 CPRINTS(ctx,
559 "%s: signature_field_offset (%d) is larger than "
560 "raw_signature_offset (%d)\n",
561 __FUNCTION__, signature_field_offset, raw_signature_offset);
562 return false;
563 }
564 uint32_t signature_offset = raw_signature_offset - signature_field_offset;
565
566 rv = get_signature_struct_size(scheme, signature_struct_size);
567 if (rv != LIBCR51SIGN_SUCCESS)
568 {
569 return false;
570 }
571
572 rv = intf->read(ctx, signature_offset, *signature_struct_size,
573 signature_struct);
574 if (rv != LIBCR51SIGN_SUCCESS)
575 {
576 CPRINTS(ctx, "%s: failed to read signature (status = %d)\n",
577 __FUNCTION__, rv);
578 return false;
579 }
580
581 return intf->trust_key_in_signature_structure(ctx, scheme, signature_struct,
582 *signature_struct_size);
583}
584// Validates the signature with verification key provided along with the
585// signature if the key is trusted.
586
587static bool validate_signature_with_key_in_signature_struct(
588 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
589 enum signature_scheme scheme, uint32_t raw_signature_offset,
590 const uint8_t* digest, uint32_t digest_size)
591{
592 // pick the biggest signature struct size.
593 uint8_t signature_struct[sizeof(struct signature_rsa4096_pkcs15)];
594 uint32_t signature_struct_size = sizeof(signature_struct);
595 if (!is_key_in_signature_struct_trusted(
596 ctx, intf, scheme, raw_signature_offset, &signature_struct,
597 &signature_struct_size))
598 {
599 CPRINTS(ctx, "%s: key in signature struct is not trusted\n",
600 __FUNCTION__);
601 return false;
602 }
603 if (!intf->verify_rsa_signature_with_modulus_and_exponent)
604 {
605 CPRINTS(
606 ctx,
607 "%s: verify_rsa_signature_with_modulus_and_exponent is not supported\n",
608 __FUNCTION__);
609 return false;
610 }
611
612 switch (scheme)
613 {
614 case SIGNATURE_RSA2048_PKCS15:
615 {
616 struct signature_rsa2048_pkcs15* sig =
617 (struct signature_rsa2048_pkcs15*)signature_struct;
618 return intf->verify_rsa_signature_with_modulus_and_exponent(
619 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
620 sig->signature, sizeof(sig->signature), digest, digest_size);
621 }
622 break;
623 case SIGNATURE_RSA3072_PKCS15:
624 {
625 struct signature_rsa3072_pkcs15* sig =
626 (struct signature_rsa3072_pkcs15*)signature_struct;
627 return intf->verify_rsa_signature_with_modulus_and_exponent(
628 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
629 sig->signature, sizeof(sig->signature), digest, digest_size);
630 }
631 break;
632 case SIGNATURE_RSA4096_PKCS15:
633 case SIGNATURE_RSA4096_PKCS15_SHA512:
634 {
635 struct signature_rsa4096_pkcs15* sig =
636 (struct signature_rsa4096_pkcs15*)signature_struct;
637 return intf->verify_rsa_signature_with_modulus_and_exponent(
638 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
639 sig->signature, sizeof(sig->signature), digest, digest_size);
640 }
641 break;
642 default:
643 CPRINTS(ctx, "%s: unsupported signature scheme %d\n", __FUNCTION__,
644 scheme);
645 return false;
646 }
647}
648
Patrick Williams60849572023-10-20 11:19:52 -0500649// Validates the signature (of type scheme) read from "device" at
650//"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
651// EEPROM area "data_offset:data_size".
652
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400653static failure_reason validate_signature(
654 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
655 uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
656 uint32_t raw_signature_offset)
Patrick Williams60849572023-10-20 11:19:52 -0500657{
658 uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
659 uint16_t key_size;
660 uint32_t digest_size;
661 uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
662 int rv;
663 enum hash_type hash_type;
664
665 if (!intf->hash_init)
666 {
Willy Tudca92e42023-11-16 23:22:07 -0800667 CPRINTS(ctx, "%s: missing hash_init\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500668 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
669 }
670 rv = get_hash_type_from_signature(scheme, &hash_type);
671 if (rv != LIBCR51SIGN_SUCCESS)
672 {
Willy Tudca92e42023-11-16 23:22:07 -0800673 CPRINTS(ctx, "%s: hash_type from signature failed\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500674 return rv;
675 }
676 rv = intf->hash_init(ctx, hash_type);
677 if (rv != LIBCR51SIGN_SUCCESS)
678 {
Willy Tudca92e42023-11-16 23:22:07 -0800679 CPRINTS(ctx, "%s: hash_init failed\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500680 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
681 }
682 rv = read_and_hash_update(ctx, intf, data_offset, data_size);
683 if (rv != LIBCR51SIGN_SUCCESS)
684 {
Willy Tudca92e42023-11-16 23:22:07 -0800685 CPRINTS(ctx, "%s: hash_update failed\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500686 return rv;
687 }
688 if (!intf->hash_final)
689 {
Willy Tudca92e42023-11-16 23:22:07 -0800690 CPRINTS(ctx, "%s: missing hash_final\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500691 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
692 }
693 rv = intf->hash_final((void*)ctx, dcrypto_digest);
694 if (rv != LIBCR51SIGN_SUCCESS)
695 {
Willy Tudca92e42023-11-16 23:22:07 -0800696 CPRINTS(ctx, "%s: hash_final failed (status = %d)\n", __FUNCTION__, rv);
Patrick Williams60849572023-10-20 11:19:52 -0500697 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
698 }
Dan Zhang027c0422025-06-01 17:36:41 +0000699
700 rv = get_hash_digest_size(hash_type, &digest_size);
701 if (rv != LIBCR51SIGN_SUCCESS)
702 {
703 return rv;
704 }
705
706 if (intf->trust_descriptor_hash)
707 {
708 if (intf->trust_descriptor_hash(ctx, dcrypto_digest, digest_size))
709 {
710 CPRINTS(ctx, "%s: descriptor hash trusted\n", __FUNCTION__);
711 return LIBCR51SIGN_SUCCESS;
712 }
713 }
714
Patrick Williams60849572023-10-20 11:19:52 -0500715 rv = get_key_size(scheme, &key_size);
716 if (rv != LIBCR51SIGN_SUCCESS)
717 {
718 return rv;
719 }
720
721 rv = intf->read(ctx, raw_signature_offset, key_size, signature);
722 if (rv != LIBCR51SIGN_SUCCESS)
723 {
Willy Tudca92e42023-11-16 23:22:07 -0800724 CPRINTS(ctx, "%s: failed to read signature (status = %d)\n",
725 __FUNCTION__, rv);
Patrick Williams60849572023-10-20 11:19:52 -0500726 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
727 }
Dan Zhang027c0422025-06-01 17:36:41 +0000728
729 if (validate_signature_with_key_in_signature_struct(
730 ctx, intf, scheme, raw_signature_offset, dcrypto_digest,
731 digest_size))
732 {
733 CPRINTS(ctx, "%s: verification with external key succeeded\n",
734 __FUNCTION__);
735 return LIBCR51SIGN_SUCCESS;
736 }
737
Patrick Williams60849572023-10-20 11:19:52 -0500738 if (!intf->verify_signature)
739 {
Willy Tudca92e42023-11-16 23:22:07 -0800740 CPRINTS(ctx, "%s: missing verify_signature\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500741 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
742 }
Dan Zhang027c0422025-06-01 17:36:41 +0000743
Patrick Williams60849572023-10-20 11:19:52 -0500744 rv = intf->verify_signature(ctx, scheme, signature, key_size,
745 dcrypto_digest, digest_size);
746 if (rv != LIBCR51SIGN_SUCCESS)
747 {
Willy Tudca92e42023-11-16 23:22:07 -0800748 CPRINTS(ctx, "%s: verification failed (status = %d)\n", __FUNCTION__,
Patrick Williams60849572023-10-20 11:19:52 -0500749 rv);
750 return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
751 }
Willy Tudca92e42023-11-16 23:22:07 -0800752 CPRINTS(ctx, "%s: verification succeeded\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500753 return LIBCR51SIGN_SUCCESS;
754}
755
756// Sanity checks the image descriptor & validates its signature.
757// This function does not validate the image_region array or image hash.
758//
759//@param[in] ctx context which describes the image and holds opaque private
760// data for the user of the library
761//@param[in] intf function pointers which interface to the current system
762// and environment
763//@param offset Absolute image descriptor flash offset.
764//@param relative_offset Image descriptor offset relative to image start.
765//@param max_size Maximum size of the flash space in bytes.
Willy Tudca92e42023-11-16 23:22:07 -0800766//@param[out] payload_blob_offset Absolute offset of BLOB data in image
767// descriptor (if BLOB data is present)
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400768static failure_reason validate_descriptor(
769 const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
770 uint32_t offset, uint32_t relative_offset, uint32_t max_size,
771 uint32_t* const restrict payload_blob_offset)
Patrick Williams60849572023-10-20 11:19:52 -0500772{
773 uint32_t max_descriptor_size, signed_size, signature_scheme,
774 signature_offset;
775 uint32_t signature_struct_offset, signature_struct_size, hash_struct_size;
776 int rv;
777
778 max_descriptor_size = max_size - relative_offset;
779 if (max_size < relative_offset ||
780 max_descriptor_size < sizeof(struct image_descriptor))
781 {
Willy Tudca92e42023-11-16 23:22:07 -0800782 CPRINTS(ctx, "%s: invalid arguments\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500783 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
784 }
785
786 rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
787 (uint8_t*)&ctx->descriptor);
788 if (rv != LIBCR51SIGN_SUCCESS)
789 {
Willy Tudca92e42023-11-16 23:22:07 -0800790 CPRINTS(ctx, "%s: failed to read descriptor\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500791 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
792 }
793 if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
794 ctx->descriptor.descriptor_offset != relative_offset ||
795 ctx->descriptor.region_count == 0 ||
796 ctx->descriptor.descriptor_area_size > max_descriptor_size ||
797 ctx->descriptor.image_size > max_size)
798 {
Willy Tudca92e42023-11-16 23:22:07 -0800799 CPRINTS(ctx, "%s: invalid descriptor\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500800 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
801 }
802 if (intf->image_size_valid == NULL)
803 {
Willy Tudca92e42023-11-16 23:22:07 -0800804 // Preserve original behavior of requiring exact image_size match if no
805 // operator is provided.
Patrick Williams60849572023-10-20 11:19:52 -0500806 if (ctx->descriptor.image_size != max_size)
Nan Zhou7a337042021-07-26 21:05:21 -0700807 {
Willy Tudca92e42023-11-16 23:22:07 -0800808 CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500809 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
Nan Zhou7a337042021-07-26 21:05:21 -0700810 }
Patrick Williams60849572023-10-20 11:19:52 -0500811 }
812 else if (!intf->image_size_valid(ctx->descriptor.image_size))
813 {
Willy Tudca92e42023-11-16 23:22:07 -0800814 CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500815 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
816 }
817 if (ctx->descriptor.image_type != IMAGE_DEV &&
818 ctx->descriptor.image_type != IMAGE_PROD &&
819 ctx->descriptor.image_type != IMAGE_BREAKOUT &&
820 ctx->descriptor.image_type != IMAGE_TEST &&
821 ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
822 {
Willy Tudca92e42023-11-16 23:22:07 -0800823 CPRINTS(ctx, "%s: bad image type\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500824 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
825 }
826 // Although the image_descriptor struct supports unauthenticated
827 // images, Haven will not allow it.
828 // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
829
830 signature_scheme = ctx->descriptor.signature_scheme;
831
832 rv = is_signature_scheme_supported(signature_scheme);
833 if (rv != LIBCR51SIGN_SUCCESS)
834 {
835 return rv;
836 }
837 rv = is_hash_type_supported(ctx->descriptor.hash_type);
838 if (rv != LIBCR51SIGN_SUCCESS)
839 {
Willy Tudca92e42023-11-16 23:22:07 -0800840 CPRINTS(ctx, "%s: invalid hash type\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500841 return rv;
842 }
843 if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
844 ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
845 {
Willy Tudca92e42023-11-16 23:22:07 -0800846 CPRINTS(ctx, "%s: unsupported descriptor\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500847 return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
848 }
849 rv = get_signature_struct_size(signature_scheme, &signature_struct_size);
850 if (rv != LIBCR51SIGN_SUCCESS)
851 {
852 return rv;
853 }
854
855 // Compute the size of the signed portion of the image descriptor.
856 signed_size = sizeof(struct image_descriptor) +
857 ctx->descriptor.region_count * sizeof(struct image_region);
858 rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
859 if (rv != LIBCR51SIGN_SUCCESS)
860 {
861 return rv;
862 }
863 signed_size += hash_struct_size;
864 if (ctx->descriptor.denylist_size)
865 {
866 signed_size += sizeof(struct denylist);
867 signed_size += ctx->descriptor.denylist_size *
868 sizeof(struct denylist_record);
869 }
870 if (ctx->descriptor.blob_size)
871 {
Willy Tudca92e42023-11-16 23:22:07 -0800872 *payload_blob_offset = offset + signed_size;
Patrick Williams60849572023-10-20 11:19:52 -0500873 signed_size += sizeof(struct blob);
874 // Previous additions are guaranteed not to overflow.
Willy Tudca92e42023-11-16 23:22:07 -0800875 if ((ctx->descriptor.blob_size >
876 ctx->descriptor.descriptor_area_size - signed_size) ||
877 // Sanity check blob size
878 (ctx->descriptor.blob_size < sizeof(struct blob_data)))
Nan Zhou7a337042021-07-26 21:05:21 -0700879 {
Willy Tudca92e42023-11-16 23:22:07 -0800880 CPRINTS(ctx, "%s: invalid blob size (0x%x)\n", __FUNCTION__,
Patrick Williams60849572023-10-20 11:19:52 -0500881 ctx->descriptor.blob_size);
882 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
Nan Zhou7a337042021-07-26 21:05:21 -0700883 }
Patrick Williams60849572023-10-20 11:19:52 -0500884 signed_size += ctx->descriptor.blob_size;
885 }
886 if (signature_struct_size >
887 ctx->descriptor.descriptor_area_size - signed_size)
888 {
889 CPRINTS(ctx,
Willy Tudca92e42023-11-16 23:22:07 -0800890 "%s: invalid descriptor area size "
Patrick Williams60849572023-10-20 11:19:52 -0500891 "(expected = 0x%x, actual = 0x%x)\n",
Willy Tudca92e42023-11-16 23:22:07 -0800892 __FUNCTION__, ctx->descriptor.descriptor_area_size,
Patrick Williams60849572023-10-20 11:19:52 -0500893 signed_size + signature_struct_size);
894 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
895 }
896 signature_struct_offset = signed_size;
897 // Omit the actual signature.
898 rv = get_signature_field_offset(signature_scheme, &signature_offset);
899 if (rv != LIBCR51SIGN_SUCCESS)
900 {
901 return rv;
902 }
903 signed_size += signature_offset;
Nan Zhou7a337042021-07-26 21:05:21 -0700904
Patrick Williams60849572023-10-20 11:19:52 -0500905 // Lookup key & validate transition.
906 rv = validate_transition(ctx, intf, offset + signature_struct_offset);
907
908 if (rv != LIBCR51SIGN_SUCCESS)
909 {
910 return rv;
911 }
912 return validate_signature(ctx, intf, offset, signed_size, signature_scheme,
913 offset + signed_size);
914}
915
916// Scans the external EEPROM for a magic value at "alignment" boundaries.
917//
918//@param device Handle to the external EEPROM.
919//@param magic 8-byte pattern to search for.
920//@param start_offset Offset to begin searching at.
921//@param limit Exclusive address (e.g. EEPROM size).
922//@param alignment Alignment boundaries (POW2) to search on.
923//@param header_offset Location to place the new header offset.
924//@return LIBCR51SIGN_SUCCESS (or non-zero on error).
925
Dan Zhang027c0422025-06-01 17:36:41 +0000926static int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
927 const struct libcr51sign_intf* intf, uint64_t magic,
928 uint32_t start_offset, uint32_t limit,
929 uint32_t alignment, uint32_t* header_offset)
Patrick Williams60849572023-10-20 11:19:52 -0500930{
931 uint64_t read_data;
932 uint32_t offset;
933 int rv;
934
935 if (limit <= start_offset || limit > ctx->end_offset ||
936 limit < sizeof(magic) || !POWER_OF_TWO(alignment))
937 {
938 return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
939 }
940
941 if (!intf->read)
942 {
Willy Tudca92e42023-11-16 23:22:07 -0800943 CPRINTS(ctx, "%s: missing intf->read\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500944 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
945 }
946 // Align start_offset to the next valid boundary.
947 start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
948 for (offset = start_offset; offset < limit - sizeof(magic);
949 offset += alignment)
950 {
951 rv = intf->read((void*)ctx, offset, sizeof(read_data),
952 (uint8_t*)&read_data);
953 if (rv != LIBCR51SIGN_SUCCESS)
Nan Zhou7a337042021-07-26 21:05:21 -0700954 {
Patrick Williams60849572023-10-20 11:19:52 -0500955 return rv;
956 }
957 if (read_data == magic)
958 {
959 if (header_offset)
Nan Zhou7a337042021-07-26 21:05:21 -0700960 {
Patrick Williams60849572023-10-20 11:19:52 -0500961 *header_offset = offset;
Nan Zhou7a337042021-07-26 21:05:21 -0700962 }
Patrick Williams60849572023-10-20 11:19:52 -0500963 return LIBCR51SIGN_SUCCESS;
964 }
965 }
966 // Failed to locate magic.
967 return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
968}
Nan Zhou7a337042021-07-26 21:05:21 -0700969
Patrick Williams60849572023-10-20 11:19:52 -0500970// Check whether the signature on the image is valid.
971// Validates the authenticity of an EEPROM image. Scans for & validates the
Willy Tudca92e42023-11-16 23:22:07 -0800972// signature on the image descriptor. If the descriptor validates, hashes the
973// rest of the image to verify its integrity.
Patrick Williams60849572023-10-20 11:19:52 -0500974//
Willy Tudca92e42023-11-16 23:22:07 -0800975// @param[in] ctx - context which describes the image and holds opaque private
Patrick Williams60849572023-10-20 11:19:52 -0500976// data for the user of the library
977// @param[in] intf - function pointers which interface to the current system
978// and environment
Willy Tudca92e42023-11-16 23:22:07 -0800979// @param[out] image_regions - image_region pointer to an array for the output
980//
Patrick Williams60849572023-10-20 11:19:52 -0500981// @return nonzero on error, zero on success
982
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400983failure_reason libcr51sign_validate(
Dan Zhang027c0422025-06-01 17:36:41 +0000984 struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
Patrick Williamsc66ebc32024-08-16 15:21:56 -0400985 struct libcr51sign_validated_regions* image_regions)
Patrick Williams60849572023-10-20 11:19:52 -0500986{
Patrick Williams60849572023-10-20 11:19:52 -0500987 int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
988 uint32_t descriptor_offset;
Willy Tudca92e42023-11-16 23:22:07 -0800989 uint32_t payload_blob_offset = 0;
Patrick Williams60849572023-10-20 11:19:52 -0500990
991 if (!ctx)
992 {
Willy Tudca92e42023-11-16 23:22:07 -0800993 CPRINTS(ctx, "%s: Missing context\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500994 return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
995 }
Dan Zhang027c0422025-06-01 17:36:41 +0000996 if (!intf)
Patrick Williams60849572023-10-20 11:19:52 -0500997 {
Willy Tudca92e42023-11-16 23:22:07 -0800998 CPRINTS(ctx, "%s: Missing interface\n", __FUNCTION__);
Patrick Williams60849572023-10-20 11:19:52 -0500999 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
1000 }
1001
Dan Zhang027c0422025-06-01 17:36:41 +00001002 ctx->validation_state = LIBCR51SIGN_IMAGE_INVALID;
1003
Patrick Williams60849572023-10-20 11:19:52 -05001004 rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
1005 ctx->end_offset, DESCRIPTOR_ALIGNMENT,
1006 &descriptor_offset);
1007 while (rv == LIBCR51SIGN_SUCCESS)
1008 {
Willy Tudca92e42023-11-16 23:22:07 -08001009 CPRINTS(ctx, "%s: potential image descriptor found @%x\n", __FUNCTION__,
Patrick Williams60849572023-10-20 11:19:52 -05001010 descriptor_offset);
Willy Tudca92e42023-11-16 23:22:07 -08001011 // Validation is split into 3 functions to minimize stack usage.
Patrick Williams60849572023-10-20 11:19:52 -05001012
Willy Tudca92e42023-11-16 23:22:07 -08001013 rv = validate_descriptor(
1014 ctx, intf, descriptor_offset, descriptor_offset - ctx->start_offset,
1015 ctx->end_offset - ctx->start_offset, &payload_blob_offset);
Patrick Williams60849572023-10-20 11:19:52 -05001016 if (rv != LIBCR51SIGN_SUCCESS)
1017 {
Willy Tudca92e42023-11-16 23:22:07 -08001018 CPRINTS(ctx, "%s: validate_descriptor() failed ec%d\n",
1019 __FUNCTION__, rv);
Patrick Williams60849572023-10-20 11:19:52 -05001020 }
Willy Tudca92e42023-11-16 23:22:07 -08001021 else
Patrick Williams60849572023-10-20 11:19:52 -05001022 {
1023 rv = validate_payload_regions_helper(ctx, intf, descriptor_offset,
1024 image_regions);
Willy Tudca92e42023-11-16 23:22:07 -08001025 if (rv != LIBCR51SIGN_SUCCESS)
Nan Zhou7a337042021-07-26 21:05:21 -07001026 {
Willy Tudca92e42023-11-16 23:22:07 -08001027 CPRINTS(ctx, "%s: validate_payload_regions() failed ec%d\n",
1028 __FUNCTION__, rv);
1029 }
1030 else if (ctx->descriptor.image_type == IMAGE_PROD)
1031 {
Dan Zhang027c0422025-06-01 17:36:41 +00001032 ctx->validation_state = LIBCR51SIGN_IMAGE_VALID;
Willy Tudca92e42023-11-16 23:22:07 -08001033 // Lookup and validate payload Image MAUV against Image MAUV
1034 // stored in the system after checking signature to ensure
1035 // offsets and sizes are not tampered with. Also, do this after
1036 // hash calculation for payload regions to ensure that stored
1037 // Image MAUV is updated (if necessary) as close to the end of
1038 // payload validation as possible
1039 rv = validate_payload_image_mauv(ctx, intf, payload_blob_offset,
1040 ctx->descriptor.blob_size);
1041 if (rv == LIBCR51SIGN_SUCCESS)
1042 {
1043 CPRINTS(ctx,
1044 "%s: Payload Image MAUV validation successful\n",
1045 __FUNCTION__);
1046 return rv;
1047 }
1048 if (rv == LIBCR51SIGN_ERROR_STORING_NEW_IMAGE_MAUV_DATA)
1049 {
1050 CPRINTS(
1051 ctx,
1052 "%s: Payload validation succeeded, but Image MAUV validation "
1053 "failed\n",
1054 __FUNCTION__);
1055 return LIBCR51SIGN_ERROR_VALID_IMAGE_BUT_NEW_IMAGE_MAUV_DATA_NOT_STORED;
1056 }
1057 CPRINTS(ctx, "%s: Payload Image MAUV validation failed\n",
1058 __FUNCTION__);
1059 // In practice, we expect only 1 valid image descriptor in
1060 // payload. If Image MAUV check fails for the payload after
1061 // validating the image descriptor, do not try validating other
1062 // image descriptors
Patrick Williams60849572023-10-20 11:19:52 -05001063 return rv;
Nan Zhou7a337042021-07-26 21:05:21 -07001064 }
Willy Tudca92e42023-11-16 23:22:07 -08001065 else
1066 {
Dan Zhang027c0422025-06-01 17:36:41 +00001067 ctx->validation_state = LIBCR51SIGN_IMAGE_VALID;
Willy Tudca92e42023-11-16 23:22:07 -08001068 return rv;
1069 }
Nan Zhou7a337042021-07-26 21:05:21 -07001070 }
Willy Tudca92e42023-11-16 23:22:07 -08001071
Patrick Williams60849572023-10-20 11:19:52 -05001072 // Store the first desc fail reason if any
1073 if (rv != LIBCR51SIGN_SUCCESS && rv_first_desc == LIBCR51SIGN_SUCCESS)
1074 rv_first_desc = rv;
1075
1076 // scan_for_magic_8() will round up to the next aligned boundary.
1077 descriptor_offset++;
Patrick Williams60849572023-10-20 11:19:52 -05001078 rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, descriptor_offset,
Willy Tudca92e42023-11-16 23:22:07 -08001079 ctx->end_offset, DESCRIPTOR_ALIGNMENT,
Patrick Williams60849572023-10-20 11:19:52 -05001080 &descriptor_offset);
Nan Zhou7a337042021-07-26 21:05:21 -07001081 }
Willy Tudca92e42023-11-16 23:22:07 -08001082 CPRINTS(ctx, "%s: failed to validate image ec%d\n", __FUNCTION__, rv);
Patrick Williams60849572023-10-20 11:19:52 -05001083 // If desc validation failed for some reason then return that reason
1084 if (rv_first_desc != LIBCR51SIGN_SUCCESS)
1085 return rv_first_desc;
Dan Zhang027c0422025-06-01 17:36:41 +00001086
1087 return rv;
Patrick Williams60849572023-10-20 11:19:52 -05001088}
Nan Zhou7a337042021-07-26 21:05:21 -07001089
Patrick Williams60849572023-10-20 11:19:52 -05001090// @func to returns the libcr51sign error code as a string
1091// @param[in] ec - Error code
1092// @return error code in string format
Nan Zhou7a337042021-07-26 21:05:21 -07001093
Patrick Williams60849572023-10-20 11:19:52 -05001094const char* libcr51sign_errorcode_to_string(failure_reason ec)
1095{
1096 switch (ec)
Nan Zhou7a337042021-07-26 21:05:21 -07001097 {
Patrick Williams60849572023-10-20 11:19:52 -05001098 case LIBCR51SIGN_SUCCESS:
1099 return "Success";
1100 case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
1101 return "Runtime Error Failure";
1102 case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
1103 return "Unsupported descriptor";
1104 case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
1105 return "Invalid descriptor";
1106 case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
1107 return "Invalid image family";
1108 case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
1109 return "Image type disallowed";
1110 case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
1111 return "Dev downgrade disallowed";
1112 case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
1113 return "Untrusted key";
1114 case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
1115 return "Invalid signature";
1116 case LIBCR51SIGN_ERROR_INVALID_HASH:
1117 return "Invalid hash";
1118 case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
1119 return "Invalid hash type";
1120 case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
1121 return "Invalid Argument";
1122 case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
1123 return "Failed to locate descriptor";
1124 case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
1125 return "Invalid context";
1126 case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
1127 return "Invalid interface";
1128 case LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME:
1129 return "Invalid signature scheme";
1130 case LIBCR51SIGN_ERROR_INVALID_REGION_INPUT:
1131 return "Invalid image region input";
1132 case LIBCR51SIGN_ERROR_INVALID_REGION_SIZE:
1133 return "Invalid image region size";
Willy Tudca92e42023-11-16 23:22:07 -08001134 case LIBCR51SIGN_ERROR_INVALID_IMAGE_MAUV_DATA:
1135 return "Invalid Image MAUV data";
1136 case LIBCR51SIGN_ERROR_RETRIEVING_STORED_IMAGE_MAUV_DATA:
1137 return "Failed to retrieve Image MAUV data stored in system";
1138 case LIBCR51SIGN_ERROR_STORING_NEW_IMAGE_MAUV_DATA:
1139 return "Failed to store Image MAUV data from payload image into system";
1140 case LIBCR51SIGN_ERROR_STORED_IMAGE_MAUV_DOES_NOT_ALLOW_UPDATE_TO_PAYLOAD:
1141 return "Image MAUV stored in system does not allow payload "
1142 "update";
1143 case LIBCR51SIGN_ERROR_VALID_IMAGE_BUT_NEW_IMAGE_MAUV_DATA_NOT_STORED:
1144 return "Payload image is valid for update but failed to store new Image "
1145 "MAUV in system";
1146 case LIBCR51SIGN_ERROR_STORED_IMAGE_MAUV_EXPECTS_PAYLOAD_IMAGE_MAUV:
1147 return "Image MAUV is expected to be present in payload when stored "
1148 "Image MAUV is present in the system";
1149 case LIBCR51SIGN_NO_STORED_MAUV_FOUND:
1150 return "Client did not find any MAUV data stored in the system";
Dan Zhang027c0422025-06-01 17:36:41 +00001151 case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR_BLOBS:
1152 return "Invalid descriptor blobs";
Patrick Williams60849572023-10-20 11:19:52 -05001153 default:
1154 return "Unknown error";
Nan Zhou7a337042021-07-26 21:05:21 -07001155 }
Patrick Williams60849572023-10-20 11:19:52 -05001156}
Nan Zhou7a337042021-07-26 21:05:21 -07001157
1158#ifdef __cplusplus
1159} // extern "C"
1160#endif