Create the root key pair on an offline device
Table of contents
- Create the template for our root certificate
- Generate root CA Certificate
- Bonus: add additional information
- Backup private key offline
I used a debian live image to do this, so that nothing is stored permanently.
When I shut it down, everything is gone. Of course, I will backup my keys somewhere safe.
You’re free to use whatever you prefer as your root CA, it can even be a completely separate and existing CA, but in this case we’ll do that using the step CLI tool.
Let’s start, here’s a list of the steps involved:
- Install the step CLI tool (see previous step)
- Create the template for our root certificate
- Generate the certificate and the private key
- Backup the private key and the certificate
Create the template for our root certificate
Configure step-ca with an RSA certificate chain
Run this command to create the file:
cat <<EOF > rsa_root_ca.tpl
{
"subject": {{ toJson .Subject }},
"issuer": {{ toJson .Subject }},
"keyUsage": ["certSign", "crlSign"],
"basicConstraints": {
"isCA": true,
"maxPathLen": 1
}
{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
, "signatureAlgorithm": "SHA256-RSAPSS"
{{- end }}
}
EOF
Let’s quickly go through the options here, but you can learn more about those here.
- Subject: this is quite self explanatory, it’s the “entity” owning the certificate. A must have property for our use case is the Common Name. Other details are optionals (more info later on).
- Issuer: since this is our Root CA, it is the same as the subject (Hint: root certs are self signed).
- keyUsage: this tells what this certificate can be used for (in our case, to sign other certificates and to sign certificate revocation lists)
- isCA: yes, this is a certificate authority, so we set this to true
- maxPathLen: this tells how many levels of CA below us are allowed to exists. In this case, only one level is admitted, so we can have one layer of intermediate CAs below the root, but they are not allowed to sign other CA below them.
The last bit, as explained within the link at the beginning of this chapter, tells our CA to sign using the RSA key type, specifically using the RSASSA-PSS key with a SHA256 digest.
It seems that MacOS and apple devices in general have some troubles dealing with certificates signed with RSASSA-PSS.
In case your clients are using macOS (which I believe they are, if you’re reading this tutorial) then just use the default root-ca profile from step or remove the whole if statement from the custom template, it’ll sign the certificate using the RSASSA with SHA-256 scheme.
Generate root CA Certificate
Let’s first put our very complex password (usa a password manager or /dev/urandom to generate it), which will be used to encrypt the private key, on a file (eg. password-file.txt). We can then move this file to our CA and feed it to the step tool as follows.
step certificate create "Example Root CA" \
root_ca.crt \
root_ca.key \
--template rsa_root_ca.tpl \
--password-file password_file.txt \
--kty RSA \
--not-after 87660h \
--size 3072
Let’s briefly go through the options:
- The first (mandatory) one is our subject, the name of our CA. In this case it is set to “Example Root CA”.
- Second and third (both mandatory) are the paths to store the public and the private keys.
- With the (optional) –template option, we set the template to use for our certificate.
- If you want to use one of the bundled templates you can use the –profile option instead, and then specify the profile name (eg. –profile root-ca)
- We then provide the password to encrypt the private key through a –password-file.
- After, we tell it to use RSA as our key type with –kty (we need this for SCEP).
- The last two options are the duration (–not-after), which in this case is set to 10 years (expressed in hours) and the key –size, which we set to 3072 bits.
Bonus: add additional information
You are of course free to make it “nicer” by providing additional information, such as Country, Organization, etc.
To do so, you first need to add the required keys to your template.
cat <<EOF > rsa_root_ca_xt.tpl
{
"subject": {
"country": {{ toJson .Insecure.User.country }},
"organization": {{ toJson .Insecure.User.organization }},
"commonName": {{ toJson .Subject.CommonName }}
},
"issuer": {
"country": {{ toJson .Insecure.User.country }},
"organization": {{ toJson .Insecure.User.organization }},
"commonName": {{ toJson .Subject.CommonName }}
},
"basicConstraints": {
"isCA": true,
"maxPathLen": 1
},
"keyUsage": ["certSign", "crlSign"]
{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
, "signatureAlgorithm": "SHA256-RSAPSS"
{{- end }}
}
EOF
for the same reasons mentioned above, delete these 3 lines from the template if you’re using Apple devices
{{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }}
, "signatureAlgorithm": "SHA256-RSAPSS"
{{- end }}
You then need to add the –set key=value options to the create command.
step certificate create "Example Root CA" \
root_ca.crt \
root_ca.key \
--template rsa_root_ca_xt.tpl \
--password-file password_file.txt \
--kty RSA \
--not-after 87660h \
--size 3072 \
--set organization="Acme Corp" \
--set country="US"
Backup private key offline
Now we have our root certificate and private key.
Download and store the private key somewhere very very very […] safe.
You cannot afford to lose it and you cannot afford to have someone else getting their hands on it.
Once we are done and we have signed our intermediates, we will shut down our vm or whatever you are using and will not touch it again until it’s time to renew or revoke an Intermediate CA or to create a new one.
Don’t forget to backup the password you used to encrypt the private key as well (possibly, not together with the key itself).