xref: /openbmc/google-misc/subprojects/libcr51sign/src/libcr51sign.c (revision 12e6ad0db531bbdc0b134742798842a25cc929aa)
1 /*
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  */
16 #include <assert.h>
17 #include <libcr51sign/libcr51sign.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 #ifdef __cplusplus
23 extern "C"
24 {
25 #endif
26 
27 #ifndef USER_PRINT
28 #define CPRINTS(ctx, ...) fprintf(stderr, __VA_ARGS__)
29 #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 
39 // 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:
125                 *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
126                 return LIBCR51SIGN_SUCCESS;
127             case HASH_SHA2_512:
128                 *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
129                 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.
183         enum
184         {
185             read_len = SIGNATURE_OFFSET
186         };
187         uint8_t buffer[read_len];
188         int rv;
189         rv = intf->read(ctx, signature_struct_offset, read_len, buffer);
190         if (rv != LIBCR51SIGN_SUCCESS)
191         {
192             CPRINTS(ctx,
193                     "validate_transition: failed to read signature struct");
194             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
195         }
196         if (*(uint32_t*)buffer != SIGNATURE_MAGIC)
197         {
198             CPRINTS(ctx, "validate_transition: bad signature magic");
199             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
200         }
201 
202         if (ctx->descriptor.image_family != ctx->current_image_family &&
203             ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
204             ctx->current_image_family != IMAGE_FAMILY_ALL)
205         {
206             CPRINTS(ctx, "validate_transition: invalid image family");
207             return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
208         }
209 
210         if (intf->is_production_mode == NULL)
211         {
212             CPRINTS(ctx, "validate_transition: missing is_production_mode");
213             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
214         }
215         if (intf->is_production_mode() &&
216             (ctx->descriptor.image_type == IMAGE_DEV))
217         {
218             CPRINTS(ctx, "validate_transition: checking exemption allowlist");
219 
220             // If function is NULL or if the function call return false, return
221             // error
222             if (intf->prod_to_dev_downgrade_allowed == NULL ||
223                 !intf->prod_to_dev_downgrade_allowed())
224             {
225                 CPRINTS(ctx, "validate_transition: illegal image type");
226                 return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
227             }
228         }
229         return LIBCR51SIGN_SUCCESS;
230     }
231 
232     // If caller had provided read_and_hash_update call that, otherwise call
233     // read and then update.
234 
235     static failure_reason
236         read_and_hash_update(const struct libcr51sign_ctx* ctx,
237                              const struct libcr51sign_intf* intf,
238                              uint32_t offset, uint32_t size)
239     {
240         uint8_t read_buffer[MAX_READ_SIZE];
241         int rv;
242         int read_size;
243 
244         if (intf->read_and_hash_update)
245         {
246             rv = intf->read_and_hash_update((void*)ctx, offset, size);
247         }
248         else
249         {
250             if (!intf->hash_update)
251             {
252                 CPRINTS(ctx, "read_and_hash_update: missing hash_update");
253                 return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
254             }
255             do
256             {
257                 read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
258                 rv = intf->read((void*)ctx, offset, read_size, read_buffer);
259                 if (rv != LIBCR51SIGN_SUCCESS)
260                 {
261                     return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
262                 }
263                 rv = intf->hash_update((void*)ctx, read_buffer, read_size);
264                 if (rv != LIBCR51SIGN_SUCCESS)
265                 {
266                     return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
267                 }
268                 offset += read_size;
269                 size -= read_size;
270             } while (size > 0);
271         }
272         return rv;
273     }
274 
275     // Validates the image_region array, namely that:
276     //  - The regions are aligned, contiguous & exhaustive
277     //  - That the image descriptor resides in a static region
278     //
279     // If the array is consistent, proceeds to hash the static regions and
280     // validates the hash. d_offset is the absolute image descriptor offset
281 
282     static failure_reason validate_payload_regions(
283         const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
284         uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
285     {
286         // Allocate buffer to accomodate largest supported hash-type(SHA512)
287         uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
288                                  LIBCR51SIGN_SHA512_DIGEST_SIZE];
289         uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
290         uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
291         uint32_t i;
292         uint8_t d_region_num = 0;
293         int rv;
294         struct image_region const* region;
295 
296         if (image_regions == NULL)
297         {
298             CPRINTS(ctx, "Missing image region input");
299             return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
300         }
301 
302         BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
303                       MEMBER_SIZE(struct hash_sha512, hash_magic)));
304         image_size = ctx->descriptor.image_size;
305         region_count = ctx->descriptor.region_count;
306         hash_offset = d_offset + sizeof(struct image_descriptor) +
307                       region_count * sizeof(struct image_region);
308         // Read the image_region array.
309 
310         if (region_count > ARRAY_SIZE(image_regions->image_regions))
311         {
312             CPRINTS(ctx, "validate_payload_regions: "
313                          "ctx->descriptor.region_count is greater "
314                          "than LIBCR51SIGN_MAX_REGION_COUNT");
315             return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
316         }
317 
318         rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
319                         region_count * sizeof(struct image_region),
320                         (uint8_t*)&image_regions->image_regions);
321 
322         image_regions->region_count = region_count;
323 
324         if (rv != LIBCR51SIGN_SUCCESS)
325         {
326             CPRINTS(ctx,
327                     "validate_payload_regions: failed to read region array");
328             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
329         }
330 
331         // Validate that the regions are contiguous & exhaustive.
332         for (i = 0, byte_count = 0; i < region_count; i++)
333         {
334             region = image_regions->image_regions + i;
335 
336             CPRINTS(ctx,
337                     "validate_payload_regions: region #%d \"%s\" (%x - %x)", i,
338                     (const char*)region->region_name, region->region_offset,
339                     region->region_offset + region->region_size);
340             if ((region->region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
341                 (region->region_size % IMAGE_REGION_ALIGNMENT) != 0)
342             {
343                 CPRINTS(
344                     ctx,
345                     "validate_payload_regions: regions must be sector aligned");
346                 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
347             }
348             if (region->region_offset != byte_count ||
349                 region->region_size > image_size - byte_count)
350             {
351                 CPRINTS(ctx, "validate_payload_regions: invalid region array");
352                 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
353             }
354             byte_count += region->region_size;
355             // The image descriptor must be part of a static region.
356             if (d_offset >= region->region_offset && d_offset < byte_count)
357             {
358                 d_region_num = i;
359                 CPRINTS(
360                     ctx,
361                     "validate_payload_regions: image descriptor in region %d",
362                     i);
363                 // The descriptor can't span regions.
364                 if (ctx->descriptor.descriptor_area_size > byte_count ||
365                     !(region->region_attributes & IMAGE_REGION_STATIC))
366                 {
367                     CPRINTS(
368                         ctx,
369                         "validate_payload_regions: descriptor must reside in "
370                         "static region");
371                     return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
372                 }
373             }
374         }
375         if (byte_count != image_size)
376         {
377             CPRINTS(ctx, "validate_payload_regions: invalid image size");
378             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
379         }
380 
381         rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
382         if (rv != LIBCR51SIGN_SUCCESS)
383         {
384             return rv;
385         }
386 
387         rv = intf->read(ctx, hash_offset,
388                         MEMBER_SIZE(struct hash_sha256, hash_magic) +
389                             digest_size,
390                         magic_and_digest);
391         if (rv != LIBCR51SIGN_SUCCESS)
392         {
393             CPRINTS(ctx,
394                     "validate_payload_regions: failed to read hash from flash");
395             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
396         }
397         if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
398         {
399             CPRINTS(ctx, "validate_payload_regions: bad hash magic");
400             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
401         }
402         rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
403         if (rv != LIBCR51SIGN_SUCCESS)
404         {
405             CPRINTS(ctx, "validate_payload_regions: hash_init failed");
406             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
407         }
408         for (i = 0; i < region_count; i++)
409         {
410             uint32_t hash_start, hash_size;
411             region = image_regions->image_regions + i;
412 
413             if (!(region->region_attributes & IMAGE_REGION_STATIC))
414             {
415                 continue;
416             }
417             hash_start = region->region_offset;
418             hash_size = region->region_size;
419 
420             // Skip the descriptor.
421             do
422             {
423                 if (i == d_region_num)
424                 {
425                     hash_size = d_offset - hash_start;
426                 }
427 
428                 if (!hash_size)
429                 {
430                     hash_start += ctx->descriptor.descriptor_area_size;
431                     hash_size = (region->region_offset + region->region_size -
432                                  hash_start);
433                 }
434                 CPRINTS("validate_payload_regions: hashing %s (%x - %x)",
435                         (const char*)region->region_name, hash_start,
436                         hash_start + hash_size);
437                 // Read the image_region array.
438                 rv = read_and_hash_update(ctx, intf, hash_start, hash_size);
439                 if (rv != LIBCR51SIGN_SUCCESS)
440                 {
441                     return rv;
442                 }
443                 hash_start += hash_size;
444             } while (hash_start != region->region_offset + region->region_size);
445         }
446         rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
447 
448         if (rv != LIBCR51SIGN_SUCCESS)
449         {
450             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
451         }
452 
453         if (memcmp(magic_and_digest +
454                        MEMBER_SIZE(struct hash_sha256, hash_magic),
455                    dcrypto_digest, digest_size))
456         {
457             CPRINTS(ctx, "validate_payload_regions: invalid hash");
458             return LIBCR51SIGN_ERROR_INVALID_HASH;
459         }
460         // Image is valid.
461         return LIBCR51SIGN_SUCCESS;
462     }
463 
464     // Create empty image_regions to pass to validate_payload_regions
465     // Support validate_payload_regions_helper to remove image_regions as a
466     // required input.
467 
468     static failure_reason
469         allocate_and_validate_payload_regions(const struct libcr51sign_ctx* ctx,
470                                               struct libcr51sign_intf* intf,
471                                               uint32_t d_offset)
472     {
473         struct libcr51sign_validated_regions image_regions;
474         return validate_payload_regions(ctx, intf, d_offset, &image_regions);
475     }
476 
477     // Wrapper around validate_payload_regions to allow nullptr for
478     // image_regions. Calls allocate_and_validate_payload_regions when
479     // image_regions is nullptr to create placer holder image_regions.
480 
481     static failure_reason validate_payload_regions_helper(
482         const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
483         uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
484     {
485         if (image_regions)
486         {
487             return validate_payload_regions(ctx, intf, d_offset, image_regions);
488         }
489 
490         return allocate_and_validate_payload_regions(ctx, intf, d_offset);
491     }
492 
493     // Check if the given signature_scheme is supported.
494     // Returns nonzero on error, zero on success
495 
496     static failure_reason
497         is_signature_scheme_supported(enum signature_scheme scheme)
498     {
499         switch (scheme)
500         {
501             case SIGNATURE_RSA2048_PKCS15:
502             case SIGNATURE_RSA3072_PKCS15:
503             case SIGNATURE_RSA4096_PKCS15:
504             case SIGNATURE_RSA4096_PKCS15_SHA512:
505                 return LIBCR51SIGN_SUCCESS;
506             default:
507                 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
508         }
509     }
510 
511     // Returns size of signature struct size in |size|
512     // Returns nonzero on error, zero on success
513 
514     static failure_reason
515         get_signature_struct_size(enum signature_scheme scheme, uint32_t* size)
516     {
517         switch (scheme)
518         {
519             case SIGNATURE_RSA2048_PKCS15:
520                 *size = sizeof(struct signature_rsa2048_pkcs15);
521                 return LIBCR51SIGN_SUCCESS;
522             case SIGNATURE_RSA3072_PKCS15:
523                 *size = sizeof(struct signature_rsa3072_pkcs15);
524                 return LIBCR51SIGN_SUCCESS;
525             case SIGNATURE_RSA4096_PKCS15:
526             case SIGNATURE_RSA4096_PKCS15_SHA512:
527                 *size = sizeof(struct signature_rsa4096_pkcs15);
528                 return LIBCR51SIGN_SUCCESS;
529             default:
530                 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
531         }
532     }
533 
534     static failure_reason
535         get_signature_field_offset(enum signature_scheme scheme,
536                                    uint32_t* offset)
537     {
538         switch (scheme)
539         {
540             case SIGNATURE_RSA2048_PKCS15:
541                 *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
542                 return LIBCR51SIGN_SUCCESS;
543             case SIGNATURE_RSA3072_PKCS15:
544                 *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
545                 return LIBCR51SIGN_SUCCESS;
546             case SIGNATURE_RSA4096_PKCS15:
547             case SIGNATURE_RSA4096_PKCS15_SHA512:
548                 *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
549                 return LIBCR51SIGN_SUCCESS;
550             default:
551                 return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
552         }
553     }
554 
555     // Validates the signature (of type scheme) read from "device" at
556     //"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
557     // EEPROM area "data_offset:data_size".
558 
559     static failure_reason validate_signature(
560         const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
561         uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
562         uint32_t raw_signature_offset)
563     {
564         uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
565         uint16_t key_size;
566         uint32_t digest_size;
567         uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
568         int rv;
569         enum hash_type hash_type;
570 
571         if (!intf->hash_init)
572         {
573             CPRINTS(ctx, "validate_signature: missing hash_init");
574             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
575         }
576         rv = get_hash_type_from_signature(scheme, &hash_type);
577         if (rv != LIBCR51SIGN_SUCCESS)
578         {
579             CPRINTS(
580                 ctx,
581                 "validate_payload_regions: hash_type from signature failed");
582             return rv;
583         }
584         rv = intf->hash_init(ctx, hash_type);
585         if (rv != LIBCR51SIGN_SUCCESS)
586         {
587             CPRINTS(ctx, "validate_payload_regions: hash_init failed");
588             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
589         }
590         rv = read_and_hash_update(ctx, intf, data_offset, data_size);
591         if (rv != LIBCR51SIGN_SUCCESS)
592         {
593             CPRINTS(ctx, "validate_signature: hash_update failed");
594             return rv;
595         }
596         if (!intf->hash_final)
597         {
598             CPRINTS(ctx, "validate_signature: missing hash_final");
599             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
600         }
601         rv = intf->hash_final((void*)ctx, dcrypto_digest);
602         if (rv != LIBCR51SIGN_SUCCESS)
603         {
604             CPRINTS(ctx, "validate_signature: hash_final failed (status = %d)",
605                     rv);
606             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
607         }
608         rv = get_key_size(scheme, &key_size);
609         if (rv != LIBCR51SIGN_SUCCESS)
610         {
611             return rv;
612         }
613 
614         rv = intf->read(ctx, raw_signature_offset, key_size, signature);
615         if (rv != LIBCR51SIGN_SUCCESS)
616         {
617             CPRINTS(
618                 ctx,
619                 "validate_signature: failed to read signature (status = %d)",
620                 rv);
621             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
622         }
623         if (!intf->verify_signature)
624         {
625             CPRINTS(ctx, "validate_signature: missing verify_signature");
626             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
627         }
628         rv = get_hash_digest_size(hash_type, &digest_size);
629         if (rv != LIBCR51SIGN_SUCCESS)
630         {
631             return rv;
632         }
633         rv = intf->verify_signature(ctx, scheme, signature, key_size,
634                                     dcrypto_digest, digest_size);
635         if (rv != LIBCR51SIGN_SUCCESS)
636         {
637             CPRINTS(ctx,
638                     "validate_signature: verification failed (status = %d)",
639                     rv);
640             return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
641         }
642         CPRINTS(ctx, "validate_signature: verification succeeded");
643         return LIBCR51SIGN_SUCCESS;
644     }
645 
646     // Sanity checks the image descriptor & validates its signature.
647     // This function does not validate the image_region array or image hash.
648     //
649     //@param[in] ctx  context which describes the image and holds opaque private
650     //                 data for the user of the library
651     //@param[in] intf  function pointers which interface to the current system
652     // and environment
653     //@param offset  Absolute image descriptor flash offset.
654     //@param relative_offset  Image descriptor offset relative to image start.
655     //@param image_size  Image size in bytes.
656     //@param descriptor  Output pointer to an image_descriptor struct
657 
658     static failure_reason validate_descriptor(
659         const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
660         uint32_t offset, uint32_t relative_offset, uint32_t image_size)
661     {
662         uint32_t max_descriptor_size, signed_size, signature_scheme,
663             signature_offset;
664         uint32_t signature_struct_offset, signature_struct_size,
665             hash_struct_size;
666         int rv;
667 
668         max_descriptor_size = image_size - relative_offset;
669         if (image_size < relative_offset ||
670             max_descriptor_size < sizeof(struct image_descriptor))
671         {
672             CPRINTS(ctx, "validate_descriptor: invalid arguments");
673             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
674         }
675 
676         rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
677                         (uint8_t*)&ctx->descriptor);
678         if (rv != LIBCR51SIGN_SUCCESS)
679         {
680             CPRINTS(ctx, "validate_descriptor: failed to read descriptor");
681             return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
682         }
683         if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
684             ctx->descriptor.descriptor_offset != relative_offset ||
685             ctx->descriptor.region_count == 0 ||
686             ctx->descriptor.descriptor_area_size > max_descriptor_size ||
687             ctx->descriptor.image_size != image_size)
688         {
689             CPRINTS(ctx, "validate_descriptor: invalid descriptor");
690             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
691         }
692         if (ctx->descriptor.image_type != IMAGE_DEV &&
693             ctx->descriptor.image_type != IMAGE_PROD &&
694             ctx->descriptor.image_type != IMAGE_BREAKOUT &&
695             ctx->descriptor.image_type != IMAGE_TEST &&
696             ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
697         {
698             CPRINTS(ctx, "validate_descriptor: bad image type");
699             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
700         }
701         // Although the image_descriptor struct supports unauthenticated
702         // images, Haven will not allow it.
703         // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
704 
705         signature_scheme = ctx->descriptor.signature_scheme;
706 
707         rv = is_signature_scheme_supported(signature_scheme);
708         if (rv != LIBCR51SIGN_SUCCESS)
709         {
710             return rv;
711         }
712         rv = is_hash_type_supported(ctx->descriptor.hash_type);
713         if (rv != LIBCR51SIGN_SUCCESS)
714         {
715             CPRINTS(ctx, "validate_payload_regions: invalid hash type");
716             return rv;
717         }
718         if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
719             ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
720         {
721             CPRINTS(ctx, "validate_descriptor: unsupported descriptor");
722             return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
723         }
724         rv =
725             get_signature_struct_size(signature_scheme, &signature_struct_size);
726         if (rv != LIBCR51SIGN_SUCCESS)
727         {
728             return rv;
729         }
730 
731         // Compute the size of the signed portion of the image descriptor.
732         signed_size =
733             sizeof(struct image_descriptor) +
734             ctx->descriptor.region_count * sizeof(struct image_region);
735         rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
736         if (rv != LIBCR51SIGN_SUCCESS)
737         {
738             return rv;
739         }
740         signed_size += hash_struct_size;
741         if (ctx->descriptor.denylist_size)
742         {
743             signed_size += sizeof(struct denylist);
744             signed_size +=
745                 ctx->descriptor.denylist_size * sizeof(struct denylist_record);
746         }
747         if (ctx->descriptor.blob_size)
748         {
749             signed_size += sizeof(struct blob);
750             // Previous additions are guaranteed not to overflow.
751             if (ctx->descriptor.blob_size >
752                 ctx->descriptor.descriptor_area_size - signed_size)
753             {
754                 CPRINTS(ctx, "validate_descriptor: invalid blob size (0x%x)",
755                         ctx->descriptor.blob_size);
756                 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
757             }
758             signed_size += ctx->descriptor.blob_size;
759         }
760         if (signature_struct_size >
761             ctx->descriptor.descriptor_area_size - signed_size)
762         {
763             CPRINTS(ctx,
764                     "validate_descriptor: invalid descriptor area size "
765                     "(expected = 0x%x, actual = 0x%x)",
766                     ctx->descriptor.descriptor_area_size,
767                     signed_size + signature_struct_size);
768             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
769         }
770         signature_struct_offset = signed_size;
771         // Omit the actual signature.
772         rv = get_signature_field_offset(signature_scheme, &signature_offset);
773         if (rv != LIBCR51SIGN_SUCCESS)
774         {
775             return rv;
776         }
777         signed_size += signature_offset;
778 
779         // Lookup key & validate transition.
780         rv = validate_transition(ctx, intf, offset + signature_struct_offset);
781 
782         if (rv != LIBCR51SIGN_SUCCESS)
783         {
784             return rv;
785         }
786         return validate_signature(ctx, intf, offset, signed_size,
787                                   signature_scheme, offset + signed_size);
788     }
789 
790     // Scans the external EEPROM for a magic value at "alignment" boundaries.
791     //
792     //@param device  Handle to the external EEPROM.
793     //@param magic   8-byte pattern to search for.
794     //@param start_offset  Offset to begin searching at.
795     //@param limit   Exclusive address (e.g. EEPROM size).
796     //@param alignment   Alignment boundaries (POW2) to search on.
797     //@param header_offset   Location to place the new header offset.
798     //@return LIBCR51SIGN_SUCCESS (or non-zero on error).
799 
800     int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
801                          const struct libcr51sign_intf* intf, uint64_t magic,
802                          uint32_t start_offset, uint32_t limit,
803                          uint32_t alignment, uint32_t* header_offset)
804     {
805         uint64_t read_data;
806         uint32_t offset;
807         int rv;
808 
809         if (limit <= start_offset || limit > ctx->end_offset ||
810             limit < sizeof(magic) || !POWER_OF_TWO(alignment))
811         {
812             return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
813         }
814 
815         if (!intf->read)
816         {
817             CPRINTS(ctx, "scan_for_magic_8: missing intf->read");
818             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
819         }
820         // Align start_offset to the next valid boundary.
821         start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
822         for (offset = start_offset; offset < limit - sizeof(magic);
823              offset += alignment)
824         {
825             rv = intf->read((void*)ctx, offset, sizeof(read_data),
826                             (uint8_t*)&read_data);
827             if (rv != LIBCR51SIGN_SUCCESS)
828             {
829                 return rv;
830             }
831             if (read_data == magic)
832             {
833                 if (header_offset)
834                 {
835                     *header_offset = offset;
836                 }
837                 return LIBCR51SIGN_SUCCESS;
838             }
839         }
840         // Failed to locate magic.
841         return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
842     }
843 
844     // Check whether the signature on the image is valid.
845     // Validates the authenticity of an EEPROM image. Scans for & validates the
846     // signature on the image descriptor. If the descriptor validates, hashes
847     // the rest of the image to verify its integrity.
848     //
849     // @param[in] ctx - context which describes the image and holds opaque
850     // private
851     //                 data for the user of the library
852     // @param[in] intf - function pointers which interface to the current system
853     //                  and environment
854     // @param[out] image_regions - image_region pointer to an array for the
855     // output
856     //
857     // @return nonzero on error, zero on success
858 
859     failure_reason libcr51sign_validate(
860         const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
861         struct libcr51sign_validated_regions* image_regions)
862     {
863         uint32_t image_limit = 0;
864         int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
865         uint32_t descriptor_offset;
866 
867         if (!ctx)
868         {
869             CPRINTS(ctx, "MIssing context");
870             return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
871         }
872         else if (!intf)
873         {
874             CPRINTS(ctx, "Missing interface");
875             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
876         }
877 
878         rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
879                               ctx->end_offset, DESCRIPTOR_ALIGNMENT,
880                               &descriptor_offset);
881         while (rv == LIBCR51SIGN_SUCCESS)
882         {
883             CPRINTS(ctx, "validate: potential image descriptor found @%x ",
884                     descriptor_offset);
885             // Validation is split into 2 functions to minimize
886             // stack usage.
887 
888             rv = validate_descriptor(ctx, intf, descriptor_offset,
889                                      descriptor_offset - ctx->start_offset,
890                                      ctx->end_offset - ctx->start_offset);
891             if (rv != LIBCR51SIGN_SUCCESS)
892             {
893                 CPRINTS(ctx, "validate: validate_descriptor() failed ec%d ",
894                         rv);
895             }
896 
897             if (rv == LIBCR51SIGN_SUCCESS)
898             {
899                 rv = validate_payload_regions_helper(
900                     ctx, intf, descriptor_offset, image_regions);
901                 if (rv == LIBCR51SIGN_SUCCESS)
902                 {
903                     CPRINTS(ctx, "validate: success!");
904                     return rv;
905                 }
906                 CPRINTS(ctx,
907                         "validate: validate_payload_regions() failed ec%d ",
908                         rv);
909             }
910             // Store the first desc fail reason if any
911             if (rv != LIBCR51SIGN_SUCCESS &&
912                 rv_first_desc == LIBCR51SIGN_SUCCESS)
913                 rv_first_desc = rv;
914 
915             // scan_for_magic_8() will round up to the next aligned boundary.
916             descriptor_offset++;
917             image_limit = ctx->end_offset - ctx->start_offset;
918             rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC,
919                                   descriptor_offset, image_limit,
920                                   DESCRIPTOR_ALIGNMENT, &descriptor_offset);
921         }
922         CPRINTS(ctx, "validate: failed to validate image ec%d ", rv);
923         // If desc validation failed for some reason then return that reason
924         if (rv_first_desc != LIBCR51SIGN_SUCCESS)
925             return rv_first_desc;
926         else
927             return rv;
928     }
929 
930     // @func to returns the libcr51sign error code as a string
931     // @param[in] ec - Error code
932     // @return error code in string format
933 
934     const char* libcr51sign_errorcode_to_string(failure_reason ec)
935     {
936         switch (ec)
937         {
938             case LIBCR51SIGN_SUCCESS:
939                 return "Success";
940             case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
941                 return "Runtime Error Failure";
942             case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
943                 return "Unsupported descriptor";
944             case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
945                 return "Invalid descriptor";
946             case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
947                 return "Invalid image family";
948             case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
949                 return "Image type disallowed";
950             case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
951                 return "Dev downgrade disallowed";
952             case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
953                 return "Untrusted key";
954             case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
955                 return "Invalid signature";
956             case LIBCR51SIGN_ERROR_INVALID_HASH:
957                 return "Invalid hash";
958             case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
959                 return "Invalid hash type";
960             case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
961                 return "Invalid Argument";
962             case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
963                 return "Failed to locate descriptor";
964             case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
965                 return "Invalid context";
966             case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
967                 return "Invalid interface";
968             case LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME:
969                 return "Invalid signature scheme";
970             case LIBCR51SIGN_ERROR_INVALID_REGION_INPUT:
971                 return "Invalid image region input";
972             case LIBCR51SIGN_ERROR_INVALID_REGION_SIZE:
973                 return "Invalid image region size";
974             default:
975                 return "Unknown error";
976         }
977     }
978 
979 #ifdef __cplusplus
980 } //  extern "C"
981 #endif
982