The following tutorial will walk you through creating a CA using the openssl command line tools.
-
Prepare the directory structure
# Create a directory where the CA will reside mkdir CA # Create subdirectories for issued certificates, issued certificate revocation lists, # new certificates, private keys and certificate signing requests respectively mkdir CA/certs CA/crl CA/newcerts CA/private CA/csr # Limit access to your private keys chmod 700 CA/private # Create a file database for certificates touch CA/index.txt # Create serial and CRL numbers echo 1000 > CA/serial echo 1000 > CA/crlnumber
-
Configure openssl (optionally, you can change the values in the section labelled
DEFAULTS
)# Download the openssl.cnf from this repository curl --no-progress-meter --output CA/openssl.cnf https://github.com/starlinglab/Starling_Certificate_Authority/blob/master/docs/openssl.cnf.example # Update the path to the CA directory sed -i'' "s#/home/user#$(pwd)#g" CA/openssl.cnf
-
Generate private key
openssl ecparam -genkey -name prime256v1 -out CA/private/ca.key.pem
-
Generate a self-signed certificate (important, the description is a required field; you can use something like
Starling Lab Root CA
for example)openssl req -new -x509 -days 7300 -config CA/openssl.cnf -key CA/private/ca.key.pem -sha256 -extensions v3_ca -out CA/certs/ca.cert.pem
-
Verify the validity of the certificate
openssl x509 -in CA/certs/ca.cert.pem -text
What is an intermediate certificate?
-
Prepare the directory structure
# Create a directory where the CA will reside mkdir intermediate-stg # Create subdirectories for issued certificates, issued certificate revocation lists, # new certificates, private keys and certificate signing requests respectively mkdir intermediate-stg/certs intermediate-stg/crl intermediate-stg/newcerts intermediate-stg/private intermediate-stg/csr # Limit access to your private keys chmod 700 intermediate-stg/private # Create a file database for certificates touch intermediate-stg/index.txt # Create serial and CRL numbers echo 1000 > intermediate-stg/serial echo 1000 > intermediate-stg/crlnumber
-
Configure openssl (optionally, you can change the values in the section labelled
DEFAULTS
)# Download the openssl.cnf from this repository curl --no-progress-meter --output intermediate-stg/openssl.cnf https://github.com/starlinglab/Starling_Certificate_Authority/blob/master/docs/openssl.cnf.example # Update the path to the intermediate-stg directory sed -i'' "s#/home/user/CA#$(pwd)/intermediate-stg#g" intermediate-stg/openssl.cnf # Update the policy used by the certificate sed -i'' "s#= policy_strict#= policy_loose#g" intermediate-stg/openssl.cnf # Update the pem file names sed -i'' "s#ca.key.pem#intermediate-stg.key.pem#g" intermediate-stg/openssl.cnf sed -i'' "s#ca.cert.pem#intermediate-stg.cert.pem#g" intermediate-stg/openssl.cnf sed -i'' "s#ca.crl.pem#intermediate-stg.crl.pem#g" intermediate-stg/openssl.cnf
-
Generate private key
openssl ecparam -genkey -name prime256v1 -out intermediate-stg/private/intermediate-stg.key.pem
-
Generate a signing request (important, the description is a required field; you can use something like
Starling Lab Intermediate CA
for example)openssl req -sha256 -new -config intermediate-stg/openssl.cnf -key intermediate-stg/private/intermediate-stg.key.pem -out intermediate-stg/csr/intermediate-stg.csr
You can sign the intermediate CSR multiple times with different root CA for cross singing.
CSR files do not contain any sensitive information and can be exchanged easily. However, it is required to set up a mechanism for verification if a file was not interfered with during such exchange.
-
Sign the intermediate CSR with root CA (you'll be asked for confirmation twice)
openssl ca -config CA/openssl.cnf -extensions v3_intermediate_ca -days 1825 -notext -md sha512 -create_serial -in intermediate-stg/csr/intermediate-stg.csr -out intermediate-stg/certs/intermediate-stg.cert.pem
-
Verify the validity of the certificate
openssl x509 -in intermediate-stg/certs/intermediate-stg.cert.pem -text
-
Verify the trust in the certificate
openssl verify -show_chain -CAfile CA/certs/ca.cert.pem intermediate-stg/certs/intermediate-stg.cert.pem
-
Choose a new name for the project certificate and expose it as a variable
keyname=test-cert
-
Generate private key
openssl ecparam -genkey -name prime256v1 -out intermediate-stg/private/$keyname.key.pem
-
Generate a signing request (important, the description is a required field; you can use something like
Starling Lab Project Certificate
for example)openssl req -sha256 -new -config intermediate-stg/openssl.cnf -key intermediate-stg/private/$keyname.key.pem -out intermediate-stg/csr/$keyname.csr
-
Sign the request with the Intermediate CA (optionally, you can use a fixed date, e.g.
-enddate 20230701120000Z
, instead of number of day, i.e.-days 375
; you'll be asked for confirmation twice)openssl ca -config intermediate-stg/openssl.cnf -extensions doc_cert -days 375 -notext -md sha256 -in intermediate-stg/csr/$keyname.csr -out intermediate-stg/certs/$keyname.cert.pem
-
Verify the validity of the certificate
openssl x509 -in intermediate-stg/certs/$keyname.cert.pem -text
-
Verify the trust in the certificate
openssl verify -show_chain -CAfile CA/certs/ca.cert.pem -untrusted intermediate-stg/certs/intermediate-stg.cert.pem intermediate-stg/certs/$keyname.cert.pem
-
Create certificate bundle
cat intermediate-stg/certs/$keyname.cert.pem > intermediate-stg/certs/$keyname.cert.bundle.pem cat intermediate-stg/certs/intermediate-stg.cert.pem >> intermediate-stg/certs/$keyname.cert.bundle.pem # if any more intermediate certs were used, or cross signed certificates to be include, bundle them here
-
Verify the trust in the certificate bundle
openssl verify -show_chain -CAfile CA/certs/ca.cert.pem -untrusted intermediate-stg/certs/$keyname.cert.bundle.pem intermediate-stg/certs/$keyname.cert.bundle.pem
If you wish to have the root CA private key live on a YubiKey you will need to install some packages and libraries. You will also need to install a management key that would be used to modify the certificates in the future. If this key is lost a factory reset would need to be done.
You can put the private key of a CA onto a Yubikey and use the key to sign certificates. This protects the key from being leaked by accident.
Install required packages and start service
sudo apt install libengine-pkcs11-openssl opensc-pkcs11 pcscd yubico-piv-tool ykcs11 gnutls-bin
systemctl start pcscd.socket
Configure management key on Yubikey. You can store key offline
export key=$(hexdump -vn24 -e'6/4 "%08X" 1 "\n"' /dev/urandom)
yubico-piv-tool -a set-mgm-key -n $key
echo $key
If you get Failed authentication with the application.
this may mean the key was initialized before. If you need to reset it see factory reset instructions in resources.
Import private key and certificate into the Yubikey (Position 9c also known as slot 02)
yubico-piv-tool -k$key -a import-key -s 9c -i private/ca.key.pem
yubico-piv-tool -k$key -a import-certificate -s9c -i certs/ca.cert.pem
You can now backup and delete the secret key from private/ca.key.pem
pin=$(export LC_CTYPE=C; dd if=/dev/urandom 2>/dev/null | tr -cd '[:digit:]' | fold -w6 | head -1)
puk=$(export LC_CTYPE=C; dd if=/dev/urandom 2>/dev/null | tr -cd '[:digit:]' | fold -w8 | head -1)
yubico-piv-tool -achange-pin -P123456 -N${pin}
yubico-piv-tool -achange-puk -P12345678 -N${puk}
You will need to find the Yubikey URI. This is unique to the physical key and needs to be looked up again if a different hardware devices is used.
List all the devices
p11tool --list-all
Copy the one that looks like the Yubikey IE pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=bd619d59419d430e;token=Starling%20Lab%20ROOT%20CA
List all the keys on the YubiKey. Value is taken from previous command.
p11tool --login --list-all pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=bd619d59419d430e;token=Starling%20Lab%20ROOT%20CA
Find Object 2
as this is where the key was imported into (Slot 02). Copy the URL Listed there IE pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=bd619d59419d430e;token=Starling%20Lab%20ROOT%20CA;id=%02;object=Certificate%20for%20Digital%20Signature;type=cert
Edit openssl.cnf, replace value of private_key
to the URL from above command
private_key = pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=bd619d59419d430e;token=Starling%20Lab%20ROOT%20CA;id=%02;object=Certificate%20for%20Digital%20Signature;type=cert`
You can now remove the private key from the secrets
folder.
NOTE: When signing with Yubikey (openssl ca
commands) you will need to tell openssl to use the pkcs11 engine by including the following -engine pkcs11
and -keyform engine
flags
IE:
openssl ca -config openssl.cnf -engine pkcs11 -keyform engine -extensions v3_intermediate_ca -days 1825 -notext -md sha512 -create_serial -in csr/intermediate-stg2022.csr -out certs/intermediate-stg2022.cert.pem
yubico-piv-tool -averify-pin -P471112
yubico-piv-tool -averify-pin -P471112
yubico-piv-tool -averify-pin -P471112
yubico-piv-tool -averify-pin -P471112
yubico-piv-tool -achange-puk -P471112 -N6756789
yubico-piv-tool -achange-puk -P471112 -N6756789
yubico-piv-tool -achange-puk -P471112 -N6756789
yubico-piv-tool -achange-puk -P471112 -N6756789
yubico-piv-tool -areset
yubico-piv-tool -aset-chuid
yubico-piv-tool -aset-ccc
openssl ec -aes-256-cbc -out intermediate-stg.key.encrypted.pem -in intermediate-stg/private/intermediate-stg.key.pem
openssl ec -in intermediate-stg.key.encrypted.pem -out intermediate-stg/private/intermediate-stg.key.decrypted.pem
qrencode -r intermediate-stg.key.encrypted.pem -o intermediate-stg.key.encrypted.png
- Create QR Code in PNG format.
- Place the image onto a standard
Ledger
with a 24-word size recovery sheet. - Clearly indicate the certificate name, the fact it is a encrypted private key, the number of copies there are and which copy this is.
- Store the password for the certificate in shared password manager.