Signed-off-by: Roland Hieber <r...@pengutronix.de> --- PATCH v3: - adapt to cs_get_uri_impl from previous patch. cs_get_uri_unchecked didn't really need to check for pkg_name anyway as it's only called by cs_append_ca_from_uri in the code provider setup path, and the code provider should always be able to get its own URI, so we can use cs_get_uri_impl here too. - cs_check_whitelist: handle the case correctly when the code signing provider is not set up yet (i.e. when the BSP is built from scratch) - small doc fixes - use fixed whitelist filename, remove CODE_SIGNING_WHITELIST_FILENAME (feedback by Michael Olbrich) - remove superfluous backslash-newline escapes in multi-line defines (feedback by Michael Olbrich) - add early error handling for openssl | spki-hash in cs_append_ca_* (feedback by Michael Olbrich) - remove factually untrue comment in cs_append_ca_from_uri (feedback by Michael Olbrich) - use $(error) instead of $(ptx/error) (feedback by Michael Olbrich)
PATCH v2: https://lore.ptxdist.org/ptxdist/20210809080608.23475-5-...@pengutronix.de - cs_check_whitelisted: make "needle" a local variable (feedback by Michael Olbrich) - cs_check_whitelisted: error out with ERROR_KEY_NOT_WHITELISTED also if whitelist does not exist yet (Michael Olbrich) - rename cs_get_uri to cs_get_uri_unchecked and let cs_get_uri wrap it instead of setting cs_no_whitelist_check=1 (Michael Olbrich) - docs: simplify introductory example (Michael Olbrich) - docs: add short paragraph on how to determine fingerprints of certs PATCH v1: https://lore.ptxdist.org/ptxdist/20210804142330.32739-5-...@pengutronix.de --- doc/daily_work.inc | 1 + doc/dev_code_signing.rst | 77 +++++++++++++++++++++++ platforms/code-signing.in | 10 +++ rules/pre/030-code-signing-consumers.make | 6 ++ scripts/lib/ptxd_lib_code_signing.sh | 56 ++++++++++++++++- 5 files changed, 149 insertions(+), 1 deletion(-) diff --git a/doc/daily_work.inc b/doc/daily_work.inc index 37bb9bc48180..a5b32dc5461c 100644 --- a/doc/daily_work.inc +++ b/doc/daily_work.inc @@ -180,6 +180,7 @@ options during the `kernel.compile` and `kernel.install` stages: PTXdist supplies the URI from the ``kernel-modules`` role of the configured code signing provider. (The code signing provider should use :ref:`cs_set_uri` to set the URI.) + The value of this kconfig option from your kernel config file is overridden. However, additional settings must also be enabled in the kernel config: diff --git a/doc/dev_code_signing.rst b/doc/dev_code_signing.rst index 413f694980eb..b0b8c9b4a3b8 100644 --- a/doc/dev_code_signing.rst +++ b/doc/dev_code_signing.rst @@ -172,3 +172,80 @@ also via an environment variable. (``=``, not ``:=``). Otherwise the variable is expanded before a code signing provider can perform its setup. + +Key Whitelisting +~~~~~~~~~~~~~~~~ + +In some use cases, it may be feasible to do additional checks to make sure that +a package uses the correct key material. +For example, suppose you have a "release" code signing provider which you use +to sign bootloaders for production, +and a "development" code signing provider which you use to sign bootloaders +with an extended feature set, e.g. to allow booting arbitrary kernels and +userlands for debugging purposes. +Your production boards are locked down in hardware so the ROM code only +executes bootloaders signed with the "release" key. +Now you don't want any bootloader with debugging features to be signed with a +release key, otherwise someone could boot them on a locked-down production +device, and use the additional debugging features to get extended access to the +production device. +In this case, key whitelisting can help to prevent signing bootloader packages +with the wrong key. + +If the ``CODE_SIGNING_REQUIRE_WHITELIST`` kconfig symbol is enabled, +the consumer functions :ref:`ptx/cs-get-ca` and :ref:`ptx/cs-get-uri` +look up the triplet of package name, role name, and the pubkey's SHA256 +fingerprint in ``configs/platform-<name>/code-signing-whitelist``. +If a key or a CA is not whitelisted for the package in which it is to be used, +the functions will exit with an error message on the terminal:: + + $ ptxdist -v print KERNEL_MAKE_OPT + ptxdist: error: SPKI whitelist record 'kernel kernel-modules + 69C9BBB8BB4DFAE74AB21D06DFB5F2C67066373AE545453276847340822CDF04' not found in + distrokit/configs/platform-v7a/code-signing-whitelist + + …/ptxdist/rules/kernel.make:196: *** cs-get-uri: whitelist check failed, see errors above. Stop. + +If ``CODE_SIGNING_REQUIRE_WHITELIST`` is disabled (the default), +all keys and CAs are provided to all packages without further checks. + +The format of the code signing whitelist consists of one triplet per line, in +which the elements of the triplet are separated by whitespace. +If a CA is to be checked, the role name is prefixed with a literal ``ca:``, +and the fingerprint refers to the public key of the certificate. +All other unmatched lines in the file are ignored, but we suggest to use ``#`` +to start a line comment so as not to add a whitelist record accidentally. + +For example, here is a whitelist for use with the *devel* code provider which +allows all provided keys to be used by their respective consumers:: + + # format: package-name role-name sha256-pubkey-fingerprint + kernel kernel-modules 69C9BBB8BB4DFAE74AB21D06DFB5F2C67066373AE545453276847340822CDF04 + image-rauc update 0034F8FE5ADC3B0DFE642407275D144DE2398C68CC9A86DD6703D7151116B44E + image-rauc ca:update 0034F8FE5ADC3B0DFE642407275D144DE2398C68CC9A86DD6703D7151116B44E + rauc ca:update 0034F8FE5ADC3B0DFE642407275D144DE2398C68CC9A86DD6703D7151116B44E + +.. note:: The match is case-sensitive, and the fingerprints are expected + in uppercase. + + If a CA consists of more than one certificate, all of their fingerprints + must be whitelisted. + +You can determine the key fingerprints by copying it from the error message, +or with the `spki-hash`__ tool from the ``host-extract-cert`` package, +or with openssl:: + + $ openssl pkey -in keyfile.pem -pubout -outform der \ + | openssl sha256 \ + | tr 'a-z' 'A-Z' + (STDIN)= 69C9BBB8BB4DFAE74AB21D06DFB5F2C67066373AE545453276847340822CDF04 + +or, in the case of certificates:: + + $ openssl x509 -noout -in cert.pem -pubkey \ + | openssl pkey -pubin -inform pem -pubout -outform der \ + | openssl sha256 \ + | tr 'a-z' 'A-Z' + (STDIN)= 0034F8FE5ADC3B0DFE642407275D144DE2398C68CC9A86DD6703D7151116B44E + +__ https://git.pengutronix.de/cgit/extract-cert/tree/spki-hash.c diff --git a/platforms/code-signing.in b/platforms/code-signing.in index 81f9ef6f3c9e..7fa46e644df7 100644 --- a/platforms/code-signing.in +++ b/platforms/code-signing.in @@ -20,4 +20,14 @@ source "generated/code_signing_provider.in" endchoice +config CODE_SIGNING_REQUIRE_WHITELISTED_KEYS + bool + prompt "require whitelisted keys" + help + Every time a key from the code provider is used, check if the consumer + is allowed to use it. + + Code signing consumers can depend on this option if they want to force + the key whitelist check. + endif diff --git a/rules/pre/030-code-signing-consumers.make b/rules/pre/030-code-signing-consumers.make index e2c6c868e0ee..24bfa1c9c815 100644 --- a/rules/pre/030-code-signing-consumers.make +++ b/rules/pre/030-code-signing-consumers.make @@ -21,6 +21,9 @@ $(strip $(call ptx/cs-consumer-env, $(1)) cs_get_uri '$(strip $(2))' ) + $(if $(filter-out 0,$(.SHELLSTATUS)), + $(error cs-get-uri: whitelist check failed – see errors above) + ) ) endef @@ -33,5 +36,8 @@ $(strip $(call ptx/cs-consumer-env, $(1)) cs_get_ca '$(strip $(2))' ) + $(if $(filter-out 0,$(.SHELLSTATUS)), + $(error cs-get-ca: whitelist check failed – see errors above) + ) ) endef diff --git a/scripts/lib/ptxd_lib_code_signing.sh b/scripts/lib/ptxd_lib_code_signing.sh index 8f35c276855f..fe819bcb07ae 100644 --- a/scripts/lib/ptxd_lib_code_signing.sh +++ b/scripts/lib/ptxd_lib_code_signing.sh @@ -1,6 +1,7 @@ #!/bin/bash # # Copyright (C) 2019 Sascha Hauer <s.ha...@pengutronix.de> +# Copyright (C) 2020 Jan Luebbe <j.lue...@pengutronix.de> # Copyright (C) 2021 Roland Hieber, Pengutronix <r...@pengutronix.de> # # For further information about the PTXdist project and license conditions @@ -145,6 +146,47 @@ cs_group_get_roles() { } export -f cs_group_get_roles +# +# cs_check_whitelisted <role> <uri/pem or fingerprint prefixed with "sha256:"> +# +# Checks if the SPKI (Subject Public Key Info) Hash is in the whitelist +# +cs_check_whitelisted() { + local role="${1:-ERROR_ROLE_IS_EMPTY}" + local src="${2}" + cs_init_variables + + if [ "${src}" = "ERROR_URI_NOT_YET_SET" ]; then + # skip check until the code signing provider has been set up + return; + fi + + if [ "$(ptxd_get_ptxconf PTXCONF_CODE_SIGNING_REQUIRE_WHITELISTED_KEYS)" != "y" ]; then + return + fi + + if ! ptxd_in_path PTXDIST_PATH_PLATFORMCONFIGDIR "code-signing-whitelist"; then + echo ERROR_KEY_NOT_WHITELISTED + ptxd_bailout "${pkg_name}: SPKI hash whitelist check for role '${role}' (${src}) is required, but configs/<platform>/code-signing-whitelist is missing." + fi + local whitelist_path="${ptxd_reply}" + + local hash + if [ "${src#sha256:}" != "${src}" ]; then + hash="${src#sha256:}" + else + hash=$(ptxd_exec_silent_stderr spki-hash "${src}") + fi + hash=${hash:-ERROR_HASH_IS_EMPTY} + local needle="${pkg_name}\s\+${role}\s\+${hash}" + + if ! grep -q --line-regexp "${needle}" "${whitelist_path}"; then + echo ERROR_KEY_NOT_WHITELISTED + ptxd_bailout "SPKI whitelist record '${pkg_name} ${role} ${hash}' not found in $(ptxd_print_path "${whitelist_path}")" + fi +} +export -f cs_check_whitelisted + # # cs_set_uri <role> <uri> # @@ -191,7 +233,12 @@ cs_get_uri() { 'Use $(call ptx/cs-get-uri, <PKG>, <role>) instead.' fi - cs_get_uri_impl "$@" + local role="${1}" + local uri=$(cs_get_uri_impl "${role}") + + if cs_check_whitelisted "${role}" "${uri}"; then + echo "${uri}" + fi } export -f cs_get_uri @@ -318,6 +365,9 @@ cs_get_ca() { fi if [ -e "${ca}" ]; then + while read fp; do + cs_check_whitelisted "ca:${role}" "sha256:${fp}" + done < "${keydir}/${role}/ca.fingerprints" echo "${ca}" fi } @@ -333,6 +383,10 @@ cs_append_ca_from_pem() { local pem="${2}" cs_init_variables + openssl x509 -in "${pem}" -inform pem -noout -pubkey | \ + spki-hash /dev/stdin >> "${keydir}/${role}/ca.fingerprints" + check_pipe_status || ptxd_bailout "Extracting SPKI hash from CA '${pem}' failed" + cat "${pem}" >> "${keydir}/${role}/ca.pem" # add new line in case ${pem} does not end with an EOL echo >> "${keydir}/${role}/ca.pem" -- 2.30.2 _______________________________________________ ptxdist mailing list ptxdist@pengutronix.de To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-requ...@pengutronix.de