Skip to content

Instantly share code, notes, and snippets.

@linjan2
Last active July 20, 2023 16:04
Show Gist options
  • Save linjan2/a35b17d980ec0dd7c2150dc5297a9c15 to your computer and use it in GitHub Desktop.
Save linjan2/a35b17d980ec0dd7c2150dc5297a9c15 to your computer and use it in GitHub Desktop.
Create OpenSSL certificates

Create OpenSSL certificates (root CA, CA, server, client)

A chain of certificates is created, resulting in a directory tree like below. A self-signed root CA issues a certificate to an intermediate CA. The intermediate CA issues certificates to a server host and a client host.

Two different OpenSSL configuration files are used. One for the req command and one for the ca command. Different configuation sections are selected depending on which certificate is being created.

.
├── ca
│   ├── certsdir
│   │   ├── 7E3A5848FEB0C9B4B2B9FE3EAF0D8276.pem
│   │   └── 7E3A5848FEB0C9B4B2B9FE3EAF0D8277.pem
│   ├── ca-chain.crt.pem
│   ├── ca.crt.pem
│   ├── ca.csr
│   ├── ca.key.pem
│   ├── index.txt
│   ├── index.txt.attr
│   ├── index.txt.attr.old
│   ├── index.txt.old
│   ├── serial.txt
│   └── serial.txt.old
├── caroot
│   ├── certsdir
│   │   ├── 36A403FF688A5BF26600A1AC9D0851AB.pem
│   │   └── 36A403FF688A5BF26600A1AC9D0851AC.pem
│   ├── caroot.crt.pem
│   ├── caroot.csr
│   ├── caroot.key.pem
│   ├── index.txt
│   ├── index.txt.attr
│   ├── index.txt.attr.old
│   ├── index.txt.old
│   ├── serial.txt
│   └── serial.txt.old
├── client
│   ├── client.crt.pem
│   ├── client.csr
│   ├── client.key.pem
│   └── full-chain.crt.pem
├── server
│   ├── full-chain.crt.pem
│   ├── server.crt.pem
│   ├── server.csr
│   └── server.key.pem
├── ca.cnf
└── req.cnf
# Setup working directory
umask 0077 # create new files as u=rwX
mkdir workingdir
cd workingdir
mkdir caroot ca server client caroot/certsdir ca/certsdir
touch caroot/index.txt ca/index.txt # create index file for root CA and CA
openssl rand -hex 16 > caroot/serial.txt # create initial serial for root CA's certificates
openssl rand -hex 16 > ca/serial.txt # create initial serial for CA's certificates
# create private keys
openssl genrsa -aes256 -out caroot/caroot.key.pem 4096 # prompts for passphrase
openssl genrsa -aes256 -out ca/ca.key.pem 4096 # prompts for passphrase
openssl genrsa -out server/server.key.pem 2048 # no password
openssl genrsa -out client/client.key.pem 2048 # no password
# view keys
openssl rsa -in caroot/caroot.key.pem -text -noout
openssl rsa -in server/server.key.pem -text -noout
# create CSRs for root CA, CA, server, and client
openssl req -new -key caroot/caroot.key.pem -out caroot/caroot.csr -config req.cnf -reqexts req_caroot_ext -subj '/C=SE/O=Test/CN=CAROOT'
openssl req -new -key ca/ca.key.pem -out ca/ca.csr -config req.cnf -reqexts req_ca_ext -subj '/C=SE/O=Test/CN=CA1'
openssl req -new -key server/server.key.pem -out server/server.csr -config req.cnf -reqexts req_server_ext -subj '/C=SE/O=Test/CN=server.example.com'
openssl req -new -key client/client.key.pem -out client/client.csr -config req.cnf -reqexts req_client_ext -subj '/C=SE/O=Test/CN=client.example.com/emailAddress=client@example.com'
# view CSRs
openssl req -noout -text -in caroot/caroot.csr
openssl req -noout -text -in ca/ca.csr
openssl req -noout -text -in server/server.csr
openssl req -noout -text -in client/client.csr
# self-sign root CA
pushd caroot # sign caroot CSR from caroot directory
openssl ca -selfsign -config ../ca.cnf \
-keyfile caroot.key.pem \
-policy ca_policy_match -extensions ca_caroot_ext -days 3650 -notext \
-in caroot.csr -out caroot.crt.pem
# view certificate
openssl x509 -text -noout -in caroot.crt.pem # as text
openssl x509 -subject -issuer -noout -in caroot.crt.pem # only subject and issuer
popd
# sign CA CSR with root CA
pushd caroot # sign ca CSR from caroot directory
openssl ca -config ../ca.cnf \
-cert caroot.crt.pem -keyfile caroot.key.pem \
-policy ca_policy_match -extensions ca_ca_ext -days 400 -notext \
-in ../ca/ca.csr -out ../ca/ca.crt.pem
# view certificate
openssl x509 -text -noout -in ../ca/ca.crt.pem # as text
openssl x509 -subject -issuer -noout -in ../ca/ca.crt.pem # only subject and issuer
popd
# sign server CSR with CA
pushd ca # sign server CSR from ca directory
openssl ca -config ../ca.cnf \
-cert ca.crt.pem -keyfile ca.key.pem \
-policy ca_policy_anything -extensions ca_server_ext -days 365 -notext \
-in ../server/server.csr -out ../server/server.crt.pem
# view certificate
openssl x509 -text -noout -in ../server/server.crt.pem # as text
openssl x509 -subject -issuer -noout -in ../server/server.crt.pem # only subject and issuer
popd
# sign client CSR with CA
pushd ca # sign client CSR from ca directory
openssl ca -config ../ca.cnf \
-cert ca.crt.pem -keyfile ca.key.pem \
-policy ca_policy_anything -extensions ca_client_ext -days 365 -notext \
-in ../client/client.csr -out ../client/client.crt.pem
# view certificate
openssl x509 -text -noout -in ../client/client.crt.pem # as text
openssl x509 -subject -issuer -noout -in ../client/client.crt.pem # only subject and issuer
popd
# bundle certificates
cat ca/ca.crt.pem caroot/caroot.crt.pem > ca-chain.crt.pem
cat server/server.crt.pem ca/ca.crt.pem > server/chain.crt.pem
cat server/server.crt.pem ca/ca.crt.pem caroot/caroot.crt.pem > server/full-chain.crt.pem
cat client/client.crt.pem ca/ca.crt.pem > client/chain.crt.pem
cat client/client.crt.pem ca/ca.crt.pem caroot/caroot.crt.pem > client/full-chain.crt.pem
# verify CA certificates
openssl verify -CAfile caroot/caroot.crt.pem caroot/caroot.crt.pem
openssl verify -CAfile caroot/caroot.crt.pem ca/ca.crt.pem
# verify endpoint certificates with full CA-chain
openssl verify -CAfile ca-chain.crt.pem server/server.crt.pem
openssl verify -CAfile ca-chain.crt.pem client/client.crt.pem
# verify partial chain upto issuing CA (not root CA)
openssl verify -CAfile ca/ca.crt.pem -show_chain -partial_chain server/server.crt.pem
openssl verify -CAfile ca/ca.crt.pem -show_chain -partial_chain client/client.crt.pem
openssl verify -CAfile server/full-chain.crt.pem -show_chain server/server.crt.pem
openssl verify -CAfile client/full-chain.crt.pem -show_chain client/client.crt.pem
# show all certificates sent by a server
openssl s_client -showcerts -connect server.example.com:443 < /dev/null
#
# Configuration for using ca
#
HOME = .
####################################################################
[ ca ]
default_ca = CA_default
[CA_default]
#default_days = 365
default_crl_days = 30
default_md = sha512 # Use public key default MD
preserve = yes # Keep passed DN ordering and don't ignore fields missing in policy
#x509_extensions = # The extensions to add to the signed certificate
email_in_dn = no # Don't concat the email in the DN
copy_extensions = copy # Required to copy SANs from CSR to cert
base_dir = .
#certificate =
#private_key =
#certs =
new_certs_dir = ${base_dir}/certsdir # Output location for new certs after signing
database = ${base_dir}/index.txt # Database index file
serial = ${base_dir}/serial.txt # File with the next serial number to use (in hex)
unique_subject = no # no means allow generation of duplicate subject certificates
#policy = # how similar the request should look to the CA certificate
crlnumber = ${base_dir}/crlnumber # the current crl number; must be commented out to leave a V1 CRL
name_opt = ca_default # Subject Name options; certificate details shown for signing confirmation
cert_opt = ca_default # Certificate field options; certificate details shown for signing confirmation
####################################################################
#
# Select a policy section with: -policy SECTION
#
[ ca_policy_match ]
countryName = match
stateOrProvinceName = optional
localityName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ ca_policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
#
# Select an extensions section with: -extensions SECTION
# With copy_extensions=copy, x509_extensions for ca copies or overrides CSR extensions for req
#
[ ca_caroot_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
[ ca_ca_ext ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
[ ca_server_ext ]
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer:always
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
[ ca_client_ext ]
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer:always
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
extendedKeyUsage = clientAuth
#
# Configuration for using req
#
HOME = .
####################################################################
[ req ]
default_bits = 4096 # 2048 for server and 4096 for CA
default_md = sha512
#default_keyfile =
#req_extensions = # add CA or server extension fields: -reqexts SECTION
string_mask = utf8only
distinguished_name = req_distinguished_name
attributes = req_attributes
[ req_attributes ]
challengePassword =
challengePassword_min = 12
challengePassword_max = 40
####################################################################
[ req_distinguished_name ]
# Describe the Subject
# Short names:
# C=countryName
# ST=stateOrProvinceName
# L=localityName
# O=organizationName
# OU=organizationalUnitName
# CN=commonName
# emailAddress
# Enter '.' to leave the field empty.
countryName = Country Name (2 letter code)
countryName_default = SE
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = .
localityName = Locality Name (eg, city)
localityName_default = .
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Test
organizationalUnitName = Organizational Unit (eg, division)
organizationalUnitName_default = .
commonName = Common Name (e.g. server FQDN or YOUR name)
emailAddress = Email Address
emailAddress_max = 64
####################################################################
#
# Extensions to CSR; these are added or overridden to certificate by ca-command when using copy_extensions=copy in ca
# Select an extensions section with: -reqexts SECTION
#
[ req_caroot_ext ]
subjectKeyIdentifier = hash
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
[ req_ca_ext ]
subjectKeyIdentifier = hash
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
[req_server_ext]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
IP.1 = 127.0.0.1
DNS.1 = localhost
DNS.2 = *.example.com
DNS.3 = example.com
[req_client_ext]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = email:copy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment