Initial commit

Initial commit.
This commit is contained in:
kntran1
2026-03-23 14:40:39 -05:00
parent e84b2b4166
commit 4e2a5258a5
872 changed files with 165227 additions and 0 deletions

2
bootloader/mcuboot/sim/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
target
.*.swp

View File

@@ -0,0 +1,54 @@
[package]
name = "bootsim"
version = "0.1.0"
authors = ["David Brown <davidb@davidb.org>"]
edition = "2021"
[features]
default = []
sig-rsa = ["mcuboot-sys/sig-rsa"]
sig-rsa3072 = ["mcuboot-sys/sig-rsa3072"]
sig-ecdsa = ["mcuboot-sys/sig-ecdsa"]
sig-ecdsa-mbedtls = ["mcuboot-sys/sig-ecdsa-mbedtls"]
sig-ecdsa-psa = ["mcuboot-sys/sig-ecdsa-psa", "mcuboot-sys/psa-crypto-api"]
sig-p384 = ["mcuboot-sys/sig-p384"]
sig-ed25519 = ["mcuboot-sys/sig-ed25519"]
overwrite-only = ["mcuboot-sys/overwrite-only"]
swap-move = ["mcuboot-sys/swap-move"]
validate-primary-slot = ["mcuboot-sys/validate-primary-slot"]
enc-rsa = ["mcuboot-sys/enc-rsa"]
enc-aes256-rsa = ["mcuboot-sys/enc-aes256-rsa"]
enc-kw = ["mcuboot-sys/enc-kw"]
enc-aes256-kw = ["mcuboot-sys/enc-aes256-kw"]
enc-ec256 = ["mcuboot-sys/enc-ec256"]
enc-ec256-mbedtls = ["mcuboot-sys/enc-ec256-mbedtls"]
enc-aes256-ec256 = ["mcuboot-sys/enc-aes256-ec256"]
enc-x25519 = ["mcuboot-sys/enc-x25519"]
enc-aes256-x25519 = ["mcuboot-sys/enc-aes256-x25519"]
bootstrap = ["mcuboot-sys/bootstrap"]
multiimage = ["mcuboot-sys/multiimage"]
ram-load = ["mcuboot-sys/ram-load"]
direct-xip = ["mcuboot-sys/direct-xip"]
downgrade-prevention = ["mcuboot-sys/downgrade-prevention"]
max-align-32 = ["mcuboot-sys/max-align-32"]
hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"]
[dependencies]
byteorder = "1.4"
libc = "0.2"
rand = { version = "0.8", features = ["small_rng"] }
docopt = "1.1.0"
serde = "1.0"
serde_derive = "1.0"
log = "0.4"
env_logger = "0.9"
simflash = { path = "simflash" }
mcuboot-sys = { path = "mcuboot-sys" }
ring = "0.16.11"
untrusted = "0.9"
pem = "1.0"
cipher = "0.3"
aes = { version = "0.7.4", features = ["ctr"] }
base64 = "0.13.0"
typenum = "1.13.0"

View File

@@ -0,0 +1,61 @@
MCUboot simulator
#################
This is a small simulator designed to exercise the mcuboot upgrade
code, specifically testing untimely reset scenarios to make sure the
code is robust.
Prerequisites
=============
The simulator is written in Rust_, and you will need to install it to
build it. The installation_ page describes this process. The
simulator can be built with the stable release of Rust.
.. _Rust: https://www.rust-lang.org/
.. _installation: https://www.rust-lang.org/en-US/install.html
Dependent code
--------------
The simulator depends on some external modules. These are stored as
submodules within git. To fetch these dependencies the first time::
$ git submodule update --init --recursive
will clone and check out these trees in the appropriate place.
Testing
=======
The tests are written as unit tests in Rust, and can be built and run
automatically::
$ cargo test
this should download and compile the necessary dependencies, compile
the relevant modules from mcuboot, build the simulator, and run the
tests.
There are several different features you can test. For example,
testing RSA signatures can be done with::
$ cargo test --features sig-rsa
For a complete list of features, see Cargo.toml.
Debugging
=========
If the simulator indicates a failure, you can turn on additional
logging by setting ``RUST_LOG=warn`` or ``RUST_LOG=error`` in the
environment::
$ RUST_LOG=warn ./target/release/bootsim run ...
It is also possible to run specific tests, for example::
$ cargo test -- basic_revert
which will run only the `basic_revert` test.

View File

@@ -0,0 +1 @@
Cargo.lock

View File

@@ -0,0 +1,104 @@
[package]
name = "mcuboot-sys"
version = "0.1.0"
authors = ["David Brown <david.brown@linaro.org>"]
description = "A simple wrapper around the mcuboot code."
build = "build.rs"
publish = false
edition = "2021"
[features]
# By default, build with simplistic signature verification.
default = []
# Verify RSA signatures. Note that at this time, the C code will not
# compile with both sig-rsa and sig-ecdsa enabled.
sig-rsa = []
# Verify RSA-3072 signatures.
sig-rsa3072 = []
# Verify ECDSA (secp256r1) signatures.
sig-ecdsa = []
# Verify ECDSA (secp256r1) signatures using mbed TLS
sig-ecdsa-mbedtls = []
# Verify ECDSA (p256 or p384) signatures using PSA Crypto API
sig-ecdsa-psa = []
# Enable P384 Curve support (instead of P256) for PSA Crypto
sig-p384 = []
# Verify ED25519 signatures.
sig-ed25519 = []
# Overwrite only upgrade
overwrite-only = []
swap-move = []
# Disable validation of the primary slot
validate-primary-slot = []
# Encrypt image in the secondary slot using RSA-OAEP-2048
enc-rsa = []
# Encrypt image in the secondary slot using AES-256-CTR and RSA-OAEP-2048
enc-aes256-rsa = []
# Encrypt image in the secondary slot using AES-KW-128
enc-kw = []
# Encrypt image in the secondary slot using AES-256-CTR and AES-KW-256
enc-aes256-kw = []
# Encrypt image in the secondary slot using ECIES-P256
enc-ec256 = []
# Encrypt image in the secondary slot using AES-256-CTR and ECIES-P256
enc-aes256-ec256 = []
# Encrypt image in the secondary slot using ECIES-P256 using Mbed TLS
enc-ec256-mbedtls = []
# Encrypt image in the secondary slot using ECIES-X25519
enc-x25519 = []
# Encrypt image in the secondary slot using AES-256-CTR and ECIES-X25519
enc-aes256-x25519 = []
# Allow bootstrapping an empty/invalid primary slot from a valid secondary slot
bootstrap = []
# Support multiple images (currently 2 instead of 1).
multiimage = []
# Support simulation of ram-loading. No swaps are performed, and the
# image is copied to RAM before loading it.
ram-load = []
# Support simulation of direct XIP. No swaps are performed, the image
# is directly executed out of whichever partition contains the most
# appropriate image.
direct-xip = []
# Check (in software) against version downgrades.
downgrade-prevention = []
# Support images with 32-byte maximum write alignment value.
max-align-32 = []
# Enable hardware rollback protection
hw-rollback-protection = []
# Enable the PSA Crypto APIs where supported for cryptography related operations.
psa-crypto-api = []
[build-dependencies]
cc = "1.0.25"
[dependencies]
libc = "0.2"
log = "0.4"
simflash = { path = "../simflash" }

View File

@@ -0,0 +1,532 @@
// Build mcuboot as a library, based on the requested features.
extern crate cc;
use std::collections::BTreeSet;
use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
fn main() {
// Feature flags.
let psa_crypto_api = env::var("CARGO_FEATURE_PSA_CRYPTO_API").is_ok();
let sig_rsa = env::var("CARGO_FEATURE_SIG_RSA").is_ok();
let sig_rsa3072 = env::var("CARGO_FEATURE_SIG_RSA3072").is_ok();
let sig_ecdsa = env::var("CARGO_FEATURE_SIG_ECDSA").is_ok();
let sig_ecdsa_mbedtls = env::var("CARGO_FEATURE_SIG_ECDSA_MBEDTLS").is_ok();
let sig_ecdsa_psa = env::var("CARGO_FEATURE_SIG_ECDSA_PSA").is_ok();
let sig_p384 = env::var("CARGO_FEATURE_SIG_P384").is_ok();
let sig_ed25519 = env::var("CARGO_FEATURE_SIG_ED25519").is_ok();
let overwrite_only = env::var("CARGO_FEATURE_OVERWRITE_ONLY").is_ok();
let swap_move = env::var("CARGO_FEATURE_SWAP_MOVE").is_ok();
let validate_primary_slot =
env::var("CARGO_FEATURE_VALIDATE_PRIMARY_SLOT").is_ok();
let enc_rsa = env::var("CARGO_FEATURE_ENC_RSA").is_ok();
let enc_aes256_rsa = env::var("CARGO_FEATURE_ENC_AES256_RSA").is_ok();
let enc_kw = env::var("CARGO_FEATURE_ENC_KW").is_ok();
let enc_aes256_kw = env::var("CARGO_FEATURE_ENC_AES256_KW").is_ok();
let enc_ec256 = env::var("CARGO_FEATURE_ENC_EC256").is_ok();
let enc_ec256_mbedtls = env::var("CARGO_FEATURE_ENC_EC256_MBEDTLS").is_ok();
let enc_aes256_ec256 = env::var("CARGO_FEATURE_ENC_AES256_EC256").is_ok();
let enc_x25519 = env::var("CARGO_FEATURE_ENC_X25519").is_ok();
let enc_aes256_x25519 = env::var("CARGO_FEATURE_ENC_AES256_X25519").is_ok();
let bootstrap = env::var("CARGO_FEATURE_BOOTSTRAP").is_ok();
let multiimage = env::var("CARGO_FEATURE_MULTIIMAGE").is_ok();
let downgrade_prevention = env::var("CARGO_FEATURE_DOWNGRADE_PREVENTION").is_ok();
let ram_load = env::var("CARGO_FEATURE_RAM_LOAD").is_ok();
let direct_xip = env::var("CARGO_FEATURE_DIRECT_XIP").is_ok();
let max_align_32 = env::var("CARGO_FEATURE_MAX_ALIGN_32").is_ok();
let hw_rollback_protection = env::var("CARGO_FEATURE_HW_ROLLBACK_PROTECTION").is_ok();
let mut conf = CachedBuild::new();
conf.conf.define("__BOOTSIM__", None);
conf.conf.define("MCUBOOT_HAVE_LOGGING", None);
conf.conf.define("MCUBOOT_USE_FLASH_AREA_GET_SECTORS", None);
conf.conf.define("MCUBOOT_HAVE_ASSERT_H", None);
conf.conf.define("MCUBOOT_MAX_IMG_SECTORS", Some("128"));
if max_align_32 {
conf.conf.define("MCUBOOT_BOOT_MAX_ALIGN", Some("32"));
} else {
conf.conf.define("MCUBOOT_BOOT_MAX_ALIGN", Some("8"));
}
conf.conf.define("MCUBOOT_IMAGE_NUMBER", Some(if multiimage { "2" } else { "1" }));
if downgrade_prevention && !overwrite_only {
panic!("Downgrade prevention requires overwrite only");
}
if bootstrap {
conf.conf.define("MCUBOOT_BOOTSTRAP", None);
conf.conf.define("MCUBOOT_OVERWRITE_ONLY_FAST", None);
}
if validate_primary_slot {
conf.conf.define("MCUBOOT_VALIDATE_PRIMARY_SLOT", None);
}
if downgrade_prevention {
conf.conf.define("MCUBOOT_DOWNGRADE_PREVENTION", None);
}
if ram_load {
conf.conf.define("MCUBOOT_RAM_LOAD", None);
}
if direct_xip {
conf.conf.define("MCUBOOT_DIRECT_XIP", None);
}
if hw_rollback_protection {
conf.conf.define("MCUBOOT_HW_ROLLBACK_PROT", None);
conf.file("csupport/security_cnt.c");
}
// Currently no more than one sig type can be used simultaneously.
if vec![sig_rsa, sig_rsa3072, sig_ecdsa, sig_ed25519].iter()
.fold(0, |sum, &v| sum + v as i32) > 1 {
panic!("mcuboot does not support more than one sig type at the same time");
}
if psa_crypto_api {
if sig_ecdsa || enc_ec256 || enc_x25519 ||
enc_aes256_ec256 || sig_ecdsa_mbedtls || enc_aes256_x25519 ||
enc_kw || enc_aes256_kw {
conf.file("csupport/psa_crypto_init_stub.c");
} else {
conf.conf.define("MCUBOOT_USE_PSA_CRYPTO", None);
conf.file("../../ext/mbedtls/library/aes.c");
conf.file("../../ext/mbedtls/library/aesni.c");
conf.file("../../ext/mbedtls/library/aria.c");
conf.file("../../ext/mbedtls/library/asn1write.c");
conf.file("../../ext/mbedtls/library/base64.c");
conf.file("../../ext/mbedtls/library/camellia.c");
conf.file("../../ext/mbedtls/library/ccm.c");
conf.file("../../ext/mbedtls/library/chacha20.c");
conf.file("../../ext/mbedtls/library/chachapoly.c");
conf.file("../../ext/mbedtls/library/cipher.c");
conf.file("../../ext/mbedtls/library/cipher_wrap.c");
conf.file("../../ext/mbedtls/library/ctr_drbg.c");
conf.file("../../ext/mbedtls/library/des.c");
conf.file("../../ext/mbedtls/library/ecdsa.c");
conf.file("../../ext/mbedtls/library/ecp.c");
conf.file("../../ext/mbedtls/library/ecp_curves.c");
conf.file("../../ext/mbedtls/library/entropy.c");
conf.file("../../ext/mbedtls/library/entropy_poll.c");
conf.file("../../ext/mbedtls/library/gcm.c");
conf.file("../../ext/mbedtls/library/md5.c");
conf.file("../../ext/mbedtls/library/nist_kw.c");
conf.file("../../ext/mbedtls/library/oid.c");
conf.file("../../ext/mbedtls/library/pem.c");
conf.file("../../ext/mbedtls/library/pk.c");
conf.file("../../ext/mbedtls/library/pkcs5.c");
conf.file("../../ext/mbedtls/library/pkcs12.c");
conf.file("../../ext/mbedtls/library/pkparse.c");
conf.file("../../ext/mbedtls/library/pk_wrap.c");
conf.file("../../ext/mbedtls/library/pkwrite.c");
conf.file("../../ext/mbedtls/library/poly1305.c");
conf.file("../../ext/mbedtls/library/psa_crypto.c");
conf.file("../../ext/mbedtls/library/psa_crypto_cipher.c");
conf.file("../../ext/mbedtls/library/psa_crypto_client.c");
conf.file("../../ext/mbedtls/library/psa_crypto_driver_wrappers.c");
conf.file("../../ext/mbedtls/library/psa_crypto_ecp.c");
conf.file("../../ext/mbedtls/library/psa_crypto_hash.c");
conf.file("../../ext/mbedtls/library/psa_crypto_mac.c");
conf.file("../../ext/mbedtls/library/psa_crypto_rsa.c");
conf.file("../../ext/mbedtls/library/psa_crypto_slot_management.c");
conf.file("../../ext/mbedtls/library/psa_crypto_storage.c");
conf.file("../../ext/mbedtls/library/psa_its_file.c");
conf.file("../../ext/mbedtls/library/ripemd160.c");
conf.file("../../ext/mbedtls/library/rsa_alt_helpers.c");
conf.file("../../ext/mbedtls/library/sha1.c");
conf.file("../../ext/mbedtls/library/sha512.c");
conf.file("../../ext/mbedtls/tests/src/random.c");
conf.conf.include("../../ext/mbedtls/library");
}
conf.conf.include("../../ext/mbedtls/tests/include/");
conf.file("../../ext/mbedtls/tests/src/fake_external_rng_for_test.c");
}
if sig_rsa || sig_rsa3072 {
conf.conf.define("MCUBOOT_SIGN_RSA", None);
// The Kconfig style defines must be added here as well because
// they are used internally by "config-rsa.h"
if sig_rsa {
conf.conf.define("MCUBOOT_SIGN_RSA_LEN", "2048");
conf.conf.define("CONFIG_BOOT_SIGNATURE_TYPE_RSA_LEN", "2048");
} else {
conf.conf.define("MCUBOOT_SIGN_RSA_LEN", "3072");
conf.conf.define("CONFIG_BOOT_SIGNATURE_TYPE_RSA_LEN", "3072");
}
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("csupport/keys.c");
conf.file("../../ext/mbedtls/library/rsa.c");
conf.file("../../ext/mbedtls/library/bignum.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/mbedtls/library/md.c");
} else if sig_ecdsa {
conf.conf.define("MCUBOOT_SIGN_EC256", None);
conf.conf.define("MCUBOOT_USE_TINYCRYPT", None);
if !enc_kw {
conf.conf.include("../../ext/mbedtls/include");
}
conf.conf.include("../../ext/tinycrypt/lib/include");
conf.file("csupport/keys.c");
conf.file("../../ext/tinycrypt/lib/source/utils.c");
conf.file("../../ext/tinycrypt/lib/source/sha256.c");
conf.file("../../ext/tinycrypt/lib/source/ecc.c");
conf.file("../../ext/tinycrypt/lib/source/ecc_dsa.c");
conf.file("../../ext/tinycrypt/lib/source/ecc_platform_specific.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
} else if sig_ecdsa_mbedtls {
conf.conf.define("MCUBOOT_SIGN_EC256", None);
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("csupport/keys.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/mbedtls/library/bignum.c");
conf.file("../../ext/mbedtls/library/ecdsa.c");
conf.file("../../ext/mbedtls/library/ecp.c");
conf.file("../../ext/mbedtls/library/ecp_curves.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
} else if sig_ecdsa_psa {
conf.conf.include("../../ext/mbedtls/include");
if sig_p384 {
conf.conf.define("MCUBOOT_SIGN_EC384", None);
conf.file("../../ext/mbedtls/library/sha512.c");
} else {
conf.conf.define("MCUBOOT_SIGN_EC256", None);
conf.file("../../ext/mbedtls/library/sha256.c");
}
conf.file("csupport/keys.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/mbedtls/library/bignum.c");
conf.file("../../ext/mbedtls/library/ecp.c");
conf.file("../../ext/mbedtls/library/ecp_curves.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
} else if sig_ed25519 {
conf.conf.define("MCUBOOT_SIGN_ED25519", None);
conf.conf.define("MCUBOOT_USE_TINYCRYPT", None);
conf.conf.include("../../ext/tinycrypt/lib/include");
conf.conf.include("../../ext/tinycrypt-sha512/lib/include");
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/tinycrypt/lib/source/sha256.c");
conf.file("../../ext/tinycrypt-sha512/lib/source/sha512.c");
conf.file("../../ext/tinycrypt/lib/source/utils.c");
conf.file("csupport/keys.c");
conf.file("../../ext/fiat/src/curve25519.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
} else if !enc_ec256 && !enc_x25519 {
// No signature type, only sha256 validation. The default
// configuration file bundled with mbedTLS is sufficient.
// When using ECIES-P256 rely on Tinycrypt.
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
}
if overwrite_only {
conf.conf.define("MCUBOOT_OVERWRITE_ONLY", None);
}
if swap_move {
conf.conf.define("MCUBOOT_SWAP_USING_MOVE", None);
} else if !overwrite_only && !direct_xip && !ram_load {
conf.conf.define("CONFIG_BOOT_SWAP_USING_SCRATCH", None);
conf.conf.define("MCUBOOT_SWAP_USING_SCRATCH", None);
}
if enc_rsa || enc_aes256_rsa {
if enc_aes256_rsa {
conf.conf.define("MCUBOOT_AES_256", None);
}
conf.conf.define("MCUBOOT_ENCRYPT_RSA", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("csupport/keys.c");
conf.conf.include("../../ext/mbedtls/include");
conf.conf.include("../../ext/mbedtls/library");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/rsa.c");
conf.file("../../ext/mbedtls/library/rsa_alt_helpers.c");
conf.file("../../ext/mbedtls/library/md.c");
conf.file("../../ext/mbedtls/library/aes.c");
conf.file("../../ext/mbedtls/library/bignum.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
}
if enc_kw || enc_aes256_kw {
if enc_aes256_kw {
conf.conf.define("MCUBOOT_AES_256", None);
}
conf.conf.define("MCUBOOT_ENCRYPT_KW", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("csupport/keys.c");
if sig_rsa || sig_rsa3072 {
conf.file("../../ext/mbedtls/library/sha256.c");
}
/* Simulator uses Mbed-TLS to wrap keys */
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/mbedtls/library/platform.c");
conf.conf.include("../../ext/mbedtls/library");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/nist_kw.c");
conf.file("../../ext/mbedtls/library/cipher.c");
conf.file("../../ext/mbedtls/library/cipher_wrap.c");
conf.file("../../ext/mbedtls/library/aes.c");
if sig_ecdsa {
conf.conf.define("MCUBOOT_USE_TINYCRYPT", None);
conf.conf.include("../../ext/tinycrypt/lib/include");
conf.file("../../ext/tinycrypt/lib/source/utils.c");
conf.file("../../ext/tinycrypt/lib/source/sha256.c");
conf.file("../../ext/tinycrypt/lib/source/aes_encrypt.c");
conf.file("../../ext/tinycrypt/lib/source/aes_decrypt.c");
conf.file("../../ext/tinycrypt/lib/source/ctr_mode.c");
}
if sig_ed25519 {
panic!("ed25519 does not support image encryption with KW yet");
}
}
if enc_ec256 {
conf.conf.define("MCUBOOT_ENCRYPT_EC256", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.conf.define("MCUBOOT_USE_TINYCRYPT", None);
conf.conf.define("MCUBOOT_SWAP_SAVE_ENCTLV", None);
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("csupport/keys.c");
conf.conf.include("../../ext/mbedtls/include");
conf.conf.include("../../ext/tinycrypt/lib/include");
/* FIXME: fail with other signature schemes ? */
conf.file("../../ext/tinycrypt/lib/source/utils.c");
conf.file("../../ext/tinycrypt/lib/source/sha256.c");
conf.file("../../ext/tinycrypt/lib/source/ecc.c");
conf.file("../../ext/tinycrypt/lib/source/ecc_dsa.c");
conf.file("../../ext/tinycrypt/lib/source/ecc_platform_specific.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/tinycrypt/lib/source/aes_encrypt.c");
conf.file("../../ext/tinycrypt/lib/source/aes_decrypt.c");
conf.file("../../ext/tinycrypt/lib/source/ctr_mode.c");
conf.file("../../ext/tinycrypt/lib/source/hmac.c");
conf.file("../../ext/tinycrypt/lib/source/ecc_dh.c");
} else if enc_ec256_mbedtls || enc_aes256_ec256 {
if enc_aes256_ec256 {
conf.conf.define("MCUBOOT_AES_256", None);
}
conf.conf.define("MCUBOOT_ENCRYPT_EC256", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.conf.define("MCUBOOT_SWAP_SAVE_ENCTLV", None);
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/mbedtls/library/bignum.c");
conf.file("../../ext/mbedtls/library/ecdh.c");
conf.file("../../ext/mbedtls/library/md.c");
conf.file("../../ext/mbedtls/library/aes.c");
conf.file("../../ext/mbedtls/library/ecp.c");
conf.file("../../ext/mbedtls/library/ecp_curves.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("csupport/keys.c");
}
if enc_x25519 {
conf.conf.define("MCUBOOT_ENCRYPT_X25519", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.conf.define("MCUBOOT_USE_TINYCRYPT", None);
conf.conf.define("MCUBOOT_SWAP_SAVE_ENCTLV", None);
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("csupport/keys.c");
conf.conf.include("../../ext/mbedtls/include");
conf.conf.include("../../ext/tinycrypt/lib/include");
conf.conf.include("../../ext/tinycrypt-sha512/lib/include");
conf.file("../../ext/fiat/src/curve25519.c");
conf.file("../../ext/tinycrypt/lib/source/utils.c");
conf.file("../../ext/tinycrypt/lib/source/sha256.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/tinycrypt/lib/source/aes_encrypt.c");
conf.file("../../ext/tinycrypt/lib/source/aes_decrypt.c");
conf.file("../../ext/tinycrypt/lib/source/ctr_mode.c");
conf.file("../../ext/tinycrypt/lib/source/hmac.c");
}
else if enc_aes256_x25519 {
conf.conf.define("MCUBOOT_AES_256", None);
conf.conf.define("MCUBOOT_ENCRYPT_X25519", None);
conf.conf.define("MCUBOOT_ENC_IMAGES", None);
conf.conf.define("MCUBOOT_USE_MBED_TLS", None);
conf.conf.define("MCUBOOT_SWAP_SAVE_ENCTLV", None);
conf.file("../../boot/bootutil/src/encrypted.c");
conf.file("csupport/keys.c");
conf.conf.include("../../ext/mbedtls/include");
conf.file("../../ext/fiat/src/curve25519.c");
conf.file("../../ext/mbedtls/library/asn1parse.c");
conf.file("../../ext/mbedtls/library/platform.c");
conf.file("../../ext/mbedtls/library/platform_util.c");
conf.file("../../ext/mbedtls/library/aes.c");
conf.file("../../ext/mbedtls/library/sha256.c");
conf.file("../../ext/mbedtls/library/md.c");
conf.file("../../ext/mbedtls/library/sha512.c");
}
if sig_rsa && enc_kw {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-rsa-kw.h>"));
} else if sig_rsa || sig_rsa3072 || enc_rsa || enc_aes256_rsa {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-rsa.h>"));
} else if sig_ecdsa_mbedtls || enc_ec256_mbedtls || enc_aes256_ec256 {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-ec.h>"));
} else if (sig_ecdsa || enc_ec256) && !enc_kw {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-asn1.h>"));
} else if sig_ed25519 || enc_x25519 {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-asn1.h>"));
} else if enc_kw || enc_aes256_kw {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-kw.h>"));
} else if enc_aes256_x25519 {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-ed25519.h>"));
} else if sig_ecdsa_psa {
conf.conf.define("MBEDTLS_CONFIG_FILE", Some("<config-ec-psa.h>"));
}
conf.file("../../boot/bootutil/src/image_validate.c");
if sig_rsa || sig_rsa3072 {
conf.file("../../boot/bootutil/src/image_rsa.c");
} else if sig_ecdsa || sig_ecdsa_mbedtls || sig_ecdsa_psa {
conf.file("../../boot/bootutil/src/image_ecdsa.c");
} else if sig_ed25519 {
conf.file("../../boot/bootutil/src/image_ed25519.c");
}
conf.file("../../boot/bootutil/src/loader.c");
conf.file("../../boot/bootutil/src/swap_misc.c");
conf.file("../../boot/bootutil/src/swap_scratch.c");
conf.file("../../boot/bootutil/src/swap_move.c");
conf.file("../../boot/bootutil/src/caps.c");
conf.file("../../boot/bootutil/src/bootutil_misc.c");
conf.file("../../boot/bootutil/src/bootutil_public.c");
conf.file("../../boot/bootutil/src/tlv.c");
conf.file("../../boot/bootutil/src/fault_injection_hardening.c");
conf.file("csupport/run.c");
conf.conf.include("../../boot/bootutil/include");
conf.conf.include("csupport");
conf.conf.debug(true);
conf.conf.flag("-Wall");
conf.conf.flag("-Werror");
// FIXME: travis-ci still uses gcc 4.8.4 which defaults to std=gnu90.
// It has incomplete std=c11 and std=c99 support but std=c99 was checked
// to build correctly so leaving it here to updated in the future...
conf.conf.flag("-std=c99");
conf.conf.compile("libbootutil.a");
walk_dir("../../boot").unwrap();
walk_dir("../../ext/tinycrypt/lib/source").unwrap();
walk_dir("../../ext/mbedtls-asn1").unwrap();
walk_dir("csupport").unwrap();
walk_dir("../../ext/mbedtls/include").unwrap();
walk_dir("../../ext/mbedtls/library").unwrap();
}
// Output the names of all files within a directory so that Cargo knows when to rebuild.
fn walk_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
for ent in fs::read_dir(path.as_ref())? {
let ent = ent?;
let p = ent.path();
if p.is_dir() {
walk_dir(p)?;
} else {
// Note that non-utf8 names will fail.
let name = p.to_str().unwrap();
if name.ends_with(".c") || name.ends_with(".h") {
println!("cargo:rerun-if-changed={}", name);
}
}
}
Ok(())
}
/// Wrap the cc::Build type so that we can make sure that files are only added a single time.
/// Other methods can be passed through as needed.
struct CachedBuild {
conf: cc::Build,
seen: BTreeSet<PathBuf>,
}
impl CachedBuild {
fn new() -> CachedBuild {
CachedBuild {
conf: cc::Build::new(),
seen: BTreeSet::new(),
}
}
/// Works like `file` in the Build, but doesn't add a file if the same path has already been
/// given.
fn file<P: AsRef<Path>>(&mut self, p: P) -> &mut CachedBuild {
let p = p.as_ref();
if !self.seen.contains(p) {
self.conf.file(p);
self.seen.insert(p.to_owned());
}
self
}
}

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
/*
* 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.
*/
#ifndef H_BOOTSIM_
#define H_BOOTSIM_
#include "mcuboot_config/mcuboot_assert.h"
#endif

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arm Limited
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_ADD_PSA_CRYPTO_H
#define MCUBOOT_MBEDTLS_CONFIG_ADD_PSA_CRYPTO_H
#include "mbedtls/build_info.h"
/* Enable PSA Crypto Core without support for the permanent storage
* Don't define MBEDTLS_PSA_CRYPTO_STORAGE_C to make sure that support
* for permanent keys is not enabled, as it is not usually required during boot
*/
#define MBEDTLS_PSA_CRYPTO_C
#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
#if defined(MCUBOOT_ENCRYPT_RSA) || defined(MCUBOOT_SIGN_RSA)
#define MBEDTLS_PK_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PK_WRITE_C
#endif /* MCUBOOT_ENCRYPT_RSA || MCUBOOT_SIGN_RSA */
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
#define MBEDTLS_PLATFORM_FREE_MACRO free
#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc
#endif /* MCUBOOT_ENCRYPT_EC256 || MCUBOOT_ENCRYPT_X25519 */
#if !defined(MCUBOOT_ENCRYPT_X25519)
#define MBEDTLS_PSA_BUILTIN_CIPHER 1
#endif /* MCUBOOT_ENCRYPT_X25519 */
#if defined(MCUBOOT_ENCRYPT_KW)
#define MBEDTLS_PSA_CRYPTO_CONFIG
#define MBEDTLS_POLY1305_C
#endif /* MCUBOOT_ENCRYPT_KW */
#if MBEDTLS_VERSION_NUMBER == 0x03000000
/* This PSA define is available only with more recent versions of 3.x */
#define PSA_KEY_ID_NULL ((psa_key_id_t)0) // not overly happy with this being here
#endif /* MBEDTLS_VERSION_NUMBER == 0x03000000 */
#endif /* MCUBOOT_MBEDTLS_CONFIG_ADD_PSA_CRYPTO_H */

View File

@@ -0,0 +1,44 @@
/*
* Configuration of mbedTLS containing only the ASN.1 parser.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - RSA or ECDSA signature verification
*/
#ifndef MBEDTLS_CONFIG_ASN1_H
#define MBEDTLS_CONFIG_ASN1_H
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
// #define MBEDTLS_ASN1_WRITE_C
// #define MBEDTLS_BIGNUM_C
// #define MBEDTLS_MD_C
// #define MBEDTLS_OID_C
// #define MBEDTLS_SHA256_C
#endif /* MBEDTLS_CONFIG_ASN1_H */

View File

@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arm Limited
*/
#ifndef MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA
#define MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include "config-add-psa-crypto.h"
#endif
#define MBEDTLS_ECP_C
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_ECDSA_C
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_AES_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#if defined(MCUBOOT_SIGN_EC384)
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#else
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#endif /* MCUBOOT_SIGN_EC384 */
#endif /* MCUBOOT_PSA_CRYPTO_CONFIG_ECDSA */

View File

@@ -0,0 +1,95 @@
/*
* Minimal configuration for using TLS in the bootloader
*
* Copyright (C) 2006-2021, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - RSA or ECDSA signature verification
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_ECDSA
#define MCUBOOT_MBEDTLS_CONFIG_ECDSA
#ifdef CONFIG_MCUBOOT_SERIAL
/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
#define MBEDTLS_BASE64_C
#endif
/* System support */
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
/* STD functions */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_EXIT_ALT
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#if !defined(CONFIG_ARM)
#define MBEDTLS_HAVE_ASM
#endif
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECDH_C
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_AES_C
/* Bring in support for x509. */
#define MBEDTLS_X509_USE_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_X509_CRT_PARSE_C
/* Save RAM by adjusting to our exact needs */
#define MBEDTLS_ECP_MAX_BITS 256
#define MBEDTLS_MPI_MAX_SIZE 32
#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
/* If encryption is being used, also enable the features needed for
* that. */
#if defined(MCUBOOT_ENC_IMAGES)
#define MBEDTLS_CIPHER_MODE_CTR
#define MBEDTLS_CIPHER_C
#define MBEDTLS_NIST_KW_C
#endif /* MCUBOOT_ENC_IMAGES */
#endif /* MCUBOOT_MBEDTLS_CONFIG_ECDSA */

View File

@@ -0,0 +1,77 @@
/*
* Configuration of mbedTLS containing only the ASN.1 parser.
*
* Copyright (C) 2006-2021, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - ed25519 signature verification
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_ED25519
#define MCUBOOT_MBEDTLS_CONFIG_ED25519
#ifdef CONFIG_MCUBOOT_SERIAL
/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
#define MBEDTLS_BASE64_C
#endif
/* System support */
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
/* STD functions */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_EXIT_ALT
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#if !defined(CONFIG_ARM)
#define MBEDTLS_HAVE_ASM
#endif
#define MBEDTLS_CIPHER_MODE_CTR
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_AES_C
/* Save RAM by adjusting to our exact needs */
//#define MBEDTLS_ECP_MAX_BITS 2048
#define MBEDTLS_MPI_MAX_SIZE 64
//#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
#endif /* MCUBOOT_MBEDTLS_CONFIG_RSA */

View File

@@ -0,0 +1,65 @@
/*
* Minimal configuration for using TLS in the bootloader
*
* Copyright (C) 2006-2021, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - RSA or ECDSA signature verification
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_KW
#define MCUBOOT_MBEDTLS_CONFIG_KW
#ifdef CONFIG_MCUBOOT_SERIAL
/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
#define MBEDTLS_BASE64_C
#endif
/* System support */
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
/* STD functions */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_EXIT_ALT
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#define MBEDTLS_ASN1_PARSE_C
#if !defined(CONFIG_ARM)
#define MBEDTLS_HAVE_ASM
#endif
#define MBEDTLS_CIPHER_MODE_CTR
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_AES_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_NIST_KW_C
#endif /* MCUBOOT_MBEDTLS_CONFIG_KW */

View File

@@ -0,0 +1,84 @@
/*
* Minimal configuration for using TLS in the bootloader
*
* Copyright (C) 2006-2023, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - RSA signature verification + NIST Keywrapping support
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_RSA_KW
#define MCUBOOT_MBEDTLS_CONFIG_RSA_KW
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include "config-add-psa-crypto.h"
#endif /* defined(MCUBOOT_USE_PSA_CRYPTO) */
#ifdef CONFIG_MCUBOOT_SERIAL
/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
#define MBEDTLS_BASE64_C
#endif
/* System support */
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
/* STD functions */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_EXIT_ALT
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#if !defined(CONFIG_ARM)
#define MBEDTLS_HAVE_ASM
#endif
#define MBEDTLS_RSA_C
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_CIPHER_MODE_CTR
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_AES_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_NIST_KW_C
/* Save RAM by adjusting to our exact needs */
#define MBEDTLS_ECP_MAX_BITS 2048
#define MBEDTLS_MPI_MAX_SIZE 256
#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
#endif /* MCUBOOT_MBEDTLS_CONFIG_RSA_KW */

View File

@@ -0,0 +1,85 @@
/*
* Minimal configuration for using TLS in the bootloader
*
* Copyright (C) 2006-2023, ARM Limited, All Rights Reserved
* Copyright (C) 2016, Linaro Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Minimal configuration for using TLS in the bootloader
*
* - RSA or ECDSA signature verification
*/
#ifndef MCUBOOT_MBEDTLS_CONFIG_RSA
#define MCUBOOT_MBEDTLS_CONFIG_RSA
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include "config-add-psa-crypto.h"
#endif
#ifdef CONFIG_MCUBOOT_SERIAL
/* Mcuboot uses mbedts-base64 for serial protocol encoding. */
#define MBEDTLS_BASE64_C
#endif
/* System support */
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
/* STD functions */
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_PLATFORM_EXIT_ALT
#define MBEDTLS_PLATFORM_PRINTF_ALT
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#if !defined(CONFIG_ARM)
#define MBEDTLS_HAVE_ASM
#endif
#define MBEDTLS_RSA_C
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_CIPHER_MODE_CTR
/* mbed TLS modules */
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_AES_C
#if (CONFIG_BOOT_SIGNATURE_TYPE_RSA_LEN == 3072)
#define MBEDTLS_MPI_MAX_SIZE 384
#else
#define MBEDTLS_MPI_MAX_SIZE 256
#endif
#define MBEDTLS_SSL_MAX_CONTENT_LEN 1024
/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
#endif /* MCUBOOT_MBEDTLS_CONFIG_RSA */

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/* This file mocks zephyr's flash map / DT macro */
#ifndef __DEVICETREE_H__
#define __DEVICETREE_H__
#define FLASH_AREA_ID(x) FLASH_AREA_ID_##x
#define FLASH_AREA_ID_image_0 1
#define FLASH_AREA_ID_image_1 2
#define FLASH_AREA_ID_image_scratch 3
#define FLASH_AREA_ID_image_2 4
#define FLASH_AREA_ID_image_3 5
#endif /*__DEVICETREE_H__*/

View File

@@ -0,0 +1,38 @@
#ifndef __FLASH_MAP_BACKEND_H__
#define __FLASH_MAP_BACKEND_H__
#include <storage/flash_map.h>
static inline uint32_t flash_area_get_off(const struct flash_area *fa)
{
return (uint32_t)fa->fa_off;
}
static inline uint32_t flash_area_get_size(const struct flash_area *fa)
{
return (uint32_t)fa->fa_size;
}
static inline uint32_t flash_sector_get_off(const struct flash_sector *fs)
{
return fs->fs_off;
}
static inline uint32_t flash_sector_get_size(const struct flash_sector *fs)
{
return fs->fs_size;
}
#define FLASH_DEVICE_ID 0
static inline uint8_t flash_area_get_device_id(const struct flash_area *fa)
{
return fa->fa_device_id;
}
static inline uint8_t flash_area_get_id(const struct flash_area *fa)
{
return fa->fa_id;
}
#endif /* __FLASH_MAP_BACKEND_H__*/

View File

@@ -0,0 +1,330 @@
/*
* 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 <bootutil/sign_key.h>
#include <mcuboot_config/mcuboot_config.h>
#if defined(MCUBOOT_SIGN_RSA)
#if MCUBOOT_SIGN_RSA_LEN == 2048
#define HAVE_KEYS
const unsigned char root_pub_der[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd1, 0x06, 0x08,
0x1a, 0x18, 0x44, 0x2c, 0x18, 0xe8, 0xfb, 0xfd, 0xf7, 0x0d, 0xa3, 0x4f,
0x1f, 0xbb, 0xee, 0x5e, 0xf9, 0xaa, 0xd2, 0x4b, 0x18, 0xd3, 0x5a, 0xe9,
0x6d, 0x18, 0x80, 0x19, 0xf9, 0xf0, 0x9c, 0x34, 0x1b, 0xcb, 0xf3, 0xbc,
0x74, 0xdb, 0x42, 0xe7, 0x8c, 0x7f, 0x10, 0x53, 0x7e, 0x43, 0x5e, 0x0d,
0x57, 0x2c, 0x44, 0xd1, 0x67, 0x08, 0x0f, 0x0d, 0xbb, 0x5c, 0xee, 0xec,
0xb3, 0x99, 0xdf, 0xe0, 0x4d, 0x84, 0x0b, 0xaa, 0x77, 0x41, 0x60, 0xed,
0x15, 0x28, 0x49, 0xa7, 0x01, 0xb4, 0x3c, 0x10, 0xe6, 0x69, 0x8c, 0x2f,
0x5f, 0xac, 0x41, 0x4d, 0x9e, 0x5c, 0x14, 0xdf, 0xf2, 0xf8, 0xcf, 0x3d,
0x1e, 0x6f, 0xe7, 0x5b, 0xba, 0xb4, 0xa9, 0xc8, 0x88, 0x7e, 0x47, 0x3c,
0x94, 0xc3, 0x77, 0x67, 0x54, 0x4b, 0xaa, 0x8d, 0x38, 0x35, 0xca, 0x62,
0x61, 0x7e, 0xb7, 0xe1, 0x15, 0xdb, 0x77, 0x73, 0xd4, 0xbe, 0x7b, 0x72,
0x21, 0x89, 0x69, 0x24, 0xfb, 0xf8, 0x65, 0x6e, 0x64, 0x3e, 0xc8, 0x0e,
0xd7, 0x85, 0xd5, 0x5c, 0x4a, 0xe4, 0x53, 0x0d, 0x2f, 0xff, 0xb7, 0xfd,
0xf3, 0x13, 0x39, 0x83, 0x3f, 0xa3, 0xae, 0xd2, 0x0f, 0xa7, 0x6a, 0x9d,
0xf9, 0xfe, 0xb8, 0xce, 0xfa, 0x2a, 0xbe, 0xaf, 0xb8, 0xe0, 0xfa, 0x82,
0x37, 0x54, 0xf4, 0x3e, 0xe1, 0x2b, 0xd0, 0xd3, 0x08, 0x58, 0x18, 0xf6,
0x5e, 0x4c, 0xc8, 0x88, 0x81, 0x31, 0xad, 0x5f, 0xb0, 0x82, 0x17, 0xf2,
0x8a, 0x69, 0x27, 0x23, 0xf3, 0xab, 0x87, 0x3e, 0x93, 0x1a, 0x1d, 0xfe,
0xe8, 0xf8, 0x1a, 0x24, 0x66, 0x59, 0xf8, 0x1c, 0xab, 0xdc, 0xce, 0x68,
0x1b, 0x66, 0x64, 0x35, 0xec, 0xfa, 0x0d, 0x11, 0x9d, 0xaf, 0x5c, 0x3a,
0xa7, 0xd1, 0x67, 0xc6, 0x47, 0xef, 0xb1, 0x4b, 0x2c, 0x62, 0xe1, 0xd1,
0xc9, 0x02, 0x03, 0x01, 0x00, 0x01
};
const unsigned int root_pub_der_len = 270;
#elif MCUBOOT_SIGN_RSA_LEN == 3072
#define HAVE_KEYS
const unsigned char root_pub_der[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
0x00, 0xb4, 0x2c, 0x0e, 0x98, 0x58, 0x10, 0xa4,
0xa7, 0x58, 0x99, 0x7c, 0x01, 0xdd, 0x08, 0x2a,
0x28, 0x34, 0x33, 0xf8, 0x96, 0x1a, 0x34, 0x20,
0x5d, 0x45, 0xc8, 0x71, 0x26, 0x25, 0xe5, 0xd2,
0x96, 0xea, 0x7b, 0xb1, 0x15, 0xaa, 0xa6, 0x8a,
0x63, 0x22, 0x8b, 0x2d, 0x4e, 0x81, 0x73, 0xbf,
0x6e, 0x15, 0x68, 0x8c, 0x1a, 0xf4, 0xef, 0x2a,
0x8f, 0x8c, 0x22, 0x9e, 0x71, 0x57, 0x4b, 0xde,
0x0f, 0x7e, 0x72, 0xd3, 0x7a, 0xb8, 0xa7, 0x1d,
0x44, 0xad, 0x87, 0x00, 0x83, 0x5c, 0xfd, 0x73,
0x05, 0x72, 0x46, 0x3f, 0x8b, 0xf9, 0x10, 0x00,
0xd8, 0x6e, 0xcc, 0x85, 0xed, 0xf9, 0x49, 0xdb,
0x78, 0x36, 0x80, 0x49, 0x38, 0x76, 0xdd, 0x5f,
0x54, 0x04, 0xda, 0x8c, 0x34, 0xa7, 0x2b, 0x13,
0x25, 0x6f, 0xd1, 0x15, 0x4f, 0xad, 0xc2, 0xe1,
0xa5, 0xd2, 0x4e, 0x57, 0x0c, 0x7e, 0x9c, 0x9b,
0xba, 0x4e, 0x68, 0xb2, 0xe0, 0x25, 0x02, 0xaa,
0x00, 0xd3, 0xb4, 0xcc, 0x2f, 0x78, 0xe5, 0xbe,
0x47, 0x67, 0x1f, 0xc8, 0x6e, 0x22, 0x6c, 0x5e,
0x61, 0xb6, 0x9a, 0xcd, 0xe5, 0xa8, 0xba, 0x7a,
0x80, 0x13, 0x1b, 0x17, 0x2e, 0x96, 0xed, 0xcf,
0xb3, 0x9b, 0xe4, 0x1c, 0xe8, 0xad, 0xa7, 0xf6,
0x3a, 0x51, 0x66, 0x5e, 0x99, 0x8e, 0x87, 0xee,
0x60, 0x25, 0xf8, 0x8d, 0xbe, 0xce, 0xa4, 0xa8,
0xca, 0x93, 0x6c, 0xd7, 0xbf, 0xd4, 0x73, 0x33,
0x8d, 0x44, 0x85, 0xcc, 0x73, 0x30, 0x08, 0x9c,
0x4d, 0xb2, 0xaa, 0x5a, 0x6c, 0x6f, 0x7b, 0xab,
0xb7, 0xb3, 0x7c, 0xc3, 0xfb, 0xe7, 0xca, 0xc4,
0xf8, 0x9a, 0x6f, 0xcb, 0xbb, 0x5b, 0x82, 0xe7,
0x7a, 0xe8, 0x19, 0xfd, 0x2f, 0x11, 0x22, 0xfb,
0x7f, 0x76, 0x8c, 0x6b, 0x94, 0xa4, 0x09, 0x4f,
0xa5, 0x6a, 0x77, 0x51, 0xeb, 0xa7, 0x7e, 0xda,
0x87, 0x06, 0xee, 0xdc, 0xbe, 0xd1, 0xea, 0x1a,
0x40, 0x1d, 0x1b, 0xff, 0x1a, 0xb1, 0x51, 0x7c,
0x12, 0xb0, 0xf3, 0xf6, 0x83, 0x01, 0x9c, 0xe7,
0x0c, 0x99, 0xbf, 0xac, 0x68, 0x58, 0x72, 0xa4,
0xb0, 0x59, 0x85, 0xee, 0x85, 0xac, 0x2a, 0x22,
0xf4, 0xcf, 0x15, 0x08, 0x80, 0x1f, 0x0d, 0xd0,
0x1e, 0xa0, 0xa0, 0x94, 0xc8, 0xf7, 0xfa, 0x65,
0xdd, 0x52, 0xe8, 0x96, 0x37, 0x23, 0x30, 0x57,
0x36, 0xe6, 0x9d, 0xf4, 0x0c, 0x4a, 0x05, 0x75,
0x1f, 0xad, 0x01, 0xca, 0xb7, 0x6d, 0x8c, 0x43,
0x74, 0x06, 0x0a, 0x81, 0xf3, 0x01, 0x62, 0xff,
0xf7, 0xf5, 0x5f, 0xaf, 0xe7, 0x2b, 0x0e, 0xf8,
0x81, 0xb5, 0x65, 0xdd, 0x01, 0xd9, 0x9f, 0x07,
0x17, 0x8a, 0x18, 0xcf, 0x23, 0x6e, 0x88, 0x65,
0x91, 0xb5, 0x7b, 0xd3, 0xb0, 0x2d, 0xaf, 0x93,
0x66, 0x63, 0x74, 0xac, 0x5a, 0xe6, 0x73, 0xde,
0x3b, 0x02, 0x03, 0x01, 0x00, 0x01,
};
const unsigned int root_pub_der_len = 398;
#endif
#elif defined(MCUBOOT_SIGN_EC256) || \
defined(MCUBOOT_SIGN_EC384)
#define HAVE_KEYS
#ifndef MCUBOOT_SIGN_EC384
const unsigned char root_pub_der[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0x2a, 0xcb, 0x40, 0x3c, 0xe8,
0xfe, 0xed, 0x5b, 0xa4, 0x49, 0x95, 0xa1, 0xa9,
0x1d, 0xae, 0xe8, 0xdb, 0xbe, 0x19, 0x37, 0xcd,
0x14, 0xfb, 0x2f, 0x24, 0x57, 0x37, 0xe5, 0x95,
0x39, 0x88, 0xd9, 0x94, 0xb9, 0xd6, 0x5a, 0xeb,
0xd7, 0xcd, 0xd5, 0x30, 0x8a, 0xd6, 0xfe, 0x48,
0xb2, 0x4a, 0x6a, 0x81, 0x0e, 0xe5, 0xf0, 0x7d,
0x8b, 0x68, 0x34, 0xcc, 0x3a, 0x6a, 0xfc, 0x53,
0x8e, 0xfa, 0xc1, };
const unsigned int root_pub_der_len = 91;
#else /* MCUBOOT_SIGN_EC384 */
const unsigned char root_pub_der[] = {
0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04,
0x0c, 0x76, 0xca, 0xae, 0x72, 0x3a, 0xa5, 0xe8,
0xf0, 0xd4, 0xf1, 0x16, 0xb5, 0x02, 0xef, 0x77,
0xa1, 0x1b, 0x93, 0x61, 0x78, 0xc0, 0x09, 0x26,
0x7b, 0x3b, 0x40, 0x9c, 0xee, 0x49, 0x85, 0xe0,
0xc9, 0x4f, 0xe7, 0xf2, 0xba, 0x97, 0x6c, 0xf3,
0x82, 0x65, 0x14, 0x2c, 0xf5, 0x0c, 0x73, 0x33,
0x4d, 0x32, 0xe7, 0x9b, 0xd3, 0x42, 0xcc, 0x95,
0x5a, 0xe5, 0xe2, 0xf5, 0xf4, 0x6e, 0x45, 0xe0,
0xed, 0x20, 0x35, 0x5c, 0xaf, 0x52, 0x35, 0x81,
0xd4, 0xdc, 0x9c, 0xe3, 0x9e, 0x22, 0x3e, 0xfb,
0x3f, 0x22, 0x10, 0xda, 0x70, 0x03, 0x37, 0xad,
0xa8, 0xf2, 0x48, 0xfe, 0x3a, 0x60, 0x69, 0xa5,
};
const unsigned int root_pub_der_len = 120;
#endif /* MCUBOOT_SIGN_EC384 */
#elif defined(MCUBOOT_SIGN_ED25519)
#define HAVE_KEYS
const unsigned char root_pub_der[] = {
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
0x70, 0x03, 0x21, 0x00, 0xd4, 0xb3, 0x1b, 0xa4,
0x9a, 0x3a, 0xdd, 0x3f, 0x82, 0x5d, 0x10, 0xca,
0x7f, 0x31, 0xb5, 0x0b, 0x0d, 0xe8, 0x7f, 0x37,
0xcc, 0xc4, 0x9f, 0x1a, 0x40, 0x3a, 0x5c, 0x13,
0x20, 0xff, 0xb4, 0xe0,
};
const unsigned int root_pub_der_len = 44;
#endif
#if defined(HAVE_KEYS)
const struct bootutil_key bootutil_keys[] = {
{
.key = root_pub_der,
.len = &root_pub_der_len,
},
};
const int bootutil_key_cnt = 1;
#endif
#if defined(MCUBOOT_ENCRYPT_RSA)
unsigned char enc_key[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xb4, 0x26, 0x14, 0x49, 0x3d, 0x16, 0x13, 0x3a, 0x6d, 0x9c, 0x84, 0xa9,
0x8b, 0x6a, 0x10, 0x20, 0x61, 0xef, 0x48, 0x04, 0xa4, 0x4b, 0x24, 0xf3,
0x00, 0x32, 0xac, 0x22, 0xe0, 0x30, 0x27, 0x70, 0x18, 0xe5, 0x55, 0xc8,
0xb8, 0x05, 0x34, 0x03, 0xb0, 0xf8, 0xa5, 0x96, 0xd2, 0x48, 0x58, 0xef,
0x70, 0xb0, 0x09, 0xdb, 0xe3, 0x58, 0x62, 0xef, 0x99, 0x63, 0x01, 0xb2,
0x89, 0xc4, 0xb3, 0xf6, 0x9e, 0x62, 0xbf, 0x4d, 0xc2, 0x8a, 0xd0, 0xc9,
0x4d, 0x43, 0xa3, 0xd8, 0xe5, 0x1d, 0xec, 0x62, 0x63, 0x08, 0xe2, 0x20,
0xa5, 0xfc, 0x78, 0xd0, 0x3e, 0x74, 0xc8, 0xa4, 0x1b, 0x36, 0xad, 0x7b,
0xf5, 0x06, 0xae, 0x4d, 0x51, 0x9b, 0x40, 0xce, 0x30, 0x4f, 0x6c, 0xea,
0xf9, 0xe9, 0x74, 0xea, 0x06, 0xee, 0x9c, 0xe4, 0x14, 0x68, 0x20, 0xb9,
0x3d, 0xe7, 0x11, 0x14, 0x8b, 0x25, 0xa3, 0xff, 0x4c, 0x8a, 0xf3, 0x53,
0xee, 0x6b, 0x3e, 0xef, 0x34, 0xcd, 0x6a, 0x3f, 0x62, 0x68, 0xc0, 0xff,
0x78, 0x4c, 0xb0, 0xc3, 0xe6, 0x96, 0x61, 0xfc, 0x1f, 0x18, 0xf1, 0x7a,
0x82, 0xe2, 0x8f, 0x35, 0xa8, 0x2b, 0x86, 0x16, 0xa4, 0x46, 0xfb, 0xac,
0x7e, 0x41, 0xdb, 0x02, 0x05, 0x91, 0x6d, 0xdf, 0xc1, 0xde, 0x13, 0x95,
0x9c, 0xf9, 0x9e, 0x5e, 0x72, 0xba, 0xa7, 0x25, 0x93, 0xfb, 0xdc, 0xe8,
0xab, 0x86, 0x45, 0x88, 0x47, 0x2d, 0xed, 0xee, 0xee, 0x97, 0x9e, 0xce,
0x5d, 0x9b, 0x04, 0x04, 0x40, 0x7c, 0xcb, 0x7c, 0x3d, 0x2c, 0x74, 0xab,
0xa4, 0xcc, 0x64, 0xa3, 0x5c, 0x95, 0x3d, 0xd4, 0xa2, 0xdc, 0x92, 0xb2,
0xc8, 0x18, 0xcb, 0xf9, 0x00, 0x39, 0x81, 0x8f, 0x8f, 0x40, 0xc2, 0xdf,
0x99, 0x29, 0xac, 0x8a, 0xc2, 0x3b, 0xd8, 0xa4, 0xf2, 0xad, 0xaf, 0x74,
0xc0, 0x11, 0xc7, 0x99, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x42, 0x47, 0x80, 0x4f, 0x31, 0xda, 0x5d, 0x58, 0xb1, 0xdb, 0x54,
0x33, 0xcc, 0xc7, 0x49, 0x07, 0xa1, 0x00, 0x98, 0x4e, 0x9c, 0xe3, 0xc8,
0xc4, 0x5e, 0xde, 0x45, 0xd6, 0xcf, 0x04, 0xe8, 0x7d, 0xa5, 0xab, 0x3a,
0xd4, 0x8e, 0x5f, 0xdb, 0xb3, 0x3f, 0xf9, 0x3b, 0x73, 0x32, 0x0a, 0xcc,
0x2d, 0xcc, 0x17, 0xf8, 0x88, 0x9e, 0x2c, 0x76, 0xba, 0x10, 0x85, 0x0c,
0xaa, 0xd3, 0x65, 0x3b, 0x91, 0x10, 0xd4, 0xe3, 0xed, 0x88, 0x15, 0xea,
0x9b, 0x25, 0x82, 0x2d, 0x56, 0x2f, 0x75, 0xc2, 0xf2, 0xaf, 0xdd, 0x24,
0xd5, 0x3e, 0x3c, 0x95, 0x76, 0x88, 0x84, 0x0f, 0x0d, 0xd1, 0xb5, 0x5c,
0x3e, 0xae, 0xf7, 0xb6, 0x49, 0x5c, 0x2c, 0xf2, 0xba, 0xe9, 0xab, 0x4f,
0x37, 0x64, 0x9b, 0x30, 0x18, 0xaa, 0x54, 0x40, 0x04, 0xea, 0x3d, 0x25,
0x4d, 0x02, 0x29, 0x71, 0x6f, 0x4d, 0x82, 0x9b, 0xc3, 0x44, 0x2a, 0x9d,
0x0c, 0x98, 0xd3, 0xc8, 0x15, 0x0d, 0x04, 0x93, 0x60, 0x30, 0xc7, 0x5e,
0x79, 0xea, 0x53, 0x9d, 0xc0, 0x0e, 0x81, 0xac, 0x90, 0xbc, 0x9e, 0x1e,
0xd2, 0x28, 0x0f, 0x10, 0xf5, 0x1f, 0xdf, 0x38, 0x7f, 0x8a, 0x90, 0x8d,
0x49, 0x07, 0x7d, 0x78, 0xcb, 0xa7, 0xef, 0x92, 0x6d, 0x3b, 0x13, 0x95,
0x9b, 0xba, 0x83, 0xc6, 0xb3, 0x71, 0x25, 0x27, 0x07, 0x99, 0x54, 0x82,
0x3d, 0xec, 0xc5, 0xf8, 0xb4, 0xa0, 0x38, 0x7a, 0x59, 0x6a, 0x0b, 0xca,
0x69, 0x6c, 0x17, 0xa4, 0x18, 0xe0, 0xb4, 0xaa, 0x89, 0x99, 0x8f, 0xcb,
0x71, 0x34, 0x09, 0x1b, 0x6e, 0xe6, 0x87, 0x00, 0xb5, 0xba, 0x70, 0x8a,
0x29, 0x3d, 0x9a, 0x06, 0x18, 0x2d, 0x66, 0x5e, 0x61, 0x37, 0xeb, 0xdd,
0x5e, 0xc8, 0x28, 0x92, 0x05, 0x30, 0xfd, 0xb8, 0x65, 0xb1, 0x7f, 0xbf,
0x2d, 0x55, 0x12, 0x91, 0xc1, 0x02, 0x81, 0x81, 0x00, 0xda, 0x65, 0xda,
0x38, 0x7c, 0x18, 0xfb, 0x00, 0x11, 0x60, 0xeb, 0x37, 0x65, 0xb8, 0x83,
0x62, 0x88, 0xc4, 0x3a, 0x4e, 0x64, 0x6a, 0xf3, 0x3e, 0x4e, 0xc0, 0x34,
0x19, 0x8a, 0xcb, 0x4a, 0xca, 0x2f, 0x5d, 0x50, 0x7a, 0xac, 0xf7, 0x9e,
0x87, 0x5a, 0xfc, 0x4d, 0x49, 0xd7, 0xf9, 0x21, 0xf5, 0x0b, 0x6f, 0x57,
0x41, 0x3d, 0x8f, 0xb8, 0xec, 0x7f, 0xcc, 0x92, 0x09, 0xbe, 0xd3, 0xa4,
0xc3, 0x14, 0x85, 0x21, 0x5d, 0x05, 0xa3, 0xaa, 0x20, 0xf6, 0x62, 0x44,
0x50, 0x03, 0x5e, 0x53, 0x4a, 0xcd, 0x6a, 0xb6, 0x65, 0x8e, 0x4e, 0x4b,
0x3f, 0x25, 0xc6, 0x16, 0x31, 0xf5, 0x99, 0x13, 0x77, 0x42, 0xda, 0xdc,
0x70, 0x4d, 0x65, 0xb0, 0x99, 0x0f, 0xdf, 0x5a, 0xb1, 0x45, 0xf0, 0xb9,
0x8e, 0xa0, 0xae, 0x4f, 0x4d, 0x65, 0x09, 0x84, 0xb5, 0x38, 0x29, 0xbf,
0x69, 0xe0, 0x88, 0x1f, 0x27, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x2a, 0x59,
0xec, 0x28, 0xc3, 0x0d, 0x4f, 0x92, 0x96, 0xca, 0x67, 0x94, 0xfc, 0x2e,
0xa6, 0x86, 0x68, 0x45, 0x53, 0x92, 0xcc, 0x86, 0x7f, 0x8a, 0xe1, 0x5d,
0xe8, 0x1d, 0x9e, 0xbb, 0x1e, 0x00, 0x26, 0x1d, 0x80, 0x12, 0xff, 0x9c,
0x11, 0x0a, 0xbd, 0xa6, 0xc3, 0x8d, 0x48, 0xda, 0xfc, 0x10, 0xf7, 0x7a,
0x16, 0x07, 0x15, 0xa0, 0x3a, 0xd3, 0x94, 0xfb, 0x52, 0x87, 0x39, 0xee,
0xe7, 0xc4, 0x26, 0x49, 0x16, 0xc6, 0xc0, 0x83, 0x25, 0xbf, 0x6a, 0x4e,
0x8c, 0x0b, 0x10, 0x85, 0x66, 0xab, 0x7e, 0xae, 0xac, 0x4c, 0x69, 0x3c,
0x44, 0xeb, 0xcd, 0xe9, 0xf6, 0x64, 0x8b, 0x4a, 0xd8, 0x6a, 0x4d, 0x6d,
0x47, 0xa9, 0xb8, 0x55, 0x72, 0xc1, 0xfd, 0xf4, 0x81, 0x4c, 0x66, 0xbe,
0x49, 0xf2, 0x75, 0x4f, 0x80, 0xf1, 0x20, 0x38, 0xb8, 0x6a, 0x1b, 0x75,
0x41, 0x30, 0x0f, 0x1b, 0x3f, 0x02, 0x81, 0x80, 0x09, 0x35, 0xfa, 0x7a,
0x1f, 0x61, 0xbe, 0x54, 0x46, 0x67, 0x5c, 0x04, 0x3e, 0x1a, 0x06, 0x10,
0x85, 0xcc, 0x20, 0xd9, 0x65, 0x8a, 0xcd, 0x2f, 0x77, 0x8a, 0xcb, 0xa7,
0xb8, 0x1e, 0xd2, 0xcc, 0xac, 0x2a, 0xb7, 0x56, 0x35, 0x2d, 0x4c, 0x56,
0x51, 0x14, 0x0a, 0xfe, 0x6e, 0x49, 0x67, 0x91, 0x3a, 0x26, 0x3b, 0xfb,
0xd8, 0x68, 0xd3, 0x57, 0xc6, 0x1c, 0x0e, 0x9c, 0xb2, 0x9b, 0xa2, 0x7b,
0x47, 0xc6, 0x45, 0x9d, 0xf2, 0xba, 0xf0, 0x55, 0xeb, 0x8e, 0x41, 0x6b,
0x4e, 0x79, 0x0f, 0xf2, 0x3b, 0xaf, 0xa0, 0x79, 0xb0, 0x02, 0xc5, 0x51,
0xa8, 0x7a, 0x2e, 0x3d, 0x75, 0x2a, 0x3b, 0x93, 0xf0, 0x11, 0xe2, 0xf2,
0x29, 0x91, 0x7c, 0x5d, 0x38, 0x3a, 0x27, 0x4d, 0x0a, 0xb2, 0x18, 0x61,
0x57, 0x8d, 0x82, 0x72, 0xb5, 0x2c, 0x2d, 0x98, 0xa7, 0x01, 0xbb, 0xbc,
0xef, 0x67, 0x4e, 0x49, 0x02, 0x81, 0x81, 0x00, 0xb2, 0x70, 0x53, 0x54,
0x70, 0x8d, 0x82, 0xad, 0xff, 0x1d, 0x55, 0x24, 0x7a, 0x8d, 0x2f, 0x8e,
0xa0, 0x7d, 0x74, 0x37, 0xcf, 0x10, 0xed, 0x86, 0xd1, 0x80, 0xe7, 0xad,
0xc1, 0x79, 0xe4, 0x7c, 0xd1, 0x7b, 0x63, 0xea, 0x5a, 0x23, 0x8d, 0x6a,
0x09, 0x3d, 0x81, 0xb2, 0x35, 0xad, 0x9e, 0xfe, 0xea, 0x07, 0x76, 0x2f,
0x2f, 0x05, 0x63, 0x44, 0xd2, 0x8e, 0x4e, 0x61, 0xca, 0xcb, 0x75, 0xca,
0x7b, 0xc2, 0x2e, 0x79, 0x04, 0xb2, 0xa1, 0x20, 0x40, 0xc4, 0x40, 0x63,
0xae, 0xe5, 0xe3, 0x14, 0x83, 0x4e, 0xa5, 0xa4, 0x0b, 0x5d, 0xd2, 0x04,
0x1b, 0x8f, 0x01, 0x69, 0xa8, 0x44, 0xdc, 0x96, 0x4c, 0x1d, 0xe9, 0x7e,
0x69, 0x38, 0xcf, 0x5c, 0x0d, 0xf9, 0xdf, 0xa7, 0x73, 0x3c, 0x4f, 0x08,
0x85, 0xce, 0x03, 0xc4, 0xdd, 0xfd, 0x70, 0x70, 0xc5, 0x99, 0x36, 0x58,
0x43, 0x98, 0x40, 0x59, 0x02, 0x81, 0x81, 0x00, 0xd5, 0xaa, 0xfb, 0xec,
0x8d, 0xc6, 0xdd, 0xfa, 0x2b, 0x5a, 0x24, 0xd0, 0xda, 0x58, 0xbd, 0x87,
0x92, 0x1a, 0x29, 0x62, 0x13, 0x1d, 0x4b, 0x79, 0x1b, 0xbe, 0x79, 0x7d,
0xad, 0x79, 0xca, 0x17, 0x75, 0xda, 0xe8, 0x32, 0xe8, 0xa0, 0x9e, 0xa8,
0x77, 0x53, 0xac, 0x38, 0xd6, 0xeb, 0xe6, 0x22, 0x65, 0xc4, 0xaa, 0x4c,
0xc8, 0xd0, 0x33, 0x1a, 0x1e, 0xbe, 0xbd, 0x73, 0x09, 0x4a, 0xfa, 0x85,
0x5c, 0xf3, 0x0c, 0x9c, 0x81, 0x56, 0x30, 0xa7, 0xf7, 0x9b, 0xf4, 0x92,
0x9c, 0x6b, 0x93, 0x6a, 0x00, 0x33, 0xdc, 0x2f, 0x54, 0x1e, 0x78, 0xd4,
0x97, 0xec, 0x24, 0xa2, 0xdb, 0x3d, 0x03, 0x33, 0x09, 0xb2, 0x2c, 0x03,
0x05, 0x40, 0xde, 0x52, 0xf2, 0x9b, 0xfa, 0x00, 0x8d, 0x4b, 0xfe, 0x5b,
0x9b, 0x9c, 0x73, 0xad, 0xfb, 0x7a, 0x00, 0x42, 0x62, 0x9e, 0xa0, 0x95,
0x55, 0x50, 0x32, 0x87
};
static unsigned int enc_key_len = 1192;
const struct bootutil_key bootutil_enc_key = {
.key = enc_key,
.len = &enc_key_len,
};
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
#if defined(MCUBOOT_AES_256)
unsigned char enc_key[] = {
0xE4, 0x5C, 0x51, 0x46, 0xD2, 0x1C, 0x82, 0x35, 0xCC, 0x1A, 0x19, 0xAF,
0xA1, 0xF2, 0xAA, 0x20, 0xC8, 0x8C, 0x7F, 0x40, 0x6C, 0xDB, 0x22, 0xAA,
0x6A, 0xB5, 0xCB, 0xAA, 0xF8, 0xB1, 0x5B, 0xB4
};
static unsigned int enc_key_len = 32;
#else
unsigned char enc_key[] = {
0xd1, 0x5a, 0x04, 0x95, 0xc4, 0xc2, 0xa8, 0xff, 0x30, 0x78, 0xce, 0x49,
0xb5, 0xfc, 0xb2, 0xdd
};
static unsigned int enc_key_len = 16;
#endif
const struct bootutil_key bootutil_enc_key = {
.key = enc_key,
.len = &enc_key_len,
};
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
unsigned char enc_key[] = {
0x30, 0x81, 0x43, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07, 0x04, 0x29, 0x30, 0x27, 0x02, 0x01, 0x01, 0x04, 0x20,
0xf6, 0x1e, 0x51, 0x9d, 0xf8, 0xfa, 0xdd, 0xa1, 0xb7, 0xd9, 0xa9, 0x64,
0x64, 0x3b, 0x54, 0xd0, 0x3d, 0xd0, 0x1f, 0xe5, 0x78, 0xd9, 0x17, 0x98,
0xa5, 0x28, 0xca, 0xcc, 0x6b, 0x67, 0x9e, 0x06, 0xa1, 0x44,
};
static unsigned int enc_key_len = 70;
const struct bootutil_key bootutil_enc_key = {
.key = enc_key,
.len = &enc_key_len,
};
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
unsigned char enc_key[] = {
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e,
0x04, 0x22, 0x04, 0x20, 0x28, 0x80, 0x2f, 0xef, 0xef, 0x82, 0x95, 0x50,
0xf1, 0x41, 0x93, 0x03, 0x6c, 0x1b, 0xb9, 0x49, 0x6c, 0x51, 0xe5, 0x26,
0x87, 0x8f, 0x77, 0x07, 0xf8, 0xb4, 0x1f, 0x04, 0x45, 0x6d, 0x84, 0x4f,
};
static unsigned int enc_key_len = 48;
const struct bootutil_key bootutil_enc_key = {
.key = enc_key,
.len = &enc_key_len,
};
#endif

View File

@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
/*
* 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.
*/
#ifndef __MCUBOOT_ASSERT_H__
#define __MCUBOOT_ASSERT_H__
#include <assert.h>
void sim_assert(int, const char *test, const char *, unsigned int, const char *);
#define ASSERT(x) sim_assert((x), #x, __FILE__, __LINE__, __func__)
#endif /* __MCUBOOT_ASSERT_H__ */

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MCUBOOT_CONFIG_H__
#define __MCUBOOT_CONFIG_H__
/*
* This file is included by the simulator, but we don't want to
* define almost anything here.
*
* Instead of using mcuboot_config.h, the simulator adds MCUBOOT_xxx
* configuration flags to the compiler command lines based on the
* values of environment variables. However, the file still must
* exist, or bootutil won't build.
*/
#define MCUBOOT_WATCHDOG_FEED() \
do { \
} while (0)
#define MCUBOOT_CPU_IDLE() \
do { \
} while (0)
#endif /* __MCUBOOT_CONFIG_H__ */

View File

@@ -0,0 +1,107 @@
/*
* 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.
*/
#ifndef __MCUBOOT_LOGGING_H__
#define __MCUBOOT_LOGGING_H__
#include <stdio.h>
#define MCUBOOT_LOG_LEVEL_OFF 0
#define MCUBOOT_LOG_LEVEL_ERROR 1
#define MCUBOOT_LOG_LEVEL_WARNING 2
#define MCUBOOT_LOG_LEVEL_INFO 3
#define MCUBOOT_LOG_LEVEL_DEBUG 4
#define MCUBOOT_LOG_LEVEL_SIM 5 /* RUST_LOG=trace */
/*
* The compiled log level determines the maximum level that can be
* printed. Messages at or below this level can be printed, provided
* they are also enabled through the Rust logging system, such as by
* setting RUST_LOG to bootsim::api=info.
*/
#ifndef MCUBOOT_LOG_LEVEL
#define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_DEBUG
#endif
#define MCUBOOT_LOG_MODULE_DECLARE(domain) /* ignore */
#define MCUBOOT_LOG_MODULE_REGISTER(domain) /* ignore */
int sim_log_enabled(int level);
#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_ERROR
#define MCUBOOT_LOG_ERR(_fmt, ...) \
do { \
if (sim_log_enabled(MCUBOOT_LOG_LEVEL_ERROR)) { \
fprintf(stderr, "[ERR] " _fmt "\n", ##__VA_ARGS__); \
fflush(stderr); \
} \
} while (0)
#else
#define MCUBOOT_LOG_ERR(...) IGNORE(__VA_ARGS__)
#endif
#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_WARNING
#define MCUBOOT_LOG_WRN(_fmt, ...) \
do { \
if (sim_log_enabled(MCUBOOT_LOG_LEVEL_WARNING)) { \
fprintf(stderr, "[WRN] " _fmt "\n", ##__VA_ARGS__); \
fflush(stderr); \
} \
} while (0)
#else
#define MCUBOOT_LOG_WRN(...) IGNORE(__VA_ARGS__)
#endif
#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_INFO
#define MCUBOOT_LOG_INF(_fmt, ...) \
do { \
if (sim_log_enabled(MCUBOOT_LOG_LEVEL_INFO)) { \
fprintf(stderr, "[INF] " _fmt "\n", ##__VA_ARGS__); \
fflush(stderr); \
} \
} while (0)
#else
#define MCUBOOT_LOG_INF(...) IGNORE(__VA_ARGS__)
#endif
#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_DEBUG
#define MCUBOOT_LOG_DBG(_fmt, ...) \
do { \
if (sim_log_enabled(MCUBOOT_LOG_LEVEL_DEBUG)) { \
fprintf(stderr, "[DBG] " _fmt "\n", ##__VA_ARGS__); \
fflush(stderr); \
} \
} while (0)
#else
#define MCUBOOT_LOG_DBG(...) IGNORE(__VA_ARGS__)
#endif
#if MCUBOOT_LOG_LEVEL >= MCUBOOT_LOG_LEVEL_SIM
#define MCUBOOT_LOG_SIM(_fmt, ...) \
do { \
if (sim_log_enabled(MCUBOOT_LOG_LEVEL_SIM)) { \
fprintf(stderr, "[SIM] " _fmt "\n", ##__VA_ARGS__); \
fflush(stderr); \
} \
} while (0)
#else
#define MCUBOOT_LOG_SIM(...) IGNORE(__VA_ARGS__)
#endif
#endif /* __MCUBOOT_LOGGING_H__ */

View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_OS_HEAP_
#define H_OS_HEAP_
#endif

View File

@@ -0,0 +1,10 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_OS_MALLOC_
#define H_OS_MALLOC_
#endif

View File

@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arm Limited
*/
/* This file, and the methods within are required when PSA Crypto API is enabled
* (--features psa-crypto-api), but the selected combination of features does
* not rely on any PSA Crypto APIs, and will not be adding any of them to the build.
*/
#include <bootutil/bootutil_log.h>
int psa_crypto_init()
{
BOOT_LOG_SIM("psa_crypto_init() is being stubbed.\n");
return 0;
}
void mbedtls_test_enable_insecure_external_rng(){
BOOT_LOG_SIM("mbedtls_test_enable_insecure_external_rng() is being stubbed.\n");
}

View File

@@ -0,0 +1,543 @@
/* Run the boot image. */
#include <assert.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bootutil/bootutil.h>
#include <bootutil/image.h>
#include <flash_map_backend/flash_map_backend.h>
#include "../../../boot/bootutil/src/bootutil_priv.h"
#include "bootsim.h"
#ifdef MCUBOOT_ENCRYPT_RSA
#include "mbedtls/rsa.h"
#include "mbedtls/asn1.h"
#endif
#ifdef MCUBOOT_ENCRYPT_KW
#include "mbedtls/nist_kw.h"
#endif
#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR
#include <bootutil/bootutil_log.h>
#include "bootutil/crypto/common.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
struct area_desc;
extern struct area_desc *sim_get_flash_areas(void);
extern void sim_set_flash_areas(struct area_desc *areas);
extern void sim_reset_flash_areas(void);
struct sim_context;
extern struct sim_context *sim_get_context(void);
extern void sim_set_context(struct sim_context *ctx);
extern void sim_reset_context(void);
extern int sim_flash_erase(uint8_t flash_id, uint32_t offset, uint32_t size);
extern int sim_flash_read(uint8_t flash_id, uint32_t offset, uint8_t *dest,
uint32_t size);
extern int sim_flash_write(uint8_t flash_id, uint32_t offset, const uint8_t *src,
uint32_t size);
extern uint32_t sim_flash_align(uint8_t flash_id);
extern uint8_t sim_flash_erased_val(uint8_t flash_id);
struct sim_context {
int flash_counter;
int jumped;
uint8_t c_asserts;
uint8_t c_catch_asserts;
jmp_buf boot_jmpbuf;
};
#ifdef MCUBOOT_ENCRYPT_RSA
static int
parse_pubkey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
int rc;
size_t len;
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -3;
}
*p += len;
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_BIT_STRING)) != 0) {
return -4;
}
if (**p != MBEDTLS_ASN1_PRIMITIVE) {
return -5;
}
*p += 1;
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -6;
}
if (mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0) {
return -7;
}
if (mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0) {
return -8;
}
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
if (*p != end) {
return -9;
}
if (mbedtls_rsa_check_pubkey(ctx) != 0) {
return -10;
}
return 0;
}
static int
fake_rng(void *p_rng, unsigned char *output, size_t len)
{
size_t i;
(void)p_rng;
for (i = 0; i < len; i++) {
output[i] = (char)i;
}
return 0;
}
#endif
int mbedtls_platform_set_calloc_free(void * (*calloc_func)(size_t, size_t),
void (*free_func)(void *));
int rsa_oaep_encrypt_(const uint8_t *pubkey, unsigned pubkey_len,
const uint8_t *seckey, unsigned seckey_len,
uint8_t *encbuf)
{
#ifdef MCUBOOT_ENCRYPT_RSA
mbedtls_rsa_context ctx;
uint8_t *cp;
uint8_t *cpend;
int rc;
mbedtls_platform_set_calloc_free(calloc, free);
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
mbedtls_rsa_init(&ctx);
mbedtls_rsa_set_padding(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
#else
mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
#endif
cp = (uint8_t *)pubkey;
cpend = cp + pubkey_len;
rc = parse_pubkey(&ctx, &cp, cpend);
if (rc) {
goto done;
}
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL,
NULL, 0, seckey_len, seckey, encbuf);
#else
rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL, MBEDTLS_RSA_PUBLIC,
NULL, 0, seckey_len, seckey, encbuf);
#endif
if (rc) {
goto done;
}
done:
mbedtls_rsa_free(&ctx);
return rc;
#else
(void)pubkey;
(void)pubkey_len;
(void)seckey;
(void)seckey_len;
(void)encbuf;
return 0;
#endif
}
int kw_encrypt_(const uint8_t *kek, const uint8_t *seckey, uint8_t *encbuf)
{
#ifdef MCUBOOT_ENCRYPT_KW
#ifdef MCUBOOT_AES_256
int key_len = 256;
int out_size = 40;
int in_len = 32;
#else
int key_len = 128;
int out_size = 24;
int in_len = 16;
#endif
mbedtls_nist_kw_context kw;
size_t olen;
int rc;
mbedtls_platform_set_calloc_free(calloc, free);
mbedtls_nist_kw_init(&kw);
rc = mbedtls_nist_kw_setkey(&kw, MBEDTLS_CIPHER_ID_AES, kek, key_len, 1);
if (rc) {
goto done;
}
rc = mbedtls_nist_kw_wrap(&kw, MBEDTLS_KW_MODE_KW, seckey, in_len, encbuf,
&olen, out_size);
done:
mbedtls_nist_kw_free(&kw);
return rc;
#else
(void)kek;
(void)seckey;
(void)encbuf;
return 0;
#endif
}
uint32_t flash_area_align(const struct flash_area *area)
{
return sim_flash_align(area->fa_device_id);
}
uint8_t flash_area_erased_val(const struct flash_area *area)
{
return sim_flash_erased_val(area->fa_device_id);
}
struct area {
struct flash_area whole;
struct flash_area *areas;
uint32_t num_areas;
uint8_t id;
};
struct area_desc {
struct area slots[16];
uint32_t num_slots;
};
int invoke_boot_go(struct sim_context *ctx, struct area_desc *adesc,
struct boot_rsp *rsp, int image_id)
{
int res;
struct boot_loader_state *state;
#if defined(MCUBOOT_SIGN_RSA) || \
(defined(MCUBOOT_SIGN_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ||\
(defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) ||\
(defined(MCUBOOT_ENCRYPT_X25519) && defined(MCUBOOT_USE_MBED_TLS))
mbedtls_platform_set_calloc_free(calloc, free);
#endif
state = malloc(sizeof(struct boot_loader_state));
sim_set_flash_areas(adesc);
sim_set_context(ctx);
if (setjmp(ctx->boot_jmpbuf) == 0) {
boot_state_clear(state);
#if BOOT_IMAGE_NUMBER > 1
if (image_id >= 0) {
memset(state->img_mask, 1, sizeof(state->img_mask));
state->img_mask[image_id] = 0;
}
#else
(void) image_id;
#endif /* BOOT_IMAGE_NUMBER > 1 */
res = context_boot_go(state, rsp);
sim_reset_flash_areas();
sim_reset_context();
free(state);
/* printf("boot_go off: %d (0x%08x)\n", res, rsp.br_image_off); */
return res;
} else {
sim_reset_flash_areas();
sim_reset_context();
free(state);
return -0x13579;
}
}
void *os_malloc(size_t size)
{
// printf("os_malloc 0x%x bytes\n", size);
return malloc(size);
}
int flash_area_id_from_multi_image_slot(int image_index, int slot)
{
switch (slot) {
case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index);
case 2: return FLASH_AREA_IMAGE_SCRATCH;
}
printf("Image flash area ID not found\n");
return -1; /* flash_area_open will fail on that */
}
int flash_area_open(uint8_t id, const struct flash_area **area)
{
uint32_t i;
struct area_desc *flash_areas;
flash_areas = sim_get_flash_areas();
for (i = 0; i < flash_areas->num_slots; i++) {
if (flash_areas->slots[i].id == id)
break;
}
if (i == flash_areas->num_slots) {
printf("Unsupported area\n");
abort();
}
/* Unsure if this is right, just returning the first area. */
*area = &flash_areas->slots[i].whole;
return 0;
}
void flash_area_close(const struct flash_area *area)
{
(void)area;
}
/*
* Read/write/erase. Offset is relative from beginning of flash area.
*/
int flash_area_read(const struct flash_area *area, uint32_t off, void *dst,
uint32_t len)
{
BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x",
__func__, area->fa_id, off, len);
return sim_flash_read(area->fa_device_id, area->fa_off + off, dst, len);
}
int flash_area_write(const struct flash_area *area, uint32_t off, const void *src,
uint32_t len)
{
BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__,
area->fa_id, off, len);
struct sim_context *ctx = sim_get_context();
if (--(ctx->flash_counter) == 0) {
ctx->jumped++;
longjmp(ctx->boot_jmpbuf, 1);
}
return sim_flash_write(area->fa_device_id, area->fa_off + off, src, len);
}
int flash_area_erase(const struct flash_area *area, uint32_t off, uint32_t len)
{
BOOT_LOG_SIM("%s: area=%d, off=%x, len=%x", __func__,
area->fa_id, off, len);
struct sim_context *ctx = sim_get_context();
if (--(ctx->flash_counter) == 0) {
ctx->jumped++;
longjmp(ctx->boot_jmpbuf, 1);
}
return sim_flash_erase(area->fa_device_id, area->fa_off + off, len);
}
int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret)
{
uint32_t i;
struct area *slot;
struct area_desc *flash_areas;
flash_areas = sim_get_flash_areas();
for (i = 0; i < flash_areas->num_slots; i++) {
if (flash_areas->slots[i].id == idx)
break;
}
if (i == flash_areas->num_slots) {
printf("Unsupported area\n");
abort();
}
slot = &flash_areas->slots[i];
if (slot->num_areas > (uint32_t)*cnt) {
printf("Too many areas in slot\n");
abort();
}
*cnt = slot->num_areas;
memcpy(ret, slot->areas, slot->num_areas * sizeof(struct flash_area));
return 0;
}
int flash_area_get_sectors(int fa_id, uint32_t *count,
struct flash_sector *sectors)
{
uint32_t i;
struct area *slot;
struct area_desc *flash_areas;
flash_areas = sim_get_flash_areas();
for (i = 0; i < flash_areas->num_slots; i++) {
if (flash_areas->slots[i].id == fa_id)
break;
}
if (i == flash_areas->num_slots) {
printf("Unsupported area\n");
abort();
}
slot = &flash_areas->slots[i];
if (slot->num_areas > *count) {
printf("Too many areas in slot\n");
abort();
}
for (i = 0; i < slot->num_areas; i++) {
sectors[i].fs_off = slot->areas[i].fa_off -
slot->whole.fa_off;
sectors[i].fs_size = slot->areas[i].fa_size;
}
*count = slot->num_areas;
return 0;
}
int flash_area_id_to_multi_image_slot(int image_index, int area_id)
{
if (area_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
return 0;
}
if (area_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
return 1;
}
printf("Unsupported image area ID\n");
abort();
}
int flash_area_id_from_image_slot(int slot) {
/* For single image cases, just use the first image. */
return flash_area_id_from_multi_image_slot(0, slot);
}
int flash_area_sector_from_off(uint32_t off, struct flash_sector *sector)
{
uint32_t i, sec_off, sec_size;
struct area *slot;
struct area_desc *flash_areas;
flash_areas = sim_get_flash_areas();
for (i = 0; i < flash_areas->num_slots; i++) {
if (flash_areas->slots[i].id == FLASH_AREA_ID(image_0))
break;
}
if (i == flash_areas->num_slots) {
printf("Unsupported area\n");
abort();
}
slot = &flash_areas->slots[i];
for (i = 0; i < slot->num_areas; i++) {
sec_off = slot->areas[i].fa_off - slot->whole.fa_off;
sec_size = slot->areas[i].fa_size;
if (off >= sec_off && off < (sec_off + sec_size)) {
sector->fs_off = sec_off;
sector->fs_size = sec_size;
break;
}
}
return (i < slot->num_areas) ? 0 : -1;
}
int flash_area_get_sector(const struct flash_area *fa, uint32_t off,
struct flash_sector *sector)
{
uint32_t i, sec_off, sec_size;
struct area *slot;
struct area_desc *flash_areas;
flash_areas = sim_get_flash_areas();
for (i = 0; i < flash_areas->num_slots; i++) {
if (&flash_areas->slots[i].whole == fa)
break;
}
if (i == flash_areas->num_slots) {
printf("Unsupported area\n");
abort();
}
slot = &flash_areas->slots[i];
for (i = 0; i < slot->num_areas; i++) {
sec_off = slot->areas[i].fa_off - slot->whole.fa_off;
sec_size = slot->areas[i].fa_size;
if (off >= sec_off && off < (sec_off + sec_size)) {
sector->fs_off = sec_off;
sector->fs_size = sec_size;
break;
}
}
return (i < slot->num_areas) ? 0 : -1;
}
void sim_assert(int x, const char *assertion, const char *file, unsigned int line, const char *function)
{
if (!(x)) {
struct sim_context *ctx = sim_get_context();
if (ctx->c_catch_asserts) {
ctx->c_asserts++;
} else {
BOOT_LOG_ERR("%s:%d: %s: Assertion `%s' failed.", file, line, function, assertion);
/* NOTE: if the assert below is triggered, the place where it was originally
* asserted is printed by the message above...
*/
assert(x);
}
}
}
uint32_t boot_max_align(void)
{
return BOOT_MAX_ALIGN;
}
uint32_t boot_magic_sz(void)
{
return BOOT_MAGIC_ALIGN_SIZE;
}

View File

@@ -0,0 +1,43 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arm Limited
*/
#include "bootutil/security_cnt.h"
#include "mcuboot_config/mcuboot_logging.h"
#include "bootutil/fault_injection_hardening.h"
/*
* Since the simulator is executing unit tests in parallel,
* the storage area where the security counter values reside
* has to be managed per thread from Rust's side.
*/
#ifdef MCUBOOT_HW_ROLLBACK_PROT
int sim_set_nv_counter_for_image(uint32_t image_index, uint32_t security_counter_value);
int sim_get_nv_counter_for_image(uint32_t image_index, uint32_t* data);
fih_ret boot_nv_security_counter_init(void) {
return FIH_SUCCESS;
}
fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt) {
uint32_t counter = 0;
FIH_DECLARE(fih_rc, FIH_FAILURE);
fih_rc = fih_ret_encode_zero_equality(sim_get_nv_counter_for_image(image_id, &counter));
MCUBOOT_LOG_INF("Read security counter value (%d) for image: %d\n", counter, image_id);
*security_cnt = fih_int_encode(counter);
FIH_RET(fih_rc);
}
int32_t boot_nv_security_counter_update(uint32_t image_id, uint32_t img_security_cnt) {
MCUBOOT_LOG_INF("Writing security counter value (%d) for image: %d\n", img_security_cnt, image_id);
return sim_set_nv_counter_for_image(image_id, img_security_cnt);
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */

View File

@@ -0,0 +1,171 @@
/*
* 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.
*/
#ifndef H_UTIL_FLASH_MAP_
#define H_UTIL_FLASH_MAP_
#ifdef __cplusplus
extern "C" {
#endif
/**
*
* Provides abstraction of flash regions for type of use.
* I.e. dude where's my image?
*
* System will contain a map which contains flash areas. Every
* region will contain flash identifier, offset within flash and length.
*
* 1. This system map could be in a file within filesystem (Initializer
* must know/figure out where the filesystem is at).
* 2. Map could be at fixed location for project (compiled to code)
* 3. Map could be at specific place in flash (put in place at mfg time).
*
* Note that the map you use must be valid for BSP it's for,
* match the linker scripts when platform executes from flash,
* and match the target offset specified in download script.
*/
#include <inttypes.h>
/**
* @brief Structure describing an area on a flash device.
*
* Multiple flash devices may be available in the system, each of
* which may have its own areas. For this reason, flash areas track
* which flash device they are part of.
*/
struct flash_area {
/**
* This flash area's ID; unique in the system.
*/
uint8_t fa_id;
/**
* ID of the flash device this area is a part of.
*/
uint8_t fa_device_id;
uint16_t pad16;
/**
* This area's offset, relative to the beginning of its flash
* device's storage.
*/
uint32_t fa_off;
/**
* This area's size, in bytes.
*/
uint32_t fa_size;
};
/**
* @brief Structure describing a sector within a flash area.
*
* Each sector has an offset relative to the start of its flash area
* (NOT relative to the start of its flash device), and a size. A
* flash area may contain sectors with different sizes.
*/
struct flash_sector {
/**
* Offset of this sector, from the start of its flash area (not device).
*/
uint32_t fs_off;
/**
* Size of this sector, in bytes.
*/
uint32_t fs_size;
};
/*
* Retrieve a memory-mapped flash device's base address.
*
* On success, the address will be stored in the value pointed to by
* ret.
*
* Returns 0 on success, or an error code on failure.
*/
int flash_device_base(uint8_t fd_id, uintptr_t *ret);
/*
* Start using flash area.
*/
int flash_area_open(uint8_t id, const struct flash_area **);
void flash_area_close(const struct flash_area *);
/*
* Read/write/erase. Offset is relative from beginning of flash area.
*/
int flash_area_read(const struct flash_area *, uint32_t off, void *dst,
uint32_t len);
int flash_area_write(const struct flash_area *, uint32_t off, const void *src,
uint32_t len);
int flash_area_erase(const struct flash_area *, uint32_t off, uint32_t len);
/*
* Alignment restriction for flash writes.
*/
uint32_t flash_area_align(const struct flash_area *);
/*
* What is value is read from erased flash bytes.
*/
uint8_t flash_area_erased_val(const struct flash_area *);
/*
* Given flash area ID, return info about sectors within the area.
*/
int flash_area_get_sectors(int fa_id, uint32_t *count,
struct flash_sector *sectors);
/* Retrieve the flash sector a given offset belongs to.
*
* Returns 0 on success, or an error code on failure.
*/
int flash_area_sector_from_off(uint32_t off, struct flash_sector *sector);
/* Retrieve the flash sector a given offset, within flash area.
*
* @param fa flash area.
* @param off offset of sector.
* @param sector pointer to structure for obtained information.
* Returns 0 on success, or an error code on failure.
*/
int flash_area_get_sector(const struct flash_area *fa, uint32_t off,
struct flash_sector *sector);
/*
* Similar to flash_area_get_sectors(), but return the values in an
* array of struct flash_area instead.
*/
__attribute__((deprecated))
int flash_area_to_sectors(int idx, int *cnt, struct flash_area *ret);
int flash_area_id_from_image_slot(int slot);
int flash_area_id_from_multi_image_slot(int image_index, int slot);
int flash_area_id_to_multi_image_slot(int image_index, int area_id);
#ifdef __cplusplus
}
#endif
#endif /* H_UTIL_FLASH_MAP_ */

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SYSFLASH_H__
#define __SYSFLASH_H__
#include <devicetree.h>
#include <mcuboot_config/mcuboot_config.h>
#if (MCUBOOT_IMAGE_NUMBER == 1)
/*
* NOTE: the definition below returns the same values for true/false on
* purpose, to avoid having to mark x as non-used by all callers when
* running in single image mode.
*/
#define FLASH_AREA_IMAGE_PRIMARY(x) (((x) == 0) ? \
FLASH_AREA_ID(image_0) : \
FLASH_AREA_ID(image_0))
#define FLASH_AREA_IMAGE_SECONDARY(x) (((x) == 0) ? \
FLASH_AREA_ID(image_1) : \
FLASH_AREA_ID(image_1))
#elif (MCUBOOT_IMAGE_NUMBER == 2)
/* MCUBoot currently supports only up to 2 updateable firmware images.
* If the number of the current image is greater than MCUBOOT_IMAGE_NUMBER - 1
* then a dummy value will be assigned to the flash area macros.
*/
#define FLASH_AREA_IMAGE_PRIMARY(x) (((x) == 0) ? \
FLASH_AREA_ID(image_0) : \
((x) == 1) ? \
FLASH_AREA_ID(image_2) : \
255)
#define FLASH_AREA_IMAGE_SECONDARY(x) (((x) == 0) ? \
FLASH_AREA_ID(image_1) : \
((x) == 1) ? \
FLASH_AREA_ID(image_3) : \
255)
#else
#error "Image slot and flash area mapping is not defined"
#endif
#define FLASH_AREA_IMAGE_SCRATCH FLASH_AREA_ID(image_scratch)
#endif /* __SYSFLASH_H__ */

View File

@@ -0,0 +1,390 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2018-2019 JUUL Labs
// Copyright (c) 2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
//! HAL api for MyNewt applications
use crate::area::CAreaDesc;
use log::{Level, log_enabled, warn};
use simflash::{Result, Flash, FlashPtr};
use std::{
cell::RefCell,
collections::HashMap,
mem,
ptr,
slice,
};
/// A FlashMap maintain a table of [device_id -> Flash trait]
pub type FlashMap = HashMap<u8, FlashPtr>;
pub struct FlashParamsStruct {
align: u32,
erased_val: u8,
}
pub type FlashParams = HashMap<u8, FlashParamsStruct>;
/// The `boot_rsp` structure used by boot_go.
#[repr(C)]
#[derive(Debug)]
pub struct BootRsp {
pub br_hdr: *const ImageHeader,
pub flash_dev_id: u8,
pub image_off: u32,
}
// TODO: Don't duplicate this image header declaration.
#[repr(C)]
#[derive(Debug)]
pub struct ImageHeader {
magic: u32,
load_addr: u32,
hdr_size: u16,
protect_tlv_size: u16,
img_size: u32,
flags: u32,
ver: ImageVersion,
_pad2: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct ImageVersion {
pub major: u8,
pub minor: u8,
pub revision: u16,
pub build_num: u32,
}
pub struct CAreaDescPtr {
pub ptr: *const CAreaDesc,
}
pub struct FlashContext {
flash_map: FlashMap,
flash_params: FlashParams,
flash_areas: CAreaDescPtr,
}
impl FlashContext {
pub fn new() -> FlashContext {
FlashContext {
flash_map: HashMap::new(),
flash_params: HashMap::new(),
flash_areas: CAreaDescPtr{ptr: ptr::null()},
}
}
}
impl Default for FlashContext {
fn default() -> FlashContext {
FlashContext {
flash_map: HashMap::new(),
flash_params: HashMap::new(),
flash_areas: CAreaDescPtr{ptr: ptr::null()},
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct CSimContext {
pub flash_counter: libc::c_int,
pub jumped: libc::c_int,
pub c_asserts: u8,
pub c_catch_asserts: u8,
// NOTE: Always leave boot_jmpbuf declaration at the end; this should
// store a "jmp_buf" which is arch specific and not defined by libc crate.
// The size below is enough to store data on a x86_64 machine.
pub boot_jmpbuf: [u64; 48],
}
impl Default for CSimContext {
fn default() -> Self {
CSimContext {
flash_counter: 0,
jumped: 0,
c_asserts: 0,
c_catch_asserts: 0,
boot_jmpbuf: [0; 48],
}
}
}
pub struct CSimContextPtr {
pub ptr: *const CSimContext,
}
impl CSimContextPtr {
pub fn new() -> CSimContextPtr {
CSimContextPtr {
ptr: ptr::null(),
}
}
}
impl Default for CSimContextPtr {
fn default() -> CSimContextPtr {
CSimContextPtr {
ptr: ptr::null(),
}
}
}
/// This struct describes the RAM layout of the current device. It will be stashed, per test
/// thread, and queried by the C code.
#[repr(C)]
#[derive(Debug, Default)]
pub struct BootsimRamInfo {
pub start: u32,
pub size: u32,
pub base: usize,
}
/// This struct stores the non-volatile security counter per image. It will be stored per test thread,
/// and the C code will set / get the values here.
#[repr(C)]
#[derive(Debug, Default)]
pub struct NvCounterStorage {
pub storage: Vec<u32>,
}
impl NvCounterStorage {
pub fn new() -> Self {
let count = if cfg!(feature = "multiimage") {
2
} else {
1
};
Self {
storage: vec![0; count]
}
}
}
thread_local! {
pub static THREAD_CTX: RefCell<FlashContext> = RefCell::new(FlashContext::new());
pub static SIM_CTX: RefCell<CSimContextPtr> = RefCell::new(CSimContextPtr::new());
pub static RAM_CTX: RefCell<BootsimRamInfo> = RefCell::new(BootsimRamInfo::default());
pub static NV_COUNTER_CTX: RefCell<NvCounterStorage> = RefCell::new(NvCounterStorage::new());
}
/// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
///
/// # Safety
///
/// This uses mem::transmute to stash a Rust pointer into a C value to
/// retrieve later. It should be safe to use this.
pub fn set_flash(dev_id: u8, dev: &mut dyn Flash) {
THREAD_CTX.with(|ctx| {
ctx.borrow_mut().flash_params.insert(dev_id, FlashParamsStruct {
align: dev.align() as u32,
erased_val: dev.erased_val(),
});
unsafe {
let dev: &'static mut dyn Flash = mem::transmute(dev);
ctx.borrow_mut().flash_map.insert(
dev_id, FlashPtr{ptr: dev as *mut dyn Flash});
}
});
}
pub fn clear_flash(dev_id: u8) {
THREAD_CTX.with(|ctx| {
ctx.borrow_mut().flash_map.remove(&dev_id);
});
}
// This isn't meant to call directly, but by a wrapper.
#[no_mangle]
pub extern "C" fn sim_get_flash_areas() -> *const CAreaDesc {
THREAD_CTX.with(|ctx| {
ctx.borrow().flash_areas.ptr
})
}
#[no_mangle]
pub extern "C" fn sim_set_flash_areas(areas: *const CAreaDesc) {
THREAD_CTX.with(|ctx| {
ctx.borrow_mut().flash_areas.ptr = areas;
});
}
#[no_mangle]
pub extern "C" fn sim_reset_flash_areas() {
THREAD_CTX.with(|ctx| {
ctx.borrow_mut().flash_areas.ptr = ptr::null();
});
}
#[no_mangle]
pub extern "C" fn sim_get_context() -> *const CSimContext {
SIM_CTX.with(|ctx| {
ctx.borrow().ptr
})
}
#[no_mangle]
pub extern "C" fn sim_set_context(ptr: *const CSimContext) {
SIM_CTX.with(|ctx| {
ctx.borrow_mut().ptr = ptr;
});
}
#[no_mangle]
pub extern "C" fn sim_reset_context() {
SIM_CTX.with(|ctx| {
ctx.borrow_mut().ptr = ptr::null();
});
}
#[no_mangle]
pub extern "C" fn bootsim_get_ram_info() -> *const BootsimRamInfo {
RAM_CTX.with(|ctx| {
if ctx.borrow().base == 0 {
// Option is messier to get a pointer out of, so just check if the base has been set to
// anything.
panic!("ram info not set, but being used");
}
ctx.as_ptr()
})
}
/// Store a copy of this RAM info.
pub fn set_ram_info(info: BootsimRamInfo) {
RAM_CTX.with(|ctx| {
ctx.replace(info);
});
}
/// Clear out the ram info.
pub fn clear_ram_info() {
RAM_CTX.with(|ctx| {
ctx.borrow_mut().base = 0;
});
}
#[no_mangle]
pub extern "C" fn sim_flash_erase(dev_id: u8, offset: u32, size: u32) -> libc::c_int {
let mut rc: libc::c_int = -19;
THREAD_CTX.with(|ctx| {
if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
let dev = unsafe { &mut *(flash.ptr) };
rc = map_err(dev.erase(offset as usize, size as usize));
}
});
rc
}
#[no_mangle]
pub extern "C" fn sim_flash_read(dev_id: u8, offset: u32, dest: *mut u8, size: u32) -> libc::c_int {
let mut rc: libc::c_int = -19;
THREAD_CTX.with(|ctx| {
if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
let mut buf: &mut[u8] = unsafe { slice::from_raw_parts_mut(dest, size as usize) };
let dev = unsafe { &mut *(flash.ptr) };
rc = map_err(dev.read(offset as usize, &mut buf));
}
});
rc
}
#[no_mangle]
pub extern "C" fn sim_flash_write(dev_id: u8, offset: u32, src: *const u8, size: u32) -> libc::c_int {
let mut rc: libc::c_int = -19;
THREAD_CTX.with(|ctx| {
if let Some(flash) = ctx.borrow().flash_map.get(&dev_id) {
let buf: &[u8] = unsafe { slice::from_raw_parts(src, size as usize) };
let dev = unsafe { &mut *(flash.ptr) };
rc = map_err(dev.write(offset as usize, &buf));
}
});
rc
}
#[no_mangle]
pub extern "C" fn sim_flash_align(id: u8) -> u32 {
THREAD_CTX.with(|ctx| {
ctx.borrow().flash_params.get(&id).unwrap().align
})
}
#[no_mangle]
pub extern "C" fn sim_flash_erased_val(id: u8) -> u8 {
THREAD_CTX.with(|ctx| {
ctx.borrow().flash_params.get(&id).unwrap().erased_val
})
}
fn map_err(err: Result<()>) -> libc::c_int {
match err {
Ok(()) => 0,
Err(e) => {
warn!("{}", e);
-1
},
}
}
/// Called by C code to determine if we should log at this level. Levels are defined in
/// bootutil/bootutil_log.h. This makes the logging from the C code controlled by bootsim::api, so
/// for example, it can be enabled with something like:
/// RUST_LOG=bootsim::api=info cargo run --release runall
/// or
/// RUST_LOG=bootsim=info cargo run --release runall
#[no_mangle]
pub extern "C" fn sim_log_enabled(level: libc::c_int) -> libc::c_int {
let res = match level {
1 => log_enabled!(Level::Error),
2 => log_enabled!(Level::Warn),
3 => log_enabled!(Level::Info),
4 => log_enabled!(Level::Debug),
5 => log_enabled!(Level::Trace), // log level == SIM
_ => false,
};
if res {
1
} else {
0
}
}
#[no_mangle]
pub extern "C" fn sim_set_nv_counter_for_image(image_index: u32, security_counter_value: u32) -> libc::c_int {
let mut rc = 0;
NV_COUNTER_CTX.with(|ctx| {
let mut counter_storage = ctx.borrow_mut();
if image_index as usize >= counter_storage.storage.len() {
rc = -1;
return;
}
if counter_storage.storage[image_index as usize] > security_counter_value {
rc = -2;
warn!("Failed to set security counter value ({}) for image index {}", security_counter_value, image_index);
return;
}
counter_storage.storage[image_index as usize] = security_counter_value;
});
return rc;
}
#[no_mangle]
pub extern "C" fn sim_get_nv_counter_for_image(image_index: u32, security_counter_value: *mut u32) -> libc::c_int {
let mut rc = 0;
NV_COUNTER_CTX.with(|ctx| {
let counter_storage = ctx.borrow();
if image_index as usize >= counter_storage.storage.len() {
rc = -1;
return;
}
unsafe { *security_counter_value = counter_storage.storage[image_index as usize] };
});
return rc;
}

View File

@@ -0,0 +1,210 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2018-2019 JUUL Labs
// Copyright (c) 2019 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
//! Describe flash areas.
use simflash::{Flash, SimFlash, Sector};
use std::ptr;
use std::collections::HashMap;
use std::borrow::BorrowMut;
/// Structure to build up the boot area table.
#[derive(Debug, Default, Clone)]
pub struct AreaDesc {
areas: Vec<Vec<FlashArea>>,
whole: Vec<FlashArea>,
sectors: HashMap<u8, Vec<Sector>>,
}
impl AreaDesc {
pub fn new() -> AreaDesc {
AreaDesc {
areas: vec![],
whole: vec![],
sectors: HashMap::new(),
}
}
pub fn add_flash_sectors(&mut self, id: u8, flash: &SimFlash) {
self.sectors.insert(id, flash.sector_iter().collect());
}
/// Add a slot to the image. The slot must align with erasable units in the flash device.
/// Panics if the description is not valid. There are also bootloader assumptions that the
/// slots are PRIMARY_SLOT, SECONDARY_SLOT, and SCRATCH in that order.
pub fn add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
let nid = id as usize;
let orig_base = base;
let orig_len = len;
let mut base = base;
let mut len = len;
while nid > self.areas.len() {
self.areas.push(vec![]);
self.whole.push(Default::default());
}
if nid != self.areas.len() {
panic!("Flash areas not added in order");
}
let mut area = vec![];
for sector in &self.sectors[&dev_id] {
if len == 0 {
break;
};
if base > sector.base + sector.size - 1 {
continue;
}
if sector.base != base {
panic!("Image does not start on a sector boundary");
}
area.push(FlashArea {
flash_id: id,
device_id: dev_id,
pad16: 0,
off: sector.base as u32,
size: sector.size as u32,
});
base += sector.size;
len -= sector.size;
}
if len != 0 {
panic!("Image goes past end of device");
}
self.areas.push(area);
self.whole.push(FlashArea {
flash_id: id,
device_id: dev_id,
pad16: 0,
off: orig_base as u32,
size: orig_len as u32,
});
}
// Add a simple slot to the image. This ignores the device layout, and just adds the area as a
// single unit. It assumes that the image lines up with image boundaries. This tests
// configurations where the partition table uses larger sectors than the underlying flash
// device.
pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
let area = vec![FlashArea {
flash_id: id,
device_id: dev_id,
pad16: 0,
off: base as u32,
size: len as u32,
}];
self.areas.push(area);
self.whole.push(FlashArea {
flash_id: id,
device_id: dev_id,
pad16: 0,
off: base as u32,
size: len as u32,
});
}
// Look for the image with the given ID, and return its offset, size and
// device id. Returns None if the area is not present.
pub fn find(&self, id: FlashId) -> Option<(usize, usize, u8)> {
for area in &self.whole {
// FIXME: should we ensure id is not duplicated over multiple devices?
if area.flash_id == id {
return Some((area.off as usize, area.size as usize, area.device_id));
}
}
None
}
pub fn get_c(&self) -> Box<CAreaDesc> {
let mut areas_box: Box<CAreaDesc> = Box::new(Default::default());
let areas: &mut CAreaDesc = areas_box.borrow_mut();
assert_eq!(self.areas.len(), self.whole.len());
for (i, area) in self.areas.iter().enumerate() {
if !area.is_empty() {
areas.slots[i].areas = &area[0];
areas.slots[i].whole = self.whole[i].clone();
areas.slots[i].num_areas = area.len() as u32;
areas.slots[i].id = area[0].flash_id;
}
}
areas.num_slots = self.areas.len() as u32;
areas_box
}
/// Return an iterator over all `FlashArea`s present.
pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
self.whole.iter()
}
}
/// The area descriptor, C format.
#[repr(C)]
#[derive(Debug, Default)]
pub struct CAreaDesc {
slots: [CArea; 16],
num_slots: u32,
}
#[repr(C)]
#[derive(Debug)]
pub struct CArea {
whole: FlashArea,
areas: *const FlashArea,
num_areas: u32,
// FIXME: is this not already available on whole/areas?
id: FlashId,
}
impl Default for CArea {
fn default() -> CArea {
CArea {
areas: ptr::null(),
whole: Default::default(),
id: FlashId::BootLoader,
num_areas: 0,
}
}
}
/// Flash area map.
#[repr(u8)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(dead_code)]
pub enum FlashId {
BootLoader = 0,
Image0 = 1,
Image1 = 2,
ImageScratch = 3,
Image2 = 4,
Image3 = 5,
}
impl Default for FlashId {
fn default() -> FlashId {
FlashId::BootLoader
}
}
#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct FlashArea {
pub flash_id: FlashId,
pub device_id: u8,
pad16: u16,
pub off: u32,
pub size: u32,
}

View File

@@ -0,0 +1,226 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
// Copyright (c) 2019-2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
//! Interface wrappers to C API entering to the bootloader
use crate::area::AreaDesc;
use simflash::SimMultiFlash;
use crate::api;
#[allow(unused)]
use std::sync::Once;
use std::borrow::Borrow;
/// The result of an invocation of `boot_go`. This is intentionally opaque so that we can provide
/// accessors for everything we need from this.
#[derive(Debug)]
pub enum BootGoResult {
/// This run was stopped by the flash simulation mechanism.
Stopped,
/// The bootloader ran to completion with the following data.
Normal {
result: i32,
asserts: u8,
resp: api::BootRsp,
},
}
impl BootGoResult {
/// Was this run interrupted.
pub fn interrupted(&self) -> bool {
matches!(self, BootGoResult::Stopped)
}
/// Was this boot run successful (returned 0)
pub fn success(&self) -> bool {
matches!(self, BootGoResult::Normal { result: 0, .. })
}
/// Success, but also no asserts.
pub fn success_no_asserts(&self) -> bool {
matches!(self, BootGoResult::Normal {
result: 0,
asserts: 0,
..
})
}
/// Get the asserts count. An interrupted run will be considered to have no asserts.
pub fn asserts(&self) -> u8 {
match self {
BootGoResult::Normal { asserts, .. } => *asserts,
_ => 0,
}
}
/// Retrieve the 'resp' field that is filled in.
pub fn resp(&self) -> Option<&api::BootRsp> {
match self {
BootGoResult::Normal { resp, .. } => Some(resp),
_ => None,
}
}
}
/// Invoke the bootloader on this flash device.
pub fn boot_go(multiflash: &mut SimMultiFlash, areadesc: &AreaDesc,
counter: Option<&mut i32>, image_index: Option<i32>,
catch_asserts: bool) -> BootGoResult {
init_crypto();
for (&dev_id, flash) in multiflash.iter_mut() {
api::set_flash(dev_id, flash);
}
let mut sim_ctx = api::CSimContext {
flash_counter: match counter {
None => 0,
Some(ref c) => **c as libc::c_int
},
c_catch_asserts: if catch_asserts { 1 } else { 0 },
.. Default::default()
};
let mut rsp = api::BootRsp {
br_hdr: std::ptr::null(),
flash_dev_id: 0,
image_off: 0,
};
let result: i32 = unsafe {
let adesc = areadesc.get_c();
match image_index {
None => raw::invoke_boot_go(&mut sim_ctx as *mut _,
adesc.borrow() as *const _,
&mut rsp as *mut _, -1) as i32,
Some(i) => raw::invoke_boot_go(&mut sim_ctx as *mut _,
adesc.borrow() as *const _,
&mut rsp as *mut _,
i as i32) as i32
}
};
let asserts = sim_ctx.c_asserts;
if let Some(c) = counter {
*c = sim_ctx.flash_counter;
}
for &dev_id in multiflash.keys() {
api::clear_flash(dev_id);
}
if result == -0x13579 {
BootGoResult::Stopped
} else {
BootGoResult::Normal { result, asserts, resp: rsp }
}
}
pub fn boot_trailer_sz(align: u32) -> u32 {
unsafe { raw::boot_trailer_sz(align) }
}
pub fn boot_status_sz(align: u32) -> u32 {
unsafe { raw::boot_status_sz(align) }
}
pub fn boot_magic_sz() -> usize {
unsafe { raw::boot_magic_sz() as usize }
}
pub fn boot_max_align() -> usize {
unsafe { raw::boot_max_align() as usize }
}
pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
unsafe {
let mut encbuf: [u8; 256] = [0; 256];
if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
seckey.as_ptr(), seckey.len() as u32,
encbuf.as_mut_ptr()) == 0 {
return Ok(encbuf);
}
Err("Failed to encrypt buffer")
}
}
pub fn kw_encrypt(kek: &[u8], seckey: &[u8], keylen: u32) -> Result<Vec<u8>, &'static str> {
unsafe {
let mut encbuf = vec![0u8; 24];
if keylen == 32 {
encbuf = vec![0u8; 40];
}
if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
return Ok(encbuf);
}
Err("Failed to encrypt buffer")
}
}
pub fn set_security_counter(image_index: u32, security_counter_value: u32) {
api::sim_set_nv_counter_for_image(image_index, security_counter_value);
}
pub fn get_security_counter(image_index: u32) -> u32 {
let mut counter_val: u32 = 0;
api::sim_get_nv_counter_for_image(image_index, &mut counter_val as *mut u32);
return counter_val;
}
mod raw {
use crate::area::CAreaDesc;
use crate::api::{BootRsp, CSimContext};
extern "C" {
// This generates a warning about `CAreaDesc` not being foreign safe. There doesn't appear to
// be any way to get rid of this warning. See https://github.com/rust-lang/rust/issues/34798
// for information and tracking.
pub fn invoke_boot_go(sim_ctx: *mut CSimContext, areadesc: *const CAreaDesc,
rsp: *mut BootRsp, image_index: libc::c_int) -> libc::c_int;
pub fn boot_trailer_sz(min_write_sz: u32) -> u32;
pub fn boot_status_sz(min_write_sz: u32) -> u32;
pub fn boot_magic_sz() -> u32;
pub fn boot_max_align() -> u32;
pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
seckey: *const u8, seckey_len: libc::c_uint,
encbuf: *mut u8) -> libc::c_int;
pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
encbuf: *mut u8) -> libc::c_int;
#[allow(unused)]
pub fn psa_crypto_init() -> u32;
#[allow(unused)]
pub fn mbedtls_test_enable_insecure_external_rng();
}
}
#[allow(unused)]
static PSA_INIT_SYNC: Once = Once::new();
#[allow(unused)]
static MBEDTLS_EXTERNAL_RNG_ENABLE_SYNC: Once = Once::new();
#[cfg(feature = "psa-crypto-api")]
fn init_crypto() {
PSA_INIT_SYNC.call_once(|| {
assert_eq!(unsafe { raw::psa_crypto_init() }, 0);
});
/* The PSA APIs require properly initialisation of the entropy subsystem
* The configuration adds the option MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG when the
* psa-crypto-api feature is enabled. As a result the tests use the implementation
* of the test external rng that needs to be initialised before being able to use it
*/
MBEDTLS_EXTERNAL_RNG_ENABLE_SYNC.call_once(|| {
unsafe { raw::mbedtls_test_enable_insecure_external_rng() }
});
}
#[cfg(not(feature = "psa-crypto-api"))]
fn init_crypto() {
// When the feature is not enabled, the init is just empty
}

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2017-2019 Linaro LTD
//
// SPDX-License-Identifier: Apache-2.0
mod area;
pub mod c;
// The API needs to be public, even though it isn't intended to be called by Rust code, but the
// functions are exported to C code.
pub mod api;
pub use crate::area::{AreaDesc, FlashId};
/// For testing the ram load feature, we need to emulate a block of RAM and be able to pass that
/// down to the C code. The call down to boot_go should go through this object so that the buffer
/// itself is managed properly.
pub struct RamBlock {
ram: Vec<u8>,
offset: u32, // 32-bit offset.
}
impl RamBlock {
pub fn new(size: u32, offset: u32) -> RamBlock {
RamBlock {
ram: vec![0; size as usize],
offset: offset,
}
}
/// Borrow the RAM buffer, with 'offset' being the beginning of the buffer.
pub fn borrow(&self) -> &[u8] {
&self.ram
}
/// Borrow a piece of the ram, with 'offset' being the beginning of the buffer.
pub fn borrow_part(&self, base: usize, size: usize) -> &[u8] {
&self.ram[base..base+size]
}
pub fn invoke<F, R>(&self, act: F) -> R
where F: FnOnce() -> R
{
api::set_ram_info(api::BootsimRamInfo {
start: self.offset,
size: self.ram.len() as u32,
base: &self.ram[0] as *const u8 as usize - self.offset as usize,
});
let result = act();
api::clear_ram_info();
result
}
}

View File

@@ -0,0 +1 @@
Cargo.lock

View File

@@ -0,0 +1,10 @@
[package]
name = "simflash"
version = "0.1.0"
authors = ["David Brown <david.brown@linaro.org>"]
edition = "2021"
[dependencies]
rand = "0.8"
log = "0.4"
thiserror = "1.0"

View File

@@ -0,0 +1,377 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2017-2018 JUUL Labs
//
// SPDX-License-Identifier: Apache-2.0
//! A flash simulator
//!
//! This module is capable of simulating the type of NOR flash commonly used in microcontrollers.
//! These generally can be written as individual bytes, but must be erased in larger units.
mod pdump;
use crate::pdump::HexDump;
use log::info;
use rand::{
self,
distributions::Standard,
Rng,
};
use std::{
collections::HashMap,
fs::File,
io::{self, Write},
iter::Enumerate,
path::Path,
slice,
};
use thiserror::Error;
pub type Result<T> = std::result::Result<T, FlashError>;
#[derive(Error, Debug)]
pub enum FlashError {
#[error("Offset out of bounds: {0}")]
OutOfBounds(String),
#[error("Invalid write: {0}")]
Write(String),
#[error("Write failed by chance: {0}")]
SimulatedFail(String),
#[error("{0}")]
Io(#[from] io::Error),
}
// Transition from error-chain.
macro_rules! bail {
($item:expr) => (return Err($item.into());)
}
pub struct FlashPtr {
pub ptr: *mut dyn Flash,
}
unsafe impl Send for FlashPtr {}
pub trait Flash {
fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
fn reset_bad_regions(&mut self);
fn set_verify_writes(&mut self, enable: bool);
fn sector_iter(&self) -> SectorIter<'_>;
fn device_size(&self) -> usize;
fn align(&self) -> usize;
fn erased_val(&self) -> u8;
}
fn ebounds<T: AsRef<str>>(message: T) -> FlashError {
FlashError::OutOfBounds(message.as_ref().to_owned())
}
#[allow(dead_code)]
fn ewrite<T: AsRef<str>>(message: T) -> FlashError {
FlashError::Write(message.as_ref().to_owned())
}
#[allow(dead_code)]
fn esimulatedwrite<T: AsRef<str>>(message: T) -> FlashError {
FlashError::SimulatedFail(message.as_ref().to_owned())
}
/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
/// mappings.
#[derive(Clone)]
pub struct SimFlash {
data: Vec<u8>,
write_safe: Vec<bool>,
sectors: Vec<usize>,
bad_region: Vec<(usize, usize, f32)>,
// Alignment required for writes.
align: usize,
verify_writes: bool,
erased_val: u8,
}
impl SimFlash {
/// Given a sector size map, construct a flash device for that.
pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
// Verify that the alignment is a positive power of two.
assert!(align > 0);
assert!(align & (align - 1) == 0);
let total = sectors.iter().sum();
SimFlash {
data: vec![erased_val; total],
write_safe: vec![true; total],
sectors,
bad_region: Vec::new(),
align,
verify_writes: true,
erased_val,
}
}
#[allow(dead_code)]
pub fn dump(&self) {
self.data.dump();
}
/// Dump this image to the given file.
#[allow(dead_code)]
pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let mut fd = File::create(path)?;
fd.write_all(&self.data)?;
Ok(())
}
// Scan the sector map, and return the base and offset within a sector for this given byte.
// Returns None if the value is outside of the device.
fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
let mut offset = offset;
for (sector, &size) in self.sectors.iter().enumerate() {
if offset < size {
return Some((sector, offset));
}
offset -= size;
}
None
}
}
pub type SimMultiFlash = HashMap<u8, SimFlash>;
impl Flash for SimFlash {
/// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
/// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
/// return an error.
fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
if slen != 0 {
bail!(ebounds("offset not at start of sector"));
}
if elen != self.sectors[end] - 1 {
bail!(ebounds("end not at start of sector"));
}
for x in &mut self.data[offset .. offset + len] {
*x = self.erased_val;
}
for x in &mut self.write_safe[offset .. offset + len] {
*x = true;
}
Ok(())
}
/// We restrict to only allowing writes of values that are:
///
/// 1. being written to for the first time
/// 2. being written to after being erased
///
/// This emulates a flash device which starts out erased, with the
/// added restriction that repeated writes to the same location
/// are disallowed, even if they would be safe to do.
fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
for &(off, len, rate) in &self.bad_region {
if offset >= off && (offset + payload.len()) <= (off + len) {
let mut rng = rand::thread_rng();
let samp: f32 = rng.sample(Standard);
if samp < rate {
bail!(esimulatedwrite(
format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
}
}
}
if offset + payload.len() > self.data.len() {
panic!("Write outside of device");
}
// Verify the alignment (which must be a power of two).
if offset & (self.align - 1) != 0 {
panic!("Misaligned write address");
}
if payload.len() & (self.align - 1) != 0 {
panic!("Write length not multiple of alignment");
}
for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
if self.verify_writes && !(*x) {
panic!("Write to unerased location at 0x{:x}", offset + i);
}
*x = false;
}
let sub = &mut self.data[offset .. offset + payload.len()];
sub.copy_from_slice(payload);
Ok(())
}
/// Read is simple.
fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
if offset + data.len() > self.data.len() {
bail!(ebounds("Read outside of device"));
}
let sub = &self.data[offset .. offset + data.len()];
data.copy_from_slice(sub);
Ok(())
}
/// Adds a new flash bad region. Writes to this area fail with a chance
/// given by `rate`.
fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
if !(0.0..=1.0).contains(&rate) {
bail!(ebounds("Invalid rate"));
}
info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
self.bad_region.push((offset, len, rate));
Ok(())
}
fn reset_bad_regions(&mut self) {
self.bad_region.clear();
}
fn set_verify_writes(&mut self, enable: bool) {
self.verify_writes = enable;
}
/// An iterator over each sector in the device.
fn sector_iter(&self) -> SectorIter<'_> {
SectorIter {
iter: self.sectors.iter().enumerate(),
base: 0,
}
}
fn device_size(&self) -> usize {
self.data.len()
}
fn align(&self) -> usize {
self.align
}
fn erased_val(&self) -> u8 {
self.erased_val
}
}
/// It is possible to iterate over the sectors in the device, each element returning this.
#[derive(Debug, Clone)]
pub struct Sector {
/// Which sector is this, starting from 0.
pub num: usize,
/// The offset, in bytes, of the start of this sector.
pub base: usize,
/// The length, in bytes, of this sector.
pub size: usize,
}
pub struct SectorIter<'a> {
iter: Enumerate<slice::Iter<'a, usize>>,
base: usize,
}
impl<'a> Iterator for SectorIter<'a> {
type Item = Sector;
fn next(&mut self) -> Option<Sector> {
match self.iter.next() {
None => None,
Some((num, &size)) => {
let base = self.base;
self.base += size;
Some(Sector {
num,
base,
size,
})
}
}
}
}
#[cfg(test)]
mod test {
use super::{Flash, FlashError, SimFlash, Result, Sector};
#[test]
fn test_flash() {
for &erased_val in &[0, 0xff] {
// NXP-style, uniform sectors.
let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
test_device(&mut f1, erased_val);
// STM style, non-uniform sectors.
let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
test_device(&mut f2, erased_val);
}
}
fn test_device(flash: &mut dyn Flash, erased_val: u8) {
let sectors: Vec<Sector> = flash.sector_iter().collect();
flash.erase(0, sectors[0].size).unwrap();
let flash_size = flash.device_size();
flash.erase(0, flash_size).unwrap();
assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
// Verify that write and erase do something.
flash.write(0, &[0x55]).unwrap();
let mut buf = [0xAA; 4];
flash.read(0, &mut buf).unwrap();
assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
flash.erase(0, sectors[0].size).unwrap();
flash.read(0, &mut buf).unwrap();
assert_eq!(buf, [erased_val; 4]);
// Program the first and last byte of each sector, verify that has been done, and then
// erase to verify the erase boundaries.
for sector in &sectors {
let byte = [(sector.num & 127) as u8];
flash.write(sector.base, &byte).unwrap();
flash.write(sector.base + sector.size - 1, &byte).unwrap();
}
// Verify the above
let mut buf = Vec::new();
for sector in &sectors {
let byte = (sector.num & 127) as u8;
buf.resize(sector.size, 0);
flash.read(sector.base, &mut buf).unwrap();
assert_eq!(buf.first(), Some(&byte));
assert_eq!(buf.last(), Some(&byte));
assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
}
}
// Helper checks for the result type.
trait EChecker {
fn is_bounds(&self) -> bool;
}
impl<T> EChecker for Result<T> {
fn is_bounds(&self) -> bool {
match *self {
Err(FlashError::OutOfBounds(_)) => true,
_ => false,
}
}
}
}

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2017,2021 Linaro LTD
//
// SPDX-License-Identifier: Apache-2.0
// Printable hexdump.
pub trait HexDump {
// Output the data value in hex.
fn dump(&self);
}
struct Dumper {
hex: String,
ascii: String,
count: usize,
total_count: usize,
}
impl Dumper {
fn new() -> Dumper {
Dumper {
hex: String::with_capacity(49),
ascii: String::with_capacity(16),
count: 0,
total_count: 0,
}
}
fn add_byte(&mut self, ch: u8) {
if self.count == 16 {
self.ship();
}
if self.count == 8 {
self.hex.push(' ');
}
self.hex.push_str(&format!(" {:02x}", ch)[..]);
self.ascii.push(if (b' '..=b'~').contains(&ch) {
ch as char
} else {
'.'
});
self.count += 1;
}
fn ship(&mut self) {
if self.count == 0 {
return;
}
println!("{:06x} {:-49} |{}|", self.total_count, self.hex, self.ascii);
self.hex.clear();
self.ascii.clear();
self.total_count += 16;
self.count = 0;
}
}
impl<'a> HexDump for &'a [u8] {
fn dump(&self) {
let mut dump = Dumper::new();
for ch in self.iter() {
dump.add_byte(*ch);
}
dump.ship();
}
}
impl HexDump for Vec<u8> {
fn dump(&self) {
(&self[..]).dump()
}
}
#[test]
fn samples() {
"Hello".as_bytes().dump();
"This is a much longer string".as_bytes().dump();
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f".as_bytes().dump();
}

View File

@@ -0,0 +1,62 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2019 JUUL Labs
// Copyright (c) 2019-2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
// Query the bootloader's capabilities.
#[repr(u32)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(unused)]
pub enum Caps {
RSA2048 = (1 << 0),
/* reserved (1 << 1) */
EcdsaP256 = (1 << 2),
SwapUsingScratch = (1 << 3),
OverwriteUpgrade = (1 << 4),
EncRsa = (1 << 5),
EncKw = (1 << 6),
ValidatePrimarySlot = (1 << 7),
RSA3072 = (1 << 8),
Ed25519 = (1 << 9),
EncEc256 = (1 << 10),
SwapUsingMove = (1 << 11),
DowngradePrevention = (1 << 12),
EncX25519 = (1 << 13),
Bootstrap = (1 << 14),
Aes256 = (1 << 15),
RamLoad = (1 << 16),
DirectXip = (1 << 17),
HwRollbackProtection = (1 << 18),
EcdsaP384 = (1 << 19),
}
impl Caps {
pub fn present(self) -> bool {
let caps = unsafe { bootutil_get_caps() };
(caps as u32) & (self as u32) != 0
}
/// Does this build have ECDSA of some type enabled for signatures.
pub fn has_ecdsa() -> bool {
Caps::EcdsaP256.present() || Caps::EcdsaP384.present()
}
/// Query for the number of images that have been configured into this
/// MCUboot build.
pub fn get_num_images() -> usize {
(unsafe { bootutil_get_num_images() }) as usize
}
/// Query if this configuration performs some kind of upgrade by writing to flash.
pub fn modifies_flash() -> bool {
// All other configurations perform upgrades by writing to flash.
!(Self::RamLoad.present() || Self::DirectXip.present())
}
}
extern "C" {
fn bootutil_get_caps() -> Caps;
fn bootutil_get_num_images() -> u32;
}

View File

@@ -0,0 +1,187 @@
// Copyright (c) 2019-2021 Linaro LTD
//
// SPDX-License-Identifier: Apache-2.0
//! Support and tests related to the dependency management for multi-image
//! support.
use crate::image::ImageVersion;
pub trait Depender {
/// Generate a version for this particular image. The slot indicates
/// which slot this is being put in.
fn my_version(&self, offset: usize, slot: usize) -> ImageVersion;
/// Return dependencies for this image/slot combination.
fn my_deps(&self, offset: usize, slot: usize) -> Vec<ImageVersion>;
/// Return the image ID of the other version.
fn other_id(&self) -> u8;
}
/// A boring image is used when we aren't testing dependencies. There will
/// be meaningful version numbers. The size field is the image number we
/// are.
pub struct BoringDep {
number: usize,
test: DepTest,
}
impl BoringDep {
pub fn new(number: usize, test: &DepTest) -> BoringDep {
BoringDep {
number,
test: test.clone(),
}
}
}
impl Depender for BoringDep {
fn my_version(&self, _offset: usize, slot: usize) -> ImageVersion {
let slot = if self.test.downgrade {
1 - slot
} else {
slot
};
ImageVersion::new_synthetic(self.number as u8, slot as u8, 0)
}
fn my_deps(&self, _offset: usize, _slot: usize) -> Vec<ImageVersion> {
vec![]
}
fn other_id(&self) -> u8 {
0
}
}
/// An individual test of the dependency mechanism describes one of the
/// possibilities for the dependency information for each image, and what
/// the expected outcome is.
#[derive(Clone, Debug)]
pub struct DepTest {
/// What kinds of dependency should be installed in the image.
pub depends: [DepType; 2],
/// What is the expected outcome of the upgrade.
pub upgrades: [UpgradeInfo; 2],
/// Should this be considered a downgrade (cause the version number to
/// decrease).
pub downgrade: bool,
}
/// Describes the various types of dependency information that can be
/// provided.
#[derive(Clone, Debug)]
pub enum DepType {
/// Do not include dependency information
Nothing,
/// Provide dependency information that matches the other image.
Correct,
/// Provide a dependency that matches the old version of the other
/// image.
OldCorrect,
/// Provide dependency information describing something newer than the
/// other image.
Newer,
/// Don't provide an upgrade image at all for this image
NoUpgrade,
}
/// Describes what our expectation is for an upgrade.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum UpgradeInfo {
/// The current version should be held.
Held,
/// The image should be upgraded
Upgraded,
}
/// A "test" that gives no dependency information.
pub static NO_DEPS: DepTest = DepTest {
depends: [DepType::Nothing, DepType::Nothing],
upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
downgrade: false,
};
/// A "test" with no dependency information, and the images marked as a
/// downgrade.
pub static REV_DEPS: DepTest = DepTest {
depends: [DepType::Nothing, DepType::Nothing],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: true,
};
/// A PairDep describes the dependencies between two pairs.
pub struct PairDep {
/// The image number of this image.
number: usize,
test: DepTest,
}
impl PairDep {
pub fn new(total_image: usize, my_image: usize, deps: &DepTest) -> PairDep {
if total_image != 2 {
panic!("PairDep only works when there are two images");
}
PairDep {
number: my_image,
test: deps.clone(),
}
}
}
impl Depender for PairDep {
fn my_version(&self, _offset: usize, slot: usize) -> ImageVersion {
let slot = if self.test.downgrade {
1 - slot
} else {
slot
};
ImageVersion::new_synthetic(self.number as u8, slot as u8, 0)
}
fn my_deps(&self, _offset: usize, slot: usize) -> Vec<ImageVersion> {
// For now, don't put any dependencies in slot zero. They could be
// added here if we someday implement checking these.
if slot == 0 {
vec![]
} else {
match self.test.depends[self.number] {
DepType::Nothing => vec![],
DepType::NoUpgrade => panic!("Shouldn't get to this point"),
DepType::Correct => vec![
ImageVersion::new_synthetic(self.other_id(), slot as u8, 0)
],
DepType::OldCorrect => vec![
ImageVersion::new_synthetic(self.other_id(), 0, 0)
],
DepType::Newer => vec![
ImageVersion::new_synthetic(self.other_id(), slot as u8, 1)
],
}
}
}
fn other_id(&self) -> u8 {
(1 - self.number) as u8
}
}
impl ImageVersion {
/// Generate an image version based on some key information. The image
/// number influences the major version number (by an arbitrary factor),
/// and the slot affects the major number on the build_number. The minor
/// number can also be given to force numbers to be different.
fn new_synthetic(image_id: u8, slot: u8, minor: u8) -> ImageVersion {
ImageVersion {
major: image_id * 20 + slot,
minor,
revision: 1,
build_num: slot as u32,
}
}
}

View File

@@ -0,0 +1,32 @@
static ECDSA256_PUB_KEY: &[u8] = &[
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0x2a, 0xcb, 0x40, 0x3c, 0xe8,
0xfe, 0xed, 0x5b, 0xa4, 0x49, 0x95, 0xa1, 0xa9,
0x1d, 0xae, 0xe8, 0xdb, 0xbe, 0x19, 0x37, 0xcd,
0x14, 0xfb, 0x2f, 0x24, 0x57, 0x37, 0xe5, 0x95,
0x39, 0x88, 0xd9, 0x94, 0xb9, 0xd6, 0x5a, 0xeb,
0xd7, 0xcd, 0xd5, 0x30, 0x8a, 0xd6, 0xfe, 0x48,
0xb2, 0x4a, 0x6a, 0x81, 0x0e, 0xe5, 0xf0, 0x7d,
0x8b, 0x68, 0x34, 0xcc, 0x3a, 0x6a, 0xfc, 0x53,
0x8e, 0xfa, 0xc1,
];
static ECDSAP384_PUB_KEY: &[u8] = &[
0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04,
0x0c, 0x76, 0xca, 0xae, 0x72, 0x3a, 0xa5, 0xe8,
0xf0, 0xd4, 0xf1, 0x16, 0xb5, 0x02, 0xef, 0x77,
0xa1, 0x1b, 0x93, 0x61, 0x78, 0xc0, 0x09, 0x26,
0x7b, 0x3b, 0x40, 0x9c, 0xee, 0x49, 0x85, 0xe0,
0xc9, 0x4f, 0xe7, 0xf2, 0xba, 0x97, 0x6c, 0xf3,
0x82, 0x65, 0x14, 0x2c, 0xf5, 0x0c, 0x73, 0x33,
0x4d, 0x32, 0xe7, 0x9b, 0xd3, 0x42, 0xcc, 0x95,
0x5a, 0xe5, 0xe2, 0xf5, 0xf4, 0x6e, 0x45, 0xe0,
0xed, 0x20, 0x35, 0x5c, 0xaf, 0x52, 0x35, 0x81,
0xd4, 0xdc, 0x9c, 0xe3, 0x9e, 0x22, 0x3e, 0xfb,
0x3f, 0x22, 0x10, 0xda, 0x70, 0x03, 0x37, 0xad,
0xa8, 0xf2, 0x48, 0xfe, 0x3a, 0x60, 0x69, 0xa5,
];

View File

@@ -0,0 +1,8 @@
static ED25519_PUB_KEY: &[u8] = &[
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
0x70, 0x03, 0x21, 0x00, 0xd4, 0xb3, 0x1b, 0xa4,
0x9a, 0x3a, 0xdd, 0x3f, 0x82, 0x5d, 0x10, 0xca,
0x7f, 0x31, 0xb5, 0x0b, 0x0d, 0xe8, 0x7f, 0x37,
0xcc, 0xc4, 0x9f, 0x1a, 0x40, 0x3a, 0x5c, 0x13,
0x20, 0xff, 0xb4, 0xe0,
];

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,231 @@
// Copyright (c) 2017-2019 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
// Copyright (c) 2019-2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
use docopt::Docopt;
use log::{warn, error};
use std::{
fmt,
process,
};
use serde_derive::Deserialize;
mod caps;
mod depends;
mod image;
mod tlv;
mod utils;
pub mod testlog;
pub use crate::{
depends::{
DepTest,
DepType,
UpgradeInfo,
NO_DEPS,
REV_DEPS,
},
image::{
ImagesBuilder,
Images,
ImageManipulation,
show_sizes,
},
};
const USAGE: &str = "
Mcuboot simulator
Usage:
bootsim sizes
bootsim run --device TYPE [--align SIZE]
bootsim runall
bootsim (--help | --version)
Options:
-h, --help Show this message
--version Version
--device TYPE MCU to simulate
Valid values: stm32f4, k64f
--align SIZE Flash write alignment
";
#[derive(Debug, Deserialize)]
struct Args {
flag_device: Option<DeviceName>,
flag_align: Option<AlignArg>,
cmd_sizes: bool,
cmd_run: bool,
cmd_runall: bool,
}
#[derive(Copy, Clone, Debug, Deserialize)]
pub enum DeviceName {
Stm32f4, K64f, K64fBig, K64fMulti, Nrf52840, Nrf52840SpiFlash,
Nrf52840UnequalSlots,
}
pub static ALL_DEVICES: &[DeviceName] = &[
DeviceName::Stm32f4,
DeviceName::K64f,
DeviceName::K64fBig,
DeviceName::K64fMulti,
DeviceName::Nrf52840,
DeviceName::Nrf52840SpiFlash,
DeviceName::Nrf52840UnequalSlots,
];
impl fmt::Display for DeviceName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match *self {
DeviceName::Stm32f4 => "stm32f4",
DeviceName::K64f => "k64f",
DeviceName::K64fBig => "k64fbig",
DeviceName::K64fMulti => "k64fmulti",
DeviceName::Nrf52840 => "nrf52840",
DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
DeviceName::Nrf52840UnequalSlots => "Nrf52840UnequalSlots",
};
f.write_str(name)
}
}
#[derive(Debug)]
struct AlignArg(usize);
struct AlignArgVisitor;
impl<'de> serde::de::Visitor<'de> for AlignArgVisitor {
type Value = AlignArg;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("1, 2, 4 or 8")
}
fn visit_u32<E>(self, n: u32) -> Result<Self::Value, E>
where E: serde::de::Error
{
Ok(match n {
1 | 2 | 4 | 8 => AlignArg(n as usize),
n => {
let err = format!("Could not deserialize '{}' as alignment", n);
return Err(E::custom(err));
}
})
}
}
impl<'de> serde::de::Deserialize<'de> for AlignArg {
fn deserialize<D>(d: D) -> Result<AlignArg, D::Error>
where D: serde::de::Deserializer<'de>
{
d.deserialize_u8(AlignArgVisitor)
}
}
pub fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit());
// println!("args: {:#?}", args);
if args.cmd_sizes {
show_sizes();
return;
}
let mut status = RunStatus::new();
if args.cmd_run {
let align = args.flag_align.map(|x| x.0).unwrap_or(1);
let device = match args.flag_device {
None => panic!("Missing mandatory device argument"),
Some(dev) => dev,
};
status.run_single(device, align, 0xff);
}
if args.cmd_runall {
for &dev in ALL_DEVICES {
for &align in &[1, 2, 4, 8] {
for &erased_val in &[0, 0xff] {
status.run_single(dev, align, erased_val);
}
}
}
}
if status.failures > 0 {
error!("{} Tests ran with {} failures", status.failures + status.passes, status.failures);
process::exit(1);
} else {
error!("{} Tests ran successfully", status.passes);
process::exit(0);
}
}
#[derive(Default)]
pub struct RunStatus {
failures: usize,
passes: usize,
}
impl RunStatus {
pub fn new() -> RunStatus {
RunStatus {
failures: 0,
passes: 0,
}
}
pub fn run_single(&mut self, device: DeviceName, align: usize, erased_val: u8) {
warn!("Running on device {} with alignment {}", device, align);
let run = match ImagesBuilder::new(device, align, erased_val) {
Ok(builder) => builder,
Err(msg) => {
warn!("Skipping {}: {}", device, msg);
return;
}
};
let mut failed = false;
// Creates a badly signed image in the secondary slot to check that
// it is not upgraded to
let bad_secondary_slot_image = run.clone().make_bad_secondary_slot_image();
failed |= bad_secondary_slot_image.run_signfail_upgrade();
let images = run.clone().make_no_upgrade_image(&NO_DEPS, ImageManipulation::None);
failed |= images.run_norevert_newimage();
let images = run.make_image(&NO_DEPS, true);
failed |= images.run_basic_revert();
failed |= images.run_revert_with_fails();
failed |= images.run_perm_with_fails();
failed |= images.run_perm_with_random_fails(5);
failed |= images.run_norevert();
failed |= images.run_with_status_fails_complete();
failed |= images.run_with_status_fails_with_reset();
//show_flash(&flash);
if failed {
self.failures += 1;
} else {
self.passes += 1;
}
}
pub fn failures(&self) -> usize {
self.failures
}
}

View File

@@ -0,0 +1,10 @@
// Copyright (c) 2017-2019 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
//
// SPDX-License-Identifier: Apache-2.0
fn main() {
env_logger::init();
bootsim::main();
}

View File

@@ -0,0 +1,53 @@
/* Autogenerated by imgtool.py, do not edit. */
static RSA3072_PUB_KEY: &[u8] = &[
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
0x00, 0xb4, 0x2c, 0x0e, 0x98, 0x58, 0x10, 0xa4,
0xa7, 0x58, 0x99, 0x7c, 0x01, 0xdd, 0x08, 0x2a,
0x28, 0x34, 0x33, 0xf8, 0x96, 0x1a, 0x34, 0x20,
0x5d, 0x45, 0xc8, 0x71, 0x26, 0x25, 0xe5, 0xd2,
0x96, 0xea, 0x7b, 0xb1, 0x15, 0xaa, 0xa6, 0x8a,
0x63, 0x22, 0x8b, 0x2d, 0x4e, 0x81, 0x73, 0xbf,
0x6e, 0x15, 0x68, 0x8c, 0x1a, 0xf4, 0xef, 0x2a,
0x8f, 0x8c, 0x22, 0x9e, 0x71, 0x57, 0x4b, 0xde,
0x0f, 0x7e, 0x72, 0xd3, 0x7a, 0xb8, 0xa7, 0x1d,
0x44, 0xad, 0x87, 0x00, 0x83, 0x5c, 0xfd, 0x73,
0x05, 0x72, 0x46, 0x3f, 0x8b, 0xf9, 0x10, 0x00,
0xd8, 0x6e, 0xcc, 0x85, 0xed, 0xf9, 0x49, 0xdb,
0x78, 0x36, 0x80, 0x49, 0x38, 0x76, 0xdd, 0x5f,
0x54, 0x04, 0xda, 0x8c, 0x34, 0xa7, 0x2b, 0x13,
0x25, 0x6f, 0xd1, 0x15, 0x4f, 0xad, 0xc2, 0xe1,
0xa5, 0xd2, 0x4e, 0x57, 0x0c, 0x7e, 0x9c, 0x9b,
0xba, 0x4e, 0x68, 0xb2, 0xe0, 0x25, 0x02, 0xaa,
0x00, 0xd3, 0xb4, 0xcc, 0x2f, 0x78, 0xe5, 0xbe,
0x47, 0x67, 0x1f, 0xc8, 0x6e, 0x22, 0x6c, 0x5e,
0x61, 0xb6, 0x9a, 0xcd, 0xe5, 0xa8, 0xba, 0x7a,
0x80, 0x13, 0x1b, 0x17, 0x2e, 0x96, 0xed, 0xcf,
0xb3, 0x9b, 0xe4, 0x1c, 0xe8, 0xad, 0xa7, 0xf6,
0x3a, 0x51, 0x66, 0x5e, 0x99, 0x8e, 0x87, 0xee,
0x60, 0x25, 0xf8, 0x8d, 0xbe, 0xce, 0xa4, 0xa8,
0xca, 0x93, 0x6c, 0xd7, 0xbf, 0xd4, 0x73, 0x33,
0x8d, 0x44, 0x85, 0xcc, 0x73, 0x30, 0x08, 0x9c,
0x4d, 0xb2, 0xaa, 0x5a, 0x6c, 0x6f, 0x7b, 0xab,
0xb7, 0xb3, 0x7c, 0xc3, 0xfb, 0xe7, 0xca, 0xc4,
0xf8, 0x9a, 0x6f, 0xcb, 0xbb, 0x5b, 0x82, 0xe7,
0x7a, 0xe8, 0x19, 0xfd, 0x2f, 0x11, 0x22, 0xfb,
0x7f, 0x76, 0x8c, 0x6b, 0x94, 0xa4, 0x09, 0x4f,
0xa5, 0x6a, 0x77, 0x51, 0xeb, 0xa7, 0x7e, 0xda,
0x87, 0x06, 0xee, 0xdc, 0xbe, 0xd1, 0xea, 0x1a,
0x40, 0x1d, 0x1b, 0xff, 0x1a, 0xb1, 0x51, 0x7c,
0x12, 0xb0, 0xf3, 0xf6, 0x83, 0x01, 0x9c, 0xe7,
0x0c, 0x99, 0xbf, 0xac, 0x68, 0x58, 0x72, 0xa4,
0xb0, 0x59, 0x85, 0xee, 0x85, 0xac, 0x2a, 0x22,
0xf4, 0xcf, 0x15, 0x08, 0x80, 0x1f, 0x0d, 0xd0,
0x1e, 0xa0, 0xa0, 0x94, 0xc8, 0xf7, 0xfa, 0x65,
0xdd, 0x52, 0xe8, 0x96, 0x37, 0x23, 0x30, 0x57,
0x36, 0xe6, 0x9d, 0xf4, 0x0c, 0x4a, 0x05, 0x75,
0x1f, 0xad, 0x01, 0xca, 0xb7, 0x6d, 0x8c, 0x43,
0x74, 0x06, 0x0a, 0x81, 0xf3, 0x01, 0x62, 0xff,
0xf7, 0xf5, 0x5f, 0xaf, 0xe7, 0x2b, 0x0e, 0xf8,
0x81, 0xb5, 0x65, 0xdd, 0x01, 0xd9, 0x9f, 0x07,
0x17, 0x8a, 0x18, 0xcf, 0x23, 0x6e, 0x88, 0x65,
0x91, 0xb5, 0x7b, 0xd3, 0xb0, 0x2d, 0xaf, 0x93,
0x66, 0x63, 0x74, 0xac, 0x5a, 0xe6, 0x73, 0xde,
0x3b, 0x02, 0x03, 0x01, 0x00, 0x01,
];

View File

@@ -0,0 +1,37 @@
/* Autogenerated by imgtool.py, do not edit. */
static RSA_PUB_KEY: &[u8] = &[
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
0x00, 0xd1, 0x06, 0x08, 0x1a, 0x18, 0x44, 0x2c,
0x18, 0xe8, 0xfb, 0xfd, 0xf7, 0x0d, 0xa3, 0x4f,
0x1f, 0xbb, 0xee, 0x5e, 0xf9, 0xaa, 0xd2, 0x4b,
0x18, 0xd3, 0x5a, 0xe9, 0x6d, 0x18, 0x80, 0x19,
0xf9, 0xf0, 0x9c, 0x34, 0x1b, 0xcb, 0xf3, 0xbc,
0x74, 0xdb, 0x42, 0xe7, 0x8c, 0x7f, 0x10, 0x53,
0x7e, 0x43, 0x5e, 0x0d, 0x57, 0x2c, 0x44, 0xd1,
0x67, 0x08, 0x0f, 0x0d, 0xbb, 0x5c, 0xee, 0xec,
0xb3, 0x99, 0xdf, 0xe0, 0x4d, 0x84, 0x0b, 0xaa,
0x77, 0x41, 0x60, 0xed, 0x15, 0x28, 0x49, 0xa7,
0x01, 0xb4, 0x3c, 0x10, 0xe6, 0x69, 0x8c, 0x2f,
0x5f, 0xac, 0x41, 0x4d, 0x9e, 0x5c, 0x14, 0xdf,
0xf2, 0xf8, 0xcf, 0x3d, 0x1e, 0x6f, 0xe7, 0x5b,
0xba, 0xb4, 0xa9, 0xc8, 0x88, 0x7e, 0x47, 0x3c,
0x94, 0xc3, 0x77, 0x67, 0x54, 0x4b, 0xaa, 0x8d,
0x38, 0x35, 0xca, 0x62, 0x61, 0x7e, 0xb7, 0xe1,
0x15, 0xdb, 0x77, 0x73, 0xd4, 0xbe, 0x7b, 0x72,
0x21, 0x89, 0x69, 0x24, 0xfb, 0xf8, 0x65, 0x6e,
0x64, 0x3e, 0xc8, 0x0e, 0xd7, 0x85, 0xd5, 0x5c,
0x4a, 0xe4, 0x53, 0x0d, 0x2f, 0xff, 0xb7, 0xfd,
0xf3, 0x13, 0x39, 0x83, 0x3f, 0xa3, 0xae, 0xd2,
0x0f, 0xa7, 0x6a, 0x9d, 0xf9, 0xfe, 0xb8, 0xce,
0xfa, 0x2a, 0xbe, 0xaf, 0xb8, 0xe0, 0xfa, 0x82,
0x37, 0x54, 0xf4, 0x3e, 0xe1, 0x2b, 0xd0, 0xd3,
0x08, 0x58, 0x18, 0xf6, 0x5e, 0x4c, 0xc8, 0x88,
0x81, 0x31, 0xad, 0x5f, 0xb0, 0x82, 0x17, 0xf2,
0x8a, 0x69, 0x27, 0x23, 0xf3, 0xab, 0x87, 0x3e,
0x93, 0x1a, 0x1d, 0xfe, 0xe8, 0xf8, 0x1a, 0x24,
0x66, 0x59, 0xf8, 0x1c, 0xab, 0xdc, 0xce, 0x68,
0x1b, 0x66, 0x64, 0x35, 0xec, 0xfa, 0x0d, 0x11,
0x9d, 0xaf, 0x5c, 0x3a, 0xa7, 0xd1, 0x67, 0xc6,
0x47, 0xef, 0xb1, 0x4b, 0x2c, 0x62, 0xe1, 0xd1,
0xc9, 0x02, 0x03, 0x01, 0x00, 0x01,
];

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2017 Linaro LTD
// Copyright (c) 2019 JUUL Labs
//
// SPDX-License-Identifier: Apache-2.0
//! Logging support for the test framework.
//!
//! https://stackoverflow.com/questions/30177845/how-to-initialize-the-logger-for-integration-tests
//!
//! The test framework runs the tests, possibly simultaneously, and in various orders. This helper
//! function, which should be called at the beginning of each test, will setup logging for all of
//! the tests.
use std::sync::Once;
static INIT: Once = Once::new();
/// Setup the logging system. Intended to be called at the beginning of each test.
pub fn setup() {
INIT.call_once(|| {
env_logger::init();
});
}

View File

@@ -0,0 +1,841 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2017-2020 JUUL Labs
// Copyright (c) 2021-2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
//! TLV Support
//!
//! mcuboot images are followed immediately by a list of TLV items that contain integrity
//! information about the image. Their generation is made a little complicated because the size of
//! the TLV block is in the image header, which is included in the hash. Since some signatures can
//! vary in size, we just make them the largest size possible.
//!
//! Because of this header, we have to make two passes. The first pass will compute the size of
//! the TLV, and the second pass will build the data for the TLV.
use byteorder::{
LittleEndian, WriteBytesExt,
};
use cipher::FromBlockCipher;
use crate::caps::Caps;
use crate::image::ImageVersion;
use log::info;
use ring::{digest, rand, agreement, hkdf, hmac};
use ring::rand::SecureRandom;
use ring::signature::{
RsaKeyPair,
RSA_PSS_SHA256,
EcdsaKeyPair,
ECDSA_P256_SHA256_ASN1_SIGNING,
Ed25519KeyPair,
ECDSA_P384_SHA384_ASN1_SIGNING,
};
use aes::{
Aes128,
Aes128Ctr,
Aes256,
Aes256Ctr,
NewBlockCipher
};
use cipher::{
generic_array::GenericArray,
StreamCipher,
};
use mcuboot_sys::c;
use typenum::{U16, U32};
#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[allow(dead_code)] // TODO: For now
pub enum TlvKinds {
KEYHASH = 0x01,
SHA256 = 0x10,
SHA384 = 0x11,
RSA2048 = 0x20,
ECDSASIG = 0x22,
RSA3072 = 0x23,
ED25519 = 0x24,
ENCRSA2048 = 0x30,
ENCKW = 0x31,
ENCEC256 = 0x32,
ENCX25519 = 0x33,
DEPENDENCY = 0x40,
SECCNT = 0x50,
}
#[allow(dead_code, non_camel_case_types)]
pub enum TlvFlags {
PIC = 0x01,
NON_BOOTABLE = 0x02,
ENCRYPTED_AES128 = 0x04,
ENCRYPTED_AES256 = 0x08,
RAM_LOAD = 0x20,
}
/// A generator for manifests. The format of the manifest can be either a
/// traditional "TLV" or a SUIT-style manifest.
pub trait ManifestGen {
/// Retrieve the header magic value for this manifest type.
fn get_magic(&self) -> u32;
/// Retrieve the flags value for this particular manifest type.
fn get_flags(&self) -> u32;
/// Retrieve the number of bytes of this manifest that is "protected".
/// This field is stored in the outside image header instead of the
/// manifest header.
fn protect_size(&self) -> u16;
/// Add a dependency on another image.
fn add_dependency(&mut self, id: u8, version: &ImageVersion);
/// Add a sequence of bytes to the payload that the manifest is
/// protecting.
fn add_bytes(&mut self, bytes: &[u8]);
/// Set an internal flag indicating that the next `make_tlv` should
/// corrupt the signature.
fn corrupt_sig(&mut self);
/// Estimate the size of the TLV. This can be called before the payload is added (but after
/// other information is added). Some of the signature algorithms can generate variable sized
/// data, and therefore, this can slightly overestimate the size.
fn estimate_size(&self) -> usize;
/// Construct the manifest for this payload.
fn make_tlv(self: Box<Self>) -> Vec<u8>;
/// Generate a new encryption random key
fn generate_enc_key(&mut self);
/// Return the current encryption key
fn get_enc_key(&self) -> Vec<u8>;
/// Set the security counter to the specified value.
fn set_security_counter(&mut self, security_cnt: Option<u32>);
/// Sets the ignore_ram_load_flag so that can be validated when it is missing,
/// it will not load successfully.
fn set_ignore_ram_load_flag(&mut self);
}
#[derive(Debug, Default)]
pub struct TlvGen {
flags: u32,
kinds: Vec<TlvKinds>,
payload: Vec<u8>,
dependencies: Vec<Dependency>,
enc_key: Vec<u8>,
/// Should this signature be corrupted.
gen_corrupted: bool,
security_cnt: Option<u32>,
/// Ignore RAM_LOAD flag
ignore_ram_load_flag: bool,
}
#[derive(Debug)]
struct Dependency {
id: u8,
version: ImageVersion,
}
impl TlvGen {
/// Construct a new tlv generator that will only contain a hash of the data.
#[allow(dead_code)]
pub fn new_hash_only() -> TlvGen {
TlvGen {
kinds: vec![TlvKinds::SHA256],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_rsa_pss() -> TlvGen {
TlvGen {
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_rsa3072_pss() -> TlvGen {
TlvGen {
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA3072],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ecdsa() -> TlvGen {
let hash_kind = if cfg!(feature = "sig-p384") {
TlvKinds::SHA384
} else {
TlvKinds::SHA256
};
TlvGen {
kinds: vec![hash_kind, TlvKinds::ECDSASIG],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ed25519() -> TlvGen {
TlvGen {
kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_enc_rsa(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_sig_enc_rsa(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCRSA2048],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_enc_kw(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_rsa_kw(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::RSA2048, TlvKinds::ENCKW],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ecdsa_kw(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSASIG, TlvKinds::ENCKW],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ecies_p256(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCEC256],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ecdsa_ecies_p256(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ECDSASIG, TlvKinds::ENCEC256],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ecies_x25519(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ENCX25519],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_ed25519_ecies_x25519(aes_key_size: u32) -> TlvGen {
let flag = if aes_key_size == 256 {
TlvFlags::ENCRYPTED_AES256 as u32
} else {
TlvFlags::ENCRYPTED_AES128 as u32
};
TlvGen {
flags: flag,
kinds: vec![TlvKinds::SHA256, TlvKinds::ED25519, TlvKinds::ENCX25519],
..Default::default()
}
}
#[allow(dead_code)]
pub fn new_sec_cnt() -> TlvGen {
TlvGen {
kinds: vec![TlvKinds::SHA256, TlvKinds::SECCNT],
..Default::default()
}
}
}
impl ManifestGen for TlvGen {
fn get_magic(&self) -> u32 {
0x96f3b83d
}
/// Retrieve the header flags for this configuration. This can be called at any time.
fn get_flags(&self) -> u32 {
// For the RamLoad case, add in the flag for this feature.
if Caps::RamLoad.present() && !self.ignore_ram_load_flag {
self.flags | (TlvFlags::RAM_LOAD as u32)
} else {
self.flags
}
}
/// Add bytes to the covered hash.
fn add_bytes(&mut self, bytes: &[u8]) {
self.payload.extend_from_slice(bytes);
}
fn protect_size(&self) -> u16 {
let mut size = 0;
if !self.dependencies.is_empty() || (Caps::HwRollbackProtection.present() && self.security_cnt.is_some()) {
// include the TLV area header.
size += 4;
// add space for each dependency.
size += (self.dependencies.len() as u16) * (4 + std::mem::size_of::<Dependency>() as u16);
if Caps::HwRollbackProtection.present() && self.security_cnt.is_some() {
size += 4 + 4;
}
}
size
}
fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
self.dependencies.push(Dependency {
id,
version: version.clone(),
});
}
fn corrupt_sig(&mut self) {
self.gen_corrupted = true;
}
fn estimate_size(&self) -> usize {
// Begin the estimate with the 4 byte header.
let mut estimate = 4;
// A very poor estimate.
// Estimate the size of the image hash.
if self.kinds.contains(&TlvKinds::SHA256) {
estimate += 4 + 32;
} else if self.kinds.contains(&TlvKinds::SHA384) {
estimate += 4 + 48;
}
// Add an estimate in for each of the signature algorithms.
if self.kinds.contains(&TlvKinds::RSA2048) {
estimate += 4 + 32; // keyhash
estimate += 4 + 256; // RSA2048
}
if self.kinds.contains(&TlvKinds::RSA3072) {
estimate += 4 + 32; // keyhash
estimate += 4 + 384; // RSA3072
}
if self.kinds.contains(&TlvKinds::ED25519) {
estimate += 4 + 32; // keyhash
estimate += 4 + 64; // ED25519 signature.
}
if self.kinds.contains(&TlvKinds::ECDSASIG) {
// ECDSA signatures are encoded as ASN.1 with the x and y values
// stored as signed integers. As such, the size can vary by 2 bytes,
// if for example the 256-bit value has the high bit, it takes an
// extra 0 byte to avoid it being seen as a negative number.
if self.kinds.contains(&TlvKinds::SHA384) {
estimate += 4 + 48; // SHA384
estimate += 4 + 104; // ECDSA384 (varies)
} else {
estimate += 4 + 32; // SHA256
estimate += 4 + 72; // ECDSA256 (varies)
}
}
// Estimate encryption.
let flag = TlvFlags::ENCRYPTED_AES256 as u32;
let aes256 = (self.get_flags() & flag) == flag;
if self.kinds.contains(&TlvKinds::ENCRSA2048) {
estimate += 4 + 256;
}
if self.kinds.contains(&TlvKinds::ENCKW) {
estimate += 4 + if aes256 { 40 } else { 24 };
}
if self.kinds.contains(&TlvKinds::ENCEC256) {
estimate += 4 + if aes256 { 129 } else { 113 };
}
if self.kinds.contains(&TlvKinds::ENCX25519) {
estimate += 4 + if aes256 { 96 } else { 80 };
}
// Gather the size of the protected TLV area.
estimate += self.protect_size() as usize;
estimate
}
/// Compute the TLV given the specified block of data.
fn make_tlv(self: Box<Self>) -> Vec<u8> {
let size_estimate = self.estimate_size();
let mut protected_tlv: Vec<u8> = vec![];
if self.protect_size() > 0 {
protected_tlv.push(0x08);
protected_tlv.push(0x69);
let size = self.protect_size();
protected_tlv.write_u16::<LittleEndian>(size).unwrap();
for dep in &self.dependencies {
protected_tlv.write_u16::<LittleEndian>(TlvKinds::DEPENDENCY as u16).unwrap();
protected_tlv.write_u16::<LittleEndian>(12).unwrap();
// The dependency.
protected_tlv.push(dep.id);
protected_tlv.push(0);
protected_tlv.write_u16::<LittleEndian>(0).unwrap();
protected_tlv.push(dep.version.major);
protected_tlv.push(dep.version.minor);
protected_tlv.write_u16::<LittleEndian>(dep.version.revision).unwrap();
protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
}
// Security counter has to be at the protected TLV area also
if Caps::HwRollbackProtection.present() && self.security_cnt.is_some() {
protected_tlv.write_u16::<LittleEndian>(TlvKinds::SECCNT as u16).unwrap();
protected_tlv.write_u16::<LittleEndian>(std::mem::size_of::<u32>() as u16).unwrap();
protected_tlv.write_u32::<LittleEndian>(self.security_cnt.unwrap() as u32).unwrap();
}
assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
}
// Ring does the signature itself, which means that it must be
// given a full, contiguous payload. Although this does help from
// a correct usage perspective, it is fairly stupid from an
// efficiency view. If this is shown to be a performance issue
// with the tests, the protected data could be appended to the
// payload, and then removed after the signature is done. For now,
// just make a signed payload.
let mut sig_payload = self.payload.clone();
sig_payload.extend_from_slice(&protected_tlv);
let mut result: Vec<u8> = vec![];
// add back signed payload
result.extend_from_slice(&protected_tlv);
// add non-protected payload
let npro_pos = result.len();
result.push(0x07);
result.push(0x69);
// Placeholder for the size.
result.write_u16::<LittleEndian>(0).unwrap();
if self.kinds.iter().any(|v| v == &TlvKinds::SHA256 || v == &TlvKinds::SHA384) {
// If a signature is not requested, corrupt the hash we are
// generating. But, if there is a signature, output the
// correct hash. We want the hash test to pass so that the
// signature verification can be validated.
let mut corrupt_hash = self.gen_corrupted;
for k in &[TlvKinds::RSA2048, TlvKinds::RSA3072,
TlvKinds::ED25519, TlvKinds::ECDSASIG]
{
if self.kinds.contains(k) {
corrupt_hash = false;
break;
}
}
if corrupt_hash {
sig_payload[0] ^= 1;
}
let (hash,hash_size,tlv_kind) = if self.kinds.contains(&TlvKinds::SHA256)
{
let hash = digest::digest(&digest::SHA256, &sig_payload);
(hash,32,TlvKinds::SHA256)
}
else {
let hash = digest::digest(&digest::SHA384, &sig_payload);
(hash,48,TlvKinds::SHA384)
};
let hash = hash.as_ref();
assert!(hash.len() == hash_size);
result.write_u16::<LittleEndian>(tlv_kind as u16).unwrap();
result.write_u16::<LittleEndian>(hash_size as u16).unwrap();
result.extend_from_slice(hash);
// Undo the corruption.
if corrupt_hash {
sig_payload[0] ^= 1;
}
}
if self.gen_corrupted {
// Corrupt what is signed by modifying the input to the
// signature code.
sig_payload[0] ^= 1;
}
if self.kinds.contains(&TlvKinds::RSA2048) ||
self.kinds.contains(&TlvKinds::RSA3072) {
let is_rsa2048 = self.kinds.contains(&TlvKinds::RSA2048);
// Output the hash of the public key.
let hash = if is_rsa2048 {
digest::digest(&digest::SHA256, RSA_PUB_KEY)
} else {
digest::digest(&digest::SHA256, RSA3072_PUB_KEY)
};
let hash = hash.as_ref();
assert!(hash.len() == 32);
result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
result.write_u16::<LittleEndian>(32).unwrap();
result.extend_from_slice(hash);
// For now assume PSS.
let key_bytes = if is_rsa2048 {
pem::parse(include_bytes!("../../root-rsa-2048.pem").as_ref()).unwrap()
} else {
pem::parse(include_bytes!("../../root-rsa-3072.pem").as_ref()).unwrap()
};
assert_eq!(key_bytes.tag, "RSA PRIVATE KEY");
let key_pair = RsaKeyPair::from_der(&key_bytes.contents).unwrap();
let rng = rand::SystemRandom::new();
let mut signature = vec![0; key_pair.public_modulus_len()];
if is_rsa2048 {
assert_eq!(signature.len(), 256);
} else {
assert_eq!(signature.len(), 384);
}
key_pair.sign(&RSA_PSS_SHA256, &rng, &sig_payload, &mut signature).unwrap();
if is_rsa2048 {
result.write_u16::<LittleEndian>(TlvKinds::RSA2048 as u16).unwrap();
} else {
result.write_u16::<LittleEndian>(TlvKinds::RSA3072 as u16).unwrap();
}
result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
result.extend_from_slice(&signature);
}
if self.kinds.contains(&TlvKinds::ECDSASIG) {
let rng = rand::SystemRandom::new();
let (signature, keyhash, keyhash_size) = if self.kinds.contains(&TlvKinds::SHA384) {
let keyhash = digest::digest(&digest::SHA384, ECDSAP384_PUB_KEY);
let key_bytes = pem::parse(include_bytes!("../../root-ec-p384-pkcs8.pem").as_ref()).unwrap();
let sign_algo = &ECDSA_P384_SHA384_ASN1_SIGNING;
let key_pair = EcdsaKeyPair::from_pkcs8(sign_algo, &key_bytes.contents).unwrap();
(key_pair.sign(&rng, &sig_payload).unwrap(), keyhash, 48)
} else {
let keyhash = digest::digest(&digest::SHA256, ECDSA256_PUB_KEY);
let key_bytes = pem::parse(include_bytes!("../../root-ec-p256-pkcs8.pem").as_ref()).unwrap();
let sign_algo = &ECDSA_P256_SHA256_ASN1_SIGNING;
let key_pair = EcdsaKeyPair::from_pkcs8(sign_algo, &key_bytes.contents).unwrap();
(key_pair.sign(&rng, &sig_payload).unwrap(), keyhash, 32)
};
// Write public key
let keyhash_slice = keyhash.as_ref();
assert!(keyhash_slice.len() == keyhash_size);
result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
result.write_u16::<LittleEndian>(keyhash_size as u16).unwrap();
result.extend_from_slice(keyhash_slice);
// Write signature
result.write_u16::<LittleEndian>(TlvKinds::ECDSASIG as u16).unwrap();
let signature = signature.as_ref().to_vec();
result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
result.extend_from_slice(&signature);
}
if self.kinds.contains(&TlvKinds::ED25519) {
let keyhash = digest::digest(&digest::SHA256, ED25519_PUB_KEY);
let keyhash = keyhash.as_ref();
assert!(keyhash.len() == 32);
result.write_u16::<LittleEndian>(TlvKinds::KEYHASH as u16).unwrap();
result.write_u16::<LittleEndian>(32).unwrap();
result.extend_from_slice(keyhash);
let hash = digest::digest(&digest::SHA256, &sig_payload);
let hash = hash.as_ref();
assert!(hash.len() == 32);
let key_bytes = pem::parse(include_bytes!("../../root-ed25519.pem").as_ref()).unwrap();
assert_eq!(key_bytes.tag, "PRIVATE KEY");
let key_pair = Ed25519KeyPair::from_seed_and_public_key(
&key_bytes.contents[16..48], &ED25519_PUB_KEY[12..44]).unwrap();
let signature = key_pair.sign(&hash);
result.write_u16::<LittleEndian>(TlvKinds::ED25519 as u16).unwrap();
let signature = signature.as_ref().to_vec();
result.write_u16::<LittleEndian>(signature.len() as u16).unwrap();
result.extend_from_slice(signature.as_ref());
}
if self.kinds.contains(&TlvKinds::ENCRSA2048) {
let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
.as_ref()).unwrap();
assert_eq!(key_bytes.tag, "PUBLIC KEY");
let cipherkey = self.get_enc_key();
let cipherkey = cipherkey.as_slice();
let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, cipherkey) {
Ok(v) => v,
Err(_) => panic!("Failed to encrypt secret key"),
};
assert!(encbuf.len() == 256);
result.write_u16::<LittleEndian>(TlvKinds::ENCRSA2048 as u16).unwrap();
result.write_u16::<LittleEndian>(256).unwrap();
result.extend_from_slice(&encbuf);
}
if self.kinds.contains(&TlvKinds::ENCKW) {
let flag = TlvFlags::ENCRYPTED_AES256 as u32;
let aes256 = (self.get_flags() & flag) == flag;
let key_bytes = if aes256 {
base64::decode(
include_str!("../../enc-aes256kw.b64").trim()).unwrap()
} else {
base64::decode(
include_str!("../../enc-aes128kw.b64").trim()).unwrap()
};
let cipherkey = self.get_enc_key();
let cipherkey = cipherkey.as_slice();
let keylen = if aes256 { 32 } else { 16 };
let encbuf = match c::kw_encrypt(&key_bytes, cipherkey, keylen) {
Ok(v) => v,
Err(_) => panic!("Failed to encrypt secret key"),
};
let size = if aes256 { 40 } else { 24 };
assert!(encbuf.len() == size);
result.write_u16::<LittleEndian>(TlvKinds::ENCKW as u16).unwrap();
result.write_u16::<LittleEndian>(size as u16).unwrap();
result.extend_from_slice(&encbuf);
}
if self.kinds.contains(&TlvKinds::ENCEC256) || self.kinds.contains(&TlvKinds::ENCX25519) {
let key_bytes = if self.kinds.contains(&TlvKinds::ENCEC256) {
pem::parse(include_bytes!("../../enc-ec256-pub.pem").as_ref()).unwrap()
} else {
pem::parse(include_bytes!("../../enc-x25519-pub.pem").as_ref()).unwrap()
};
assert_eq!(key_bytes.tag, "PUBLIC KEY");
let rng = rand::SystemRandom::new();
let alg = if self.kinds.contains(&TlvKinds::ENCEC256) {
&agreement::ECDH_P256
} else {
&agreement::X25519
};
let pk = match agreement::EphemeralPrivateKey::generate(alg, &rng) {
Ok(v) => v,
Err(_) => panic!("Failed to generate ephemeral keypair"),
};
let pubk = match pk.compute_public_key() {
Ok(pubk) => pubk,
Err(_) => panic!("Failed computing ephemeral public key"),
};
let peer_pubk = if self.kinds.contains(&TlvKinds::ENCEC256) {
agreement::UnparsedPublicKey::new(&agreement::ECDH_P256, &key_bytes.contents[26..])
} else {
agreement::UnparsedPublicKey::new(&agreement::X25519, &key_bytes.contents[12..])
};
#[derive(Debug, PartialEq)]
struct OkmLen<T: core::fmt::Debug + PartialEq>(T);
impl hkdf::KeyType for OkmLen<usize> {
fn len(&self) -> usize {
self.0
}
}
let flag = TlvFlags::ENCRYPTED_AES256 as u32;
let aes256 = (self.get_flags() & flag) == flag;
let derived_key = match agreement::agree_ephemeral(
pk, &peer_pubk, ring::error::Unspecified, |shared| {
let salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]);
let prk = salt.extract(&shared);
let okm_len = if aes256 { 64 } else { 48 };
let okm = match prk.expand(&[b"MCUBoot_ECIES_v1"], OkmLen(okm_len)) {
Ok(okm) => okm,
Err(_) => panic!("Failed building HKDF OKM"),
};
let mut buf = if aes256 { vec![0u8; 64] } else { vec![0u8; 48] };
match okm.fill(&mut buf) {
Ok(_) => Ok(buf),
Err(_) => panic!("Failed generating HKDF output"),
}
},
) {
Ok(v) => v,
Err(_) => panic!("Failed building HKDF"),
};
let nonce = GenericArray::from_slice(&[0; 16]);
let mut cipherkey = self.get_enc_key();
if aes256 {
let key: &GenericArray<u8, U32> = GenericArray::from_slice(&derived_key[..32]);
let block = Aes256::new(&key);
let mut cipher = Aes256Ctr::from_block_cipher(block, &nonce);
cipher.apply_keystream(&mut cipherkey);
} else {
let key: &GenericArray<u8, U16> = GenericArray::from_slice(&derived_key[..16]);
let block = Aes128::new(&key);
let mut cipher = Aes128Ctr::from_block_cipher(block, &nonce);
cipher.apply_keystream(&mut cipherkey);
}
let size = if aes256 { 32 } else { 16 };
let key = hmac::Key::new(hmac::HMAC_SHA256, &derived_key[size..]);
let tag = hmac::sign(&key, &cipherkey);
let mut buf = vec![];
buf.append(&mut pubk.as_ref().to_vec());
buf.append(&mut tag.as_ref().to_vec());
buf.append(&mut cipherkey);
if self.kinds.contains(&TlvKinds::ENCEC256) {
let size = if aes256 { 129 } else { 113 };
assert!(buf.len() == size);
result.write_u16::<LittleEndian>(TlvKinds::ENCEC256 as u16).unwrap();
result.write_u16::<LittleEndian>(size as u16).unwrap();
} else {
let size = if aes256 { 96 } else { 80 };
assert!(buf.len() == size);
result.write_u16::<LittleEndian>(TlvKinds::ENCX25519 as u16).unwrap();
result.write_u16::<LittleEndian>(size as u16).unwrap();
}
result.extend_from_slice(&buf);
}
// Patch the size back into the TLV header.
let size = (result.len() - npro_pos) as u16;
let mut size_buf = &mut result[npro_pos + 2 .. npro_pos + 4];
size_buf.write_u16::<LittleEndian>(size).unwrap();
// ECDSA is stored as an ASN.1 integer. For a 128-bit value, this maximally results in 33
// bytes of storage for each of the two values. If the high bit is zero, it will take 32
// bytes, if the top 8 bits are zero, it will take 31 bits, and so on. The smaller size
// will occur with decreasing likelihood. We'll allow this to get a bit smaller, hopefully
// allowing the tests to pass with false failures rare. For this case, we'll handle up to
// the top 16 bits of both numbers being all zeros (1 in 2^32).
if !Caps::has_ecdsa() {
if size_estimate != result.len() {
panic!("Incorrect size estimate: {} (actual {})", size_estimate, result.len());
}
} else {
if size_estimate < result.len() || size_estimate > result.len() + 6 {
panic!("Incorrect size estimate: {} (actual {})", size_estimate, result.len());
}
}
if size_estimate != result.len() {
log::warn!("Size off: {} actual {}", size_estimate, result.len());
}
result
}
fn generate_enc_key(&mut self) {
let rng = rand::SystemRandom::new();
let flag = TlvFlags::ENCRYPTED_AES256 as u32;
let aes256 = (self.get_flags() & flag) == flag;
let mut buf = if aes256 {
vec![0u8; 32]
} else {
vec![0u8; 16]
};
if rng.fill(&mut buf).is_err() {
panic!("Error generating encrypted key");
}
info!("New encryption key: {:02x?}", buf);
self.enc_key = buf;
}
fn get_enc_key(&self) -> Vec<u8> {
if self.enc_key.len() != 32 && self.enc_key.len() != 16 {
panic!("No random key was generated");
}
self.enc_key.clone()
}
fn set_security_counter(&mut self, security_cnt: Option<u32>) {
self.security_cnt = security_cnt;
}
fn set_ignore_ram_load_flag(&mut self) {
self.ignore_ram_load_flag = true;
}
}
include!("rsa_pub_key-rs.txt");
include!("rsa3072_pub_key-rs.txt");
include!("ecdsa_pub_key-rs.txt");
include!("ed25519_pub_key-rs.txt");

View File

@@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
//
// SPDX-License-Identifier: Apache-2.0
//! Utility functions used throughout MCUboot
pub fn align_up(num: u32, align: u32) -> u32 {
assert!(align.is_power_of_two());
(num + (align - 1)) & !(align - 1)
}

View File

@@ -0,0 +1,201 @@
// Copyright (c) 2017-2021 Linaro LTD
// Copyright (c) 2017-2019 JUUL Labs
// Copyright (c) 2021-2023 Arm Limited
//
// SPDX-License-Identifier: Apache-2.0
//! Core tests
//!
//! Run the existing testsuite as a Rust unit test.
use bootsim::{
DepTest, DepType, UpgradeInfo,
ImagesBuilder,
Images,
NO_DEPS,
REV_DEPS,
testlog,
ImageManipulation
};
use std::{
env,
sync::atomic::{AtomicUsize, Ordering},
};
/// A single test, after setting up logging and such. Within the $body,
/// $arg will be bound to each device.
macro_rules! test_shell {
($name:ident, $arg: ident, $body:expr) => {
#[test]
fn $name() {
testlog::setup();
ImagesBuilder::each_device(|$arg| {
$body;
});
}
}
}
/// A typical test calls a particular constructor, and runs a given test on
/// that constructor.
macro_rules! sim_test {
($name:ident, $maker:ident($($margs:expr),*), $test:ident($($targs:expr),*)) => {
test_shell!($name, r, {
let image = r.$maker($($margs),*);
dump_image(&image, stringify!($name));
assert!(!image.$test($($targs),*));
});
};
}
sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgrade());
sim_test!(secondary_trailer_leftover, make_erased_secondary_image(), run_secondary_leftover_trailer());
sim_test!(bootstrap, make_bootstrap_image(), run_bootstrap());
sim_test!(oversized_bootstrap, make_oversized_bootstrap_image(), run_oversized_bootstrap());
sim_test!(norevert_newimage, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_norevert_newimage());
sim_test!(basic_revert, make_image(&NO_DEPS, true), run_basic_revert());
sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails());
sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails());
sim_test!(perm_with_random_fails, make_image(&NO_DEPS, true), run_perm_with_random_fails(5));
sim_test!(norevert, make_image(&NO_DEPS, true), run_norevert());
#[cfg(not(feature = "max-align-32"))]
sim_test!(oversized_secondary_slot, make_oversized_secondary_slot_image(), run_oversizefail_upgrade());
sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_status_fails_complete());
sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset());
sim_test!(downgrade_prevention, make_image(&REV_DEPS, true), run_nodowngrade());
sim_test!(direct_xip_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_direct_xip());
sim_test!(ram_load_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_ram_load());
sim_test!(ram_load_split, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_split_ram_load());
sim_test!(hw_prot_failed_security_cnt_check, make_image_with_security_counter(Some(0)), run_hw_rollback_prot());
sim_test!(hw_prot_missing_security_cnt, make_image_with_security_counter(None), run_hw_rollback_prot());
sim_test!(ram_load_out_of_bounds, make_no_upgrade_image(&NO_DEPS, ImageManipulation::WrongOffset), run_ram_load_boot_with_result(false));
sim_test!(ram_load_missing_header_flag, make_no_upgrade_image(&NO_DEPS, ImageManipulation::IgnoreRamLoadFlag), run_ram_load_boot_with_result(false));
sim_test!(ram_load_failed_validation, make_no_upgrade_image(&NO_DEPS, ImageManipulation::BadSignature), run_ram_load_boot_with_result(false));
sim_test!(ram_load_corrupt_higher_version_image, make_no_upgrade_image(&NO_DEPS, ImageManipulation::CorruptHigherVersionImage), run_ram_load_boot_with_result(true));
#[cfg(feature = "multiimage")]
sim_test!(ram_load_overlapping_images_same_base, make_no_upgrade_image(&NO_DEPS, ImageManipulation::OverlapImages(true)), run_ram_load_boot_with_result(false));
#[cfg(feature = "multiimage")]
sim_test!(ram_load_overlapping_images_offset, make_no_upgrade_image(&NO_DEPS, ImageManipulation::OverlapImages(false)), run_ram_load_boot_with_result(false));
// Test various combinations of incorrect dependencies.
test_shell!(dependency_combos, r, {
// Only test setups with two images.
if r.num_images() != 2 {
return;
}
for dep in TEST_DEPS {
let image = r.clone().make_image(&dep, true);
dump_image(&image, "dependency_combos");
assert!(!image.run_check_deps(&dep));
}
});
/// These are the variants of dependencies we will test.
pub static TEST_DEPS: &[DepTest] = &[
// A sanity test, no dependencies should upgrade.
DepTest {
depends: [DepType::Nothing, DepType::Nothing],
upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
downgrade: false,
},
// If all of the dependencies are met, we should also upgrade.
DepTest {
depends: [DepType::Correct, DepType::Correct],
upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Upgraded],
downgrade: false,
},
// If none of the dependencies are met, the images should be held.
DepTest {
depends: [DepType::Newer, DepType::Newer],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: false,
},
// If the first image is not met, we should hold back on the
// dependencies (it is not well defined what the correct behavior is
// here, it could also be correct to upgrade only the second image).
DepTest {
depends: [DepType::Newer, DepType::Correct],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: false,
},
// Test the variant in the other direction.
DepTest {
depends: [DepType::Correct, DepType::Newer],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: false,
},
// Test where only the first image is upgraded, and there are no
// dependencies.
DepTest {
depends: [DepType::Nothing, DepType::NoUpgrade],
upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Held],
downgrade: false,
},
// Test one image with a valid dependency on the first image.
DepTest {
depends: [DepType::OldCorrect, DepType::NoUpgrade],
upgrades: [UpgradeInfo::Upgraded, UpgradeInfo::Held],
downgrade: false,
},
// Test one image with an invalid dependency on the first image.
DepTest {
depends: [DepType::Newer, DepType::NoUpgrade],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: false,
},
// Test where only the second image is upgraded, and there are no
// dependencies.
DepTest {
depends: [DepType::NoUpgrade, DepType::Nothing],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Upgraded],
downgrade: false,
},
// Test one image with a valid dependency on the second image.
DepTest {
depends: [DepType::NoUpgrade, DepType::OldCorrect],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Upgraded],
downgrade: false,
},
// Test one image with an invalid dependency on the second image.
DepTest {
depends: [DepType::NoUpgrade, DepType::Newer],
upgrades: [UpgradeInfo::Held, UpgradeInfo::Held],
downgrade: false,
},
];
/// Counter for the image number.
static IMAGE_NUMBER: AtomicUsize = AtomicUsize::new(0);
/// Dump an image if that makes sense. The name is the name of the test
/// being run. If the MCUBOT_DEBUG_DUMP environment variable contains, in
/// one of its comma separate strings a substring of this name, then this
/// image will be dumped. As a special case, we will dump everything if
/// this environment variable is set to all.
fn dump_image(image: &Images, name: &str) {
if let Ok(request) = env::var("MCUBOOT_DEBUG_DUMP") {
if request.split(',').any(|req| {
req == "all" || name.contains(req)
}) {
let count = IMAGE_NUMBER.fetch_add(1, Ordering::SeqCst);
let full_name = format!("{}-{:04}", name, count);
log::info!("Dump {:?}", full_name);
image.debug_dump(&full_name);
}
}
}