diff --git a/.github/opensslroot.cfg b/.github/opensslroot.cfg new file mode 100644 index 0000000..5eaf1eb --- /dev/null +++ b/.github/opensslroot.cfg @@ -0,0 +1,317 @@ +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = ./randfile + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +subjectKeyIdentifier=hash + +#authorityKeyIdentifier=keyid:always,issuer:always + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +#authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d310711 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,135 @@ +name: Capsule Generation CI + +on: + push: + pull_request: + +jobs: + build-capsule: + runs-on: ubuntu-latest + env: + REP_ROOT: ${{ github.workspace }} + CERT_PATH: ${{ github.workspace }}/certs + BOOT_BINARIES_URL: https://qartifactory-edge.qualcomm.com/artifactory/qsc_releases/software/chip/qualcomm_linux-spf-1-0/qualcomm-linux-spf-1-0_test_device_public/r1.0_00116.0/qcm6490-le-1-0/common/build/ufs/bin/QCM6490_bootbinaries.zip + defaults: + run: + working-directory: uefi_capsule_generation + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y uuid-dev device-tree-compiler + pip install validators requests pyelftools pylibfdt + + - name: Generate OpenSSL certificates + working-directory: ${{ github.workspace }} + run: | + set -e + + mkdir -p ${CERT_PATH} + cd ${CERT_PATH} + + # Set env variables with proper configuration: + export FMP_ROOT_CERT_SUBJECT="/CN=OEM Root CA/O=FMP/OU=OEM Key/L=San Diego/ST=California/C=US" + export FMP_CA_CERT_SUBJECT="/CN=OEM Intermediate CA/O=FMP/OU=OEM Key/L=San Diego/ST=California/C=US" + export FMP_USER_CERT_SUBJECT="/CN=OEM User/O=FMP/OU=OEM Key/L=San Diego/ST=California/C=US" + export FMP_KEY_PASSWORD="testpassword" + + # The demoCA directory should be initialized: + mkdir -p demoCA + mkdir -p demoCA/newcerts + touch demoCA/index.txt + echo 01 > demoCA/serial + + cp ${REP_ROOT}/.github/opensslroot.cfg ./ + + # Create rand file: + dd if=/dev/urandom of=randfile bs=256 count=1 > /dev/null 2>&1 + + # Generate a Root Key/Certificate: + openssl genrsa -aes256 -passout "pass:${FMP_KEY_PASSWORD}" -out QcFMPRoot.key 2048 + openssl req -new -x509 -config opensslroot.cfg -subj "${FMP_ROOT_CERT_SUBJECT}" -days 3650 \ + -passin "pass:${FMP_KEY_PASSWORD}" -key QcFMPRoot.key -out QcFMPRoot.crt + openssl x509 -in QcFMPRoot.crt -out QcFMPRoot.cer -outform DER + openssl x509 -inform DER -in QcFMPRoot.cer -outform PEM -out QcFMPRoot.pub.pem + + # Generate the Intermediate Key/Certificate: + openssl genrsa -aes256 -passout "pass:${FMP_KEY_PASSWORD}" -out QcFMPSub.key 2048 + openssl req -new -config opensslroot.cfg -subj "${FMP_CA_CERT_SUBJECT}" \ + -passin "pass:${FMP_KEY_PASSWORD}" -key QcFMPSub.key -out QcFMPSub.csr + openssl ca -config opensslroot.cfg -extensions v3_ca -batch \ + -in QcFMPSub.csr -days 3650 -out QcFMPSub.crt -cert QcFMPRoot.crt \ + -passin "pass:${FMP_KEY_PASSWORD}" -keyfile QcFMPRoot.key + openssl x509 -in QcFMPSub.crt -out QcFMPSub.cer -outform DER + openssl x509 -inform DER -in QcFMPSub.cer -outform PEM -out QcFMPSub.pub.pem + + # Generate User Key Pair/Certificate for Data Signing: + openssl genrsa -aes256 -passout "pass:${FMP_KEY_PASSWORD}" -out QcFMPCert.key 2048 + openssl req -new -config opensslroot.cfg -subj "${FMP_USER_CERT_SUBJECT}" \ + -passin "pass:${FMP_KEY_PASSWORD}" -key QcFMPCert.key -out QcFMPCert.csr + openssl ca -config opensslroot.cfg -batch -in QcFMPCert.csr -days 3650 \ + -out QcFMPCert.crt -cert QcFMPSub.crt -passin "pass:${FMP_KEY_PASSWORD}" -keyfile QcFMPSub.key + openssl x509 -in QcFMPCert.crt -out QcFMPCert.cer -outform DER + openssl x509 -inform DER -in QcFMPCert.cer -outform PEM -out QcFMPCert.pub.pem + + # Convert the User Key and Certificate: + openssl pkcs12 -export -passout "pass:${FMP_KEY_PASSWORD}" -out QcFMPCert.pfx \ + -passin "pass:${FMP_KEY_PASSWORD}" -inkey QcFMPCert.key -in QcFMPCert.crt + openssl pkcs12 -passin "pass:${FMP_KEY_PASSWORD}" -in QcFMPCert.pfx -nodes \ + -out QcFMPCert.pem + + - name: Convert certificate to HEX format + run: | + python3 BinToHex.py ${CERT_PATH}/QcFMPRoot.cer ${CERT_PATH}/QcFMPRoot.inc + echo "Contents of QcFMPRoot.inc:" + cat ${CERT_PATH}/QcFMPRoot.inc + - name: Setup environment + run: | + python3 capsule_setup.py + - name: Fetch boot binaries + run: | + wget ${BOOT_BINARIES_URL} + unzip QCM6490_bootbinaries.zip -d ./ + - name: Add certificates to the XBLConfig + run: | + python3 xblconfig_parser.py ./QCM6490_bootbinaries/xbl_config.elf dump --out-dir ./QCM6490_bootbinaries + echo "Successfully dumped XBLConfig sections. Now updating the QcCapsuleRootCert property in the DTB and patching it back to XBLConfig." + + oldcert=$(fdtdump ./QCM6490_bootbinaries/post-ddr-kodiak-1.0.dtb 2>&1 | grep QcCapsuleRoot || true) + echo "Old value of QcCapsuleRoot property: $oldcert" + + python3 set_dtb_property.py ./QCM6490_bootbinaries/post-ddr-kodiak-1.0.dtb /sw/uefi/uefiplat QcCapsuleRootCert "@list:${CERT_PATH}/QcFMPRoot.inc" ./QCM6490_bootbinaries/post-ddr-kodiak-1.0-updated.dtb + + newcert=$(fdtdump ./QCM6490_bootbinaries/post-ddr-kodiak-1.0-updated.dtb 2>&1 | grep QcCapsuleRoot || true) + echo "New value of QcCapsuleRoot property: $newcert" + + python3 xblconfig_parser.py ./QCM6490_bootbinaries/xbl_config.elf replace 8 ./QCM6490_bootbinaries/post-ddr-kodiak-1.0-updated.dtb ./QCM6490_bootbinaries/xbl_config_patched.elf + mv ./QCM6490_bootbinaries/xbl_config_patched.elf ./QCM6490_bootbinaries/xbl_config.elf + echo "Old value of QcCapsuleRoot property: $oldcert" + echo "New value of QcCapsuleRoot property: $newcert" + if [ "$oldcert" = "$newcert" ]; then + echo "Error: Certificate was not updated in XBLConfig" + exit 1 + fi + - name: Generate firmware version and create firmware volume + run: | + python3 SYSFW_VERSION_program.py -Gen -FwVer 0.0.1.2 -LFwVer 0.0.0.0 -O SYSFW_VERSION.bin + python3 SYSFW_VERSION_program.py --PrintAll SYSFW_VERSION.bin + python3 FVCreation.py firmware.fv -FvType "SYS_FW" FvUpdate.xml SYSFW_VERSION.bin ./QCM6490_bootbinaries + - name: Update JSON parameters + run: | + python3 UpdateJsonParameters.py -j config.json -f SYS_FW -b SYSFW_VERSION.bin -pf firmware.fv \ + -p ${CERT_PATH}/QcFMPCert.pem -x ${CERT_PATH}/QcFMPRoot.pub.pem -oc ${CERT_PATH}/QcFMPSub.pub.pem -g 6F25BFD2-A165-468B-980F-AC51A0A45C52 + - name: Generate capsule file + run: | + python3 GenerateCapsule.py -e -j config.json -o capsule_file.cap --capflag PersistAcrossReset -v + - name: Dump capsule information + run: | + python3 GenerateCapsule.py --dump-info capsule_file.cap