This module guides you through creating a quantum-resistant Root Certificate Authority for Sassy Corp using ML-DSA-87 (FIPS 204). The Root CA is the trust anchor of your PKI—it signs the Intermediate CA certificate and establishes the chain of trust.
After completing this module, you will be able to:
- Generate an ML-DSA-87 key pair for the Root CA
- Create an OpenSSL configuration file for CA operations
- Create a self-signed Root CA certificate
- Generate an initial Certificate Revocation List (CRL)
- Verify the Root CA certificate structure
| Attribute | Value |
|---|---|
| Algorithm | ML-DSA-87 (NIST Level 5 / 256-bit security) |
| Validity | 10 years |
| Key Usage | Certificate Sign, CRL Sign |
| Path Length | 1 (can sign only one level of sub-CAs) |
| Hash Function | SHA-512 |
Why ML-DSA-87?
The Root CA requires the highest security level because:
- It is the ultimate trust anchor
- Compromise would affect the entire PKI (but it's a lab so c'est la vie)
- Long validity period (10 years) requires future-proof security
- ML-DSA-87 provides NIST Level 5 security (equivalent to 256-bit classical)
Verify you are operating as the pqcadmin user:
whoamiIf not, switch to the pqcadmin user:
sudo su - pqcadminNavigate to the Root CA directory:
cd /opt/sassycorp-pqc/root-caCreate the OpenSSL configuration file for the Root CA (and of course you can modify this to your own internal needs):
vim /opt/sassycorp-pqc/root-ca/openssl.cnfEnter the following configuration:
# Sassy Corp Root CA - OpenSSL Configuration
# FIPS 204 (ML-DSA-87) Compliant
####################################################################
[ ca ]
default_ca = CA_default
[ CA_default ]
# Directory and file locations
dir = /opt/sassycorp-pqc/root-ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# Root CA certificate and private key
private_key = $dir/private/root-ca.key
certificate = $dir/certs/root-ca.crt
# Certificate Revocation Lists
crlnumber = $dir/crlnumber
crl = $dir/crl/root-ca.crl
crl_extensions = crl_ext
default_crl_days = 30
# Certificate defaults
default_md = sha512
name_opt = ca_default
cert_opt = ca_default
default_days = 1825
preserve = no
policy = policy_strict
# Extensions
x509_extensions = v3_intermediate_ca
copy_extensions = copy
####################################################################
[ policy_strict ]
# Root CA only signs Intermediate CAs
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Intermediate CA can sign certificates with different attributes
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
default_md = sha512
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
countryName = US
stateOrProvinceName = Washington
localityName = Winthrop
organizationName = Sassy Corp
organizationalUnitName = PKI Operations
commonName = Sassy Corp Root CA
emailAddress = pki@sassycorp.internal
####################################################################
[ v3_ca ]
# Root CA certificate extensions
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:1
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectAltName = @alt_names_ca
[ v3_intermediate_ca ]
# Intermediate CA certificate extensions
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
authorityInfoAccess = caIssuers;URI:http://pki.sassycorp.lab/root-ca.crt
crlDistributionPoints = URI:http://pki.sassycorp.lab/root-ca.crl
subjectAltName = @alt_names_intermediate
[ crl_ext ]
# CRL extensions
authorityKeyIdentifier = keyid:always
####################################################################
[ alt_names_ca ]
DNS.1 = sassycorp.lab
DNS.2 = pki.sassycorp.lab
email.1 = pki@sassycorp.internal
[ alt_names_intermediate ]
DNS.1 = intermediate.sassycorp.lab
email.1 = pki@sassycorp.internalSave and exit.
Set appropriate permissions on the configuration file:
chmod 644 /opt/sassycorp-pqc/root-ca/openssl.cnfGenerate the ML-DSA-87 private key:
openssl genpkey -algorithm ML-DSA-87 -out /opt/sassycorp-pqc/root-ca/private/root-ca.keySet restrictive permissions on the private key:
chmod 400 /opt/sassycorp-pqc/root-ca/private/root-ca.keyVerify the key was created:
ls -la /opt/sassycorp-pqc/root-ca/private/Expected output:
-r-------- 1 pqcadmin pqcadmin <size> <date> root-ca.key
View the private key details (without exposing the actual key material):
openssl pkey -in /opt/sassycorp-pqc/root-ca/private/root-ca.key -noout -text | head -20Expected output:
ML-DSA-87 Private-Key:
priv:
<hexadecimal values representing the private key>
Extract and view the public key component:
openssl pkey -in /opt/sassycorp-pqc/root-ca/private/root-ca.key -pubout -out /opt/sassycorp-pqc/root-ca/certs/root-ca.pubopenssl pkey -pubin -in /opt/sassycorp-pqc/root-ca/certs/root-ca.pub -noout -text | head -10Generate the self-signed Root CA certificate valid for 10 years (3650 days):
openssl req -config /opt/sassycorp-pqc/root-ca/openssl.cnf \
-key /opt/sassycorp-pqc/root-ca/private/root-ca.key \
-new -x509 -days 3650 \
-extensions v3_ca \
-out /opt/sassycorp-pqc/root-ca/certs/root-ca.crtCommand breakdown:
| Option | Purpose |
|---|---|
-config |
Use the Root CA configuration file |
-key |
Private key to sign the certificate |
-new |
Create a new certificate request |
-x509 |
Output a self-signed certificate |
-days 3650 |
Certificate validity (10 years) |
-extensions v3_ca |
Use v3_ca extension section |
-out |
Output file for the certificate |
Set permissions on the certificate:
chmod 444 /opt/sassycorp-pqc/root-ca/certs/root-ca.crtView the complete certificate:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -textCheck the issuer and subject (should be identical for self-signed):
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -issuer -subjectExpected output:
issuer=C=US, ST=Washington, L=Winthrop, O=Sassy Corp, OU=PKI Operations, CN=Sassy Corp Root CA, emailAddress=pki@sassycorp.internal
subject=C=US, ST=Washington, L=Winthrop, O=Sassy Corp, OU=PKI Operations, CN=Sassy Corp Root CA, emailAddress=pki@sassycorp.internal
Check the validity dates:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -datesExpected output (dates will vary):
notBefore=<current date>
notAfter=<date 10 years from now>
Check the signature algorithm:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -text | grep "Signature Algorithm"Expected output:
Signature Algorithm: ML-DSA-87
Signature Algorithm: ML-DSA-87
Verify the Basic Constraints extension:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -text | grep -A1 "Basic Constraints"Expected output:
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
Verify the Key Usage extension:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -text | grep -A1 "Key Usage"Expected output:
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
Verify the certificate signature is valid:
openssl verify -CAfile /opt/sassycorp-pqc/root-ca/certs/root-ca.crt /opt/sassycorp-pqc/root-ca/certs/root-ca.crtExpected output:
/opt/sassycorp-pqc/root-ca/certs/root-ca.crt: OK
Create the initial Certificate Revocation List:
openssl ca -config /opt/sassycorp-pqc/root-ca/openssl.cnf \
-gencrl \
-out /opt/sassycorp-pqc/root-ca/crl/root-ca.crlSet permissions on the CRL:
chmod 644 /opt/sassycorp-pqc/root-ca/crl/root-ca.crlVerify the CRL:
openssl crl -in /opt/sassycorp-pqc/root-ca/crl/root-ca.crl -noout -textExpected output (partial):
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: ML-DSA-87
Issuer: C=US, ST=Washington, L=Winthrop, O=Sassy Corp, OU=PKI Operations, CN=Sassy Corp Root CA, emailAddress=pki@sassycorp.internal
Last Update: <date>
Next Update: <date + 30 days>
CRL extensions:
X509v3 Authority Key Identifier:
<key identifier>
No Revoked Certificates.
...
Generate fingerprints for certificate verification:
SHA-256 fingerprint:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -fingerprint -sha256SHA-512 fingerprint:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -fingerprint -sha512Record these fingerprints securely—they can be used to verify certificate authenticity during distribution.
Create a DER-encoded version for systems that require it:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -outform DER -out /opt/sassycorp-pqc/root-ca/certs/root-ca.derchmod 444 /opt/sassycorp-pqc/root-ca/certs/root-ca.derCreate a secure backup of the Root CA (in production, this would go to offline storage):
mkdir -p /opt/sassycorp-pqc/backupsCreate an encrypted backup archive:
tar -czf - /opt/sassycorp-pqc/root-ca/private/root-ca.key | openssl enc -aes-256-cbc -pbkdf2 -out /opt/sassycorp-pqc/backups/root-ca-key-backup.tar.gz.encYou will be prompted for a password. Use a strong password and store it securely.
Warning: In a production environment, the Root CA private key should be stored on a secured air-gapped system or Hardware Security Module (HSM). Never leave the private key on an internet-connected system. There's more you SHOULD do but this is very bare minimum.
List all files in the Root CA directory:
find /opt/sassycorp-pqc/root-ca -type f -exec ls -la {} \;Expected files and permissions:
-rw-r--r-- 1 pqcadmin pqcadmin <size> openssl.cnf
-r-------- 1 pqcadmin pqcadmin <size> private/root-ca.key
-r--r--r-- 1 pqcadmin pqcadmin <size> certs/root-ca.crt
-r--r--r-- 1 pqcadmin pqcadmin <size> certs/root-ca.der
-r--r--r-- 1 pqcadmin pqcadmin <size> certs/root-ca.pub
-r--r--r-- 1 pqcadmin pqcadmin <size> crl/root-ca.crl
-rw-r--r-- 1 pqcadmin pqcadmin <size> index.txt
-rw-r--r-- 1 pqcadmin pqcadmin <size> index.txt.attr
-rw-r--r-- 1 pqcadmin pqcadmin <size> serial
-rw-r--r-- 1 pqcadmin pqcadmin <size> crlnumber
You have successfully created a quantum-resistant Root CA for Sassy Corp:
| Component | Details |
|---|---|
| Algorithm | ML-DSA-87 (FIPS 204, Level 5) |
| Certificate | /opt/sassycorp-pqc/root-ca/certs/root-ca.crt |
| Private Key | /opt/sassycorp-pqc/root-ca/private/root-ca.key |
| Public Key | /opt/sassycorp-pqc/root-ca/certs/root-ca.pub |
| CRL | /opt/sassycorp-pqc/root-ca/crl/root-ca.crl |
| Validity | 10 years |
| Path Length | 1 (one sub-CA level) |
Problem: OpenSSL doesn't recognize ML-DSA-87
Solution: Verify you're using the correct OpenSSL binary:
openssl versionProblem: Cannot read private key
Solution: Ensure correct ownership and permissions:
sudo chown pqcadmin:pqcadmin /opt/sassycorp-pqc/root-ca/private/root-ca.key
chmod 400 /opt/sassycorp-pqc/root-ca/private/root-ca.keyProblem: Self-signature verification fails
Solution: Ensure the certificate was created with the correct key:
openssl x509 -in /opt/sassycorp-pqc/root-ca/certs/root-ca.crt -noout -pubkey > /tmp/cert-pub.pem
openssl pkey -in /opt/sassycorp-pqc/root-ca/private/root-ca.key -pubout > /tmp/key-pub.pem
diff /tmp/cert-pub.pem /tmp/key-pub.pemIf there's a difference, regenerate the certificate.
Before proceeding, verify:
- Root CA private key has 400 permissions
- Private key directory has 700 permissions
- Certificate signature algorithm is ML-DSA-87
- Basic Constraints shows CA:TRUE with pathlen:1
- Key Usage includes keyCertSign and cRLSign
- Self-signature verification succeeds
- Backup of private key is created and secured
Next: Intermediate CA →