Skip to content

Instantly share code, notes, and snippets.

@wolever
Created April 19, 2012 15:27
Show Gist options
  • Save wolever/2421697 to your computer and use it in GitHub Desktop.
Save wolever/2421697 to your computer and use it in GitHub Desktop.
Tools for creating private certificate authorities
#!/bin/bash
set -e
nodes="-nodes"
if [[ "$1" == "-des" ]]; then
nodes=""
shift
fi
if [[ ! "$1" || ! "$2" || "$1" =~ "^-" ]]; then
echo "usage: $0 [-des] CommonName directory"
exit 2
fi
name="$1"
dir="$2"
subj="/C=CA/ST=Ontario/L=Toronto/O=Luminautics Inc./CN=$name"
cakey="ca.key"
if [[ ! "$nodes" ]]; then
cakey="$cakey-encrypted"
fi
if [[ -d "$dir" ]]; then
echo "error: $dir/ exists"
exit 1
fi
mkdir "$dir"
cat "`dirname "$0"`"/openssl.default.cfg | sed -e "s/{{CAKEY}}/$cakey/" > "$dir/openssl.cfg"
cd "$dir"
# Because we want to explicitly set the default start and end dates (see
# default_startdate, default_enddate in openssl.cfg), some hoops need to be
# jumped through:
# - A key + self-signed cert must be created
# - A CSR must be generated from that key
# - Then the self-signed cert must be used to sign the CSR
# First create a key + self-signed certificate
openssl req -new -x509 -config ./openssl.cfg \
-keyout "$cakey" \
-out "temp_cert.crt" \
-subj "$subj" \
$nodes \
-extensions "standard_ca"
mkdir "certs"
touch "database"
echo "0001" > "serial"
# Generate a new CSR from the private key
openssl req -new -config ./openssl.cfg \
-key "$cakey" \
-out "temp_csr.csr" \
-subj "$subj" \
$nodes \
-extensions "standard_ca"
# Use the self-signed certificate to sign the CSR, producing the final
# certificate.
openssl ca -config ./openssl.cfg \
-batch \
-cert "temp_cert.crt" \
-out "ca.crt" \
-in "temp_csr.csr" \
-extensions "standard_ca"
# Optionally, export the cert in pkcs12 format
#openssl pkcs12 -export -in "$cakey" -out "ca.p12"
# Cleanup!
rm temp_*
#!/bin/bash
set -e
usage() {
echo "usage: $0 [-server] [-des] ca keyname"
echo " -server include 'nsCertType=server' in the certificate"
echo " (for use with OpenVPN's 'ns-cert-type' option)"
echo " -des also include an encrypted private key"
}
extensions="standard"
nodes="-nodes"
while :; do
if [[ $# -eq 2 ]]; then
break
fi
case "${1-}" in
"-server")
extensions="server"
shift
;;
"-des")
nodes=""
shift
;;
**)
usage
exit 2
;;
esac
done
ca="${1%/}"
keyname="$2"
subj="/C=CA/ST=Ontario/L=Toronto/O=Luminautics Inc./CN=$keyname"
if [[ ! -d "$ca" ]]; then
echo "error: can't find $ca/"
exit 1
fi
cd "$ca/"
echo "--- creating key ---"
keyfile="$keyname-temp.key"
reqfile="$keyname-temp.csr"
crtfile="$keyname-temp.crt"
openssl req -new -config ./openssl.cfg \
-keyout "$keyfile" \
-out "$reqfile" \
-subj "$subj" \
-nodes \
-extensions "$extensions"
if [[ -f "passphrase" ]]; then
echo "=========="
echo "PASSWORD: `cat passphrase`"
echo "=========="
fi
openssl ca -config ./openssl.cfg \
-batch \
-noemailDN \
-in "$reqfile" \
-out "$crtfile" \
-extensions "$extensions"
pemfile="certs/$keyname.pem"
if [[ "$nodes" ]]; then
cat "$crtfile" "$keyfile" > "$pemfile"
echo "$ca/$pemfile created."
else
# Store an encrypted copy of the certificate in the CA's store
openssl rsa '-in' "$keyfile" -des3 -out "$keyfile-encrypted"
cat "$crtfile" "$keyfile-encrypted" > "$pemfile-encrypted"
echo "$ca/$pemfile-encrypted created."
# And stick an unencrypted copy of the certificate in /tmp/
touch "/tmp/$keyname.pem"
chmod 600 "/tmp/$keyname.pem"
cat "$crtfile" "$keyfile" > "/tmp/$keyname.pem"
echo "/tmp/$keyname.pem created"
fi
rm "$keyname-temp"*
#
# OpenSSL configuration file.
#
# Establish working directory.
dir = .
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = $dir/serial
database = $dir/database
new_certs_dir = $dir/certs
certificate = $dir/ca.crt
private_key = $dir/{{CAKEY}}
default_md = sha1
preserve = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
default_days =
default_startdate = 700101000001Z
default_enddate = 300101000000Z
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = sha1 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
#0.organizationName = Organization Name (company)
#organizationalUnitName = Organizational Unit Name (department, division)
#emailAddress = Email Address
#emailAddress_max = 40
#localityName = Locality Name (city, district)
#stateOrProvinceName = State or Province Name (full name)
#countryName = Country Name (2 letter code)
#countryName_min = 2
#countryName_max = 2
#commonName = commonName (hostname)
#commonName_max = 64
#0.organizationName_default = David Wolever
#organizationalUnitName_defaul =
#emailAddress_default = david@wolever.net
#localityName_default = Toronto
#stateOrProvinceName_default = Ontario
#countryName_default = CA
#
# Custom extension definitions
#
[ standard_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
[ standard ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ server ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
nsCertType = server
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment