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