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

30
bootloader/mcuboot/.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
outdir/
.*.swp
target.sh
*.pyc
tags
rusty-tags.*
# mynewt
/repos/
/project.state
/bin/
/targets/
**/build/**/*
#Eclipse project files
.cproject
.project
# Compiled python modules.
*.pyc
# Setuptools distribution folder.
/scripts/dist/
# Python egg metadata, regenerated from source files by setuptools.
/scripts/*.egg-info
/scripts/*.egg
# The target directory from Rust development
/target/

21
bootloader/mcuboot/.gitmodules vendored Normal file
View File

@@ -0,0 +1,21 @@
[submodule "sim/mbedtls"]
path = ext/mbedtls
url = https://github.com/ARMmbed/mbedtls
[submodule "boot/cypress/libs/mtb-pdl-cat1"]
path = boot/cypress/libs/mtb-pdl-cat1
url = https://github.com/cypresssemiconductorco/mtb-pdl-cat1.git
[submodule "boot/cypress/libs/pdl/psoc6pdl"]
path = boot/cypress/libs/pdl/psoc6pdl
url = https://github.com/cypresssemiconductorco/psoc6pdl.git
[submodule "boot/cypress/libs/retarget-io"]
path = boot/cypress/libs/retarget-io
url = https://github.com/cypresssemiconductorco/retarget-io.git
[submodule "boot/cypress/libs/core-lib"]
path = boot/cypress/libs/core-lib
url = https://github.com/cypresssemiconductorco/core-lib.git
[submodule "boot/cypress/libs/psoc6hal"]
path = boot/cypress/libs/psoc6hal
url = https://github.com/cypresssemiconductorco/psoc6hal.git
[submodule "boot/cypress/libs/cy-mbedtls-acceleration"]
path = boot/cypress/libs/cy-mbedtls-acceleration
url = https://github.com/cypresssemiconductorco/cy-mbedtls-acceleration.git

View File

@@ -0,0 +1,20 @@
boot/boot_serial/*
boot/mynewt/*
boot/zephyr/*
boot/cypress/*
boot/espressif/*
boot/nuttx/*
ci/*
docs/*
ptest/*
samples/*
scripts/*
sim/*
testplan/*
ext/fiat/*
ext/mbedtls/*
ext/mbedtls-asn1/*
ext/nrf/*
ext/tinycrypt/tests/*
ext/tinycrypt/*
ext/tinycrypt-sha512/*

View File

@@ -0,0 +1,81 @@
# Travis configuration. Run FI hardening tests.
language: minimal
services:
- docker
matrix:
include:
- os: linux
language: minimal
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=RELEASE SKIP_SIZE=2,4,6,8,10 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 FIH_LEVEL=LOW TEST=fih-tests DAMAGE_TYPE=SIGNATURE
- os: linux
language: minimal
env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=8,10 FIH_LEVEL=MEDIUM TEST=fih-tests DAMAGE_TYPE=SIGNATURE
## Corrupt image hash is not tested as it is in the unprotected TLV section
## and is easy to calculate a valid hash for a changed image
#- os: linux
# language: minimal
# env: BUILD_TYPE=MINSIZEREL SKIP_SIZE=2,4,6 TEST=fih-tests DAMAGE_TYPE=IMAGE_HASH
## Max profile is not tested as it requires HW entropy source which is not
## present in the QEMU system being used for the tests.
#- os: linux
# language: minimal
# env: FIH_LEVEL=MAX TEST=fih-tests
before_install:
- |
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
./ci/check-signed-off-by.sh
if [ $? -ne 0 ]; then
exit 1
fi
fi
install:
- ./ci/${TEST}_install.sh
script:
- ./ci/${TEST}_run.sh
cache:
directories:
- docker
notifications:
slack:
rooms:
- secure: "Tg9ZvJfb6e4QSEsxUvwW2MIqbuNRxD4nAOkgs8eopj/fRtqN6Zk06NVSeMmYcZunDFJXUSzYANBsF98OtaaUlm4WVt2T0ZFBJZrOYfIv18/zXCjYa04sDxur57F1ZYTYKyRpdUkfzPd/rGE4jKLQNcia+r/BTQbJkcZbXeg5/6cUeMP1so8/o0oMhSQP+GH0fLbyLzx3VPE8zu6+j2fCFC7R3idxtfO9VtsKlubfi3HgPgXTs+DEAAA8aoOku2esjFSFXTtdUFGz90YzyShZvtMcRg3Grp9+PZAsJwWk4eKSonKCO0DScfPUlMZbJcV7VsmyTxYKLLsGRZae6ZBH+XLfx5XeqgtgCor3FYx2dUXYfV9y8VvERDdossB0gZ/V2OUGePctDefiORytV6dMa7X3AfSdosgs/tjG4kbf+PMaVULzwF6dd3CdsxdClSl68UQPWA6wC2TEyo1EQea8jgZU6heLustZaQZhBkFkr/6j75XeGBjPw2fgVRkgg/OnTOYmo7N8181wOU+xORIEO1BtYmgRpc0cgpm4H9457diSHG1D2SoNy4tiQPCW2enN00QNGK5pZSL/FGA/ReUcALgAW0QcOljjU2bUSGPxo/VAi5ZyljWgVAGQ5qHJ4jgdfPf7VJUzCVH64G1S5+0gZPpO6vvvPdZtqeXrfBZMOBw="
on_success: always

View File

@@ -0,0 +1,134 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
mcuboot@groups.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

542
bootloader/mcuboot/Cargo.lock generated Normal file
View File

@@ -0,0 +1,542 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
"ctr",
"opaque-debug",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bootsim"
version = "0.1.0"
dependencies = [
"aes",
"base64",
"byteorder",
"cipher",
"docopt",
"env_logger",
"libc",
"log",
"mcuboot-sys",
"pem",
"rand",
"ring",
"serde",
"serde_derive",
"simflash",
"typenum",
"untrusted 0.9.0",
]
[[package]]
name = "bumpalo"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array",
]
[[package]]
name = "cpufeatures"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
dependencies = [
"libc",
]
[[package]]
name = "ctr"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
dependencies = [
"cipher",
]
[[package]]
name = "docopt"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f"
dependencies = [
"lazy_static",
"regex",
"serde",
"strsim",
]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "js-sys"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
[[package]]
name = "log"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if",
]
[[package]]
name = "mcuboot-sys"
version = "0.1.0"
dependencies = [
"cc",
"libc",
"log",
"simflash",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "pem"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947"
dependencies = [
"base64",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro2"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted 0.7.1",
"web-sys",
"winapi",
]
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "simflash"
version = "0.1.0"
dependencies = [
"log",
"rand",
"thiserror",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
[[package]]
name = "web-sys"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -0,0 +1,14 @@
[workspace]
members = ["sim"]
exclude = ["ptest"]
resolver = "2"
# The simulator runs very slowly without optimization. A value of 1
# compiles in about half the time, but runs about 5-6 times slower. 2
# and 3 are hardly different in either compile time or performance.
# Use 2 in case that makes the code slightly more debuggable.
[profile.test]
opt-level = 2
[profile.dev]
opt-level = 2

206
bootloader/mcuboot/LICENSE Normal file
View File

@@ -0,0 +1,206 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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 product bundles tinycrypt, which is available under the "3-clause BSD"
license. For details, and bundled files see:
* ext/tinycrypt/LICENSE
* ext/tinycrypt

11
bootloader/mcuboot/NOTICE Normal file
View File

@@ -0,0 +1,11 @@
Apache Mynewt
Copyright 2015-2017 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
Portions of this software were developed at
Runtime Inc, copyright 2015.
Portions of this software were developed at
Arm Limited, copyright 2019-2021.

View File

@@ -0,0 +1,85 @@
# [MCUboot](http://mcuboot.com/)
[![Package on PyPI](https://img.shields.io/pypi/v/imgtool.svg)][pypi]
[![Coverity Scan Build Status](https://scan.coverity.com/projects/12307/badge.svg)][coverity]
[![Build Status (Sim)](https://github.com/mcu-tools/mcuboot/workflows/Sim/badge.svg)][sim]
[![Build Status (Mynewt)](https://github.com/mcu-tools/mcuboot/workflows/Mynewt/badge.svg)][mynewt]
[![Build Status (Espressif)](https://github.com/mcu-tools/mcuboot/workflows/Espressif/badge.svg)][espressif]
[![Publishing Status (imgtool)](https://github.com/mcu-tools/mcuboot/workflows/imgtool/badge.svg)][imgtool]
[![Build Status (Travis CI)](https://img.shields.io/travis/mcu-tools/mcuboot/main.svg?label=travis-ci)][travis]
[![Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)][license]
[pypi]: https://pypi.org/project/imgtool/
[coverity]: https://scan.coverity.com/projects/mcuboot
[sim]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Sim
[mynewt]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Mynewt
[espressif]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:Espressif
[imgtool]: https://github.com/mcu-tools/mcuboot/actions?query=workflow:imgtool
[travis]: https://travis-ci.org/mcu-tools/mcuboot
[license]: https://github.com/mcu-tools/mcuboot/blob/main/LICENSE
This is MCUboot version 2.1.0
MCUboot is a secure bootloader for 32-bits microcontrollers. It defines a
common infrastructure for the bootloader and the system flash layout on
microcontroller systems, and provides a secure bootloader that enables easy
software upgrade.
MCUboot is not dependent on any specific operating system and hardware and
relies on hardware porting layers from the operating system it works with.
Currently, MCUboot works with the following operating systems and SoCs:
- [Zephyr](https://www.zephyrproject.org/)
- [Apache Mynewt](https://mynewt.apache.org/)
- [Apache NuttX](https://nuttx.apache.org/)
- [RIOT](https://www.riot-os.org/)
- [Mbed OS](https://os.mbed.com/)
- [Espressif](https://www.espressif.com/)
- [Cypress/Infineon](https://www.cypress.com/)
RIOT is supported only as a boot target. We will accept any new
port contributed by the community once it is good enough.
## MCUboot How-tos
See the following pages for instructions on using MCUboot with different
operating systems and SoCs:
- [Zephyr](docs/readme-zephyr.md)
- [Apache Mynewt](docs/readme-mynewt.md)
- [Apache NuttX](docs/readme-nuttx.md)
- [RIOT](docs/readme-riot.md)
- [Mbed OS](docs/readme-mbed.md)
- [Espressif](docs/readme-espressif.md)
- [Cypress/Infineon](boot/cypress/README.md)
There are also instructions for the [Simulator](sim/README.rst).
## Roadmap
The issues being planned and worked on are tracked using GitHub issues. To
give your input, visit [MCUboot GitHub
Issues](https://github.com/mcu-tools/mcuboot/issues).
## Source files
You can find additional documentation on the bootloader in the source files.
For more information, use the following links:
- [boot/bootutil](https://github.com/mcu-tools/mcuboot/tree/main/boot/bootutil) - The core of the bootloader itself.
- [boot/boot\_serial](https://github.com/mcu-tools/mcuboot/tree/main/boot/boot_serial) - Support for serial upgrade within the bootloader itself.
- [boot/zephyr](https://github.com/mcu-tools/mcuboot/tree/main/boot/zephyr) - Port of the bootloader to Zephyr.
- [boot/mynewt](https://github.com/mcu-tools/mcuboot/tree/main/boot/mynewt) - Bootloader application for Apache Mynewt.
- [boot/nuttx](https://github.com/mcu-tools/mcuboot/tree/main/boot/nuttx) - Bootloader application and port of MCUboot interfaces for Apache NuttX.
- [boot/mbed](https://github.com/mcu-tools/mcuboot/tree/main/boot/mbed) - Port of the bootloader to Mbed OS.
- [boot/espressif](https://github.com/mcu-tools/mcuboot/tree/main/boot/espressif) - Bootloader application and MCUboot port for Espressif SoCs.
- [boot/cypress](https://github.com/mcu-tools/mcuboot/tree/main/boot/cypress) - Bootloader application and MCUboot port for Cypress/Infineon SoCs.
- [imgtool](https://github.com/mcu-tools/mcuboot/tree/main/scripts/imgtool.py) - A tool to securely sign firmware images for booting by MCUboot.
- [sim](https://github.com/mcu-tools/mcuboot/tree/main/sim) - A bootloader simulator for testing and regression.
## Joining the project
Developers are welcome!
Use the following links to join or see more about the project:
* [Our developer mailing list](https://groups.io/g/MCUBoot)
* [Our Discord channel](https://discord.com/channels/1106321706588577904/1106322802308550716) <br />
Get [your invite](https://discord.com/invite/5PpXhvda5p)

View File

@@ -0,0 +1,59 @@
/*
* 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 __BOOT_SERIAL_H__
#define __BOOT_SERIAL_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* Function pointers to read/write data from uart.
* read returns the number of bytes read, str points to buffer to fill,
* cnt is the number of bytes to fill within buffer, *newline will be
* set if newline is the last character.
* write takes as it's arguments pointer to data to write, and the count
* of bytes.
*/
struct boot_uart_funcs {
int (*read)(char *str, int cnt, int *newline);
void (*write)(const char *ptr, int cnt);
};
/**
* Start processing newtmgr commands for uploading image0 over serial.
* Assumes serial port is open and waits for download command.
*/
void boot_serial_start(const struct boot_uart_funcs *f);
/**
* Start processing newtmgr commands for uploading image0 over serial.
* Assumes serial port is open and waits for download command.
* This function will return if there is no mcumgr command received within
* the given timeout. If a command is received within this timeout, the
* function is similar to boot_serial_start
*/
void boot_serial_check_start(const struct boot_uart_funcs *f, int timeout_in_ms);
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_SERIAL_H__ */

View File

@@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Nordic Semiconductor ASA
*/
#ifndef H_BOOT_SERIAL_ENCRYPTION_
#define H_BOOT_SERIAL_ENCRYPTION_
#include "bootutil/fault_injection_hardening.h"
/**
* Validate hash of a primary boot image doing on the fly decryption as well
*
* @param[in] fa_p flash area pointer
* @param[in] hdr boot image header pointer
* @param[in] buf buffer which is used for validating data
* @param[in] buf_size size of input buffer
*
* @return FIH_SUCCESS on success, error code otherwise
*/
fih_ret
boot_image_validate_encrypted(const struct flash_area *fa_p,
struct image_header *hdr, uint8_t *buf,
uint16_t buf_size);
/**
* Handle an encrypted firmware in the main flash.
* This will decrypt the image inplace
*/
int boot_handle_enc_fw(const struct flash_area *flash_area);
#endif

View File

@@ -0,0 +1,38 @@
#
# 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.
#
pkg.name: boot/boot_serial
pkg.description: The boot_serial library is used when downloading image over serial port.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- boot
- bootloader
pkg.deps:
- "@apache-mynewt-core/hw/hal"
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/encoding/base64"
- "@mcuboot/boot/mynewt/flash_map_backend"
- "@mcuboot/boot/mynewt/boot_uart"
- "@mcuboot/boot/zcbor"
- "@apache-mynewt-core/util/crc"
pkg.req_apis:
- bootloader

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
* Copyright (c) 2020 Arm Limited
*/
#include <assert.h>
#include "bootutil/image.h"
#include <../src/bootutil_priv.h>
#include "bootutil/bootutil_log.h"
#include "bootutil/bootutil_public.h"
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/enc_key.h"
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_ENC_IMAGES
BOOT_LOG_MODULE_DECLARE(serial_encryption);
fih_ret
boot_image_validate_encrypted(const struct flash_area *fa_p,
struct image_header *hdr, uint8_t *buf,
uint16_t buf_size)
{
FIH_DECLARE(fih_rc, FIH_FAILURE);
struct boot_loader_state boot_data;
struct boot_loader_state *state = &boot_data;
struct boot_status _bs;
struct boot_status *bs = &_bs;
uint8_t image_index;
int rc;
memset(&boot_data, 0, sizeof(struct boot_loader_state));
image_index = BOOT_CURR_IMG(state);
if(IS_ENCRYPTED(hdr)) {
rc = boot_enc_load(BOOT_CURR_ENC(state), 1, hdr, fa_p, bs);
if (rc < 0) {
FIH_RET(fih_rc);
}
rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs);
if (rc < 0) {
FIH_RET(fih_rc);
}
}
FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
hdr, fa_p, buf, buf_size, NULL, 0, NULL);
FIH_RET(fih_rc);
}
/*
* Compute the total size of the given image. Includes the size of
* the TLVs.
*/
static int
read_image_size(const struct flash_area *fa_p,
struct image_header *hdr,
uint32_t *size)
{
struct image_tlv_info info;
uint32_t off;
uint32_t protect_tlv_size;
int rc;
off = BOOT_TLV_OFF(hdr);
if (flash_area_read(fa_p, off, &info, sizeof(info))) {
rc = BOOT_EFLASH;
goto done;
}
protect_tlv_size = hdr->ih_protect_tlv_size;
if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
if (protect_tlv_size != info.it_tlv_tot) {
rc = BOOT_EBADIMAGE;
goto done;
}
if (flash_area_read(fa_p, off + info.it_tlv_tot, &info, sizeof(info))) {
rc = BOOT_EFLASH;
goto done;
}
} else if (protect_tlv_size != 0) {
rc = BOOT_EBADIMAGE;
goto done;
}
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
rc = BOOT_EBADIMAGE;
goto done;
}
*size = off + protect_tlv_size + info.it_tlv_tot;
rc = 0;
done:
return rc;
}
/**
* reads, decrypts in RAM & write back the decrypted image in the same region
* This function is NOT power failsafe since the image is decrypted in the RAM
* buffer.
*
* @param flash_area The ID of the source flash area.
* @param off_src The offset within the flash area to
* copy from.
* @param sz The number of bytes to copy. should match erase sector
*
* @return 0 on success; nonzero on failure.
*/
static int
decrypt_region_inplace(struct boot_loader_state *state,
const struct flash_area *fap,
struct image_header *hdr,
uint32_t off, uint32_t sz)
{
uint32_t bytes_copied;
int chunk_sz;
int rc;
uint32_t tlv_off;
size_t blk_off;
uint16_t idx;
uint32_t blk_sz;
int slot = flash_area_id_to_multi_image_slot(BOOT_CURR_IMG(state),
flash_area_get_id(fap));
uint8_t buf[sz] __attribute__((aligned));
assert(sz <= sizeof buf);
assert(slot >= 0);
bytes_copied = 0;
while (bytes_copied < sz) {
if (sz - bytes_copied > sizeof buf) {
chunk_sz = sizeof buf;
} else {
chunk_sz = sz - bytes_copied;
}
rc = flash_area_read(fap, off + bytes_copied, buf, chunk_sz);
if (rc != 0) {
return BOOT_EFLASH;
}
if (IS_ENCRYPTED(hdr)) {
blk_sz = chunk_sz;
idx = 0;
if (off + bytes_copied < hdr->ih_hdr_size) {
/* do not decrypt header */
if (hdr->ih_hdr_size > (off + bytes_copied + chunk_sz)) {
/* all bytes in header, skip decryption */
blk_sz = 0;
}
else {
blk_sz = off + bytes_copied + chunk_sz - hdr->ih_hdr_size;
}
blk_off = 0;
idx = hdr->ih_hdr_size;
} else {
blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
}
tlv_off = BOOT_TLV_OFF(hdr);
if (off + bytes_copied + chunk_sz > tlv_off) {
/* do not decrypt TLVs */
if (off + bytes_copied >= tlv_off) {
blk_sz = 0;
} else {
blk_sz = tlv_off - (off + bytes_copied);
}
}
boot_enc_decrypt(BOOT_CURR_ENC(state), slot,
(off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
blk_off, &buf[idx]);
}
rc = flash_area_erase(fap, off + bytes_copied, chunk_sz);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = flash_area_write(fap, off + bytes_copied, buf, chunk_sz);
if (rc != 0) {
return BOOT_EFLASH;
}
bytes_copied += chunk_sz;
MCUBOOT_WATCHDOG_FEED();
}
return 0;
}
/**
* Check if a image was encrypted into the first slot, and decrypt it
* in place. this operation is not power failsafe.
*
* The operation is done by checking the last flash sector, and using it as a
* temporarely scratch partition. The
*
* @param[in] fa_p flash area pointer
* @param[in] hdr boot image header pointer
*
* @return FIH_SUCCESS on success, error code otherwise
*/
inline static fih_ret
decrypt_image_inplace(const struct flash_area *fa_p,
struct image_header *hdr)
{
FIH_DECLARE(fih_rc, FIH_FAILURE);
int rc;
struct boot_loader_state boot_data;
struct boot_loader_state *state = &boot_data;
struct boot_status _bs;
struct boot_status *bs = &_bs;
size_t size;
size_t sect_size;
size_t sect_count;
size_t sect;
struct flash_sector sector;
memset(&boot_data, 0, sizeof(struct boot_loader_state));
memset(&_bs, 0, sizeof(struct boot_status));
/* Get size from last sector to know page/sector erase size */
rc = flash_area_get_sector(fa_p, boot_status_off(fa_p), &sector);
if(IS_ENCRYPTED(hdr)) {
#if 0 //Skip this step?, the image will just not boot if it's not decrypted properly
static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
/* First check if the encrypted image is a good image before decrypting */
FIH_CALL(boot_image_validate_encrypted,fih_rc,fa_p,&_hdr,tmpbuf,BOOT_TMPBUF_SZ);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_RET(fih_rc);
}
#endif
memset(&boot_data, 0, sizeof(struct boot_loader_state));
/* Load the encryption keys into cache */
rc = boot_enc_load(BOOT_CURR_ENC(state), 0, hdr, fa_p, bs);
if (rc < 0) {
FIH_RET(fih_rc);
}
if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs)) {
FIH_RET(fih_rc);
}
}
else
{
/* Expected encrypted image! */
FIH_RET(fih_rc);
}
uint32_t src_size = 0;
rc = read_image_size(fa_p,hdr, &src_size);
if (rc != 0) {
FIH_RET(fih_rc);
}
/* TODO: This assumes every sector has an equal size, should instead use
* flash_area_get_sectors() to get the size of each sector and iterate
* over it.
*/
sect_size = sector.fs_size;
sect_count = fa_p->fa_size / sect_size;
for (sect = 0, size = 0; size < src_size && sect < sect_count; sect++) {
rc = decrypt_region_inplace(state, fa_p,hdr, size, sect_size);
if (rc != 0) {
FIH_RET(fih_rc);
}
size += sect_size;
}
fih_rc = FIH_SUCCESS;
FIH_RET(fih_rc);
}
int
boot_handle_enc_fw(const struct flash_area *flash_area)
{
int rc = -1;
struct image_header _hdr = { 0 };
FIH_DECLARE(fih_rc, FIH_FAILURE);
rc = boot_image_load_header(flash_area, &_hdr);
if (rc != 0) {
goto out;
}
if (IS_ENCRYPTED(&_hdr)) {
//encrypted, we need to decrypt in place
FIH_CALL(decrypt_image_inplace,fih_rc,flash_area,&_hdr);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
rc = -1;
goto out;
}
}
else
{
rc = 0;
}
out:
return rc;
}
#endif

View File

@@ -0,0 +1,106 @@
/*
* 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 __BOOTUTIL_SERIAL_PRIV_H__
#define __BOOTUTIL_SERIAL_PRIV_H__
#ifdef __cplusplus
extern "C" {
#endif
/*
* From shell.h
*/
#define SHELL_NLIP_PKT_START1 6
#define SHELL_NLIP_PKT_START2 9
#define SHELL_NLIP_DATA_START1 4
#define SHELL_NLIP_DATA_START2 20
/*
* From newtmgr.h
*/
#define MGMT_ERR_OK 0
#define MGMT_ERR_EUNKNOWN 1
#define MGMT_ERR_ENOMEM 2
#define MGMT_ERR_EINVAL 3
#define MGMT_ERR_ENOENT 5
#define MGMT_ERR_ENOTSUP 8
#define MGMT_ERR_EBUSY 10
#define NMGR_OP_READ 0
#define NMGR_OP_WRITE 2
#define MGMT_GROUP_ID_DEFAULT 0
#define MGMT_GROUP_ID_IMAGE 1
#define MGMT_GROUP_ID_PERUSER 64
#define NMGR_ID_ECHO 0
#define NMGR_ID_CONS_ECHO_CTRL 1
#define NMGR_ID_RESET 5
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
struct nmgr_hdr {
#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
uint8_t _res1:3;
uint8_t nh_version:2;
uint8_t nh_op:3; /* NMGR_OP_XXX */
#else
uint8_t nh_op:3; /* NMGR_OP_XXX */
uint8_t nh_version:2;
uint8_t _res1:3;
#endif
uint8_t nh_flags;
uint16_t nh_len; /* length of the payload */
uint16_t nh_group; /* NMGR_GROUP_XXX */
uint8_t nh_seq; /* sequence number */
uint8_t nh_id; /* message ID within group */
} __packed;
/*
* From imgmgr.h
*/
#define IMGMGR_NMGR_ID_STATE 0
#define IMGMGR_NMGR_ID_UPLOAD 1
#define IMGMGR_NMGR_ID_SLOT_INFO 6
void boot_serial_input(char *buf, int len);
extern const struct boot_uart_funcs *boot_uf;
/**
* @brief Selects direct image to upload according to the "image"
* parameter of the mcumgr update frame.
*
* @param[in] image_id the value of the "image" parameter of the
* mcumgr update frame to be translated.
*
* @return flash area ID for the image if defined;
* -EINVAL when flash area for given image number has not been
* defined.
*/
extern int flash_area_id_from_direct_image(int image_id);
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_SERIAL_PRIV_H__ */

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include "zcbor_bulk.h"
int zcbor_map_decode_bulk(zcbor_state_t *zsd, struct zcbor_map_decode_key_val *map,
size_t map_size, size_t *matched)
{
bool ok;
struct zcbor_map_decode_key_val *dptr = map;
if (!zcbor_map_start_decode(zsd)) {
return -EBADMSG;
}
*matched = 0;
ok = true;
do {
struct zcbor_string key;
bool found = false;
size_t map_count = 0;
ok = zcbor_tstr_decode(zsd, &key);
while (ok && map_count < map_size) {
if (dptr >= (map + map_size)) {
dptr = map;
}
if (key.len == dptr->key.len &&
memcmp(key.value, dptr->key.value, key.len) == 0) {
if (dptr->found) {
return -EADDRINUSE;
}
if (!dptr->decoder(zsd, dptr->value_ptr)) {
/* Failure to decode value matched to key
* means that either decoder has been
* incorrectly assigned or SMP payload
* is broken anyway.
*/
return -ENOMSG;
}
dptr->found = true;
found = true;
++dptr;
++(*matched);
break;
}
++dptr;
++map_count;
}
if (!found && ok) {
ok = zcbor_any_skip(zsd, NULL);
}
} while (ok);
return zcbor_map_end_decode(zsd) ? 0 : -EBADMSG;
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_ZCBOR_BULK_PRIV_
#define H_ZCBOR_BULK_PRIV_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __ZEPHYR__
#include <zcbor_common.h>
#include <zcbor_decode.h>
#else
#include "zcbor_common.h"
#include "zcbor_decode.h"
#endif
/** @cond INTERNAL_HIDDEN */
struct zcbor_map_decode_key_val {
struct zcbor_string key; /* Map key string */
zcbor_decoder_t *decoder; /* Key corresponding decoder */
void *value_ptr;
bool found;
};
/** @brief Define single key-decoder mapping
*
* The macro creates a single zcbor_map_decode_key_val type object.
*
* @param k key is "" enclosed string representing key;
* @param dec decoder function; this should be zcbor_decoder_t
* type function from zcbor or a user provided implementation
* compatible with the type.
* @param vp non-NULL pointer for result of decoding; should correspond
* to type served by decoder function for the mapping.
*/
#define ZCBOR_MAP_DECODE_KEY_DECODER(k, dec, vp) \
{ \
{ \
.value = (uint8_t *)k, \
.len = sizeof(k) - 1, \
}, \
.decoder = (zcbor_decoder_t *)dec, \
.value_ptr = vp, \
}
/** @brief Define single key-value decode mapping
*
* ZCBOR_MAP_DECODE_KEY_DECODER should be used instead of this macro as,
* this macro does not allow keys with whitespaces embeeded, which CBOR
* does allow.
*
* The macro creates a single zcbor_map_decode_key_val type object.
*
* @param k key; the @p k will be stringified so should be given
* without "";
* @param dec decoder function; this should be zcbor_decoder_t
* type function from zcbor or a user provided implementation
* compatible with the type.
* @param vp non-NULL pointer for result of decoding; should correspond
* to type served by decoder function for the mapping.
*/
#define ZCBOR_MAP_DECODE_KEY_VAL(k, dec, vp) \
ZCBOR_MAP_DECODE_KEY_DECODER(STRINGIFY(k), dec, vp)
/** @brief Decodes single level map according to a provided key-decode map.
*
* The function takes @p map of key to decoder array defined as:
*
* struct zcbor_map_decode_key_val map[] = {
* ZCBOR_MAP_DECODE_KEY_DECODER("key0", decode_fun0, val_ptr0),
* ZCBOR_MAP_DECODE_KEY_DECODER("key1", decode_fun1, val_ptr1),
* ...
* };
*
* where "key?" is string representing key; the decode_fun? is
* zcbor_decoder_t compatible function, either from zcbor or defined by
* user; val_ptr? are pointers to variables where decoder function for
* a given key will place a decoded value - they have to agree in type
* with decoder function.
*
* Failure to decode any of values will cause the function to return
* negative error, and leave the map open: map is broken anyway or key-decoder
* mapping is broken, and we can not really decode the map.
*
* Note that the function opens map by itself and will fail if map
* is already opened.
*
* @param zsd zcbor decoder state;
* @param map key-decoder mapping list;
* @param map_size size of maps, both maps have to have the same size;
* @param matched pointer to the counter of matched keys, zeroed upon
* successful map entry and incremented only for successful
* decoded fields.
* @return 0 when the whole map has been parsed, there have been
* no decoding errors, and map has been closed successfully;
* -ENOMSG when given decoder function failed to decode
* value;
* -EADDRINUSE when key appears twice within map, map is then
* parsed up to they key that has appeared twice;
* -EBADMSG when failed to close map.
*/
int zcbor_map_decode_bulk(zcbor_state_t *zsd, struct zcbor_map_decode_key_val *map,
size_t map_size, size_t *matched);
/** @endcond */
#ifdef __cplusplus
}
#endif
#endif /* H_ZCBOR_BULK_PRIV_ */

View File

@@ -0,0 +1,96 @@
# 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.
#
syscfg.defs:
BOOT_SERIAL_DETECT_PIN:
description: >
Start the serial boot loader if this pin is asserted at boot time.
value: '-1'
restrictions:
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
(BOOT_SERIAL_NVREG_INDEX != -1)'
BOOT_SERIAL_DETECT_PIN_CFG:
description: >
GPIO configuration for the serial boot loader detect pin.
value: 'HAL_GPIO_PULL_UP'
BOOT_SERIAL_DETECT_PIN_VAL:
description: >
The value the detect pin must be set to for the serial boot loader
to start.
value: 0
BOOT_SERIAL_DETECT_TIMEOUT:
description: >
The duration, in milliseconds, to listen on the UART for the
management string (BOOT_SERIAL_DETECT_STRING). If the management
string is detected during this period, the serial boot loader is
started. If the period expires without the management string being
received, the boot loader runs in the normal (non-serial) mode.
Specify 0 to disable listening on the UART for the management
string.
value: 0
restrictions:
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
(BOOT_SERIAL_NVREG_INDEX != -1)'
BOOT_SERIAL_DETECT_STRING:
description: >
The string to listen for on the UART. If this management string is
detected during the timeout period, the serial boot loader is
started. If the period expires without this string being received,
the boot loader runs in the normal (non-serial) mode. This setting
has no effect if BOOT_SERIAL_DETECT_TIMEOUT is set to 0.
value: '"nmgr"'
BOOT_SERIAL_REPORT_PIN:
description: >
The GPIO to toggle while the serial boot loader is running. Set to
-1 to disable reporting.
value: 'LED_BLINK_PIN'
BOOT_SERIAL_REPORT_FREQ:
description: >
The toggle rate, in Hz, of the serial boot loader report pin.
value: 4
BOOT_SERIAL_NVREG_MAGIC:
description: >
Magic number, to be saved in a retained (reset-surviving) register.
If the value in the register matches, the serial bootloader will
load. Value must not be 0.
value: 0xB7
restrictions:
- '(BOOT_SERIAL_NVREG_MAGIC != 0)'
BOOT_SERIAL_NVREG_INDEX:
description: >
Index of retained register to use (using hal_nvreg_read) for reading
magic value.
value: -1
restrictions:
- '(BOOT_SERIAL_DETECT_PIN != -1) ||
(BOOT_SERIAL_DETECT_TIMEOUT != 0) ||
(BOOT_SERIAL_NVREG_INDEX != -1)'
BOOT_SERIAL_MGMT_ECHO:
description: If enabled, support for the mcumgr echo command is being added.
value: 0

View File

@@ -0,0 +1,35 @@
# 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.
#
pkg.name: boot/boot_serial/test
pkg.type: unittest
pkg.description: "Boot serial unit tests."
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@mcuboot/boot/boot_serial"
- "@mcuboot/boot/bootutil"
- "@apache-mynewt-core/sys/log/stub"
- "@apache-mynewt-core/test/testutil"
pkg.deps.SELFTEST:
- "@apache-mynewt-core/sys/console/stub"
pkg.cflags:
- '-DMCUBOOT_MYNEWT=1'

View File

@@ -0,0 +1,85 @@
/*
* 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 <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "syscfg/syscfg.h"
#include "sysflash/sysflash.h"
#include "os/endian.h"
#include "base64/base64.h"
#include "crc/crc16.h"
#include "testutil/testutil.h"
#include "hal/hal_flash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "boot_serial/boot_serial.h"
#include "boot_serial_priv.h"
TEST_CASE_DECL(boot_serial_setup)
TEST_CASE_DECL(boot_serial_empty_msg)
TEST_CASE_DECL(boot_serial_empty_img_msg)
TEST_CASE_DECL(boot_serial_img_msg)
TEST_CASE_DECL(boot_serial_upload_bigger_image)
static void
test_uart_write(const char *str, int len)
{
}
static const struct boot_uart_funcs test_uart = {
.write = test_uart_write
};
void
tx_msg(void *src, int len)
{
boot_serial_input(src, len);
}
TEST_SUITE(boot_serial_suite)
{
boot_serial_setup();
boot_serial_empty_msg();
boot_serial_empty_img_msg();
boot_serial_img_msg();
boot_serial_upload_bigger_image();
}
int
boot_serial_test(void)
{
boot_uf = &test_uart;
boot_serial_suite();
return tu_any_failed;
}
#if MYNEWT_VAL(SELFTEST)
int
main(void)
{
sysinit();
boot_serial_test();
return tu_any_failed;
}
#endif

View File

@@ -0,0 +1,50 @@
/*
* 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 _BOOT_TEST_H
#define _BOOT_TEST_H
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "syscfg/syscfg.h"
#include "sysflash/sysflash.h"
#include "os/endian.h"
#include "base64/base64.h"
#include "crc/crc16.h"
#include "testutil/testutil.h"
#include "hal/hal_flash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "bootutil/bootutil.h"
#include "boot_serial_priv.h"
#ifdef __cplusplus
extern "C" {
#endif
void tx_msg(void *src, int len);
#ifdef __cplusplus
}
#endif
#endif /* _BOOT_TEST_H */

View File

@@ -0,0 +1,35 @@
/*
* 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 "boot_test.h"
TEST_CASE(boot_serial_empty_img_msg)
{
char buf[sizeof(struct nmgr_hdr) + 32];
struct nmgr_hdr *hdr;
hdr = (struct nmgr_hdr *)buf;
memset(hdr, 0, sizeof(*hdr));
hdr->nh_op = NMGR_OP_WRITE;
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
hdr->nh_len = htons(2);
strcpy((char *)(hdr + 1), "{}");
tx_msg(buf, sizeof(*hdr) + 2);
}

View File

@@ -0,0 +1,37 @@
/*
* 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 "boot_test.h"
TEST_CASE(boot_serial_empty_msg)
{
char buf[4];
struct nmgr_hdr hdr;
tx_msg(buf, 0);
strcpy(buf, "--");
tx_msg(buf, 2);
memset(&hdr, 0, sizeof(hdr));
tx_msg(&hdr, sizeof(hdr));
hdr.nh_op = NMGR_OP_WRITE;
tx_msg(&hdr, sizeof(hdr));
}

View File

@@ -0,0 +1,70 @@
/*
* 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 "boot_test.h"
TEST_CASE(boot_serial_img_msg)
{
char img[16];
char enc_img[BASE64_ENCODE_SIZE(sizeof(img)) + 1];
char buf[sizeof(struct nmgr_hdr) + sizeof(enc_img) + 32];
int len;
int rc;
struct nmgr_hdr *hdr;
const struct flash_area *fap;
/* 00000000 a3 64 64 61 74 61 58 10 |.ddataX.|
* 00000008 a5 a5 a5 a5 a5 a5 a5 a5 |........|
* 00000010 a5 a5 a5 a5 a5 a5 a5 a5 |........|
* 00000018 63 6c 65 6e 1a 00 01 14 |clen....|
* 00000020 e8 63 6f 66 66 00 |.coff.|
*/
static const uint8_t payload[] = {
0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x10,
/* 16 bytes of image data starts here. */
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
};
memset(img, 0xa5, sizeof(img));
hdr = (struct nmgr_hdr *)buf;
memset(hdr, 0, sizeof(*hdr));
hdr->nh_op = NMGR_OP_WRITE;
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
memcpy(hdr + 1, payload, sizeof payload);
hdr->nh_len = htons(sizeof payload);
len = sizeof(*hdr) + sizeof payload;
tx_msg(buf, len);
/*
* Validate contents inside the primary slot
*/
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
assert(rc == 0);
rc = flash_area_read(fap, 0, enc_img, sizeof(img));
assert(rc == 0);
assert(!memcmp(enc_img, img, sizeof(img)));
}

View File

@@ -0,0 +1,24 @@
/*
* 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 "boot_test.h"
TEST_CASE(boot_serial_setup)
{
}

View File

@@ -0,0 +1,117 @@
/*
* 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 <flash_map_backend/flash_map_backend.h>
#include "boot_test.h"
#include "zcbor_common.h"
TEST_CASE(boot_serial_upload_bigger_image)
{
char img[256];
char enc_img[64];
char buf[sizeof(struct nmgr_hdr) + 128];
int len;
int off;
int rc;
struct nmgr_hdr *hdr;
const struct flash_area *fap;
int i;
const int payload_off = sizeof *hdr;
const int img_data_off = payload_off + 8;
/* 00000000 a3 64 64 61 74 61 58 20 |.ddataX.|
* 00000008 00 00 00 00 00 00 00 00 |........|
* 00000010 00 00 00 00 00 00 00 00 |........|
* 00000018 00 00 00 00 00 00 00 00 |........|
* 00000020 00 00 00 00 00 00 00 00 |........|
* 00000028 63 6c 65 6e 1a 00 01 14 |clen....|
* 00000030 e8 63 6f 66 66 00 |.coff.|
*/
static const uint8_t payload_first[] = {
0xa3, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
/* 32 bytes of image data starts here. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x63, 0x6c, 0x65, 0x6e, 0x1a, 0x00, 0x01, 0x14,
0xe8, 0x63, 0x6f, 0x66, 0x66, 0x00,
};
/* 00000000 a3 64 64 61 74 61 58 20 |.ddataX.|
* 00000008 00 00 00 00 00 00 00 00 |........|
* 00000010 00 00 00 00 00 00 00 00 |........|
* 00000018 00 00 00 00 00 00 00 00 |........|
* 00000020 00 00 00 00 00 00 00 00 |........|
* 00000028 63 6f 66 66 00 00 |coff..|
*/
static const uint8_t payload_next[] = {
0xa2, 0x64, 0x64, 0x61, 0x74, 0x61, 0x58, 0x20,
/* 32 bytes of image data starts here. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x63, 0x6f, 0x66, 0x66,
/* 2 bytes of offset value starts here. */
0x00, 0x00
};
for (i = 0; i < sizeof(img); i++) {
img[i] = i;
}
for (off = 0; off < sizeof(img); off += 32) {
hdr = (struct nmgr_hdr *)buf;
memset(hdr, 0, sizeof(*hdr));
hdr->nh_op = NMGR_OP_WRITE;
hdr->nh_group = htons(MGMT_GROUP_ID_IMAGE);
hdr->nh_id = IMGMGR_NMGR_ID_UPLOAD;
if (off) {
memcpy(buf + payload_off, payload_next, sizeof payload_next);
len = sizeof payload_next;
buf[payload_off + len - 2] = ZCBOR_VALUE_IS_1_BYTE;
buf[payload_off + len - 1] = off;
} else {
memcpy(buf + payload_off, payload_first, sizeof payload_first);
len = sizeof payload_first;
}
memcpy(buf + img_data_off, img + off, 32);
hdr->nh_len = htons(len);
len = sizeof(*hdr) + len;
tx_msg(buf, len);
}
/*
* Validate contents inside the primary slot
*/
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &fap);
assert(rc == 0);
for (off = 0; off < sizeof(img); off += sizeof(enc_img)) {
rc = flash_area_read(fap, off, enc_img, sizeof(enc_img));
assert(rc == 0);
assert(!memcmp(enc_img, &img[off], sizeof(enc_img)));
}
}

View File

@@ -0,0 +1,23 @@
# 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.
#
# Package: boot/boot_serial/test
syscfg.vals:
# This is here to work around the $notnull syscfg restriction.
BOOT_SERIAL_DETECT_PIN: 0

View File

@@ -0,0 +1,35 @@
#------------------------------------------------------------------------------
# Copyright (c) 2020-2023, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
#------------------------------------------------------------------------------
add_library(bootutil STATIC)
target_include_directories(bootutil
PUBLIC
include
PRIVATE
src
)
target_sources(bootutil
PRIVATE
src/boot_record.c
src/bootutil_misc.c
src/bootutil_public.c
src/caps.c
src/encrypted.c
src/fault_injection_hardening.c
src/fault_injection_hardening_delay_rng_mbedtls.c
src/image_ecdsa.c
src/image_ed25519.c
src/image_rsa.c
src/image_validate.c
src/loader.c
src/swap_misc.c
src/swap_move.c
src/swap_scratch.c
src/tlv.c
)

View File

@@ -0,0 +1,68 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 Linaro Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_BENCH_H__
#define H_BOOTUTIL_BENCH_H__
#include "ignore.h"
#ifdef MCUBOOT_USE_BENCH
/* The platform-specific benchmark code should define a
* `bench_state_t` type that holds the information needed for the
* benchmark. This is generally something small, such as an integer
* holding the state. This should also define plat_bench_start and
* plat_bench_end, which likely have to be macros so that log messages
* come from the right place in the code. */
#include <platform-bench.h>
/*
* These are simple barrier-type benchmarks. If a platform has
* benchmarks that are enabled, calling `boot_bench_start()` before a
* block of code and `boot_bench_stop()` after that block of code will
* present this information in some manner (usually through logging).
* The details of what is measured and how it is printed are specific
* to the platform and the implementation. A pointer to the
* platform-specific state should be passed in.
*/
#define boot_bench_start(_state) do { \
plat_bench_start(_state); \
} while (0)
#define boot_bench_stop(_state) do { \
plat_bench_stop(_state); \
} while (0)
#else /* not MCUBOOT_USE_BENCH */
/* The type needs to take space. As long as it remains unused, the C
* compiler should eliminate this value entirely. */
typedef int bench_state_t;
/* Without benchmarking enabled, these are just empty. */
#define boot_bench_start(_state) do { \
IGNORE(_state); \
} while(0)
#define boot_bench_stop(_state) do { \
IGNORE(_state); \
} while(0)
#endif /* not MCUBOOT_USE_BENCH */
#endif /* not H_BOOTUTIL_BENCH_H__ */

View File

@@ -0,0 +1,181 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file
* @brief Hooks definition implementation API
*
* This file contains API interface definition for hooks which can be
* implemented to overide or to amend some of MCUboot's native routines.
*/
#ifndef H_BOOTUTIL_HOOKS
#define H_BOOTUTIL_HOOKS
#ifdef MCUBOOT_IMAGE_ACCESS_HOOKS
#define BOOT_HOOK_CALL(f, ret_default, ...) f(__VA_ARGS__)
#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
do { \
FIH_CALL(f, fih_rc, __VA_ARGS__); \
} while(0);
#else
#define BOOT_HOOK_CALL(f, ret_default, ...) ret_default
#define BOOT_HOOK_CALL_FIH(f, fih_ret_default, fih_rc, ...) \
do { \
fih_rc = fih_ret_default; \
} while(0);
#endif
/** Hook for provide image header data.
*
* This Hook may be used to overide image header read implementation or doing
* a custom action before.
*
* @param img_index the index of the image pair
* @param slot slot number
* @param img_head image header structure to be populated
*
* @retval 0: header was read/populated, skip direct header data read
* BOOT_HOOK_REGULAR: follow the normal execution path,
* otherwise an error-code value.
*/
int boot_read_image_header_hook(int img_index, int slot,
struct image_header *img_head);
/** Hook for Validate image hash/signature
*
* This Hook may be used to overide image validation procedure or doing
* a custom action before.
*
* @param img_index the index of the image pair
* @param slot slot number
*
* @retval FIH_SUCCESS: image is valid, skip direct validation
* FIH_FAILURE: image is invalid, skip direct validation
* FIH_BOOT_HOOK_REGULAR: follow the normal execution path.
*/
fih_ret boot_image_check_hook(int img_index, int slot);
/** Hook for implement image update
*
* This hook is for for implementing an alternative mechanism of image update or
* doing a custom action before.
*
* @param img_index the index of the image pair
* @param img_head the image header of the secondary image
* @param area the flash area of the secondary image.
*
* @retval 0: update was done, skip performing the update
* BOOT_HOOK_REGULAR: follow the normal execution path,
* otherwise an error-code value.
*/
int boot_perform_update_hook(int img_index, struct image_header *img_head,
const struct flash_area *area);
/** Hook for implement image's post copying action
*
* This hook is for implement action which might be done right after image was
* copied to the primary slot. This hook is called in MCUBOOT_OVERWRITE_ONLY
* mode only.
*
* @param img_index the index of the image pair
* @param area the flash area of the primary image.
* @param size size of copied image.
*
* @retval 0: success, mcuboot will follow normal code execution flow after
* execution of this call.
* non-zero: an error, mcuboot will return from
* boot_copy_image() with error.
* Update will be undone so might be resume on the next boot.
*/
int boot_copy_region_post_hook(int img_index, const struct flash_area *area,
size_t size);
/** Hook for implement image's post recovery upload action
*
* This hook is for implement action which might be done right after image was
* copied to the primary slot. This hook is called in serial recovery upload
* operation.
*
* @param img_index the index of the image pair
* @param area the flash area of the primary image.
* @param size size of copied image.
*
* @retval 0: success, mcuboot will follow normal code execution flow after
* execution of this call.
* non-zero: an error, will be transferred as part of comand response
* as "rc" entry.
*/
int boot_serial_uploaded_hook(int img_index, const struct flash_area *area,
size_t size);
/** Hook for implement the image's slot installation status fetch operation for
* the MGMT custom command.
*
* The image's slot installation status is custom property. It's detailed
* definition depends on user implementation. It is only defined that the status
* will be set to 0 if this hook not provides another value.
*
* @param img_index the index of the image pair
* @param slot slot number
* @param img_install_stat the image installation status to be populated
*
* @retval 0: the installaton status was fetched successfully,
* BOOT_HOOK_REGULAR: follow the normal execution path, status will be
* set to 0
* otherwise an error-code value. Error-code is ignored, but it is up to
* the implementation to reflect this error in img_install_stat.
*/
int boot_img_install_stat_hook(int image_index, int slot,
int *img_install_stat);
/** Hook will be invoked when boot_serial requests device reset.
* The hook may be used to prevent device reset.
*
* @param force set to true when request tries to force reset.
*
* @retval 0 when reset should be performed;
* BOOT_RESET_REQUEST_HOOK_BUSY when some processing is still in
* progress;
* BOOT_RESET_REQUEST_HOOK_TIMEOUT internal process timed out;
* BOOT_RESET_REQUEST_HOOK_CHECK_FAILED internal code failed to
* obtian status;
* BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR unspecified internal
* error while checking status.
*/
int boot_reset_request_hook(bool force);
#define BOOT_RESET_REQUEST_HOOK_BUSY 1
#define BOOT_RESET_REQUEST_HOOK_TIMEOUT 2
#define BOOT_RESET_REQUEST_HOOK_CHECK_FAILED 3
#define BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR 4
#endif /*H_BOOTUTIL_HOOKS*/

View File

@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file
* @brief Hooks definition implementation API
*
* This file contains API interface definition for hooks which can be
* implemented for overide some of MCUboot's native routines.
*/
#ifndef H_BOOTUTIL_PUBLIC_HOOKS
#define H_BOOTUTIL_PUBLIC_HOOKS
#include "bootutil/boot_hooks.h"
/** Hook for provide primary image swap state.
*
* @param img_index the index of the image pair
* @param state image swap state structure to be populated
*
* @retval 0: header was read/populated
* FIH_FAILURE: image is invalid,
* BOOT_HOOK_REGULAR if hook not implemented for the image-slot,
* othervise an error-code value.
*/
int boot_read_swap_state_primary_slot_hook(int image_index,
struct boot_swap_state *state);
#endif /*H_BOOTUTIL_PUBLIC_HOOKS*/

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2021 Arm Limited
*
* 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.
*/
#ifndef __BOOT_RECORD_H__
#define __BOOT_RECORD_H__
#include <stdint.h>
#include <stddef.h>
#include "bootutil/image.h"
#include "bootutil/bootutil.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Error codes for using the shared memory area. */
enum shared_memory_status {
SHARED_MEMORY_OK = 0,
SHARED_MEMORY_OVERFLOW,
SHARED_MEMORY_OVERWRITE,
SHARED_MEMORY_GEN_ERROR,
SHARED_MEMORY_WRITE_ERROR,
SHARED_MEMORY_READ_ERROR,
};
/**
* @brief Add a data item to the shared data area between bootloader and
* runtime SW
*
* @param[in] major_type TLV major type, identify consumer
* @param[in] minor_type TLV minor type, identify TLV type
* @param[in] size length of added data
* @param[in] data pointer to data
*
* @return 0 on success; nonzero on failure.
*/
int boot_add_data_to_shared_area(uint8_t major_type,
uint16_t minor_type,
size_t size,
const uint8_t *data);
/**
* Add an image's all boot status information to the shared memory area
* between the bootloader and runtime SW.
*
* @param[in] sw_module Identifier of the SW component.
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
*
* @return 0 on success; nonzero on failure.
*/
int boot_save_boot_status(uint8_t sw_module,
const struct image_header *hdr,
const struct flash_area *fap);
/**
* Add application specific data to the shared memory area between the
* bootloader and runtime SW.
*
* @param[in] hdr Pointer to the image header stored in RAM.
* @param[in] fap Pointer to the flash area where image is stored.
* @param[in] slot The currently active slot being booted.
* @param[in] max_app_sizes The maximum sizes of images that can be loaded.
*
* @return 0 on success; nonzero on failure.
*/
int boot_save_shared_data(const struct image_header *hdr,
const struct flash_area *fap,
const uint8_t active_slot,
const struct image_max_size *max_app_sizes);
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_RECORD_H__ */

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2018-2020 Arm Limited
* Copyright (c) 2020 Linaro Limited
*
* 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.
*/
#ifndef __BOOT_STATUS_H__
#define __BOOT_STATUS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The shared data between boot loader and runtime SW is TLV encoded. The
* shared data is stored in a well known location in memory and this is a
* contract between boot loader and runtime SW.
*
* The structure of shared data must be the following:
* - At the beginning there must be a header: struct shared_data_tlv_header
* This contains a magic number and a size field which covers the entire
* size of the shared data area including this header.
* - After the header there come the entries which are composed from an entry
* header structure: struct shared_data_tlv_entry and the data. In the entry
* header is a type field (tly_type) which identify the consumer of the
* entry in the runtime SW and specify the subtype of that data item. There
* is a size field (tlv_len) which covers the size of the the data. After
* this structure comes the actual data.
*
* - Arbitrary number and size of data entry can be in the shared memory area.
*
* This table gives of overview about the tlv_type field in the entry header.
* The tlv_type always composed from a major and minor number. Major number
* identifies the addressee in runtime SW, who should process the data entry.
* Minor number used to encode more info about the data entry. The actual
* definition of minor number could change per major number.
*
* In case of boot status data, which can be processed by an attestation
* service the minor number is split further to two part: sw_module and claim.
* The sw_module identifies the SW component in the system which the data item
* belongs to and the claim part identifies the exact type of the data.
*
* |---------------------------------------|
* | tlv_type (16) |
* |---------------------------------------|
* | tlv_major(4)| tlv_minor(12) |
* |---------------------------------------|
* | MAJOR_IAS | sw_module(6) | claim(6) |
* |---------------------------------------|
*/
/* General macros to handle TLV type */
#define MAJOR_MASK 0xF /* 4 bit */
#define MAJOR_POS 12 /* 12 bit */
#define MINOR_MASK 0xFFF /* 12 bit */
#define SET_TLV_TYPE(major, minor) \
(((uint16_t)((major) & MAJOR_MASK) << MAJOR_POS) \
| ((minor) & MINOR_MASK))
#define GET_MAJOR(tlv_type) ((uint16_t)(tlv_type) >> MAJOR_POS)
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
/* Magic value which marks the beginning of shared data area in memory */
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
/* Initial attestation specific macros */
/**
* Major numbers (4 bit) to identify the
* consumer of shared data in runtime SW.
*/
#define TLV_MAJOR_IAS 0x1
#define TLV_MAJOR_BLINFO 0x2
/* Initial attestation: Claim per SW components / SW modules */
/* Bits: 0-2 */
#define SW_VERSION 0x00
#define SW_SIGNER_ID 0x01
/* Reserved 0x02 */
#define SW_TYPE 0x03
/* Bits: 3-5 */
#define SW_MEASURE_VALUE 0x08
#define SW_MEASURE_TYPE 0x09
#define SW_BOOT_RECORD 0x3F
#define MODULE_POS 6 /* 6 bit */
#define CLAIM_MASK 0x3F /* 6 bit */
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
#define GET_IAS_MODULE(tlv_type) ((uint16_t)GET_MINOR(tlv_type) >> MODULE_POS)
#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
#define SET_IAS_MINOR(sw_module, claim) \
(((uint16_t)(sw_module) << MODULE_POS) | (claim))
/* Bootloader information */
#define BLINFO_MODE 0x00
#define BLINFO_SIGNATURE_TYPE 0x01
#define BLINFO_RECOVERY 0x02
#define BLINFO_RUNNING_SLOT 0x03
#define BLINFO_BOOTLOADER_VERSION 0x04
#define BLINFO_MAX_APPLICATION_SIZE 0x05 /* Same as BLINFO_MAX_APPLICATION_SIZE_IMAGE_0, legacy name */
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_0 BLINFO_MAX_APPLICATION_SIZE
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_1 0x06
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_2 0x07
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_3 0x08
#define BLINFO_MAX_APPLICATION_SIZE_IMAGE_4 0x09
enum mcuboot_mode {
MCUBOOT_MODE_SINGLE_SLOT,
MCUBOOT_MODE_SWAP_USING_SCRATCH,
MCUBOOT_MODE_UPGRADE_ONLY,
MCUBOOT_MODE_SWAP_USING_MOVE,
MCUBOOT_MODE_DIRECT_XIP,
MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT,
MCUBOOT_MODE_RAM_LOAD,
MCUBOOT_MODE_FIRMWARE_LOADER
};
enum mcuboot_signature_type {
MCUBOOT_SIGNATURE_TYPE_NONE,
MCUBOOT_SIGNATURE_TYPE_RSA,
MCUBOOT_SIGNATURE_TYPE_ECDSA_P256,
MCUBOOT_SIGNATURE_TYPE_ED25519
};
enum mcuboot_recovery_mode {
MCUBOOT_RECOVERY_MODE_NONE,
MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY,
MCUBOOT_RECOVERY_MODE_DFU,
};
/**
* Shared data TLV header. All fields in little endian.
*
* -----------------------------------
* | tlv_magic(16) | tlv_tot_len(16) |
* -----------------------------------
*/
struct shared_data_tlv_header {
uint16_t tlv_magic;
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
};
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
/**
* Shared data TLV entry header format. All fields in little endian.
*
* -------------------------------
* | tlv_type(16) | tlv_len(16) |
* -------------------------------
* | Raw data |
* -------------------------------
*/
struct shared_data_tlv_entry {
uint16_t tlv_type;
uint16_t tlv_len; /* TLV data length (not including this header). */
};
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
/* Structure to store the boot data for the runtime SW. */
struct shared_boot_data {
struct shared_data_tlv_header header;
uint8_t data[];
};
#ifdef __cplusplus
}
#endif
#endif /* __BOOT_STATUS_H__ */

View File

@@ -0,0 +1,104 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BOOTUTIL_
#define H_BOOTUTIL_
#include <inttypes.h>
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/bootutil_public.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MCUBOOT_IMAGE_NUMBER
#define BOOT_IMAGE_NUMBER MCUBOOT_IMAGE_NUMBER
#else
#define BOOT_IMAGE_NUMBER 1
#endif
_Static_assert(BOOT_IMAGE_NUMBER > 0, "Invalid value for BOOT_IMAGE_NUMBER");
struct image_header;
/**
* A response object provided by the boot loader code; indicates where to jump
* to execute the main image.
*/
struct boot_rsp {
/** A pointer to the header of the image to be executed. */
const struct image_header *br_hdr;
/**
* The flash offset of the image to execute. Indicates the position of
* the image header within its flash device.
*/
uint8_t br_flash_dev_id;
uint32_t br_image_off;
};
/* This is not actually used by mcuboot's code but can be used by apps
* when attempting to read/write a trailer.
*/
struct image_trailer {
uint8_t swap_type;
uint8_t pad1[BOOT_MAX_ALIGN - 1];
uint8_t copy_done;
uint8_t pad2[BOOT_MAX_ALIGN - 1];
uint8_t image_ok;
uint8_t pad3[BOOT_MAX_ALIGN - 1];
#if BOOT_MAX_ALIGN > BOOT_MAGIC_SZ
uint8_t pad4[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ];
#endif
uint8_t magic[BOOT_MAGIC_SZ];
};
struct image_max_size {
bool calculated;
uint32_t max_size;
};
/* you must have pre-allocated all the entries within this structure */
fih_ret boot_go(struct boot_rsp *rsp);
fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);
struct boot_loader_state;
void boot_state_clear(struct boot_loader_state *state);
fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp);
const struct image_max_size *boot_get_max_app_size(void);
#define SPLIT_GO_OK (0)
#define SPLIT_GO_NON_MATCHING (-1)
#define SPLIT_GO_ERR (-2)
fih_ret split_go(int loader_slot, int split_slot, void **entry);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,59 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Linaro Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_LOG_H_
#define H_BOOTUTIL_LOG_H_
#include "ignore.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <mcuboot_config/mcuboot_config.h>
#ifdef MCUBOOT_HAVE_LOGGING
#include <mcuboot_config/mcuboot_logging.h>
#define BOOT_LOG_ERR(...) MCUBOOT_LOG_ERR(__VA_ARGS__)
#define BOOT_LOG_WRN(...) MCUBOOT_LOG_WRN(__VA_ARGS__)
#define BOOT_LOG_INF(...) MCUBOOT_LOG_INF(__VA_ARGS__)
#define BOOT_LOG_DBG(...) MCUBOOT_LOG_DBG(__VA_ARGS__)
#define BOOT_LOG_SIM(...) MCUBOOT_LOG_SIM(__VA_ARGS__)
#define BOOT_LOG_MODULE_DECLARE(module) MCUBOOT_LOG_MODULE_DECLARE(module)
#define BOOT_LOG_MODULE_REGISTER(module) MCUBOOT_LOG_MODULE_REGISTER(module)
#else
#define BOOT_LOG_ERR(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_WRN(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_INF(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_DBG(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_SIM(...) IGNORE(__VA_ARGS__)
#define BOOT_LOG_MODULE_DECLARE(module)
#define BOOT_LOG_MODULE_REGISTER(module)
#endif /* MCUBOOT_HAVE_LOGGING */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,316 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
* Copyright (c) 2020-2021 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file
* @brief Public MCUBoot interface API
*
* This file contains API which can be combined with the application in order
* to interact with the MCUBoot bootloader. This API are shared code-base betwen
* MCUBoot and the application which controls DFU process.
*/
#ifndef H_BOOTUTIL_PUBLIC
#define H_BOOTUTIL_PUBLIC
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <flash_map_backend/flash_map_backend.h>
#include <mcuboot_config/mcuboot_config.h>
#include <bootutil/image.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ALIGN_UP
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#endif
#ifndef ALIGN_DOWN
#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
#endif
/** Attempt to boot the contents of the primary slot. */
#define BOOT_SWAP_TYPE_NONE 1
/**
* Swap to the secondary slot.
* Absent a confirm command, revert back on next boot.
*/
#define BOOT_SWAP_TYPE_TEST 2
/**
* Swap to the secondary slot,
* and permanently switch to booting its contents.
*/
#define BOOT_SWAP_TYPE_PERM 3
/** Swap back to alternate slot. A confirm changes this state to NONE. */
#define BOOT_SWAP_TYPE_REVERT 4
/** Swap failed because image to be run is not valid */
#define BOOT_SWAP_TYPE_FAIL 5
/** Swapping encountered an unrecoverable error */
#define BOOT_SWAP_TYPE_PANIC 0xff
#define BOOT_MAGIC_SZ 16
#ifdef MCUBOOT_BOOT_MAX_ALIGN
#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
_Static_assert(MCUBOOT_BOOT_MAX_ALIGN >= 8 && MCUBOOT_BOOT_MAX_ALIGN <= 32,
"Unsupported value for MCUBOOT_BOOT_MAX_ALIGN for SWAP upgrade modes");
#endif
#define BOOT_MAX_ALIGN MCUBOOT_BOOT_MAX_ALIGN
#define BOOT_MAGIC_ALIGN_SIZE ALIGN_UP(BOOT_MAGIC_SZ, BOOT_MAX_ALIGN)
#else
#define BOOT_MAX_ALIGN 8
#define BOOT_MAGIC_ALIGN_SIZE BOOT_MAGIC_SZ
#endif
#define BOOT_MAGIC_GOOD 1
#define BOOT_MAGIC_BAD 2
#define BOOT_MAGIC_UNSET 3
#define BOOT_MAGIC_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_MAGIC_NOTGOOD 5 /* NOTE: control only, not dependent on sector */
/*
* NOTE: leave BOOT_FLAG_SET equal to one, this is written to flash!
*/
#define BOOT_FLAG_SET 1
#define BOOT_FLAG_BAD 2
#define BOOT_FLAG_UNSET 3
#define BOOT_FLAG_ANY 4 /* NOTE: control only, not dependent on sector */
#define BOOT_EFLASH 1
#define BOOT_EFILE 2
#define BOOT_EBADIMAGE 3
#define BOOT_EBADVECT 4
#define BOOT_EBADSTATUS 5
#define BOOT_ENOMEM 6
#define BOOT_EBADARGS 7
#define BOOT_EBADVERSION 8
#define BOOT_EFLASH_SEC 9
#define BOOT_HOOK_REGULAR 1
/*
* Extract the swap type and image number from image trailers's swap_info
* filed.
*/
#define BOOT_GET_SWAP_TYPE(swap_info) ((swap_info) & 0x0F)
#define BOOT_GET_IMAGE_NUM(swap_info) ((swap_info) >> 4)
/* Construct the swap_info field from swap type and image number */
#define BOOT_SET_SWAP_INFO(swap_info, image, type) { \
assert((image) < 0xF); \
assert((type) < 0xF); \
(swap_info) = (image) << 4 \
| (type); \
}
#ifdef MCUBOOT_HAVE_ASSERT_H
#include "mcuboot_config/mcuboot_assert.h"
#else
#include <assert.h>
#ifndef ASSERT
#define ASSERT assert
#endif
#endif
struct boot_swap_state {
uint8_t magic; /* One of the BOOT_MAGIC_[...] values. */
uint8_t swap_type; /* One of the BOOT_SWAP_TYPE_[...] values. */
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_num; /* Boot status belongs to this image */
};
/**
* @brief Determines the action, if any, that mcuboot will take on a image pair.
*
* @param image_index Image pair index.
*
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
* fail.
*/
int boot_swap_type_multi(int image_index);
/**
* @brief Determines the action, if any, that mcuboot will take.
*
* Works the same as a boot_swap_type_multi(0) call;
*
* @return a BOOT_SWAP_TYPE_[...] constant on success, negative errno code on
* fail.
*/
int boot_swap_type(void);
/**
* Marks the image with the given index in the secondary slot as pending. On the
* next reboot, the system will perform a one-time boot of the the secondary
* slot image.
*
* @param image_index Image pair index.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_pending_multi(int image_index, int permanent);
/**
* Marks the image with index 0 in the secondary slot as pending. On the next
* reboot, the system will perform a one-time boot of the the secondary slot
* image. Note that this API is kept for compatibility. The
* boot_set_pending_multi() API is recommended.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_pending(int permanent);
/**
* Marks the image with the given index in the primary slot as confirmed. The
* system will continue booting into the image in the primary slot until told to
* boot from a different slot.
*
* @param image_index Image pair index.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_confirmed_multi(int image_index);
/**
* Marks the image with index 0 in the primary slot as confirmed. The system
* will continue booting into the image in the primary slot until told to boot
* from a different slot. Note that this API is kept for compatibility. The
* boot_set_confirmed_multi() API is recommended.
*
* @return 0 on success; nonzero on failure.
*/
int boot_set_confirmed(void);
/**
* @brief Get offset of the swap info field in the image trailer.
*
* @param fap Flash are for which offset is determined.
*
* @retval offset of the swap info field.
*/
uint32_t boot_swap_info_off(const struct flash_area *fap);
/**
* @brief Get value of image-ok flag of the image.
*
* If called from chin-loaded image the image-ok flag value can be used to check
* whether application itself is already confirmed.
*
* @param fap Flash area of the image.
* @param image_ok[out] image-ok value.
*
* @return 0 on success; nonzero on failure.
*/
int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok);
/**
* @brief Read the image swap state
*
* @param flash_area_id id of flash partition from which state will be read;
* @param state pointer to structure for storing swap state.
*
* @return 0 on success; non-zero error code on failure;
*/
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state);
/**
* @brief Read the image swap state
*
* @param fa pointer to flash_area object;
* @param state pointer to structure for storing swap state.
*
* @return 0 on success; non-zero error code on failure.
*/
int
boot_read_swap_state(const struct flash_area *fa,
struct boot_swap_state *state);
/**
* @brief Set next image application slot by flash area pointer
*
* @param fa pointer to flash_area representing image to set for next boot;
* @param active should be true if @fa points to currently running image
* slot, false otherwise;
* @param confirm confirms image; when @p active is true, this is considered
* true, regardless of passed value.
*
* It is users responsibility to identify whether @p fa provided as parameter
* is currently running/active image and provide proper value to @p active.
* Failing to do so may render device non-upgradeable.
*
* Note that in multi-image setup running/active application is the one
* that is currently being executed by any MCU core, from the pair of
* slots dedicated to that MCU core. As confirming application currently
* running on a given slot should be, preferably, done after functional
* tests prove application to function correctly, it may not be a good idea
* to cross-confirm running images.
* An application should only confirm slots designated to MCU core it is
* running on.
*
* @return 0 on success; non-zero error code on failure.
*/
int
boot_set_next(const struct flash_area *fa, bool active, bool confirm);
/**
* Attempts to load image header from flash; verifies flash header fields.
*
* @param[in] fa_p flash area pointer
* @param[out] hdr buffer for image header
*
* @return 0 on success, error code otherwise
*/
int
boot_image_load_header(const struct flash_area *fa_p,
struct image_header *hdr);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,35 @@
/*
* 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_BOOTUTIL_TEST_
#define H_BOOTUTIL_TEST_
#ifdef __cplusplus
extern "C" {
#endif
int boot_test_all(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2021-2023 Arm Limited
*
* 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.
*/
#ifndef H_BOOTUTIL_CAPS_H_
#define H_BOOTUTIL_CAPS_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The bootloader can be compile with different capabilities selected
* at compile time. This function provides runtime access to these
* capabilities. This is intended primarily for testing, although
* these will possibly be available at runtime to the application
* running within the bootloader.
*/
uint32_t bootutil_get_caps(void);
#define BOOTUTIL_CAP_RSA2048 (1<<0)
/* reserved (1<<1) */
#define BOOTUTIL_CAP_ECDSA_P256 (1<<2)
#define BOOTUTIL_CAP_SWAP_USING_SCRATCH (1<<3)
#define BOOTUTIL_CAP_OVERWRITE_UPGRADE (1<<4)
#define BOOTUTIL_CAP_ENC_RSA (1<<5)
#define BOOTUTIL_CAP_ENC_KW (1<<6)
#define BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT (1<<7)
#define BOOTUTIL_CAP_RSA3072 (1<<8)
#define BOOTUTIL_CAP_ED25519 (1<<9)
#define BOOTUTIL_CAP_ENC_EC256 (1<<10)
#define BOOTUTIL_CAP_SWAP_USING_MOVE (1<<11)
#define BOOTUTIL_CAP_DOWNGRADE_PREVENTION (1<<12)
#define BOOTUTIL_CAP_ENC_X25519 (1<<13)
#define BOOTUTIL_CAP_BOOTSTRAP (1<<14)
#define BOOTUTIL_CAP_AES256 (1<<15)
#define BOOTUTIL_CAP_RAM_LOAD (1<<16)
#define BOOTUTIL_CAP_DIRECT_XIP (1<<17)
#define BOOTUTIL_CAP_HW_ROLLBACK_PROT (1<<18)
#define BOOTUTIL_CAP_ECDSA_P384 (1<<19)
/*
* Query the number of images this bootloader is configured for. This
* is also primarily used for testing.
*/
uint32_t bootutil_get_num_images(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,158 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_AES_CTR_H_
#define __BOOTUTIL_CRYPTO_AES_CTR_H_
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT) + defined(MCUBOOT_USE_PSA_CRYPTO)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT or PSA"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/aes.h>
#include "bootutil/enc_key_public.h"
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16)
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#if defined(MCUBOOT_AES_256)
#error "Cannot use AES-256 for encryption with Tinycrypt library."
#endif
#include <string.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/ctr_mode.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE TC_AES_KEY_SIZE
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE TC_AES_BLOCK_SIZE
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include <psa/crypto.h>
#include "bootutil/enc_key_public.h"
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16)
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_PSA_CRYPTO)
typedef struct {
/* Fixme: This should not be, here, psa_key_id should be passed */
uint8_t key[BOOT_ENC_KEY_SIZE];
} bootutil_aes_ctr_context;
void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx);
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
{
memset(ctx, 0, sizeof(ctx));
}
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
{
memcpy(ctx->key, k, sizeof(ctx->key));
return 0;
}
int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter,
const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c);
int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter,
const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m);
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_aes_context bootutil_aes_ctr_context;
static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
{
(void)mbedtls_aes_init(ctx);
}
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
{
mbedtls_aes_free(ctx);
}
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
{
return mbedtls_aes_setkey_enc(ctx, k, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE * 8);
}
static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c)
{
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
return mbedtls_aes_crypt_ctr(ctx, mlen, &blk_off, counter, stream_block, m, c);
}
static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m)
{
uint8_t stream_block[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
return mbedtls_aes_crypt_ctr(ctx, clen, &blk_off, counter, stream_block, c, m);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_aes_key_sched_struct bootutil_aes_ctr_context;
static inline void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
{
(void)ctx;
}
static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx)
{
(void)ctx;
}
static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k)
{
int rc;
rc = tc_aes128_set_encrypt_key(ctx, k);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static int _bootutil_aes_ctr_crypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *in, uint32_t inlen, uint32_t blk_off, uint8_t *out)
{
int rc;
rc = tc_ctr_mode(out, inlen, in, inlen, counter, &blk_off, ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *m, uint32_t mlen, uint32_t blk_off, uint8_t *c)
{
return _bootutil_aes_ctr_crypt(ctx, counter, m, mlen, blk_off, c);
}
static inline int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter, const uint8_t *c, uint32_t clen, uint32_t blk_off, uint8_t *m)
{
return _bootutil_aes_ctr_crypt(ctx, counter, c, clen, blk_off, m);
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_AES_CTR_H_ */

View File

@@ -0,0 +1,142 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_AES_KW_H_
#define __BOOTUTIL_CRYPTO_AES_KW_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/aes.h>
#include <mbedtls/nist_kw.h>
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#if defined(MCUBOOT_AES_256)
#error "Cannot use AES-256 for encryption with Tinycrypt library."
#endif
#include <tinycrypt/aes.h>
#include <tinycrypt/constants.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_nist_kw_context bootutil_aes_kw_context;
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
{
(void)mbedtls_nist_kw_init(ctx);
}
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
{
mbedtls_nist_kw_free(ctx);
}
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
{
return mbedtls_nist_kw_setkey(ctx, MBEDTLS_CIPHER_ID_AES, k, klen * 8, 0);
}
static inline int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
{
size_t olen;
return mbedtls_nist_kw_unwrap(ctx, MBEDTLS_KW_MODE_KW, wrapped_key, wrapped_key_len, key, &olen, key_len);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_aes_key_sched_struct bootutil_aes_kw_context;
static inline void bootutil_aes_kw_init(bootutil_aes_kw_context *ctx)
{
(void)ctx;
}
static inline void bootutil_aes_kw_drop(bootutil_aes_kw_context *ctx)
{
(void)ctx;
}
static inline int bootutil_aes_kw_set_unwrap_key(bootutil_aes_kw_context *ctx, const uint8_t *k, uint32_t klen)
{
int rc;
if (klen != 16) {
return -1;
}
rc = tc_aes128_set_decrypt_key(ctx, k);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
/*
* Implements AES key unwrapping following RFC-3394 section 2.2.2, using
* tinycrypt for AES-128 decryption.
*/
static int bootutil_aes_kw_unwrap(bootutil_aes_kw_context *ctx, const uint8_t *wrapped_key, uint32_t wrapped_key_len, uint8_t *key, uint32_t key_len)
{
uint8_t A[8];
uint8_t B[16];
int8_t i, j, k;
if (wrapped_key_len != 24 || key_len != 16) {
return -1;
}
for (k = 0; k < 8; k++) {
A[k] = wrapped_key[k];
key[k] = wrapped_key[8 + k];
key[8 + k] = wrapped_key[16 + k];
}
for (j = 5; j >= 0; j--) {
for (i = 2; i > 0; i--) {
for (k = 0; k < 8; k++) {
B[k] = A[k];
B[8 + k] = key[((i-1) * 8) + k];
}
B[7] ^= 2 * j + i;
if (tc_aes_decrypt((uint8_t *)&B, (uint8_t *)&B, ctx) != TC_CRYPTO_SUCCESS) {
return -1;
}
for (k = 0; k < 8; k++) {
A[k] = B[k];
key[((i-1) * 8) + k] = B[8 + k];
}
}
}
for (i = 0, k = 0; i < 8; i++) {
k |= A[i] ^ 0xa6;
}
if (k) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_AES_KW_H_ */

View File

@@ -0,0 +1,29 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2021 Arm Limited
*/
#ifndef __BOOTUTIL_CRYPTO_COMMON_H__
#define __BOOTUTIL_CRYPTO_COMMON_H__
/* The check below can be performed even for those cases
* where MCUBOOT_USE_MBED_TLS has not been defined
*/
#include "mbedtls/version.h"
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
#define MBEDTLS_CONTEXT_MEMBER(X) MBEDTLS_PRIVATE(X)
#else
#define MBEDTLS_CONTEXT_MEMBER(X) X
#endif
/* Newer versions of Mbed TLS have removed the private accessor requirement for
* the ASN1 fields.
*/
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) && (MBEDTLS_VERSION_NUMBER < 0x03010000)
#define ASN1_CONTEXT_MEMBER(X) MBEDTLS_PRIVATE(X)
#else
#define ASN1_CONTEXT_MEMBER(X) X
#endif
#endif /* __BOOTUTIL_CRYPTO_COMMON_H__ */

View File

@@ -0,0 +1,154 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDH_P256_H_
#define __BOOTUTIL_CRYPTO_ECDH_P256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/ecp.h>
#include <mbedtls/ecdh.h>
#define EC256_PUBK_LEN (65)
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/ecc_dh.h>
#include <tinycrypt/constants.h>
#define BOOTUTIL_CRYPTO_ECDH_P256_HASH_SIZE (4 * 8)
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef uintptr_t bootutil_ecdh_p256_context;
static inline void bootutil_ecdh_p256_init(bootutil_ecdh_p256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdh_p256_drop(bootutil_ecdh_p256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdh_p256_shared_secret(bootutil_ecdh_p256_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
{
int rc;
(void)ctx;
if (pk[0] != 0x04) {
return -1;
}
rc = uECC_valid_public_key(&pk[1], uECC_secp256r1());
if (rc != 0) {
return -1;
}
rc = uECC_shared_secret(&pk[1], sk, z, uECC_secp256r1());
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_MBED_TLS)
#define NUM_ECC_BYTES 32
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
static int fake_rng(void *p_rng, unsigned char *output, size_t len);
#endif
typedef struct bootutil_ecdh_p256_context {
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
mbedtls_mpi z;
mbedtls_mpi d;
} bootutil_ecdh_p256_context;
static inline void bootutil_ecdh_p256_init(bootutil_ecdh_p256_context *ctx)
{
mbedtls_mpi_init(&ctx->z);
mbedtls_mpi_init(&ctx->d);
mbedtls_ecp_group_init(&ctx->grp);
mbedtls_ecp_point_init(&ctx->P);
if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1) != 0) {
mbedtls_ecp_group_free(&ctx->grp);
mbedtls_ecp_point_free(&ctx->P);
}
}
static inline void bootutil_ecdh_p256_drop(bootutil_ecdh_p256_context *ctx)
{
mbedtls_mpi_free(&ctx->d);
mbedtls_mpi_free(&ctx->z);
mbedtls_ecp_group_free(&ctx->grp);
mbedtls_ecp_point_free(&ctx->P);
}
static inline int bootutil_ecdh_p256_shared_secret(bootutil_ecdh_p256_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
{
int rc;
rc = mbedtls_ecp_point_read_binary(&ctx->grp,
&ctx->P,
pk,
EC256_PUBK_LEN);
if (rc != 0) {
mbedtls_ecp_group_free(&ctx->grp);
mbedtls_ecp_point_free(&ctx->P);
return -1;
}
rc = mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->P);
if (rc != 0) {
mbedtls_ecp_group_free(&ctx->grp);
mbedtls_ecp_point_free(&ctx->P);
return -1;
}
mbedtls_mpi_read_binary(&ctx->d, sk, NUM_ECC_BYTES);
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
rc = mbedtls_ecdh_compute_shared(&ctx->grp,
&ctx->z,
&ctx->P,
&ctx->d,
fake_rng,
NULL);
#else
rc = mbedtls_ecdh_compute_shared(&ctx->grp,
&ctx->z,
&ctx->P,
&ctx->d,
NULL,
NULL);
#endif
mbedtls_mpi_write_binary(&ctx->z, z, NUM_ECC_BYTES);
return rc;
}
#endif /* MCUBOOT_USE_MBED_TLS */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDH_P256_H_ */

View File

@@ -0,0 +1,57 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDH_X25519_H_
#define __BOOTUTIL_CRYPTO_ECDH_X25519_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS)
extern int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
const uint8_t peer_public_value[32]);
typedef uintptr_t bootutil_ecdh_x25519_context;
static inline void bootutil_ecdh_x25519_init(bootutil_ecdh_x25519_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdh_x25519_drop(bootutil_ecdh_x25519_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdh_x25519_shared_secret(bootutil_ecdh_x25519_context *ctx, const uint8_t *pk, const uint8_t *sk, uint8_t *z)
{
int rc;
(void)ctx;
rc = X25519(z, sk, pk);
if (rc != 0) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDH_X25519_H_ */

View File

@@ -0,0 +1,672 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023-2024 Arm Limited
*/
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, the choices are: MCUBOOT_USE_TINYCRYPT, MCUBOOT_USE_CC310,
* MCUBOOT_USE_MBED_TLS, MCUBOOT_USE_PSA_CRYPTO. Note that support for
* MCUBOOT_USE_PSA_CRYPTO is still experimental and it might not support all
* the crypto abstractions that MCUBOOT_USE_MBED_TLS supports. For this
* reason, it's allowed to have both of them defined, and for crypto modules
* that support both abstractions, the MCUBOOT_USE_PSA_CRYPTO will take
* precedence.
*/
#ifndef __BOOTUTIL_CRYPTO_ECDSA_H_
#define __BOOTUTIL_CRYPTO_ECDSA_H_
#include <stdint.h>
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
#define MCUBOOT_USE_PSA_OR_MBED_TLS
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_SIGN_EC384) && \
!defined(MCUBOOT_USE_PSA_CRYPTO)
#error "P384 requires PSA_CRYPTO to be defined"
#endif
#if (defined(MCUBOOT_USE_TINYCRYPT) + \
defined(MCUBOOT_USE_CC310) + \
defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \
defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
#error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO"
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/ecc_dsa.h>
#include <tinycrypt/constants.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
#include <cc310_glue.h>
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include <psa/crypto.h>
#include <string.h>
#elif defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/ecdsa.h>
/* Indicate to the caller that the verify function needs the raw ASN.1
* signature, not a decoded one. */
#define MCUBOOT_ECDSA_NEED_ASN1_SIG
#endif /* MCUBOOT_USE_MBED_TLS */
/*TODO: remove this after cypress port mbedtls to abstract crypto api */
#if defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_MBED_TLS)
#define NUM_ECC_BYTES (256 / 8)
#endif
/* Universal defines */
#define BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE (32)
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil/sign_key.h"
#include "common.h"
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
#include <bl_crypto.h>
#define NUM_ECC_BYTES (256 / 8)
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \
defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \
&& !defined(MCUBOOT_USE_PSA_CRYPTO)
/*
* Declaring these like this adds NULL termination.
*/
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
/*
* Parse a public key. Helper function.
*/
static int bootutil_import_key(uint8_t **cp, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *cp + len;
/* ECParameters (RFC5480) */
if (mbedtls_asn1_get_alg(cp, end, &alg, &param)) {
return -2;
}
/* id-ecPublicKey (RFC5480) */
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
/* namedCurve (RFC5480) */
if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 ||
memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -4;
}
/* ECPoint (RFC5480) */
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
return -6;
}
if (*cp + len != end) {
return -7;
}
if (len != 2 * NUM_ECC_BYTES + 1) {
return -8;
}
return 0;
}
#endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */
/*
* cp points to ASN1 string containing an integer.
* Verify the tag, and that the length is 32 bytes. Helper function.
*/
static int bootutil_read_bigint(uint8_t i[NUM_ECC_BYTES], uint8_t **cp, uint8_t *end)
{
size_t len;
if (mbedtls_asn1_get_tag(cp, end, &len, MBEDTLS_ASN1_INTEGER)) {
return -3;
}
if (len >= NUM_ECC_BYTES) {
memcpy(i, *cp + len - NUM_ECC_BYTES, NUM_ECC_BYTES);
} else {
memset(i, 0, NUM_ECC_BYTES - len);
memcpy(i + NUM_ECC_BYTES - len, *cp, len);
}
*cp += len;
return 0;
}
/*
* Read in signature. Signature has r and s encoded as integers. Helper function.
*/
static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp, uint8_t *end)
{
int rc;
size_t len;
rc = mbedtls_asn1_get_tag(&cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
if (rc) {
return -1;
}
if (cp + len > end) {
return -2;
}
rc = bootutil_read_bigint(signature, &cp, end);
if (rc) {
return -3;
}
rc = bootutil_read_bigint(signature + NUM_ECC_BYTES, &cp, end);
if (rc) {
return -4;
}
return 0;
}
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef uintptr_t bootutil_ecdsa_context;
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_len)
{
int rc;
(void)ctx;
(void)pk_len;
(void)sig_len;
(void)hash_len;
uint8_t signature[2 * NUM_ECC_BYTES];
rc = bootutil_decode_sig(signature, sig, sig + sig_len);
if (rc) {
return -1;
}
/* Only support uncompressed keys. */
if (pk[0] != 0x04) {
return -1;
}
pk++;
rc = uECC_verify(pk, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, signature, uECC_secp256r1());
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
uint8_t **cp,uint8_t *end)
{
(void)ctx;
return bootutil_import_key(cp, end);
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
typedef uintptr_t bootutil_ecdsa_context;
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_len)
{
(void)ctx;
(void)pk_len;
(void)hash_len;
uint8_t dsig[2 * NUM_ECC_BYTES];
if (bootutil_decode_sig(dsig, sig, sig + sig_len)) {
return -1;
}
/* Only support uncompressed keys. */
if (pk[0] != 0x04) {
return -1;
}
pk++;
return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE);
}
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
uint8_t **cp,uint8_t *end)
{
(void)ctx;
return bootutil_import_key(cp, end);
}
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_PSA_CRYPTO)
typedef struct {
psa_key_id_t key_id;
size_t curve_byte_count;
psa_algorithm_t required_algorithm;
} bootutil_ecdsa_context;
/* ECDSA public key with format specified in RFC5280 et al. in ASN.1 syntax
*
* SEQUENCE {
* SEQUENCE {
* OBJECT idEcPublicKey
* OBJECT namedCurve
* }
* BIT STRING publicKey
* }
*
* ECDSA signature format specified in RFC3279 et al. in ASN.1 syntax
*
* SEQUENCE {
* INTEGER r
* INTEGER s
* }
*
*/
/* Offset in bytes from the start of the encoding to the length field
* of the innermost SEQUENCE in the ECDSA public key
*/
#define PUB_KEY_LEN_OFF (3)
/* Offset in bytes from the start of the publicKey encoding of the BIT STRING */
#define PUB_KEY_VAL_OFF (3)
/* Computes the pointer to the idEcPublicKey OID from the base of the encoding */
#define PUB_KEY_OID_OFFSET(p) (*p + PUB_KEY_LEN_OFF+1)
/* Computes the pointer to the namedCurve OID from the base of the encoding */
#define CURVE_TYPE_OID_OFFSET(p) PUB_KEY_OID_OFFSET(p) + sizeof(IdEcPublicKey)
/* This helper function gets a pointer to the bitstring associated to the publicKey
* as encoded per RFC 5280. This function assumes that the public key encoding is not
* bigger than 127 bytes (i.e. usually up until 384 bit curves)
*
* \param[in,out] p Double pointer to a buffer containing the RFC 5280 of the ECDSA public key.
* On output, the pointer is updated to point to the start of the public key
* in BIT STRING form.
* \param[out] size Pointer to a buffer containing the size of the public key extracted
*
*/
static inline void get_public_key_from_rfc5280_encoding(uint8_t **p, size_t *size)
{
uint8_t *key_start = (*p) + (PUB_KEY_LEN_OFF + 1 + (*p)[PUB_KEY_LEN_OFF] + PUB_KEY_VAL_OFF);
*p = key_start;
*size = key_start[-2]-1; /* -2 from PUB_KEY_VAL_OFF to get the length, -1 to remove the ASN.1 padding byte count */
}
/* This helper function parses a signature as specified in RFC3279 into a pair
* (r,s) of contiguous bytes
*
* \param[in] sig Pointer to a buffer containing the encoded signature
* \param[in] num_of_curve_bytes The required number of bytes for r and s
* \param[out] r_s_pair Buffer containing the (r,s) pair extracted. It's caller
* responsibility to ensure the buffer is big enough to
* hold the parsed (r,s) pair.
*/
static void parse_signature_from_rfc5480_encoding(const uint8_t *sig,
size_t num_of_curve_bytes,
uint8_t *r_s_pair)
{
const uint8_t *sig_ptr = NULL;
/* r or s can be greater than the expected size by one, due to the way
* ASN.1 encodes signed integers. If either r or s starts with a bit 1,
* a zero byte will be added in front of the encoding
*/
/* sig[0] == 0x30, sig[1] == <length>, sig[2] == 0x02 */
/* Move r in place */
size_t r_len = sig[3];
sig_ptr = &sig[4];
if (r_len >= num_of_curve_bytes) {
sig_ptr = sig_ptr + r_len - num_of_curve_bytes;
memcpy(&r_s_pair[0], sig_ptr, num_of_curve_bytes);
if(r_len % 2) {
r_len--;
}
} else {
/* For encodings that reduce the size of r or s in case of zeros */
memcpy(&r_s_pair[num_of_curve_bytes - r_len], sig_ptr, r_len);
}
/* Move s in place */
size_t s_len = sig_ptr[r_len+1]; /* + 1 to skip SEQUENCE */
sig_ptr = &sig_ptr[r_len+2];
if (s_len >= num_of_curve_bytes) {
sig_ptr = sig_ptr + s_len - num_of_curve_bytes;
memcpy(&r_s_pair[num_of_curve_bytes], sig_ptr, num_of_curve_bytes);
} else {
/* For encodings that reduce the size of r or s in case of zeros */
memcpy(&r_s_pair[2*num_of_curve_bytes - s_len], sig_ptr, s_len);
}
}
// OID id-ecPublicKey 1.2.840.10045.2.1.
static const uint8_t IdEcPublicKey[] = {0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01};
#if defined(MCUBOOT_SIGN_EC256)
// OID secp256r1 1.2.840.10045.3.1.7.
static const uint8_t Secp256r1[] = {0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
#endif /* MCUBOOT_SIGN_EC256 */
#if defined(MCUBOOT_SIGN_EC384)
// OID secp384r1 1.3.132.0.34
static const uint8_t Secp384r1[] = {0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22};
#endif /* MCUBOOT_SIGN_EC384 */
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
{
#if !defined(MCUBOOT_BUILTIN_KEY)
ctx->key_id = PSA_KEY_ID_NULL;
ctx->curve_byte_count = 0;
ctx->required_algorithm = 0;
#else /* !MCUBOOT_BUILTIN_KEY */
/* The incoming key ID is equal to the image index. The key ID value must be
* shifted (by one in this case) because zero is reserved (PSA_KEY_ID_NULL)
* and considered invalid.
*/
ctx->key_id++; /* Make sure it is not equal to 0. */
#if defined(MCUBOOT_SIGN_EC256)
ctx->curve_byte_count = 32;
ctx->required_algorithm = PSA_ALG_SHA_256;
#endif /* MCUBOOT_SIGN_EC256 */
#if defined(MCUBOOT_SIGN_EC384)
ctx->curve_byte_count = 48;
ctx->required_algorithm = PSA_ALG_SHA_384;
#endif /* MCUBOOT_SIGN_EC384 */
#endif /* !MCUBOOT_BUILTIN_KEY */
}
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
{
if (ctx->key_id != PSA_KEY_ID_NULL) {
(void)psa_destroy_key(ctx->key_id);
}
}
#if !defined(MCUBOOT_BUILTIN_KEY)
/*
* Parse a ECDSA public key with format specified in RFC5280 et al.
*
* OID for icEcPublicKey is 1.2.840.10045.2.1
* OIDs for supported curves are as follows:
* secp256r1 (prime256v1): 1.2.840.10045.3.1.7
* secp384r1: 1.3.132.0.34
*/
static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
uint8_t **cp, uint8_t *end)
{
psa_key_attributes_t key_attributes = psa_key_attributes_init();
size_t key_size;
(void)end;
/* public key oid is valid */
if (memcmp(PUB_KEY_OID_OFFSET(cp), IdEcPublicKey, sizeof(IdEcPublicKey))) {
return (int)PSA_ERROR_INVALID_ARGUMENT;
}
#if defined(MCUBOOT_SIGN_EC256)
if (!memcmp(CURVE_TYPE_OID_OFFSET(cp), Secp256r1, sizeof(Secp256r1))) {
ctx->curve_byte_count = 32;
ctx->required_algorithm = PSA_ALG_SHA_256;
} else
#endif /* MCUBOOT_SIGN_EC256 */
#if defined(MCUBOOT_SIGN_EC384)
if (!memcmp(CURVE_TYPE_OID_OFFSET(cp), Secp384r1, sizeof(Secp384r1))) {
ctx->curve_byte_count = 48;
ctx->required_algorithm = PSA_ALG_SHA_384;
} else
#endif /* MCUBOOT_SIGN_EC384 */
{
return (int)PSA_ERROR_INVALID_ARGUMENT;
}
get_public_key_from_rfc5280_encoding(cp, &key_size);
/* Set attributes and import key */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(ctx->required_algorithm));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
return (int)psa_import_key(&key_attributes, *cp, key_size, &ctx->key_id);
}
#endif /* !MCUBOOT_BUILTIN_KEY */
/* Verify the signature against the provided hash. The signature gets parsed from
* the encoding first, then PSA Crypto has a dedicated API for ECDSA verification
*/
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hlen,
uint8_t *sig, size_t slen)
{
(void)pk;
(void)pk_len;
(void)slen;
uint8_t reformatted_signature[96] = {0}; /* Enough for P-384 signature sizes */
parse_signature_from_rfc5480_encoding(sig, ctx->curve_byte_count,reformatted_signature);
return (int) psa_verify_hash(ctx->key_id, PSA_ALG_ECDSA(ctx->required_algorithm),
hash, hlen, reformatted_signature, 2*ctx->curve_byte_count);
}
#elif defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_ecdsa_context bootutil_ecdsa_context;
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
{
mbedtls_ecdsa_init(ctx);
}
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
{
mbedtls_ecdsa_free(ctx);
}
#ifdef CY_MBEDTLS_HW_ACCELERATION
/*
* Parse the public key used for signing.
*/
static int bootutil_parse_eckey(bootutil_ecdsa_context *ctx, uint8_t **p, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *p + len;
if (mbedtls_asn1_get_alg(p, end, &alg, &param)) {
return -2;
}
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1||
memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -4;
}
if (mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1)) {
return -5;
}
if (mbedtls_asn1_get_bitstring_null(p, end, &len)) {
return -6;
}
if (*p + len != end) {
return -7;
}
if (mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, *p, end - *p)) {
return -8;
}
if (mbedtls_ecp_check_pubkey(&ctx->grp, &ctx->Q)) {
return -9;
}
return 0;
}
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_len)
{
(void)pk;
(void)pk_len;
/*
* This is simplified, as the hash length is also 32 bytes.
*/
while (sig[sig_len - 1] == '\0') {
sig_len--;
}
return mbedtls_ecdsa_read_signature(&ctx, hash, hash_len, sig, sig_len);
}
#else /* CY_MBEDTLS_HW_ACCELERATION */
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_len)
{
int rc;
(void)sig;
(void)hash;
(void)hash_len;
rc = mbedtls_ecp_group_load(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), MBEDTLS_ECP_DP_SECP256R1);
if (rc) {
return -1;
}
rc = mbedtls_ecp_point_read_binary(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), &ctx->MBEDTLS_CONTEXT_MEMBER(Q), pk, pk_len);
if (rc) {
return -1;
}
rc = mbedtls_ecp_check_pubkey(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), &ctx->MBEDTLS_CONTEXT_MEMBER(Q));
if (rc) {
return -1;
}
rc = mbedtls_ecdsa_read_signature(ctx, hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE,
sig, sig_len);
if (rc) {
return -1;
}
return 0;
}
#endif /* CY_MBEDTLS_HW_ACCELERATION */
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
uint8_t **cp,uint8_t *end)
{
int rc;
#ifdef CY_MBEDTLS_HW_ACCELERATION
rc = bootutil_parse_eckey(&ctx, cp, end);
#else
(void)ctx;
rc = bootutil_import_key(cp, end);
#endif
return rc;
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
typedef uintptr_t bootutil_ecdsa_context;
static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx)
{
(void)ctx;
}
static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx,
uint8_t *pk, size_t pk_len,
uint8_t *hash, size_t hash_len,
uint8_t *sig, size_t sig_len)
{
(void)ctx;
(void)pk_len;
(void)hash_len;
uint8_t dsig[2 * NUM_ECC_BYTES];
if (bootutil_decode_sig(dsig, sig, sig + sig_len)) {
return -1;
}
/* Only support uncompressed keys. */
if (pk[0] != 0x04) {
return -1;
}
pk++;
return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig);
}
static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx,
uint8_t **cp,uint8_t *end)
{
(void)ctx;
return bootutil_import_key(cp, end);
}
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_ECDSA_H_ */

View File

@@ -0,0 +1,134 @@
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, there are two choices: MCUBOOT_USE_MBED_TLS, or
* MCUBOOT_USE_TINYCRYPT. It is a compile error there is not exactly
* one of these defined.
*/
#ifndef __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
#define __BOOTUTIL_CRYPTO_HMAC_SHA256_H_
#include "mcuboot_config/mcuboot_config.h"
#if (defined(MCUBOOT_USE_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT)) != 1
#error "One crypto backend must be defined: either MBED_TLS or TINYCRYPT"
#endif
#if defined(MCUBOOT_USE_MBED_TLS)
#include <stdint.h>
#include <stddef.h>
#include <mbedtls/cmac.h>
#include <mbedtls/md.h>
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/sha256.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/hmac.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_hmac_state_struct bootutil_hmac_sha256_context;
static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx)
{
(void)ctx;
}
static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx)
{
(void)ctx;
}
static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size)
{
int rc;
rc = tc_hmac_set_key(ctx, key, key_size);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
rc = tc_hmac_init(ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length)
{
int rc;
rc = tc_hmac_update(ctx, data, data_length);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen)
{
int rc;
rc = tc_hmac_final(tag, taglen, ctx);
if (rc != TC_CRYPTO_SUCCESS) {
return -1;
}
return 0;
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_MBED_TLS)
/**
* The generic message-digest context.
*/
typedef mbedtls_md_context_t bootutil_hmac_sha256_context;
static inline void bootutil_hmac_sha256_init(bootutil_hmac_sha256_context *ctx)
{
mbedtls_md_init(ctx);
}
static inline void bootutil_hmac_sha256_drop(bootutil_hmac_sha256_context *ctx)
{
mbedtls_md_free(ctx);
}
static inline int bootutil_hmac_sha256_set_key(bootutil_hmac_sha256_context *ctx, const uint8_t *key, unsigned int key_size)
{
int rc;
rc = mbedtls_md_setup(ctx, mbedtls_md_info_from_string("SHA256"), 1);
if (rc != 0) {
return rc;
}
rc = mbedtls_md_hmac_starts(ctx, key, key_size);
return rc;
}
static inline int bootutil_hmac_sha256_update(bootutil_hmac_sha256_context *ctx, const void *data, unsigned int data_length)
{
return mbedtls_md_hmac_update(ctx, data, data_length);
}
static inline int bootutil_hmac_sha256_finish(bootutil_hmac_sha256_context *ctx, uint8_t *tag, unsigned int taglen)
{
(void)taglen;
/*
* HMAC the key and check that our received MAC matches the generated tag
*/
return mbedtls_md_hmac_finish(ctx, tag);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_HMAC_SHA256_H_ */

View File

@@ -0,0 +1,356 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Arm Limited
*/
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, the choices are: MCUBOOT_USE_MBED_TLS and
* MCUBOOT_USE_PSA_CRYPTO. Note that support for MCUBOOT_USE_PSA_CRYPTO is
* still experimental and it might not support all the crypto abstractions
* that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
* both of them defined, and for crypto modules that support both abstractions,
* the MCUBOOT_USE_PSA_CRYPTO will take precedence.
*/
/*
* Note: The source file that includes this header should either define one of the
* two options BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED or BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
* This will make the signature functions or encryption functions visible without
* generating a "defined but not used" compiler warning
*/
#ifndef __BOOTUTIL_CRYPTO_RSA_H_
#define __BOOTUTIL_CRYPTO_RSA_H_
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
#define MCUBOOT_USE_PSA_OR_MBED_TLS
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
#if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
#error "One crypto backend must be defined: either MBED_TLS/PSA_CRYPTO"
#endif
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include <psa/crypto.h>
#include "bootutil/enc_key_public.h"
#elif defined(MCUBOOT_USE_MBED_TLS)
#include "mbedtls/rsa.h"
#include "mbedtls/version.h"
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
#include "rsa_alt_helpers.h"
#else
#include "mbedtls/rsa_internal.h"
#endif
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
#include "mbedtls/asn1.h"
#include "bootutil/crypto/common.h"
#endif /* MCUBOOT_USE_MBED_TLS */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_PSA_CRYPTO)
typedef struct {
psa_key_id_t key_id;
} bootutil_rsa_context;
static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
{
ctx->key_id = PSA_KEY_ID_NULL;
}
static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
{
if (ctx->key_id != PSA_KEY_ID_NULL) {
(void)psa_destroy_key(ctx->key_id);
}
}
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
static int bootutil_rsa_oaep_decrypt(
bootutil_rsa_context *ctx,
size_t *olen,
const uint8_t *input,
uint8_t *output,
size_t output_max_len)
{
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
/* Perform an additional defensive check to compare the modulus of the RSA
* key to the expected input of the decryption function, i.e. TLV_ENC_RSA_SZ
*/
psa_key_attributes_t key_attr = psa_key_attributes_init();
status = psa_get_key_attributes(ctx->key_id, &key_attr);
if (status != PSA_SUCCESS) {
return -1;
}
size_t input_size = PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attr));
if (input_size != TLV_ENC_RSA_SZ) {
return -1;
}
status = psa_asymmetric_decrypt(ctx->key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
input, TLV_ENC_RSA_SZ, NULL, 0,
output, output_max_len, olen);
return (int)status;
}
/*
* Parse a RSA private key with format specified in RFC3447 A.1.2
*
* The key is meant to be used for OAEP decrypt hence algorithm and usage are hardcoded
*/
static int
bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
psa_key_attributes_t key_attributes = psa_key_attributes_init();
/* Set attributes and import key */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
return (int)status;
}
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
/*
* Parse a RSA public key with format specified in RFC3447 A.1.1
*
* The key is meant to be used for PSS signature verification hence algorithm and usage are hardcoded
*/
static int
bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
psa_key_attributes_t key_attributes = psa_key_attributes_init();
/* Set attributes and import key */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
return (int)status;
}
/* Get the modulus (N) length in bytes */
static size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
{
psa_key_attributes_t key_attributes = psa_key_attributes_init();
psa_status_t status = psa_get_key_attributes(ctx->key_id, &key_attributes);
if (status != PSA_SUCCESS) {
return 0;
}
return PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attributes));
}
/* PSA Crypto has a dedicated API for RSASSA-PSS verification */
static inline int bootutil_rsassa_pss_verify(const bootutil_rsa_context *ctx,
uint8_t *hash, size_t hlen, uint8_t *sig, size_t slen)
{
return (int) psa_verify_hash(ctx->key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
hash, hlen, sig, slen);
}
#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
#elif defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_rsa_context bootutil_rsa_context;
static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
{
#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
}
static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
{
mbedtls_rsa_free(ctx);
}
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
static int fake_rng(void *p_rng, unsigned char *output, size_t len);
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED && MBEDTLS_VERSION_NUMBER >= 3.0 */
#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
static inline int bootutil_rsa_oaep_decrypt(
bootutil_rsa_context *ctx,
size_t *olen,
const uint8_t *input,
uint8_t *output,
size_t output_max_len)
{
int rc = -1;
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, fake_rng, NULL,
NULL, 0, olen, input, output, output_max_len);
#else
rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, NULL, NULL, MBEDTLS_RSA_PRIVATE,
NULL, 0, olen, input, output, output_max_len);
#endif
return rc;
}
/*
* Parse a RSA private key with format specified in RFC3447 A.1.2
*/
static int
bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
{
size_t len;
if (mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
/* Non-optional fields. */
if ( /* version */
mbedtls_asn1_get_int(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(ver)) != 0 ||
/* public modulus */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0 ||
/* public exponent */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0 ||
/* private exponent */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(D)) != 0 ||
/* primes */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(P)) != 0 ||
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(Q)) != 0) {
return -3;
}
#if !defined(MBEDTLS_RSA_NO_CRT)
/*
* DP/DQ/QP are only used inside mbedTLS if it was built with the
* Chinese Remainder Theorem enabled (default). In case it is disabled
* we parse, or if not available, we calculate those values.
*/
if (*p < end) {
if ( /* d mod (p-1) and d mod (q-1) */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DP)) != 0 ||
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DQ)) != 0 ||
/* q ^ (-1) mod p */
mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
return -4;
}
} else {
if (mbedtls_rsa_deduce_crt(&ctx->MBEDTLS_CONTEXT_MEMBER(P),
&ctx->MBEDTLS_CONTEXT_MEMBER(Q),
&ctx->MBEDTLS_CONTEXT_MEMBER(D),
&ctx->MBEDTLS_CONTEXT_MEMBER(DP),
&ctx->MBEDTLS_CONTEXT_MEMBER(DQ),
&ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
return -5;
}
}
#endif /* !MBEDTLS_RSA_NO_CRT */
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
if (mbedtls_rsa_check_privkey(ctx) != 0) {
return -6;
}
return 0;
}
#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
/*
* Parse a RSA public key with format specified in RFC3447 A.1.1
*/
static int
bootutil_rsa_parse_public_key(bootutil_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_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N))) != 0 ||
(rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E))) != 0) {
return -3;
}
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
if (*p != end) {
return -4;
}
/* The Mbed TLS version is more than 2.6.1 */
#if MBEDTLS_VERSION_NUMBER > 0x02060100
rc = mbedtls_rsa_import(ctx, &ctx->MBEDTLS_CONTEXT_MEMBER(N), NULL,
NULL, NULL, &ctx->MBEDTLS_CONTEXT_MEMBER(E));
if (rc != 0) {
return -5;
}
#endif
rc = mbedtls_rsa_check_pubkey(ctx);
if (rc != 0) {
return -6;
}
ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
return 0;
}
/* Get the modulus (N) length in bytes */
static inline size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
{
return mbedtls_rsa_get_len(ctx);
}
/* Performs modular exponentiation using the public key output = input^E mod N */
static inline int bootutil_rsa_public(bootutil_rsa_context *ctx, const uint8_t *input, uint8_t *output)
{
return mbedtls_rsa_public(ctx, input, output);
}
#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
#endif /* MCUBOOT_USE_MBED_TLS */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_RSA_H_ */

View File

@@ -0,0 +1,250 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
* Copyright (c) 2021-2023 Arm Limited
*/
/*
* This module provides a thin abstraction over some of the crypto
* primitives to make it easier to swap out the used crypto library.
*
* At this point, the choices are: MCUBOOT_USE_MBED_TLS, MCUBOOT_USE_TINYCRYPT,
* MCUBOOT_USE_PSA_CRYPTO, MCUBOOT_USE_CC310. Note that support for MCUBOOT_USE_PSA_CRYPTO
* is still experimental and it might not support all the crypto abstractions
* that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
* both of them defined, and for crypto modules that support both abstractions,
* the MCUBOOT_USE_PSA_CRYPTO will take precedence.
*/
#ifndef __BOOTUTIL_CRYPTO_SHA_H_
#define __BOOTUTIL_CRYPTO_SHA_H_
#include "mcuboot_config/mcuboot_config.h"
#include "mcuboot_config/mcuboot_logging.h"
#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
#define MCUBOOT_USE_PSA_OR_MBED_TLS
#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
#if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \
defined(MCUBOOT_USE_TINYCRYPT) + \
defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \
defined(MCUBOOT_USE_CC310)) != 1
#error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO"
#endif
#if defined(MCUBOOT_SHA512)
#define IMAGE_HASH_SIZE (64)
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA512
#elif defined(MCUBOOT_SIGN_EC384)
#define IMAGE_HASH_SIZE (48)
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA384
#else
#define IMAGE_HASH_SIZE (32)
#define EXPECTED_HASH_TLV IMAGE_TLV_SHA256
#endif /* MCUBOOT_SIGN */
/* Universal defines for SHA-256 */
#define BOOTUTIL_CRYPTO_SHA256_BLOCK_SIZE (64)
#define BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE (32)
#if defined(MCUBOOT_USE_PSA_CRYPTO)
#include <psa/crypto.h>
#elif defined(MCUBOOT_USE_MBED_TLS)
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
#include <mbedtls/compat-2.x.h>
#endif
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
#include <tinycrypt/sha256.h>
#include <tinycrypt/constants.h>
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
#include <cc310_glue.h>
#endif /* MCUBOOT_USE_CC310 */
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MCUBOOT_USE_PSA_CRYPTO)
typedef psa_hash_operation_t bootutil_sha_context;
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
{
*ctx = psa_hash_operation_init();
#if defined(MCUBOOT_SHA512)
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_512);
#elif defined(MCUBOOT_SIGN_EC384)
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_384);
#else
psa_status_t status = psa_hash_setup(ctx, PSA_ALG_SHA_256);
#endif
return (int)status;
}
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
{
return (int)psa_hash_abort(ctx);
}
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
const void *data,
uint32_t data_len)
{
return (int)psa_hash_update(ctx, data, data_len);
}
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
uint8_t *output)
{
size_t hash_length = 0;
/* Assumes the output buffer is at least the expected size of the hash */
#if defined(MCUBOOT_SHA512)
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_512), &hash_length);
#elif defined(MCUBOOT_SIGN_EC384)
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_384), &hash_length);
#else
return (int)psa_hash_finish(ctx, output, PSA_HASH_LENGTH(PSA_ALG_SHA_256), &hash_length);
#endif
}
#elif defined(MCUBOOT_USE_MBED_TLS)
typedef mbedtls_sha256_context bootutil_sha_context;
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
{
mbedtls_sha256_init(ctx);
return mbedtls_sha256_starts_ret(ctx, 0);
}
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
{
mbedtls_sha256_free(ctx);
return 0;
}
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
const void *data,
uint32_t data_len)
{
return mbedtls_sha256_update_ret(ctx, data, data_len);
}
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
uint8_t *output)
{
return mbedtls_sha256_finish_ret(ctx, output);
}
#endif /* MCUBOOT_USE_MBED_TLS */
#if defined(MCUBOOT_USE_TINYCRYPT)
typedef struct tc_sha256_state_struct bootutil_sha_context;
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
{
tc_sha256_init(ctx);
return 0;
}
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
{
(void)ctx;
return 0;
}
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
const void *data,
uint32_t data_len)
{
return tc_sha256_update(ctx, data, data_len);
}
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
uint8_t *output)
{
return tc_sha256_final(output, ctx);
}
#endif /* MCUBOOT_USE_TINYCRYPT */
#if defined(MCUBOOT_USE_CC310)
static inline int bootutil_sha_init(bootutil_sha_context *ctx)
{
cc310_sha256_init(ctx);
return 0;
}
static inline int bootutil_sha_drop(bootutil_sha_context *ctx)
{
(void)ctx;
nrf_cc310_disable();
return 0;
}
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
const void *data,
uint32_t data_len)
{
cc310_sha256_update(ctx, data, data_len);
return 0;
}
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
uint8_t *output)
{
cc310_sha256_finalize(ctx, output);
return 0;
}
#endif /* MCUBOOT_USE_CC310 */
#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)
#include <bl_crypto.h>
typedef bl_sha256_ctx_t bootutil_sha_context;
static inline void bootutil_sha_init(bootutil_sha_context *ctx)
{
bl_sha256_init(ctx);
}
static inline void bootutil_sha_drop(bootutil_sha_context *ctx)
{
(void)ctx;
}
static inline int bootutil_sha_update(bootutil_sha_context *ctx,
const void *data,
uint32_t data_len)
{
return bl_sha256_update(ctx, data, data_len);
}
static inline int bootutil_sha_finish(bootutil_sha_context *ctx,
uint8_t *output)
{
bl_sha256_finalize(ctx, output);
return 0;
}
#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_CRYPTO_SHA_H_ */

View File

@@ -0,0 +1,83 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
* Copyright (c) 2019 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef BOOTUTIL_ENC_KEY_H
#define BOOTUTIL_ENC_KEY_H
#include <stdbool.h>
#include <stdint.h>
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/crypto/aes_ctr.h"
#include "bootutil/image.h"
#include "bootutil/sign_key.h"
#include "bootutil/enc_key_public.h"
#ifdef __cplusplus
extern "C" {
#endif
#define BOOT_ENC_TLV_ALIGN_SIZE ALIGN_UP(BOOT_ENC_TLV_SIZE, BOOT_MAX_ALIGN)
struct enc_key_data {
uint8_t valid;
bootutil_aes_ctr_context aes_ctr;
};
/**
* Retrieve the private key for image encryption.
*
* @param[out] private_key structure to store the private key and
* its length.
*
* @return 0 on success; nonzero on failure.
*
*/
int boot_enc_retrieve_private_key(struct bootutil_key **private_key);
struct boot_status;
/* Decrypt random, symmetric encryption key */
int boot_decrypt_key(const uint8_t *buf, uint8_t *enckey);
int boot_enc_init(struct enc_key_data *enc_state, uint8_t slot);
int boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot);
int boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot,
const struct boot_status *bs);
int boot_enc_load(struct enc_key_data *enc_state, int slot,
const struct image_header *hdr, const struct flash_area *fap,
struct boot_status *bs);
bool boot_enc_valid(struct enc_key_data *enc_state, int slot);
void boot_enc_encrypt(struct enc_key_data *enc_state, int slot,
uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf);
void boot_enc_decrypt(struct enc_key_data *enc_state, int slot,
uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf);
void boot_enc_zeroize(struct enc_key_data *enc_state);
#ifdef __cplusplus
}
#endif
#endif /* BOOTUTIL_ENC_KEY_H */

View File

@@ -0,0 +1,66 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef BOOTUTIL_ENC_KEY_PUBLIC_H
#define BOOTUTIL_ENC_KEY_PUBLIC_H
#include <mcuboot_config/mcuboot_config.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ALIGN_UP
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#endif
#ifdef MCUBOOT_AES_256
#define BOOT_ENC_KEY_SIZE 32
#else
#define BOOT_ENC_KEY_SIZE 16
#endif
#define BOOT_ENC_KEY_ALIGN_SIZE ALIGN_UP(BOOT_ENC_KEY_SIZE, BOOT_MAX_ALIGN)
#define TLV_ENC_RSA_SZ 256
#define TLV_ENC_KW_SZ (BOOT_ENC_KEY_SIZE + 8)
#define TLV_ENC_EC256_SZ (65 + 32 + BOOT_ENC_KEY_SIZE)
#define TLV_ENC_X25519_SZ (32 + 32 + BOOT_ENC_KEY_SIZE)
#if defined(MCUBOOT_ENCRYPT_RSA)
#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ
#elif defined(MCUBOOT_ENCRYPT_EC256)
#define BOOT_ENC_TLV_SIZE TLV_ENC_EC256_SZ
#elif defined(MCUBOOT_ENCRYPT_X25519)
#define BOOT_ENC_TLV_SIZE TLV_ENC_X25519_SZ
#else
#define BOOT_ENC_TLV_SIZE TLV_ENC_KW_SZ
#endif
#ifdef __cplusplus
}
#endif
#endif /* BOOTUTIL_ENC_KEY_PUBLIC_H */

View File

@@ -0,0 +1,371 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#ifndef __FAULT_INJECTION_HARDENING_H__
#define __FAULT_INJECTION_HARDENING_H__
/* Fault injection mitigation library.
*
* Has support for different measures, which can either be enabled/disabled
* separately or by defining one of the MCUBOOT_FIH_PROFILEs.
*
* NOTE: These constructs against fault injection attacks are not guaranteed to
* be secure for all compilers, but execution is going to be correct and
* including them will certainly help to harden the code.
*
* FIH_ENABLE_DOUBLE_VARS makes critical variables into a tuple (x, x ^ msk).
* Then the correctness of x can be checked by XORing the two tuple values
* together. This also means that comparisons between fih_ints can be verified
* by doing x == y && x_msk == y_msk.
*
* FIH_ENABLE_GLOBAL_FAIL makes all while(1) failure loops redirect to a global
* failure loop. This loop has mitigations against loop escapes / unlooping.
* This also means that any unlooping won't immediately continue executing the
* function that was executing before the failure.
*
* FIH_ENABLE_CFI (Control Flow Integrity) creates a global counter that is
* incremented before every FIH_CALL of vulnerable functions. On the function
* return the counter is decremented, and after the return it is verified that
* the counter has the same value as before this process. This can be used to
* verify that the function has actually been called. This protection is
* intended to discover that important functions are called in an expected
* sequence and neither of them is missed due to an instruction skip which could
* be a result of glitching attack. It does not provide protection against ROP
* or JOP attacks.
*
* FIH_ENABLE_DELAY causes random delays. This makes it hard to cause faults
* precisely. It requires an RNG. An mbedtls integration is provided in
* fault_injection_hardening_delay_mbedtls.h, but any RNG that has an entropy
* source can be used by implementing the fih_delay_random_uchar function.
*
* The basic call pattern is:
*
* FIH_DECLARE(fih_rc, FIH_FAILURE);
* FIH_CALL(vulnerable_function, fih_rc, arg1, arg2);
* if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
* FIH_PANIC;
* }
*
* Note that any function called by FIH_CALL must only return using FIH_RETURN,
* as otherwise the CFI counter will not be decremented and the CFI check will
* fail causing a panic.
*/
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_FIH_PROFILE_HIGH)
#define FIH_ENABLE_DELAY /* Requires an entropy source */
#define FIH_ENABLE_DOUBLE_VARS
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif defined(MCUBOOT_FIH_PROFILE_MEDIUM)
#define FIH_ENABLE_DOUBLE_VARS
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif defined(MCUBOOT_FIH_PROFILE_LOW)
#define FIH_ENABLE_GLOBAL_FAIL
#define FIH_ENABLE_CFI
#elif !defined(MCUBOOT_FIH_PROFILE_OFF)
#define MCUBOOT_FIH_PROFILE_OFF
#endif /* MCUBOOT_FIH_PROFILE */
#ifdef FIH_ENABLE_DELAY
#include "fault_injection_hardening_delay_rng.h"
#endif /* FIH_ENABLE_DELAY */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Non-zero success value to defend against register resets. Zero is the most
* common value for a corrupted register so complex bit-patterns are used
*/
#ifndef MCUBOOT_FIH_PROFILE_OFF
#define FIH_POSITIVE_VALUE 0x1AAAAAAA
#define FIH_NEGATIVE_VALUE 0x15555555
#define FIH_CONST1 0x1FCDEA88
#define FIH_CONST2 0x19C1F6E1
#else
#define FIH_POSITIVE_VALUE 0
#define FIH_NEGATIVE_VALUE -1
#define FIH_CONST1 1
#define FIH_CONST2 1
#endif
/* A volatile mask is used to prevent compiler optimization - the mask is xored
* with the variable to create the backup and the integrity can be checked with
* another xor. The mask value doesn't _really_ matter that much, as long as
* it has reasonably high hamming weight.
*/
#define _FIH_MASK_VALUE 0xBEEF
#ifdef FIH_ENABLE_DOUBLE_VARS
/* All ints are replaced with two int - the normal one and a backup which is
* XORed with the mask.
*/
extern volatile int _fih_mask;
typedef volatile struct {
volatile int val;
volatile int msk;
} fih_int;
typedef volatile int fih_ret;
#else
typedef int fih_int;
typedef int fih_ret;
#endif /* FIH_ENABLE_DOUBLE_VARS */
extern fih_ret FIH_SUCCESS;
extern fih_ret FIH_FAILURE;
extern fih_ret FIH_NO_BOOTABLE_IMAGE;
extern fih_ret FIH_BOOT_HOOK_REGULAR;
#ifdef FIH_ENABLE_GLOBAL_FAIL
/* Global failure handler - more resistant to unlooping. noinline and used are
* used to prevent optimization
*/
__attribute__((noinline)) __attribute__((used))
void fih_panic_loop(void);
#define FIH_PANIC fih_panic_loop()
#else
#define FIH_PANIC while (1) {}
#endif /* FIH_ENABLE_GLOBAL_FAIL */
/* NOTE: For functions to be inlined outside their compilation unit they have to
* have the body in the header file. This is required as function calls are easy
* to skip.
*/
#ifdef FIH_ENABLE_DELAY
/* Delaying logic, with randomness from a CSPRNG */
__attribute__((always_inline)) inline
int fih_delay(void)
{
unsigned char delay;
int foo = 0;
volatile int rc;
delay = fih_delay_random_uchar();
for (volatile int i = 0; i < delay; i++) {
foo++;
}
rc = 1;
/* rc is volatile so if it is the return value then the function cannot be
* optimized
*/
return rc;
}
#else
__attribute__((always_inline)) inline
int fih_delay_init(void)
{
return 1;
}
__attribute__((always_inline)) inline
int fih_delay(void)
{
return 1;
}
#endif /* FIH_ENABLE_DELAY */
#ifdef FIH_ENABLE_DOUBLE_VARS
__attribute__((always_inline)) inline
void fih_int_validate(fih_int x)
{
if (x.val != (x.msk ^ _fih_mask)) {
FIH_PANIC;
}
}
/* Convert a fih_int to an int. Validate for tampering. */
__attribute__((always_inline)) inline
int fih_int_decode(fih_int x)
{
fih_int_validate(x);
return x.val;
}
/* Convert an int to a fih_int, can be used to encode specific error codes. */
__attribute__((always_inline)) inline
fih_int fih_int_encode(int x)
{
fih_int ret = {x, x ^ _fih_mask};
return ret;
}
/* Standard equality. If A == B then 1, else 0 */
#define FIH_EQ(x, y) ((x == y) && fih_delay() && !(y != x))
#define FIH_NOT_EQ(x, y) ((x != y) || !fih_delay() || !(y == x))
#define FIH_SET(x, y) x = y; if(fih_delay() && (x != y)) FIH_PANIC
#else
/* NOOP */
__attribute__((always_inline)) inline
void fih_int_validate(fih_int x)
{
(void) x;
return;
}
/* NOOP */
__attribute__((always_inline)) inline
int fih_int_decode(fih_int x)
{
return x;
}
/* NOOP */
__attribute__((always_inline)) inline
fih_int fih_int_encode(int x)
{
return x;
}
#define FIH_EQ(x, y) (x == y)
#define FIH_NOT_EQ(x, y) (x != y)
#define FIH_SET(x, y) x = y
#endif /* FIH_ENABLE_DOUBLE_VARS */
#define FIH_DECLARE(var, val) \
fih_ret FIH_SET(var, val)
/* C has a common return pattern where 0 is a correct value and all others are
* errors. This function converts 0 to FIH_SUCCESS and any other number to a
* value that is not FIH_SUCCESS
*/
__attribute__((always_inline)) inline
fih_ret fih_ret_encode_zero_equality(int x)
{
if (x) {
return FIH_FAILURE;
} else {
return FIH_SUCCESS;
}
}
#ifdef FIH_ENABLE_CFI
extern fih_int _fih_cfi_ctr;
#endif /* FIH_ENABLE_CFI */
fih_int fih_cfi_get_and_increment(void);
void fih_cfi_validate(fih_int saved);
void fih_cfi_decrement(void);
/* Label for interacting with FIH testing tool. Can be parsed from the elf file
* after compilation. Does not require debug symbols.
*/
#if defined(__ICCARM__)
#define FIH_LABEL(str, lin, cnt) __asm volatile ("FIH_LABEL_" str "_" #lin "_" #cnt "::" ::);
#elif defined(__APPLE__)
#define FIH_LABEL(str) do {} while (0)
#else
#define FIH_LABEL(str) __asm volatile ("FIH_LABEL_" str "_%=:" ::);
#endif
/* Main FIH calling macro. return variable is second argument. Does some setup
* before and validation afterwards. Inserts labels for use with testing script.
*
* First perform the precall step - this gets the current value of the CFI
* counter and saves it to a local variable, and then increments the counter.
*
* Then set the return variable to FIH_FAILURE as a base case.
*
* Then perform the function call. As part of the funtion FIH_RET must be called
* which will decrement the counter.
*
* The postcall step gets the value of the counter and compares it to the
* previously saved value. If this is equal then the function call and all child
* function calls were performed.
*/
#if defined(__ICCARM__)
#define FIH_CALL(f, ret, ...) FIH_CALL2(f, ret, __LINE__, __COUNTER__, __VA_ARGS__)
#define FIH_CALL2(f, ret, l, c, ...) \
do { \
FIH_LABEL("FIH_CALL_START", l, c); \
FIH_CFI_PRECALL_BLOCK; \
ret = FIH_FAILURE; \
if (fih_delay()) { \
ret = f(__VA_ARGS__); \
} \
FIH_CFI_POSTCALL_BLOCK; \
FIH_LABEL("FIH_CALL_END", l, c); \
} while (0)
#else
#define FIH_CALL(f, ret, ...) \
do { \
FIH_LABEL("FIH_CALL_START"); \
FIH_CFI_PRECALL_BLOCK; \
ret = FIH_FAILURE; \
if (fih_delay()) { \
ret = f(__VA_ARGS__); \
} \
FIH_CFI_POSTCALL_BLOCK; \
FIH_LABEL("FIH_CALL_END"); \
} while (0)
#endif
/* FIH return changes the state of the internal state machine. If you do a
* FIH_CALL then you need to do a FIH_RET else the state machine will detect
* tampering and panic.
*/
#define FIH_RET(ret) \
do { \
FIH_CFI_PRERET; \
return ret; \
} while (0)
#ifdef FIH_ENABLE_CFI
/* Macro wrappers for functions - Even when the functions have zero body this
* saves a few bytes on noop functions as it doesn't generate the call/ret
*
* CFI precall function saves the CFI counter and then increments it - the
* postcall then checks if the counter is equal to the saved value. In order for
* this to be the case a FIH_RET must have been performed inside the called
* function in order to decrement the counter, so the function must have been
* called.
*/
#define FIH_CFI_PRECALL_BLOCK \
fih_int _fih_cfi_saved_value = fih_cfi_get_and_increment()
#define FIH_CFI_POSTCALL_BLOCK \
fih_cfi_validate(_fih_cfi_saved_value)
#define FIH_CFI_PRERET \
fih_cfi_decrement()
#else
#define FIH_CFI_PRECALL_BLOCK
#define FIH_CFI_POSTCALL_BLOCK
#define FIH_CFI_PRERET
#endif /* FIH_ENABLE_CFI */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __FAULT_INJECTION_HARDENING_H__ */

View File

@@ -0,0 +1,30 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#ifndef __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
#define __FAULT_INJECTION_HARDENING_DELAY_RNG_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* \brief Set up the RNG for use with random delays. Called once at startup.
*/
int fih_delay_init(void);
/**
* \brief Get a random unsigned char from an RNG seeded with an entropy source.
*
* \return A random value that fits inside an unsigned char.
*/
unsigned char fih_delay_random_uchar(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __FAULT_INJECTION_HARDENING_DELAY_RNG_H__ */

View File

@@ -0,0 +1,70 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_IGNORE_
#define H_IGNORE_
#ifdef __cplusplus
extern "C" {
#endif
/**
* These macros prevent the "set but not used" warnings for log writes below
* the log level.
*/
#define IGN_1(X) ((void)(X))
#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__)
#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__)
#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__)
#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__)
#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__)
#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__)
#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__)
#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__)
#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__)
#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__)
#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__)
#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__)
#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__)
#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__)
#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__)
#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__)
#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__)
#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__)
#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__)
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME
#define IGNORE(...) \
GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \
IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \
IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,228 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2016-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2023 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_IMAGE_
#define H_IMAGE_
#include <inttypes.h>
#include <stdbool.h>
#include "bootutil/fault_injection_hardening.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
struct flash_area;
#define IMAGE_MAGIC 0x96f3b83d
#define IMAGE_MAGIC_V1 0x96f3b83c
#define IMAGE_MAGIC_NONE 0xffffffff
#define IMAGE_TLV_INFO_MAGIC 0x6907
#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908
#define IMAGE_HEADER_SIZE 32
#define IMAGE_HASH_LEN 32 /* Size of SHA256 TLV hash */
/*
* Image header flags.
*/
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
#define IMAGE_F_ENCRYPTED_AES128 0x00000004 /* Encrypted using AES128. */
#define IMAGE_F_ENCRYPTED_AES256 0x00000008 /* Encrypted using AES256. */
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
/*
* Indicates that this image should be loaded into RAM instead of run
* directly from flash. The address to load should be in the
* ih_load_addr field of the header.
*/
#define IMAGE_F_RAM_LOAD 0x00000020
/*
* Indicates that ih_load_addr stores information on flash/ROM address the
* image has been built for.
*/
#define IMAGE_F_ROM_FIXED 0x00000100
/*
* Flags that indicate if the image data is compressed
*/
#define IMAGE_F_COMPRESSED_LZMA1 0x00000200
#define IMAGE_F_COMPRESSED_LZMA2 0x00000400
#define IMAGE_F_COMPRESSED_ARM_THUMB_FLT 0x00000800
/*
* ECSDA224 is with NIST P-224
* ECSDA256 is with NIST P-256
*/
/*
* Image trailer TLV types.
*
* Signature is generated by computing signature over the image hash.
*
* Signature comes in the form of 2 TLVs.
* 1st on identifies the public key which should be used to verify it.
* 2nd one is the actual signature.
*/
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
#define IMAGE_TLV_PUBKEY 0x02 /* public key */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */
#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */
#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */
#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
#define IMAGE_TLV_SIG_PURE 0x25 /* Indicator that attached signature has been prepared
* over image rather than its digest.
*/
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */
#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */
/* The following flags relate to compressed images and are for the decompressed image data */
#define IMAGE_TLV_DECOMP_SIZE 0x70 /* Decompressed image size excluding header/TLVs */
#define IMAGE_TLV_DECOMP_SHA 0x71 /*
* Decompressed image shaX hash, this field must match
* the format and size of the raw slot (compressed)
* shaX hash
*/
#define IMAGE_TLV_DECOMP_SIGNATURE 0x72 /*
* Decompressed image signature, this field must match
* the format and size of the raw slot (compressed)
* signature
*/
/*
* vendor reserved TLVs at xxA0-xxFF,
* where xx denotes the upper byte
* range. Examples:
* 0x00a0 - 0x00ff
* 0x01a0 - 0x01ff
* 0x02a0 - 0x02ff
* ...
* 0xffa0 - 0xfffe
*/
#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */
struct image_version {
uint8_t iv_major;
uint8_t iv_minor;
uint16_t iv_revision;
uint32_t iv_build_num;
} __packed;
struct image_dependency {
uint8_t image_id; /* Image index (from 0) */
uint8_t _pad1;
uint16_t _pad2;
struct image_version image_min_version; /* Indicates at minimum which
* version of firmware must be
* available to satisfy compliance
*/
};
/** Image header. All fields are in little endian byte order. */
struct image_header {
uint32_t ih_magic;
uint32_t ih_load_addr;
uint16_t ih_hdr_size; /* Size of image header (bytes). */
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
uint32_t ih_img_size; /* Does not include header. */
uint32_t ih_flags; /* IMAGE_F_[...]. */
struct image_version ih_ver;
uint32_t _pad1;
} __packed;
/** Image TLV header. All fields in little endian. */
struct image_tlv_info {
uint16_t it_magic;
uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */
} __packed;
/** Image trailer TLV format. All fields in little endian. */
struct image_tlv {
uint16_t it_type; /* IMAGE_TLV_[...]. */
uint16_t it_len; /* Data length (not including TLV header). */
} __packed;
#define ENCRYPTIONFLAGS (IMAGE_F_ENCRYPTED_AES128 | IMAGE_F_ENCRYPTED_AES256)
#define IS_ENCRYPTED(hdr) (((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES128) \
|| ((hdr)->ih_flags & IMAGE_F_ENCRYPTED_AES256))
#define MUST_DECRYPT(fap, idx, hdr) \
(flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_ENCRYPTED(hdr))
#define COMPRESSIONFLAGS (IMAGE_F_COMPRESSED_LZMA1 | IMAGE_F_COMPRESSED_LZMA2 \
| IMAGE_F_COMPRESSED_ARM_THUMB_FLT)
#define IS_COMPRESSED(hdr) ((hdr)->ih_flags & COMPRESSIONFLAGS)
#define MUST_DECOMPRESS(fap, idx, hdr) \
(flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_COMPRESSED(hdr))
_Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
"struct image_header not required size");
struct enc_key_data;
fih_ret bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr,
const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz,
uint8_t *seed, int seed_len, uint8_t *out_hash);
struct image_tlv_iter {
const struct image_header *hdr;
const struct flash_area *fap;
uint16_t type;
bool prot;
uint32_t prot_end;
uint32_t tlv_off;
uint32_t tlv_end;
};
int bootutil_tlv_iter_begin(struct image_tlv_iter *it,
const struct image_header *hdr,
const struct flash_area *fap, uint16_t type,
bool prot);
int bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off,
uint16_t *len, uint16_t *type);
int bootutil_tlv_iter_is_prot(struct image_tlv_iter *it, uint32_t off);
int32_t bootutil_get_img_security_cnt(struct image_header *hdr,
const struct flash_area *fap,
uint32_t *security_cnt);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022, Laird Connectivity
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_MCUBOOT_STATUS_
#define H_MCUBOOT_STATUS_
/* Enumeration representing the states that MCUboot can be in */
typedef enum
{
MCUBOOT_STATUS_STARTUP = 0,
MCUBOOT_STATUS_UPGRADING,
MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND,
MCUBOOT_STATUS_NO_BOOTABLE_IMAGE_FOUND,
MCUBOOT_STATUS_BOOT_FAILED,
MCUBOOT_STATUS_USB_DFU_WAITING,
MCUBOOT_STATUS_USB_DFU_ENTERED,
MCUBOOT_STATUS_USB_DFU_TIMED_OUT,
MCUBOOT_STATUS_SERIAL_DFU_ENTERED,
} mcuboot_status_type_t;
#if defined(CONFIG_MCUBOOT_ACTION_HOOKS)
extern void mcuboot_status_change(mcuboot_status_type_t status);
#else
#define mcuboot_status_change(_status) do {} while (0)
#endif
#endif /* H_MCUBOOT_STATUS_ */

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __RAMLOAD_H__
#define __RAMLOAD_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
/**
* Provides information about the Executable RAM for a given image ID.
*
* @param image_id Index of the image (from 0).
* @param exec_ram_start Pointer to store the start address of the exec RAM
* @param exec_ram_size Pointer to store the size of the exec RAM
*
* @return 0 on success; nonzero on failure.
*/
int boot_get_image_exec_ram_info(uint32_t image_id,
uint32_t *exec_ram_start,
uint32_t *exec_ram_size);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __RAMLOAD_H__ */

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2019-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __SECURITY_CNT_H__
#define __SECURITY_CNT_H__
/**
* @file security_cnt.h
*
* @note The interface must be implemented in a fail-safe way that is
* resistant to asynchronous power failures or it can use hardware
* counters that have this capability, if supported by the platform.
* When a counter incrementation was interrupted it must be able to
* continue the incrementation process or recover the previous consistent
* status of the counters. If the counters have reached a stable status
* (every counter incrementation operation has finished), from that point
* their value cannot decrease due to any kind of power failure.
*
* @note A security counter might be implemented using non-volatile OTP memory
* (i.e. fuses) in which case it is the responsibility of the platform
* code to map each possible security counter values onto the fuse bits
* as the direct usage of counter values can be costly / impractical.
*/
#include <stdint.h>
#include "bootutil/fault_injection_hardening.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Initialises the security counters.
*
* @return FIH_SUCCESS on success
*/
fih_ret boot_nv_security_counter_init(void);
/**
* Reads the stored value of a given image's security counter.
*
* @param image_id Index of the image (from 0).
* @param security_cnt Pointer to store the security counter value.
*
* @return FIH_SUCCESS on success
*/
fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt);
/**
* Updates the stored value of a given image's security counter with a new
* security counter value if the new one is greater.
*
* @param image_id Index of the image (from 0).
* @param img_security_cnt New security counter value. The new value must be
* between 0 and UINT32_MAX and it must be greater than
* or equal to the current security counter value.
*
* @return 0 on success; nonzero on failure.
*/
int32_t boot_nv_security_counter_update(uint32_t image_id,
uint32_t img_security_cnt);
#ifdef __cplusplus
}
#endif
#endif /* __SECURITY_CNT_H__ */

View File

@@ -0,0 +1,71 @@
/*
* 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 __BOOTUTIL_SIGN_KEY_H_
#define __BOOTUTIL_SIGN_KEY_H_
#include <stddef.h>
#include <stdint.h>
/* mcuboot_config.h is needed for MCUBOOT_HW_KEY to work */
#include "mcuboot_config/mcuboot_config.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MCUBOOT_HW_KEY
struct bootutil_key {
const uint8_t *key;
const unsigned int *len;
};
extern const struct bootutil_key bootutil_keys[];
#else
struct bootutil_key {
uint8_t *key;
unsigned int *len;
};
extern struct bootutil_key bootutil_keys[];
/**
* Retrieve the hash of the corresponding public key for image authentication.
*
* @param[in] image_index Index of the image to be authenticated.
* @param[out] public_key_hash Buffer to store the key-hash in.
* @param[in,out] key_hash_size As input the size of the buffer. As output
* the actual key-hash length.
*
* @return 0 on success; nonzero on failure.
*/
int boot_retrieve_public_key_hash(uint8_t image_index,
uint8_t *public_key_hash,
size_t *key_hash_size);
#endif /* !MCUBOOT_HW_KEY */
extern const int bootutil_key_cnt;
#ifdef __cplusplus
}
#endif
#endif /* __BOOTUTIL_SIGN_KEY_H_ */

View File

@@ -0,0 +1,65 @@
#
# 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.
#
pkg.name: boot/bootutil
pkg.description: The bootutil library performs most of the functions of a boot loader.
pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- boot
- bootloader
pkg.apis:
- bootloader
pkg.cflags:
- "-DMCUBOOT_MYNEWT=1"
pkg.cflags.BOOTUTIL_USE_MBED_TLS:
- '-DMBEDTLS_USER_CONFIG_FILE="mbedtls/config_mynewt.h"'
pkg.deps:
- "@mcuboot/boot/mynewt/mcuboot_config"
- "@apache-mynewt-core/hw/hal"
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/defs"
- "@mcuboot/boot/mynewt/flash_map_backend"
pkg.ign_files.BOOTUTIL_SINGLE_APPLICATION_SLOT:
- "loader.c"
- "swap_scratch.c"
pkg.deps.BOOTUTIL_USE_MBED_TLS:
- "@apache-mynewt-core/crypto/mbedtls"
pkg.deps.BOOTUTIL_USE_TINYCRYPT:
- "@mcuboot/ext/tinycrypt/lib"
- "@mcuboot/ext/mbedtls-asn1"
pkg.deps.BOOTUTIL_SIGN_ED25519:
- "@mcuboot/ext/tinycrypt/lib"
- "@mcuboot/ext/tinycrypt-sha512/lib"
- "@mcuboot/ext/mbedtls-asn1"
- "@mcuboot/ext/fiat"
pkg.deps.BOOTUTIL_ENCRYPT_X25519:
- "@mcuboot/ext/tinycrypt/lib"
- "@mcuboot/ext/tinycrypt-sha512/lib"
- "@mcuboot/ext/mbedtls-asn1"
- "@mcuboot/ext/fiat"

View File

@@ -0,0 +1,343 @@
/*
* Copyright (c) 2018-2023 Arm Limited
* Copyright (c) 2020 Linaro Limited
* Copyright (c) 2023, Nordic Semiconductor ASA
*
* 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.
*/
#include <stddef.h>
#include <stdint.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#include "bootutil/crypto/sha.h"
#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
#include "bootutil/boot_record.h"
#include "bootutil/boot_status.h"
#include "bootutil_priv.h"
#include "bootutil/image.h"
#include "flash_map_backend/flash_map_backend.h"
#if !defined(MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION)
/**
* @var shared_memory_init_done
*
* @brief Indicates whether shared memory area was already initialized.
*
*/
static bool shared_memory_init_done;
/* See in boot_record.h */
int
boot_add_data_to_shared_area(uint8_t major_type,
uint16_t minor_type,
size_t size,
const uint8_t *data)
{
struct shared_data_tlv_entry tlv_entry = {0};
struct shared_boot_data *boot_data;
uint16_t boot_data_size;
uintptr_t tlv_end, offset;
if (data == NULL) {
return SHARED_MEMORY_GEN_ERROR;
}
boot_data = (struct shared_boot_data *)MCUBOOT_SHARED_DATA_BASE;
/* Check whether first time to call this function. If does then initialise
* shared data area.
*/
if (!shared_memory_init_done) {
memset((void *)MCUBOOT_SHARED_DATA_BASE, 0, MCUBOOT_SHARED_DATA_SIZE);
boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
shared_memory_init_done = true;
}
/* Check whether TLV entry is already added.
* Get the boundaries of TLV section
*/
tlv_end = MCUBOOT_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
offset = MCUBOOT_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
/* Iterates over the TLV section looks for the same entry if found then
* returns with error: SHARED_MEMORY_OVERWRITE
*/
while (offset < tlv_end) {
/* Create local copy to avoid unaligned access */
memcpy(&tlv_entry, (const void *)offset, SHARED_DATA_ENTRY_HEADER_SIZE);
if (GET_MAJOR(tlv_entry.tlv_type) == major_type &&
GET_MINOR(tlv_entry.tlv_type) == minor_type) {
return SHARED_MEMORY_OVERWRITE;
}
offset += SHARED_DATA_ENTRY_SIZE(tlv_entry.tlv_len);
}
/* Add TLV entry */
tlv_entry.tlv_type = SET_TLV_TYPE(major_type, minor_type);
tlv_entry.tlv_len = size;
if (!boot_u16_safe_add(&boot_data_size, boot_data->header.tlv_tot_len,
SHARED_DATA_ENTRY_SIZE(size))) {
return SHARED_MEMORY_GEN_ERROR;
}
/* Verify overflow of shared area */
if (boot_data_size > MCUBOOT_SHARED_DATA_SIZE) {
return SHARED_MEMORY_OVERFLOW;
}
offset = tlv_end;
memcpy((void *)offset, &tlv_entry, SHARED_DATA_ENTRY_HEADER_SIZE);
offset += SHARED_DATA_ENTRY_HEADER_SIZE;
memcpy((void *)offset, data, size);
boot_data->header.tlv_tot_len += SHARED_DATA_ENTRY_SIZE(size);
return SHARED_MEMORY_OK;
}
#endif /* MCUBOOT_MEASURED_BOOT OR MCUBOOT_DATA_SHARING */
#endif /* !MCUBOOT_CUSTOM_DATA_SHARING_FUNCTION */
#ifdef MCUBOOT_MEASURED_BOOT
/* See in boot_record.h */
int
boot_save_boot_status(uint8_t sw_module,
const struct image_header *hdr,
const struct flash_area *fap)
{
struct image_tlv_iter it;
uint32_t offset;
uint16_t len;
uint16_t type;
uint16_t ias_minor;
size_t record_len = 0;
uint8_t image_hash[IMAGE_HASH_SIZE];
uint8_t buf[MAX_BOOT_RECORD_SZ];
bool boot_record_found = false;
bool hash_found = false;
int rc;
/* Manifest data is concatenated to the end of the image.
* It is encoded in TLV format.
*/
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
if (rc) {
return -1;
}
/* Traverse through the TLV area to find the boot record
* and image hash TLVs.
*/
while (true) {
rc = bootutil_tlv_iter_next(&it, &offset, &len, &type);
if (rc < 0) {
return -1;
} else if (rc > 0) {
break;
}
if (type == IMAGE_TLV_BOOT_RECORD) {
if (len > sizeof(buf)) {
return -1;
}
rc = flash_area_read(fap, offset, buf, len);
if (rc) {
return -1;
}
record_len = len;
boot_record_found = true;
} else if (type == EXPECTED_HASH_TLV) {
/* Get the image's hash value from the manifest section. */
if (len > sizeof(image_hash)) {
return -1;
}
rc = flash_area_read(fap, offset, image_hash, len);
if (rc) {
return -1;
}
hash_found = true;
/* The boot record TLV is part of the protected TLV area which is
* located before the other parts of the TLV area (including the
* image hash) so at this point it is okay to break the loop
* as the boot record TLV should have already been found.
*/
break;
}
}
if (!boot_record_found || !hash_found) {
return -1;
}
/* Ensure that we have enough in the record for the hash. This
* prevents an underflow in the calculation below.
*/
if (record_len < sizeof(image_hash)) {
return -1;
}
/* Update the measurement value (hash of the image) data item in the
* boot record. It is always the last item in the structure to make
* it easy to calculate its position.
* The image hash is computed over the image header, the image itself and
* the protected TLV area (which should already include the image hash as
* part of the boot record TLV). For this reason this field has been
* filled with zeros during the image signing process.
*/
offset = record_len - sizeof(image_hash);
/* The size of 'buf' has already been checked when
* the BOOT_RECORD TLV was read, it won't overflow.
*/
memcpy(buf + offset, image_hash, sizeof(image_hash));
/* Add the CBOR encoded boot record to the shared data area. */
ias_minor = SET_IAS_MINOR(sw_module, SW_BOOT_RECORD);
rc = boot_add_data_to_shared_area(TLV_MAJOR_IAS,
ias_minor,
record_len,
buf);
if (rc != SHARED_MEMORY_OK) {
return rc;
}
return 0;
}
#endif /* MCUBOOT_MEASURED_BOOT */
#ifdef MCUBOOT_DATA_SHARING_BOOTINFO
int boot_save_shared_data(const struct image_header *hdr, const struct flash_area *fap,
const uint8_t slot, const struct image_max_size *max_app_sizes)
{
int rc;
uint8_t image = 0;
#if defined(MCUBOOT_SINGLE_APPLICATION_SLOT)
uint8_t mode = MCUBOOT_MODE_SINGLE_SLOT;
#elif defined(MCUBOOT_SWAP_USING_SCRATCH)
uint8_t mode = MCUBOOT_MODE_SWAP_USING_SCRATCH;
#elif defined(MCUBOOT_OVERWRITE_ONLY)
uint8_t mode = MCUBOOT_MODE_UPGRADE_ONLY;
#elif defined(MCUBOOT_SWAP_USING_MOVE)
uint8_t mode = MCUBOOT_MODE_SWAP_USING_MOVE;
#elif defined(MCUBOOT_DIRECT_XIP)
#if defined(MCUBOOT_DIRECT_XIP_REVERT)
uint8_t mode = MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT;
#else
uint8_t mode = MCUBOOT_MODE_DIRECT_XIP;
#endif
#elif defined(MCUBOOT_RAM_LOAD)
uint8_t mode = MCUBOOT_MODE_RAM_LOAD;
#elif defined(MCUBOOT_FIRMWARE_LOADER)
uint8_t mode = MCUBOOT_MODE_FIRMWARE_LOADER;
#else
#error "Unknown mcuboot operating mode"
#endif
#if defined(MCUBOOT_SIGN_RSA)
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_RSA;
#elif defined(MCUBOOT_SIGN_EC256)
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ECDSA_P256;
#elif defined(MCUBOOT_SIGN_ED25519)
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_ED25519;
#else
uint8_t signature_type = MCUBOOT_SIGNATURE_TYPE_NONE;
#endif
#if defined(MCUBOOT_SERIAL_RECOVERY)
uint8_t recovery = MCUBOOT_RECOVERY_MODE_SERIAL_RECOVERY;
#elif defined(MCUBOOT_USB_DFU)
uint8_t recovery = MCUBOOT_RECOVERY_MODE_DFU;
#else
uint8_t recovery = MCUBOOT_RECOVERY_MODE_NONE;
#endif
#if defined(MCUBOOT_VERSION_AVAILABLE)
struct image_version mcuboot_version = {
.iv_major = MCUBOOT_VERSION_MAJOR,
.iv_minor = MCUBOOT_VERSION_MINOR,
#if defined(MCUBOOT_VERSION_PATCHLEVEL)
.iv_revision = MCUBOOT_VERSION_PATCHLEVEL,
#else
.iv_revision = 0,
#endif
#if defined(MCUBOOT_VERSION_TWEAK)
.iv_build_num = MCUBOOT_VERSION_TWEAK,
#else
.iv_build_num = 0,
#endif
};
#endif
/* Write out all fields */
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO, BLINFO_MODE,
sizeof(mode), &mode);
if (!rc) {
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
BLINFO_SIGNATURE_TYPE,
sizeof(signature_type),
&signature_type);
}
if (!rc) {
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
BLINFO_RECOVERY,
sizeof(recovery), &recovery);
}
if (!rc) {
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
BLINFO_RUNNING_SLOT,
sizeof(slot), (void *)&slot);
}
#if defined(MCUBOOT_VERSION_AVAILABLE)
if (!rc) {
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
BLINFO_BOOTLOADER_VERSION,
sizeof(mcuboot_version),
(void *)&mcuboot_version);
}
#endif
while (image < BOOT_IMAGE_NUMBER && !rc) {
if (max_app_sizes[image].calculated == true) {
rc = boot_add_data_to_shared_area(TLV_MAJOR_BLINFO,
(BLINFO_MAX_APPLICATION_SIZE + image),
sizeof(max_app_sizes[image].max_size),
(void *)&max_app_sizes[image].max_size);
}
++image;
}
return rc;
}
#endif /* MCUBOOT_DATA_SHARING_BOOTINFO */

View File

@@ -0,0 +1,357 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include <inttypes.h>
#include <stddef.h>
#include "sysflash/sysflash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "bootutil/image.h"
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "bootutil_misc.h"
#include "bootutil/bootutil_log.h"
#include "bootutil/fault_injection_hardening.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
BOOT_LOG_MODULE_DECLARE(mcuboot);
/* Currently only used by imgmgr */
int boot_current_slot;
/**
* @brief Determine if the data at two memory addresses is equal
*
* @param s1 The first memory region to compare.
* @param s2 The second memory region to compare.
* @param n The amount of bytes to compare.
*
* @note This function does not comply with the specification of memcmp,
* so should not be considered a drop-in replacement. It has no
* constant time execution. The point is to make sure that all the
* bytes are compared and detect if loop was abused and some cycles
* was skipped due to fault injection.
*
* @return FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
*/
#ifdef MCUBOOT_FIH_PROFILE_OFF
inline
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
{
return memcmp(s1, s2, n);
}
#else
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n)
{
size_t i;
uint8_t *s1_p = (uint8_t*) s1;
uint8_t *s2_p = (uint8_t*) s2;
FIH_DECLARE(ret, FIH_FAILURE);
for (i = 0; i < n; i++) {
if (s1_p[i] != s2_p[i]) {
goto out;
}
}
if (i == n) {
ret = FIH_SUCCESS;
}
out:
FIH_RET(ret);
}
#endif
/*
* Amount of space used to save information required when doing a swap,
* or while a swap is under progress, but not the status of sector swap
* progress itself.
*/
static inline uint32_t
boot_trailer_info_sz(void)
{
return (
#ifdef MCUBOOT_ENC_IMAGES
/* encryption keys */
# if MCUBOOT_SWAP_SAVE_ENCTLV
BOOT_ENC_TLV_ALIGN_SIZE * 2 +
# else
BOOT_ENC_KEY_ALIGN_SIZE * 2 +
# endif
#endif
/* swap_type + copy_done + image_ok + swap_size */
BOOT_MAX_ALIGN * 4 +
BOOT_MAGIC_ALIGN_SIZE
);
}
/*
* Amount of space used to maintain progress information for a single swap
* operation.
*/
static inline uint32_t
boot_status_entry_sz(uint32_t min_write_sz)
{
return BOOT_STATUS_STATE_COUNT * min_write_sz;
}
uint32_t
boot_status_sz(uint32_t min_write_sz)
{
return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz);
}
uint32_t
boot_trailer_sz(uint32_t min_write_sz)
{
return boot_status_sz(min_write_sz) + boot_trailer_info_sz();
}
#if MCUBOOT_SWAP_USING_SCRATCH
/*
* Similar to `boot_trailer_sz` but this function returns the space used to
* store status in the scratch partition. The scratch partition only stores
* status during the swap of the last sector from primary/secondary (which
* is the first swap operation) and thus only requires space for one swap.
*/
static uint32_t
boot_scratch_trailer_sz(uint32_t min_write_sz)
{
return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz();
}
#endif
int
boot_status_entries(int image_index, const struct flash_area *fap)
{
#if MCUBOOT_SWAP_USING_SCRATCH
if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SCRATCH) {
return BOOT_STATUS_STATE_COUNT;
} else
#endif
if (flash_area_get_id(fap) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
return BOOT_STATUS_STATE_COUNT * BOOT_STATUS_MAX_ENTRIES;
}
return -1;
}
uint32_t
boot_status_off(const struct flash_area *fap)
{
uint32_t off_from_end;
uint32_t elem_sz;
elem_sz = flash_area_align(fap);
#if MCUBOOT_SWAP_USING_SCRATCH
if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
off_from_end = boot_scratch_trailer_sz(elem_sz);
} else {
#endif
off_from_end = boot_trailer_sz(elem_sz);
#if MCUBOOT_SWAP_USING_SCRATCH
}
#endif
assert(off_from_end <= flash_area_get_size(fap));
return flash_area_get_size(fap) - off_from_end;
}
#ifdef MCUBOOT_ENC_IMAGES
static inline uint32_t
boot_enc_key_off(const struct flash_area *fap, uint8_t slot)
{
#if MCUBOOT_SWAP_SAVE_ENCTLV
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_TLV_ALIGN_SIZE);
#else
return boot_swap_size_off(fap) - ((slot + 1) * BOOT_ENC_KEY_ALIGN_SIZE);
#endif
}
#endif
/**
* This functions tries to locate the status area after an aborted swap,
* by looking for the magic in the possible locations.
*
* If the magic is successfully found, a flash_area * is returned and it
* is the responsibility of the called to close it.
*
* @returns 0 on success, -1 on errors
*/
int
boot_find_status(int image_index, const struct flash_area **fap)
{
uint8_t areas[] = {
#if MCUBOOT_SWAP_USING_SCRATCH
FLASH_AREA_IMAGE_SCRATCH,
#endif
FLASH_AREA_IMAGE_PRIMARY(image_index),
};
unsigned int i;
/*
* In the middle a swap, tries to locate the area that is currently
* storing a valid magic, first on the primary slot, then on scratch.
* Both "slots" can end up being temporary storage for a swap and it
* is assumed that if magic is valid then other metadata is too,
* because magic is always written in the last step.
*/
for (i = 0; i < sizeof(areas) / sizeof(areas[0]); i++) {
uint8_t magic[BOOT_MAGIC_SZ];
if (flash_area_open(areas[i], fap)) {
break;
}
if (flash_area_read(*fap, boot_magic_off(*fap), magic, BOOT_MAGIC_SZ)) {
flash_area_close(*fap);
break;
}
if (BOOT_MAGIC_GOOD == boot_magic_decode(magic)) {
return 0;
}
flash_area_close(*fap);
}
/* If we got here, no magic was found */
fap = NULL;
return -1;
}
int
boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size)
{
uint32_t off;
int rc;
off = boot_swap_size_off(fap);
rc = flash_area_read(fap, off, swap_size, sizeof *swap_size);
return rc;
}
#ifdef MCUBOOT_ENC_IMAGES
int
boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs)
{
uint32_t off;
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint32_t i;
#endif
int rc;
off = boot_enc_key_off(fap, slot);
#if MCUBOOT_SWAP_SAVE_ENCTLV
rc = flash_area_read(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
if (rc == 0) {
for (i = 0; i < BOOT_ENC_TLV_ALIGN_SIZE; i++) {
if (bs->enctlv[slot][i] != 0xff) {
break;
}
}
/* Only try to decrypt non-erased TLV metadata */
if (i != BOOT_ENC_TLV_ALIGN_SIZE) {
rc = boot_decrypt_key(bs->enctlv[slot], bs->enckey[slot]);
}
}
#else
rc = flash_area_read(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
#endif
return rc;
}
#endif
int
boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size)
{
uint32_t off;
off = boot_swap_size_off(fap);
BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%lx (0x%lx)",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)flash_area_get_off(fap) + off);
return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4);
}
#ifdef MCUBOOT_ENC_IMAGES
int
boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
const struct boot_status *bs)
{
uint32_t off;
int rc;
off = boot_enc_key_off(fap, slot);
BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)flash_area_get_off(fap) + off);
#if MCUBOOT_SWAP_SAVE_ENCTLV
rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE);
#else
rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE);
#endif
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
#endif
uint32_t bootutil_max_image_size(const struct flash_area *fap)
{
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \
defined(MCUBOOT_FIRMWARE_LOADER)
return boot_status_off(fap);
#elif defined(MCUBOOT_SWAP_USING_MOVE)
struct flash_sector sector;
/* get the last sector offset */
int rc = flash_area_get_sector(fap, boot_status_off(fap), &sector);
if (rc) {
BOOT_LOG_ERR("Unable to determine flash sector of the image trailer");
return 0; /* Returning of zero here should cause any check which uses
* this value to fail.
*/
}
return flash_sector_get_off(&sector);
#elif defined(MCUBOOT_OVERWRITE_ONLY)
return boot_swap_info_off(fap);
#elif defined(MCUBOOT_DIRECT_XIP)
return boot_swap_info_off(fap);
#elif defined(MCUBOOT_RAM_LOAD)
return boot_swap_info_off(fap);
#endif
}

View File

@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
*/
#ifndef H_BOOTUTIL_MISC_
#define H_BOOTUTIL_MISC_
#include <string.h>
#include <inttypes.h>
#include <stddef.h>
#include "bootutil/bootutil_public.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
static int
boot_magic_decode(const uint8_t *magic)
{
if (memcmp(magic, BOOT_IMG_MAGIC, BOOT_MAGIC_SZ) == 0) {
return BOOT_MAGIC_GOOD;
}
return BOOT_MAGIC_BAD;
}
static inline uint32_t
boot_magic_off(const struct flash_area *fap)
{
return flash_area_get_size(fap) - BOOT_MAGIC_SZ;
}
static inline uint32_t
boot_image_ok_off(const struct flash_area *fap)
{
return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
}
static inline uint32_t
boot_copy_done_off(const struct flash_area *fap)
{
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
}
static inline uint32_t
boot_swap_size_off(const struct flash_area *fap)
{
return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
}
#endif /* H_BOOTUTIL_MISC_ */

View File

@@ -0,0 +1,486 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2020 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef H_BOOTUTIL_PRIV_
#define H_BOOTUTIL_PRIV_
#include <string.h>
#include "sysflash/sysflash.h"
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "bootutil/fault_injection_hardening.h"
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct flash_area;
#define BOOT_TMPBUF_SZ 256
/** Number of image slots in flash; currently limited to two. */
#define BOOT_NUM_SLOTS 2
#if (defined(MCUBOOT_OVERWRITE_ONLY) + \
defined(MCUBOOT_SWAP_USING_MOVE) + \
defined(MCUBOOT_DIRECT_XIP) + \
defined(MCUBOOT_RAM_LOAD) + \
defined(MCUBOOT_FIRMWARE_LOADER) + \
defined(MCUBOOT_SWAP_USING_SCRATCH)) > 1
#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY, MCUBOOT_SWAP_USING_MOVE, MCUBOOT_DIRECT_XIP, MCUBOOT_RAM_LOAD or MCUBOOT_FIRMWARE_LOADER"
#endif
#if !defined(MCUBOOT_DIRECT_XIP) && \
defined(MCUBOOT_DIRECT_XIP_REVERT)
#error "MCUBOOT_DIRECT_XIP_REVERT cannot be enabled unless MCUBOOT_DIRECT_XIP is used"
#endif
#if !defined(MCUBOOT_OVERWRITE_ONLY) && \
!defined(MCUBOOT_SWAP_USING_MOVE) && \
!defined(MCUBOOT_DIRECT_XIP) && \
!defined(MCUBOOT_RAM_LOAD) && \
!defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \
!defined(MCUBOOT_FIRMWARE_LOADER)
#define MCUBOOT_SWAP_USING_SCRATCH 1
#endif
#define BOOT_STATUS_OP_MOVE 1
#define BOOT_STATUS_OP_SWAP 2
/*
* Maintain state of copy progress.
*/
struct boot_status {
uint32_t idx; /* Which area we're operating on */
uint8_t state; /* Which part of the swapping process are we at */
uint8_t op; /* What operation are we performing? */
uint8_t use_scratch; /* Are status bytes ever written to scratch? */
uint8_t swap_type; /* The type of swap in effect */
uint32_t swap_size; /* Total size of swapped image */
#ifdef MCUBOOT_ENC_IMAGES
uint8_t enckey[BOOT_NUM_SLOTS][BOOT_ENC_KEY_ALIGN_SIZE];
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint8_t enctlv[BOOT_NUM_SLOTS][BOOT_ENC_TLV_ALIGN_SIZE];
#endif
#endif
int source; /* Which slot contains swap status metadata */
};
#define BOOT_STATUS_IDX_0 1
#define BOOT_STATUS_STATE_0 1
#define BOOT_STATUS_STATE_1 2
#define BOOT_STATUS_STATE_2 3
/**
* End-of-image slot structure.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ ~
* ~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * 3) ~
* ~ ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Encryption key 0 (16 octets) [*] |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0xff padding as needed |
* | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 0) [*] |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Encryption key 1 (16 octets) [*] |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0xff padding as needed |
* | (BOOT_MAX_ALIGN minus 16 octets from Encryption key 1) [*] |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Swap size (4 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0xff padding as needed |
* | (BOOT_MAX_ALIGN minus 4 octets from Swap size) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Swap info | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Copy done | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Image OK | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | 0xff padding as needed |
* | (BOOT_MAX_ALIGN minus 16 octets from MAGIC) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | MAGIC (16 octets) |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* [*]: Only present if the encryption option is enabled
* (`MCUBOOT_ENC_IMAGES`).
*/
union boot_img_magic_t
{
struct {
uint16_t align;
uint8_t magic[14];
};
uint8_t val[16];
};
extern const union boot_img_magic_t boot_img_magic;
#define BOOT_IMG_MAGIC (boot_img_magic.val)
#if BOOT_MAX_ALIGN == 8
#define BOOT_IMG_ALIGN (BOOT_MAX_ALIGN)
#else
#define BOOT_IMG_ALIGN (boot_img_magic.align)
#endif
_Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image magic");
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
#define ARE_SLOTS_EQUIVALENT() 0
#else
#define ARE_SLOTS_EQUIVALENT() 1
#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_ENC_IMAGES)
#error "Image encryption (MCUBOOT_ENC_IMAGES) is not supported when MCUBOOT_DIRECT_XIP is selected."
#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_ENC_IMAGES */
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS
#define BOOT_LOG_IMAGE_INFO(slot, hdr) \
BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \
((slot) == BOOT_PRIMARY_SLOT) ? "Primary" : "Secondary", \
(hdr)->ih_ver.iv_major, \
(hdr)->ih_ver.iv_minor, \
(hdr)->ih_ver.iv_revision, \
(hdr)->ih_ver.iv_build_num)
#if MCUBOOT_SWAP_USING_MOVE
#define BOOT_STATUS_MOVE_STATE_COUNT 1
#define BOOT_STATUS_SWAP_STATE_COUNT 2
#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT)
#else
#define BOOT_STATUS_STATE_COUNT 3
#endif
/** Maximum number of image sectors supported by the bootloader. */
#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS
#define BOOT_PRIMARY_SLOT 0
#define BOOT_SECONDARY_SLOT 1
#define BOOT_STATUS_SOURCE_NONE 0
#define BOOT_STATUS_SOURCE_SCRATCH 1
#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2
/**
* Compatibility shim for flash sector type.
*
* This can be deleted when flash_area_to_sectors() is removed.
*/
#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
typedef struct flash_sector boot_sector_t;
#else
typedef struct flash_area boot_sector_t;
#endif
/** Private state maintained during boot. */
struct boot_loader_state {
struct {
struct image_header hdr;
const struct flash_area *area;
boot_sector_t *sectors;
uint32_t num_sectors;
} imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
#if MCUBOOT_SWAP_USING_SCRATCH
struct {
const struct flash_area *area;
boot_sector_t *sectors;
uint32_t num_sectors;
} scratch;
#endif
uint8_t swap_type[BOOT_IMAGE_NUMBER];
uint32_t write_sz;
#if defined(MCUBOOT_ENC_IMAGES)
struct enc_key_data enc[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS];
#endif
#if (BOOT_IMAGE_NUMBER > 1)
uint8_t curr_img_idx;
bool img_mask[BOOT_IMAGE_NUMBER];
#endif
#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
struct slot_usage_t {
/* Index of the slot chosen to be loaded */
uint32_t active_slot;
bool slot_available[BOOT_NUM_SLOTS];
#if defined(MCUBOOT_RAM_LOAD)
/* Image destination and size for the active slot */
uint32_t img_dst;
uint32_t img_sz;
#elif defined(MCUBOOT_DIRECT_XIP_REVERT)
/* Swap status for the active slot */
struct boot_swap_state swap_state;
#endif
} slot_usage[BOOT_IMAGE_NUMBER];
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
};
fih_ret bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
size_t slen, uint8_t key_id);
fih_ret bootutil_verify_img(const uint8_t *img, uint32_t size,
uint8_t *sig, size_t slen, uint8_t key_id);
fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n);
int boot_find_status(int image_index, const struct flash_area **fap);
int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val);
uint32_t boot_status_sz(uint32_t min_write_sz);
uint32_t boot_trailer_sz(uint32_t min_write_sz);
int boot_status_entries(int image_index, const struct flash_area *fap);
uint32_t boot_status_off(const struct flash_area *fap);
int boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state);
int boot_read_swap_state_by_id(int flash_area_id,
struct boot_swap_state *state);
int boot_write_magic(const struct flash_area *fap);
int boot_write_status(const struct boot_loader_state *state, struct boot_status *bs);
int boot_write_copy_done(const struct flash_area *fap);
int boot_write_image_ok(const struct flash_area *fap);
int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num);
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
int boot_write_trailer(const struct flash_area *fap, uint32_t off,
const uint8_t *inbuf, uint8_t inlen);
int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
uint8_t flag_val);
int boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size);
int boot_slots_compatible(struct boot_loader_state *state);
uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz);
int boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs);
int boot_copy_region(struct boot_loader_state *state,
const struct flash_area *fap_src,
const struct flash_area *fap_dst,
uint32_t off_src, uint32_t off_dst, uint32_t sz);
int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
bool boot_status_is_reset(const struct boot_status *bs);
#ifdef MCUBOOT_ENC_IMAGES
int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
const struct boot_status *bs);
int boot_read_enc_key(const struct flash_area *fap, uint8_t slot,
struct boot_status *bs);
#endif
/**
* Checks that a buffer is erased according to what the erase value for the
* flash device provided in `flash_area` is.
*
* @returns true if the buffer is erased; false if any of the bytes is not
* erased, or when buffer is NULL, or when len == 0.
*/
bool bootutil_buffer_is_erased(const struct flash_area *area,
const void *buffer, size_t len);
/**
* Safe (non-overflowing) uint32_t addition. Returns true, and stores
* the result in *dest if it can be done without overflow. Otherwise,
* returns false.
*/
static inline bool boot_u32_safe_add(uint32_t *dest, uint32_t a, uint32_t b)
{
/*
* "a + b <= UINT32_MAX", subtract 'b' from both sides to avoid
* the overflow.
*/
if (a > UINT32_MAX - b) {
return false;
} else {
*dest = a + b;
return true;
}
}
/**
* Safe (non-overflowing) uint16_t addition. Returns true, and stores
* the result in *dest if it can be done without overflow. Otherwise,
* returns false.
*/
static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b)
{
uint32_t tmp = a + b;
if (tmp > UINT16_MAX) {
return false;
} else {
*dest = tmp;
return true;
}
}
/*
* Accessors for the contents of struct boot_loader_state.
*/
/* These are macros so they can be used as lvalues. */
#if (BOOT_IMAGE_NUMBER > 1)
#define BOOT_CURR_IMG(state) ((state)->curr_img_idx)
#else
#define BOOT_CURR_IMG(state) 0
#endif
#ifdef MCUBOOT_ENC_IMAGES
#define BOOT_CURR_ENC(state) ((state)->enc[BOOT_CURR_IMG(state)])
#else
#define BOOT_CURR_ENC(state) NULL
#endif
#define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)])
#define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area)
#define BOOT_WRITE_SZ(state) ((state)->write_sz)
#define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)])
#define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size)
#define BOOT_IS_UPGRADE(swap_type) \
(((swap_type) == BOOT_SWAP_TYPE_TEST) || \
((swap_type) == BOOT_SWAP_TYPE_REVERT) || \
((swap_type) == BOOT_SWAP_TYPE_PERM))
static inline struct image_header*
boot_img_hdr(struct boot_loader_state *state, size_t slot)
{
return &BOOT_IMG(state, slot).hdr;
}
static inline size_t
boot_img_num_sectors(const struct boot_loader_state *state, size_t slot)
{
return BOOT_IMG(state, slot).num_sectors;
}
/*
* Offset of the slot from the beginning of the flash device.
*/
static inline uint32_t
boot_img_slot_off(struct boot_loader_state *state, size_t slot)
{
return flash_area_get_off(BOOT_IMG(state, slot).area);
}
#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
static inline size_t
boot_img_sector_size(const struct boot_loader_state *state,
size_t slot, size_t sector)
{
return flash_area_get_size(&BOOT_IMG(state, slot).sectors[sector]);
}
/*
* Offset of the sector from the beginning of the image, NOT the flash
* device.
*/
static inline uint32_t
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
size_t sector)
{
return flash_area_get_off(&BOOT_IMG(state, slot).sectors[sector]) -
flash_area_get_off(&BOOT_IMG(state, slot).sectors[0]);
}
#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
static inline size_t
boot_img_sector_size(const struct boot_loader_state *state,
size_t slot, size_t sector)
{
return flash_sector_get_size(&BOOT_IMG(state, slot).sectors[sector]);
}
static inline uint32_t
boot_img_sector_off(const struct boot_loader_state *state, size_t slot,
size_t sector)
{
return flash_sector_get_off(&BOOT_IMG(state, slot).sectors[sector]) -
flash_sector_get_off(&BOOT_IMG(state, slot).sectors[0]);
}
#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
#ifdef MCUBOOT_RAM_LOAD
# ifdef __BOOTSIM__
/* Query for the layout of a RAM buffer appropriate for holding the
* image. This will be per-test-thread, and therefore must be queried
* through this call. */
struct bootsim_ram_info {
uint32_t start;
uint32_t size;
uintptr_t base;
};
struct bootsim_ram_info *bootsim_get_ram_info(void);
#define IMAGE_GET_FIELD(field) (bootsim_get_ram_info()->field)
#define IMAGE_RAM_BASE IMAGE_GET_FIELD(base)
#define IMAGE_EXECUTABLE_RAM_START IMAGE_GET_FIELD(start)
#define IMAGE_EXECUTABLE_RAM_SIZE IMAGE_GET_FIELD(size)
# else
# define IMAGE_RAM_BASE ((uintptr_t)0)
# endif
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
(memcpy((output),(void*)(IMAGE_RAM_BASE + (hdr)->ih_load_addr + (start)), \
(size)), 0)
#else
#define IMAGE_RAM_BASE ((uintptr_t)0)
#define LOAD_IMAGE_DATA(hdr, fap, start, output, size) \
(flash_area_read((fap), (start), (output), (size)))
#endif /* MCUBOOT_RAM_LOAD */
uint32_t bootutil_max_image_size(const struct flash_area *fap);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,762 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2023 Arm Limited
* Copyright (c) 2020-2023 Nordic Semiconductor ASA
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* @file
* @brief Public MCUBoot interface API implementation
*
* This file contains API implementation which can be combined with
* the application in order to interact with the MCUBoot bootloader.
* This file contains shared code-base betwen MCUBoot and the application
* which controls DFU process.
*/
#include <string.h>
#include <inttypes.h>
#include <stddef.h>
#include "sysflash/sysflash.h"
#include "flash_map_backend/flash_map_backend.h"
#include "bootutil/image.h"
#include "bootutil/bootutil_public.h"
#include "bootutil/bootutil_log.h"
#include "bootutil/boot_public_hooks.h"
#include "bootutil_priv.h"
#include "bootutil_misc.h"
#ifdef CONFIG_MCUBOOT
BOOT_LOG_MODULE_DECLARE(mcuboot);
#else
BOOT_LOG_MODULE_REGISTER(mcuboot_util);
#endif
#if BOOT_MAX_ALIGN == 8
const union boot_img_magic_t boot_img_magic = {
.val = {
0x77, 0xc2, 0x95, 0xf3,
0x60, 0xd2, 0xef, 0x7f,
0x35, 0x52, 0x50, 0x0f,
0x2c, 0xb6, 0x79, 0x80
}
};
#else
const union boot_img_magic_t boot_img_magic = {
.align = BOOT_MAX_ALIGN,
.magic = {
0x2d, 0xe1,
0x5d, 0x29, 0x41, 0x0b,
0x8d, 0x77, 0x67, 0x9c,
0x11, 0x0f, 0x1f, 0x8a
}
};
#endif
struct boot_swap_table {
uint8_t magic_primary_slot;
uint8_t magic_secondary_slot;
uint8_t image_ok_primary_slot;
uint8_t image_ok_secondary_slot;
uint8_t copy_done_primary_slot;
uint8_t swap_type;
};
/**
* This set of tables maps image trailer contents to swap operation type.
* When searching for a match, these tables must be iterated sequentially.
*
* NOTE: the table order is very important. The settings in the secondary
* slot always are priority to the primary slot and should be located
* earlier in the table.
*
* The table lists only states where there is action needs to be taken by
* the bootloader, as in starting/finishing a swap operation.
*/
static const struct boot_swap_table boot_swap_tables[] = {
{
.magic_primary_slot = BOOT_MAGIC_ANY,
.magic_secondary_slot = BOOT_MAGIC_GOOD,
.image_ok_primary_slot = BOOT_FLAG_ANY,
.image_ok_secondary_slot = BOOT_FLAG_UNSET,
.copy_done_primary_slot = BOOT_FLAG_ANY,
.swap_type = BOOT_SWAP_TYPE_TEST,
},
{
.magic_primary_slot = BOOT_MAGIC_ANY,
.magic_secondary_slot = BOOT_MAGIC_GOOD,
.image_ok_primary_slot = BOOT_FLAG_ANY,
.image_ok_secondary_slot = BOOT_FLAG_SET,
.copy_done_primary_slot = BOOT_FLAG_ANY,
.swap_type = BOOT_SWAP_TYPE_PERM,
},
{
.magic_primary_slot = BOOT_MAGIC_GOOD,
.magic_secondary_slot = BOOT_MAGIC_UNSET,
.image_ok_primary_slot = BOOT_FLAG_UNSET,
.image_ok_secondary_slot = BOOT_FLAG_ANY,
.copy_done_primary_slot = BOOT_FLAG_SET,
.swap_type = BOOT_SWAP_TYPE_REVERT,
},
};
#define BOOT_SWAP_TABLES_COUNT \
(sizeof boot_swap_tables / sizeof boot_swap_tables[0])
static int
boot_flag_decode(uint8_t flag)
{
if (flag != BOOT_FLAG_SET) {
return BOOT_FLAG_BAD;
}
return BOOT_FLAG_SET;
}
uint32_t
boot_swap_info_off(const struct flash_area *fap)
{
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
}
/**
* Determines if a status source table is satisfied by the specified magic
* code.
*
* @param tbl_val A magic field from a status source table.
* @param val The magic value in a trailer, encoded as a
* BOOT_MAGIC_[...].
*
* @return 1 if the two values are compatible;
* 0 otherwise.
*/
int
boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
{
switch (tbl_val) {
case BOOT_MAGIC_ANY:
return 1;
case BOOT_MAGIC_NOTGOOD:
return val != BOOT_MAGIC_GOOD;
default:
return tbl_val == val;
}
}
bool bootutil_buffer_is_erased(const struct flash_area *area,
const void *buffer, size_t len)
{
size_t i;
uint8_t *u8b;
uint8_t erased_val;
if (buffer == NULL || len == 0) {
return false;
}
erased_val = flash_area_erased_val(area);
for (i = 0, u8b = (uint8_t *)buffer; i < len; i++) {
if (u8b[i] != erased_val) {
return false;
}
}
return true;
}
static int
boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
{
int rc;
rc = flash_area_read(fap, off, flag, sizeof *flag);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, flag, sizeof *flag)) {
*flag = BOOT_FLAG_UNSET;
} else {
*flag = boot_flag_decode(*flag);
}
return 0;
}
static inline int
boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done)
{
return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
}
int
boot_read_swap_state(const struct flash_area *fap,
struct boot_swap_state *state)
{
uint8_t magic[BOOT_MAGIC_SZ];
uint32_t off;
uint8_t swap_info;
int rc;
off = boot_magic_off(fap);
rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, magic, BOOT_MAGIC_SZ)) {
state->magic = BOOT_MAGIC_UNSET;
} else {
state->magic = boot_magic_decode(magic);
}
off = boot_swap_info_off(fap);
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
if (rc < 0) {
return BOOT_EFLASH;
}
/* Extract the swap type and image number */
state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info) ||
state->swap_type > BOOT_SWAP_TYPE_REVERT) {
state->swap_type = BOOT_SWAP_TYPE_NONE;
state->image_num = 0;
}
rc = boot_read_copy_done(fap, &state->copy_done);
if (rc) {
return BOOT_EFLASH;
}
return boot_read_image_ok(fap, &state->image_ok);
}
int
boot_read_swap_state_by_id(int flash_area_id, struct boot_swap_state *state)
{
const struct flash_area *fap;
int rc;
rc = flash_area_open(flash_area_id, &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_read_swap_state(fap, state);
flash_area_close(fap);
return rc;
}
int
boot_write_magic(const struct flash_area *fap)
{
uint32_t off;
uint32_t pad_off;
int rc;
uint8_t magic[BOOT_MAGIC_ALIGN_SIZE];
uint8_t erased_val;
off = boot_magic_off(fap);
/* image_trailer structure was modified with additional padding such that
* the pad+magic ends up in a flash minimum write region. The address
* returned by boot_magic_off() is the start of magic which is not the
* start of the flash write boundary and thus writes to the magic will fail.
* To account for this change, write to magic is first padded with 0xFF
* before writing to the trailer.
*/
pad_off = ALIGN_DOWN(off, BOOT_MAX_ALIGN);
erased_val = flash_area_erased_val(fap);
memset(&magic[0], erased_val, sizeof(magic));
memcpy(&magic[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ], BOOT_IMG_MAGIC, BOOT_MAGIC_SZ);
BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)(flash_area_get_off(fap) + off));
rc = flash_area_write(fap, pad_off, &magic[0], BOOT_MAGIC_ALIGN_SIZE);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
/**
* Write trailer data; status bytes, swap_size, etc
*
* @returns 0 on success, != 0 on error.
*/
int
boot_write_trailer(const struct flash_area *fap, uint32_t off,
const uint8_t *inbuf, uint8_t inlen)
{
uint8_t buf[BOOT_MAX_ALIGN];
uint8_t erased_val;
uint32_t align;
int rc;
align = flash_area_align(fap);
align = ALIGN_UP(inlen, align);
if (align > BOOT_MAX_ALIGN) {
return -1;
}
erased_val = flash_area_erased_val(fap);
memcpy(buf, inbuf, inlen);
memset(&buf[inlen], erased_val, align - inlen);
rc = flash_area_write(fap, off, buf, align);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
int
boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
uint8_t flag_val)
{
const uint8_t buf[1] = { flag_val };
return boot_write_trailer(fap, off, buf, 1);
}
int
boot_write_image_ok(const struct flash_area *fap)
{
uint32_t off;
off = boot_image_ok_off(fap);
BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%lx (0x%lx)",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)(flash_area_get_off(fap) + off));
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
}
int
boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok)
{
return boot_read_flag(fap, image_ok, boot_image_ok_off(fap));
}
/**
* Writes the specified value to the `swap-type` field of an image trailer.
* This value is persisted so that the boot loader knows what swap operation to
* resume in case of an unexpected reset.
*/
int
boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num)
{
uint32_t off;
uint8_t swap_info;
BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
off = boot_swap_info_off(fap);
BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%lx (0x%lx), swap_type=0x%x"
" image_num=0x%x",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)(flash_area_get_off(fap) + off),
swap_type, image_num);
return boot_write_trailer(fap, off, (const uint8_t *) &swap_info, 1);
}
int
boot_swap_type_multi(int image_index)
{
const struct boot_swap_table *table;
struct boot_swap_state primary_slot;
struct boot_swap_state secondary_slot;
int rc;
size_t i;
rc = BOOT_HOOK_CALL(boot_read_swap_state_primary_slot_hook,
BOOT_HOOK_REGULAR, image_index, &primary_slot);
if (rc == BOOT_HOOK_REGULAR)
{
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&primary_slot);
}
if (rc) {
return BOOT_SWAP_TYPE_PANIC;
}
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&secondary_slot);
if (rc == BOOT_EFLASH) {
BOOT_LOG_INF("Secondary image of image pair (%d.) "
"is unreachable. Treat it as empty", image_index);
secondary_slot.magic = BOOT_MAGIC_UNSET;
secondary_slot.swap_type = BOOT_SWAP_TYPE_NONE;
secondary_slot.copy_done = BOOT_FLAG_UNSET;
secondary_slot.image_ok = BOOT_FLAG_UNSET;
secondary_slot.image_num = 0;
} else if (rc) {
return BOOT_SWAP_TYPE_PANIC;
}
for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
table = boot_swap_tables + i;
if (boot_magic_compatible_check(table->magic_primary_slot,
primary_slot.magic) &&
boot_magic_compatible_check(table->magic_secondary_slot,
secondary_slot.magic) &&
(table->image_ok_primary_slot == BOOT_FLAG_ANY ||
table->image_ok_primary_slot == primary_slot.image_ok) &&
(table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
table->image_ok_secondary_slot == secondary_slot.image_ok) &&
(table->copy_done_primary_slot == BOOT_FLAG_ANY ||
table->copy_done_primary_slot == primary_slot.copy_done)) {
BOOT_LOG_INF("Image index: %d, Swap type: %s", image_index,
table->swap_type == BOOT_SWAP_TYPE_TEST ? "test" :
table->swap_type == BOOT_SWAP_TYPE_PERM ? "perm" :
table->swap_type == BOOT_SWAP_TYPE_REVERT ? "revert" :
"BUG; can't happen");
if (table->swap_type != BOOT_SWAP_TYPE_TEST &&
table->swap_type != BOOT_SWAP_TYPE_PERM &&
table->swap_type != BOOT_SWAP_TYPE_REVERT) {
return BOOT_SWAP_TYPE_PANIC;
}
return table->swap_type;
}
}
BOOT_LOG_INF("Image index: %d, Swap type: none", image_index);
return BOOT_SWAP_TYPE_NONE;
}
int
boot_write_copy_done(const struct flash_area *fap)
{
uint32_t off;
off = boot_copy_done_off(fap);
BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%lx (0x%lx)",
flash_area_get_id(fap), (unsigned long)off,
(unsigned long)(flash_area_get_off(fap) + off));
return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
}
#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP
static int flash_area_to_image(const struct flash_area *fa)
{
#if BOOT_IMAGE_NUMBER > 1
uint8_t i = 0;
int id = flash_area_get_id(fa);
while (i < BOOT_IMAGE_NUMBER) {
if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) {
return i;
}
++i;
}
#else
(void)fa;
#endif
return 0;
}
int
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
{
struct boot_swap_state slot_state;
int rc;
if (active) {
confirm = true;
}
rc = boot_read_swap_state(fa, &slot_state);
if (rc != 0) {
return rc;
}
switch (slot_state.magic) {
case BOOT_MAGIC_GOOD:
/* If non-active then swap already scheduled, else confirm needed.*/
if (active && slot_state.image_ok == BOOT_FLAG_UNSET) {
/* Intentionally do not check copy_done flag to be able to
* confirm a padded image which has been programmed using
* a programming interface.
*/
rc = boot_write_image_ok(fa);
}
break;
case BOOT_MAGIC_UNSET:
if (!active) {
rc = boot_write_magic(fa);
if (rc == 0 && confirm) {
rc = boot_write_image_ok(fa);
}
if (rc == 0) {
uint8_t swap_type;
if (confirm) {
swap_type = BOOT_SWAP_TYPE_PERM;
} else {
swap_type = BOOT_SWAP_TYPE_TEST;
}
rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa));
}
}
break;
case BOOT_MAGIC_BAD:
if (active) {
rc = BOOT_EBADVECT;
} else {
/* The image slot is corrupt. There is no way to recover, so erase the
* slot to allow future upgrades.
*/
flash_area_erase(fa, 0, flash_area_get_size(fa));
rc = BOOT_EBADIMAGE;
}
break;
default:
/* Something is not OK, this should never happen */
assert(0);
rc = BOOT_EBADIMAGE;
}
return rc;
}
#else
int
boot_set_next(const struct flash_area *fa, bool active, bool confirm)
{
struct boot_swap_state slot_state;
int rc;
if (active) {
/* The only way to set active slot for next boot is to confirm it,
* as DirectXIP will conclude that, since slot has not been confirmed
* last boot, it is bad and will remove it.
*/
confirm = true;
}
rc = boot_read_swap_state(fa, &slot_state);
if (rc != 0) {
return rc;
}
switch (slot_state.magic) {
case BOOT_MAGIC_UNSET:
/* Magic is needed for MCUboot to even consider booting an image */
rc = boot_write_magic(fa);
if (rc != 0) {
break;
}
/* Pass */
case BOOT_MAGIC_GOOD:
if (confirm) {
if (slot_state.copy_done == BOOT_FLAG_UNSET) {
/* Magic is needed for DirectXIP to even try to boot application.
* DirectXIP will set copy-done flag before attempting to boot
* application. Next boot, application that has copy-done flag
* is expected to already have ok flag, otherwise it will be removed.
*/
rc = boot_write_copy_done(fa);
if (rc != 0) {
break;
}
}
if (slot_state.image_ok == BOOT_FLAG_UNSET) {
rc = boot_write_image_ok(fa);
if (rc != 0) {
break;
}
}
}
break;
case BOOT_MAGIC_BAD:
/* This image will not be boot next time anyway */
rc = BOOT_EBADIMAGE;
break;
default:
/* Something is not OK, this should never happen */
assert(0);
rc = BOOT_EBADSTATUS;
}
return rc;
}
#endif
/*
* This function is not used by the bootloader itself, but its required API
* by external tooling like mcumgr.
*/
int
boot_swap_type(void)
{
return boot_swap_type_multi(0);
}
/**
* Marks the image with the given index in the secondary slot as pending. On the
* next reboot, the system will perform a one-time boot of the the secondary
* slot image.
*
* @param image_index Image pair index.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_pending_multi(int image_index, int permanent)
{
const struct flash_area *fap;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_set_next(fap, false, !(permanent == 0));
flash_area_close(fap);
return rc;
}
/**
* Marks the image with index 0 in the secondary slot as pending. On the next
* reboot, the system will perform a one-time boot of the the secondary slot
* image. Note that this API is kept for compatibility. The
* boot_set_pending_multi() API is recommended.
*
* @param permanent Whether the image should be used permanently or
* only tested once:
* 0=run image once, then confirm or revert.
* 1=run image forever.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_pending(int permanent)
{
return boot_set_pending_multi(0, permanent);
}
/**
* Marks the image with the given index in the primary slot as confirmed. The
* system will continue booting into the image in the primary slot until told to
* boot from a different slot.
*
* @param image_index Image pair index.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_confirmed_multi(int image_index)
{
const struct flash_area *fap = NULL;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_set_next(fap, true, true);
flash_area_close(fap);
return rc;
}
/**
* Marks the image with index 0 in the primary slot as confirmed. The system
* will continue booting into the image in the primary slot until told to boot
* from a different slot. Note that this API is kept for compatibility. The
* boot_set_confirmed_multi() API is recommended.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_set_confirmed(void)
{
return boot_set_confirmed_multi(0);
}
int
boot_image_load_header(const struct flash_area *fa_p,
struct image_header *hdr)
{
uint32_t size;
int rc = flash_area_read(fa_p, 0, hdr, sizeof *hdr);
if (rc != 0) {
rc = BOOT_EFLASH;
BOOT_LOG_ERR("Failed reading image header");
return BOOT_EFLASH;
}
if (hdr->ih_magic != IMAGE_MAGIC) {
BOOT_LOG_ERR("Bad image magic 0x%lx", (unsigned long)hdr->ih_magic);
return BOOT_EBADIMAGE;
}
if (hdr->ih_flags & IMAGE_F_NON_BOOTABLE) {
BOOT_LOG_ERR("Image not bootable");
return BOOT_EBADIMAGE;
}
if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size) ||
size >= flash_area_get_size(fa_p)) {
return BOOT_EBADIMAGE;
}
return 0;
}

View File

@@ -0,0 +1,95 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017 Linaro Limited
* Copyright (c) 2021-2023 Arm Limited
*
* 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.
*/
#include <bootutil/caps.h>
#include "mcuboot_config/mcuboot_config.h"
uint32_t bootutil_get_caps(void)
{
uint32_t res = 0;
#if defined(MCUBOOT_SIGN_RSA)
#if MCUBOOT_SIGN_RSA_LEN == 2048
res |= BOOTUTIL_CAP_RSA2048;
#endif
#if MCUBOOT_SIGN_RSA_LEN == 3072
res |= BOOTUTIL_CAP_RSA3072;
#endif
#endif
#if defined(MCUBOOT_SIGN_EC256)
res |= BOOTUTIL_CAP_ECDSA_P256;
#endif
#if defined(MCUBOOT_SIGN_EC384)
res |= BOOTUTIL_CAP_ECDSA_P384;
#endif
#if defined(MCUBOOT_SIGN_ED25519)
res |= BOOTUTIL_CAP_ED25519;
#endif
#if defined(MCUBOOT_OVERWRITE_ONLY)
res |= BOOTUTIL_CAP_OVERWRITE_UPGRADE;
#elif defined(MCUBOOT_SWAP_USING_MOVE)
res |= BOOTUTIL_CAP_SWAP_USING_MOVE;
#else
res |= BOOTUTIL_CAP_SWAP_USING_SCRATCH;
#endif
#if defined(MCUBOOT_ENCRYPT_RSA)
res |= BOOTUTIL_CAP_ENC_RSA;
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
res |= BOOTUTIL_CAP_ENC_KW;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
res |= BOOTUTIL_CAP_ENC_EC256;
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
res |= BOOTUTIL_CAP_ENC_X25519;
#endif
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
res |= BOOTUTIL_CAP_VALIDATE_PRIMARY_SLOT;
#endif
#if defined(MCUBOOT_DOWNGRADE_PREVENTION)
res |= BOOTUTIL_CAP_DOWNGRADE_PREVENTION;
#endif
#if defined(MCUBOOT_BOOTSTRAP)
res |= BOOTUTIL_CAP_BOOTSTRAP;
#endif
#if defined(MCUBOOT_AES_256)
res |= BOOTUTIL_CAP_AES256;
#endif
#if defined(MCUBOOT_RAM_LOAD)
res |= BOOTUTIL_CAP_RAM_LOAD;
#endif
#if defined(MCUBOOT_DIRECT_XIP)
res |= BOOTUTIL_CAP_DIRECT_XIP;
#endif
#if defined(MCUBOOT_HW_ROLLBACK_PROT)
res |= BOOTUTIL_CAP_HW_ROLLBACK_PROT;
#endif
return res;
}
uint32_t bootutil_get_num_images(void)
{
#if defined(MCUBOOT_IMAGE_NUMBER)
return MCUBOOT_IMAGE_NUMBER;
#else
return 1;
#endif
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <mcuboot_config/mcuboot_config.h>
#include "bootutil/bootutil_log.h"
#include <psa/crypto.h>
#include <psa/crypto_types.h>
#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
#include <cracen_psa_kmu.h>
#endif
BOOT_LOG_MODULE_DECLARE(ed25519_psa);
#define SHA512_DIGEST_LENGTH 64
#define EDDSA_KEY_LENGTH 32
#define EDDSA_SIGNAGURE_LENGTH 64
#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
/* List of KMU stored key ids available for MCUboot */
#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id)
static psa_key_id_t kmu_key_ids[3] = {
MAKE_PSA_KMU_KEY_ID(226),
MAKE_PSA_KMU_KEY_ID(228),
MAKE_PSA_KMU_KEY_ID(230)
};
#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0]))
#endif
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[EDDSA_SIGNAGURE_LENGTH],
const uint8_t public_key[EDDSA_KEY_LENGTH])
{
/* Set to any error */
psa_status_t status = PSA_ERROR_BAD_STATE;
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t kid;
int ret = 0; /* Fail by default */
/* Initialize PSA Crypto */
status = psa_crypto_init();
if (status != PSA_SUCCESS) {
BOOT_LOG_ERR("PSA crypto init failed %d\n", status);
return 0;
}
status = PSA_ERROR_BAD_STATE;
psa_set_key_type(&key_attr,
PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS));
psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_algorithm(&key_attr, PSA_ALG_PURE_EDDSA);
status = psa_import_key(&key_attr, public_key, EDDSA_KEY_LENGTH, &kid);
if (status != PSA_SUCCESS) {
BOOT_LOG_ERR("ED25519 key import failed %d", status);
return 0;
}
status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len,
signature, EDDSA_SIGNAGURE_LENGTH);
if (status != PSA_SUCCESS) {
BOOT_LOG_ERR("ED25519 signature verification failed %d", status);
ret = 0;
/* Pass through to destroy key */
} else {
ret = 1;
/* Pass through to destroy key */
}
status = psa_destroy_key(kid);
if (status != PSA_SUCCESS) {
/* Just for logging */
BOOT_LOG_WRN("Failed to destroy key %d", status);
}
return ret;
}
#else
int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[EDDSA_SIGNAGURE_LENGTH],
const uint8_t public_key[EDDSA_KEY_LENGTH])
{
ARG_UNUSED(public_key);
/* Set to any error */
psa_status_t status = PSA_ERROR_BAD_STATE;
int ret = 0; /* Fail by default */
/* Initialize PSA Crypto */
status = psa_crypto_init();
if (status != PSA_SUCCESS) {
BOOT_LOG_ERR("PSA crypto init failed %d", status);
return 0;
}
status = PSA_ERROR_BAD_STATE;
for (int i = 0; i < KMU_KEY_COUNT; ++i) {
psa_key_id_t kid = kmu_key_ids[i];
status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message,
message_len, signature,
EDDSA_SIGNAGURE_LENGTH);
if (status == PSA_SUCCESS) {
ret = 1;
break;
}
BOOT_LOG_ERR("ED25519 signature verification failed %d", status);
}
return ret;
}
#endif

View File

@@ -0,0 +1,755 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
* Copyright (c) 2019-2024 Arm Limited
*/
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_ENC_IMAGES)
#include <stddef.h>
#include <inttypes.h>
#include <string.h>
#if defined(MCUBOOT_ENCRYPT_RSA)
#define BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED
#include "bootutil/crypto/rsa.h"
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
#include "bootutil/crypto/aes_kw.h"
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
#include "bootutil/crypto/ecdh_p256.h"
#endif
#if !defined(MCUBOOT_USE_PSA_CRYPTO)
#if defined(MCUBOOT_ENCRYPT_X25519)
#include "bootutil/crypto/ecdh_x25519.h"
#endif
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
#include "bootutil/crypto/sha.h"
#include "bootutil/crypto/hmac_sha256.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#endif
#endif
#include "bootutil/image.h"
#include "bootutil/enc_key.h"
#include "bootutil/sign_key.h"
#include "bootutil/crypto/common.h"
#include "bootutil_priv.h"
#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE
#if defined(MCUBOOT_ENCRYPT_RSA)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048
#elif defined(MCUBOOT_ENCRYPT_KW)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW
#elif defined(MCUBOOT_ENCRYPT_EC256)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256
# define EC_PUBK_INDEX (0)
# define EC_TAG_INDEX (65)
# define EC_CIPHERKEY_INDEX (65 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN,
"Please fix ECIES-P256 component indexes");
#elif defined(MCUBOOT_ENCRYPT_X25519)
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
# define EC_PUBK_INDEX (0)
# define EC_TAG_INDEX (32)
# define EC_CIPHERKEY_INDEX (32 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN,
"Please fix ECIES-X25519 component indexes");
#endif
/* NOUP Fixme: */
#if !defined(CONFIG_BOOT_ED25519_PSA)
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
#if defined(_compare)
static inline int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size)
{
return _compare(a, b, size);
}
#else
static int bootutil_constant_time_compare(const uint8_t *a, const uint8_t *b, size_t size)
{
const uint8_t *tempa = a;
const uint8_t *tempb = b;
uint8_t result = 0;
unsigned int i;
for (i = 0; i < size; i++) {
result |= tempa[i] ^ tempb[i];
}
return result;
}
#endif
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
static int
key_unwrap(const uint8_t *wrapped, uint8_t *enckey, struct bootutil_key *bootutil_enc_key)
{
bootutil_aes_kw_context aes_kw;
int rc;
bootutil_aes_kw_init(&aes_kw);
rc = bootutil_aes_kw_set_unwrap_key(&aes_kw, bootutil_enc_key->key, *bootutil_enc_key->len);
if (rc != 0) {
goto done;
}
rc = bootutil_aes_kw_unwrap(&aes_kw, wrapped, TLV_ENC_KW_SZ, enckey, BOOT_ENC_KEY_SIZE);
if (rc != 0) {
goto done;
}
done:
bootutil_aes_kw_drop(&aes_kw);
return rc;
}
#endif /* MCUBOOT_ENCRYPT_KW */
#if defined(MCUBOOT_ENCRYPT_EC256)
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
#define SHARED_KEY_LEN NUM_ECC_BYTES
#define PRIV_KEY_LEN NUM_ECC_BYTES
/*
* Parses the output of `imgtool keygen`, which produces a PKCS#8 elliptic
* curve keypair. See RFC5208 and RFC5915.
*/
static int
parse_ec256_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
{
int rc;
size_t len;
int version;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
return -3;
}
if ((rc = mbedtls_asn1_get_alg(p, end, &alg, &param)) != 0) {
return -5;
}
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -6;
}
if (param.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 ||
memcmp(param.ASN1_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -7;
}
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return -8;
}
/* RFC5915 - ECPrivateKey */
if ((rc = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return -9;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 1) {
return -10;
}
/* privateKey */
if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return -11;
}
if (len != NUM_ECC_BYTES) {
return -12;
}
memcpy(private_key, *p, len);
/* publicKey usually follows but is not parsed here */
return 0;
}
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
#if defined(MCUBOOT_ENCRYPT_X25519)
#define X25519_OID "\x6e"
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \
MBEDTLS_OID_ORG_GOV X25519_OID;
#define SHARED_KEY_LEN 32
#define PRIV_KEY_LEN 32
static int
parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
{
size_t len;
int version;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
return -3;
}
if (mbedtls_asn1_get_alg(p, end, &alg, &param) != 0) {
return -4;
}
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -5;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -6;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -7;
}
if (len != PRIV_KEY_LEN) {
return -8;
}
memcpy(private_key, *p, PRIV_KEY_LEN);
return 0;
}
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
/*
* HKDF as described by RFC5869.
*
* @param ikm The input data to be derived.
* @param ikm_len Length of the input data.
* @param info An information tag.
* @param info_len Length of the information tag.
* @param okm Output of the KDF computation.
* @param okm_len On input the requested length; on output the generated length
*/
static int
hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len,
uint8_t *okm, uint16_t *okm_len)
{
bootutil_hmac_sha256_context hmac;
uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint16_t off;
uint16_t len;
uint8_t counter;
bool first;
int rc;
/*
* Extract
*/
if (ikm == NULL || okm == NULL || ikm_len == 0) {
return -1;
}
bootutil_hmac_sha256_init(&hmac);
memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_update(&hmac, ikm, ikm_len);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_finish(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
bootutil_hmac_sha256_drop(&hmac);
/*
* Expand
*/
len = *okm_len;
counter = 1;
first = true;
for (off = 0; len > 0; off += BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, ++counter) {
bootutil_hmac_sha256_init(&hmac);
rc = bootutil_hmac_sha256_set_key(&hmac, prk, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
if (first) {
first = false;
} else {
rc = bootutil_hmac_sha256_update(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
}
rc = bootutil_hmac_sha256_update(&hmac, info, info_len);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_update(&hmac, &counter, 1);
if (rc != 0) {
goto error;
}
rc = bootutil_hmac_sha256_finish(&hmac, T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
goto error;
}
bootutil_hmac_sha256_drop(&hmac);
if (len > BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) {
memcpy(&okm[off], T, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
len -= BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
} else {
memcpy(&okm[off], T, len);
len = 0;
}
}
return 0;
error:
bootutil_hmac_sha256_drop(&hmac);
return -1;
}
#endif /* MCUBOOT_ENCRYPT_EC256 || MCUBOOT_ENCRYPT_X25519 */
#if !defined(MCUBOOT_ENC_BUILTIN_KEY)
extern const struct bootutil_key bootutil_enc_key;
/*
* Default implementation to retrieve the private encryption key which is
* embedded in the bootloader code (when MCUBOOT_ENC_BUILTIN_KEY is not defined).
*/
int boot_enc_retrieve_private_key(struct bootutil_key **private_key)
{
*private_key = (struct bootutil_key *)&bootutil_enc_key;
return 0;
}
#endif /* !MCUBOOT_ENC_BUILTIN_KEY */
#if ( (defined(MCUBOOT_ENCRYPT_RSA) && defined(MCUBOOT_USE_MBED_TLS) && !defined(MCUBOOT_USE_PSA_CRYPTO)) || \
(defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) )
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
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 /* MBEDTLS_VERSION_NUMBER */
#endif /* (MCUBOOT_ENCRYPT_RSA && MCUBOOT_USE_MBED_TLS && !MCUBOOT_USE_PSA_CRYPTO) ||
(MCUBOOT_ENCRYPT_EC256 && MCUBOOT_USE_MBED_TLS) */
/*
* Decrypt an encryption key TLV.
*
* @param buf An encryption TLV read from flash (build time fixed length)
* @param enckey An AES-128 or AES-256 key sized buffer to store to plain key.
*/
int
boot_decrypt_key(const uint8_t *buf, uint8_t *enckey)
{
#if defined(MCUBOOT_ENCRYPT_RSA)
bootutil_rsa_context rsa;
uint8_t *cp;
uint8_t *cpend;
size_t olen;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256)
bootutil_ecdh_p256_context ecdh_p256;
#endif
#if defined(MCUBOOT_ENCRYPT_X25519)
bootutil_ecdh_x25519_context ecdh_x25519;
#endif
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
bootutil_hmac_sha256_context hmac;
bootutil_aes_ctr_context aes_ctr;
uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t shared[SHARED_KEY_LEN];
uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t *cp;
uint8_t *cpend;
uint8_t private_key[PRIV_KEY_LEN];
uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
uint16_t len;
#endif
struct bootutil_key *bootutil_enc_key = NULL;
int rc = -1;
rc = boot_enc_retrieve_private_key(&bootutil_enc_key);
if (rc) {
return rc;
}
if (bootutil_enc_key == NULL) {
return rc;
}
#if defined(MCUBOOT_ENCRYPT_RSA)
bootutil_rsa_init(&rsa);
cp = (uint8_t *)bootutil_enc_key->key;
cpend = cp + *bootutil_enc_key->len;
/* The enckey is encrypted through RSA so for decryption we need the private key */
rc = bootutil_rsa_parse_private_key(&rsa, &cp, cpend);
if (rc) {
bootutil_rsa_drop(&rsa);
return rc;
}
rc = bootutil_rsa_oaep_decrypt(&rsa, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
bootutil_rsa_drop(&rsa);
if (rc) {
return rc;
}
#endif /* defined(MCUBOOT_ENCRYPT_RSA) */
#if defined(MCUBOOT_ENCRYPT_KW)
assert(*bootutil_enc_key->len == BOOT_ENC_KEY_SIZE);
rc = key_unwrap(buf, enckey, bootutil_enc_key);
#endif /* defined(MCUBOOT_ENCRYPT_KW) */
#if defined(MCUBOOT_ENCRYPT_EC256)
cp = (uint8_t *)bootutil_enc_key->key;
cpend = cp + *bootutil_enc_key->len;
/*
* Load the stored EC256 decryption private key
*/
rc = parse_ec256_enckey(&cp, cpend, private_key);
if (rc) {
return rc;
}
/*
* First "element" in the TLV is the curve point (public key)
*/
bootutil_ecdh_p256_init(&ecdh_p256);
rc = bootutil_ecdh_p256_shared_secret(&ecdh_p256, &buf[EC_PUBK_INDEX], private_key, shared);
bootutil_ecdh_p256_drop(&ecdh_p256);
if (rc != 0) {
return -1;
}
#endif /* defined(MCUBOOT_ENCRYPT_EC256) */
#if defined(MCUBOOT_ENCRYPT_X25519)
cp = (uint8_t *)bootutil_enc_key->key;
cpend = cp + *bootutil_enc_key->len;
/*
* Load the stored X25519 decryption private key
*/
rc = parse_x25519_enckey(&cp, cpend, private_key);
if (rc) {
return rc;
}
/*
* First "element" in the TLV is the curve point (public key)
*/
bootutil_ecdh_x25519_init(&ecdh_x25519);
rc = bootutil_ecdh_x25519_shared_secret(&ecdh_x25519, &buf[EC_PUBK_INDEX], private_key, shared);
bootutil_ecdh_x25519_drop(&ecdh_x25519);
if (!rc) {
return -1;
}
#endif /* defined(MCUBOOT_ENCRYPT_X25519) */
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
/*
* Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
*/
len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
derived_key, &len);
if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) {
return -1;
}
/*
* HMAC the key and check that our received MAC matches the generated tag
*/
bootutil_hmac_sha256_init(&hmac);
rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOT_ENC_KEY_SIZE], 32);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
/* Assumes the tag buffer is at least sizeof(hmac_tag_size(state)) bytes */
rc = bootutil_hmac_sha256_finish(&hmac, tag, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
bootutil_hmac_sha256_drop(&hmac);
/*
* Finally decrypt the received ciphered key
*/
bootutil_aes_ctr_init(&aes_ctr);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
rc = bootutil_aes_ctr_set_key(&aes_ctr, derived_key);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
}
bootutil_aes_ctr_drop(&aes_ctr);
rc = 0;
#endif /* defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) */
return rc;
}
#endif /* CONFIG_BOOT_ED25519_PSA */
/*
* Load encryption key.
*/
int
boot_enc_load(struct enc_key_data *enc_state, int slot,
const struct image_header *hdr, const struct flash_area *fap,
struct boot_status *bs)
{
uint32_t off;
uint16_t len;
struct image_tlv_iter it;
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint8_t *buf;
#else
uint8_t buf[EXPECTED_ENC_LEN];
#endif
int rc;
/* Already loaded... */
if (enc_state[slot].valid) {
return 1;
}
/* Initialize the AES context */
boot_enc_init(enc_state, slot);
rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_ENC_TLV, false);
if (rc) {
return -1;
}
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
if (rc != 0) {
return rc;
}
if (len != EXPECTED_ENC_LEN) {
return -1;
}
#if MCUBOOT_SWAP_SAVE_ENCTLV
buf = bs->enctlv[slot];
memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE);
#endif
rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN);
if (rc) {
return -1;
}
return boot_decrypt_key(buf, bs->enckey[slot]);
}
int
boot_enc_init(struct enc_key_data *enc_state, uint8_t slot)
{
bootutil_aes_ctr_init(&enc_state[slot].aes_ctr);
return 0;
}
int
boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot)
{
bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr);
enc_state[slot].valid = 0;
return 0;
}
int
boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot,
const struct boot_status *bs)
{
int rc;
rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]);
if (rc != 0) {
boot_enc_drop(enc_state, slot);
return -1;
}
enc_state[slot].valid = 1;
return 0;
}
bool
boot_enc_valid(struct enc_key_data *enc_state, int slot)
{
return enc_state[slot].valid;
}
void
boot_enc_encrypt(struct enc_key_data *enc_state, int slot, uint32_t off,
uint32_t sz, uint32_t blk_off, uint8_t *buf)
{
struct enc_key_data *enc = &enc_state[slot];
uint8_t nonce[16];
/* Nothing to do with size == 0 */
if (sz == 0) {
return;
}
memset(nonce, 0, 12);
off >>= 4;
nonce[12] = (uint8_t)(off >> 24);
nonce[13] = (uint8_t)(off >> 16);
nonce[14] = (uint8_t)(off >> 8);
nonce[15] = (uint8_t)off;
assert(enc->valid == 1);
bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
}
void
boot_enc_decrypt(struct enc_key_data *enc_state, int slot, uint32_t off,
uint32_t sz, uint32_t blk_off, uint8_t *buf)
{
struct enc_key_data *enc = &enc_state[slot];
uint8_t nonce[16];
/* Nothing to do with size == 0 */
if (sz == 0) {
return;
}
memset(nonce, 0, 12);
off >>= 4;
nonce[12] = (uint8_t)(off >> 24);
nonce[13] = (uint8_t)(off >> 16);
nonce[14] = (uint8_t)(off >> 8);
nonce[15] = (uint8_t)off;
assert(enc->valid == 1);
bootutil_aes_ctr_decrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
}
/**
* Clears encrypted state after use.
*/
void
boot_enc_zeroize(struct enc_key_data *enc_state)
{
uint8_t slot;
for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
(void)boot_enc_drop(enc_state, slot);
}
memset(enc_state, 0, sizeof(struct enc_key_data) * BOOT_NUM_SLOTS);
}
#endif /* MCUBOOT_ENC_IMAGES */

View File

@@ -0,0 +1,454 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include "mcuboot_config/mcuboot_config.h"
#include <stddef.h>
#include <inttypes.h>
#include <string.h>
/* We are not really using the MBEDTLS but need the ASN.1 parsing functions */
#define MBEDTLS_ASN1_PARSE_C
#include "bootutil/crypto/sha.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil/image.h"
#include "bootutil/enc_key.h"
#include "bootutil/sign_key.h"
#include "bootutil/crypto/common.h"
#include "bootutil_priv.h"
#include "bootutil/bootutil_log.h"
BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc);
#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE
#define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
#define EC_PUBK_INDEX (0)
#define EC_TAG_INDEX (32)
#define EC_CIPHERKEY_INDEX (32 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN,
"Please fix ECIES-X25519 component indexes");
#define X25519_OID "\x6e"
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \
MBEDTLS_OID_ORG_GOV X25519_OID;
#define SHARED_KEY_LEN 32
#define PRIV_KEY_LEN 32
/* Fixme: This duplicates code from encrypted.c and depends on mbedtls */
static int
parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key)
{
size_t len;
int version;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE) != 0) {
return -1;
}
if (*p + len != end) {
return -2;
}
version = 0;
if (mbedtls_asn1_get_int(p, end, &version) || version != 0) {
return -3;
}
if (mbedtls_asn1_get_alg(p, end, &alg, &param) != 0) {
return -4;
}
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -5;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -6;
}
if (mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING) != 0) {
return -7;
}
if (len != PRIV_KEY_LEN) {
return -8;
}
memcpy(private_key, *p, PRIV_KEY_LEN);
return 0;
}
void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx)
{
psa_status_t psa_ret = psa_crypto_init();
(void)ctx;
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES init PSA crypto init failed %d", psa_ret);
assert(0);
}
}
#if defined(MCUBOOT_ENC_IMAGES)
extern const struct bootutil_key bootutil_enc_key;
/*
* Decrypt an encryption key TLV.
*
* @param buf An encryption TLV read from flash (build time fixed length)
* @param enckey An AES-128 or AES-256 key sized buffer to store to plain key.
*/
int
boot_decrypt_key(const uint8_t *buf, uint8_t *enckey)
{
uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t *cp;
uint8_t *cpend;
uint8_t private_key[PRIV_KEY_LEN];
size_t len;
psa_status_t psa_ret = PSA_ERROR_BAD_STATE;
psa_status_t psa_cleanup_ret = PSA_ERROR_BAD_STATE;
psa_key_id_t kid;
psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT;
psa_key_derivation_operation_t key_do = PSA_KEY_DERIVATION_OPERATION_INIT;
psa_algorithm_t key_do_alg;
int rc = -1;
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
/* The psa_cipher_decrypt needs initialization vector of proper length at
* the beginning of the input buffer.
*/
uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) +
BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE];
psa_ret = psa_crypto_init();
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES crypto init failed %d", psa_ret);
return -1;
}
/*
* Load the stored X25519 decryption private key
*/
rc = parse_x25519_enckey(&cp, cpend, private_key);
if (rc) {
return rc;
}
psa_set_key_type(&kattr, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY));
psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DERIVE);
psa_set_key_algorithm(&kattr, PSA_ALG_ECDH);
psa_ret = psa_import_key(&kattr, private_key, sizeof(private_key), &kid);
memset(private_key, 0, sizeof(private_key));
psa_reset_key_attributes(&kattr);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("Built-in key import failed %d", psa_ret);
return -1;
}
key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256));
psa_ret = psa_key_derivation_setup(&key_do, key_do_alg);
if (psa_ret != PSA_SUCCESS) {
psa_cleanup_ret = psa_destroy_key(kid);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret);
}
BOOT_LOG_ERR("Key derivation setup failed %d", psa_ret);
return -1;
}
/* Note: PSA 1.1.2 does not have psa_key_agreement that would be useful here
* as it could just add the derived key to the storage and return key id.
* Instead, we have to use the code below to generate derived key and put it
* into storage, to obtain the key id we can then use with psa_mac_* functions.
*/
psa_ret = psa_key_derivation_key_agreement(&key_do, PSA_KEY_DERIVATION_INPUT_SECRET,
kid, &buf[EC_PUBK_INDEX],
BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
psa_cleanup_ret = psa_destroy_key(kid);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("Built-in key destruction failed %d", psa_cleanup_ret);
}
if (psa_ret != PSA_SUCCESS) {
psa_cleanup_ret = psa_key_derivation_abort(&key_do);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret);
}
BOOT_LOG_ERR("Key derivation failed %d", psa_ret);
return -1;
}
/* Only info, no salt */
psa_ret = psa_key_derivation_input_bytes(&key_do, PSA_KEY_DERIVATION_INPUT_INFO,
"MCUBoot_ECIES_v1", 16);
if (psa_ret != PSA_SUCCESS) {
psa_cleanup_ret = psa_key_derivation_abort(&key_do);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("Key derivation abort failed %d", psa_ret);
}
BOOT_LOG_ERR("Key derivation failed %d", psa_ret);
return -1;
}
len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
psa_ret = psa_key_derivation_output_bytes(&key_do, derived_key, len);
psa_cleanup_ret = psa_key_derivation_abort(&key_do);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("Key derivation cleanup failed %d", psa_ret);
}
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("Key derivation failed %d", psa_ret);
return -1;
}
/* The derived key consists of BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE bytes
* followed by BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes. Both parts will
* be imported at the point where needed and discarded immediately after.
*/
psa_set_key_type(&kattr, PSA_KEY_TYPE_HMAC);
psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256));
/* Import the MAC tag key part of derived key, that is the part that starts
* after BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE and has length of
* BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE bytes.
*/
psa_ret = psa_import_key(&kattr,
&derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE],
BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, &kid);
psa_reset_key_attributes(&kattr);
if (psa_ret != PSA_SUCCESS) {
memset(derived_key, 0, sizeof(derived_key));
BOOT_LOG_ERR("MAC key import failed %d", psa_ret);
return -1;
}
/* Verify the MAC tag of the random encryption key */
psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256),
&buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE,
&buf[EC_TAG_INDEX],
BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
psa_cleanup_ret = psa_destroy_key(kid);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("MAC key destruction failed %d", psa_cleanup_ret);
}
if (psa_ret != PSA_SUCCESS) {
memset(derived_key, 0, sizeof(derived_key));
BOOT_LOG_ERR("MAC verification failed %d", psa_ret);
return -1;
}
/* The derived key is used in AES decryption of random key */
psa_set_key_type(&kattr, PSA_KEY_TYPE_AES);
psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&kattr, PSA_ALG_CTR);
/* Import the AES partition of derived key, the first 16 bytes */
psa_ret = psa_import_key(&kattr, &derived_key[0],
BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &kid);
memset(derived_key, 0, sizeof(derived_key));
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES key import failed %d", psa_ret);
return -1;
}
/* Decrypt the random AES encryption key with AES and the key obtained
* at derivation. */
memset(&iv_and_key[0], 0, PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR));
memcpy(&iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR)],
&buf[EC_CIPHERKEY_INDEX],
sizeof(iv_and_key) - PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR));
len = 0;
psa_ret = psa_cipher_decrypt(kid, PSA_ALG_CTR, iv_and_key, sizeof(iv_and_key),
enckey, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, &len);
memset(iv_and_key, 0, sizeof(iv_and_key));
psa_cleanup_ret = psa_destroy_key(kid);
if (psa_cleanup_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("AES key destruction failed %d", psa_cleanup_ret);
}
if (psa_ret != PSA_SUCCESS || len != BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE) {
memset(enckey, 0, BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE);
BOOT_LOG_ERR("Random key decryption failed %d", psa_ret);
return -1;
}
return 0;
}
int bootutil_aes_ctr_encrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter,
const uint8_t *m, uint32_t mlen, size_t blk_off, uint8_t *c)
{
int ret = 0;
psa_status_t psa_ret = PSA_ERROR_BAD_STATE;
psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t kid;
psa_cipher_operation_t psa_op;
size_t elen = 0; /* Decrypted length */
/* Fixme: calling psa_crypto_init multiple times is not a problem,
* yet the code here is only present because there is not general
* crypto init. */
psa_ret = psa_crypto_init();
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret);
ret = -1;
goto gone;
}
psa_op = psa_cipher_operation_init();
/* Fixme: Import should happen when key is decrypted, but due to lack
* of key destruction there is no way to destroy key stored by
* psa other way than here. */
psa_set_key_type(&kattr, PSA_KEY_TYPE_AES);
psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_ENCRYPT);
psa_set_key_algorithm(&kattr, PSA_ALG_CTR);
psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid);
psa_reset_key_attributes(&kattr);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES enc import key failed %d", psa_ret);
ret = -1;
goto gone;
}
/* This could be done with psa_cipher_decrypt one-shot operation, but
* multi-part operation is used to avoid re-allocating input buffer
* to account for IV in front of data.
*/
psa_ret = psa_cipher_encrypt_setup(&psa_op, kid, PSA_ALG_CTR);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES enc setup failed %d", psa_ret);
ret = -1;
goto gone_with_key;
}
/* Fixme: hardcoded counter size, but it is hardcoded everywhere */
psa_ret = psa_cipher_set_iv(&psa_op, counter, 16);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES enc IV set failed %d", psa_ret);
ret = -1;
goto gone_after_setup;
}
psa_ret = psa_cipher_update(&psa_op, m, mlen, c, mlen, &elen);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES enc encryption failed %d", psa_ret);
ret = -1;
goto gone_after_setup;
}
gone_after_setup:
psa_ret = psa_cipher_abort(&psa_op);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("AES enc cipher abort failed %d", psa_ret);
/* Intentionally not changing the ret */
}
gone_with_key:
/* Fixme: Should be removed once key is shared by id */
psa_ret = psa_destroy_key(kid);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("AES enc destroy key failed %d", psa_ret);
/* Intentionally not changing the ret */
}
gone:
return ret;
}
int bootutil_aes_ctr_decrypt(bootutil_aes_ctr_context *ctx, uint8_t *counter,
const uint8_t *c, uint32_t clen, size_t blk_off, uint8_t *m)
{
int ret = 0;
psa_status_t psa_ret = PSA_ERROR_BAD_STATE;
psa_key_attributes_t kattr = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t kid;
psa_cipher_operation_t psa_op;
size_t dlen = 0; /* Decrypted length */
/* Fixme: the init should already happen before calling the function, but
* somehow it does not, for example when recovering in swap.
*/
psa_ret = psa_crypto_init();
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret);
ret = -1;
goto gone;
}
psa_op = psa_cipher_operation_init();
/* Fixme: Import should happen when key is decrypted, but due to lack
* of key destruction there is no way to destroy key stored by
* psa other way than here. */
psa_set_key_type(&kattr, PSA_KEY_TYPE_AES);
psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_DECRYPT);
psa_set_key_algorithm(&kattr, PSA_ALG_CTR);
psa_ret = psa_import_key(&kattr, ctx->key, BOOT_ENC_KEY_SIZE, &kid);
psa_reset_key_attributes(&kattr);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES dec import key failed %d", psa_ret);
ret = -1;
goto gone;
}
/* This could be done with psa_cipher_decrypt one-shot operation, but
* multi-part operation is used to avoid re-allocating input buffer
* to account for IV in front of data.
*/
psa_ret = psa_cipher_decrypt_setup(&psa_op, kid, PSA_ALG_CTR);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES dec setup failed %d", psa_ret);
ret = -1;
goto gone_with_key;
}
/* Fixme: hardcoded counter size, but it is hardcoded everywhere */
psa_ret = psa_cipher_set_iv(&psa_op, counter, 16);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES dec IV set failed %d", psa_ret);
ret = -1;
goto gone_after_setup;
}
psa_ret = psa_cipher_update(&psa_op, c, clen, m, clen, &dlen);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_ERR("AES dec decryption failed %d", psa_ret);
ret = -1;
goto gone_after_setup;
}
gone_after_setup:
psa_ret = psa_cipher_abort(&psa_op);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("PSA dec abort failed %d", psa_ret);
/* Intentionally not changing the ret */
}
gone_with_key:
psa_ret = psa_destroy_key(kid);
if (psa_ret != PSA_SUCCESS) {
BOOT_LOG_WRN("PSA dec key failed %d", psa_ret);
/* Intentionally not changing the ret */
}
gone:
return ret;
}
#endif /* defined(MCUBOOT_ENC_IMAGES) */

View File

@@ -0,0 +1,78 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#include "bootutil/fault_injection_hardening.h"
#ifdef FIH_ENABLE_DOUBLE_VARS
/* Variable that could be (but isn't) changed at runtime to force the compiler
* not to optimize the double check. Value doesn't matter.
*/
volatile int _fih_mask = _FIH_MASK_VALUE;
#endif /* FIH_ENABLE_DOUBLE_VARS */
fih_ret FIH_SUCCESS = FIH_POSITIVE_VALUE;
fih_ret FIH_FAILURE = FIH_NEGATIVE_VALUE;
fih_ret FIH_NO_BOOTABLE_IMAGE = FIH_CONST1;
fih_ret FIH_BOOT_HOOK_REGULAR = FIH_CONST2;
#ifdef FIH_ENABLE_CFI
#ifdef FIH_ENABLE_DOUBLE_VARS
fih_int _fih_cfi_ctr = {0, 0 ^ _FIH_MASK_VALUE};
#else
fih_int _fih_cfi_ctr = {0};
#endif /* FIH_ENABLE_DOUBLE_VARS */
/* Increment the CFI counter by one, and return the value before the increment.
*/
fih_int fih_cfi_get_and_increment(void)
{
fih_int saved = _fih_cfi_ctr;
_fih_cfi_ctr = fih_int_encode(fih_int_decode(saved) + 1);
return saved;
}
/* Validate that the saved precall value is the same as the value of the global
* counter. For this to be the case, a fih_ret must have been called between
* these functions being executed. If the values aren't the same then panic.
*/
void fih_cfi_validate(fih_int saved)
{
if (fih_int_decode(saved) != fih_int_decode(_fih_cfi_ctr)) {
FIH_PANIC;
}
}
/* Decrement the global CFI counter by one, so that it has the same value as
* before the cfi_precall
*/
void fih_cfi_decrement(void)
{
_fih_cfi_ctr = fih_int_encode(fih_int_decode(_fih_cfi_ctr) - 1);
}
#endif /* FIH_ENABLE_CFI */
#ifdef FIH_ENABLE_GLOBAL_FAIL
/* Global failure loop for bootloader code. Uses attribute used to prevent
* compiler removing due to non-standard calling procedure. Multiple loop jumps
* used to make unlooping difficult.
*/
__attribute__((used))
__attribute__((noinline))
void fih_panic_loop(void)
{
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
__asm volatile ("b fih_panic_loop");
}
#endif /* FIH_ENABLE_GLOBAL_FAIL */

View File

@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2020 Arm Limited
*/
#include "bootutil/fault_injection_hardening.h"
#ifdef FIH_ENABLE_DELAY
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
/* Mbedtls implementation of the delay RNG. Can be replaced by any other RNG
* implementation that is backed by an entropy source by altering these
* functions. This is not provided as a header API and a C file implementation
* due to issues with inlining.
*/
#ifdef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#error "FIH_ENABLE_DELAY requires an entropy source"
#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
mbedtls_entropy_context fih_entropy_ctx;
mbedtls_ctr_drbg_context fih_drbg_ctx;
int fih_delay_init(void)
{
mbedtls_entropy_init(&fih_entropy_ctx);
mbedtls_ctr_drbg_init(&fih_drbg_ctx);
mbedtls_ctr_drbg_seed(&fih_drbg_ctx , mbedtls_entropy_func,
&fih_entropy_ctx, NULL, 0);
return 1;
}
unsigned char fih_delay_random_uchar(void)
{
unsigned char delay;
mbedtls_ctr_drbg_random(&fih_drbg_ctx,(unsigned char*) &delay,
sizeof(delay));
return delay;
}
#endif /* FIH_ENABLE_DELAY */

View File

@@ -0,0 +1,95 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2017 Linaro LTD
* Copyright (C) 2021-2024 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_SIGN_EC256) || defined(MCUBOOT_SIGN_EC384)
#include "bootutil_priv.h"
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/crypto/ecdsa.h"
#if !defined(MCUBOOT_BUILTIN_KEY)
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
bootutil_ecdsa_context ctx;
FIH_DECLARE(fih_rc, FIH_FAILURE);
uint8_t *pubkey;
uint8_t *end;
pubkey = (uint8_t *)bootutil_keys[key_id].key;
end = pubkey + *bootutil_keys[key_id].len;
bootutil_ecdsa_init(&ctx);
rc = bootutil_ecdsa_parse_public_key(&ctx, &pubkey, end);
if (rc) {
goto out;
}
rc = bootutil_ecdsa_verify(&ctx, pubkey, end-pubkey, hash, hlen, sig, slen);
fih_rc = fih_ret_encode_zero_equality(rc);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
}
out:
bootutil_ecdsa_drop(&ctx);
FIH_RET(fih_rc);
}
#else /* !MCUBOOT_BUILTIN_KEY */
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
bootutil_ecdsa_context ctx;
FIH_DECLARE(fih_rc, FIH_FAILURE);
/* Use builtin key for image verification, no key parsing is required. */
ctx.key_id = key_id;
bootutil_ecdsa_init(&ctx);
/* The public key pointer and key size can be omitted. */
rc = bootutil_ecdsa_verify(&ctx, NULL, 0, hash, hlen, sig, slen);
fih_rc = fih_ret_encode_zero_equality(rc);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
}
bootutil_ecdsa_drop(&ctx);
FIH_RET(fih_rc);
}
#endif /* MCUBOOT_BUILTIN_KEY */
#endif /* MCUBOOT_SIGN_EC256 || MCUBOOT_SIGN_EC384 */

View File

@@ -0,0 +1,160 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
* Copyright (c) 2021-2023 Arm Limited
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#if defined(CONFIG_NRF_SECURITY)
/* We are not really using the MBEDTLS but need the ASN.1 parsing funcitons */
#define MBEDTLS_ASN1_PARSE_C
#endif
#ifdef MCUBOOT_SIGN_ED25519
#include "bootutil/sign_key.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1.h"
#include "bootutil_priv.h"
#include "bootutil/crypto/common.h"
#include "bootutil/crypto/sha.h"
#define EDDSA_SIGNATURE_LENGTH 64
#define NUM_ED25519_BYTES 32
extern int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[EDDSA_SIGNATURE_LENGTH],
const uint8_t public_key[NUM_ED25519_BYTES]);
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70";
/*
* Parse the public key used for signing.
*/
static int
bootutil_import_key(uint8_t **cp, uint8_t *end)
{
size_t len;
mbedtls_asn1_buf alg;
mbedtls_asn1_buf param;
if (mbedtls_asn1_get_tag(cp, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return -1;
}
end = *cp + len;
if (mbedtls_asn1_get_alg(cp, end, &alg, &param)) {
return -2;
}
if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ed25519_pubkey_oid) - 1 ||
memcmp(alg.ASN1_CONTEXT_MEMBER(p), ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) {
return -3;
}
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
return -4;
}
if (*cp + len != end) {
return -5;
}
if (len != NUM_ED25519_BYTES) {
return -6;
}
return 0;
}
#endif
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
uint8_t *pubkey = NULL;
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
uint8_t *end;
#endif
if (hlen != IMAGE_HASH_SIZE || slen != EDDSA_SIGNATURE_LENGTH) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
pubkey = (uint8_t *)bootutil_keys[key_id].key;
end = pubkey + *bootutil_keys[key_id].len;
rc = bootutil_import_key(&pubkey, end);
if (rc) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
#endif
rc = ED25519_verify(hash, IMAGE_HASH_SIZE, sig, pubkey);
if (rc == 0) {
/* if verify returns 0, there was an error. */
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
FIH_SET(fih_rc, FIH_SUCCESS);
out:
FIH_RET(fih_rc);
}
fih_ret
bootutil_verify_img(const uint8_t *img, uint32_t size,
uint8_t *sig, size_t slen, uint8_t key_id)
{
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
uint8_t *pubkey = NULL;
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
uint8_t *end;
#endif
if (slen != EDDSA_SIGNATURE_LENGTH) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
pubkey = (uint8_t *)bootutil_keys[key_id].key;
end = pubkey + *bootutil_keys[key_id].len;
rc = bootutil_import_key(&pubkey, end);
if (rc) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
#endif
rc = ED25519_verify(img, size, sig, pubkey);
if (rc == 0) {
/* if verify returns 0, there was an error. */
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
FIH_SET(fih_rc, FIH_SUCCESS);
out:
FIH_RET(fih_rc);
}
#endif /* MCUBOOT_SIGN_ED25519 */

View File

@@ -0,0 +1,288 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2018 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
* Copyright (c) 2020-2023 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <string.h>
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_RSA
#include "bootutil_priv.h"
#include "bootutil/sign_key.h"
#include "bootutil/fault_injection_hardening.h"
#define BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
#include "bootutil/crypto/rsa.h"
/* PSA Crypto APIs provide an integrated API to perform the verification
* while for other crypto backends we need to implement each step at this
* abstraction level
*/
#if !defined(MCUBOOT_USE_PSA_CRYPTO)
#include "bootutil/crypto/sha.h"
/*
* Constants for this particular constrained implementation of
* RSA-PSS. In particular, we support RSA 2048, with a SHA256 hash,
* and a 32-byte salt. A signature with different parameters will be
* rejected as invalid.
*/
/* The size, in octets, of the message. */
#define PSS_EMLEN (MCUBOOT_SIGN_RSA_LEN / 8)
/* The size of the hash function. For SHA256, this is 32 bytes. */
#define PSS_HLEN 32
/* Size of the salt, should be fixed. */
#define PSS_SLEN 32
/* The length of the mask: emLen - hLen - 1. */
#define PSS_MASK_LEN (PSS_EMLEN - PSS_HLEN - 1)
#define PSS_HASH_OFFSET PSS_MASK_LEN
/* For the mask itself, how many bytes should be all zeros. */
#define PSS_MASK_ZERO_COUNT (PSS_MASK_LEN - PSS_SLEN - 1)
#define PSS_MASK_ONE_POS PSS_MASK_ZERO_COUNT
/* Where the salt starts. */
#define PSS_MASK_SALT_POS (PSS_MASK_ONE_POS + 1)
static const uint8_t pss_zeros[8] = {0};
/*
* Compute the RSA-PSS mask-generation function, MGF1. Assumptions
* are that the mask length will be less than 256 * PSS_HLEN, and
* therefore we never need to increment anything other than the low
* byte of the counter.
*
* This is described in PKCS#1, B.2.1.
*/
static void
pss_mgf1(uint8_t *mask, const uint8_t *hash)
{
bootutil_sha_context ctx;
uint8_t counter[4] = { 0, 0, 0, 0 };
uint8_t htmp[PSS_HLEN];
int count = PSS_MASK_LEN;
int bytes;
while (count > 0) {
bootutil_sha_init(&ctx);
bootutil_sha_update(&ctx, hash, PSS_HLEN);
bootutil_sha_update(&ctx, counter, 4);
bootutil_sha_finish(&ctx, htmp);
counter[3]++;
bytes = PSS_HLEN;
if (bytes > count)
bytes = count;
memcpy(mask, htmp, bytes);
mask += bytes;
count -= bytes;
}
bootutil_sha_drop(&ctx);
}
/*
* Validate an RSA signature, using RSA-PSS, as described in PKCS #1
* v2.2, section 9.1.2, with many parameters required to have fixed
* values. RSASSA-PSS-VERIFY RFC8017 section 8.1.2
*/
static fih_ret
bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
uint8_t *sig, size_t slen)
{
bootutil_sha_context shactx;
uint8_t em[MBEDTLS_MPI_MAX_SIZE];
uint8_t db_mask[PSS_MASK_LEN];
uint8_t h2[PSS_HLEN];
int i;
FIH_DECLARE(fih_rc, FIH_FAILURE);
/* The caller has already verified that slen == bootutil_rsa_get_len(ctx) */
if (slen != PSS_EMLEN ||
PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
goto out;
}
if (hlen != PSS_HLEN) {
goto out;
}
/* Apply RSAVP1 to produce em = sig^E mod N using the public key */
if (bootutil_rsa_public(ctx, sig, em)) {
goto out;
}
/*
* PKCS #1 v2.2, 9.1.2 EMSA-PSS-Verify
*
* emBits is 2048
* emLen = ceil(emBits/8) = 256
*
* The salt length is not known at the beginning.
*/
/* Step 1. The message is constrained by the address space of a
* 32-bit processor, which is far less than the 2^61-1 limit of
* SHA-256.
*/
/* Step 2. mHash is passed in as 'hash', with hLen the hlen
* argument. */
/* Step 3. if emLen < hLen + sLen + 2, inconsistent and stop.
* The salt length is not known at this point.
*/
/* Step 4. If the rightmost octet of EM does have the value
* 0xbc, output inconsistent and stop.
*/
if (em[PSS_EMLEN - 1] != 0xbc) {
goto out;
}
/* Step 5. Let maskedDB be the leftmost emLen - hLen - 1 octets
* of EM, and H be the next hLen octets.
*
* maskedDB is then the first 256 - 32 - 1 = 0-222
* H is 32 bytes 223-254
*/
/* Step 6. If the leftmost 8emLen - emBits bits of the leftmost
* octet in maskedDB are not all equal to zero, output
* inconsistent and stop.
*
* 8emLen - emBits is zero, so there is nothing to test here.
*/
/* Step 7. let dbMask = MGF(H, emLen - hLen - 1). */
pss_mgf1(db_mask, &em[PSS_HASH_OFFSET]);
/* Step 8. let DB = maskedDB xor dbMask.
* To avoid needing an additional buffer, store the 'db' in the
* same buffer as db_mask. From now, to the end of this function,
* db_mask refers to the unmasked 'db'. */
for (i = 0; i < PSS_MASK_LEN; i++) {
db_mask[i] ^= em[i];
}
/* Step 9. Set the leftmost 8emLen - emBits bits of the leftmost
* octet in DB to zero.
* pycrypto seems to always make the emBits 2047, so we need to
* clear the top bit. */
db_mask[0] &= 0x7F;
/* Step 10. If the emLen - hLen - sLen - 2 leftmost octets of DB
* are not zero or if the octet at position emLen - hLen - sLen -
* 1 (the leftmost position is "position 1") does not have
* hexadecimal value 0x01, output "inconsistent" and stop. */
for (i = 0; i < PSS_MASK_ZERO_COUNT; i++) {
if (db_mask[i] != 0) {
goto out;
}
}
if (db_mask[PSS_MASK_ONE_POS] != 1) {
goto out;
}
/* Step 11. Let salt be the last sLen octets of DB */
/* Step 12. Let M' = 0x00 00 00 00 00 00 00 00 || mHash || salt; */
/* Step 13. Let H' = Hash(M') */
bootutil_sha_init(&shactx);
bootutil_sha_update(&shactx, pss_zeros, 8);
bootutil_sha_update(&shactx, hash, PSS_HLEN);
bootutil_sha_update(&shactx, &db_mask[PSS_MASK_SALT_POS], PSS_SLEN);
bootutil_sha_finish(&shactx, h2);
bootutil_sha_drop(&shactx);
/* Step 14. If H = H', output "consistent". Otherwise, output
* "inconsistent". */
FIH_CALL(boot_fih_memequal, fih_rc, h2, &em[PSS_HASH_OFFSET], PSS_HLEN);
out:
FIH_RET(fih_rc);
}
#else /* MCUBOOT_USE_PSA_CRYPTO */
static fih_ret
bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
uint8_t *sig, size_t slen)
{
int rc = -1;
FIH_DECLARE(fih_rc, FIH_FAILURE);
/* PSA Crypto APIs allow the verification in a single call */
rc = bootutil_rsassa_pss_verify(ctx, hash, hlen, sig, slen);
fih_rc = fih_ret_encode_zero_equality(rc);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
}
FIH_RET(fih_rc);
}
#endif /* MCUBOOT_USE_PSA_CRYPTO */
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
bootutil_rsa_context ctx;
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
uint8_t *cp;
uint8_t *end;
bootutil_rsa_init(&ctx);
cp = (uint8_t *)bootutil_keys[key_id].key;
end = cp + *bootutil_keys[key_id].len;
/* The key used for signature verification is a public RSA key */
rc = bootutil_rsa_parse_public_key(&ctx, &cp, end);
if (rc || slen != bootutil_rsa_get_len(&ctx)) {
goto out;
}
FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig, slen);
out:
bootutil_rsa_drop(&ctx);
FIH_RET(fih_rc);
}
#endif /* MCUBOOT_SIGN_RSA */

View File

@@ -0,0 +1,920 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2024 Arm Limited
*
* Original license:
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <flash_map_backend/flash_map_backend.h>
#include "bootutil/image.h"
#include "bootutil/crypto/sha.h"
#include "bootutil/sign_key.h"
#include "bootutil/security_cnt.h"
#include "bootutil/fault_injection_hardening.h"
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_DECOMPRESS_IMAGES)
#include <nrf_compress/implementation.h>
#include <compression/decompression.h>
#endif
#include "bootutil/bootutil_log.h"
BOOT_LOG_MODULE_DECLARE(mcuboot);
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
#if defined(MCUBOOT_SIGN_RSA)
#include "mbedtls/rsa.h"
#endif
#if defined(MCUBOOT_SIGN_EC256)
#include "mbedtls/ecdsa.h"
#endif
#if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SIGN_RSA) || \
defined(MCUBOOT_SIGN_EC256)
#include "mbedtls/asn1.h"
#endif
#include "bootutil_priv.h"
#ifndef MCUBOOT_SIGN_PURE
/*
* Compute SHA hash over the image.
* (SHA384 if ECDSA-P384 is being used,
* SHA256 otherwise).
*/
static int
bootutil_img_hash(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr, const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *hash_result,
uint8_t *seed, int seed_len)
{
bootutil_sha_context sha_ctx;
uint32_t size;
uint16_t hdr_size;
uint32_t blk_off;
uint32_t tlv_off;
#if !defined(MCUBOOT_HASH_STORAGE_DIRECTLY)
int rc;
uint32_t off;
uint32_t blk_sz;
#endif
#if (BOOT_IMAGE_NUMBER == 1) || !defined(MCUBOOT_ENC_IMAGES) || \
defined(MCUBOOT_RAM_LOAD)
(void)enc_state;
(void)image_index;
(void)hdr_size;
(void)blk_off;
(void)tlv_off;
#ifdef MCUBOOT_RAM_LOAD
(void)blk_sz;
(void)off;
(void)rc;
(void)fap;
(void)tmp_buf;
(void)tmp_buf_sz;
#endif
#endif
#ifdef MCUBOOT_ENC_IMAGES
/* Encrypted images only exist in the secondary slot */
if (MUST_DECRYPT(fap, image_index, hdr) &&
!boot_enc_valid(enc_state, 1)) {
return -1;
}
#endif
bootutil_sha_init(&sha_ctx);
/* in some cases (split image) the hash is seeded with data from
* the loader image */
if (seed && (seed_len > 0)) {
bootutil_sha_update(&sha_ctx, seed, seed_len);
}
/* Hash is computed over image header and image itself. */
size = hdr_size = hdr->ih_hdr_size;
size += hdr->ih_img_size;
tlv_off = size;
/* If protected TLVs are present they are also hashed. */
size += hdr->ih_protect_tlv_size;
#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY
/* No chunk loading, storage is mapped to address space and can
* be directly given to hashing function.
*/
bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size);
#else /* MCUBOOT_HASH_STORAGE_DIRECTLY */
#ifdef MCUBOOT_RAM_LOAD
bootutil_sha_update(&sha_ctx,
(void*)(IMAGE_RAM_BASE + hdr->ih_load_addr),
size);
#else
for (off = 0; off < size; off += blk_sz) {
blk_sz = size - off;
if (blk_sz > tmp_buf_sz) {
blk_sz = tmp_buf_sz;
}
#ifdef MCUBOOT_ENC_IMAGES
/* The only data that is encrypted in an image is the payload;
* both header and TLVs (when protected) are not.
*/
if ((off < hdr_size) && ((off + blk_sz) > hdr_size)) {
/* read only the header */
blk_sz = hdr_size - off;
}
if ((off < tlv_off) && ((off + blk_sz) > tlv_off)) {
/* read only up to the end of the image payload */
blk_sz = tlv_off - off;
}
#endif
rc = flash_area_read(fap, off, tmp_buf, blk_sz);
if (rc) {
bootutil_sha_drop(&sha_ctx);
return rc;
}
#ifdef MCUBOOT_ENC_IMAGES
if (MUST_DECRYPT(fap, image_index, hdr)) {
/* Only payload is encrypted (area between header and TLVs) */
int slot = flash_area_id_to_multi_image_slot(image_index,
flash_area_get_id(fap));
if (off >= hdr_size && off < tlv_off) {
blk_off = (off - hdr_size) & 0xf;
boot_enc_decrypt(enc_state, slot, off - hdr_size,
blk_sz, blk_off, tmp_buf);
}
}
#endif
bootutil_sha_update(&sha_ctx, tmp_buf, blk_sz);
}
#endif /* MCUBOOT_RAM_LOAD */
#endif /* MCUBOOT_HASH_STORAGE_DIRECTLY */
bootutil_sha_finish(&sha_ctx, hash_result);
bootutil_sha_drop(&sha_ctx);
return 0;
}
#endif
/*
* Currently, we only support being able to verify one type of
* signature, because there is a single verification function that we
* call. List the type of TLV we are expecting. If we aren't
* configured for any signature, don't define this macro.
*/
#if (defined(MCUBOOT_SIGN_RSA) + \
defined(MCUBOOT_SIGN_EC256) + \
defined(MCUBOOT_SIGN_EC384) + \
defined(MCUBOOT_SIGN_ED25519)) > 1
#error "Only a single signature type is supported!"
#endif
#if defined(MCUBOOT_SIGN_RSA)
# if MCUBOOT_SIGN_RSA_LEN == 2048
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS
# elif MCUBOOT_SIGN_RSA_LEN == 3072
# define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS
# else
# error "Unsupported RSA signature length"
# endif
# define SIG_BUF_SIZE (MCUBOOT_SIGN_RSA_LEN / 8)
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE) /* 2048 bits */
#elif defined(MCUBOOT_SIGN_EC256) || \
defined(MCUBOOT_SIGN_EC384) || \
defined(MCUBOOT_SIGN_EC)
# define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG
# define SIG_BUF_SIZE 128
# define EXPECTED_SIG_LEN(x) (1) /* always true, ASN.1 will validate */
#elif defined(MCUBOOT_SIGN_ED25519)
# define EXPECTED_SIG_TLV IMAGE_TLV_ED25519
# define SIG_BUF_SIZE 64
# define EXPECTED_SIG_LEN(x) ((x) == SIG_BUF_SIZE)
#else
# define SIG_BUF_SIZE 32 /* no signing, sha256 digest only */
#endif
#if (defined(MCUBOOT_HW_KEY) + \
defined(MCUBOOT_BUILTIN_KEY)) > 1
#error "Please use either MCUBOOT_HW_KEY or the MCUBOOT_BUILTIN_KEY feature."
#endif
#ifdef EXPECTED_SIG_TLV
#if !defined(MCUBOOT_BUILTIN_KEY)
#if !defined(MCUBOOT_HW_KEY)
/* The key TLV contains the hash of the public key. */
# define EXPECTED_KEY_TLV IMAGE_TLV_KEYHASH
# define KEY_BUF_SIZE IMAGE_HASH_SIZE
#else
/* The key TLV contains the whole public key.
* Add a few extra bytes to the key buffer size for encoding and
* for public exponent.
*/
# define EXPECTED_KEY_TLV IMAGE_TLV_PUBKEY
# define KEY_BUF_SIZE (SIG_BUF_SIZE + 24)
#endif /* !MCUBOOT_HW_KEY */
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
#if !defined(MCUBOOT_HW_KEY)
static int
bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len)
{
bootutil_sha_context sha_ctx;
int i;
const struct bootutil_key *key;
uint8_t hash[IMAGE_HASH_SIZE];
if (keyhash_len > IMAGE_HASH_SIZE) {
return -1;
}
for (i = 0; i < bootutil_key_cnt; i++) {
key = &bootutil_keys[i];
bootutil_sha_init(&sha_ctx);
bootutil_sha_update(&sha_ctx, key->key, *key->len);
bootutil_sha_finish(&sha_ctx, hash);
if (!memcmp(hash, keyhash, keyhash_len)) {
bootutil_sha_drop(&sha_ctx);
return i;
}
}
bootutil_sha_drop(&sha_ctx);
return -1;
}
#else /* !MCUBOOT_HW_KEY */
extern unsigned int pub_key_len;
static int
bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len)
{
bootutil_sha_context sha_ctx;
uint8_t hash[IMAGE_HASH_SIZE];
uint8_t key_hash[IMAGE_HASH_SIZE];
size_t key_hash_size = sizeof(key_hash);
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
bootutil_sha_init(&sha_ctx);
bootutil_sha_update(&sha_ctx, key, key_len);
bootutil_sha_finish(&sha_ctx, hash);
bootutil_sha_drop(&sha_ctx);
rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size);
if (rc) {
return -1;
}
/* Adding hardening to avoid this potential attack:
* - Image is signed with an arbitrary key and the corresponding public
* key is added as a TLV field.
* - During public key validation (comparing against key-hash read from
* HW) a fault is injected to accept the public key as valid one.
*/
FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size);
if (FIH_EQ(fih_rc, FIH_SUCCESS)) {
bootutil_keys[0].key = key;
pub_key_len = key_len;
return 0;
}
return -1;
}
#endif /* !MCUBOOT_HW_KEY */
#endif /* !MCUBOOT_BUILTIN_KEY */
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
#endif /* EXPECTED_SIG_TLV */
/**
* Reads the value of an image's security counter.
*
* @param hdr Pointer to the image header structure.
* @param fap Pointer to a description structure of the image's
* flash area.
* @param security_cnt Pointer to store the security counter value.
*
* @return 0 on success; nonzero on failure.
*/
int32_t
bootutil_get_img_security_cnt(struct image_header *hdr,
const struct flash_area *fap,
uint32_t *img_security_cnt)
{
struct image_tlv_iter it;
uint32_t off;
uint16_t len;
int32_t rc;
if ((hdr == NULL) ||
(fap == NULL) ||
(img_security_cnt == NULL)) {
/* Invalid parameter. */
return BOOT_EBADARGS;
}
/* The security counter TLV is in the protected part of the TLV area. */
if (hdr->ih_protect_tlv_size == 0) {
return BOOT_EBADIMAGE;
}
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SEC_CNT, true);
if (rc) {
return rc;
}
/* Traverse through the protected TLV area to find
* the security counter TLV.
*/
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
if (rc != 0) {
/* Security counter TLV has not been found. */
return -1;
}
if (len != sizeof(*img_security_cnt)) {
/* Security counter is not valid. */
return BOOT_EBADIMAGE;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, img_security_cnt, len);
if (rc != 0) {
return BOOT_EFLASH;
}
return 0;
}
#if defined(MCUBOOT_SIGN_PURE)
/* Returns:
* 0 -- found
* 1 -- not found or found but not true
* -1 -- failed for some reason
*
* Value of TLV does not matter, presence decides.
*/
static int bootutil_check_for_pure(const struct image_header *hdr,
const struct flash_area *fap)
{
struct image_tlv_iter it;
uint32_t off;
uint16_t len;
int32_t rc;
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_SIG_PURE, false);
if (rc) {
return rc;
}
/* Search for the TLV */
rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
if (rc == 0 && len == 1) {
bool val;
rc = LOAD_IMAGE_DATA(hdr, fap, off, &val, 1);
if (rc == 0) {
rc = !val;
}
}
return rc;
}
#endif
#ifndef ALLOW_ROGUE_TLVS
/*
* The following list of TLVs are the only entries allowed in the unprotected
* TLV section. All other TLV entries must be in the protected section.
*/
static const uint16_t allowed_unprot_tlvs[] = {
IMAGE_TLV_KEYHASH,
IMAGE_TLV_PUBKEY,
IMAGE_TLV_SHA256,
IMAGE_TLV_SHA384,
IMAGE_TLV_SHA512,
IMAGE_TLV_RSA2048_PSS,
IMAGE_TLV_ECDSA224,
IMAGE_TLV_ECDSA_SIG,
IMAGE_TLV_RSA3072_PSS,
IMAGE_TLV_ED25519,
#if defined(MCUBOOT_SIGN_PURE)
IMAGE_TLV_SIG_PURE,
#endif
IMAGE_TLV_ENC_RSA2048,
IMAGE_TLV_ENC_KW,
IMAGE_TLV_ENC_EC256,
IMAGE_TLV_ENC_X25519,
/* Mark end with ANY. */
IMAGE_TLV_ANY,
};
#endif
/*
* Verify the integrity of the image.
* Return non-zero if image could not be validated/does not validate.
*/
fih_ret
bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
struct image_header *hdr, const struct flash_area *fap,
uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *seed,
int seed_len, uint8_t *out_hash)
{
uint32_t off;
uint16_t len;
uint16_t type;
#ifdef EXPECTED_SIG_TLV
FIH_DECLARE(valid_signature, FIH_FAILURE);
#ifndef MCUBOOT_BUILTIN_KEY
int key_id = -1;
#else
/* Pass a key ID equal to the image index, the underlying crypto library
* is responsible for mapping the image index to a builtin key ID.
*/
int key_id = image_index;
#endif /* !MCUBOOT_BUILTIN_KEY */
#ifdef MCUBOOT_HW_KEY
uint8_t key_buf[KEY_BUF_SIZE];
#endif
#endif /* EXPECTED_SIG_TLV */
struct image_tlv_iter it;
uint8_t buf[SIG_BUF_SIZE];
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
int image_hash_valid = 0;
uint8_t hash[IMAGE_HASH_SIZE];
#endif
int rc = 0;
FIH_DECLARE(fih_rc, FIH_FAILURE);
#ifdef MCUBOOT_HW_ROLLBACK_PROT
fih_int security_cnt = fih_int_encode(INT_MAX);
uint32_t img_security_cnt = 0;
FIH_DECLARE(security_counter_valid, FIH_FAILURE);
#endif
#ifdef MCUBOOT_DECOMPRESS_IMAGES
/* If the image is compressed, the integrity of the image must also be validated */
if (MUST_DECOMPRESS(fap, image_index, hdr)) {
bool found_decompressed_size = false;
bool found_decompressed_sha = false;
bool found_decompressed_signature = false;
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true);
if (rc) {
goto out;
}
if (it.tlv_end > bootutil_max_image_size(fap)) {
rc = -1;
goto out;
}
while (true) {
uint16_t expected_size = 0;
bool *found_flag = NULL;
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
break;
}
switch (type) {
case IMAGE_TLV_DECOMP_SIZE:
expected_size = sizeof(size_t);
found_flag = &found_decompressed_size;
break;
case IMAGE_TLV_DECOMP_SHA:
expected_size = IMAGE_HASH_SIZE;
found_flag = &found_decompressed_sha;
break;
case IMAGE_TLV_DECOMP_SIGNATURE:
found_flag = &found_decompressed_signature;
break;
default:
continue;
};
if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) {
rc = -1;
goto out;
} else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) {
rc = -1;
goto out;
}
*found_flag = true;
}
rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature);
if (rc) {
goto out;
}
}
#endif
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
tmp_buf_sz, hash, seed, seed_len);
if (rc) {
goto out;
}
if (out_hash) {
memcpy(out_hash, hash, IMAGE_HASH_SIZE);
}
#endif
#if defined(MCUBOOT_SIGN_PURE)
/* If Pure type signature is expected then it has to be there */
rc = bootutil_check_for_pure(hdr, fap);
if (rc != 0) {
goto out;
}
#endif
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
if (rc) {
goto out;
}
if (it.tlv_end > bootutil_max_image_size(fap)) {
rc = -1;
goto out;
}
/*
* Traverse through all of the TLVs, performing any checks we know
* and are able to do.
*/
while (true) {
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
break;
}
#ifndef ALLOW_ROGUE_TLVS
/*
* Ensure that the non-protected TLV only has entries necessary to hold
* the signature. We also allow encryption related keys to be in the
* unprotected area.
*/
if (!bootutil_tlv_iter_is_prot(&it, off)) {
bool found = false;
for (const uint16_t *p = allowed_unprot_tlvs; *p != IMAGE_TLV_ANY; p++) {
if (type == *p) {
found = true;
break;
}
}
if (!found) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
}
#endif
switch(type) {
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
case EXPECTED_HASH_TLV:
{
/* Verify the image hash. This must always be present. */
if (len != sizeof(hash)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
if (rc) {
goto out;
}
FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
image_hash_valid = 1;
break;
}
#endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
#ifdef EXPECTED_KEY_TLV
case EXPECTED_KEY_TLV:
{
/*
* Determine which key we should be checking.
*/
if (len > KEY_BUF_SIZE) {
rc = -1;
goto out;
}
#ifndef MCUBOOT_HW_KEY
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(buf, len);
#else
rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(image_index, key_buf, len);
#endif /* !MCUBOOT_HW_KEY */
/*
* The key may not be found, which is acceptable. There
* can be multiple signatures, each preceded by a key.
*/
break;
}
#endif /* EXPECTED_KEY_TLV */
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
#ifdef EXPECTED_SIG_TLV
case EXPECTED_SIG_TLV:
{
#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU)
/* Ignore this signature if it is out of bounds. */
if (key_id < 0 || key_id >= bootutil_key_cnt) {
key_id = -1;
continue;
}
#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
#ifndef MCUBOOT_SIGN_PURE
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
buf, len, key_id);
#else
/* Directly check signature on the image, by using the mapping of
* a device to memory. The pointer is beginning of image in flash,
* so offset of area, the range is header + image + protected tlvs.
*/
FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap),
hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size,
buf, len, key_id);
#endif
key_id = -1;
break;
}
#endif /* EXPECTED_SIG_TLV */
#ifdef MCUBOOT_HW_ROLLBACK_PROT
case IMAGE_TLV_SEC_CNT:
{
/*
* Verify the image's security counter.
* This must always be present.
*/
if (len != sizeof(img_security_cnt)) {
/* Security counter is not valid. */
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len);
if (rc) {
goto out;
}
FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index,
&security_cnt);
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
/* Compare the new image's security counter value against the
* stored security counter value.
*/
fih_rc = fih_ret_encode_zero_equality(img_security_cnt <
(uint32_t)fih_int_decode(security_cnt));
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
/* The image's security counter has been successfully verified. */
security_counter_valid = fih_rc;
break;
}
#endif /* MCUBOOT_HW_ROLLBACK_PROT */
}
}
#if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE)
rc = !image_hash_valid;
if (rc) {
goto out;
}
#elif defined(MCUBOOT_SIGN_PURE)
/* This returns true on EQ, rc is err on non-0 */
rc = FIH_NOT_EQ(valid_signature, FIH_SUCCESS);
#endif
#ifdef EXPECTED_SIG_TLV
FIH_SET(fih_rc, valid_signature);
#endif
#ifdef MCUBOOT_HW_ROLLBACK_PROT
if (FIH_NOT_EQ(security_counter_valid, FIH_SUCCESS)) {
rc = -1;
goto out;
}
#endif
#ifdef MCUBOOT_DECOMPRESS_IMAGES
/* Only after all previous verifications have passed, perform a dry-run of the decompression
* and ensure the image is valid
*/
if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) {
image_hash_valid = 0;
FIH_SET(valid_signature, FIH_FAILURE);
rc = bootutil_img_hash_decompress(enc_state, image_index, hdr, fap, tmp_buf, tmp_buf_sz,
hash, seed, seed_len);
if (rc) {
goto out;
}
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true);
if (rc) {
goto out;
}
if (it.tlv_end > bootutil_max_image_size(fap)) {
rc = -1;
goto out;
}
while (true) {
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
break;
}
if (type == IMAGE_TLV_DECOMP_SHA) {
/* Verify the image hash. This must always be present. */
if (len != sizeof(hash)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
if (rc) {
goto out;
}
FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
FIH_SET(fih_rc, FIH_FAILURE);
goto out;
}
image_hash_valid = 1;
}
}
rc = !image_hash_valid;
if (rc) {
goto out;
}
#ifdef EXPECTED_SIG_TLV
#ifdef EXPECTED_KEY_TLV
rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false);
if (rc) {
goto out;
}
if (it.tlv_end > bootutil_max_image_size(fap)) {
rc = -1;
goto out;
}
while (true) {
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
break;
}
if (type == EXPECTED_KEY_TLV) {
/*
* Determine which key we should be checking.
*/
if (len > KEY_BUF_SIZE) {
rc = -1;
goto out;
}
#ifndef MCUBOOT_HW_KEY
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(buf, len);
#else
rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
if (rc) {
goto out;
}
key_id = bootutil_find_key(image_index, key_buf, len);
#endif /* !MCUBOOT_HW_KEY */
/*
* The key may not be found, which is acceptable. There
* can be multiple signatures, each preceded by a key.
*/
}
}
#endif /* EXPECTED_KEY_TLV */
rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true);
if (rc) {
goto out;
}
if (it.tlv_end > bootutil_max_image_size(fap)) {
rc = -1;
goto out;
}
while (true) {
rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
if (rc < 0) {
goto out;
} else if (rc > 0) {
rc = 0;
break;
}
if (type == IMAGE_TLV_DECOMP_SIGNATURE) {
/* Ignore this signature if it is out of bounds. */
if (key_id < 0 || key_id >= bootutil_key_cnt) {
key_id = -1;
continue;
}
if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
rc = -1;
goto out;
}
rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
if (rc) {
goto out;
}
FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
buf, len, key_id);
key_id = -1;
}
}
#endif /* EXPECTED_SIG_TLV */
}
#endif
#ifdef EXPECTED_SIG_TLV
FIH_SET(fih_rc, valid_signature);
#endif
out:
if (rc) {
FIH_SET(fih_rc, FIH_FAILURE);
}
FIH_RET(fih_rc);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
BOOT_LOG_MODULE_DECLARE(mcuboot);
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
int
swap_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap)
{
uint8_t slot;
uint32_t sector;
uint32_t trailer_sz;
uint32_t total_sz;
uint32_t off;
uint32_t sz;
int fa_id_primary;
int fa_id_secondary;
uint8_t image_index;
int rc;
BOOT_LOG_DBG("erasing trailer; fa_id=%d", flash_area_get_id(fap));
image_index = BOOT_CURR_IMG(state);
fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
BOOT_PRIMARY_SLOT);
fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
BOOT_SECONDARY_SLOT);
if (flash_area_get_id(fap) == fa_id_primary) {
slot = BOOT_PRIMARY_SLOT;
} else if (flash_area_get_id(fap) == fa_id_secondary) {
slot = BOOT_SECONDARY_SLOT;
} else {
return BOOT_EFLASH;
}
/* delete starting from last sector and moving to beginning */
sector = boot_img_num_sectors(state, slot) - 1;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
total_sz = 0;
do {
sz = boot_img_sector_size(state, slot, sector);
off = boot_img_sector_off(state, slot, sector);
rc = boot_erase_region(fap, off, sz);
assert(rc == 0);
sector--;
total_sz += sz;
} while (total_sz < trailer_sz);
return rc;
}
int
swap_status_init(const struct boot_loader_state *state,
const struct flash_area *fap,
const struct boot_status *bs)
{
struct boot_swap_state swap_state;
uint8_t image_index;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
BOOT_LOG_DBG("initializing status; fa_id=%d", flash_area_get_id(fap));
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&swap_state);
assert(rc == 0);
if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
rc = boot_write_swap_info(fap, bs->swap_type, image_index);
assert(rc == 0);
}
if (swap_state.image_ok == BOOT_FLAG_SET) {
rc = boot_write_image_ok(fap);
assert(rc == 0);
}
rc = boot_write_swap_size(fap, bs->swap_size);
assert(rc == 0);
#ifdef MCUBOOT_ENC_IMAGES
rc = boot_write_enc_key(fap, 0, bs);
assert(rc == 0);
rc = boot_write_enc_key(fap, 1, bs);
assert(rc == 0);
#endif
rc = boot_write_magic(fap);
assert(rc == 0);
return 0;
}
int
swap_read_status(struct boot_loader_state *state, struct boot_status *bs)
{
const struct flash_area *fap;
uint32_t off;
uint8_t swap_info;
int area_id;
int rc;
bs->source = swap_status_source(state);
switch (bs->source) {
case BOOT_STATUS_SOURCE_NONE:
return 0;
#if MCUBOOT_SWAP_USING_SCRATCH
case BOOT_STATUS_SOURCE_SCRATCH:
area_id = FLASH_AREA_IMAGE_SCRATCH;
break;
#endif
case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
break;
default:
assert(0);
return BOOT_EBADARGS;
}
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = swap_read_status_bytes(fap, state, bs);
if (rc == 0) {
off = boot_swap_info_off(fap);
rc = flash_area_read(fap, off, &swap_info, sizeof swap_info);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
if (bootutil_buffer_is_erased(fap, &swap_info, sizeof swap_info)) {
BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
rc = 0;
}
/* Extract the swap type info */
bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
}
done:
flash_area_close(fap);
return rc;
}
int
swap_set_copy_done(uint8_t image_index)
{
const struct flash_area *fap;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_write_copy_done(fap);
flash_area_close(fap);
return rc;
}
int
swap_set_image_ok(uint8_t image_index)
{
const struct flash_area *fap;
struct boot_swap_state state;
int rc;
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap);
if (rc != 0) {
return BOOT_EFLASH;
}
rc = boot_read_swap_state(fap, &state);
if (rc != 0) {
rc = BOOT_EFLASH;
goto out;
}
if (state.image_ok == BOOT_FLAG_UNSET) {
rc = boot_write_image_ok(fap);
}
out:
flash_area_close(fap);
return rc;
}
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */

View File

@@ -0,0 +1,608 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
BOOT_LOG_MODULE_DECLARE(mcuboot);
#ifdef MCUBOOT_SWAP_USING_MOVE
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
* FIXME: this might have to be updated for threaded sim
*/
int boot_status_fails = 0;
#define BOOT_STATUS_ASSERT(x) \
do { \
if (!(x)) { \
boot_status_fails++; \
} \
} while (0)
#else
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
#endif
uint32_t
find_last_idx(struct boot_loader_state *state, uint32_t swap_size)
{
uint32_t sector_sz;
uint32_t sz;
uint32_t last_idx;
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
sz = 0;
last_idx = 0;
while (1) {
sz += sector_sz;
last_idx++;
if (sz >= swap_size) {
break;
}
}
return last_idx;
}
int
boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs)
{
const struct flash_area *fap;
uint32_t off;
uint32_t sz;
uint32_t last_idx;
uint32_t swap_size;
int area_id;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
off = 0;
if (bs && !boot_status_is_reset(bs)) {
boot_find_status(BOOT_CURR_IMG(state), &fap);
if (fap == NULL || boot_read_swap_size(fap, &swap_size)) {
rc = BOOT_EFLASH;
goto done;
}
flash_area_close(fap);
last_idx = find_last_idx(state, swap_size);
sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
/*
* Find the correct offset or slot where the image header is expected to
* be found for the steps where it is moved or swapped.
*/
if (bs->op == BOOT_STATUS_OP_MOVE && slot == 0 && bs->idx > last_idx) {
off = sz;
} else if (bs->op == BOOT_STATUS_OP_SWAP) {
if (bs->idx > 1 && bs->idx <= last_idx) {
slot = (slot == 0) ? 1 : 0;
} else if (bs->idx == 1) {
if (slot == 0) {
off = sz;
} else if (slot == 1 && bs->state == 2) {
slot = 0;
}
}
}
}
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
rc = flash_area_open(area_id, &fap);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
rc = flash_area_read(fap, off, out_hdr, sizeof *out_hdr);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
/* We only know where the headers are located when bs is valid */
if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
rc = -1;
goto done;
}
rc = 0;
done:
flash_area_close(fap);
return rc;
}
int
swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state, struct boot_status *bs)
{
uint32_t off;
uint8_t status;
int max_entries;
int found_idx;
uint8_t write_sz;
int move_entries;
int rc;
int last_rc;
int erased_sections;
int i;
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
if (max_entries < 0) {
return BOOT_EBADARGS;
}
erased_sections = 0;
found_idx = -1;
/* skip erased sectors at the end */
last_rc = 1;
write_sz = BOOT_WRITE_SZ(state);
off = boot_status_off(fap);
for (i = max_entries; i > 0; i--) {
rc = flash_area_read(fap, off + (i - 1) * write_sz, &status, 1);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, &status, 1)) {
if (rc != last_rc) {
erased_sections++;
}
} else {
if (found_idx == -1) {
found_idx = i;
}
}
last_rc = rc;
}
if (erased_sections > 1) {
/* This means there was an error writing status on the last
* swap. Tell user and move on to validation!
*/
#if !defined(__BOOTSIM__)
BOOT_LOG_ERR("Detected inconsistent status!");
#endif
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/* With validation of the primary slot disabled, there is no way
* to be sure the swapped primary slot is OK, so abort!
*/
assert(0);
#endif
}
move_entries = BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT;
if (found_idx == -1) {
/* no swap status found; nothing to do */
} else if (found_idx < move_entries) {
bs->op = BOOT_STATUS_OP_MOVE;
bs->idx = (found_idx / BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_IDX_0;
bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;;
} else {
bs->op = BOOT_STATUS_OP_SWAP;
bs->idx = ((found_idx - move_entries) / BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_IDX_0;
bs->state = ((found_idx - move_entries) % BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_STATE_0;
}
return 0;
}
uint32_t
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
{
uint32_t off;
int idx_sz;
idx_sz = elem_sz * ((bs->op == BOOT_STATUS_OP_MOVE) ?
BOOT_STATUS_MOVE_STATE_COUNT : BOOT_STATUS_SWAP_STATE_COUNT);
off = ((bs->op == BOOT_STATUS_OP_MOVE) ?
0 : (BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT * elem_sz)) +
(bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
return off;
}
static int app_max_sectors(struct boot_loader_state *state)
{
uint32_t sz = 0;
uint32_t sector_sz;
uint32_t trailer_sz;
uint32_t first_trailer_idx;
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
while (1) {
sz += sector_sz;
if (sz >= trailer_sz) {
break;
}
first_trailer_idx--;
}
return first_trailer_idx;
}
int
boot_slots_compatible(struct boot_loader_state *state)
{
#ifdef PM_S1_ADDRESS
/* Patch needed for NCS. In this case, image 1 primary points to the other
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
* With this configuration, image 0 and image 1 share the secondary slot.
* Hence, the primary slot of image 1 will be *smaller* than image 1's
* secondary slot. This is not allowed in upstream mcuboot, so we need
* this patch to allow it. Also, all of these checks are redundant when
* partition manager is in use, and since we have the same sector size
* in all of our flash.
*/
return 1;
#else
size_t num_sectors_pri;
size_t num_sectors_sec;
size_t sector_sz_pri = 0;
size_t sector_sz_sec = 0;
size_t i;
size_t num_usable_sectors_pri;
num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
num_usable_sectors_pri = app_max_sectors(state);
if ((num_sectors_pri != num_sectors_sec) &&
(num_sectors_pri != (num_sectors_sec + 1)) &&
(num_usable_sectors_pri != (num_sectors_sec + 1))) {
BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors");
BOOT_LOG_DBG("slot0 sectors: %d, slot1 sectors: %d, usable slot0 sectors: %d",
(int)num_sectors_pri, (int)num_sectors_sec,
(int)(num_usable_sectors_pri - 1));
return 0;
} else if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}
if (num_usable_sectors_pri != (num_sectors_sec + 1)) {
BOOT_LOG_DBG("Non-optimal sector distribution, slot0 has %d usable sectors (%d assigned) "
"but slot1 has %d assigned", (int)(num_usable_sectors_pri - 1),
(int)num_sectors_pri, (int)num_sectors_sec);
}
for (i = 0; i < num_sectors_sec; i++) {
sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i);
if (sector_sz_pri != sector_sz_sec) {
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
return 0;
}
}
if (num_sectors_pri > num_sectors_sec) {
if (sector_sz_pri != boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i)) {
BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
return 0;
}
}
return 1;
#endif /* PM_S1_ADDRESS */
}
#define BOOT_LOG_SWAP_STATE(area, state) \
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
"image_ok=0x%x", \
(area), \
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
"bad"), \
(state)->swap_type, \
(state)->copy_done, \
(state)->image_ok)
int
swap_status_source(struct boot_loader_state *state)
{
struct boot_swap_state state_primary_slot;
struct boot_swap_state state_secondary_slot;
int rc;
uint8_t source;
uint8_t image_index;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&state_primary_slot);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY(image_index),
&state_secondary_slot);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Secondary image", &state_secondary_slot);
if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
state_primary_slot.copy_done == BOOT_FLAG_UNSET &&
state_secondary_slot.magic != BOOT_MAGIC_GOOD) {
source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
BOOT_LOG_INF("Boot source: primary slot");
return source;
}
BOOT_LOG_INF("Boot source: none");
return BOOT_STATUS_SOURCE_NONE;
}
/*
* "Moves" the sector located at idx - 1 to idx.
*/
static void
boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs, const struct flash_area *fap_pri,
const struct flash_area *fap_sec)
{
uint32_t new_off;
uint32_t old_off;
int rc;
/*
* FIXME: assuming sectors of size == sz, a single off variable
* would be enough
*/
/* Calculate offset from start of image area. */
new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
if (bs->idx == BOOT_STATUS_IDX_0) {
if (bs->source != BOOT_STATUS_SOURCE_PRIMARY_SLOT) {
rc = swap_erase_trailer_sectors(state, fap_pri);
assert(rc == 0);
rc = swap_status_init(state, fap_pri, bs);
assert(rc == 0);
}
rc = swap_erase_trailer_sectors(state, fap_sec);
assert(rc == 0);
}
rc = boot_erase_region(fap_pri, new_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->idx++;
BOOT_STATUS_ASSERT(rc == 0);
}
static void
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs, const struct flash_area *fap_pri,
const struct flash_area *fap_sec)
{
uint32_t pri_off;
uint32_t pri_up_off;
uint32_t sec_off;
int rc;
pri_up_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
pri_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1);
if (bs->state == BOOT_STATUS_STATE_0) {
rc = boot_erase_region(fap_pri, pri_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_1;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_1) {
rc = boot_erase_region(fap_sec, sec_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->idx++;
bs->state = BOOT_STATUS_STATE_0;
BOOT_STATUS_ASSERT(rc == 0);
}
}
/*
* When starting a revert the swap status exists in the primary slot, and
* the status in the secondary slot is erased. To start the swap, the status
* area in the primary slot must be re-initialized; if during the small
* window of time between re-initializing it and writing the first metadata
* a reset happens, the swap process is broken and cannot be resumed.
*
* This function handles the issue by making the revert look like a permanent
* upgrade (by initializing the secondary slot).
*/
void
fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
const struct flash_area *fap_sec)
{
struct boot_swap_state swap_state;
int rc;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
/* No fixup required */
if (bs->swap_type != BOOT_SWAP_TYPE_REVERT ||
bs->op != BOOT_STATUS_OP_MOVE ||
bs->idx != BOOT_STATUS_IDX_0) {
return;
}
rc = boot_read_swap_state(fap_sec, &swap_state);
assert(rc == 0);
BOOT_LOG_SWAP_STATE("Secondary image", &swap_state);
if (swap_state.magic == BOOT_MAGIC_UNSET) {
rc = swap_erase_trailer_sectors(state, fap_sec);
assert(rc == 0);
rc = boot_write_image_ok(fap_sec);
assert(rc == 0);
rc = boot_write_swap_size(fap_sec, bs->swap_size);
assert(rc == 0);
rc = boot_write_magic(fap_sec);
assert(rc == 0);
}
}
void
swap_run(struct boot_loader_state *state, struct boot_status *bs,
uint32_t copy_size)
{
uint32_t sz;
uint32_t sector_sz;
uint32_t idx;
uint32_t trailer_sz;
uint32_t first_trailer_idx;
uint32_t last_idx;
uint8_t image_index;
const struct flash_area *fap_pri;
const struct flash_area *fap_sec;
int rc;
BOOT_LOG_INF("Starting swap using move algorithm.");
last_idx = find_last_idx(state, copy_size);
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
/*
* When starting a new swap upgrade, check that there is enough space.
*/
if (boot_status_is_reset(bs)) {
sz = 0;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
while (1) {
sz += sector_sz;
if (sz >= trailer_sz) {
break;
}
first_trailer_idx--;
}
if (last_idx >= first_trailer_idx) {
BOOT_LOG_WRN("Not enough free space to run swap upgrade");
BOOT_LOG_WRN("required %d bytes but only %d are available",
(last_idx + 1) * sector_sz,
first_trailer_idx * sector_sz);
bs->swap_type = BOOT_SWAP_TYPE_NONE;
return;
}
}
image_index = BOOT_CURR_IMG(state);
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
assert (rc == 0);
fixup_revert(state, bs, fap_sec);
if (bs->op == BOOT_STATUS_OP_MOVE) {
idx = last_idx;
while (idx > 0) {
if (idx <= (last_idx - bs->idx + 1)) {
boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
}
idx--;
}
bs->idx = BOOT_STATUS_IDX_0;
}
bs->op = BOOT_STATUS_OP_SWAP;
idx = 1;
while (idx <= last_idx) {
if (idx >= bs->idx) {
boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
}
idx++;
}
flash_area_close(fap_pri);
flash_area_close(fap_sec);
}
int app_max_size(struct boot_loader_state *state)
{
uint32_t sector_sz_primary;
uint32_t sector_sz_secondary;
uint32_t sz_primary;
uint32_t sz_secondary;
sector_sz_primary = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
sector_sz_secondary = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0);
/* Account for image flags and move sector */
sz_primary = app_max_sectors(state) * sector_sz_primary - sector_sz_primary;
sz_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) * sector_sz_secondary;
return (sz_primary <= sz_secondary ? sz_primary : sz_secondary);
}
#endif

View File

@@ -0,0 +1,70 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
BOOT_LOG_MODULE_DECLARE(mcuboot);
void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs)
{
uint32_t sector_sz;
uint8_t image_index;
const struct flash_area *fap_pri;
const struct flash_area *fap_sec;
int rc;
BOOT_LOG_INF("Starting swap using nsib algorithm.");
sector_sz = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0);
#if (CONFIG_NCS_IS_VARIANT_IMAGE)
rc = flash_area_open(PM_S0_ID, &fap_pri);
#else
rc = flash_area_open(PM_S1_ID, &fap_pri);
#endif
assert (rc == 0);
image_index = BOOT_CURR_IMG(state);
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
assert (rc == 0);
rc = boot_erase_region(fap_pri, 0, fap_pri->fa_size);
assert(rc == 0);
rc = boot_copy_region(state, fap_sec, fap_pri, 0, 0, fap_pri->fa_size);
assert(rc == 0);
rc = swap_erase_trailer_sectors(state, fap_sec);
assert(rc == 0);
rc = boot_erase_region(fap_sec, 0, MIN((fap_pri->fa_size + sector_sz), fap_sec->fa_size));
assert(rc == 0);
flash_area_close(fap_pri);
flash_area_close(fap_sec);
}

View File

@@ -0,0 +1,117 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#ifndef H_SWAP_PRIV_
#define H_SWAP_PRIV_
#include "mcuboot_config/mcuboot_config.h"
#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE)
/**
* Calculates the amount of space required to store the trailer, and erases
* all sectors required for this storage in the given flash_area.
*/
int swap_erase_trailer_sectors(const struct boot_loader_state *state,
const struct flash_area *fap);
/**
* Initialize the given flash_area with the metadata required to start a new
* swap upgrade.
*/
int swap_status_init(const struct boot_loader_state *state,
const struct flash_area *fap,
const struct boot_status *bs);
/**
* Tries to locate an interrupted swap status (metadata). If not metadata
* was found returns BOOT_STATUS_SOURCE_NONE.
*
* Must return one of:
* - BOOT_STATUS_SOURCE_NONE
* - BOOT_STATUS_SOURCE_SCRATCH
* - BOOT_STATUS_SOURCE_PRIMARY_SLOT
*/
int swap_status_source(struct boot_loader_state *state);
/**
* Reads the boot status from the flash. The boot status contains
* the current state of an interrupted image copy operation. If the boot
* status is not present, or it indicates that previous copy finished,
* there is no operation in progress.
*/
int swap_read_status(struct boot_loader_state *state, struct boot_status *bs);
/**
* Iterate over the swap status bytes in the given flash_area and populate
* the given boot_status with the calculated index where a swap upgrade was
* interrupted.
*/
int swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state,
struct boot_status *bs);
/**
* Marks the image in the primary slot as fully copied.
*/
int swap_set_copy_done(uint8_t image_index);
/**
* Marks a reverted image in the primary slot as confirmed. This is necessary to
* ensure the status bytes from the image revert operation don't get processed
* on a subsequent boot.
*
* NOTE: image_ok is tested before writing because if there's a valid permanent
* image installed on the primary slot and the new image to be upgrade to has a
* bad sig, image_ok would be overwritten.
*/
int swap_set_image_ok(uint8_t image_index);
/**
* Start a new or resume an interrupted swap according to the parameters
* found in the given boot_status.
*/
void swap_run(struct boot_loader_state *state,
struct boot_status *bs,
uint32_t copy_size);
#if MCUBOOT_SWAP_USING_SCRATCH
#define BOOT_SCRATCH_AREA(state) ((state)->scratch.area)
static inline size_t boot_scratch_area_size(const struct boot_loader_state *state)
{
return flash_area_get_size(BOOT_SCRATCH_AREA(state));
}
#endif
#endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) */
/**
* Returns the maximum size of an application that can be loaded to a slot.
*/
int app_max_size(struct boot_loader_state *state);
#if defined(PM_S1_ADDRESS) && !defined(MCUBOOT_OVERWRITE_ONLY) && \
(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED))
/**
* Performs an NSIB update
*/
void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs);
#endif
#endif /* H_SWAP_PRIV_ */

View File

@@ -0,0 +1,992 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
*
* 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.
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "bootutil/bootutil.h"
#include "bootutil_priv.h"
#include "swap_priv.h"
#include "bootutil/bootutil_log.h"
#include "mcuboot_config/mcuboot_config.h"
BOOT_LOG_MODULE_DECLARE(mcuboot);
#if !defined(MCUBOOT_SWAP_USING_MOVE)
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
* FIXME: this might have to be updated for threaded sim
*/
int boot_status_fails = 0;
#define BOOT_STATUS_ASSERT(x) \
do { \
if (!(x)) { \
boot_status_fails++; \
} \
} while (0)
#else
#define BOOT_STATUS_ASSERT(x) ASSERT(x)
#endif
#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
/**
* Reads the status of a partially-completed swap, if any. This is necessary
* to recover in case the boot lodaer was reset in the middle of a swap
* operation.
*/
int
swap_read_status_bytes(const struct flash_area *fap,
struct boot_loader_state *state, struct boot_status *bs)
{
uint32_t off;
uint8_t status;
int max_entries;
int found;
int found_idx;
int invalid;
int rc;
int i;
off = boot_status_off(fap);
max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
if (max_entries < 0) {
return BOOT_EBADARGS;
}
found = 0;
found_idx = 0;
invalid = 0;
for (i = 0; i < max_entries; i++) {
rc = flash_area_read(fap, off + i * BOOT_WRITE_SZ(state),
&status, 1);
if (rc < 0) {
return BOOT_EFLASH;
}
if (bootutil_buffer_is_erased(fap, &status, 1)) {
if (found && !found_idx) {
found_idx = i;
}
} else if (!found) {
found = 1;
} else if (found_idx) {
invalid = 1;
break;
}
}
if (invalid) {
/* This means there was an error writing status on the last
* swap. Tell user and move on to validation!
*/
#if !defined(__BOOTSIM__)
BOOT_LOG_ERR("Detected inconsistent status!");
#endif
#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/* With validation of the primary slot disabled, there is no way
* to be sure the swapped primary slot is OK, so abort!
*/
assert(0);
#endif
}
if (found) {
if (!found_idx) {
found_idx = i;
}
bs->idx = (found_idx / BOOT_STATUS_STATE_COUNT) + 1;
bs->state = (found_idx % BOOT_STATUS_STATE_COUNT) + 1;
}
return 0;
}
uint32_t
boot_status_internal_off(const struct boot_status *bs, int elem_sz)
{
int idx_sz;
idx_sz = elem_sz * BOOT_STATUS_STATE_COUNT;
return (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
(bs->state - BOOT_STATUS_STATE_0) * elem_sz;
}
/*
* Slots are compatible when all sectors that store up to to size of the image
* round up to sector size, in both slot's are able to fit in the scratch
* area, and have sizes that are a multiple of each other (powers of two
* presumably!).
*/
int
boot_slots_compatible(struct boot_loader_state *state)
{
#ifdef PM_S1_ADDRESS
/* Patch needed for NCS. In this case, image 1 primary points to the other
* B1 slot (ie S0 or S1), and image 0 primary points to the app.
* With this configuration, image 0 and image 1 share the secondary slot.
* Hence, the primary slot of image 1 will be *smaller* than image 1's
* secondary slot. This is not allowed in upstream mcuboot, so we need
* this patch to allow it. Also, all of these checks are redundant when
* partition manager is in use, and since we have the same sector size
* in all of our flash.
*/
return 1;
#else
size_t num_sectors_primary;
size_t num_sectors_secondary;
size_t sz0, sz1;
size_t primary_slot_sz, secondary_slot_sz;
#ifndef MCUBOOT_OVERWRITE_ONLY
size_t scratch_sz;
#endif
size_t i, j;
int8_t smaller;
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
(num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
return 0;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
scratch_sz = boot_scratch_area_size(state);
#endif
/*
* The following loop scans all sectors in a linear fashion, assuring that
* for each possible sector in each slot, it is able to fit in the other
* slot's sector or sectors. Slot's should be compatible as long as any
* number of a slot's sectors are able to fit into another, which only
* excludes cases where sector sizes are not a multiple of each other.
*/
i = sz0 = primary_slot_sz = 0;
j = sz1 = secondary_slot_sz = 0;
smaller = 0;
while (i < num_sectors_primary || j < num_sectors_secondary) {
if (sz0 == sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
i++;
j++;
} else if (sz0 < sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/* Guarantee that multiple sectors of the secondary slot
* fit into the primary slot.
*/
if (smaller == 2) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 1;
i++;
} else {
size_t sector_size = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
#ifdef MCUBOOT_DECOMPRESS_IMAGES
if (sector_size == 0) {
/* Since this supports decompressed images, we can safely exit if slot1 is
* smaller than slot0.
*/
break;
}
#endif
sz1 += sector_size;
/* Guarantee that multiple sectors of the primary slot
* fit into the secondary slot.
*/
if (smaller == 1) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 2;
j++;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
if (sz0 == sz1) {
primary_slot_sz += sz0;
secondary_slot_sz += sz1;
/* Scratch has to fit each swap operation to the size of the larger
* sector among the primary slot and the secondary slot.
*/
if (sz0 > scratch_sz || sz1 > scratch_sz) {
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
return 0;
}
smaller = sz0 = sz1 = 0;
}
#endif
}
#ifndef MCUBOOT_DECOMPRESS_IMAGES
if ((i != num_sectors_primary) ||
(j != num_sectors_secondary) ||
(primary_slot_sz != secondary_slot_sz)) {
BOOT_LOG_WRN("Cannot upgrade: slots are not compatible");
return 0;
}
#endif
return 1;
#endif /* PM_S1_ADDRESS */
}
#define BOOT_LOG_SWAP_STATE(area, state) \
BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, " \
"image_ok=0x%x", \
(area), \
((state)->magic == BOOT_MAGIC_GOOD ? "good" : \
(state)->magic == BOOT_MAGIC_UNSET ? "unset" : \
"bad"), \
(state)->swap_type, \
(state)->copy_done, \
(state)->image_ok)
struct boot_status_table {
uint8_t bst_magic_primary_slot;
uint8_t bst_magic_scratch;
uint8_t bst_copy_done_primary_slot;
uint8_t bst_status_source;
};
/**
* This set of tables maps swap state contents to boot status location.
* When searching for a match, these tables must be iterated in order.
*/
static const struct boot_status_table boot_status_tables[] = {
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Good | Any |
* copy-done | Set | N/A |
* ----------+--------------+--------------'
* source: none |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_SET,
.bst_status_source = BOOT_STATUS_SOURCE_NONE,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Good | Any |
* copy-done | Unset | N/A |
* ----------+--------------+--------------'
* source: primary slot |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_GOOD,
.bst_magic_scratch = BOOT_MAGIC_NOTGOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Any | Good |
* copy-done | Any | N/A |
* ----------+--------------+--------------'
* source: scratch |
* ----------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_ANY,
.bst_magic_scratch = BOOT_MAGIC_GOOD,
.bst_copy_done_primary_slot = BOOT_FLAG_ANY,
.bst_status_source = BOOT_STATUS_SOURCE_SCRATCH,
},
{
/* | primary slot | scratch |
* ----------+--------------+--------------|
* magic | Unset | Any |
* copy-done | Unset | N/A |
* ----------+--------------+--------------|
* source: varies |
* ----------------------------------------+--------------------------+
* This represents one of two cases: |
* o No swaps ever (no status to read, so no harm in checking). |
* o Mid-revert; status in primary slot. |
* -------------------------------------------------------------------'
*/
.bst_magic_primary_slot = BOOT_MAGIC_UNSET,
.bst_magic_scratch = BOOT_MAGIC_ANY,
.bst_copy_done_primary_slot = BOOT_FLAG_UNSET,
.bst_status_source = BOOT_STATUS_SOURCE_PRIMARY_SLOT,
},
};
#define BOOT_STATUS_TABLES_COUNT \
(sizeof boot_status_tables / sizeof boot_status_tables[0])
/**
* Determines where in flash the most recent boot status is stored. The boot
* status is necessary for completing a swap that was interrupted by a boot
* loader reset.
*
* @return A BOOT_STATUS_SOURCE_[...] code indicating where status should
* be read from.
*/
int
swap_status_source(struct boot_loader_state *state)
{
const struct boot_status_table *table;
#if MCUBOOT_SWAP_USING_SCRATCH
struct boot_swap_state state_scratch;
#endif
struct boot_swap_state state_primary_slot;
int rc;
size_t i;
uint8_t source;
uint8_t image_index;
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
image_index = BOOT_CURR_IMG(state);
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
&state_primary_slot);
assert(rc == 0);
#if MCUBOOT_SWAP_USING_SCRATCH
rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH, &state_scratch);
assert(rc == 0);
#endif
BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
#if MCUBOOT_SWAP_USING_SCRATCH
BOOT_LOG_SWAP_STATE("Scratch", &state_scratch);
#endif
for (i = 0; i < BOOT_STATUS_TABLES_COUNT; i++) {
table = &boot_status_tables[i];
if (boot_magic_compatible_check(table->bst_magic_primary_slot,
state_primary_slot.magic) &&
#if MCUBOOT_SWAP_USING_SCRATCH
boot_magic_compatible_check(table->bst_magic_scratch,
state_scratch.magic) &&
#endif
(table->bst_copy_done_primary_slot == BOOT_FLAG_ANY ||
table->bst_copy_done_primary_slot == state_primary_slot.copy_done))
{
source = table->bst_status_source;
#if (BOOT_IMAGE_NUMBER > 1) && MCUBOOT_SWAP_USING_SCRATCH
/* In case of multi-image boot it can happen that if boot status
* info is found on scratch area then it does not belong to the
* currently examined image.
*/
if (source == BOOT_STATUS_SOURCE_SCRATCH &&
state_scratch.image_num != BOOT_CURR_IMG(state)) {
source = BOOT_STATUS_SOURCE_NONE;
}
#endif
BOOT_LOG_INF("Boot source: %s",
source == BOOT_STATUS_SOURCE_NONE ? "none" :
source == BOOT_STATUS_SOURCE_SCRATCH ? "scratch" :
source == BOOT_STATUS_SOURCE_PRIMARY_SLOT ?
"primary slot" : "BUG; can't happen");
return source;
}
}
BOOT_LOG_INF("Boot source: none");
return BOOT_STATUS_SOURCE_NONE;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
/**
* Calculates the number of sectors the scratch area can contain. A "last"
* source sector is specified because images are copied backwards in flash
* (final index to index number 0).
*
* @param last_sector_idx The index of the last source sector
* (inclusive).
* @param out_first_sector_idx The index of the first source sector
* (inclusive) gets written here.
*
* @return The number of bytes comprised by the
* [first-sector, last-sector] range.
*/
static uint32_t
boot_copy_sz(const struct boot_loader_state *state, int last_sector_idx,
int *out_first_sector_idx)
{
size_t scratch_sz;
uint32_t new_sz;
uint32_t sz;
int i;
sz = 0;
scratch_sz = boot_scratch_area_size(state);
for (i = last_sector_idx; i >= 0; i--) {
new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/*
* The secondary slot is not being checked here, because
* `boot_slots_compatible` already provides assurance that the copy size
* will be compatible with the primary slot and scratch.
*/
if (new_sz > scratch_sz) {
break;
}
sz = new_sz;
}
/* i currently refers to a sector that doesn't fit or it is -1 because all
* sectors have been processed. In both cases, exclude sector i.
*/
*out_first_sector_idx = i + 1;
return sz;
}
/**
* Finds the index of the last sector in the primary slot that needs swapping.
*
* @param state Current bootloader's state.
* @param copy_size Total number of bytes to swap.
*
* @return Index of the last sector in the primary slot that needs swapping.
*/
static int
find_last_sector_idx(const struct boot_loader_state *state, uint32_t copy_size)
{
int last_sector_idx;
uint32_t primary_slot_size;
uint32_t secondary_slot_size;
primary_slot_size = 0;
secondary_slot_size = 0;
last_sector_idx = 0;
/*
* Knowing the size of the largest image between both slots, here we
* find what is the last sector in the primary slot that needs swapping.
* Since we already know that both slots are compatible, the secondary
* slot's last sector is not really required after this check is finished.
*/
while (1) {
if ((primary_slot_size < copy_size) ||
(primary_slot_size < secondary_slot_size)) {
primary_slot_size += boot_img_sector_size(state,
BOOT_PRIMARY_SLOT,
last_sector_idx);
}
if ((secondary_slot_size < copy_size) ||
(secondary_slot_size < primary_slot_size)) {
secondary_slot_size += boot_img_sector_size(state,
BOOT_SECONDARY_SLOT,
last_sector_idx);
}
if (primary_slot_size >= copy_size &&
secondary_slot_size >= copy_size &&
primary_slot_size == secondary_slot_size) {
break;
}
last_sector_idx++;
}
return last_sector_idx;
}
/**
* Finds the number of swap operations that have to be performed to swap the two images.
*
* @param state Current bootloader's state.
* @param copy_size Total number of bytes to swap.
*
* @return The number of swap operations that have to be performed.
*/
static uint32_t
find_swap_count(const struct boot_loader_state *state, uint32_t copy_size)
{
int first_sector_idx;
int last_sector_idx;
uint32_t swap_count;
last_sector_idx = find_last_sector_idx(state, copy_size);
swap_count = 0;
while (last_sector_idx >= 0) {
boot_copy_sz(state, last_sector_idx, &first_sector_idx);
last_sector_idx = first_sector_idx - 1;
swap_count++;
}
return swap_count;
}
/**
* Swaps the contents of two flash regions within the two image slots.
*
* @param idx The index of the first sector in the range of
* sectors being swapped.
* @param sz The number of bytes to swap.
* @param bs The current boot status. This struct gets
* updated according to the outcome.
*
* @return 0 on success; nonzero on failure.
*/
static void
boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
struct boot_status *bs)
{
const struct flash_area *fap_primary_slot;
const struct flash_area *fap_secondary_slot;
const struct flash_area *fap_scratch;
uint32_t copy_sz;
uint32_t trailer_sz;
uint32_t sector_sz;
uint32_t img_off;
uint32_t scratch_trailer_off;
struct boot_swap_state swap_state;
size_t last_sector;
bool erase_scratch;
uint8_t image_index;
int rc;
/* Calculate offset from start of image area. */
img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
copy_sz = sz;
trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
/* sz in this function is always sized on a multiple of the sector size.
* The check against the start offset of the last sector
* is to determine if we're swapping the last sector. The last sector
* needs special handling because it's where the trailer lives. If we're
* copying it, we need to use scratch to write the trailer temporarily.
*
* NOTE: `use_scratch` is a temporary flag (never written to flash) which
* controls if special handling is needed (swapping last sector).
*/
last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, last_sector);
if (sector_sz < trailer_sz) {
uint32_t trailer_sector_sz = sector_sz;
while (trailer_sector_sz < trailer_sz) {
/* Consider that the image trailer may span across sectors of
* different sizes.
*/
sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, --last_sector);
trailer_sector_sz += sector_sz;
}
}
if ((img_off + sz) >
boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
copy_sz -= trailer_sz;
}
bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
image_index = BOOT_CURR_IMG(state);
rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
&fap_primary_slot);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index),
&fap_secondary_slot);
assert (rc == 0);
rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &fap_scratch);
assert (rc == 0);
if (bs->state == BOOT_STATUS_STATE_0) {
BOOT_LOG_DBG("erasing scratch area");
rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
assert(rc == 0);
if (bs->idx == BOOT_STATUS_IDX_0) {
/* Write a trailer to the scratch area, even if we don't need the
* scratch area for status. We need a temporary place to store the
* `swap-type` while we erase the primary trailer.
*/
rc = swap_status_init(state, fap_scratch, bs);
assert(rc == 0);
if (!bs->use_scratch) {
/* Prepare the primary status area... here it is known that the
* last sector is not being used by the image data so it's safe
* to erase.
*/
rc = swap_erase_trailer_sectors(state, fap_primary_slot);
assert(rc == 0);
rc = swap_status_init(state, fap_primary_slot, bs);
assert(rc == 0);
/* Erase the temporary trailer from the scratch area. */
rc = boot_erase_region(fap_scratch, 0,
flash_area_get_size(fap_scratch));
assert(rc == 0);
}
}
rc = boot_copy_region(state, fap_secondary_slot, fap_scratch,
img_off, 0, copy_sz);
assert(rc == 0);
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_1;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_1) {
rc = boot_erase_region(fap_secondary_slot, img_off, sz);
assert(rc == 0);
rc = boot_copy_region(state, fap_primary_slot, fap_secondary_slot,
img_off, img_off, copy_sz);
assert(rc == 0);
if (bs->idx == BOOT_STATUS_IDX_0 && !bs->use_scratch) {
/* If not all sectors of the slot are being swapped,
* guarantee here that only the primary slot will have the state.
*/
rc = swap_erase_trailer_sectors(state, fap_secondary_slot);
assert(rc == 0);
}
rc = boot_write_status(state, bs);
bs->state = BOOT_STATUS_STATE_2;
BOOT_STATUS_ASSERT(rc == 0);
}
if (bs->state == BOOT_STATUS_STATE_2) {
rc = boot_erase_region(fap_primary_slot, img_off, sz);
assert(rc == 0);
/* NOTE: If this is the final sector, we exclude the image trailer from
* this copy (copy_sz was truncated earlier).
*/
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
0, img_off, copy_sz);
assert(rc == 0);
if (bs->use_scratch) {
scratch_trailer_off = boot_status_off(fap_scratch);
/* copy current status that is being maintained in scratch */
rc = boot_copy_region(state, fap_scratch, fap_primary_slot,
scratch_trailer_off, img_off + copy_sz,
(BOOT_STATUS_STATE_COUNT - 1) * BOOT_WRITE_SZ(state));
BOOT_STATUS_ASSERT(rc == 0);
rc = boot_read_swap_state(fap_scratch, &swap_state);
assert(rc == 0);
if (swap_state.image_ok == BOOT_FLAG_SET) {
rc = boot_write_image_ok(fap_primary_slot);
assert(rc == 0);
}
if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
rc = boot_write_swap_info(fap_primary_slot,
swap_state.swap_type, image_index);
assert(rc == 0);
}
rc = boot_write_swap_size(fap_primary_slot, bs->swap_size);
assert(rc == 0);
#ifdef MCUBOOT_ENC_IMAGES
rc = boot_write_enc_key(fap_primary_slot, 0, bs);
assert(rc == 0);
rc = boot_write_enc_key(fap_primary_slot, 1, bs);
assert(rc == 0);
#endif
rc = boot_write_magic(fap_primary_slot);
assert(rc == 0);
}
/* If we wrote a trailer to the scratch area, erase it after we persist
* a trailer to the primary slot. We do this to prevent mcuboot from
* reading a stale status from the scratch area in case of immediate
* reset.
*/
erase_scratch = bs->use_scratch;
bs->use_scratch = 0;
rc = boot_write_status(state, bs);
bs->idx++;
bs->state = BOOT_STATUS_STATE_0;
BOOT_STATUS_ASSERT(rc == 0);
if (erase_scratch) {
rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch));
assert(rc == 0);
}
}
flash_area_close(fap_primary_slot);
flash_area_close(fap_secondary_slot);
flash_area_close(fap_scratch);
}
void
swap_run(struct boot_loader_state *state, struct boot_status *bs,
uint32_t copy_size)
{
uint32_t sz;
int first_sector_idx;
int last_sector_idx;
uint32_t swap_idx;
BOOT_LOG_INF("Starting swap using scratch algorithm.");
last_sector_idx = find_last_sector_idx(state, copy_size);
swap_idx = 0;
while (last_sector_idx >= 0) {
sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
boot_swap_sectors(first_sector_idx, sz, state, bs);
}
last_sector_idx = first_sector_idx - 1;
swap_idx++;
}
}
#endif /* !MCUBOOT_OVERWRITE_ONLY */
int app_max_size(struct boot_loader_state *state)
{
size_t num_sectors_primary;
size_t num_sectors_secondary;
size_t sz0, sz1;
size_t primary_slot_sz, secondary_slot_sz;
#ifndef MCUBOOT_OVERWRITE_ONLY
size_t scratch_sz;
#endif
size_t i, j;
int8_t smaller;
num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
#ifndef MCUBOOT_OVERWRITE_ONLY
scratch_sz = boot_scratch_area_size(state);
#endif
/*
* The following loop scans all sectors in a linear fashion, assuring that
* for each possible sector in each slot, it is able to fit in the other
* slot's sector or sectors. Slot's should be compatible as long as any
* number of a slot's sectors are able to fit into another, which only
* excludes cases where sector sizes are not a multiple of each other.
*/
i = sz0 = primary_slot_sz = 0;
j = sz1 = secondary_slot_sz = 0;
smaller = 0;
while (i < num_sectors_primary || j < num_sectors_secondary) {
if (sz0 == sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
i++;
j++;
} else if (sz0 < sz1) {
sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
/* Guarantee that multiple sectors of the secondary slot
* fit into the primary slot.
*/
if (smaller == 2) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 1;
i++;
} else {
sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
/* Guarantee that multiple sectors of the primary slot
* fit into the secondary slot.
*/
if (smaller == 1) {
BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
return 0;
}
smaller = 2;
j++;
}
#ifndef MCUBOOT_OVERWRITE_ONLY
if (sz0 == sz1) {
primary_slot_sz += sz0;
secondary_slot_sz += sz1;
/* Scratch has to fit each swap operation to the size of the larger
* sector among the primary slot and the secondary slot.
*/
if (sz0 > scratch_sz || sz1 > scratch_sz) {
BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
return 0;
}
smaller = sz0 = sz1 = 0;
}
#endif
}
#ifdef MCUBOOT_OVERWRITE_ONLY
return (sz1 < sz0 ? sz1 : sz0);
#else
return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz);
#endif
}
#else
int app_max_size(struct boot_loader_state *state)
{
const struct flash_area *fap;
int fa_id;
int rc;
uint32_t active_slot;
int primary_sz, secondary_sz;
active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
rc = flash_area_open(fa_id, &fap);
assert(rc == 0);
primary_sz = flash_area_get_size(fap);
flash_area_close(fap);
if (active_slot == BOOT_PRIMARY_SLOT) {
active_slot = BOOT_SECONDARY_SLOT;
} else {
active_slot = BOOT_PRIMARY_SLOT;
}
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
rc = flash_area_open(fa_id, &fap);
assert(rc == 0);
secondary_sz = flash_area_get_size(fap);
flash_area_close(fap);
return (secondary_sz < primary_sz ? secondary_sz : primary_sz);
}
#endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
int
boot_read_image_header(struct boot_loader_state *state, int slot,
struct image_header *out_hdr, struct boot_status *bs)
{
const struct flash_area *fap;
#ifdef MCUBOOT_SWAP_USING_SCRATCH
uint32_t swap_count;
uint32_t swap_size;
#endif
int area_id;
int hdr_slot;
int rc = 0;
#ifndef MCUBOOT_SWAP_USING_SCRATCH
(void)bs;
#endif
#if (BOOT_IMAGE_NUMBER == 1)
(void)state;
#endif
hdr_slot = slot;
#ifdef MCUBOOT_SWAP_USING_SCRATCH
/* If the slots are being swapped, the headers might have been moved to scratch area or to the
* other slot depending on the progress of the swap process.
*/
if (bs && !boot_status_is_reset(bs)) {
rc = boot_find_status(BOOT_CURR_IMG(state), &fap);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
rc = boot_read_swap_size(fap, &swap_size);
flash_area_close(fap);
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
swap_count = find_swap_count(state, swap_size);
if (bs->idx - BOOT_STATUS_IDX_0 >= swap_count) {
/* If all segments have been swapped, the header is located in the other slot */
hdr_slot = (slot == BOOT_PRIMARY_SLOT) ? BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
} else if (bs->idx - BOOT_STATUS_IDX_0 == swap_count - 1) {
/* If the last swap operation is in progress, the headers are currently being swapped
* since the first segment of each slot is the last to be processed.
*/
if (slot == BOOT_SECONDARY_SLOT && bs->state >= BOOT_STATUS_STATE_1) {
/* After BOOT_STATUS_STATE_1, the secondary image's header has been moved to the
* scratch area.
*/
hdr_slot = BOOT_NUM_SLOTS;
} else if (slot == BOOT_PRIMARY_SLOT && bs->state >= BOOT_STATUS_STATE_2) {
/* After BOOT_STATUS_STATE_2, the primary image's header has been moved to the
* secondary slot.
*/
hdr_slot = BOOT_SECONDARY_SLOT;
}
}
}
if (hdr_slot == BOOT_NUM_SLOTS) {
area_id = FLASH_AREA_IMAGE_SCRATCH;
} else {
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
}
#else
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), hdr_slot);
#endif
rc = flash_area_open(area_id, &fap);
if (rc == 0) {
rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
flash_area_close(fap);
}
if (rc != 0) {
rc = BOOT_EFLASH;
goto done;
}
done:
return rc;
}
#endif /* !MCUBOOT_SWAP_USING_MOVE */

View File

@@ -0,0 +1,154 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2019 JUUL Labs
* Copyright (c) 2020 Arm Limited
*
* 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.
*/
#include <stddef.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "bootutil_priv.h"
/*
* Initialize a TLV iterator.
*
* @param it An iterator struct
* @param hdr image_header of the slot's image
* @param fap flash_area of the slot which is storing the image
* @param type Type of TLV to look for
* @param prot true if TLV has to be stored in the protected area, false otherwise
*
* @returns 0 if the TLV iterator was successfully started
* -1 on errors
*/
int
bootutil_tlv_iter_begin(struct image_tlv_iter *it, const struct image_header *hdr,
const struct flash_area *fap, uint16_t type, bool prot)
{
uint32_t off_;
struct image_tlv_info info;
if (it == NULL || hdr == NULL || fap == NULL) {
return -1;
}
off_ = BOOT_TLV_OFF(hdr);
if (LOAD_IMAGE_DATA(hdr, fap, off_, &info, sizeof(info))) {
return -1;
}
if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) {
if (hdr->ih_protect_tlv_size != info.it_tlv_tot) {
return -1;
}
if (LOAD_IMAGE_DATA(hdr, fap, off_ + info.it_tlv_tot,
&info, sizeof(info))) {
return -1;
}
} else if (hdr->ih_protect_tlv_size != 0) {
return -1;
}
if (info.it_magic != IMAGE_TLV_INFO_MAGIC) {
return -1;
}
it->hdr = hdr;
it->fap = fap;
it->type = type;
it->prot = prot;
it->prot_end = off_ + it->hdr->ih_protect_tlv_size;
it->tlv_end = off_ + it->hdr->ih_protect_tlv_size + info.it_tlv_tot;
// position on first TLV
it->tlv_off = off_ + sizeof(info);
return 0;
}
/*
* Find next TLV
*
* @param it The image TLV iterator struct
* @param off The offset of the TLV's payload in flash
* @param len The length of the TLV's payload
* @param type If not NULL returns the type of TLV found
*
* @returns 0 if a TLV with with matching type was found
* 1 if no more TLVs with matching type are available
* -1 on errors
*/
int
bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len,
uint16_t *type)
{
struct image_tlv tlv;
int rc;
if (it == NULL || it->hdr == NULL || it->fap == NULL) {
return -1;
}
while (it->tlv_off < it->tlv_end) {
if (it->hdr->ih_protect_tlv_size > 0 && it->tlv_off == it->prot_end) {
it->tlv_off += sizeof(struct image_tlv_info);
}
rc = LOAD_IMAGE_DATA(it->hdr, it->fap, it->tlv_off, &tlv, sizeof tlv);
if (rc) {
return -1;
}
/* No more TLVs in the protected area */
if (it->prot && it->tlv_off >= it->prot_end) {
return 1;
}
if (it->type == IMAGE_TLV_ANY || tlv.it_type == it->type) {
if (type != NULL) {
*type = tlv.it_type;
}
*off = it->tlv_off + sizeof(tlv);
*len = tlv.it_len;
it->tlv_off += sizeof(tlv) + tlv.it_len;
return 0;
}
it->tlv_off += sizeof(tlv) + tlv.it_len;
}
return 1;
}
/*
* Return if a TLV entry is in the protected area.
*
* @param it The image TLV iterator struct
* @param off The offset of the entry to check.
*
* @return 0 if this TLV iterator entry is not protected.
* 1 if this TLV iterator entry is in the protected region
* -1 if the iterator is invalid.
*/
int
bootutil_tlv_iter_is_prot(struct image_tlv_iter *it, uint32_t off)
{
if (it == NULL || it->hdr == NULL || it->fap == NULL) {
return -1;
}
return off < it->prot_end;
}

View File

@@ -0,0 +1,46 @@
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
if(CONFIG_MCUBOOT_BOOTUTIL_LIB)
zephyr_interface_library_named(MCUBOOT_BOOTUTIL)
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
../
../include
../../zephyr/include
)
zephyr_library_named(mcuboot_util)
zephyr_library_sources(
../src/bootutil_public.c
)
# Sensitivity to the TEST_BOOT_IMAGE_ACCESS_HOOKS define is implemented for
# allowing the test-build with the hooks feature enabled.
if(TEST_BOOT_IMAGE_ACCESS_HOOKS)
zephyr_library_sources(
${APPLICATION_SOURCE_DIR}/hooks_sample.c
)
endif()
zephyr_library_link_libraries(MCUBOOT_BOOTUTIL)
target_link_libraries(MCUBOOT_BOOTUTIL INTERFACE zephyr_interface)
if(CONFIG_BOOT_USE_TINYCRYPT)
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
../../../ext/tinycrypt/lib/include
)
endif()
if(CONFIG_BOOT_USE_PSA_CRYPTO)
target_include_directories(MCUBOOT_BOOTUTIL INTERFACE
${ZEPHYR_MBEDTLS_MODULE_DIR}/include
)
endif()
if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_PSA_CORE_OBERON)
zephyr_link_libraries(mbedTLS)
endif()
endif()

View File

@@ -0,0 +1,41 @@
outdir/
.*.swp
target.sh
*.pyc
tags
rusty-tags.*
# mynewt
/repos/
/project.state
/bin/
/targets/
**/build/**/*
#Eclipse project files
.cproject
.project
# Compiled python modules.
*.pyc
# Setuptools distribution folder.
/scripts/dist/
# Python egg metadata, regenerated from source files by setuptools.
/scripts/*.egg-info
/scripts/*.egg
# Build dirs
*out/*/*
*out/obj/*
# Build files
*.o
*.d
*.map
*.elf
*.bin
*.hex
*.log
*.lst

View File

@@ -0,0 +1,132 @@
################################################################################
# \file BlinkyApp.mk
# \version 1.0
#
# \brief
# Makefile to describe demo application BlinkyApp for Cypress MCUBoot based applications.
#
################################################################################
# \copyright
# Copyright 2018-2019 Cypress Semiconductor Corporation
# 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.
################################################################################
include host.mk
# Cypress' MCUBoot Application supports GCC ARM only at this moment
# Set defaults to:
# - compiler GCC
# - build configuration to Debug
# - image type to BOOT
COMPILER ?= GCC_ARM
IMG_TYPE ?= BOOT
# For which core this application is built
CORE ?= CM4
# image type can be BOOT or UPGRADE
IMG_TYPES = BOOT UPGRADE
# possible values are 0 and 0xff
# internal Flash by default
ERASED_VALUE ?= 0
ifneq ($(COMPILER), GCC_ARM)
$(error Only GCC ARM is supported at this moment)
endif
CUR_APP_PATH = $(PRJ_DIR)/$(APP_NAME)
include $(PRJ_DIR)/platforms.mk
include $(PRJ_DIR)/common_libs.mk
include $(PRJ_DIR)/toolchains.mk
# Application-specific DEFINES
ifeq ($(IMG_TYPE), BOOT)
DEFINES_APP := -DBOOT_IMG
else
DEFINES_APP := -DUPGRADE_IMG
endif
# Define start of application, RAM start and size, slot size
ifeq ($(PLATFORM), PSOC_062_2M)
DEFINES_APP += -DRAM_START=0x08040000
DEFINES_APP += -DRAM_SIZE=0x10000
else ifeq ($(PLATFORM), PSOC_062_1M)
DEFINES_APP += -DRAM_START=0x08020000
DEFINES_APP += -DRAM_SIZE=0x10000
else ifeq ($(PLATFORM), PSOC_062_512K)
DEFINES_APP += -DRAM_START=0x08020000
DEFINES_APP += -DRAM_SIZE=0x10000
endif
DEFINES_APP += -DRAM_SIZE=0x10000
DEFINES_APP += -DUSER_APP_START=0x10018000
SLOT_SIZE ?= 0x10000
# Collect Test Application sources
SOURCES_APP_SRC := $(wildcard $(CUR_APP_PATH)/*.c)
# Collect all the sources
SOURCES_APP += $(SOURCES_APP_SRC)
# Collect includes for BlinkyApp
INCLUDE_DIRS_APP := $(addprefix -I, $(CURDIR))
INCLUDE_DIRS_APP += $(addprefix -I, $(CUR_APP_PATH))
# Overwite path to linker script if custom is required, otherwise default from BSP is used
ifeq ($(COMPILER), GCC_ARM)
LINKER_SCRIPT := $(subst /cygdrive/c,c:,$(CUR_APP_PATH)/linker/$(APP_NAME).ld)
else
$(error Only GCC ARM is supported at this moment)
endif
ASM_FILES_APP :=
ASM_FILES_APP += $(ASM_FILES_STARTUP)
# We still need this for MCUBoot apps signing
IMGTOOL_PATH ?= ../../scripts/imgtool.py
SIGN_ARGS := sign --header-size 1024 --pad-header --align 8 -v "2.0" -S $(SLOT_SIZE) -M 512 --overwrite-only -R $(ERASED_VALUE) -k keys/$(SIGN_KEY_FILE).pem
# Output folder
OUT := $(APP_NAME)/out
# Output folder to contain build artifacts
OUT_TARGET := $(OUT)/$(PLATFORM)
OUT_CFG := $(OUT_TARGET)/$(BUILDCFG)
# Set build directory for BOOT and UPGRADE images
ifeq ($(IMG_TYPE), UPGRADE)
ifeq ($(ENC_IMG), 1)
SIGN_ARGS += --encrypt ../../$(ENC_KEY_FILE).pem
endif
SIGN_ARGS += --pad
UPGRADE_SUFFIX :=_upgrade
OUT_CFG := $(OUT_CFG)/upgrade
else
OUT_CFG := $(OUT_CFG)/boot
endif
pre_build:
$(info [PRE_BUILD] - Generating linker script for application $(CUR_APP_PATH)/linker/$(APP_NAME).ld)
@$(CC) -E -x c $(CFLAGS) $(INCLUDE_DIRS) $(CUR_APP_PATH)/linker/$(APP_NAME)_template.ld | grep -v '^#' >$(CUR_APP_PATH)/linker/$(APP_NAME).ld
# Post build action to execute after main build job
post_build: $(OUT_CFG)/$(APP_NAME).hex
$(info [POST_BUILD] - Executing post build script for $(APP_NAME))
mv -f $(OUT_CFG)/$(APP_NAME).hex $(OUT_CFG)/$(APP_NAME)_unsigned.hex
$(PYTHON_PATH) $(IMGTOOL_PATH) $(SIGN_ARGS) $(OUT_CFG)/$(APP_NAME)_unsigned.hex $(OUT_CFG)/$(APP_NAME)$(UPGRADE_SUFFIX).hex

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="ilg.gnumcueclipse.debug.gdbjtag.openocd.launchConfigurationType">
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doContinue" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doDebugInRam" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doFirstReset" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateConsole" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateTelnetConsole" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doSecondReset" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbCLient" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbServer" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.enableSemihosting" value="true"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.firstResetType" value="init"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherCommands" value="set mem inaccessible-by-default off"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherOptions" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerConnectionAddress" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerExecutable" value="${cy_tools_path:openocd}/bin/openocd"/>
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerGdbPortNumber" value="3333"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerLog" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerOther" value="-s &quot;${cy_tools_path:openocd}/scripts&quot;&#13;&#10;-s &quot;${workspace_loc}/BlinkyLED_config/GeneratedSource&quot;&#13;&#10;-c &quot;source [find interface/kitprog3.cfg]&quot;&#13;&#10;-c &quot;source [find target/psoc6_2m.cfg]&quot;&#13;&#10;-c &quot;gdb_port 3332&quot;&#13;&#10;-c &quot;puts stderr {Started by GNU MCU Eclipse}&quot;&#13;&#10;-c &quot;init; reset init&quot;"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTclPortNumber" value="6666"/>
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTelnetPortNumber" value="4444"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherInitCommands" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherRunCommands" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.secondResetType" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.svdPath" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageFileName" value="/Users/rnok/repos/cy_mcuboot_project/cy_mcuboot/boot/cypress/BlinkyApp/out/boot/CY8CKIT-064S2-4343W/Debug/BlinkyApp.elf"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageOffset" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.ipAddress" value="localhost"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.jtagDevice" value="GNU MCU OpenOCD"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadImage" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadSymbols" value="true"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.pcRegister" value=""/>
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.portNumber" value="3333"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setPcRegister" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setResume" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setStopAt" value="false"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.stopAt" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsFileName" value="/Users/rnok/repos/cy_mcuboot_project/cy_mcuboot/boot/cypress/BlinkyApp/out/CY8CKIT-064S2-4343W/Debug/boot/BlinkyApp.elf"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsOffset" value=""/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForImage" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForSymbols" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForImage" value="true"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForSymbols" value="true"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useRemoteTarget" value="true"/>
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="${cy_sdk_install_dir}/tools/gcc-7.2.1-1.0/bin/arm-none-eabi-gdb${cy_exe_platform_ext}"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.UPDATE_THREADLIST_ON_SUSPEND" value="false"/>
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/>
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="boot/cypress/BlinkyApp/out/PSOC_062_2M/Debug/boot/BlinkyApp.elf"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="cy_mcuboot"/>
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="true"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value="ilg.gnuarmeclipse.managedbuild.cross.toolchain.base.1139973781"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/cy_mcuboot"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#10;&lt;memoryBlockExpression address=&quot;268566528&quot; label=&quot;0x10020000&quot;/&gt;&#10;&lt;memoryBlockExpression address=&quot;268632064&quot; label=&quot;0x10030000&quot;/&gt;&#10;&lt;/memoryBlockExpressionList&gt;&#10;"/>
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
</launchConfiguration>

View File

@@ -0,0 +1,165 @@
### Blinking LED test application for MCUboot bootloader
### Description
Implements simple Blinky LED CM4 application to demonstrate MCUboot Application operation in terms of BOOT and UPGRADE process.
It is started by MCUboot Application which is running on CM0p.
Functionality:
* Blinks RED led with 2 different rates, depending on type of image - BOOT or UPGRADE.
* Prints debug info and version of itself to terminal at 115200 baud.
* Can be built for BOOT slot or UPGRADE slot of bootloader.
Currently supported platforms
* PSOC_062_2M
* PSOC_062_1M
* PSOC_062_512K
### Hardware limitations
Since this application is created to demonstrate MCUboot library features and not as reference examples some considerations are taken.
1. Port/pin `P5_0` and `P5_1` used to configure serial port for debug prints. These pins are the most commonly used for serial port connection among available Cypress PSoC 6 kits. If you try to use custom hardware with this application - change definitions of `CY_DEBUG_UART_TX` and `CY_DEBUG_UART_RX` in `main.c` of BlinkyApp to port/pin pairs corresponding to your design.
2. Port `GPIO_PRT13` pin `7U` used to define user connection LED. This pin is the most commonly used for USER_LED connection among available Cypress PSoC 6 kits. If you try to use custom hardware with this application - change definitions of `LED_PORT` and `LED_PIN` in `main.c` of BlinkyApp to port/pin pairs corresponding to your design.
### Pre-build action
Pre-build action is implemented for defining start address and size of flash, as well as RAM start address and size for BlinkyApp.
These values are set by specifing following macros: `-DUSER_APP_SIZE`, `-DUSER_APP_START`, `-DRAM_SIZE`, `-DRAM_START` in makefile.
Pre-build action calls GCC preprocessor which intantiates defines for particular values in `BlinkyApp_template.ld`.
Default values set for currently supported targets:
* `BlinkyApp.mk` to `-DUSER_APP_START=0x10018000`
**Important**: make sure RAM areas of CM4-based BlinkyApp and CM0p-based MCUBootApp bootloader do not overlap.
Memory (stack) corruption of CM0p application can cause failure if SystemCall-served operations invoked from CM4.
### Building an application
Root directory for build is **boot/cypress.**
The following command will build regular HEX file of a BlinkyApp for BOOT slot. Substitute `PLATFORM=` to a paltform name you use in all following commands.
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT
This have following defaults suggested:
BUILDCFG=Debug
IMG_TYPE=BOOT
To build UPGRADE image use following command:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x10000
Note: HEADER_OFFSET=%SLOT_SIZE%
Example command-line for single-image:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT
**Building Multi-Image**
`BlinkyApp` can be built to use in multi-image bootloader configuration.
To get appropriate artifacts to use with multi image MCUBootApp, makefile flag `HEADER_OFFSET=` can be used.
Example usage:
Considering default config:
* first image BOOT (PRIMARY) slot start `0x10018000`
* slot size `0x10000`
* second image BOOT (PRIMARY) slot start `0x10038000`
To get appropriate artifact for second image PRIMARY slot run this command:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=BOOT HEADER_OFFSET=0x20000
*Note:* only 2 images are supported at the moment.
**How to build upgrade image for external memory:**
To prepare MCUBootApp for work with external memory please refer to `MCUBootApp/ExternalMemory.md`.
For build BlinkyApp upgrade image for external memory use command:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x7FE8000 ERASED_VALUE=0xff
`HEADER_OFFSET` defines the offset from original boot image address. This one in line above suggests secondary slot will start from `0x18000000`.
`ERASED_VALUE` defines the memory cell contents in erased state. It is `0x00` for PSoC6's internal Flash and `0xff` for S25FL512S.
In case of using muti-image configuration, upgrade image for second application can be built using next command:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x8028000 ERASED_VALUE=0xff
Note: for S25FL512S block address shuld be mutiple by 0x40000
**How to build encrypted upgrade image :**
To prepare MCUBootApp for work with encrypted upgrade image please refer to `MCUBootApp/Readme.md`.
To obtain encrypted upgrade image of BlinkyApp extra flag `ENC_IMG=1` should be passed in command line, for example:
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x20000 ENC_IMG=1
This also suggests user already placed corresponing `*.pem` key in `\keys` folder. The key variables are defined in root `Makefile` as `SIGN_KEY_FILE` and `ENC_KEY_FILE`
### Post-build
Post build action is executed at compile time for `BlinkyApp`. In case of build for `PSOC_062_2M` platform it calls `imgtool` from `MCUboot` scripts and adds signature to compiled image.
Flags passed to `imgtool` for signature are defined in `SIGN_ARGS` variable in BlinkyApp.mk.
### How to program an application
Use any preferred tool for programming hex files.
Hex file names to use for programming:
`BlinkyApp` always produce build artifacts in 2 separate folders - `boot` and `upgrade`.
`BlinkyApp` built to run with `MCUBootApp` produces files with name BlinkyApp.hex in `boot` directory and `BlinkyApp_upgrade.hex` in `upgrade` folder. These files are ready to be flashed to the board.
`BlinkyApp_unsigned.hex` hex file is also preserved in both cases for possible troubleshooting.
Files to use for programming are:
`BOOT` - boot/BlinkyApp.hex
`UPGRADE` - upgrade/BlinkyApp_upgrade.hex
**Flags:**
- `BUILDCFG` - configuration **Release** or **Debug**
- `MAKEINFO` - 0 (default) - less build info, 1 - verbose output of compilation.
- `HEADER_OFFSET` - 0 (default) - no offset of output hex file, 0x%VALUE% - offset for output hex file. Value 0x10000 is slot size MCUboot Bootloader in this example.
- `IMG_TYPE` - `BOOT` (default) - build image for BOOT slot of MCUboot Bootloader, `UPGRADE` - build image for UPGRADE slot of MCUboot Bootloader.
- `ENC_IMG` - 0 (default) - build regular upgrade image, `1` - build encrypted upgrade image (MCUBootApp should also be built with this flash set 1)
**NOTE**: In case of `UPGRADE` image `HEADER_OFFSET` should be set to MCUboot Bootloader slot size.
### Example terminal output
When user application programmed in BOOT slot:
===========================
[BlinkyApp] BlinkyApp v1.0 [CM4]
===========================
[BlinkyApp] GPIO initialized
[BlinkyApp] UART initialized
[BlinkyApp] Retarget I/O set to 115200 baudrate
[BlinkyApp] Red led blinks with 1 sec period
When user application programmed in UPRADE slot and upgrade procedure was successful:
===========================
[BlinkyApp] BlinkyApp v2.0 [+]
===========================
[BlinkyApp] GPIO initialized
[BlinkyApp] UART initialized
[BlinkyApp] Retarget I/O set to 115200 baudrate
[BlinkyApp] Red led blinks with 0.25 sec period

View File

@@ -0,0 +1,60 @@
################################################################################
# \file libs.mk
# \version 1.0
#
# \brief
# Makefile to describe libraries needed for Cypress MCUBoot based applications.
#
################################################################################
# \copyright
# Copyright 2018-2019 Cypress Semiconductor Corporation
# 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.
################################################################################
################################################################################
# PDL library
################################################################################
PDL_VERSION = 121
#
CUR_LIBS_PATH = $(PRJ_DIR)/libs
# Collect source files for Retarget-io
SOURCES_RETARGET_IO := $(wildcard $(CUR_LIBS_PATH)/retarget-io/*.c)
SOURCES_WATCHDOG := $(wildcard $(CUR_LIBS_PATH)/watchdog/*.c)
# Collect source files for HAL
SOURCES_HAL := $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/*.c)
SOURCES_HAL += $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/triggers/*.c)
SOURCES_HAL += $(wildcard $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/source/pin_packages/*.c)
# Retarget-io related include directories
INCLUDE_DIRS_RETARGET_IO := $(CUR_LIBS_PATH)/retarget-io
INCLUDE_DIRS_WATCHDOG := $(CUR_LIBS_PATH)/watchdog
# Collect dirrectories containing headers for PSOC6 HAL
INCLUDE_DIRS_HAL := $(CUR_LIBS_PATH)/psoc6hal/include
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include/pin_packages
INCLUDE_DIRS_HAL += $(CUR_LIBS_PATH)/psoc6hal/COMPONENT_PSOC6HAL/include/triggers
# Collected source files for libraries
SOURCES_LIBS += $(SOURCES_RETARGET_IO)
SOURCES_LIBS += $(SOURCES_WATCHDOG)
SOURCES_LIBS += $(SOURCES_HAL)
# Collected include directories for libraries
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_RETARGET_IO))
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_WATCHDOG))
INCLUDE_DIRS_LIBS += $(addprefix -I,$(INCLUDE_DIRS_HAL))

View File

@@ -0,0 +1,425 @@
/***************************************************************************//**
* \file cy8c6xxa_cm4_dual.ld
* \version 2.60
*
* Linker file for the GNU C compiler.
*
* The main purpose of the linker script is to describe how the sections in the
* input files should be mapped into the output file, and to control the memory
* layout of the output file.
*
* \note The entry point location is fixed and starts at 0x10000000. The valid
* application image should be placed there.
*
* \note The linker files included with the PDL template projects must be generic
* and handle all common use cases. Your project may not use every section
* defined in the linker files. In that case you may see warnings during the
* build process. In your project, you can simply comment out or remove the
* relevant code in the linker file.
*
********************************************************************************
* \copyright
* Copyright 2016-2019 Cypress Semiconductor Corporation
* 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.
*******************************************************************************/
#include <main.h>
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
ENTRY(Reset_Handler)
/* Size of the stack section at the end of CM4 SRAM */
STACK_SIZE = 0x1000;
/* The size of the MCU boot header area at the start of FLASH */
BOOT_HEADER_SIZE = 0x400;
/* Force symbol to be entered in the output file as an undefined symbol. Doing
* this may, for example, trigger linking of additional modules from standard
* libraries. You may list several symbols for each EXTERN, and you may use
* EXTERN multiple times. This command has the same effect as the -u command-line
* option.
*/
EXTERN(Reset_Handler)
/* The MEMORY section below describes the location and size of blocks of memory in the target.
* Use this section to specify the memory regions available for allocation.
*/
MEMORY
{
/* The ram and flash regions control RAM and flash memory allocation for the CM4 core.
* You can change the memory allocation by editing the 'ram' and 'flash' regions.
* Note that 2 KB of RAM (at the end of the SRAM) are reserved for system use.
* Using this memory region for other purposes will lead to unexpected behavior.
* Your changes must be aligned with the corresponding memory regions for CM0+ core in 'xx_cm0plus.ld',
* where 'xx' is the device group; for example, 'cy8c6xx7_cm0plus.ld'.
*/
ram (rwx) : ORIGIN = RAM_START, LENGTH = RAM_SIZE
flash (rx) : ORIGIN = USER_APP_START, LENGTH = USER_APP_SIZE
/* This is a 32K flash region used for EEPROM emulation. This region can also be used as the general purpose flash.
* You can assign sections to this memory region for only one of the cores.
* Note some middleware (e.g. BLE, Emulated EEPROM) can place their data into this memory region.
* Therefore, repurposing this memory region will prevent such middleware from operation.
*/
em_eeprom (rx) : ORIGIN = 0x14000000, LENGTH = 0x8000 /* 32 KB */
/* The following regions define device specific memory regions and must not be changed. */
sflash_user_data (rx) : ORIGIN = 0x16000800, LENGTH = 0x800 /* Supervisory flash: User data */
sflash_nar (rx) : ORIGIN = 0x16001A00, LENGTH = 0x200 /* Supervisory flash: Normal Access Restrictions (NAR) */
sflash_public_key (rx) : ORIGIN = 0x16005A00, LENGTH = 0xC00 /* Supervisory flash: Public Key */
sflash_toc_2 (rx) : ORIGIN = 0x16007C00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 */
sflash_rtoc_2 (rx) : ORIGIN = 0x16007E00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 Copy */
xip (rx) : ORIGIN = 0x18000000, LENGTH = 0x8000000 /* 128 MB */
efuse (r) : ORIGIN = 0x90700000, LENGTH = 0x100000 /* 1 MB */
}
/* Library configurations */
GROUP(libgcc.a libc.a libm.a libnosys.a)
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __copy_table_start__
* __copy_table_end__
* __zero_table_start__
* __zero_table_end__
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
* __Vectors_End
* __Vectors_Size
*/
SECTIONS
{
/* Cortex-M4 application flash area */
.text ORIGIN(flash) + BOOT_HEADER_SIZE :
{
. = ALIGN(4);
__Vectors = . ;
KEEP(*(.vectors))
. = ALIGN(4);
__Vectors_End = .;
__Vectors_Size = __Vectors_End - __Vectors;
__end__ = .;
. = ALIGN(4);
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
/* Read-only code (constants). */
*(.rodata .rodata.* .constdata .constdata.* .conststring .conststring.*)
KEEP(*(.eh_frame*))
} > flash
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > flash
__exidx_end = .;
/* To copy multiple ROM to RAM sections,
* uncomment .copy.table section and,
* define __STARTUP_COPY_MULTIPLE in startup_psoc6_02_cm4.S */
.copy.table :
{
. = ALIGN(4);
__copy_table_start__ = .;
/* Copy interrupt vectors from flash to RAM */
LONG (__Vectors) /* From */
LONG (__ram_vectors_start__) /* To */
LONG (__Vectors_End - __Vectors) /* Size */
/* Copy data section to RAM */
LONG (__etext) /* From */
LONG (__data_start__) /* To */
LONG (__data_end__ - __data_start__) /* Size */
__copy_table_end__ = .;
} > flash
/* To clear multiple BSS sections,
* uncomment .zero.table section and,
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_psoc6_02_cm4.S */
.zero.table :
{
. = ALIGN(4);
__zero_table_start__ = .;
LONG (__bss_start__)
LONG (__bss_end__ - __bss_start__)
__zero_table_end__ = .;
} > flash
__etext = . ;
.ramVectors (NOLOAD) : ALIGN(8)
{
__ram_vectors_start__ = .;
KEEP(*(.ram_vectors))
__ram_vectors_end__ = .;
} > ram
.data __ram_vectors_end__ : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*))
. = ALIGN(4);
KEEP(*(.cy_ramfunc*))
. = ALIGN(4);
__data_end__ = .;
} > ram
/* Place variables in the section that should not be initialized during the
* device startup.
*/
.noinit (NOLOAD) : ALIGN(8)
{
KEEP(*(.noinit))
} > ram
/* The uninitialized global or static variables are placed in this section.
*
* The NOLOAD attribute tells linker that .bss section does not consume
* any space in the image. The NOLOAD attribute changes the .bss type to
* NOBITS, and that makes linker to A) not allocate section in memory, and
* A) put information to clear the section with all zeros during application
* loading.
*
* Without the NOLOAD attribute, the .bss section might get PROGBITS type.
* This makes linker to A) allocate zeroed section in memory, and B) copy
* this section to RAM during application loading.
*/
.bss (NOLOAD):
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > ram
.heap (NOLOAD):
{
__HeapBase = .;
__end__ = .;
end = __end__;
KEEP(*(.heap*))
. = ORIGIN(ram) + LENGTH(ram) - STACK_SIZE;
__HeapLimit = .;
} > ram
/* .stack_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later */
.stack_dummy (NOLOAD):
{
KEEP(*(.stack*))
} > ram
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(ram) + LENGTH(ram);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
/* Used for the digital signature of the secure application and the Bootloader SDK application.
* The size of the section depends on the required data size. */
.cy_app_signature ORIGIN(flash) + LENGTH(flash) - 256 :
{
KEEP(*(.cy_app_signature))
} > flash
/* Emulated EEPROM Flash area */
.cy_em_eeprom :
{
KEEP(*(.cy_em_eeprom))
} > em_eeprom
/* Supervisory Flash: User data */
.cy_sflash_user_data :
{
KEEP(*(.cy_sflash_user_data))
} > sflash_user_data
/* Supervisory Flash: Normal Access Restrictions (NAR) */
.cy_sflash_nar :
{
KEEP(*(.cy_sflash_nar))
} > sflash_nar
/* Supervisory Flash: Public Key */
.cy_sflash_public_key :
{
KEEP(*(.cy_sflash_public_key))
} > sflash_public_key
/* Supervisory Flash: Table of Content # 2 */
.cy_toc_part2 :
{
KEEP(*(.cy_toc_part2))
} > sflash_toc_2
/* Supervisory Flash: Table of Content # 2 Copy */
.cy_rtoc_part2 :
{
KEEP(*(.cy_rtoc_part2))
} > sflash_rtoc_2
/* Places the code in the Execute in Place (XIP) section. See the smif driver
* documentation for details.
*/
.cy_xip :
{
KEEP(*(.cy_xip))
} > xip
/* eFuse */
.cy_efuse :
{
KEEP(*(.cy_efuse))
} > efuse
/* These sections are used for additional metadata (silicon revision,
* Silicon/JTAG ID, etc.) storage.
*/
.cymeta 0x90500000 : { KEEP(*(.cymeta)) } :NONE
}
/* The following symbols used by the cymcuelftool. */
/* Flash */
__cy_memory_0_start = 0x10000000;
__cy_memory_0_length = 0x00200000;
__cy_memory_0_row_size = 0x200;
/* Emulated EEPROM Flash area */
__cy_memory_1_start = 0x14000000;
__cy_memory_1_length = 0x8000;
__cy_memory_1_row_size = 0x200;
/* Supervisory Flash */
__cy_memory_2_start = 0x16000000;
__cy_memory_2_length = 0x8000;
__cy_memory_2_row_size = 0x200;
/* XIP */
__cy_memory_3_start = 0x18000000;
__cy_memory_3_length = 0x08000000;
__cy_memory_3_row_size = 0x200;
/* eFuse */
__cy_memory_4_start = 0x90700000;
__cy_memory_4_length = 0x100000;
__cy_memory_4_row_size = 1;
/* EOF */

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2020 Cypress Semiconductor Corporation
*
* 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.
*/
/*******************************************************************************/
#include "system_psoc6.h"
#include "cy_pdl.h"
#include "cyhal.h"
#include "cy_retarget_io.h"
#include "watchdog.h"
/* Define pins for UART debug output */
#define CY_DEBUG_UART_TX (P5_1)
#define CY_DEBUG_UART_RX (P5_0)
#if defined(PSOC_062_2M)
#warning "Check if User LED is correct for your target board."
#define LED_PORT GPIO_PRT13
#define LED_PIN 7U
#elif defined(PSOC_062_1M)
#define LED_PORT GPIO_PRT13
#define LED_PIN 7U
#elif defined(PSOC_062_512K)
#define LED_PORT GPIO_PRT11
#define LED_PIN 1U
#endif
#define LED_NUM 5U
#define LED_DRIVEMODE CY_GPIO_DM_STRONG_IN_OFF
#define LED_INIT_DRIVESTATE 1
const cy_stc_gpio_pin_config_t LED_config =
{
.outVal = 1,
.driveMode = CY_GPIO_DM_STRONG_IN_OFF,
.hsiom = HSIOM_SEL_GPIO,
.intEdge = CY_GPIO_INTR_DISABLE,
.intMask = 0UL,
.vtrip = CY_GPIO_VTRIP_CMOS,
.slewRate = CY_GPIO_SLEW_FAST,
.driveSel = CY_GPIO_DRIVE_FULL,
.vregEn = 0UL,
.ibufMode = 0UL,
.vtripSel = 0UL,
.vrefSel = 0UL,
.vohSel = 0UL,
};
#define WATCHDOG_UPD_MESSAGE "[BlinkyApp] Update watchdog timer started in MCUBootApp to mark successful start of user app\r\n"
#define WATCHDOG_FREE_MESSAGE "[BlinkyApp] Turn off watchdog timer\r\n"
#ifdef BOOT_IMG
#define BLINK_PERIOD (1000u)
#define GREETING_MESSAGE_VER "[BlinkyApp] BlinkyApp v1.0 [CM4]\r\n"
#define GREETING_MESSAGE_INFO "[BlinkyApp] Red led blinks with 1 sec period\r\n"
#elif defined(UPGRADE_IMG)
#define BLINK_PERIOD (250u)
#define GREETING_MESSAGE_VER "[BlinkyApp] BlinkyApp v2.0 [+]\r\n"
#define GREETING_MESSAGE_INFO "[BlinkyApp] Red led blinks with 0.25 sec period\r\n"
#else
#error "[BlinkyApp] Please specify type of image: -DBOOT_IMG or -DUPGRADE_IMG\r\n"
#endif
void check_result(int res)
{
if (res != CY_RSLT_SUCCESS) {
CY_ASSERT(0);
}
}
void test_app_init_hardware(void)
{
/* enable interrupts */
__enable_irq();
/* Disabling watchdog so it will not interrupt normal flow later */
Cy_GPIO_Pin_Init(LED_PORT, LED_PIN, &LED_config);
/* Initialize retarget-io to use the debug UART port */
check_result(cy_retarget_io_init(CY_DEBUG_UART_TX, CY_DEBUG_UART_RX,
CY_RETARGET_IO_BAUDRATE));
printf("\n===========================\r\n");
printf(GREETING_MESSAGE_VER);
printf("===========================\r\n");
printf("[BlinkyApp] GPIO initialized \r\n");
printf("[BlinkyApp] UART initialized \r\n");
printf("[BlinkyApp] Retarget I/O set to 115200 baudrate \r\n");
}
int main(void)
{
uint32_t blinky_period = BLINK_PERIOD;
test_app_init_hardware();
printf(GREETING_MESSAGE_INFO);
/* Update watchdog timer to mark successful start up of application */
printf(WATCHDOG_UPD_MESSAGE);
cy_wdg_kick();
printf(WATCHDOG_FREE_MESSAGE);
cy_wdg_free();
for (;;)
{
/* Toggle the user LED periodically */
Cy_SysLib_Delay(blinky_period/2);
/* Invert the USER LED state */
Cy_GPIO_Inv(LED_PORT, LED_PIN);
}
return 0;
}

View File

@@ -0,0 +1,25 @@
/*
\copyright
* Copyright 2017-2019 Cypress Semiconductor Corporation
* 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.
*******************************************************************************/
#ifndef USER_APP_START
#define USER_APP_START 0x10000000
#endif
#ifndef USER_APP_SIZE
#define USER_APP_SIZE 0x10000
#endif

View File

@@ -0,0 +1,100 @@
### External Memory support for Secondary Slot
**Description**
Given document describes the use of external memory module as a secondary (upgrade) slot with Cypress' PSoC6 devices.
The demonstration device is CY8CPROTO-062-4343W board which is PSoC6 device with 2M of Flash available.
The memory module present on board is S25FL512SAGMFI010 512-Mbit external Quad SPI NOR Flash.
Using external memory for secondary slot allows to nearly double the size of Boot Image.
**Operation Design and Flow**
The design is based on using SFDP command's auto-discovery functionality of memory module IC and Cypress' SMIF PDL driver.
It is assumed that user's design meets following:
* The memory-module used is SFDP-compliant;
* There only one module is being used for secondary slot;
* Only "OWERWRITE" bootloading scheme is used;
* The address for secondary slot should start from 0x18000000.
This corresponds to PSoC6's SMIF (Serial Memory InterFace) IP block mapping.
* The slot size for upgrade slot is even (or smaller) to erase size (0x40000) of given memory module.
This requirement is accepted for code simplicity.
The default flash map implemented is the following:
Single-image mode.
`[0x10000000, 0x10018000]` - MCUBootApp (bootloader) area;
`[0x10018000, 0x10028000]` - primary slot for BlinkyApp;
`[0x18000000, 0x18010000]` - secondary slot for BlinkyApp;
`[0x10038000, 0x10039000]` - scratch area (not used);
Multi(dual)-image mode.
`[0x10000000, 0x10018000]` - MCUBootApp (bootloader) area;
`[0x10018000, 0x10028000]` - primary1 slot for BlinkyApp;
`[0x18000000, 0x18010000]` - secondary1 slot for BlinkyApp;
`[0x10038000, 0x10048000]` - primary2 slot for user app ;
`[0x18040000, 0x18050000]` - secondary2 slot for user app;
`[0x10058000, 0x10059000]` - scratch area (not used);
Size of slots `0x10000` - 64kB
**Note 1**: make sure primary, secondary slot and bootloader app sizes are appropriate and correspond to flash area size defined in Applications' linker files.
**Note 2**: make sure secondary slot start address is aligned (or smaller) to erase size (0x40000 - 256kB).
MCUBootApp's `main.c` contains the call to Init-SFDP API which performs required GPIO configurations, SMIF IP block configurations, SFDP protocol read and memory-config structure initialization.
After that MCUBootApp is ready to accept upgrade image from external memory module.
Once valid upgrade image was accepted the image in external memory will be erased.
**How to enable external memory support:**
1. Pass `USE_EXTERNAL_FLASH=1` flag to `make` command when building MCUBootApp.
2. Navigate to `cy_flash_map.c` and check if secondary slot start address and size meet the application's needs.
3. Define which slave select is used for external memory on a board by setting `smif_id` value in `main.c`.
4. Build MCUBootApp as described in `Readme.md`.
**Note 3**: External memory code is developed basing on PDL and can be run on CM0p core only. It may require modifications if used on CM4.
**How to build upgrade image for external memory:**
make app APP_NAME=BlinkyApp PLATFORM=PSOC_062_2M IMG_TYPE=UPGRADE HEADER_OFFSET=0x7FE8000 ERASED_VALUE=0xff
`HEADER_OFFSET` defines the offset from original boot image address. This one in line above suggests secondary slot will start from `0x18000000`.
`ERASED_VALUE` defines the memory cell contents in erased state. It is `0x00` for PSoC6's internal Flash and `0xff` for S25FL512S.
**Programming to external memory**
The MCUBootApp programming can be done similarly to described in `Readme.md`:
export OPENOCD=/Applications/ModusToolbox/tools_2.1/openocd
${OPENOCD}/bin/openocd -s ${OPENOCD}/scripts \
-f ${OPENOCD}/scripts/interface/kitprog3.cfg \
-f ${OPENOCD}/scripts/target/psoc6_2m.cfg \
-c "init; psoc6 sflash_restrictions 1" \
-c "init; reset init; program PATH_TO_APPLICATION.hex" \
-c "resume; reset; exit"
There is a NULL-pointer placed for SMIF configuration pointer in TOC2 (Table Of Contents, `cy_serial_flash_prog.c`).
This is done to force CY8PROTO-062-4343W DAP Link firmware to program external memory with hardcoded values.
1. Press SW3 Mode button on a board to switch the board into DAP Link mode.
2. Once DAP Link removable disk appeared drop (copy) the upgrade image HEX file to it.
This will invoke firmware to program external memory.
**Note 3:** the programming of external memory is limited to S25FL512S p/n only at this moment.

View File

@@ -0,0 +1,418 @@
/***************************************************************************//**
* \file cy8c6xxa_cm0plus.ld
* \version 2.60
*
* Linker file for the GNU C compiler.
*
* The main purpose of the linker script is to describe how the sections in the
* input files should be mapped into the output file, and to control the memory
* layout of the output file.
*
* \note The entry point location is fixed and starts at 0x10000000. The valid
* application image should be placed there.
*
* \note The linker files included with the PDL template projects must be generic
* and handle all common use cases. Your project may not use every section
* defined in the linker files. In that case you may see warnings during the
* build process. In your project, you can simply comment out or remove the
* relevant code in the linker file.
*
********************************************************************************
* \copyright
* Copyright 2016-2019 Cypress Semiconductor Corporation
* 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.
*******************************************************************************/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
ENTRY(Reset_Handler)
/* Size of the stack section at the end of CM0+ SRAM */
STACK_SIZE = 0x1000;
/* Force symbol to be entered in the output file as an undefined symbol. Doing
* this may, for example, trigger linking of additional modules from standard
* libraries. You may list several symbols for each EXTERN, and you may use
* EXTERN multiple times. This command has the same effect as the -u command-line
* option.
*/
EXTERN(Reset_Handler)
/* The MEMORY section below describes the location and size of blocks of memory in the target.
* Use this section to specify the memory regions available for allocation.
*/
MEMORY
{
/* The ram and flash regions control RAM and flash memory allocation for the CM0+ core.
* You can change the memory allocation by editing the 'ram' and 'flash' regions.
* Note that 2 KB of RAM (at the end of the SRAM) are reserved for system use.
* Using this memory region for other purposes will lead to unexpected behavior.
* Your changes must be aligned with the corresponding memory regions for the CM4 core in 'xx_cm4_dual.ld',
* where 'xx' is the device group; for example, 'cy8c6xx7_cm4_dual.ld'.
*/
public_ram (rw) : ORIGIN = 0x08000000, LENGTH = 0x800
ram (rwx) : ORIGIN = 0x08000800, LENGTH = 0x1F800
flash (rx) : ORIGIN = 0x10000000, LENGTH = 0x18000
/* This is a 32K flash region used for EEPROM emulation. This region can also be used as the general purpose flash.
* You can assign sections to this memory region for only one of the cores.
* Note some middleware (e.g. BLE, Emulated EEPROM) can place their data into this memory region.
* Therefore, repurposing this memory region will prevent such middleware from operation.
*/
em_eeprom (rx) : ORIGIN = 0x14000000, LENGTH = 0x8000 /* 32 KB */
/* The following regions define device specific memory regions and must not be changed. */
sflash_user_data (rx) : ORIGIN = 0x16000800, LENGTH = 0x800 /* Supervisory flash: User data */
sflash_nar (rx) : ORIGIN = 0x16001A00, LENGTH = 0x200 /* Supervisory flash: Normal Access Restrictions (NAR) */
sflash_public_key (rx) : ORIGIN = 0x16005A00, LENGTH = 0xC00 /* Supervisory flash: Public Key */
sflash_toc_2 (rx) : ORIGIN = 0x16007C00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 */
sflash_rtoc_2 (rx) : ORIGIN = 0x16007E00, LENGTH = 0x200 /* Supervisory flash: Table of Content # 2 Copy */
xip (rx) : ORIGIN = 0x18000000, LENGTH = 0x8000000 /* 128 MB */
efuse (r) : ORIGIN = 0x90700000, LENGTH = 0x100000 /* 1 MB */
}
/* Library configurations */
GROUP(libgcc.a libc.a libm.a libnosys.a)
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __copy_table_start__
* __copy_table_end__
* __zero_table_start__
* __zero_table_end__
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
* __Vectors_End
* __Vectors_Size
*/
SECTIONS
{
.cy_app_header :
{
KEEP(*(.cy_app_header))
} > flash
/* Cortex-M0+ application flash area */
.text :
{
. = ALIGN(4);
__Vectors = . ;
KEEP(*(.vectors))
. = ALIGN(4);
__Vectors_End = .;
__Vectors_Size = __Vectors_End - __Vectors;
__end__ = .;
. = ALIGN(4);
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
/* Read-only code (constants). */
*(.rodata .rodata.* .constdata .constdata.* .conststring .conststring.*)
KEEP(*(.eh_frame*))
} > flash
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > flash
__exidx_end = .;
/* To copy multiple ROM to RAM sections,
* uncomment .copy.table section and,
* define __STARTUP_COPY_MULTIPLE in startup_psoc6_02_cm0plus.S */
.copy.table :
{
. = ALIGN(4);
__copy_table_start__ = .;
/* Copy interrupt vectors from flash to RAM */
LONG (__Vectors) /* From */
LONG (__ram_vectors_start__) /* To */
LONG (__Vectors_End - __Vectors) /* Size */
/* Copy data section to RAM */
LONG (__etext) /* From */
LONG (__data_start__) /* To */
LONG (__data_end__ - __data_start__) /* Size */
__copy_table_end__ = .;
} > flash
/* To clear multiple BSS sections,
* uncomment .zero.table section and,
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_psoc6_02_cm0plus.S */
.zero.table :
{
. = ALIGN(4);
__zero_table_start__ = .;
LONG (__bss_start__)
LONG (__bss_end__ - __bss_start__)
__zero_table_end__ = .;
} > flash
__etext = . ;
/* Set stack top to end of RAM, and stack limit move down by
* size of stack_dummy section */
__StackTop = ORIGIN(ram) + LENGTH(ram);
__StackLimit = __StackTop - STACK_SIZE ;
PROVIDE(__stack = __StackTop);
.stackSpace (NOLOAD) : ALIGN(8)
{
. = . + STACK_SIZE ;
} > ram
.ramVectors (NOLOAD) : ALIGN(8)
{
__ram_vectors_start__ = .;
KEEP(*(.ram_vectors))
__ram_vectors_end__ = .;
} > ram
/* Unprotected public RAM */
.cy_sharedmem (NOLOAD):
{
. = ALIGN(4);
__public_ram_start__ = .;
KEEP(*(.cy_sharedmem))
. = ALIGN(4);
__public_ram_end__ = .;
} > public_ram
.data __ram_vectors_end__ : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*))
. = ALIGN(4);
KEEP(*(.cy_ramfunc*))
. = ALIGN(4);
__data_end__ = .;
} > ram
/* Place variables in the section that should not be initialized during the
* device startup.
*/
.noinit (NOLOAD) : ALIGN(8)
{
KEEP(*(.noinit))
} > ram
/* The uninitialized global or static variables are placed in this section.
*
* The NOLOAD attribute tells linker that .bss section does not consume
* any space in the image. The NOLOAD attribute changes the .bss type to
* NOBITS, and that makes linker to A) not allocate section in memory, and
* A) put information to clear the section with all zeros during application
* loading.
*
* Without the NOLOAD attribute, the .bss section might get PROGBITS type.
* This makes linker to A) allocate zeroed section in memory, and B) copy
* this section to RAM during application loading.
*/
.bss (NOLOAD):
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > ram
.heap (NOLOAD):
{
__HeapBase = .;
__end__ = .;
end = __end__;
KEEP(*(.heap*))
. = ORIGIN(ram) + LENGTH(ram);
__HeapLimit = .;
} > ram
/* Emulated EEPROM Flash area */
.cy_em_eeprom :
{
KEEP(*(.cy_em_eeprom))
} > em_eeprom
/* Supervisory Flash: User data */
.cy_sflash_user_data :
{
KEEP(*(.cy_sflash_user_data))
} > sflash_user_data
/* Supervisory Flash: Normal Access Restrictions (NAR) */
.cy_sflash_nar :
{
KEEP(*(.cy_sflash_nar))
} > sflash_nar
/* Supervisory Flash: Public Key */
.cy_sflash_public_key :
{
KEEP(*(.cy_sflash_public_key))
} > sflash_public_key
/* Supervisory Flash: Table of Content # 2 */
.cy_toc_part2 :
{
KEEP(*(.cy_toc_part2))
} > sflash_toc_2
/* Supervisory Flash: Table of Content # 2 Copy */
.cy_rtoc_part2 :
{
KEEP(*(.cy_rtoc_part2))
} > sflash_rtoc_2
/* Places the code in the Execute in Place (XIP) section. See the smif driver
* documentation for details.
*/
.cy_xip :
{
KEEP(*(.cy_xip))
} > xip
/* eFuse */
.cy_efuse :
{
KEEP(*(.cy_efuse))
} > efuse
/* These sections are used for additional metadata (silicon revision,
* Silicon/JTAG ID, etc.) storage.
*/
.cymeta 0x90500000 : { KEEP(*(.cymeta)) } :NONE
}
/* The following symbols used by the cymcuelftool. */
/* Flash */
__cy_memory_0_start = 0x10000000;
__cy_memory_0_length = 0x00200000;
__cy_memory_0_row_size = 0x200;
/* Emulated EEPROM Flash area */
__cy_memory_1_start = 0x14000000;
__cy_memory_1_length = 0x8000;
__cy_memory_1_row_size = 0x200;
/* Supervisory Flash */
__cy_memory_2_start = 0x16000000;
__cy_memory_2_length = 0x8000;
__cy_memory_2_row_size = 0x200;
/* XIP */
__cy_memory_3_start = 0x18000000;
__cy_memory_3_length = 0x08000000;
__cy_memory_3_row_size = 0x200;
/* eFuse */
__cy_memory_4_start = 0x90700000;
__cy_memory_4_length = 0x100000;
__cy_memory_4_row_size = 1;
/* EOF */

View File

@@ -0,0 +1,113 @@
################################################################################
# \file MCUBootApp.mk
# \version 1.0
#
# \brief
# Makefile for Cypress MCUBoot-based application.
#
################################################################################
# \copyright
# Copyright 2018-2019 Cypress Semiconductor Corporation
# 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.
################################################################################
include host.mk
# Cypress' MCUBoot Application supports GCC ARM only at this moment
# Set default compiler to GCC if not specified from command line
COMPILER ?= GCC_ARM
USE_CRYPTO_HW ?= 0
USE_EXTERNAL_FLASH ?= 0
MCUBOOT_IMAGE_NUMBER ?= 1
ENC_IMG ?= 0
# For which core this application is built
CORE ?= CM0P
ifneq ($(COMPILER), GCC_ARM)
$(error Only GCC ARM is supported at this moment)
endif
CUR_APP_PATH = $(PRJ_DIR)/$(APP_NAME)
include $(PRJ_DIR)/platforms.mk
include $(PRJ_DIR)/common_libs.mk
include $(PRJ_DIR)/toolchains.mk
# default slot size is 0x10000, 512bytes per row/sector, so 128 sectors
MAX_IMG_SECTORS ?= 128
# Application-specific DEFINES
DEFINES_APP := -DMBEDTLS_CONFIG_FILE="\"mcuboot_crypto_config.h\""
DEFINES_APP += -DECC256_KEY_FILE="\"keys/$(SIGN_KEY_FILE).pub\""
DEFINES_APP += -DCORE=$(CORE)
DEFINES_APP += -DMCUBOOT_IMAGE_NUMBER=$(MCUBOOT_IMAGE_NUMBER)
ifeq ($(USE_EXTERNAL_FLASH), 1)
DEFINES_APP += -DCY_BOOT_USE_EXTERNAL_FLASH
endif
DEFINES_APP += -DMCUBOOT_MAX_IMG_SECTORS=$(MAX_IMG_SECTORS)
# Hardrware acceleration support
ifeq ($(USE_CRYPTO_HW), 1)
DEFINES_APP += -DMBEDTLS_USER_CONFIG_FILE="\"mcuboot_crypto_acc_config.h\""
DEFINES_APP += -DCY_CRYPTO_HAL_DISABLE
DEFINES_APP += -DCY_MBEDTLS_HW_ACCELERATION
endif
# Encrypted image support
ifeq ($(ENC_IMG), 1)
DEFINES_APP += -DENC_IMG=1
endif
# Collect MCUBoot sourses
SOURCES_MCUBOOT := $(wildcard $(CURDIR)/../bootutil/src/*.c)
# Collect MCUBoot Application sources
SOURCES_APP_SRC := $(wildcard $(CUR_APP_PATH)/*.c)
# Collect Flash Layer port sources
SOURCES_FLASH_PORT := $(wildcard $(CURDIR)/cy_flash_pal/*.c)
SOURCES_FLASH_PORT += $(wildcard $(CURDIR)/cy_flash_pal/flash_qspi/*.c)
# Collect all the sources
SOURCES_APP := $(SOURCES_MCUBOOT)
SOURCES_APP += $(SOURCES_APP_SRC)
SOURCES_APP += $(SOURCES_FLASH_PORT)
INCLUDE_DIRS_MCUBOOT := $(addprefix -I, $(CURDIR)/../bootutil/include)
INCLUDE_DIRS_MCUBOOT += $(addprefix -I, $(CURDIR)/../bootutil/src)
INCLUDE_DIRS_MCUBOOT += $(addprefix -I, $(CURDIR)/..)
INCLUDE_DIRS_APP := $(addprefix -I, $(CURDIR))
INCLUDE_DIRS_APP += $(addprefix -I, $(CURDIR)/cy_flash_pal/flash_qspi)
INCLUDE_DIRS_APP += $(addprefix -I, $(CURDIR)/cy_flash_pal/include)
INCLUDE_DIRS_APP += $(addprefix -I, $(CURDIR)/cy_flash_pal/include/flash_map_backend)
INCLUDE_DIRS_APP += $(addprefix -I, $(CUR_APP_PATH))
INCLUDE_DIRS_APP += $(addprefix -I, $(CUR_APP_PATH)/config)
INCLUDE_DIRS_APP += $(addprefix -I, $(CUR_APP_PATH)/os)
ASM_FILES_APP :=
ASM_FILES_APP += $(ASM_FILES_STARTUP)
# Output folder
OUT := $(APP_NAME)/out
# Output folder to contain build artifacts
OUT_TARGET := $(OUT)/$(PLATFORM)
OUT_CFG := $(OUT_TARGET)/$(BUILDCFG)
# Overwite path to linker script if custom is required
ifeq ($(COMPILER), GCC_ARM)
LINKER_SCRIPT := $(subst /cygdrive/c,c:,$(CUR_APP_PATH)/$(APP_NAME).ld)
else
$(error Only GCC ARM is supported at this moment)
endif

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="ilg.gnumcueclipse.debug.gdbjtag.openocd.launchConfigurationType">
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doContinue" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doDebugInRam" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doFirstReset" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateConsole" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doGdbServerAllocateTelnetConsole" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doSecondReset" value="false"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbCLient" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.doStartGdbServer" value="true"/>
<booleanAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.enableSemihosting" value="true"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.firstResetType" value="init"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherCommands" value="set mem inaccessible-by-default off"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbClientOtherOptions" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerConnectionAddress" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerExecutable" value="${cy_tools_path:openocd}/bin/openocd"/>
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerGdbPortNumber" value="3333"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerLog" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerOther" value="-s &quot;${cy_tools_path:openocd}/scripts&quot;&#13;&#10;-s &quot;${workspace_loc}/boot/cypress&quot;&#13;&#10;-c &quot;source [find interface/kitprog3.cfg]&quot;&#13;&#10;-c &quot;source [find target/psoc6_2m.cfg]&quot;&#13;&#10;-c &quot;puts stderr {Started by GNU MCU Eclipse}&quot;"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTclPortNumber" value="6666"/>
<intAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.gdbServerTelnetPortNumber" value="4444"/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherInitCommands" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.otherRunCommands" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.openocd.secondResetType" value=""/>
<stringAttribute key="ilg.gnumcueclipse.debug.gdbjtag.svdPath" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageFileName" value="./out/PSOC_062_2M/Debug/MCUBootApp.elf"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.imageOffset" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.ipAddress" value="localhost"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.jtagDevice" value="GNU MCU OpenOCD"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadImage" value="true"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.loadSymbols" value="true"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.pcRegister" value=""/>
<intAttribute key="org.eclipse.cdt.debug.gdbjtag.core.portNumber" value="3333"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setPcRegister" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setResume" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.setStopAt" value="false"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.stopAt" value=""/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsFileName" value="./out/PSOC_062_2M/Debug/MCUBootApp.elf"/>
<stringAttribute key="org.eclipse.cdt.debug.gdbjtag.core.symbolsOffset" value=""/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForImage" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useFileForSymbols" value="false"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForImage" value="true"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useProjBinaryForSymbols" value="true"/>
<booleanAttribute key="org.eclipse.cdt.debug.gdbjtag.core.useRemoteTarget" value="true"/>
<stringAttribute key="org.eclipse.cdt.dsf.gdb.DEBUG_NAME" value="${cy_sdk_install_dir}/tools/gcc-7.2.1-1.0/bin/arm-none-eabi-gdb${cy_exe_platform_ext}"/>
<booleanAttribute key="org.eclipse.cdt.dsf.gdb.UPDATE_THREADLIST_ON_SUSPEND" value="false"/>
<intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="0"/>
<stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
<stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="boot/cypress/MCUBootApp/out/PSOC_062_2M/Debug/MCUBootApp.elf"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_ATTR" value="cy_mcuboot"/>
<booleanAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_AUTO_ATTR" value="false"/>
<stringAttribute key="org.eclipse.cdt.launch.PROJECT_BUILD_CONFIG_ID_ATTR" value=""/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/cy_mcuboot"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#10;&lt;memoryBlockExpression address=&quot;268566528&quot; label=&quot;0x10020000&quot;/&gt;&#10;&lt;memoryBlockExpression address=&quot;268632064&quot; label=&quot;0x10030000&quot;/&gt;&#10;&lt;/memoryBlockExpressionList&gt;&#10;"/>
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
</launchConfiguration>

View File

@@ -0,0 +1,221 @@
### Port of MCUboot library to be used with Cypress targets
**Solution Description**
Given solution demonstrates operation of MCUboot on Cypress' PSoC6 device.
There are two applications implemented:
* MCUBootApp - PSoC6 MCUboot-based bootloading application;
* BlinkyApp - simple PSoC6 blinking LED application which is a target of BOOT/UPGRADE;
Cypress boards, that can be used with this evaluation example:
- CY8CPROTO-062-4343W - PSoC 6 2M on board
- CY8CKIT-062-WIFI-BT - PSoC 6 1M on board
- CY8CPROTO-062S3-4343W - PSoC 6 512K on board
The default flash map implemented is the following:
Single-image mode.
`[0x10000000, 0x10018000]` - MCUBootApp (bootloader) area;
`[0x10018000, 0x10028000]` - primary slot for BlinkyApp;
`[0x10028000, 0x10038000]` - secondary slot for BlinkyApp;
`[0x10038000, 0x10039000]` - scratch area (not used);
Size of slots `0x10000` - 64kb
MCUBootApp checks image integrity with SHA256, image authenticity with EC256 digital signature verification and uses completely SW implementation of cryptographic functions based on Mbed TLS Library.
**Important**: make sure primary, secondary slot and bootloader app sizes are appropriate and correspond to flash area size defined in Applications' linker files.
**Important**: make sure RAM areas of CM0p-based MCUBootApp bootloader and CM4-based BlinkyApp do not overlap.
Memory (stack) corruption of CM0p application can cause failure if SystemCall-served operations invoked from CM4.
### Hardware cryptography acceleration
Cypress PSOC6 MCU family supports hardware acceleration of cryptography based on Mbed TLS Library via shim layer. Implementation of this layer is supplied as separate submodule `cy-mbedtls-acceleration`. HW acceleration of cryptography shortens boot time more then 4 times, comparing to software implementation (observation results).
To enable hardware acceleration in `MCUBootApp` pass flag `USE_CRYPTO_HW=1` to `make` while build.
Hardware acceleration of cryptography is enabled for PSOC6 devices by default.
### How to modify memory map
__Option 1.__
Navigate to `sysflash.h` and modify the flash area(s) / slots sizes to meet your needs.
__Option 2.__
Navigate to `sysflash.h`, uncomment `CY_FLASH_MAP_EXT_DESC` definition.
Now define and initialize `struct flash_area *boot_area_descs[]` with flash memory addresses and sizes you need at the beginning of application, so flash APIs from `cy_flash_map.c` will use it.
__Note:__ for both options make sure you have updated `MCUBOOT_MAX_IMG_SECTORS` appropriatery with sector size assumed to be 512.
**How to override the flash map values during build process:**
Navigate to MCUBootApp.mk, find section `DEFINES_APP +=`
Update this line and or add similar for flash map parameters to override.
The possible list could be:
* MCUBOOT_MAX_IMG_SECTORS
* CY_FLASH_MAP_EXT_DESC
* CY_BOOT_SCRATCH_SIZE
* CY_BOOT_BOOTLOADER_SIZE
* CY_BOOT_PRIMARY_1_SIZE
* CY_BOOT_SECONDARY_1_SIZE
* CY_BOOT_PRIMARY_2_SIZE
* CY_BOOT_SECONDARY_2_SIZE
As an example in a makefile it should look like following:
`DEFINES_APP +=-DCY_FLASH_MAP_EXT_DESC`
`DEFINES_APP +=-DMCUBOOT_MAX_IMG_SECTORS=512`
`DEFINES_APP +=-DCY_BOOT_PRIMARY_1_SIZE=0x15000`
**Multi-Image Operation**
Multi-image operation considers upgrading and verification of more then one image on the device.
To enable multi-image operation define `MCUBOOT_IMAGE_NUMBER` in `MCUBootApp/config/mcuboot_config.h` file should be set to 2 (only dual-image is supported at the moment). This could also be done on build time by passing `MCUBOOT_IMAGE_NUMBER=2` as parameter to `make`.
Default value of `MCUBOOT_IMAGE_NUMBER` is 1, which corresponds to single image configuratios.
In multi-image operation (two images are considered for simplicity) MCUboot Bootloader application operates as following:
* Verifies Primary_1 and Primary_2 images;
* Verifies Secondary_1 and Secondary_2 images;
* Upgrades Secondary to Primary if valid images found;
* Boots image from Primary_1 slot only;
* Boots Primary_1 only if both - Primary_1 and Primary_2 are present and valid;
This ensures two dependent applications can be accepted by device only in case both images are valid.
**Default Flash map for Multi-Image operation:**
`0x10000000 - 0x10018000` - MCUboot Bootloader
`0x10018000 - 0x10028000` - Primary_1 (BOOT) slot of Bootloader
`0x10028000 - 0x10038000` - Secondary_1 (UPGRADE) slot of Bootloader
`0x10038000 - 0x10048000` - Primary_2 (BOOT) slot of Bootloader
`0x10048000 - 0x10058000` - Secondary_2 (UPGRADE) slot of Bootloader
`0x10058000 - 0x10059000` - Scratch of Bootloader
Size of slots `0x10000` - 64kb
__Note:__ It is also possible to place secondary (upgrade) slots in external memory module so resulting image size can be doubled.
For more details about External Memory usage, please refer to separate guiding document `ExternalMemory.md`.
### Hardware limitations
Since this application is created to demonstrate MCUboot library features and not as reference examples some considerations are taken.
1. `SCB5` used to configure serial port for debug prints. This is the most commonly used Serial Communication Block number among available Cypress PSoC 6 kits. If you try to use custom hardware with this application - change definition of `CYBSP_UART_HW` in `main.c` of MCUBootApp to SCB* that correspond to your design.
2. `CY_SMIF_SLAVE_SELECT_0` is used as definition SMIF driver API. This configuration is used on evaluation kit for this example CY8CPROTO-062-4343W, CY8PROTO-062S3-4343W, CY8CKIT-062-4343W. If you try to use custom hardware with this application - change value of `smif_id` in `main.c` of MCUBootApp to value that corresponds to your design.
### Downloading solution's assets
There is a set assets required:
* MCUBooot Library (root repository)
* PSoC6 HAL Library
* PSoC6 Peripheral Drivers Library (PDL)
* Mbed TLS Cryptographic Library
To get submodules - run the following command:
git submodule update --init --recursive
### Building solution
This folder contains make files infrastructure for building MCUBoot Bootloader. Same approach used in sample BlinkyLedApp application. Example command are provided below for couple different build configurations.
* Build MCUBootApp in `Debug` for signle image use case.
make app APP_NAME=MCUBootApp PLATFORM=PSOC_062_2M BUILDCFG=Debug MCUBOOT_IMAGE_NUMBER=1
* Build MCUBootApp in `Release` for multi image use case.
make app APP_NAME=MCUBootApp PLATFORM=PSOC_062_2M BUILDCFG=Release MCUBOOT_IMAGE_NUMBER=2
* To Build MCUBootApp with external memory support - pass `USE_EXTERNAL_FLASH=1` flag to `make` command in examples above. In this case UPGRADE image will be located in external memory. Refer to ExternalMemory.md for additional details.
Root directory for build is **boot/cypress.**
**Encrypted Image Support**
To protect user image from unwanted read - Upgrade Image Encryption can be applied. The ECDH/HKDF with EC256 scheme is used in a given solution as well as Mbed TLS as a crypto provider.
To enable image encryption support use `ENC_IMG=1` build flag (BlinkyApp should also be built with this flash set 1).
User is also responsible for providing corresponding binary key data in `enc_priv_key[]` (file `\MCUBootApp\keys.c`). The public part will be used by imgtool when signing and encrypting upgrade image. Signing image with encryption is described in `\BlinkyApp\Readme.md`.
After MCUBootApp is built with these settings unencrypted and encrypted images will be accepted in secondary (upgrade) slot.
Example command:
make app APP_NAME=MCUBootApp PLATFORM=PSOC_062_2M BUILDCFG=Debug MCUBOOT_IMAGE_NUMBER=1 ENC_IMG=1
**Programming solution**
There are couple ways of programming hex of MCUBootApp and BlinkyApp. Following instructions assume one of Cypress development kits, for example `CY8CPROTO_062_4343W`.
1. Direct usage of OpenOCD.
OpenOCD package is supplied with ModuToolbox IDE and can be found in installation folder under `./tools_2.1/openocd`.
Open terminal application - and execute following command after substitution `PATH_TO_APPLICATION.hex` and `OPENOCD` paths.
Connect a board to your computer. Switch Kitprog3 to DAP-BULK mode by pressing `SW3 MODE` button until `LED2 STATUS` constantly shines.
export OPENOCD=/Applications/ModusToolbox/tools_2.1/openocd
${OPENOCD}/bin/openocd -s ${OPENOCD}/scripts \
-f ${OPENOCD}/scripts/interface/kitprog3.cfg \
-f ${OPENOCD}/scripts/target/psoc6_2m.cfg \
-c "init; reset init; program PATH_TO_APPLICATION.hex" \
-c "resume; reset; exit"
2. Using GUI tool `Cypress Programmer` - follow [link](https://www.cypress.com/products/psoc-programming-solutions) to download.
Connect board to your computer. Switch Kitprog3 to DAP-BULK mode by pressing `SW3 MODE` button until `LED2 STATUS` constantly shines. Open `Cypress Programmer` and click `Connect`, then choose hex file: `MCUBootApp.hex` or `BlinkyApp.hex` and click `Program`. Check log to ensure programming success. Reset board.
3. Using `DAPLINK`.
Connect board to your computer. Switch embeded Kitprog3 to `DAPLINK` mode by pressing `SW3 MODE` button until `LED2 STATUS` blinks fast and mass storage device appeared in OS. Drag and drop `hex` files you wish to program to `DAPLINK` drive in your OS.
**Currently supported platforms:**
* PSOC_062_2M
* PSOC_062_1M
* PSOC_062_512K
**Build environment troubleshooting:**
Regular shell/terminal combination on Linux and MacOS.
On Windows:
* Cygwin
* Msys2
Also IDE may be used:
* Eclipse / ModusToolbox ("makefile project from existing source")
*Make* - make sure it is added to system's `PATH` variable and correct path is first in the list;
*Python/Python3* - make sure you have correct path referenced in `PATH`;
*Msys2* - to use systems PATH navigate to msys2 folder, open `msys2_shell.cmd`, uncomment set `MSYS2_PATH_TYPE=inherit`, restart MSYS2 shell.
This will iherit system's PATH so should find `python3.7` installed in regular way as well as imgtool and its dependencies.

View File

@@ -0,0 +1,22 @@
/*
* mcuboot_assert.h
*
* Cypress-specific assert() macro redefinition
*
*/
#ifndef MCUBOOT_ASSERT_H
#define MCUBOOT_ASSERT_H
//#include "cy_bootloader_services.h"
#define CYBL_ASSERT(...) Cy_BLServ_Assert(__VA_ARGS__)
#if !defined(NDEBUG)
#undef assert
#define assert(...) CYBL_ASSERT(__VA_ARGS__)
#else
#define assert
#endif
#endif /* MCUBOOT_ASSERT_H */

View File

@@ -0,0 +1,166 @@
/* Copyright 2019 Cypress Semiconductor Corporation
*
* Copyright (c) 2018 Open Source Foundries Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef MCUBOOT_CONFIG_H
#define MCUBOOT_CONFIG_H
/*
* Template configuration file for MCUboot.
*
* When porting MCUboot to a new target, copy it somewhere that your
* include path can find it as mcuboot_config/mcuboot_config.h, and
* make adjustments to suit your platform.
*
* For examples, see:
*
* boot/zephyr/include/mcuboot_config/mcuboot_config.h
* boot/mynewt/mcuboot_config/include/mcuboot_config/mcuboot_config.h
*/
/* Default maximum number of flash sectors per image slot; change
* as desirable. */
#ifndef MCUBOOT_MAX_IMG_SECTORS
#define MCUBOOT_MAX_IMG_SECTORS 2560
#endif
/*
* Signature types
*
* You must choose exactly one signature type.
*/
/* Uncomment for RSA signature support */
//#define MCUBOOT_SIGN_RSA
/* Uncomment for ECDSA signatures using curve P-256. */
#define MCUBOOT_SIGN_EC256
/*
* Upgrade mode
*
* The default is to support A/B image swapping with rollback. A
* simpler code path, which only supports overwriting the
* existing image with the update image, is also available.
*/
/* Uncomment to enable the overwrite-only code path. */
#define MCUBOOT_OVERWRITE_ONLY
#ifdef MCUBOOT_OVERWRITE_ONLY
/* Uncomment to only erase and overwrite those slot 0 sectors needed
* to install the new image, rather than the entire image slot. */
/* #define MCUBOOT_OVERWRITE_ONLY_FAST */
#endif
/*
* Cryptographic settings
*
* You must choose between mbedTLS and Tinycrypt as source of
* cryptographic primitives. Other cryptographic settings are also
* available.
*/
/* Uncomment to use ARM's mbedTLS cryptographic primitives */
#define MCUBOOT_USE_MBED_TLS
/* Uncomment to use Tinycrypt's. */
/* #define MCUBOOT_USE_TINYCRYPT */
/*
* Always check the signature of the image in slot 0 before booting,
* even if no upgrade was performed. This is recommended if the boot
* time penalty is acceptable.
*/
#define MCUBOOT_VALIDATE_PRIMARY_SLOT
/*
* Flash abstraction
*/
/* Uncomment if your flash map API supports flash_area_get_sectors().
* See the flash APIs for more details. */
// TODO: FWSECURITY-755
#define MCUBOOT_USE_FLASH_AREA_GET_SECTORS
/* Default number of separately updateable images; change in case of
* multiple images. */
#ifndef MCUBOOT_IMAGE_NUMBER
#define MCUBOOT_IMAGE_NUMBER 1
#endif
/*
* Currently there is no configuration option, for this platform,
* that enables the system specific mcumgr commands in mcuboot
*/
#define MCUBOOT_PERUSER_MGMT_GROUP_ENABLED 0
/*
* Logging
*/
/*
* If logging is enabled the following functions must be defined by the
* platform:
*
* MCUBOOT_LOG_ERR(...)
* MCUBOOT_LOG_WRN(...)
* MCUBOOT_LOG_INF(...)
* MCUBOOT_LOG_DBG(...)
*
* The following global logging level configuration macros must also be
* defined, each with a unique value. Those will be used to define a global
* configuration and will allow any source files to override the global
* configuration:
*
* MCUBOOT_LOG_LEVEL_OFF
* MCUBOOT_LOG_LEVEL_ERROR
* MCUBOOT_LOG_LEVEL_WARNING
* MCUBOOT_LOG_LEVEL_INFO
* MCUBOOT_LOG_LEVEL_DEBUG
*
* The global logging level must be defined, with one of the previously defined
* logging levels:
*
* #define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_(OFF|ERROR|WARNING|INFO|DEBUG)
*
* MCUBOOT_LOG_LEVEL sets the minimum level that will be logged. The function
* priority is:
*
* MCUBOOT_LOG_ERR > MCUBOOT_LOG_WRN > MCUBOOT_LOG_INF > MCUBOOT_LOG_DBG
*
* NOTE: Each source file is still able to request its own logging level by
* defining BOOT_LOG_LEVEL before #including `bootutil_log.h`
*/
#define MCUBOOT_HAVE_LOGGING 1
/* Define this to support native mcuboot logging system */
#define CONFIG_MCUBOOT 1
/*
* Assertions
*/
/* Uncomment if your platform has its own mcuboot_config/mcuboot_assert.h.
* If so, it must provide an ASSERT macro for use by bootutil. Otherwise,
* "assert" is used. */
//#define MCUBOOT_HAVE_ASSERT_H
#define MCUBOOT_WATCHDOG_FEED() \
do { \
/* TODO: to be implemented */ \
} while (0)
/* Uncomment these if support of encrypted upgrade image is needed */
#ifdef ENC_IMG
#define MCUBOOT_ENC_IMAGES
#define MCUBOOT_ENCRYPT_EC256
#define NUM_ECC_BYTES (256 / 8)
#endif /* ENC_IMG */
/*
* No direct idle call implemented
*/
#define MCUBOOT_CPU_IDLE() \
do { \
} while (0)
#endif /* MCUBOOT_CONFIG_H */

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
* Copyright (c) 2015 Runtime Inc
* Copyright (c) 2020 Cypress Semiconductor Corporation
*
* 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_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
/*
* 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_INFO
#endif
int sim_log_enabled(int level);
#define sim_log_enabled(x) 1
#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\r", ##__VA_ARGS__); \
} \
} 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\r", ##__VA_ARGS__); \
} \
} 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\r", ##__VA_ARGS__); \
} \
} 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\r", ##__VA_ARGS__); \
} \
} while (0)
#else
#define MCUBOOT_LOG_DBG(...) IGNORE(__VA_ARGS__)
#endif
#define MCUBOOT_LOG_MODULE_DECLARE(...)
#endif /* MCUBOOT_LOGGING_H */

View File

@@ -0,0 +1,54 @@
/*
* mbed Microcontroller Library
* Copyright (c) 2019 Cypress Semiconductor Corporation
*
* 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.
*/
/**
* \file mcuboot_crypto_acc_config.h
* \version 1.1
*/
#ifndef MCUBOOT_MBEDTLS_DEVICE_H
#define MCUBOOT_MBEDTLS_DEVICE_H
/* Currently this target supports SHA1 */
// #define MBEDTLS_SHA1_C
#define MBEDTLS_SHA1_ALT
#define MBEDTLS_SHA256_ALT
#define MBEDTLS_SHA512_ALT
/* Currently this target supports CBC, CFB, OFB, CTR and XTS cipher modes */
#define MBEDTLS_AES_ALT
// #define MBEDTLS_CIPHER_MODE_CBC
// #define MBEDTLS_CIPHER_MODE_CFB
// #define MBEDTLS_CIPHER_MODE_OFB
#ifdef MCUBOOT_ENC_IMAGES
#define MBEDTLS_CIPHER_MODE_CTR
#endif
// #define MBEDTLS_CIPHER_MODE_XTS
/* Only NIST-P curves are currently supported */
#define MBEDTLS_ECP_ALT
// #define MBEDTLS_ECP_DP_SECP192R1_ENABLED
// #define MBEDTLS_ECP_DP_SECP224R1_ENABLED
// #define MBEDTLS_ECP_DP_SECP256R1_ENABLED
// #define MBEDTLS_ECP_DP_SECP384R1_ENABLED
// #define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECDSA_SIGN_ALT
#define MBEDTLS_ECDSA_VERIFY_ALT
#endif /* MCUBOOT_MBEDTLS_DEVICE_H */

Some files were not shown because too many files have changed in this diff Show More