From: Michael Olbrich <m.olbrich@pengutronix.de>
To: Roland Hieber <rhi@pengutronix.de>, ptxdist@pengutronix.de
Subject: Re: [ptxdist] [PATCH v3 5/5] ptxd_lib_code_signing: add key whitelist checks
Date: Wed, 29 Sep 2021 14:08:50 +0200 [thread overview]
Message-ID: <20210929120850.GG2560099@pengutronix.de> (raw)
In-Reply-To: <20210912205925.23644-5-rhi@pengutronix.de>
On Sun, Sep 12, 2021 at 10:59:25PM +0200, Roland Hieber wrote:
> Signed-off-by: Roland Hieber <rhi@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-rhi@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-rhi@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.
I think, where the whitelist is expected should be mentioned here as well.
Michael
> +
> 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.hauer@pengutronix.de>
> +# Copyright (C) 2020 Jan Luebbe <j.luebbe@pengutronix.de>
> # Copyright (C) 2021 Roland Hieber, Pengutronix <rhi@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-request@pengutronix.de
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
ptxdist mailing list
ptxdist@pengutronix.de
To unsubscribe, send a mail with subject "unsubscribe" to ptxdist-request@pengutronix.de
next prev parent reply other threads:[~2021-09-29 12:09 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-12 20:59 [ptxdist] [PATCH v3 1/5] kernel: make sure that kbuild can extract keys from the HSM Roland Hieber
2021-09-12 20:59 ` [ptxdist] [PATCH v3 2/5] ptxd_lib_code_signing: return success in case of ERROR_CA_NOT_YET_SET Roland Hieber
2021-09-12 20:59 ` [ptxdist] [PATCH v3 3/5] libptxdist: introduce ptxd_exec_silent_stderr Roland Hieber
2021-09-12 20:59 ` [ptxdist] [PATCH v3 4/5] ptxd_lib_code_signing: provide consumer functions with some environment Roland Hieber
2021-09-12 20:59 ` [ptxdist] [PATCH v3 5/5] ptxd_lib_code_signing: add key whitelist checks Roland Hieber
2021-09-29 12:08 ` Michael Olbrich [this message]
2021-09-29 11:54 ` [ptxdist] [PATCH v3 1/5] kernel: make sure that kbuild can extract keys from the HSM Michael Olbrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210929120850.GG2560099@pengutronix.de \
--to=m.olbrich@pengutronix.de \
--cc=ptxdist@pengutronix.de \
--cc=rhi@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox