Skip to content

Instantly share code, notes, and snippets.

@wowlocal
Last active May 1, 2023 16:10
Show Gist options
  • Save wowlocal/32ab8ee4de5f33a8be542e3195ca9d66 to your computer and use it in GitHub Desktop.
Save wowlocal/32ab8ee4de5f33a8be542e3195ca9d66 to your computer and use it in GitHub Desktop.
This script generates the files needed for the CA, intermediate CA and server certificates.
#!/bin/bash
# Credits: https://jamielinux.com/docs/openssl-certificate-authority
set -e
set -u
set -o pipefail
# check if ca dir exists
if [ -d "ca" ]; then
echo "\"ca\" directory already exists. Please remove it first."
exit 1
fi
read -s -p "Enter password for the CA: " ca_password
echo # newline
read -p "Enter hostname for the server certificate: " server_hostname
echo # newline
read -p "Enter IP address for the server certificate (optional): " server_ip
echo # newline
# cd to the directory of this script
cd "$(dirname "$0")"
no_prompts=1
# check if the first argument is passed
if [ $# -gt 0 ]; then
if [ "$1" == "-show_prompts" ]; then
no_prompts=0
else
echo "Usage: $0 [-show_prompts]"
exit 1
fi
fi
echo " --- Generating files..."
mkdir ca
cd ca
mkdir certs crl newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > crlnumber
# prepare the configuration file
cat <<EOF > openssl.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = .
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
# The root key and root certificate.
private_key = \$dir/private/ca.key.pem
certificate = \$dir/certs/ca.cert.pem
# For certificate revocation lists.
crlnumber = \$dir/crlnumber
crl = \$dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_strict
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of \`man ca\`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the \`ca\` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the \`req\` tool (\`man req\`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = GB
stateOrProvinceName_default = England
localityName_default =
0.organizationName_default = Alice Ltd
organizationalUnitName_default =
emailAddress_default =
[ v3_ca ]
# Extensions for a typical CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (\`man x509v3_config\`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (\`man ocsp\`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
EOF
echo " --- Generating the root key..."
if [ $no_prompts -eq 1 ]; then
openssl genrsa -aes256 -out private/ca.key.pem -passout pass:"$ca_password" 4096
else
openssl genrsa -aes256 -out private/ca.key.pem 4096
fi
echo " --- Generating the root certificate..."
chmod 400 private/ca.key.pem
if [ $no_prompts -eq 1 ]; then
openssl req -config openssl.cnf \
-key private/ca.key.pem \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out certs/ca.cert.pem \
-passin pass:"$ca_password" <<EOF
GB
England
London
University College London
Computer Science
Common Name
[email protected]
EOF
else
openssl req -config openssl.cnf \
-key private/ca.key.pem \
-new -x509 -days 7300 -sha256 -extensions v3_ca \
-out certs/ca.cert.pem
fi
chmod 444 certs/ca.cert.pem
echo " --- Generating the intermediate CA..."
mkdir intermediate
cd intermediate
mkdir certs crl csr newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > crlnumber
# prepare the configuration file
cat <<EOF > openssl.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = .
certs = \$dir/certs
crl_dir = \$dir/crl
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
copy_extensions = copy
# The root key and root certificate.
private_key = \$dir/private/intermediate.key.pem
certificate = \$dir/certs/intermediate.cert.pem
# For certificate revocation lists.
crlnumber = \$dir/crlnumber
crl = \$dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 375
preserve = no
policy = policy_loose
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of \`man ca\`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the \`ca\` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the \`req\` tool (\`man req\`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
# Optionally, specify some defaults.
countryName_default = GB
stateOrProvinceName_default = England
localityName_default =
0.organizationName_default = Alice Ltd
organizationalUnitName_default =
emailAddress_default =
[ v3_ca ]
# Extensions for a typical CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (\`man x509v3_config\`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (\`man x509v3_config\`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# Extension for CRLs (\`man x509v3_config\`).
authorityKeyIdentifier=keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (\`man ocsp\`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
EOF
echo " --- Generating the intermediate key..."
if [ $no_prompts -eq 1 ]; then
openssl genrsa -aes256 -out private/intermediate.key.pem -passout pass:"$ca_password" 4096
else
openssl genrsa -aes256 -out private/intermediate.key.pem 4096
fi
chmod 400 private/intermediate.key.pem
echo " --- Generating the intermediate certificate..."
if [ $no_prompts -eq 1 ]; then
openssl req -config openssl.cnf -new -sha256 \
-key private/intermediate.key.pem \
-out csr/intermediate.csr.pem \
-passin pass:"$ca_password" <<EOF
GB
England
London
University College London
Computer Science
Common Name
[email protected]
EOF
else
openssl req -config openssl.cnf -new -sha256 \
-key private/intermediate.key.pem \
-out csr/intermediate.csr.pem
fi
# sign the intermediate certificate
echo " --- Signing the intermediate certificate..."
cd ..
if [ $no_prompts -eq 1 ]; then
openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in intermediate/csr/intermediate.csr.pem \
-out intermediate/certs/intermediate.cert.pem \
-passin pass:"$ca_password" <<EOF
y
y
EOF
else
openssl ca -config openssl.cnf -extensions v3_intermediate_ca \
-days 3650 -notext -md sha256 \
-in intermediate/csr/intermediate.csr.pem \
-out intermediate/certs/intermediate.cert.pem
fi
chmod 444 intermediate/certs/intermediate.cert.pem
echo " --- Verifying the intermediate certificate..."
# verify the intermediate certificate against the root certificate
openssl verify -CAfile certs/ca.cert.pem intermediate/certs/intermediate.cert.pem
# create the certificate chain file
cat intermediate/certs/intermediate.cert.pem \
certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
chmod 444 intermediate/certs/ca-chain.cert.pem
# Server certificate
cd intermediate
# prepare the configuration file
cat <<EOF > server.cnf
HOME = .
RANDFILE = \$ENV::HOME/.rnd
####################################################################
[ req ]
default_bits = 2048
default_keyfile = serverkey.pem
distinguished_name = server_distinguished_name
req_extensions = server_req_extensions
string_mask = utf8only
####################################################################
[ server_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = MD
localityName = Locality Name (eg, city)
localityName_default = Baltimore
organizationName = Organization Name (eg, company)
organizationName_default = Test Server, Limited
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Test Server
emailAddress = Email Address
emailAddress_default = [email protected]
####################################################################
[ server_req_extensions ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
####################################################################
[ alternate_names ]
EOF
echo DNS.1 = $server_hostname >> server.cnf
if [[ -n "$server_ip" ]]; then
echo IP.1 = $server_ip >> server.cnf
fi
echo " --- Generating the server key..."
if [ $no_prompts -eq 1 ]; then
openssl genrsa -aes256 \
-out private/www.example.com.key.pem -passout pass:"$ca_password" 2048
else
openssl genrsa -aes256 \
-out private/www.example.com.key.pem 2048
fi
chmod 400 private/www.example.com.key.pem
echo " --- Generating the server certificate..."
if [ $no_prompts -eq 1 ]; then
openssl req -config server.cnf \
-key private/www.example.com.key.pem \
-new -sha256 -out csr/www.example.com.csr.pem \
-passin pass:"$ca_password" <<EOF
GB
England
London
University College London
Common Name
[email protected]
EOF
else
openssl req -config server.cnf \
-key private/www.example.com.key.pem \
-new -sha256 -out csr/www.example.com.csr.pem
fi
echo " --- Signing the server certificate..."
if [ $no_prompts -eq 1 ]; then
openssl ca -config openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in csr/www.example.com.csr.pem \
-out certs/www.example.com.cert.pem \
-passin pass:"$ca_password" <<EOF
y
y
EOF
else
openssl ca -config openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in csr/www.example.com.csr.pem \
-out certs/www.example.com.cert.pem
fi
chmod 444 certs/www.example.com.cert.pem
echo " --- Verifying the server certificate..."
# Verify server cert against the intermediate,root chain
openssl verify -CAfile certs/ca-chain.cert.pem \
certs/www.example.com.cert.pem
# Create certificate chain file for server to serve
cat certs/www.example.com.cert.pem \
certs/ca-chain.cert.pem > certs/www.example.com.chain.cert.pem
echo "\nDone!\n"
echo "The certificates are in the certs/ directory."
echo "The private keys are in the private/ directory."
echo "Intermediate and Server certificates are in the intermediate/ directory."
echo "The server cert and key file name is www.example.com.cert.pem and www.example.com.key.pem respectively."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment