Build-time secure-boot signing of Qualcomm firmware - #3168
Igor Opaniuk (igoropaniuk) wants to merge 13 commits into
Conversation
|
This is based on the original #2598 + comments addressed |
|
Also need a CI entry so we can build with the new kas files. |
ee5c01a to
d5751ae
Compare
Test Results 66 files 311 suites 4h 35m 8s ⏱️ For more details on these failures, see this check. Results for commit 2073d47. ♻️ This comment has been updated with latest results. |
|
We should also hash the content of the keys, in keys they are modified by the user, something like: |
d5751ae to
c483aac
Compare
|
Test fails are unrelated to these changes, seems they are board/lab flakes (sm8750/qcs8300/iq-9075 LAVA jobs) |
Sectools needs the per-SoC Security Profile XML that describes a
chipset's image ids and signing rules. Qualcomm publishes them in
qualcomm/security-profiles (BSD-3-Clause-Clear).
Stage them in the native sysroot under ${datadir}/qcom-security-profiles
so qcom-firmware-sign.bbclass can pick one by filename. Plain data, no
toolchain needed.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Sectools v2 signs, verifies and inspects Qualcomm firmware images
against a Security Profile. It ships as a pre-built binary from the
Qualcomm Software Center, which allows anonymous downloads.
Package release 1.50.0: install the Linux build matching BUILD_ARCH
(x86_64 or aarch64) into ${bindir}, restrict COMPATIBLE_HOST to those
two and anchor the license to the bundled License.pdf. The archive
name only carries two version parts, hence ZIP_TOPDIR.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
FIRMWARE_COMPRESSION is applied inline in do_install:append. A later change needs to undo it before signing the blobs and redo it afterwards, so give the compression a name, firmware_qcom_compress, and add its inverse, firmware_qcom_decompress. No functional change. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
510cff2 to
0558c45
Compare
|
Jose Quaresma (@quaresmajose) addressed you comments, thanks! |
0558c45 to
f7d5c86
Compare
The pre-built Qualcomm firmware this layer ships is unsigned, and a
secure-boot enabled device needs an OEM signature on it.
Add a class that signs images at build time with sectools-native and
security-profiles-native. do_qcom_firmware_sign runs after do_install
and before do_deploy, do_package and do_populate_sysroot, under pseudo so
files rewritten in ${D} keep their ownership. With
QCOM_FIRMWARE_SIGN_ENABLE at its default "0" the task is noexec, pulls in
no dependencies, and the per-SoC Security Profile stays out of the task
hashes so shared recipes keep identical signatures across machines.
The task is driven by data: every file with a QCOM_FIRMWARE_SIGN_SUFFIXES
suffix under QCOM_FIRMWARE_SIGN_DIRS is mapped to a sectools image id
(conf/qcom-firmware-sign-image-ids.conf), checked against the active
profile, signed with the keys in QCOM_FIRMWARE_SIGN_KEY_DIR and verified
against the OEM root hash. Recipes configure those variables and hook
prefuncs/postfuncs rather than redefining the task.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The SoC boot binaries are deployed exactly as unpacked, unsigned. Point qcom-firmware-sign at QCOM_BOOT_BINARY_DIRS, one level deep and including .melf, so the images are signed in place before do_deploy picks them up. The recipes stay allarch unless signing is on; a signed build is machine-specific. No-op unless QCOM_FIRMWARE_SIGN_ENABLE is "1". Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
HLOS firmware is authenticated by TrustZone and needs an OEM signature
on a secure-boot enabled device, like the boot binaries.
Point qcom-firmware-sign at ${D}${FW_QCOM_BASE_PATH}. Compressed blobs
no longer match the image-id map, so firmware_qcom_decompress runs as a
prefunc of the sign task and firmware_qcom_compress as a postfunc; the
packaged output is unchanged for builds that do not sign; the recipes
stay allarch unless signing is on and are machine-specific otherwise.
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
A class that adds files to the qcomflash bundle has to run after every artefact is in place and before the tarball is created. Move the symlink and tarball creation out of create_qcomflash_pkg into create_qcomflash_tarball, registered as a postfunc of do_image_qcomflash, so such a class can prepend its own postfunc. No functional change. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
A VIP-fused device only programs images whose digests appear in a table signed with the OEM keys, so a signed build is not flashable without one, and the table must cover exactly the files in the bundle. Add qcomflash-vip.bbclass: qdl --dry-run --create-digests produces the table, sectools mbn-tool wraps it and it is signed as image id VIP. It lands in the qcomflash tarball as vip-tables/DigestsToSign.bin.mbn, via a do_image_qcomflash postfunc ahead of the tarball, ready for qdl --vip-table-path. image_types_qcom.bbclass inherits the class when QCOMFLASH_VIP is "1", which follows QCOM_FIRMWARE_SIGN_ENABLE. qdl-native comes from the qdl 2.8 recipe. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
The Security Profile is a property of the silicon, not of a build overlay. Set QCOM_FIRMWARE_SIGN_SECPROFILE in the SoC includes for the targets qualcomm/security-profiles covers: kodiak (QCS6490), lemans (QCS9100), monaco (QCS8300) and talos (QCS615). Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Exercising the signing pipeline needs an OEM key set, and production
material cannot live in the tree. Add a development ECDSA PKI under
ci/test-keys/ecdsa: root and attestation CA certificates, the CA key
and the root hash for sectools --verify-root.
DEVELOPMENT KEYS ONLY, never for production builds.
The commands used to generate the certificates and keys:
# Generate Root CA certificate/keys
openssl ecparam -genkey -name secp384r1 -outform PEM -out qpsa_rootca0.key
openssl req -new -key qpsa_rootca0.key -sha384 -out rootca_pem0.crt \
-subj '/C=US/CN=Generated OEM Root CA/OU=CDMA Technologies/OU=General Use OEM Key (OEM should update all fields)/L=San Diego/O=SecTools/ST=California' \
-config opensslroot.cfg -x509 -days 7300 -set_serial 1
openssl x509 -in rootca_pem0.crt -inform PEM -out qpsa_rootca0.cer -outform DER
# Generate Attestation CA certificate/keys
openssl ecparam -genkey -name secp384r1 -outform PEM -out qpsa_attestca0.key
openssl req -new -key qpsa_attestca0.key -out ca0.CSR \
-subj '/C=US/ST=California/CN=Generated OEM Attestation CA/O=SecTools/L=San Diego' \
-config opensslroot.cfg -sha384
openssl x509 -req -in ca0.CSR -CA rootca_pem0.crt -CAkey qpsa_rootca0.key -out ca_pem0.crt \
-set_serial 1 -days 7300 -extfile v3.ext -sha384 -CAcreateserial
openssl x509 -inform PEM -in ca_pem0.crt -outform DER -out qpsa_attestca0.cer
# Calculate hash of Root CA certificate
openssl dgst -sha384 qpsa_rootca0.cer > sha384_roots_hash.txt
opensslroot.cfg is a stock openssl.cnf (a copy of the one shipped with
OpenSSL is enough) whose [ req ] section points x509_extensions at a
[ v3_ca ] section with basicConstraints = CA:true, keyUsage = cRLSign,
keyCertSign and subjectKeyIdentifier = hash; these become the root
certificate's extensions. v3.ext is a four-line extension file for the
attestation CA:
authorityKeyIdentifier=keyid,issuer
subjectKeyIdentifier=hash
basicConstraints=CA:true,pathlen:0
keyUsage=keyCertSign
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Point QCOM_FIRMWARE_SIGN_KEY_DIR at ci/test-keys/ecdsa, mirroring
ci/capsule-test-keys.yml:
kas build ci/<machine>.yml:ci/secure-boot.yml:ci/ecdsa-secure-boot-test-keys.yml
Assisted-by: Claude Code:claude-fable-5
Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
ci/secure-boot.yml sets QCOM_FIRMWARE_SIGN_ENABLE to "1", which also puts the VIP table into the qcomflash bundle, and provides development placeholders for the fuse-binding ids and the anti-rollback floor. The profile comes from the machine, the keys from a second overlay such as ci/ecdsa-secure-boot-test-keys.yml. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
Nothing exercises ci/secure-boot.yml in CI, so a change to the signing class or the sectools recipe only breaks a signing build after it lands. Add an rb3gen2-core-kit entry that builds with the secure-boot overlay and the ECDSA test keys, next to the capsule one. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
f7d5c86 to
2073d47
Compare
|
|
||
| create_qcomflash_tarball() { | ||
| # Create symlink to ${QCOMFLASH_DIR} dir | ||
| ln -rsf ${QCOMFLASH_DIR} ${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.qcomflash |
There was a problem hiding this comment.
This ln -rsf now runs after create_symlinks (image.bbclass prepends it to every do_image_* postfunc list), so the link already exists and points at a directory. Without -n, ln follows it and creates <IMAGE_NAME>.qcomflash -> . inside the bundle, which then ends up in the tarball (confirmed on a local rb3gen2 build). create_symlinks already creates the same link, so just drop this line.
This PR adds a build-time secure-boot signing pipeline for Qualcomm firmware. It introduces two -native recipes - sectools-native, security-profiles-native, and - together with a qcom-firmware-sign.bbclass that any recipe can inherit to sign its deploy artefacts before they ship. It also generates VIP tables using QDL, so the final package is ready to be flashed with QDL to the secured device with VIP engaged.
A development ECDSA test-key set and a ci/secure-boot.yml kas overlay are included so a fresh checkout can exercise the full pipeline end-to-end without sourcing OEM signing material.
To test this build: