I’m trying to setup a PKI based on a CA root and CA intermediary.
I have scripts/generateServerCARoot.sh
which creates the CA root:
##!/usr/bin/env bash
set -xeuo pipefail
CA_DIR=server/generated/ca-root
REQ_DIR=server/requests
mkdir -p $CA_DIR
touch $CA_DIR/ca.index
openssl rand -hex 16 > $CA_DIR/ca.serial
mkdir "$CA_DIR/certs" "$CA_DIR/newcerts" "$CA_DIR/private"
openssl genpkey -algorithm RSA -aes-256-cbc -out "$CA_DIR/private/ca.key.pem" -pkeyopt rsa_keygen_bits:4096
chmod 400 "$CA_DIR/private/ca.key.pem"
openssl req -new -out "$CA_DIR/certs/ca.cert.pem" -config "$CA_DIR/ca.conf" -x509 -days 365 -key "$CA_DIR/private/ca.key.pem"
openssl x509 -in "$CA_DIR/certs/ca.cert.pem" -out "$CA_DIR/ca.pem" -outform PEM
With the configuration (server/generated/ca-intermediate/ca.conf
):
[ req ]
default_bits = 4096
encrypt_key = yes
default_md = sha256
string_mask = utf8only
utf8 = yes
prompt = no
x509_extensions = x509_ext
distinguished_name = distinguished_name
[ x509_ext ]
basicConstraints = critical, CA:true
nameConstraints = critical, @name_constraints
subjectKeyIdentifier = hash
issuerAltName = issuer:copy
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = digitalSignature, keyCertSign, cRLSign
[ distinguished_name ]
commonName = Barracuda Root Certificate Authority
[ ca ]
default_ca = CA_default
[ CA_default ]
base_dir = server/generated/ca-intermediate
database = $base_dir/ca.index
serial = $base_dir/ca.serial
certs = $base_dir/certs
new_certs_dir = $base_dir/newcerts
default_md = sha256
default_days = 365
email_in_dn = no
copy_extensions = copy
uniqueSubject = no
policy = root_ca_policy
private_key = $base_dir/private/ca.key.pem
certificate = $base_dir/certs/ca.cert.pem
[ ca_policy ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
[ root_ca_policy ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ intermediate_ca_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ server_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ name_constraints ]
permitted;DNS.0 = srv.local
It runs without errors.
Then I want to create and sign my CA intermediary scripts/generateServerCAIntermediate.sh
:
##!/usr/bin/env bash
set -xeuo pipefail
CA_ROOT_DIR=server/generated/ca-root
CA_DIR=server/generated/ca-intermediate
REQ_DIR=server/requests
mkdir -p $CA_DIR
touch $CA_DIR/ca.index
openssl rand -hex 16 > $CA_DIR/ca.serial
mkdir "$CA_DIR/certs" "$CA_DIR/newcerts" "$CA_DIR/private"
openssl genpkey -algorithm RSA -aes-256-cbc -out "$CA_DIR/private/ca.key.pem" -pkeyopt rsa_keygen_bits:4096
chmod 400 "$CA_DIR/private/ca.key.pem"
openssl req -new -out "$CA_DIR/certs/ca.csr.pem" -config "$CA_DIR/ca.conf" -x509 -days 365 -key "$CA_DIR/private/ca.key.pem"
# openssl ca -out "$CA_DIR/certs/ca.cert.pem" -config "$CA_DIR/sign-ca.conf" -extensions x509_ext -days 32 -notext -key "$CA_DIR/certs/ca.csr.pem"
# openssl x509 -req -out "$CA_DIR/certs/ca.cert.pem" -CA "$CA_DIR/sign-ca.conf" -days 32 -in "$CA_DIR/certs/ca.csr.pem"
openssl ca -batch -config "$CA_DIR/sign-ca.conf" -notext -in "$CA_DIR/certs/ca.csr.pem" -out "$CA_DIR/certs/ca.cert.pem"
openssl x509 -in "$CA_DIR/certs/ca.cert.pem" -out "$CA_DIR/ca.pem" -outform PEM
echo "Copy '$CA_DIR/ca.pem' to srv@/etc/nixos/certificates/.../ca.pem"
With the intermediate CA (server/generated/ca-root/ca.conf
):
[ req ]
default_bits = 4096
encrypt_key = yes
default_md = sha256
string_mask = utf8only
utf8 = yes
prompt = no
x509_extensions = x509_ext
distinguished_name = distinguished_name
[ x509_ext ]
basicConstraints = critical, CA:true
nameConstraints = critical, @name_constraints
subjectKeyIdentifier = hash
issuerAltName = issuer:copy
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = digitalSignature, keyCertSign, cRLSign
[ distinguished_name ]
commonName = Barracuda Root Certificate Authority
[ ca ]
default_ca = CA_default
[ CA_default ]
base_dir = server/generated/ca-root
database = $base_dir/ca.index
serial = $base_dir/ca.serial
certs = $base_dir/certs
new_certs_dir = $base_dir/newcerts
default_md = sha256
default_days = 365
email_in_dn = no
copy_extensions = copy
uniqueSubject = no
policy = root_ca_policy
private_key = $base_dir/private/ca.key.pem
certificate = $base_dir/certs/ca.cert.pem
[ ca_policy ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
[ root_ca_policy ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ intermediate_ca_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ server_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ name_constraints ]
permitted;DNS.0 = srv.local
And finally the configuration used to sign the intermediate CA (server/generated/ca-intermediate/sign-ca.conf
):
[ req ]
default_bits = 4096
encrypt_key = yes
default_md = sha256
string_mask = utf8only
utf8 = yes
prompt = no
x509_extensions = x509_ext
distinguished_name = distinguished_name
[ x509_ext ]
basicConstraints = critical, CA:true, pathlen:0
nameConstraints = critical, @name_constraints
subjectKeyIdentifier = hash
issuerAltName = issuer:copy
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = digitalSignature, keyCertSign, cRLSign
[ distinguished_name ]
commonName = Barracuda Intermediate Certificate Authority
[ ca ]
default_ca = CA_default
[ CA_default ]
base_dir = server/generated/ca-root
database = $base_dir/ca.index
serial = $base_dir/ca.serial
certs = $base_dir/certs
new_certs_dir = $base_dir/newcerts
default_md = sha256
default_days = 32
email_in_dn = no
copy_extensions = copy
uniqueSubject = no
policy = intermediate_ca_policy
private_key = $base_dir/private/ca.key.pem
certificate = $base_dir/certs/ca.cert.pem
[ ca_policy ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = supplied
[ root_ca_policy ]
countryName = match
stateOrProvinceName = match
localityName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ intermediate_ca_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ server_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ name_constraints ]
permitted;DNS.0 = srv.local
However, it fails on signing the intermediate CA:
+ openssl ca -batch -config server/generated/ca-intermediate/sign-ca.conf -notext -in server/generated/ca-intermediate/certs/ca.csr.pem -out server/generated/ca-intermediate/certs/ca.cert.pem
Using configuration from server/generated/ca-intermediate/sign-ca.conf
Enter pass phrase for server/generated/ca-root/private/ca.key.pem:
Error reading certificate request in server/generated/ca-intermediate/certs/ca.csr.pem
140263254656832:error:09FFF06C:PEM routines:CRYPTO_internal:no start line:/build/libressl-3.7.3/crypto/pem/pem_lib.c:694:Expecting: CERTIFICATE REQUEST
I don’t know why server/generated/ca-intermediate/certs/ca.csr.pem
is not a certificate, while I used openssl req -new
.
Which step did I miss?
You used
openssl req -new ... -x509 ...
which generates a self-signed cert, NOT a CSR which is what you want. Once you remove-x509
you should remove-days 32
because a CSR has no time period; only a cert does that. In addition you have the subject name of the intermediate CA the same as the root CA which will make this cert unusable because reliers will think it is self-signed (even if it’s not). Also I’m skeptical this is programming or development (although in a script) so not officially answering.