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