Skip to content

Add support for multiple same-type signatures with key ID parsing #2305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion boot/bootutil/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
# Copyright (c) 2020-2025, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -17,6 +17,9 @@ target_include_directories(bootutil
target_sources(bootutil
PRIVATE
src/boot_record.c
src/bootutil_find_key.c
src/bootutil_img_hash.c
src/bootutil_img_security_cnt.c
src/bootutil_misc.c
src/bootutil_public.c
src/caps.c
Expand All @@ -33,6 +36,7 @@ target_sources(bootutil
src/swap_scratch.c
src/tlv.c
)

if(CONFIG_BOOT_RAM_LOAD)
target_sources(bootutil
PRIVATE
Expand Down
5 changes: 0 additions & 5 deletions boot/bootutil/include/bootutil/crypto/ecdsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,6 @@ static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
ctx->required_algorithm = 0;

#else /* !MCUBOOT_BUILTIN_KEY */
/* The incoming key ID is equal to the image index. The key ID value must be
* shifted (by one in this case) because zero is reserved (PSA_KEY_ID_NULL)
* and considered invalid.
*/
ctx->key_id++; /* Make sure it is not equal to 0. */
#if defined(MCUBOOT_SIGN_EC256)
ctx->curve_byte_count = 32;
ctx->required_algorithm = PSA_ALG_SHA_256;
Expand Down
18 changes: 18 additions & 0 deletions boot/bootutil/include/bootutil/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ extern "C" {
*/
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
#define IMAGE_TLV_PUBKEY 0x02 /* public key */
#define IMAGE_TLV_KEYID 0x03 /* Key ID */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */
#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */
Expand Down Expand Up @@ -235,6 +236,23 @@ int32_t bootutil_get_img_security_cnt(struct boot_loader_state *state, int slot,
const struct flash_area *fap,
uint32_t *img_security_cnt);

#if defined(MCUBOOT_BUILTIN_KEY)
int bootutil_find_key(uint8_t image_index, uint8_t *key_id_buf, uint8_t key_id_buf_len);
#elif defined(MCUBOOT_HW_KEY)
int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len);
#else
int bootutil_find_key(uint8_t image_index, uint8_t *keyhash, uint8_t keyhash_len);
#endif

int bootutil_img_hash(struct boot_loader_state *state,
struct image_header *hdr, const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result,
uint8_t *seed, int seed_len
#if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY)
, uint32_t start_offset
#endif
);

#ifdef __cplusplus
}
#endif
Expand Down
38 changes: 38 additions & 0 deletions boot/bootutil/include/bootutil/sign_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@

/* mcuboot_config.h is needed for MCUBOOT_HW_KEY to work */
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_IMAGE_MULTI_SIG_SUPPORT
#include <stdbool.h>
#endif /* MCUBOOT_IMAGE_MULTI_SIG_SUPPORT */

#ifdef __cplusplus
extern "C" {
Expand All @@ -39,6 +42,17 @@ struct bootutil_key {
};

extern const struct bootutil_key bootutil_keys[];
#ifdef MCUBOOT_BUILTIN_KEY
/**
* Verify that the specified key ID is valid for authenticating the given image.
*
* @param[in] image_index Index of the image to be verified.
* @param[in] key_id Identifier of the key to be verified against the image.
*
* @return 0 if the key ID is valid for the image; nonzero on failure.
*/
int boot_verify_key_id_for_image(uint8_t image_index, uint32_t key_id);
#endif /* MCUBOOT_BUILTIN_KEY */
#else
struct bootutil_key {
uint8_t *key;
Expand All @@ -51,17 +65,41 @@ extern struct bootutil_key bootutil_keys[];
* Retrieve the hash of the corresponding public key for image authentication.
*
* @param[in] image_index Index of the image to be authenticated.
* @param[in] key_index Index of the key to be used.
* @param[out] public_key_hash Buffer to store the key-hash in.
* @param[in,out] key_hash_size As input the size of the buffer. As output
* the actual key-hash length.
*
* @return 0 on success; nonzero on failure.
*/
int boot_retrieve_public_key_hash(uint8_t image_index,
uint8_t key_index,
uint8_t *public_key_hash,
size_t *key_hash_size);

#endif /* !MCUBOOT_HW_KEY */

#ifdef MCUBOOT_IMAGE_MULTI_SIG_SUPPORT
/**
* @brief Checks the key policy for signature verification.
*
* Determines whether a given key might or must be used to sign an image,
* based on the validity of the signature and the key index. Updates the
* provided output parameters to reflect the policy.
*
* @param valid_sig Indicates if the signature is valid.
* @param key The key index to check.
* @param[out] key_might_sign Set to true if the key might be used to sign.
* @param[out] key_must_sign Set to true if the key must be used to sign.
* @param[out] key_must_sign_count Set to the number of keys that must sign.
*
* @return 0 on success, or a negative error code on failure.
*/
int boot_plat_check_key_policy(bool valid_sig, uint32_t key,
bool *key_might_sign, bool *key_must_sign,
uint8_t *key_must_sign_count);
#endif /* MCUBOOT_IMAGE_MULTI_SIG_SUPPORT */

extern const int bootutil_key_cnt;

#ifdef __cplusplus
Expand Down
131 changes: 131 additions & 0 deletions boot/bootutil/src/bootutil_find_key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2025 Arm Limited
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

#include <stdint.h>

#include "bootutil/bootutil_log.h"
#include "bootutil/crypto/sha.h"
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/image.h"
#include "bootutil/sign_key.h"
#include "bootutil_priv.h"
#include "mcuboot_config/mcuboot_config.h"

#ifdef MCUBOOT_IMAGE_MULTI_SIG_SUPPORT
#define NUM_OF_KEYS MCUBOOT_ROTPK_MAX_KEYS_PER_IMAGE
#else
#define NUM_OF_KEYS 1
#endif /* MCUBOOT_IMAGE_MULTI_SIG_SUPPORT */

#if defined(MCUBOOT_BUILTIN_KEY)
int bootutil_find_key(uint8_t image_index, uint8_t *key_id_buf, uint8_t key_id_buf_len)
{
uint32_t key_id;
FIH_DECLARE(fih_rc, FIH_FAILURE);

/* Key id is passed */
assert(key_id_buf_len == sizeof(uint32_t));
memcpy(&key_id, key_id_buf, sizeof(key_id));

/* Check if key id is associated with the image */
FIH_CALL(boot_verify_key_id_for_image, fih_rc, image_index, key_id);
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
return (int32_t)key_id;
}

return -1;
}

#elif defined(MCUBOOT_HW_KEY)
extern unsigned int pub_key_len;
int bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
{
bootutil_sha_context sha_ctx;
uint8_t hash[IMAGE_HASH_SIZE];
uint8_t key_hash[IMAGE_HASH_SIZE];
size_t key_hash_size = sizeof(key_hash);
int rc;
uint8_t key_index;
FIH_DECLARE(fih_rc, FIH_FAILURE);

bootutil_sha_init(&sha_ctx);
bootutil_sha_update(&sha_ctx, key, key_len);
bootutil_sha_finish(&sha_ctx, hash);
bootutil_sha_drop(&sha_ctx);

for(key_index = 0; key_index < NUM_OF_KEYS; key_index++) {
rc = boot_retrieve_public_key_hash(image_index, key_index, key_hash, &key_hash_size);
if (rc) {
return -1;
}

/* Adding hardening to avoid this potential attack:
* - Image is signed with an arbitrary key and the corresponding public
* key is added as a TLV field.
* - During public key validation (comparing against key-hash read from
* HW) a fault is injected to accept the public key as valid one.
*/
FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size);
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
BOOT_LOG_INF("Key %d hash found for image %d", key_index, image_index);
bootutil_keys[0].key = key;
pub_key_len = key_len;
return 0;
}
}
BOOT_LOG_ERR("Key hash NOT found for image %d!", image_index);

return -1;
}

#else /* !defined MCUBOOT_BUILTIN_KEY && !defined MCUBOOT_HW_KEY */
int bootutil_find_key(uint8_t image_index, uint8_t *keyhash, uint8_t keyhash_len)
{
bootutil_sha_context sha_ctx;
int i;
uint8_t hash[IMAGE_HASH_SIZE];
const struct bootutil_key *key;
(void)image_index;

if (keyhash_len > IMAGE_HASH_SIZE) {
return -1;
}

for (i = 0; i < bootutil_key_cnt; i++) {
key = &bootutil_keys[i];
bootutil_sha_init(&sha_ctx);
bootutil_sha_update(&sha_ctx, key->key, *key->len);
bootutil_sha_finish(&sha_ctx, hash);
bootutil_sha_drop(&sha_ctx);
if (!memcmp(hash, keyhash, keyhash_len)) {
return i;
}
}
return -1;
}
#endif
Loading
Loading