xref: /openbmc/google-misc/dhcp-done/subprojects/libcr51sign/src/libcr51sign.c (revision 027c042e5847fd0e8bc9ab68b62d7a4f0d5efa47)
15acaca2fSWilliam A. Kennington III /*
25acaca2fSWilliam A. Kennington III  * Copyright 2021 Google LLC
35acaca2fSWilliam A. Kennington III  *
45acaca2fSWilliam A. Kennington III  * Licensed under the Apache License, Version 2.0 (the "License");
55acaca2fSWilliam A. Kennington III  * you may not use this file except in compliance with the License.
65acaca2fSWilliam A. Kennington III  * You may obtain a copy of the License at
75acaca2fSWilliam A. Kennington III  *
85acaca2fSWilliam A. Kennington III  *      http://www.apache.org/licenses/LICENSE-2.0
95acaca2fSWilliam A. Kennington III  *
105acaca2fSWilliam A. Kennington III  * Unless required by applicable law or agreed to in writing, software
115acaca2fSWilliam A. Kennington III  * distributed under the License is distributed on an "AS IS" BASIS,
125acaca2fSWilliam A. Kennington III  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135acaca2fSWilliam A. Kennington III  * See the License for the specific language governing permissions and
145acaca2fSWilliam A. Kennington III  * limitations under the License.
155acaca2fSWilliam A. Kennington III  */
16dca92e47SWilly Tu #include <assert.h>
17dca92e47SWilly Tu #include <libcr51sign/cr51_image_descriptor.h>
185acaca2fSWilliam A. Kennington III #include <libcr51sign/libcr51sign.h>
19dca92e47SWilly Tu #include <libcr51sign/libcr51sign_internal.h>
20dca92e47SWilly Tu #include <libcr51sign/libcr51sign_mauv.h>
21*027c042eSDan Zhang #include <stddef.h>
22dca92e47SWilly Tu #include <stdint.h>
235acaca2fSWilliam A. Kennington III #include <stdio.h>
24dca92e47SWilly Tu #include <stdlib.h>
255acaca2fSWilliam A. Kennington III #include <string.h>
265acaca2fSWilliam A. Kennington III 
275acaca2fSWilliam A. Kennington III #ifdef __cplusplus
285acaca2fSWilliam A. Kennington III extern "C"
295acaca2fSWilliam A. Kennington III {
305acaca2fSWilliam A. Kennington III #endif
315acaca2fSWilliam A. Kennington III 
325acaca2fSWilliam A. Kennington III // True of x is a power of two
335acaca2fSWilliam A. Kennington III #define POWER_OF_TWO(x) ((x) && !((x) & ((x) - 1)))
345acaca2fSWilliam A. Kennington III 
355acaca2fSWilliam A. Kennington III // Maximum version supported. Major revisions are not backwards compatible.
365acaca2fSWilliam A. Kennington III #define MAX_MAJOR_VERSION 1
375acaca2fSWilliam A. Kennington III 
385acaca2fSWilliam A. Kennington III // Descriptor alignment on the external EEPROM.
395acaca2fSWilliam A. Kennington III #define DESCRIPTOR_ALIGNMENT (64 * 1024)
405acaca2fSWilliam A. Kennington III 
415acaca2fSWilliam A. Kennington III // SPS EEPROM sector size is 4KiB, since this is the smallest erasable size.
425acaca2fSWilliam A. Kennington III #define IMAGE_REGION_ALIGNMENT 4096
435acaca2fSWilliam A. Kennington III 
445acaca2fSWilliam A. Kennington III #define MAX_READ_SIZE 1024
455acaca2fSWilliam A. Kennington III 
465acaca2fSWilliam A. Kennington III #ifndef ARRAY_SIZE
475acaca2fSWilliam A. Kennington III #define ARRAY_SIZE(t) (sizeof(t) / sizeof(t[0]))
485acaca2fSWilliam A. Kennington III #endif
495acaca2fSWilliam A. Kennington III 
50*027c042eSDan Zhang // Values of SIGNATURE_OFFSET should be same for all sig types (2048,3072,4096)
515acaca2fSWilliam A. Kennington III #define SIGNATURE_OFFSET offsetof(struct signature_rsa3072_pkcs15, modulus)
525acaca2fSWilliam A. Kennington III 
535acaca2fSWilliam A. Kennington III #ifndef BUILD_ASSERT
545acaca2fSWilliam A. Kennington III #define BUILD_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)]))
555acaca2fSWilliam A. Kennington III #endif
565acaca2fSWilliam A. Kennington III 
575acaca2fSWilliam A. Kennington III // Returns the bytes size of keys used in the given signature_scheme.
585acaca2fSWilliam A. Kennington III // Return error if signature_scheme is invalid.
595acaca2fSWilliam A. Kennington III //
605acaca2fSWilliam A. Kennington III static failure_reason get_key_size(enum signature_scheme signature_scheme,
615acaca2fSWilliam A. Kennington III                                    uint16_t* key_size)
625acaca2fSWilliam A. Kennington III {
635acaca2fSWilliam A. Kennington III     switch (signature_scheme)
645acaca2fSWilliam A. Kennington III     {
655acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA2048_PKCS15:
665acaca2fSWilliam A. Kennington III             *key_size = 256;
675acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
685acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA3072_PKCS15:
695acaca2fSWilliam A. Kennington III             *key_size = 384;
705acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
715acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15:
725acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15_SHA512:
735acaca2fSWilliam A. Kennington III             *key_size = 512;
745acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
755acaca2fSWilliam A. Kennington III         default:
765acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
775acaca2fSWilliam A. Kennington III     }
785acaca2fSWilliam A. Kennington III }
795acaca2fSWilliam A. Kennington III 
805acaca2fSWilliam A. Kennington III // Returns the hash_type for a given signature scheme
815acaca2fSWilliam A. Kennington III // Returns error if scheme is invalid.
825acaca2fSWilliam A. Kennington III failure_reason get_hash_type_from_signature(enum signature_scheme scheme,
835acaca2fSWilliam A. Kennington III                                             enum hash_type* type)
845acaca2fSWilliam A. Kennington III {
855acaca2fSWilliam A. Kennington III     switch (scheme)
865acaca2fSWilliam A. Kennington III     {
875acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA2048_PKCS15:
885acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA3072_PKCS15:
895acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15:
905acaca2fSWilliam A. Kennington III             *type = HASH_SHA2_256;
915acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
925acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15_SHA512:
935acaca2fSWilliam A. Kennington III             *type = HASH_SHA2_512;
945acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
955acaca2fSWilliam A. Kennington III         default:
965acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
975acaca2fSWilliam A. Kennington III     }
985acaca2fSWilliam A. Kennington III }
995acaca2fSWilliam A. Kennington III 
1005acaca2fSWilliam A. Kennington III // Check if the given hash_type is supported.
1015acaca2fSWilliam A. Kennington III // Returns error if hash_type is not supported.
1025acaca2fSWilliam A. Kennington III static failure_reason is_hash_type_supported(enum hash_type type)
1035acaca2fSWilliam A. Kennington III {
1045acaca2fSWilliam A. Kennington III     switch (type)
1055acaca2fSWilliam A. Kennington III     {
1065acaca2fSWilliam A. Kennington III         case HASH_SHA2_256:
1075acaca2fSWilliam A. Kennington III         case HASH_SHA2_512:
1085acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
1095acaca2fSWilliam A. Kennington III         default:
1105acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
1115acaca2fSWilliam A. Kennington III     }
1125acaca2fSWilliam A. Kennington III }
1135acaca2fSWilliam A. Kennington III 
1145acaca2fSWilliam A. Kennington III // Determines digest size for a given hash_type.
1155acaca2fSWilliam A. Kennington III // Returns error if hash_type is not supported.
1166084957fSPatrick Williams static failure_reason get_hash_digest_size(enum hash_type type, uint32_t* size)
1175acaca2fSWilliam A. Kennington III {
1185acaca2fSWilliam A. Kennington III     switch (type)
1195acaca2fSWilliam A. Kennington III     {
1205acaca2fSWilliam A. Kennington III         case HASH_SHA2_256:
1215acaca2fSWilliam A. Kennington III             *size = LIBCR51SIGN_SHA256_DIGEST_SIZE;
1225acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
1235acaca2fSWilliam A. Kennington III         case HASH_SHA2_512:
1245acaca2fSWilliam A. Kennington III             *size = LIBCR51SIGN_SHA512_DIGEST_SIZE;
1255acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
1265acaca2fSWilliam A. Kennington III         default:
1275acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
1285acaca2fSWilliam A. Kennington III     }
1295acaca2fSWilliam A. Kennington III }
1305acaca2fSWilliam A. Kennington III 
1315acaca2fSWilliam A. Kennington III // Determines hash struct size for a given hash_type.
1325acaca2fSWilliam A. Kennington III // Returns error if hash_type is not supported.
1336084957fSPatrick Williams static failure_reason get_hash_struct_size(enum hash_type type, uint32_t* size)
1345acaca2fSWilliam A. Kennington III {
1355acaca2fSWilliam A. Kennington III     switch (type)
1365acaca2fSWilliam A. Kennington III     {
1375acaca2fSWilliam A. Kennington III         case HASH_SHA2_256:
1385acaca2fSWilliam A. Kennington III             *size = sizeof(struct hash_sha256);
1395acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
1405acaca2fSWilliam A. Kennington III         case HASH_SHA2_512:
141dca92e47SWilly Tu             *size = sizeof(struct hash_sha512);
1425acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
1435acaca2fSWilliam A. Kennington III         default:
1445acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_HASH_TYPE;
1455acaca2fSWilliam A. Kennington III     }
1465acaca2fSWilliam A. Kennington III }
1475acaca2fSWilliam A. Kennington III 
1485acaca2fSWilliam A. Kennington III // Checks that:
1495acaca2fSWilliam A. Kennington III //  - The signing key is trusted
1505acaca2fSWilliam A. Kennington III //  - The target version is not denylisted
1515acaca2fSWilliam A. Kennington III // If validating a staged update, also checks that:
1525acaca2fSWilliam A. Kennington III //  - The target image family matches the current image family
1535acaca2fSWilliam A. Kennington III //  - The image type transition is legal (i.e. dev -> *|| prod -> prod) or
1545acaca2fSWilliam A. Kennington III //    alternatively that the hardware ID is allowlisted
1555acaca2fSWilliam A. Kennington III // Assuming the caller has performed following:
1565acaca2fSWilliam A. Kennington III // board_get_base_key_index();
1575acaca2fSWilliam A. Kennington III // board_get_key_array
1585acaca2fSWilliam A. Kennington III // Possible return codes:
1595acaca2fSWilliam A. Kennington III // LIBCR51SIGN_SUCCESS = 0,
1605acaca2fSWilliam A. Kennington III // LIBCR51SIGN_ERROR_RUNTIME_FAILURE = 1,
1615acaca2fSWilliam A. Kennington III // LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR = 3,
1625acaca2fSWilliam A. Kennington III // LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY = 4,
1635acaca2fSWilliam A. Kennington III // LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED = 5,
1645acaca2fSWilliam A. Kennington III 
1656084957fSPatrick Williams static failure_reason validate_transition(const struct libcr51sign_ctx* ctx,
1665acaca2fSWilliam A. Kennington III                                           const struct libcr51sign_intf* intf,
1675acaca2fSWilliam A. Kennington III                                           uint32_t signature_struct_offset)
1685acaca2fSWilliam A. Kennington III {
1695acaca2fSWilliam A. Kennington III     BUILD_ASSERT((offsetof(struct signature_rsa2048_pkcs15, modulus) ==
1705acaca2fSWilliam A. Kennington III                       SIGNATURE_OFFSET &&
1715acaca2fSWilliam A. Kennington III                   offsetof(struct signature_rsa3072_pkcs15, modulus) ==
1725acaca2fSWilliam A. Kennington III                       SIGNATURE_OFFSET &&
1735acaca2fSWilliam A. Kennington III                   offsetof(struct signature_rsa4096_pkcs15, modulus) ==
1745acaca2fSWilliam A. Kennington III                       SIGNATURE_OFFSET));
1755acaca2fSWilliam A. Kennington III 
1765acaca2fSWilliam A. Kennington III     // Read up to the modulus.
1775acaca2fSWilliam A. Kennington III     enum
1785acaca2fSWilliam A. Kennington III     {
1795acaca2fSWilliam A. Kennington III         read_len = SIGNATURE_OFFSET
1805acaca2fSWilliam A. Kennington III     };
181*027c042eSDan Zhang     uint32_t buffer[read_len / sizeof(uint32_t)];
1825acaca2fSWilliam A. Kennington III     int rv;
183*027c042eSDan Zhang     rv = intf->read(ctx, signature_struct_offset, read_len, (uint8_t*)buffer);
1845acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
1855acaca2fSWilliam A. Kennington III     {
186dca92e47SWilly Tu         CPRINTS(ctx, "%s: failed to read signature struct\n", __FUNCTION__);
1875acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
1885acaca2fSWilliam A. Kennington III     }
189*027c042eSDan Zhang     if (*buffer != SIGNATURE_MAGIC)
1905acaca2fSWilliam A. Kennington III     {
191dca92e47SWilly Tu         CPRINTS(ctx, "%s: bad signature magic\n", __FUNCTION__);
1925acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
1935acaca2fSWilliam A. Kennington III     }
1945acaca2fSWilliam A. Kennington III 
1955acaca2fSWilliam A. Kennington III     if (ctx->descriptor.image_family != ctx->current_image_family &&
1965acaca2fSWilliam A. Kennington III         ctx->descriptor.image_family != IMAGE_FAMILY_ALL &&
1975acaca2fSWilliam A. Kennington III         ctx->current_image_family != IMAGE_FAMILY_ALL)
1985acaca2fSWilliam A. Kennington III     {
199dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid image family\n", __FUNCTION__);
2005acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY;
2015acaca2fSWilliam A. Kennington III     }
2025acaca2fSWilliam A. Kennington III 
203d2bcdd5cSWilly Tu     if (intf->is_production_mode == NULL)
2045acaca2fSWilliam A. Kennington III     {
205dca92e47SWilly Tu         CPRINTS(ctx, "%s: missing is_production_mode\n", __FUNCTION__);
2065acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
2075acaca2fSWilliam A. Kennington III     }
2086084957fSPatrick Williams     if (intf->is_production_mode() && (ctx->descriptor.image_type == IMAGE_DEV))
2095acaca2fSWilliam A. Kennington III     {
210dca92e47SWilly Tu         CPRINTS(ctx, "%s: checking exemption allowlist\n", __FUNCTION__);
2115acaca2fSWilliam A. Kennington III 
212d2bcdd5cSWilly Tu         // If function is NULL or if the function call return false, return
213d2bcdd5cSWilly Tu         // error
214d2bcdd5cSWilly Tu         if (intf->prod_to_dev_downgrade_allowed == NULL ||
215d2bcdd5cSWilly Tu             !intf->prod_to_dev_downgrade_allowed())
2165acaca2fSWilliam A. Kennington III         {
217dca92e47SWilly Tu             CPRINTS(ctx, "%s: illegal image type\n", __FUNCTION__);
2185acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED;
2195acaca2fSWilliam A. Kennington III         }
2205acaca2fSWilliam A. Kennington III     }
2215acaca2fSWilliam A. Kennington III     return LIBCR51SIGN_SUCCESS;
2225acaca2fSWilliam A. Kennington III }
2235acaca2fSWilliam A. Kennington III 
224dca92e47SWilly Tu // If caller had provided read_and_hash_update call that, otherwise call read
225dca92e47SWilly Tu // and then update.
2265acaca2fSWilliam A. Kennington III 
2276084957fSPatrick Williams static failure_reason read_and_hash_update(const struct libcr51sign_ctx* ctx,
2285acaca2fSWilliam A. Kennington III                                            const struct libcr51sign_intf* intf,
2295acaca2fSWilliam A. Kennington III                                            uint32_t offset, uint32_t size)
2305acaca2fSWilliam A. Kennington III {
2315acaca2fSWilliam A. Kennington III     uint8_t read_buffer[MAX_READ_SIZE];
2325acaca2fSWilliam A. Kennington III     int rv;
233*027c042eSDan Zhang     uint32_t read_size;
2345acaca2fSWilliam A. Kennington III 
2355acaca2fSWilliam A. Kennington III     if (intf->read_and_hash_update)
2365acaca2fSWilliam A. Kennington III     {
2375acaca2fSWilliam A. Kennington III         rv = intf->read_and_hash_update((void*)ctx, offset, size);
2385acaca2fSWilliam A. Kennington III     }
2395acaca2fSWilliam A. Kennington III     else
2405acaca2fSWilliam A. Kennington III     {
2415acaca2fSWilliam A. Kennington III         if (!intf->hash_update)
2425acaca2fSWilliam A. Kennington III         {
243dca92e47SWilly Tu             CPRINTS(ctx, "%s: missing hash_update\n", __FUNCTION__);
2445acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
2455acaca2fSWilliam A. Kennington III         }
2465acaca2fSWilliam A. Kennington III         do
2475acaca2fSWilliam A. Kennington III         {
2485acaca2fSWilliam A. Kennington III             read_size = size < MAX_READ_SIZE ? size : MAX_READ_SIZE;
2495acaca2fSWilliam A. Kennington III             rv = intf->read((void*)ctx, offset, read_size, read_buffer);
2505acaca2fSWilliam A. Kennington III             if (rv != LIBCR51SIGN_SUCCESS)
2515acaca2fSWilliam A. Kennington III             {
2525acaca2fSWilliam A. Kennington III                 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
2535acaca2fSWilliam A. Kennington III             }
2545acaca2fSWilliam A. Kennington III             rv = intf->hash_update((void*)ctx, read_buffer, read_size);
2555acaca2fSWilliam A. Kennington III             if (rv != LIBCR51SIGN_SUCCESS)
2565acaca2fSWilliam A. Kennington III             {
2575acaca2fSWilliam A. Kennington III                 return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
2585acaca2fSWilliam A. Kennington III             }
2595acaca2fSWilliam A. Kennington III             offset += read_size;
2605acaca2fSWilliam A. Kennington III             size -= read_size;
2615acaca2fSWilliam A. Kennington III         } while (size > 0);
2625acaca2fSWilliam A. Kennington III     }
2635acaca2fSWilliam A. Kennington III     return rv;
2645acaca2fSWilliam A. Kennington III }
2655acaca2fSWilliam A. Kennington III 
2665acaca2fSWilliam A. Kennington III // Validates the image_region array, namely that:
2675acaca2fSWilliam A. Kennington III //  - The regions are aligned, contiguous & exhaustive
2685acaca2fSWilliam A. Kennington III //  - That the image descriptor resides in a static region
2695acaca2fSWilliam A. Kennington III //
2705acaca2fSWilliam A. Kennington III // If the array is consistent, proceeds to hash the static regions and
2715acaca2fSWilliam A. Kennington III // validates the hash. d_offset is the absolute image descriptor offset
2725acaca2fSWilliam A. Kennington III 
2735acaca2fSWilliam A. Kennington III static failure_reason validate_payload_regions(
2745acaca2fSWilliam A. Kennington III     const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
2755acaca2fSWilliam A. Kennington III     uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
2765acaca2fSWilliam A. Kennington III {
277*027c042eSDan Zhang     // Allocate buffer to accommodate largest supported hash-type(SHA512)
2785acaca2fSWilliam A. Kennington III     uint8_t magic_and_digest[MEMBER_SIZE(struct hash_sha512, hash_magic) +
2795acaca2fSWilliam A. Kennington III                              LIBCR51SIGN_SHA512_DIGEST_SIZE];
2805acaca2fSWilliam A. Kennington III     uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
2815acaca2fSWilliam A. Kennington III     uint32_t byte_count, region_count, image_size, hash_offset, digest_size;
282deb5501aSWilliam A. Kennington III     uint32_t i;
283*027c042eSDan Zhang     uint32_t d_region_num = 0;
284deb5501aSWilliam A. Kennington III     int rv;
285dca92e47SWilly Tu     struct image_region const* region;
2865acaca2fSWilliam A. Kennington III 
2875acaca2fSWilliam A. Kennington III     if (image_regions == NULL)
2885acaca2fSWilliam A. Kennington III     {
289dca92e47SWilly Tu         CPRINTS(ctx, "%s: Missing image region input\n", __FUNCTION__);
2905acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_REGION_INPUT;
2915acaca2fSWilliam A. Kennington III     }
2925acaca2fSWilliam A. Kennington III 
2935acaca2fSWilliam A. Kennington III     BUILD_ASSERT((MEMBER_SIZE(struct hash_sha256, hash_magic) ==
2945acaca2fSWilliam A. Kennington III                   MEMBER_SIZE(struct hash_sha512, hash_magic)));
2955acaca2fSWilliam A. Kennington III     image_size = ctx->descriptor.image_size;
2965acaca2fSWilliam A. Kennington III     region_count = ctx->descriptor.region_count;
2975acaca2fSWilliam A. Kennington III     hash_offset = d_offset + sizeof(struct image_descriptor) +
2985acaca2fSWilliam A. Kennington III                   region_count * sizeof(struct image_region);
2995acaca2fSWilliam A. Kennington III     // Read the image_region array.
3005acaca2fSWilliam A. Kennington III 
3015acaca2fSWilliam A. Kennington III     if (region_count > ARRAY_SIZE(image_regions->image_regions))
3025acaca2fSWilliam A. Kennington III     {
303dca92e47SWilly Tu         CPRINTS(ctx,
304dca92e47SWilly Tu                 "%s: ctx->descriptor.region_count is greater "
305dca92e47SWilly Tu                 "than LIBCR51SIGN_MAX_REGION_COUNT\n",
306dca92e47SWilly Tu                 __FUNCTION__);
3075acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_REGION_SIZE;
3085acaca2fSWilliam A. Kennington III     }
3095acaca2fSWilliam A. Kennington III 
310deb5501aSWilliam A. Kennington III     rv = intf->read(ctx, d_offset + sizeof(struct image_descriptor),
3115acaca2fSWilliam A. Kennington III                     region_count * sizeof(struct image_region),
3125acaca2fSWilliam A. Kennington III                     (uint8_t*)&image_regions->image_regions);
3135acaca2fSWilliam A. Kennington III 
3145acaca2fSWilliam A. Kennington III     image_regions->region_count = region_count;
3155acaca2fSWilliam A. Kennington III 
3165acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
3175acaca2fSWilliam A. Kennington III     {
318dca92e47SWilly Tu         CPRINTS(ctx, "%s: failed to read region array\n", __FUNCTION__);
3195acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
3205acaca2fSWilliam A. Kennington III     }
3215acaca2fSWilliam A. Kennington III 
3225acaca2fSWilliam A. Kennington III     // Validate that the regions are contiguous & exhaustive.
3235acaca2fSWilliam A. Kennington III     for (i = 0, byte_count = 0; i < region_count; i++)
3245acaca2fSWilliam A. Kennington III     {
3255acaca2fSWilliam A. Kennington III         region = image_regions->image_regions + i;
3265acaca2fSWilliam A. Kennington III 
327dca92e47SWilly Tu         CPRINTS(ctx, "%s: region #%d \"%s\" (%x - %x)\n", __FUNCTION__, i,
328dca92e47SWilly Tu                 (const char*)region->region_name, region->region_offset,
3295acaca2fSWilliam A. Kennington III                 region->region_offset + region->region_size);
3305acaca2fSWilliam A. Kennington III         if ((region->region_offset % IMAGE_REGION_ALIGNMENT) != 0 ||
3315acaca2fSWilliam A. Kennington III             (region->region_size % IMAGE_REGION_ALIGNMENT) != 0)
3325acaca2fSWilliam A. Kennington III         {
333dca92e47SWilly Tu             CPRINTS(ctx, "%s: regions must be sector aligned\n", __FUNCTION__);
3345acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
3355acaca2fSWilliam A. Kennington III         }
3365acaca2fSWilliam A. Kennington III         if (region->region_offset != byte_count ||
3375acaca2fSWilliam A. Kennington III             region->region_size > image_size - byte_count)
3385acaca2fSWilliam A. Kennington III         {
339dca92e47SWilly Tu             CPRINTS(ctx, "%s: invalid region array\n", __FUNCTION__);
3405acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
3415acaca2fSWilliam A. Kennington III         }
3425acaca2fSWilliam A. Kennington III         byte_count += region->region_size;
3435acaca2fSWilliam A. Kennington III         // The image descriptor must be part of a static region.
3445acaca2fSWilliam A. Kennington III         if (d_offset >= region->region_offset && d_offset < byte_count)
3455acaca2fSWilliam A. Kennington III         {
3465acaca2fSWilliam A. Kennington III             d_region_num = i;
347dca92e47SWilly Tu             CPRINTS(ctx, "%s: image descriptor in region %d\n", __FUNCTION__,
3485acaca2fSWilliam A. Kennington III                     i);
3495acaca2fSWilliam A. Kennington III             // The descriptor can't span regions.
350dca92e47SWilly Tu             if ((ctx->descriptor.descriptor_area_size >
351dca92e47SWilly Tu                  (byte_count - d_offset)) ||
3525acaca2fSWilliam A. Kennington III                 !(region->region_attributes & IMAGE_REGION_STATIC))
3535acaca2fSWilliam A. Kennington III             {
3546084957fSPatrick Williams                 CPRINTS(ctx,
355dca92e47SWilly Tu                         "%s: descriptor must reside in "
356dca92e47SWilly Tu                         "static region\n",
357dca92e47SWilly Tu                         __FUNCTION__);
3585acaca2fSWilliam A. Kennington III                 return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
3595acaca2fSWilliam A. Kennington III             }
3605acaca2fSWilliam A. Kennington III         }
3615acaca2fSWilliam A. Kennington III     }
3625acaca2fSWilliam A. Kennington III     if (byte_count != image_size)
3635acaca2fSWilliam A. Kennington III     {
364dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
3655acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
3665acaca2fSWilliam A. Kennington III     }
3675acaca2fSWilliam A. Kennington III 
3685acaca2fSWilliam A. Kennington III     rv = get_hash_digest_size(ctx->descriptor.hash_type, &digest_size);
3695acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
3705acaca2fSWilliam A. Kennington III     {
3715acaca2fSWilliam A. Kennington III         return rv;
3725acaca2fSWilliam A. Kennington III     }
3735acaca2fSWilliam A. Kennington III 
3745acaca2fSWilliam A. Kennington III     rv = intf->read(ctx, hash_offset,
3756084957fSPatrick Williams                     MEMBER_SIZE(struct hash_sha256, hash_magic) + digest_size,
3765acaca2fSWilliam A. Kennington III                     magic_and_digest);
3775acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
3785acaca2fSWilliam A. Kennington III     {
379dca92e47SWilly Tu         CPRINTS(ctx, "%s: failed to read hash from flash\n", __FUNCTION__);
3805acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
3815acaca2fSWilliam A. Kennington III     }
3825acaca2fSWilliam A. Kennington III     if (*(uint32_t*)magic_and_digest != HASH_MAGIC)
3835acaca2fSWilliam A. Kennington III     {
384dca92e47SWilly Tu         CPRINTS(ctx, "%s: bad hash magic\n", __FUNCTION__);
3855acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
3865acaca2fSWilliam A. Kennington III     }
3875acaca2fSWilliam A. Kennington III     rv = intf->hash_init(ctx, ctx->descriptor.hash_type);
3885acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
3895acaca2fSWilliam A. Kennington III     {
390dca92e47SWilly Tu         CPRINTS(ctx, "%s: hash_init failed\n", __FUNCTION__);
3915acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
3925acaca2fSWilliam A. Kennington III     }
3935acaca2fSWilliam A. Kennington III     for (i = 0; i < region_count; i++)
3945acaca2fSWilliam A. Kennington III     {
3955acaca2fSWilliam A. Kennington III         uint32_t hash_start, hash_size;
3965acaca2fSWilliam A. Kennington III         region = image_regions->image_regions + i;
3975acaca2fSWilliam A. Kennington III 
3985acaca2fSWilliam A. Kennington III         if (!(region->region_attributes & IMAGE_REGION_STATIC))
3995acaca2fSWilliam A. Kennington III         {
4005acaca2fSWilliam A. Kennington III             continue;
4015acaca2fSWilliam A. Kennington III         }
4025acaca2fSWilliam A. Kennington III         hash_start = region->region_offset;
4035acaca2fSWilliam A. Kennington III         hash_size = region->region_size;
4045acaca2fSWilliam A. Kennington III 
4055acaca2fSWilliam A. Kennington III         // Skip the descriptor.
4065acaca2fSWilliam A. Kennington III         do
4075acaca2fSWilliam A. Kennington III         {
4085acaca2fSWilliam A. Kennington III             if (i == d_region_num)
4095acaca2fSWilliam A. Kennington III             {
4105acaca2fSWilliam A. Kennington III                 hash_size = d_offset - hash_start;
4115acaca2fSWilliam A. Kennington III                 if (!hash_size)
4125acaca2fSWilliam A. Kennington III                 {
4135acaca2fSWilliam A. Kennington III                     hash_start += ctx->descriptor.descriptor_area_size;
414dca92e47SWilly Tu                     hash_size = (region->region_offset + region->region_size -
415dca92e47SWilly Tu                                  hash_start);
4165acaca2fSWilliam A. Kennington III                 }
417dca92e47SWilly Tu             }
418dca92e47SWilly Tu 
419dca92e47SWilly Tu             CPRINTS(ctx, "%s: hashing %s (%x - %x)\n", __FUNCTION__,
420deb5501aSWilliam A. Kennington III                     (const char*)region->region_name, hash_start,
4215acaca2fSWilliam A. Kennington III                     hash_start + hash_size);
4225acaca2fSWilliam A. Kennington III             // Read the image_region array.
4235acaca2fSWilliam A. Kennington III             rv = read_and_hash_update(ctx, intf, hash_start, hash_size);
4245acaca2fSWilliam A. Kennington III             if (rv != LIBCR51SIGN_SUCCESS)
4255acaca2fSWilliam A. Kennington III             {
4265acaca2fSWilliam A. Kennington III                 return rv;
4275acaca2fSWilliam A. Kennington III             }
4285acaca2fSWilliam A. Kennington III             hash_start += hash_size;
4295acaca2fSWilliam A. Kennington III         } while (hash_start != region->region_offset + region->region_size);
4305acaca2fSWilliam A. Kennington III     }
4315acaca2fSWilliam A. Kennington III     rv = intf->hash_final((void*)ctx, (uint8_t*)dcrypto_digest);
4325acaca2fSWilliam A. Kennington III 
4335acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
4345acaca2fSWilliam A. Kennington III     {
4355acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
4365acaca2fSWilliam A. Kennington III     }
4375acaca2fSWilliam A. Kennington III 
4386084957fSPatrick Williams     if (memcmp(magic_and_digest + MEMBER_SIZE(struct hash_sha256, hash_magic),
439*027c042eSDan Zhang                dcrypto_digest, digest_size) != 0)
4405acaca2fSWilliam A. Kennington III     {
441dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid hash\n", __FUNCTION__);
4425acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_HASH;
4435acaca2fSWilliam A. Kennington III     }
4445acaca2fSWilliam A. Kennington III     // Image is valid.
4455acaca2fSWilliam A. Kennington III     return LIBCR51SIGN_SUCCESS;
4465acaca2fSWilliam A. Kennington III }
4475acaca2fSWilliam A. Kennington III 
4485acaca2fSWilliam A. Kennington III // Create empty image_regions to pass to validate_payload_regions
449dca92e47SWilly Tu // Support validate_payload_regions_helper to remove image_regions as a required
450dca92e47SWilly Tu // input.
4515acaca2fSWilliam A. Kennington III 
452c66ebc35SPatrick Williams static failure_reason allocate_and_validate_payload_regions(
453c66ebc35SPatrick Williams     const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
4545acaca2fSWilliam A. Kennington III     uint32_t d_offset)
4555acaca2fSWilliam A. Kennington III {
4565acaca2fSWilliam A. Kennington III     struct libcr51sign_validated_regions image_regions;
4575acaca2fSWilliam A. Kennington III     return validate_payload_regions(ctx, intf, d_offset, &image_regions);
4585acaca2fSWilliam A. Kennington III }
4595acaca2fSWilliam A. Kennington III 
460dca92e47SWilly Tu // Wrapper around validate_payload_regions to allow nullptr for image_regions.
461dca92e47SWilly Tu // Calls allocate_and_validate_payload_regions when image_regions is nullptr to
462dca92e47SWilly Tu // create placer holder image_regions.
4635acaca2fSWilliam A. Kennington III 
4645acaca2fSWilliam A. Kennington III static failure_reason validate_payload_regions_helper(
4655acaca2fSWilliam A. Kennington III     const struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
4665acaca2fSWilliam A. Kennington III     uint32_t d_offset, struct libcr51sign_validated_regions* image_regions)
4675acaca2fSWilliam A. Kennington III {
4685acaca2fSWilliam A. Kennington III     if (image_regions)
4695acaca2fSWilliam A. Kennington III     {
4705acaca2fSWilliam A. Kennington III         return validate_payload_regions(ctx, intf, d_offset, image_regions);
4715acaca2fSWilliam A. Kennington III     }
4725acaca2fSWilliam A. Kennington III 
4735acaca2fSWilliam A. Kennington III     return allocate_and_validate_payload_regions(ctx, intf, d_offset);
4745acaca2fSWilliam A. Kennington III }
4755acaca2fSWilliam A. Kennington III 
4765acaca2fSWilliam A. Kennington III // Check if the given signature_scheme is supported.
4775acaca2fSWilliam A. Kennington III // Returns nonzero on error, zero on success
4785acaca2fSWilliam A. Kennington III 
4796c41aba5SPatrick Williams static failure_reason is_signature_scheme_supported(
4806c41aba5SPatrick Williams     enum signature_scheme scheme)
4815acaca2fSWilliam A. Kennington III {
4825acaca2fSWilliam A. Kennington III     switch (scheme)
4835acaca2fSWilliam A. Kennington III     {
4845acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA2048_PKCS15:
4855acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA3072_PKCS15:
4865acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15:
4875acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15_SHA512:
4885acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
4895acaca2fSWilliam A. Kennington III         default:
4905acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
4915acaca2fSWilliam A. Kennington III     }
4925acaca2fSWilliam A. Kennington III }
4935acaca2fSWilliam A. Kennington III 
4945acaca2fSWilliam A. Kennington III // Returns size of signature struct size in |size|
4955acaca2fSWilliam A. Kennington III // Returns nonzero on error, zero on success
4965acaca2fSWilliam A. Kennington III 
4976c41aba5SPatrick Williams static failure_reason get_signature_struct_size(enum signature_scheme scheme,
4986c41aba5SPatrick Williams                                                 uint32_t* size)
4995acaca2fSWilliam A. Kennington III {
5005acaca2fSWilliam A. Kennington III     switch (scheme)
5015acaca2fSWilliam A. Kennington III     {
5025acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA2048_PKCS15:
5035acaca2fSWilliam A. Kennington III             *size = sizeof(struct signature_rsa2048_pkcs15);
5045acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5055acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA3072_PKCS15:
5065acaca2fSWilliam A. Kennington III             *size = sizeof(struct signature_rsa3072_pkcs15);
5075acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5085acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15:
5095acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15_SHA512:
5105acaca2fSWilliam A. Kennington III             *size = sizeof(struct signature_rsa4096_pkcs15);
5115acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5125acaca2fSWilliam A. Kennington III         default:
5135acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
5145acaca2fSWilliam A. Kennington III     }
5155acaca2fSWilliam A. Kennington III }
5165acaca2fSWilliam A. Kennington III 
5176c41aba5SPatrick Williams static failure_reason get_signature_field_offset(enum signature_scheme scheme,
5186c41aba5SPatrick Williams                                                  uint32_t* offset)
5195acaca2fSWilliam A. Kennington III {
5205acaca2fSWilliam A. Kennington III     switch (scheme)
5215acaca2fSWilliam A. Kennington III     {
5225acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA2048_PKCS15:
5235acaca2fSWilliam A. Kennington III             *offset = offsetof(struct signature_rsa2048_pkcs15, signature);
5245acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5255acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA3072_PKCS15:
5265acaca2fSWilliam A. Kennington III             *offset = offsetof(struct signature_rsa3072_pkcs15, signature);
5275acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5285acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15:
5295acaca2fSWilliam A. Kennington III         case SIGNATURE_RSA4096_PKCS15_SHA512:
5305acaca2fSWilliam A. Kennington III             *offset = offsetof(struct signature_rsa4096_pkcs15, signature);
5315acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
5325acaca2fSWilliam A. Kennington III         default:
5335acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME;
5345acaca2fSWilliam A. Kennington III     }
5355acaca2fSWilliam A. Kennington III }
5365acaca2fSWilliam A. Kennington III 
537*027c042eSDan Zhang __attribute__((nonnull)) static bool is_key_in_signature_struct_trusted(
538*027c042eSDan Zhang     const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
539*027c042eSDan Zhang     enum signature_scheme scheme, uint32_t raw_signature_offset,
540*027c042eSDan Zhang     void* signature_struct, uint32_t* signature_struct_size)
541*027c042eSDan Zhang {
542*027c042eSDan Zhang     if (!intf->trust_key_in_signature_structure)
543*027c042eSDan Zhang     {
544*027c042eSDan Zhang         CPRINTS(ctx, "%s: trust_key_in_signature_structure is not supported\n",
545*027c042eSDan Zhang                 __FUNCTION__);
546*027c042eSDan Zhang         return false;
547*027c042eSDan Zhang     }
548*027c042eSDan Zhang 
549*027c042eSDan Zhang     uint32_t signature_field_offset;
550*027c042eSDan Zhang     int rv = get_signature_field_offset(scheme, &signature_field_offset);
551*027c042eSDan Zhang     if (rv != LIBCR51SIGN_SUCCESS)
552*027c042eSDan Zhang     {
553*027c042eSDan Zhang         return false;
554*027c042eSDan Zhang     }
555*027c042eSDan Zhang 
556*027c042eSDan Zhang     if (signature_field_offset > raw_signature_offset)
557*027c042eSDan Zhang     {
558*027c042eSDan Zhang         CPRINTS(ctx,
559*027c042eSDan Zhang                 "%s: signature_field_offset (%d) is larger than "
560*027c042eSDan Zhang                 "raw_signature_offset (%d)\n",
561*027c042eSDan Zhang                 __FUNCTION__, signature_field_offset, raw_signature_offset);
562*027c042eSDan Zhang         return false;
563*027c042eSDan Zhang     }
564*027c042eSDan Zhang     uint32_t signature_offset = raw_signature_offset - signature_field_offset;
565*027c042eSDan Zhang 
566*027c042eSDan Zhang     rv = get_signature_struct_size(scheme, signature_struct_size);
567*027c042eSDan Zhang     if (rv != LIBCR51SIGN_SUCCESS)
568*027c042eSDan Zhang     {
569*027c042eSDan Zhang         return false;
570*027c042eSDan Zhang     }
571*027c042eSDan Zhang 
572*027c042eSDan Zhang     rv = intf->read(ctx, signature_offset, *signature_struct_size,
573*027c042eSDan Zhang                     signature_struct);
574*027c042eSDan Zhang     if (rv != LIBCR51SIGN_SUCCESS)
575*027c042eSDan Zhang     {
576*027c042eSDan Zhang         CPRINTS(ctx, "%s: failed to read signature (status = %d)\n",
577*027c042eSDan Zhang                 __FUNCTION__, rv);
578*027c042eSDan Zhang         return false;
579*027c042eSDan Zhang     }
580*027c042eSDan Zhang 
581*027c042eSDan Zhang     return intf->trust_key_in_signature_structure(ctx, scheme, signature_struct,
582*027c042eSDan Zhang                                                   *signature_struct_size);
583*027c042eSDan Zhang }
584*027c042eSDan Zhang // Validates the signature with verification key provided along with the
585*027c042eSDan Zhang // signature if the key is trusted.
586*027c042eSDan Zhang 
587*027c042eSDan Zhang static bool validate_signature_with_key_in_signature_struct(
588*027c042eSDan Zhang     const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
589*027c042eSDan Zhang     enum signature_scheme scheme, uint32_t raw_signature_offset,
590*027c042eSDan Zhang     const uint8_t* digest, uint32_t digest_size)
591*027c042eSDan Zhang {
592*027c042eSDan Zhang     // pick the biggest signature struct size.
593*027c042eSDan Zhang     uint8_t signature_struct[sizeof(struct signature_rsa4096_pkcs15)];
594*027c042eSDan Zhang     uint32_t signature_struct_size = sizeof(signature_struct);
595*027c042eSDan Zhang     if (!is_key_in_signature_struct_trusted(
596*027c042eSDan Zhang             ctx, intf, scheme, raw_signature_offset, &signature_struct,
597*027c042eSDan Zhang             &signature_struct_size))
598*027c042eSDan Zhang     {
599*027c042eSDan Zhang         CPRINTS(ctx, "%s: key in signature struct is not trusted\n",
600*027c042eSDan Zhang                 __FUNCTION__);
601*027c042eSDan Zhang         return false;
602*027c042eSDan Zhang     }
603*027c042eSDan Zhang     if (!intf->verify_rsa_signature_with_modulus_and_exponent)
604*027c042eSDan Zhang     {
605*027c042eSDan Zhang         CPRINTS(
606*027c042eSDan Zhang             ctx,
607*027c042eSDan Zhang             "%s: verify_rsa_signature_with_modulus_and_exponent is not supported\n",
608*027c042eSDan Zhang             __FUNCTION__);
609*027c042eSDan Zhang         return false;
610*027c042eSDan Zhang     }
611*027c042eSDan Zhang 
612*027c042eSDan Zhang     switch (scheme)
613*027c042eSDan Zhang     {
614*027c042eSDan Zhang         case SIGNATURE_RSA2048_PKCS15:
615*027c042eSDan Zhang         {
616*027c042eSDan Zhang             struct signature_rsa2048_pkcs15* sig =
617*027c042eSDan Zhang                 (struct signature_rsa2048_pkcs15*)signature_struct;
618*027c042eSDan Zhang             return intf->verify_rsa_signature_with_modulus_and_exponent(
619*027c042eSDan Zhang                 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
620*027c042eSDan Zhang                 sig->signature, sizeof(sig->signature), digest, digest_size);
621*027c042eSDan Zhang         }
622*027c042eSDan Zhang         break;
623*027c042eSDan Zhang         case SIGNATURE_RSA3072_PKCS15:
624*027c042eSDan Zhang         {
625*027c042eSDan Zhang             struct signature_rsa3072_pkcs15* sig =
626*027c042eSDan Zhang                 (struct signature_rsa3072_pkcs15*)signature_struct;
627*027c042eSDan Zhang             return intf->verify_rsa_signature_with_modulus_and_exponent(
628*027c042eSDan Zhang                 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
629*027c042eSDan Zhang                 sig->signature, sizeof(sig->signature), digest, digest_size);
630*027c042eSDan Zhang         }
631*027c042eSDan Zhang         break;
632*027c042eSDan Zhang         case SIGNATURE_RSA4096_PKCS15:
633*027c042eSDan Zhang         case SIGNATURE_RSA4096_PKCS15_SHA512:
634*027c042eSDan Zhang         {
635*027c042eSDan Zhang             struct signature_rsa4096_pkcs15* sig =
636*027c042eSDan Zhang                 (struct signature_rsa4096_pkcs15*)signature_struct;
637*027c042eSDan Zhang             return intf->verify_rsa_signature_with_modulus_and_exponent(
638*027c042eSDan Zhang                 ctx, scheme, sig->modulus, sizeof(sig->modulus), sig->exponent,
639*027c042eSDan Zhang                 sig->signature, sizeof(sig->signature), digest, digest_size);
640*027c042eSDan Zhang         }
641*027c042eSDan Zhang         break;
642*027c042eSDan Zhang         default:
643*027c042eSDan Zhang             CPRINTS(ctx, "%s: unsupported signature scheme %d\n", __FUNCTION__,
644*027c042eSDan Zhang                     scheme);
645*027c042eSDan Zhang             return false;
646*027c042eSDan Zhang     }
647*027c042eSDan Zhang }
648*027c042eSDan Zhang 
6495acaca2fSWilliam A. Kennington III // Validates the signature (of type scheme) read from "device" at
6505acaca2fSWilliam A. Kennington III //"raw_signature_offset" with "public_key" over a SHA256/SHA512 digest of
6515acaca2fSWilliam A. Kennington III // EEPROM area "data_offset:data_size".
6525acaca2fSWilliam A. Kennington III 
653c66ebc35SPatrick Williams static failure_reason validate_signature(
654c66ebc35SPatrick Williams     const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
655c66ebc35SPatrick Williams     uint32_t data_offset, uint32_t data_size, enum signature_scheme scheme,
6565acaca2fSWilliam A. Kennington III     uint32_t raw_signature_offset)
6575acaca2fSWilliam A. Kennington III {
6585acaca2fSWilliam A. Kennington III     uint8_t signature[LIBCR51SIGN_MAX_SIGNATURE_SIZE];
6595acaca2fSWilliam A. Kennington III     uint16_t key_size;
6605acaca2fSWilliam A. Kennington III     uint32_t digest_size;
6615acaca2fSWilliam A. Kennington III     uint8_t dcrypto_digest[LIBCR51SIGN_SHA512_DIGEST_SIZE];
6625acaca2fSWilliam A. Kennington III     int rv;
6635acaca2fSWilliam A. Kennington III     enum hash_type hash_type;
6645acaca2fSWilliam A. Kennington III 
6655acaca2fSWilliam A. Kennington III     if (!intf->hash_init)
6665acaca2fSWilliam A. Kennington III     {
667dca92e47SWilly Tu         CPRINTS(ctx, "%s: missing hash_init\n", __FUNCTION__);
6685acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
6695acaca2fSWilliam A. Kennington III     }
6705acaca2fSWilliam A. Kennington III     rv = get_hash_type_from_signature(scheme, &hash_type);
6715acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
6725acaca2fSWilliam A. Kennington III     {
673dca92e47SWilly Tu         CPRINTS(ctx, "%s: hash_type from signature failed\n", __FUNCTION__);
6745acaca2fSWilliam A. Kennington III         return rv;
6755acaca2fSWilliam A. Kennington III     }
6765acaca2fSWilliam A. Kennington III     rv = intf->hash_init(ctx, hash_type);
6775acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
6785acaca2fSWilliam A. Kennington III     {
679dca92e47SWilly Tu         CPRINTS(ctx, "%s: hash_init failed\n", __FUNCTION__);
6805acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
6815acaca2fSWilliam A. Kennington III     }
6825acaca2fSWilliam A. Kennington III     rv = read_and_hash_update(ctx, intf, data_offset, data_size);
6835acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
6845acaca2fSWilliam A. Kennington III     {
685dca92e47SWilly Tu         CPRINTS(ctx, "%s: hash_update failed\n", __FUNCTION__);
6865acaca2fSWilliam A. Kennington III         return rv;
6875acaca2fSWilliam A. Kennington III     }
6885acaca2fSWilliam A. Kennington III     if (!intf->hash_final)
6895acaca2fSWilliam A. Kennington III     {
690dca92e47SWilly Tu         CPRINTS(ctx, "%s: missing hash_final\n", __FUNCTION__);
6915acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
6925acaca2fSWilliam A. Kennington III     }
6935acaca2fSWilliam A. Kennington III     rv = intf->hash_final((void*)ctx, dcrypto_digest);
6945acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
6955acaca2fSWilliam A. Kennington III     {
696dca92e47SWilly Tu         CPRINTS(ctx, "%s: hash_final failed (status = %d)\n", __FUNCTION__, rv);
6975acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
6985acaca2fSWilliam A. Kennington III     }
699*027c042eSDan Zhang 
700*027c042eSDan Zhang     rv = get_hash_digest_size(hash_type, &digest_size);
701*027c042eSDan Zhang     if (rv != LIBCR51SIGN_SUCCESS)
702*027c042eSDan Zhang     {
703*027c042eSDan Zhang         return rv;
704*027c042eSDan Zhang     }
705*027c042eSDan Zhang 
706*027c042eSDan Zhang     if (intf->trust_descriptor_hash)
707*027c042eSDan Zhang     {
708*027c042eSDan Zhang         if (intf->trust_descriptor_hash(ctx, dcrypto_digest, digest_size))
709*027c042eSDan Zhang         {
710*027c042eSDan Zhang             CPRINTS(ctx, "%s: descriptor hash trusted\n", __FUNCTION__);
711*027c042eSDan Zhang             return LIBCR51SIGN_SUCCESS;
712*027c042eSDan Zhang         }
713*027c042eSDan Zhang     }
714*027c042eSDan Zhang 
7155acaca2fSWilliam A. Kennington III     rv = get_key_size(scheme, &key_size);
7165acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
7175acaca2fSWilliam A. Kennington III     {
7185acaca2fSWilliam A. Kennington III         return rv;
7195acaca2fSWilliam A. Kennington III     }
7205acaca2fSWilliam A. Kennington III 
7215acaca2fSWilliam A. Kennington III     rv = intf->read(ctx, raw_signature_offset, key_size, signature);
7225acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
7235acaca2fSWilliam A. Kennington III     {
724dca92e47SWilly Tu         CPRINTS(ctx, "%s: failed to read signature (status = %d)\n",
725dca92e47SWilly Tu                 __FUNCTION__, rv);
7265acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
7275acaca2fSWilliam A. Kennington III     }
728*027c042eSDan Zhang 
729*027c042eSDan Zhang     if (validate_signature_with_key_in_signature_struct(
730*027c042eSDan Zhang             ctx, intf, scheme, raw_signature_offset, dcrypto_digest,
731*027c042eSDan Zhang             digest_size))
732*027c042eSDan Zhang     {
733*027c042eSDan Zhang         CPRINTS(ctx, "%s: verification with external key succeeded\n",
734*027c042eSDan Zhang                 __FUNCTION__);
735*027c042eSDan Zhang         return LIBCR51SIGN_SUCCESS;
736*027c042eSDan Zhang     }
737*027c042eSDan Zhang 
7385acaca2fSWilliam A. Kennington III     if (!intf->verify_signature)
7395acaca2fSWilliam A. Kennington III     {
740dca92e47SWilly Tu         CPRINTS(ctx, "%s: missing verify_signature\n", __FUNCTION__);
7415acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
7425acaca2fSWilliam A. Kennington III     }
743*027c042eSDan Zhang 
7445acaca2fSWilliam A. Kennington III     rv = intf->verify_signature(ctx, scheme, signature, key_size,
7455acaca2fSWilliam A. Kennington III                                 dcrypto_digest, digest_size);
7465acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
7475acaca2fSWilliam A. Kennington III     {
748dca92e47SWilly Tu         CPRINTS(ctx, "%s: verification failed (status = %d)\n", __FUNCTION__,
7495acaca2fSWilliam A. Kennington III                 rv);
7505acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_SIGNATURE;
7515acaca2fSWilliam A. Kennington III     }
752dca92e47SWilly Tu     CPRINTS(ctx, "%s: verification succeeded\n", __FUNCTION__);
7535acaca2fSWilliam A. Kennington III     return LIBCR51SIGN_SUCCESS;
7545acaca2fSWilliam A. Kennington III }
7555acaca2fSWilliam A. Kennington III 
7565acaca2fSWilliam A. Kennington III // Sanity checks the image descriptor & validates its signature.
7575acaca2fSWilliam A. Kennington III // This function does not validate the image_region array or image hash.
7585acaca2fSWilliam A. Kennington III //
7595acaca2fSWilliam A. Kennington III //@param[in] ctx  context which describes the image and holds opaque private
7605acaca2fSWilliam A. Kennington III //                 data for the user of the library
7615acaca2fSWilliam A. Kennington III //@param[in] intf  function pointers which interface to the current system
7625acaca2fSWilliam A. Kennington III // and environment
7635acaca2fSWilliam A. Kennington III //@param offset  Absolute image descriptor flash offset.
7645acaca2fSWilliam A. Kennington III //@param relative_offset  Image descriptor offset relative to image start.
765af46bea6SWilliam A. Kennington III //@param max_size Maximum size of the flash space in bytes.
766dca92e47SWilly Tu //@param[out] payload_blob_offset  Absolute offset of BLOB data in image
767dca92e47SWilly Tu //                                 descriptor (if BLOB data is present)
768c66ebc35SPatrick Williams static failure_reason validate_descriptor(
769c66ebc35SPatrick Williams     const struct libcr51sign_ctx* ctx, const struct libcr51sign_intf* intf,
770c66ebc35SPatrick Williams     uint32_t offset, uint32_t relative_offset, uint32_t max_size,
771dca92e47SWilly Tu     uint32_t* const restrict payload_blob_offset)
7725acaca2fSWilliam A. Kennington III {
7735acaca2fSWilliam A. Kennington III     uint32_t max_descriptor_size, signed_size, signature_scheme,
7745acaca2fSWilliam A. Kennington III         signature_offset;
7756084957fSPatrick Williams     uint32_t signature_struct_offset, signature_struct_size, hash_struct_size;
7765acaca2fSWilliam A. Kennington III     int rv;
7775acaca2fSWilliam A. Kennington III 
778af46bea6SWilliam A. Kennington III     max_descriptor_size = max_size - relative_offset;
779af46bea6SWilliam A. Kennington III     if (max_size < relative_offset ||
7805acaca2fSWilliam A. Kennington III         max_descriptor_size < sizeof(struct image_descriptor))
7815acaca2fSWilliam A. Kennington III     {
782dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid arguments\n", __FUNCTION__);
7835acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
7845acaca2fSWilliam A. Kennington III     }
7855acaca2fSWilliam A. Kennington III 
7865acaca2fSWilliam A. Kennington III     rv = intf->read(ctx, offset, sizeof(ctx->descriptor),
7875acaca2fSWilliam A. Kennington III                     (uint8_t*)&ctx->descriptor);
7885acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
7895acaca2fSWilliam A. Kennington III     {
790dca92e47SWilly Tu         CPRINTS(ctx, "%s: failed to read descriptor\n", __FUNCTION__);
7915acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_RUNTIME_FAILURE;
7925acaca2fSWilliam A. Kennington III     }
7935acaca2fSWilliam A. Kennington III     if (ctx->descriptor.descriptor_magic != DESCRIPTOR_MAGIC ||
7945acaca2fSWilliam A. Kennington III         ctx->descriptor.descriptor_offset != relative_offset ||
7955acaca2fSWilliam A. Kennington III         ctx->descriptor.region_count == 0 ||
7965acaca2fSWilliam A. Kennington III         ctx->descriptor.descriptor_area_size > max_descriptor_size ||
797af46bea6SWilliam A. Kennington III         ctx->descriptor.image_size > max_size)
7985acaca2fSWilliam A. Kennington III     {
799dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid descriptor\n", __FUNCTION__);
800af46bea6SWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
801af46bea6SWilliam A. Kennington III     }
802af46bea6SWilliam A. Kennington III     if (intf->image_size_valid == NULL)
803af46bea6SWilliam A. Kennington III     {
804dca92e47SWilly Tu         // Preserve original behavior of requiring exact image_size match if no
805dca92e47SWilly Tu         // operator is provided.
806af46bea6SWilliam A. Kennington III         if (ctx->descriptor.image_size != max_size)
807af46bea6SWilliam A. Kennington III         {
808dca92e47SWilly Tu             CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
809af46bea6SWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
810af46bea6SWilliam A. Kennington III         }
811af46bea6SWilliam A. Kennington III     }
812af46bea6SWilliam A. Kennington III     else if (!intf->image_size_valid(ctx->descriptor.image_size))
813af46bea6SWilliam A. Kennington III     {
814dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid image size\n", __FUNCTION__);
8155acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
8165acaca2fSWilliam A. Kennington III     }
8175acaca2fSWilliam A. Kennington III     if (ctx->descriptor.image_type != IMAGE_DEV &&
8185acaca2fSWilliam A. Kennington III         ctx->descriptor.image_type != IMAGE_PROD &&
8195acaca2fSWilliam A. Kennington III         ctx->descriptor.image_type != IMAGE_BREAKOUT &&
8205acaca2fSWilliam A. Kennington III         ctx->descriptor.image_type != IMAGE_TEST &&
8215acaca2fSWilliam A. Kennington III         ctx->descriptor.image_type != IMAGE_UNSIGNED_INTEGRITY)
8225acaca2fSWilliam A. Kennington III     {
823dca92e47SWilly Tu         CPRINTS(ctx, "%s: bad image type\n", __FUNCTION__);
8245acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
8255acaca2fSWilliam A. Kennington III     }
8265acaca2fSWilliam A. Kennington III     // Although the image_descriptor struct supports unauthenticated
8275acaca2fSWilliam A. Kennington III     // images, Haven will not allow it.
8285acaca2fSWilliam A. Kennington III     // Haven only supports SHA256 + RSA2048/RSA3072_PKCS15 currently.
8295acaca2fSWilliam A. Kennington III 
8305acaca2fSWilliam A. Kennington III     signature_scheme = ctx->descriptor.signature_scheme;
8315acaca2fSWilliam A. Kennington III 
8325acaca2fSWilliam A. Kennington III     rv = is_signature_scheme_supported(signature_scheme);
8335acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
8345acaca2fSWilliam A. Kennington III     {
8355acaca2fSWilliam A. Kennington III         return rv;
8365acaca2fSWilliam A. Kennington III     }
8375acaca2fSWilliam A. Kennington III     rv = is_hash_type_supported(ctx->descriptor.hash_type);
8385acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
8395acaca2fSWilliam A. Kennington III     {
840dca92e47SWilly Tu         CPRINTS(ctx, "%s: invalid hash type\n", __FUNCTION__);
8415acaca2fSWilliam A. Kennington III         return rv;
8425acaca2fSWilliam A. Kennington III     }
8435acaca2fSWilliam A. Kennington III     if (ctx->descriptor.descriptor_major > MAX_MAJOR_VERSION ||
8445acaca2fSWilliam A. Kennington III         ctx->descriptor.region_count > LIBCR51SIGN_MAX_REGION_COUNT)
8455acaca2fSWilliam A. Kennington III     {
846dca92e47SWilly Tu         CPRINTS(ctx, "%s: unsupported descriptor\n", __FUNCTION__);
8475acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR;
8485acaca2fSWilliam A. Kennington III     }
8496084957fSPatrick Williams     rv = get_signature_struct_size(signature_scheme, &signature_struct_size);
8505acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
8515acaca2fSWilliam A. Kennington III     {
8525acaca2fSWilliam A. Kennington III         return rv;
8535acaca2fSWilliam A. Kennington III     }
8545acaca2fSWilliam A. Kennington III 
8555acaca2fSWilliam A. Kennington III     // Compute the size of the signed portion of the image descriptor.
8562be45238SPatrick Williams     signed_size = sizeof(struct image_descriptor) +
8576084957fSPatrick Williams                   ctx->descriptor.region_count * sizeof(struct image_region);
8585acaca2fSWilliam A. Kennington III     rv = get_hash_struct_size(ctx->descriptor.hash_type, &hash_struct_size);
8595acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
8605acaca2fSWilliam A. Kennington III     {
8615acaca2fSWilliam A. Kennington III         return rv;
8625acaca2fSWilliam A. Kennington III     }
8635acaca2fSWilliam A. Kennington III     signed_size += hash_struct_size;
8645acaca2fSWilliam A. Kennington III     if (ctx->descriptor.denylist_size)
8655acaca2fSWilliam A. Kennington III     {
8665acaca2fSWilliam A. Kennington III         signed_size += sizeof(struct denylist);
8672be45238SPatrick Williams         signed_size += ctx->descriptor.denylist_size *
8682be45238SPatrick Williams                        sizeof(struct denylist_record);
8695acaca2fSWilliam A. Kennington III     }
8705acaca2fSWilliam A. Kennington III     if (ctx->descriptor.blob_size)
8715acaca2fSWilliam A. Kennington III     {
872dca92e47SWilly Tu         *payload_blob_offset = offset + signed_size;
8735acaca2fSWilliam A. Kennington III         signed_size += sizeof(struct blob);
8745acaca2fSWilliam A. Kennington III         // Previous additions are guaranteed not to overflow.
875dca92e47SWilly Tu         if ((ctx->descriptor.blob_size >
876dca92e47SWilly Tu              ctx->descriptor.descriptor_area_size - signed_size) ||
877dca92e47SWilly Tu             // Sanity check blob size
878dca92e47SWilly Tu             (ctx->descriptor.blob_size < sizeof(struct blob_data)))
8795acaca2fSWilliam A. Kennington III         {
880dca92e47SWilly Tu             CPRINTS(ctx, "%s: invalid blob size (0x%x)\n", __FUNCTION__,
8815acaca2fSWilliam A. Kennington III                     ctx->descriptor.blob_size);
8825acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
8835acaca2fSWilliam A. Kennington III         }
8845acaca2fSWilliam A. Kennington III         signed_size += ctx->descriptor.blob_size;
8855acaca2fSWilliam A. Kennington III     }
8865acaca2fSWilliam A. Kennington III     if (signature_struct_size >
8875acaca2fSWilliam A. Kennington III         ctx->descriptor.descriptor_area_size - signed_size)
8885acaca2fSWilliam A. Kennington III     {
8895acaca2fSWilliam A. Kennington III         CPRINTS(ctx,
890dca92e47SWilly Tu                 "%s: invalid descriptor area size "
891af46bea6SWilliam A. Kennington III                 "(expected = 0x%x, actual = 0x%x)\n",
892dca92e47SWilly Tu                 __FUNCTION__, ctx->descriptor.descriptor_area_size,
8935acaca2fSWilliam A. Kennington III                 signed_size + signature_struct_size);
8945acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR;
8955acaca2fSWilliam A. Kennington III     }
8965acaca2fSWilliam A. Kennington III     signature_struct_offset = signed_size;
8975acaca2fSWilliam A. Kennington III     // Omit the actual signature.
8985acaca2fSWilliam A. Kennington III     rv = get_signature_field_offset(signature_scheme, &signature_offset);
8995acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
9005acaca2fSWilliam A. Kennington III     {
9015acaca2fSWilliam A. Kennington III         return rv;
9025acaca2fSWilliam A. Kennington III     }
9035acaca2fSWilliam A. Kennington III     signed_size += signature_offset;
9045acaca2fSWilliam A. Kennington III 
9055acaca2fSWilliam A. Kennington III     // Lookup key & validate transition.
9065acaca2fSWilliam A. Kennington III     rv = validate_transition(ctx, intf, offset + signature_struct_offset);
9075acaca2fSWilliam A. Kennington III 
9085acaca2fSWilliam A. Kennington III     if (rv != LIBCR51SIGN_SUCCESS)
9095acaca2fSWilliam A. Kennington III     {
9105acaca2fSWilliam A. Kennington III         return rv;
9115acaca2fSWilliam A. Kennington III     }
9126084957fSPatrick Williams     return validate_signature(ctx, intf, offset, signed_size, signature_scheme,
9136084957fSPatrick Williams                               offset + signed_size);
9145acaca2fSWilliam A. Kennington III }
9155acaca2fSWilliam A. Kennington III 
9165acaca2fSWilliam A. Kennington III // Scans the external EEPROM for a magic value at "alignment" boundaries.
9175acaca2fSWilliam A. Kennington III //
9185acaca2fSWilliam A. Kennington III //@param device  Handle to the external EEPROM.
9195acaca2fSWilliam A. Kennington III //@param magic   8-byte pattern to search for.
9205acaca2fSWilliam A. Kennington III //@param start_offset  Offset to begin searching at.
9215acaca2fSWilliam A. Kennington III //@param limit   Exclusive address (e.g. EEPROM size).
9225acaca2fSWilliam A. Kennington III //@param alignment   Alignment boundaries (POW2) to search on.
9235acaca2fSWilliam A. Kennington III //@param header_offset   Location to place the new header offset.
9245acaca2fSWilliam A. Kennington III //@return LIBCR51SIGN_SUCCESS (or non-zero on error).
9255acaca2fSWilliam A. Kennington III 
926*027c042eSDan Zhang static int scan_for_magic_8(const struct libcr51sign_ctx* ctx,
9275acaca2fSWilliam A. Kennington III                             const struct libcr51sign_intf* intf, uint64_t magic,
928*027c042eSDan Zhang                             uint32_t start_offset, uint32_t limit,
929*027c042eSDan Zhang                             uint32_t alignment, uint32_t* header_offset)
9305acaca2fSWilliam A. Kennington III {
9315acaca2fSWilliam A. Kennington III     uint64_t read_data;
9325acaca2fSWilliam A. Kennington III     uint32_t offset;
9335acaca2fSWilliam A. Kennington III     int rv;
9345acaca2fSWilliam A. Kennington III 
9355acaca2fSWilliam A. Kennington III     if (limit <= start_offset || limit > ctx->end_offset ||
9365acaca2fSWilliam A. Kennington III         limit < sizeof(magic) || !POWER_OF_TWO(alignment))
9375acaca2fSWilliam A. Kennington III     {
9385acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_ARGUMENT;
9395acaca2fSWilliam A. Kennington III     }
9405acaca2fSWilliam A. Kennington III 
9415acaca2fSWilliam A. Kennington III     if (!intf->read)
9425acaca2fSWilliam A. Kennington III     {
943dca92e47SWilly Tu         CPRINTS(ctx, "%s: missing intf->read\n", __FUNCTION__);
9445acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
9455acaca2fSWilliam A. Kennington III     }
9465acaca2fSWilliam A. Kennington III     // Align start_offset to the next valid boundary.
9475acaca2fSWilliam A. Kennington III     start_offset = ((start_offset - 1) & ~(alignment - 1)) + alignment;
9485acaca2fSWilliam A. Kennington III     for (offset = start_offset; offset < limit - sizeof(magic);
9495acaca2fSWilliam A. Kennington III          offset += alignment)
9505acaca2fSWilliam A. Kennington III     {
9515acaca2fSWilliam A. Kennington III         rv = intf->read((void*)ctx, offset, sizeof(read_data),
9525acaca2fSWilliam A. Kennington III                         (uint8_t*)&read_data);
9535acaca2fSWilliam A. Kennington III         if (rv != LIBCR51SIGN_SUCCESS)
9545acaca2fSWilliam A. Kennington III         {
9555acaca2fSWilliam A. Kennington III             return rv;
9565acaca2fSWilliam A. Kennington III         }
9575acaca2fSWilliam A. Kennington III         if (read_data == magic)
9585acaca2fSWilliam A. Kennington III         {
9595acaca2fSWilliam A. Kennington III             if (header_offset)
9605acaca2fSWilliam A. Kennington III             {
9615acaca2fSWilliam A. Kennington III                 *header_offset = offset;
9625acaca2fSWilliam A. Kennington III             }
9635acaca2fSWilliam A. Kennington III             return LIBCR51SIGN_SUCCESS;
9645acaca2fSWilliam A. Kennington III         }
9655acaca2fSWilliam A. Kennington III     }
9665acaca2fSWilliam A. Kennington III     // Failed to locate magic.
9675acaca2fSWilliam A. Kennington III     return LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC;
9685acaca2fSWilliam A. Kennington III }
9695acaca2fSWilliam A. Kennington III 
9705acaca2fSWilliam A. Kennington III // Check whether the signature on the image is valid.
9715acaca2fSWilliam A. Kennington III // Validates the authenticity of an EEPROM image. Scans for & validates the
972dca92e47SWilly Tu // signature on the image descriptor. If the descriptor validates, hashes the
973dca92e47SWilly Tu // rest of the image to verify its integrity.
9745acaca2fSWilliam A. Kennington III //
975dca92e47SWilly Tu // @param[in] ctx - context which describes the image and holds opaque private
9765acaca2fSWilliam A. Kennington III //                 data for the user of the library
9775acaca2fSWilliam A. Kennington III // @param[in] intf - function pointers which interface to the current system
9785acaca2fSWilliam A. Kennington III //                  and environment
979dca92e47SWilly Tu // @param[out] image_regions - image_region pointer to an array for the output
980dca92e47SWilly Tu //
9815acaca2fSWilliam A. Kennington III // @return nonzero on error, zero on success
9825acaca2fSWilliam A. Kennington III 
983c66ebc35SPatrick Williams failure_reason libcr51sign_validate(
984*027c042eSDan Zhang     struct libcr51sign_ctx* ctx, struct libcr51sign_intf* intf,
9855acaca2fSWilliam A. Kennington III     struct libcr51sign_validated_regions* image_regions)
9865acaca2fSWilliam A. Kennington III {
9875acaca2fSWilliam A. Kennington III     int rv, rv_first_desc = LIBCR51SIGN_SUCCESS;
9885acaca2fSWilliam A. Kennington III     uint32_t descriptor_offset;
989dca92e47SWilly Tu     uint32_t payload_blob_offset = 0;
9905acaca2fSWilliam A. Kennington III 
9915acaca2fSWilliam A. Kennington III     if (!ctx)
9925acaca2fSWilliam A. Kennington III     {
993dca92e47SWilly Tu         CPRINTS(ctx, "%s: Missing context\n", __FUNCTION__);
9945acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_CONTEXT;
9955acaca2fSWilliam A. Kennington III     }
996*027c042eSDan Zhang     if (!intf)
9975acaca2fSWilliam A. Kennington III     {
998dca92e47SWilly Tu         CPRINTS(ctx, "%s: Missing interface\n", __FUNCTION__);
9995acaca2fSWilliam A. Kennington III         return LIBCR51SIGN_ERROR_INVALID_INTERFACE;
10005acaca2fSWilliam A. Kennington III     }
10015acaca2fSWilliam A. Kennington III 
1002*027c042eSDan Zhang     ctx->validation_state = LIBCR51SIGN_IMAGE_INVALID;
1003*027c042eSDan Zhang 
10045acaca2fSWilliam A. Kennington III     rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, ctx->start_offset,
10055acaca2fSWilliam A. Kennington III                           ctx->end_offset, DESCRIPTOR_ALIGNMENT,
10065acaca2fSWilliam A. Kennington III                           &descriptor_offset);
10075acaca2fSWilliam A. Kennington III     while (rv == LIBCR51SIGN_SUCCESS)
10085acaca2fSWilliam A. Kennington III     {
1009dca92e47SWilly Tu         CPRINTS(ctx, "%s: potential image descriptor found @%x\n", __FUNCTION__,
10105acaca2fSWilliam A. Kennington III                 descriptor_offset);
1011dca92e47SWilly Tu         // Validation is split into 3 functions to minimize stack usage.
10125acaca2fSWilliam A. Kennington III 
1013dca92e47SWilly Tu         rv = validate_descriptor(
1014dca92e47SWilly Tu             ctx, intf, descriptor_offset, descriptor_offset - ctx->start_offset,
1015dca92e47SWilly Tu             ctx->end_offset - ctx->start_offset, &payload_blob_offset);
10165acaca2fSWilliam A. Kennington III         if (rv != LIBCR51SIGN_SUCCESS)
10175acaca2fSWilliam A. Kennington III         {
1018dca92e47SWilly Tu             CPRINTS(ctx, "%s: validate_descriptor() failed ec%d\n",
1019dca92e47SWilly Tu                     __FUNCTION__, rv);
10205acaca2fSWilliam A. Kennington III         }
1021dca92e47SWilly Tu         else
10225acaca2fSWilliam A. Kennington III         {
10236084957fSPatrick Williams             rv = validate_payload_regions_helper(ctx, intf, descriptor_offset,
10246084957fSPatrick Williams                                                  image_regions);
1025dca92e47SWilly Tu             if (rv != LIBCR51SIGN_SUCCESS)
1026dca92e47SWilly Tu             {
1027dca92e47SWilly Tu                 CPRINTS(ctx, "%s: validate_payload_regions() failed ec%d\n",
1028dca92e47SWilly Tu                         __FUNCTION__, rv);
1029dca92e47SWilly Tu             }
1030dca92e47SWilly Tu             else if (ctx->descriptor.image_type == IMAGE_PROD)
1031dca92e47SWilly Tu             {
1032*027c042eSDan Zhang                 ctx->validation_state = LIBCR51SIGN_IMAGE_VALID;
1033dca92e47SWilly Tu                 // Lookup and validate payload Image MAUV against Image MAUV
1034dca92e47SWilly Tu                 // stored in the system after checking signature to ensure
1035dca92e47SWilly Tu                 // offsets and sizes are not tampered with. Also, do this after
1036dca92e47SWilly Tu                 // hash calculation for payload regions to ensure that stored
1037dca92e47SWilly Tu                 // Image MAUV is updated (if necessary) as close to the end of
1038dca92e47SWilly Tu                 // payload validation as possible
1039dca92e47SWilly Tu                 rv = validate_payload_image_mauv(ctx, intf, payload_blob_offset,
1040dca92e47SWilly Tu                                                  ctx->descriptor.blob_size);
10415acaca2fSWilliam A. Kennington III                 if (rv == LIBCR51SIGN_SUCCESS)
10425acaca2fSWilliam A. Kennington III                 {
1043dca92e47SWilly Tu                     CPRINTS(ctx,
1044dca92e47SWilly Tu                             "%s: Payload Image MAUV validation successful\n",
1045dca92e47SWilly Tu                             __FUNCTION__);
10465acaca2fSWilliam A. Kennington III                     return rv;
10475acaca2fSWilliam A. Kennington III                 }
1048dca92e47SWilly Tu                 if (rv == LIBCR51SIGN_ERROR_STORING_NEW_IMAGE_MAUV_DATA)
1049dca92e47SWilly Tu                 {
1050dca92e47SWilly Tu                     CPRINTS(
1051dca92e47SWilly Tu                         ctx,
1052dca92e47SWilly Tu                         "%s: Payload validation succeeded, but Image MAUV validation "
1053dca92e47SWilly Tu                         "failed\n",
1054dca92e47SWilly Tu                         __FUNCTION__);
1055dca92e47SWilly Tu                     return LIBCR51SIGN_ERROR_VALID_IMAGE_BUT_NEW_IMAGE_MAUV_DATA_NOT_STORED;
10565acaca2fSWilliam A. Kennington III                 }
1057dca92e47SWilly Tu                 CPRINTS(ctx, "%s: Payload Image MAUV validation failed\n",
1058dca92e47SWilly Tu                         __FUNCTION__);
1059dca92e47SWilly Tu                 // In practice, we expect only 1 valid image descriptor in
1060dca92e47SWilly Tu                 // payload. If Image MAUV check fails for the payload after
1061dca92e47SWilly Tu                 // validating the image descriptor, do not try validating other
1062dca92e47SWilly Tu                 // image descriptors
1063dca92e47SWilly Tu                 return rv;
1064dca92e47SWilly Tu             }
1065dca92e47SWilly Tu             else
1066dca92e47SWilly Tu             {
1067*027c042eSDan Zhang                 ctx->validation_state = LIBCR51SIGN_IMAGE_VALID;
1068dca92e47SWilly Tu                 return rv;
1069dca92e47SWilly Tu             }
1070dca92e47SWilly Tu         }
1071dca92e47SWilly Tu 
10725acaca2fSWilliam A. Kennington III         // Store the first desc fail reason if any
10736084957fSPatrick Williams         if (rv != LIBCR51SIGN_SUCCESS && rv_first_desc == LIBCR51SIGN_SUCCESS)
10745acaca2fSWilliam A. Kennington III             rv_first_desc = rv;
10755acaca2fSWilliam A. Kennington III 
10765acaca2fSWilliam A. Kennington III         // scan_for_magic_8() will round up to the next aligned boundary.
10775acaca2fSWilliam A. Kennington III         descriptor_offset++;
10786084957fSPatrick Williams         rv = scan_for_magic_8(ctx, intf, DESCRIPTOR_MAGIC, descriptor_offset,
1079dca92e47SWilly Tu                               ctx->end_offset, DESCRIPTOR_ALIGNMENT,
10806084957fSPatrick Williams                               &descriptor_offset);
10815acaca2fSWilliam A. Kennington III     }
1082dca92e47SWilly Tu     CPRINTS(ctx, "%s: failed to validate image ec%d\n", __FUNCTION__, rv);
10835acaca2fSWilliam A. Kennington III     // If desc validation failed for some reason then return that reason
10845acaca2fSWilliam A. Kennington III     if (rv_first_desc != LIBCR51SIGN_SUCCESS)
10855acaca2fSWilliam A. Kennington III         return rv_first_desc;
1086*027c042eSDan Zhang 
10875acaca2fSWilliam A. Kennington III     return rv;
10885acaca2fSWilliam A. Kennington III }
10895acaca2fSWilliam A. Kennington III 
10905acaca2fSWilliam A. Kennington III // @func to returns the libcr51sign error code as a string
10915acaca2fSWilliam A. Kennington III // @param[in] ec - Error code
10925acaca2fSWilliam A. Kennington III // @return error code in string format
10935acaca2fSWilliam A. Kennington III 
10945acaca2fSWilliam A. Kennington III const char* libcr51sign_errorcode_to_string(failure_reason ec)
10955acaca2fSWilliam A. Kennington III {
10965acaca2fSWilliam A. Kennington III     switch (ec)
10975acaca2fSWilliam A. Kennington III     {
10985acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_SUCCESS:
10995acaca2fSWilliam A. Kennington III             return "Success";
11005acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_RUNTIME_FAILURE:
11015acaca2fSWilliam A. Kennington III             return "Runtime Error Failure";
11025acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_UNSUPPORTED_DESCRIPTOR:
11035acaca2fSWilliam A. Kennington III             return "Unsupported descriptor";
11045acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR:
11055acaca2fSWilliam A. Kennington III             return "Invalid descriptor";
11065acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_IMAGE_FAMILY:
11075acaca2fSWilliam A. Kennington III             return "Invalid image family";
11085acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_IMAGE_TYPE_DISALLOWED:
11095acaca2fSWilliam A. Kennington III             return "Image type disallowed";
11105acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_DEV_DOWNGRADE_DISALLOWED:
11115acaca2fSWilliam A. Kennington III             return "Dev downgrade disallowed";
11125acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_UNTRUSTED_KEY:
11135acaca2fSWilliam A. Kennington III             return "Untrusted key";
11145acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_SIGNATURE:
11155acaca2fSWilliam A. Kennington III             return "Invalid signature";
11165acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_HASH:
11175acaca2fSWilliam A. Kennington III             return "Invalid hash";
11185acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_HASH_TYPE:
11195acaca2fSWilliam A. Kennington III             return "Invalid hash type";
11205acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_ARGUMENT:
11215acaca2fSWilliam A. Kennington III             return "Invalid Argument";
11225acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_FAILED_TO_LOCATE_MAGIC:
11235acaca2fSWilliam A. Kennington III             return "Failed to locate descriptor";
11245acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_CONTEXT:
11255acaca2fSWilliam A. Kennington III             return "Invalid context";
11265acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_INTERFACE:
11275acaca2fSWilliam A. Kennington III             return "Invalid interface";
11285acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_SIG_SCHEME:
11295acaca2fSWilliam A. Kennington III             return "Invalid signature scheme";
11305acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_REGION_INPUT:
11315acaca2fSWilliam A. Kennington III             return "Invalid image region input";
11325acaca2fSWilliam A. Kennington III         case LIBCR51SIGN_ERROR_INVALID_REGION_SIZE:
11335acaca2fSWilliam A. Kennington III             return "Invalid image region size";
1134dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_INVALID_IMAGE_MAUV_DATA:
1135dca92e47SWilly Tu             return "Invalid Image MAUV data";
1136dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_RETRIEVING_STORED_IMAGE_MAUV_DATA:
1137dca92e47SWilly Tu             return "Failed to retrieve Image MAUV data stored in system";
1138dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_STORING_NEW_IMAGE_MAUV_DATA:
1139dca92e47SWilly Tu             return "Failed to store Image MAUV data from payload image into system";
1140dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_STORED_IMAGE_MAUV_DOES_NOT_ALLOW_UPDATE_TO_PAYLOAD:
1141dca92e47SWilly Tu             return "Image MAUV stored in system does not allow payload "
1142dca92e47SWilly Tu                    "update";
1143dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_VALID_IMAGE_BUT_NEW_IMAGE_MAUV_DATA_NOT_STORED:
1144dca92e47SWilly Tu             return "Payload image is valid for update but failed to store new Image "
1145dca92e47SWilly Tu                    "MAUV in system";
1146dca92e47SWilly Tu         case LIBCR51SIGN_ERROR_STORED_IMAGE_MAUV_EXPECTS_PAYLOAD_IMAGE_MAUV:
1147dca92e47SWilly Tu             return "Image MAUV is expected to be present in payload when stored "
1148dca92e47SWilly Tu                    "Image MAUV is present in the system";
1149dca92e47SWilly Tu         case LIBCR51SIGN_NO_STORED_MAUV_FOUND:
1150dca92e47SWilly Tu             return "Client did not find any MAUV data stored in the system";
1151*027c042eSDan Zhang         case LIBCR51SIGN_ERROR_INVALID_DESCRIPTOR_BLOBS:
1152*027c042eSDan Zhang             return "Invalid descriptor blobs";
11535acaca2fSWilliam A. Kennington III         default:
11545acaca2fSWilliam A. Kennington III             return "Unknown error";
11555acaca2fSWilliam A. Kennington III     }
11565acaca2fSWilliam A. Kennington III }
11575acaca2fSWilliam A. Kennington III 
11585acaca2fSWilliam A. Kennington III #ifdef __cplusplus
11595acaca2fSWilliam A. Kennington III } //  extern "C"
11605acaca2fSWilliam A. Kennington III #endif
1161