Hoi, > > On Wed, 2024-11-27 at 03:39 +0000, Johannes Schneider via > lists.openembedded.org wrote: > > > On Fri, 2024-11-01 at 13:05 +0100, Johannes Schneider via > > > lists.openembedded.org wrote: > > > > Add handling of ca-chains which can consist of more than one > > > > certificate in a .pem file, which need to be split off, processed and > > > > stored separately in the softhsm - as the tool-chain > > > > signing.bbclass::signing_import_cert* -> softhsm -> 'extract-cert' > > > > only supports one-per-file, due to using/expecting "plain" x509 > > > > in-/output. > > > > > > > > The added signing_import_cert_chain_from_pem function takes a <role> > > > > basename, and iterates through the input .pem file, creating numbered > > > > <role>_1, _2, ... roles as needed. > > > > > > Why do you want to import certificates without corresponding private > > > keys into the singing mechanism? > > > > > > They can't be used for signing, so don't really fit the role concept as > > > I intended it. This mismatch then leads to workarounds such as the _N > > > suffix and the problem below. > > > > During a (yocto) build, there can be places where the key is used to sign > > something, and other places where the corresponding certificate is > > inserted/used > > to verify the former - so there are two different "consumers" of one role; > > e.g. > > the kernel fitimage is signed with A.key, and at bootloader build time > > A.cert is > > inserted into the bootloader so that it can later verify what it is > > supposed to load. > > Yes, this split between signed artifact component (e.g. fitimage) and > authenticating component (e.g. bootloader) was the main motivation for > the concept of roles: both users of a role can be switched from one > (development) key to a different one at a single place > (local/auto.conf). > > > Now the bootloader<>kernel uscase is simple, because there is no > > verification of > > the certificate; e.g. there is no need to provide the complete chain. > > (for fit images, the certificate isn't even available during > authentication, only the public key) > > > But other usecases sign $something during buildtime, and at runtime this > > artifact would then be verified against a certificate, which in turn would > > need > > to be verified against it's CA-chain. > > Beyond the simple case of self-signed certificates, I find it clearer > to talk about leaf, intermediate and root certificates. Depending on > context, "chain" can mean leaf+intermediates, intermediates only, or > even leaf+intermediates+root. > > On the target, only the root certificates need to be stored in a > trusted location. The intermediate certificates are usually provided > with the signature to let the authenticating component to build a path > to a trusted root.
Or stored also in a trusted location? -> openssl -CApath /usr/share/ca-certificate/youre-company/ (which openssl/libopenssl actually picks up automatically, if the certificates there have hash-symlinks; and that's what we're using ATM) > > The leaf certificate is special in this case mainly because it's the > only certificate for which we have the corresponding private key. > > > By keeping the leaf (key+cert) plus all links (just the cert) up the > > certificate > > chain, the softhsm can be used as "single source of keymaterial". Otherwise > > there could be a rift between taking the keys from the softhsm during > > buildtime, > > but takeing the certificate (-chains) from $elsewhere. > > If we say signing.bbclass instead of SoftHSM, I'd agree. > (thumbsup) i was more refering to the "thing storing the keymaterial" the softhsm just happens to be the default backend of the .bbclass > > SoftHSM doesn't actually provide more security for private keys than > simple .pem files. So why add all this complexity instead of using > simple OE variable pointing to a private key file? Because it allows us > to: > - support hardware tokens > - decouple key configuration from key usage > => simplifies reuse > => consistent configuration for many recipes > - use same code-paths for development and release > => better testing > > (for more background info, see my OE WS 2023 talk > https://pretalx.com/openembedded-workshop-2023/talk/3C8MFF/) > > > I definitely agree that signing.bbclass should also have a way to get > the intermediate and root certs for any given key-pair via the role. > Introducing additional certificate-only roles for this causes new > problems, though (see below). what new problems? it's already being done for e.g. HABv4, where there are roles that do import a (leaf) certificat, but don't have a key to import > > > > > Afterwards the certificates can be used or extracted one-by-one from > > > > the softhsm, using the numbered roles; the only precondition - or > > > > limitation - is that the PKI structure has to be known beforhand; > > > > e.g. how many certificates are between leaf and root. > > > > > > The point of the signing.bbclass is to abstract over different HSMs and > > > allow flexible key selection at the .conf level. > > > > > > With this approach, any recipe using this set of generated > > > (certificate-only) roles now needs to know how long the chain is and > > > the PKIs with different layouts are no longer possible. > > > > That is the one caveat - the layout has to be the same and known beforehand; > > should we add more logic=complexity into the class to detect and handle this > > (... i guess: no ;-)? > > The information has to be stored somewhere, but ideally only in one > place. It can't be the recipes, because we always have (at least) two > of them (signing and authenticating components). Also, hard-coding > details of the layout in recipes reduces reusability across layers or > projects. > > I'm not willing to give up on the goal of proper decoupling. As the > inherent complexity has to live somewhere, I'd prefer the class, so a > single implementation can be reused and the recipes are less complex. > > > One aspect to consider is that there is not a one-to-one relationship > between the leaf certificate and the set of CA certificates Depends on which way you look, there is a 1:1 from leaf->intermediary, and then intermediary/-ies->root But you're right, it's not necessarily 1:1 in the other direction. > (intermediates+root): CAs are used to support multiple interchangeable > leaf certificates under a single trusted root. Without the need of > multiple leaf certs, you could just use a self-signed cert and avoid > all this complexity. :) :-D - or just do away with the code-signing complexity alltogether, and allow people to run OSS-software of their choosing on the hardware they paid money for ;-) > > For example, one build configuration could have different key-pairs > (roles) for different components, e.g. kernel modules and an IPE > policies. Their certificates may still be signed by the same CA, as > they are authenticated by the same component (the kernel). > > > So, handling (intermediate and root) CA certificates separately from > the roles would allow us to refer to them indirectly. > > > > Could you describe you use-case in detail? I think we should try to > > > find a design which avoids using roles for certificate chains, while > > > also allowing different PKI layouts between SoftHSM and actual HSMs. > > > > We have a build setup that, depending on a build-configuration switch, uses > > either development-keymaterial, or production-keymaterial. So the (soft)HSM > > encapsuled by the signing.bbclass and it's roles becomes the common > > interface > > through which all keymaterial is requested for artifact-signing purposes, or > > certificate (chains) are gathered to populate e.g. the rootfs with, for use > > during system runtime. > > Yes. > > > The intended usecase of the signing.bbclass is certainly to swith around the > > actual underlying HSMs (e.g. have a softhsm with devkeys, but a "real" HSM > > for > > the production usecase) - but due to limitations with our CI > > infrastructure... > > we only have a secured channel to fetch the productive keymaterial, but > > still > > need/intend to use the softhsm to "secure" the keymaterial on the CI during > > build-time. > > Using SoftHSM doesn't provide any security. If you're OK with that, it > still is useful as part of the abstraction, so that keys can be > switched without touching recipes. > > > Note that certificates are not secret, so storing them in a HSM is > primarily useful because that avoids the need of a different storage > location. Alternatively, all certs could be stored as files in the > layer and found by recursively walking the X509v3 Authority Key > Identifiers (but that would likely need a small tool to be called from > the class). > > > > > Signed-off-by: Johannes Schneider > > > > <[email protected]> > > > > --- > > > > meta-oe/classes/signing.bbclass | 30 ++++++++++++++++++++++++++++++ > > > > 1 file changed, 30 insertions(+) > > > > > > > > diff --git a/meta-oe/classes/signing.bbclass > > > > b/meta-oe/classes/signing.bbclass > > > > index 3e662ff73..8af7bbf8e 100644 > > > > --- a/meta-oe/classes/signing.bbclass > > > > +++ b/meta-oe/classes/signing.bbclass > > > > @@ -134,6 +134,36 @@ signing_import_cert_from_der() { > > > > signing_pkcs11_tool --type cert --write-object "${der}" --label > > > > "${role}" > > > > } > > > > > > > > +# signing_import_cert_chain_from_pem <role> <pem> > > > > +# > > > > + > > > > +# Import a certificate *chain* from a PEM file to a role. > > > > +# (e.g. multiple ones concatenated in one file) > > > > +# > > > > +# Due to limitations in the toolchain: > > > > +# signing class -> softhsm -> 'extract-cert' > > > > +# the input certificate is split into a sequentially numbered list of > > > > roles, > > > > +# starting at <role>_1 > > > > +# > > > > +# (The limitations are the conversion step from x509 to a plain .der, > > > > and > > > > +# extract-cert expecting a x509 and then producing only plain .der > > > > again) > > > > +signing_import_cert_chain_from_pem() { > > > > + local role="${1}" > > > > + local pem="${2}" > > > > + local i=1 > > > > + > > > > + cat "${pem}" | \ > > > > + while openssl x509 -inform pem -outform der -out > > > > ${B}/temp_${i}.der; do > > > > + signing_import_define_role "${role}_${i}" > > > > > > Calling signing_import_define_role() from an import function breaks the > > > separation and ordering we currently use (first > > > signing_import_define_role(), then import certs/keys) and is surprising > > > compared to the existing signing_import_define_role() > > > > That is true... got any advice/ideas on how to handle this? > > > > This way the PKI layout = the certificate chain lenght, has not to be known > > at > > the time of the import, but only when using the roles. A separate > > signing_import_define_N_roles(N) to have them prepared "blindly" ahead of > > time? > > If we separate certificates from roles, we'd have something like this > in the provider (where development keys are imported): > signing_import_prepare > > signing_import_root_cert kernel ".../kernel-ca.crt" > > signing_import_define_role kernel_modules > signing_import_cert_from_pem kernel_modules "${S}/kmod-development.crt" > signing_import_key_from_pem kernel_modules "${S}/kmod-development.key" > signing_import_set_ca kernel_modules kernel > That is an idea! adding a variable to to the SIGNING_ENV_FILE that allows to preserves the relation between certificates. Having a "signing_import_set_ca" is probably enough: leafs would point to their intermediary, and that to it's root; having an signing_import_root_cert is IMO not needed, as it's the same as a signing_import_cert_from_pem. > signing_import_define_role kernel_ipe > signing_import_cert_from_pem kernel_ipe "${S}/ipe-development.crt" > signing_import_key_from_pem kernel_ipe "${S}/ipe-development.key" > signing_import_set_ca kernel_ipe kernel > > signing_import_finish > > In the recipes using these roles, you'd need to refer to the CA. For > the kernel (authenticating component): > signing_prepare > cp "$(signing_get_root_cert kernel)" "${B}/kernel_ca.pem" > if it would be just a simple 'cp'... it's always a "get the pkcs11 uri" + extract-cert :-/ It would be neat if the signing.bbclass would support getting to the (public) certificate out of a role directly. > > When signing the modules, you'd use: > signing_prepare > signing_use_role kernel_modules > ... use $PKCS11_URI > > > For cases wth intermediate certificates, we could chain them to their > respective CA: > signing_import_prepare > > signing_import_root_cert kernel ".../kernel-ca.crt" > signing_import_intermediate_cert kernel_2024 kernel ".../kernel-kmods.crt" > and why not: signing_import_define_role kernel signing_import_cert_from_pem kernel ".../kernel-ca.crt" signing_import_define_role kernel_2024 signing_import_cert_from_pem kernel_2024 ".../kernel-kmods.crt" signing_import_set_ca kernel_2024 kernel Or did you mean to abstract those steps away in the functions signing_import_root_cert + signing_import_intermediate_cert ... seems redudndant to the import_cert_from_pem > > signing_import_define_role kernel_modules > signing_import_cert_from_pem kernel_modules "${S}/kmod-development.crt" > signing_import_key_from_pem kernel_modules "${S}/kmod-development.key" > signing_import_set_ca kernel_modules kernel_2024 > > signing_import_define_role kernel_ipe > signing_import_cert_from_pem kernel_ipe "${S}/ipe-development.crt" > signing_import_key_from_pem kernel_ipe "${S}/ipe-development.key" > signing_import_set_ca kernel_ipe kernel_2024 > > signing_import_finish > > To support this, only the user (e.g. kernel modules, IPE policy) would > need to conditionally include the intermediate certificates: > > signing_prepare > signing_use_role kernel_modules > SIGN_CMD="... --key=PKCS11_URI ..." > if signing_has_intermediate_certs kernel_modules; then > SIGN_CMD="$SIGN_CMD --intermediate=$(signing_get_intermediate_certs > kernel_modules)" > fi > > This recipe-level-code would support all cases: > - self-signed cert for simple cases > - leaf + root cert (no intermediates) > - leaf + intermediate + root cert (intermediates include with the signature) > > > For release builds, in addition to overriding the roles, you'd need to > override the certificates as well in you .conf: > SIGNING_PKCS11_URI[kernel_modules] = > "pkcs11:serial=DENK0200554;object=kmod&pin-value=123456" > SIGNING_CA_CERT[kernel_modules] = "file:///kod-ca.cert" > SIGNING_PKCS11_URI[kernel_ipe] = > "pkcs11:serial=DENK0200554;object=ipe&pin-value=123456" > SIGNING_CA_CERT[kernel_ipe] = "pkcs11:serial=DENK0200554;object=ipe-ca" > SIGNING_CA_CERT[kernel] = "pkcs11:serial=DENK0200554;object=kernel-ca" > So, you could have the certificates as files or in the HSM. > > If you'd need to define a different hierarchy, you'd add: > SIGNING_CA[kernel_modules] = "product_a_kmods_2024" > SIGNING_CA_CERT[kernel_modules] = "..." > SIGNING_CA[kernel_ipe] = "product_a_ipe_2024" > SIGNING_CA_CERT[kernel_ipe] = "..." > SIGNING_CA[product_a_kmods_2024] = "product_a_2024" > SIGNING_CA_CERT[product_a_kmods_2024] = "..." > SIGNING_CA[product_a_ipe_2024] = "product_a_2024" > SIGNING_CA_CERT[product_a_ipe_2024] = "..." > SIGNING_CA[product_a_2024] = "release-ca" > SIGNING_CA_CERT[product_a_2024] = "..." > SIGNING_CA_CERT[release-ca] = "..." > And the actual recipes wouldn't need to change, preserving the > decoupling between recipes and PKI configuration. > > I think that should offer enough flexibility for your and other > scenarios. > > Regards > Jan seems like this patch was already accepted in <master> :-) i'll put togheter another one to add the 'signing_import_set_ca', since it would supplement everything nicely. gruß Johannes
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#114126): https://lists.openembedded.org/g/openembedded-devel/message/114126 Mute This Topic: https://lists.openembedded.org/mt/109331453/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
