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?