| # Step by step to generate sample self-signed X.509 certificate chain and sign data with PKCS7 structure | |
| This readme demonstrates how to generate 3-layer X.509 certificate chain (RootCA | |
| -> IntermediateCA -> SigningCert) with OpenSSL commands, and user MUST set a | |
| UNIQUE Subject Name ("Common Name") on these three different certificates. | |
| ## How to generate a self-signed X.509 certificate chain via OPENSSL | |
| ### Set OPENSSL environment | |
| NOTE: Below steps are required for Windows. Linux may already have the OPENSSL | |
| environment correctly. | |
| ```cmd | |
| set OPENSSL_HOME=c:\home\openssl\openssl-[version] | |
| set OPENSSL_CONF=%OPENSSL_HOME%\apps\openssl.cnf | |
| ``` | |
| When a user uses OpenSSL (req or ca command) to generate the certificates, | |
| OpenSSL will use the openssl.cnf file as the configuration data (can use | |
| "-config path/to/openssl.cnf" to describe the specific config file). | |
| The user need check the openssl.cnf file, to find your CA path setting, e.g. | |
| check if the path exists in [ CA_default ] section. | |
| ```inf | |
| [ CA_default ] | |
| dir = ./demoCA # Where everything is kept | |
| ``` | |
| You may need the following steps for initialization: | |
| ```cmd | |
| rd ./demoCA /S/Q | |
| mkdir ./demoCA | |
| echo.>./demoCA/index.txt | |
| echo 01 > ./demoCA/serial | |
| mkdir ./demoCA/newcerts | |
| ``` | |
| OpenSSL will apply the options from the specified sections in openssl.cnf when | |
| creating certificates or certificate signing requests. Make sure your | |
| configuration in `openssl.cnf` is correct and rational for certificate | |
| constraints. The following sample sections were used when generating test | |
| certificates in this readme. | |
| ``` inf | |
| [ req ] | |
| default_bits = 2048 | |
| default_keyfile = privkey.pem | |
| distinguished_name = req_distinguished_name | |
| attributes = req_attributes | |
| x509_extensions = v3_ca # The extensions to add to the self signed cert | |
| ... | |
| [ v3_ca ] | |
| # Extensions for a typical Root CA. | |
| subjectKeyIdentifier=hash | |
| authorityKeyIdentifier=keyid:always,issuer | |
| basicConstraints = critical,CA:true | |
| keyUsage = critical, digitalSignature, cRLSign, keyCertSign | |
| ... | |
| [ v3_intermediate_ca ] | |
| # Extensions for a typical intermediate CA. | |
| subjectKeyIdentifier = hash | |
| authorityKeyIdentifier = keyid:always,issuer | |
| basicConstraints = critical, CA:true | |
| keyUsage = critical, digitalSignature, cRLSign, keyCertSign | |
| ... | |
| [ usr_cert ] | |
| # Extensions for user end certificates. | |
| basicConstraints = CA:FALSE | |
| nsCertType = client, email | |
| subjectKeyIdentifier = hash | |
| authorityKeyIdentifier = keyid,issuer | |
| keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment | |
| extendedKeyUsage = clientAuth, emailProtection | |
| ... | |
| ``` | |
| ### Generate the certificate chain | |
| NOTE: User MUST set a UNIQUE "Common Name" on the different certificate | |
| 1) Generate the Root Pair: | |
| * Generate a root key: | |
| ```cmd | |
| openssl genrsa -aes256 -out TestRoot.key 2048 | |
| ``` | |
| * Generate a self-signed root certificate: | |
| ```cmd | |
| openssl req -extensions v3_ca -new -x509 -days 3650 -key TestRoot.key -out TestRoot.crt | |
| openssl x509 -in TestRoot.crt -out TestRoot.cer -outform DER | |
| openssl x509 -inform DER -in TestRoot.cer -outform PEM -out TestRoot.pub.pem | |
| ``` | |
| 2) Generate the Intermediate Pair: | |
| * Generate the intermediate key: | |
| ```cmd | |
| openssl genrsa -aes256 -out TestSub.key 2048 | |
| ``` | |
| * Generate the intermediate certificate: | |
| ```cmd | |
| openssl req -new -days 3650 -key TestSub.key -out TestSub.csr | |
| openssl ca -extensions v3_intermediate_ca -in TestSub.csr -days 3650 -out TestSub.crt -cert TestRoot.crt -keyfile TestRoot.key | |
| openssl x509 -in TestSub.crt -out TestSub.cer -outform DER | |
| openssl x509 -inform DER -in TestSub.cer -outform PEM -out TestSub.pub.pem | |
| ``` | |
| 3) Generate User Key Pair for Data Signing: | |
| * Generate User key: | |
| ```cmd | |
| openssl genrsa -aes256 -out TestCert.key 2048 | |
| ``` | |
| * Generate User certificate: | |
| ```cmd | |
| openssl req -new -days 3650 -key TestCert.key -out TestCert.csr | |
| openssl ca -extensions usr_cert -in TestCert.csr -days 3650 -out TestCert.crt -cert TestSub.crt -keyfile TestSub.key | |
| openssl x509 -in TestCert.crt -out TestCert.cer -outform DER | |
| openssl x509 -inform DER -in TestCert.cer -outform PEM -out TestCert.pub.pem | |
| ``` | |
| * Convert Key and Certificate for signing | |
| Password is removed with -nodes flag for convenience in this sample. | |
| ```cmd | |
| openssl pkcs12 -export -out TestCert.pfx -inkey TestCert.key -in TestCert.crt | |
| openssl pkcs12 -in TestCert.pfx -nodes -out TestCert.pem | |
| ``` | |
| ## Verify Data Signing & Verification with new X.509 Certificate Chain | |
| 1) Sign a Binary File to generate a detached PKCS7 signature: | |
| ```cmd | |
| openssl smime -sign -binary -signer TestCert.pem -outform DER -md sha256 -certfile TestSub.pub.pem -out test.bin.p7 -in test.bin | |
| ``` | |
| 2) Verify PKCS7 Signature of a Binary File: | |
| ```cmd | |
| openssl smime -verify -inform DER -in test.bin.p7 -content test.bin -CAfile TestRoot.pub.pem -out test.org.bin | |
| ``` | |
| ## Generate DSC PCD include files for Certificate | |
| The `BinToPcd` utility can be used to convert the binary Certificate file to a | |
| text file can be included from a DSC file to set a PCD to the contents of the | |
| Certificate file. | |
| The following 2 PCDs can be set to the PKCS7 Certificate value. The first one | |
| supports a single certificate. The second one supports multiple certificate | |
| values using the XDR format. | |
| * `gEfiSecurityPkgTokenSpaceGuid.PcdPkcs7CertBuffer` | |
| * `gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr` | |
| ### Generate DSC PCD include files | |
| ```cmd | |
| BinToPcd.py -i TestRoot.cer -p gEfiSecurityPkgTokenSpaceGuid.PcdPkcs7CertBuffer -o TestRoot.cer.gEfiSecurityPkgTokenSpaceGuid.PcdPkcs7CertBuffer.inc | |
| BinToPcd.py -i TestRoot.cer -p gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr -x -o TestRoot.cer.gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr.inc | |
| ``` | |
| These files can be used in `!include` statements in DSC file PCD sections. For | |
| example: | |
| * Platform scoped fixed at build PCD section | |
| ```edk2_dsc | |
| [PcdsFixedAtBuild] | |
| !include BaseTools/Source/Python/Pkcs7Sign/TestRoot.cer.gEfiSecurityPkgTokenSpaceGuid.PcdPkcs7CertBuffer.inc | |
| ``` | |
| * Platform scoped patchable in module PCD section | |
| ```edk2_dsc | |
| [PcdsPatchableInModule] | |
| !include BaseTools/Source/Python/Pkcs7Sign/TestRoot.cer.gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr.inc | |
| ``` | |
| * Module scoped fixed at build PCD section | |
| ```edk2_dsc | |
| [Components] | |
| FmpDevicePkg/FmpDxe/FmpDxe.inf { | |
| <PcdsFixedAtBuild> | |
| !include BaseTools/Source/Python/Pkcs7Sign/TestRoot.cer.gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr.inc | |
| } | |
| ``` |