fit_image_verify_required_sigs() at boot/image-fit-sig.c:187 looks up the
"/signature" node of the U-Boot control devicetree and returns success
when it is absent, at boot/image-fit-sig.c:203-207:
/* Work out what we need to verify */
*no_sigsp = 1;
key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
if (key_node < 0) {
debug("%s: No signature node found: %s\n", __func__,
fdt_strerror(key_node));
return 0;
}
With no /signature node there are no keys marked 'required', so nothing
downstream can fail the image: a FIT whose signatures are absent,
malformed or invalid verifies successfully. The only indication is a
debug() call, which is compiled out of a normal build.
fit_config_verify_required_keys() carries the same early return, and in
that path reqd_sigs also stays at 0, so the closing
"if (reqd_sigs && !verified)" check never fires either.
'iminfo' at this HEAD verifies images but not configurations, so it
reaches this gate directly. Against a control devicetree with no
/signature node at all, and a FIT whose configuration signature carries
no 'value':
## Checking hash(es) for FIT Image at 10400100 ...
Hash(es) for Image 0 (kernel): sha256+
Hash(es) for Image 1 (fdt-1): sha256+
That '+' is fit_image_verify_with_data() reporting the signature
verified, on a board holding no keys whatsoever.
Add FIT_REQUIRE_CONFIG_SIGS, which turns a missing "/signature" node,
and a "/signature" node holding no required keys, into a verification
failure on both gates. With CONFIG_FIT_REQUIRE_CONFIG_SIGS=y the same
command gives:
## Checking hash(es) for FIT Image at 10400100 ...
Hash(es) for Image 0 (kernel): No signature node in control FDT:
FDT_ERR_NOTFOUND
error!
Unable to verify required signature for '' hash node in 'kernel' image node
Bad hash in FIT image!
The option defaults to n, and that is a measured choice. Full test_vboot
on sandbox with these patches applied:
option at its default (not set): 32 passed, 0 failed
CONFIG_FIT_REQUIRE_CONFIG_SIGS=y: 19 passed, 13 failed
The 13 are not a defect in the patch. test/py/tests/test_vboot.py:312
boots an unsigned-images FIT against a key-less devicetree and asserts
that it boots, which encodes the old contract. Restructuring that is
Ludwig Nussel's 5/8. Default n keeps the shipped behaviour byte-for-byte
unchanged.
The new console message is printed only when the option is enabled.
Jonas Karlman objected to an unconditional message: Rockchip enables
FIT_SIGNATURE for image hash integrity alone and has no /signature node
by design, so an unconditional message would be noise on every boot
there. Measured with the option off, the string "No signature node in
control FDT" appears 0 times in the boot output, and 'iminfo' prints the
same 'sha256+' lines as an unpatched build.
printf() is used rather than log_err() so that this stays applicable to
main standalone; log_err() in this file requires Ludwig's 3/8. If these
are ever squashed together, log_err() is the better choice.
Not tested:
- SPL: SPL_FIT_REQUIRE_CONFIG_SIGS compiles through CONFIG_IS_ENABLED,
but no SPL configuration was built or run. Compile coverage only.
- Host tools: mkimage and fit_check_sign build, but no fit_check_sign
behaviour change was exercised. CONFIG_IS_ENABLED is false in the host
build since tools/Makefile only defines CONFIG_FIT_SIGNATURE, so
unchanged host behaviour is argued, not measured.
- Sandbox only: sandbox_defconfig on x86-64. No signed-boot hardware.
- Jonas's Rockchip setup was not reproduced.
No Fixes: tag. The early return is original behaviour rather than a
regression. The oldest commit touching it in this path is commit
b983cc2da0ba ("lib: rsa: decouple rsa from FIT image verification"),
which moves the code from common/image-sig.c to common/image-fit-sig.c
rather than introducing it. No introducing commit could be identified
with enough confidence to tag one.
Signed-off-by: Eva Crystal <[email protected]>
---
boot/Kconfig | 27 +++++++++++++++++++++++++++
boot/image-fit-sig.c | 15 +++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/boot/Kconfig b/boot/Kconfig
index c67dc0ba49..c1dd1de6ed 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -137,6 +137,25 @@ config FIT_SIGNATURE
format support in this case, enable it using
CONFIG_LEGACY_IMAGE_FORMAT.
+config FIT_REQUIRE_CONFIG_SIGS
+ bool "Fail verification when the control FDT has no /signature node"
+ depends on FIT_SIGNATURE
+ help
+ Without this option both required-signature gates return success
+ when the U-Boot control devicetree contains no "/signature" node.
+ Verified boot is then silently disabled: a FIT image whose
+ signatures are absent, malformed or invalid verifies successfully
+ and the only indication is a debug() message, which is compiled
+ out of a normal build.
+
+ Enable this option to treat a missing "/signature" node, and a
+ "/signature" node which holds no keys marked required="conf", as a
+ verification failure instead.
+
+ Say N if the same U-Boot binary must also run in setups which carry
+ no keys, or which enable FIT_SIGNATURE only for image hash
+ integrity checking rather than for signature enforcement.
+
config FIT_SIGNATURE_MAX_SIZE
hex "Max size of signed FIT structures"
depends on FIT_SIGNATURE
@@ -259,6 +278,14 @@ config SPL_FIT_SIGNATURE_MAX_SIZE
device memory. Assure this size does not extend past expected storage
space.
+config SPL_FIT_REQUIRE_CONFIG_SIGS
+ bool "Fail verification when the SPL control FDT has no /signature node"
+ depends on SPL_FIT_SIGNATURE
+ select FIT_REQUIRE_CONFIG_SIGS
+ help
+ Enable the FIT_REQUIRE_CONFIG_SIGS behaviour in SPL. See the help text
+ of FIT_REQUIRE_CONFIG_SIGS for details.
+
config SPL_LOAD_FIT
bool "Enable SPL loading U-Boot as a FIT (basic fitImage features)"
depends on SPL
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index a0c50bba4c..06ec0f39d8 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -201,6 +201,11 @@ int fit_image_verify_required_sigs(const void *fit, int
image_noffset,
*no_sigsp = 1;
key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
if (key_node < 0) {
+ if (CONFIG_IS_ENABLED(FIT_REQUIRE_CONFIG_SIGS)) {
+ printf("No signature node in control FDT: %s\n",
+ fdt_strerror(key_node));
+ return -ENOENT;
+ }
debug("%s: No signature node found: %s\n", __func__,
fdt_strerror(key_node));
return 0;
@@ -684,6 +689,11 @@ static int fit_config_verify_required_keys(const void
*fit, int conf_noffset,
/* Work out what we need to verify */
key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
if (key_node < 0) {
+ if (CONFIG_IS_ENABLED(FIT_REQUIRE_CONFIG_SIGS)) {
+ printf("No signature node in control FDT: %s\n",
+ fdt_strerror(key_node));
+ return -ENOENT;
+ }
debug("%s: No signature node found: %s\n", __func__,
fdt_strerror(key_node));
return 0;
@@ -735,6 +745,11 @@ static int fit_config_verify_required_keys(const void
*fit, int conf_noffset,
return -EPERM;
}
+ if (!reqd_sigs && CONFIG_IS_ENABLED(FIT_REQUIRE_CONFIG_SIGS)) {
+ printf("No required keys found for configuration
verification\n");
+ return -EPERM;
+ }
+
return 0;
}
--
2.53.0