Skip to content

Instantly share code, notes, and snippets.

@AlexAtkinson
Last active May 28, 2024 23:39
Show Gist options
  • Save AlexAtkinson/98efb3718e493abd263c32a0cd5032e6 to your computer and use it in GitHub Desktop.
Save AlexAtkinson/98efb3718e493abd263c32a0cd5032e6 to your computer and use it in GitHub Desktop.
Create a CA & Server Cert
#!/usr/bin/env bash
# ----------------------------------------------------------------------------------------------------------------------
#
# make-ca-cert.sh
#
# SYNOPSIS
# Creates a CA if one doesn't already exist, and installs it (debian).
# Creats a server certificate (including wildcard SAN) signed by the CA.
#
# ----------------------------------------------------------------------------------------------------------------------
# Environment Settings
# ----------------------------------------------------------------------------------------------------------------------
# none
# ----------------------------------------------------------------------------------------------------------------------
# Variables
# ----------------------------------------------------------------------------------------------------------------------
THIS_SCRIPT="${0##*/}"
DIR_NAME="${PWD##*/}"
PARENT_DIR_PATH="${PWD%/*}"
PARENT_DIR_NAME="${PARENT_DIR_PATH##*/}"
RC_LOG="false"
[[ "$RC_LOG" == "true" ]] && LOG_FILE="${THIS_SCRIPT}.log"
IFS_BAK=$IFS
# ----------------------------------------------------------------------------------------------------------------------
# Functions
# ----------------------------------------------------------------------------------------------------------------------
show_help() {
echo -e "$(cat << EOF
NAME
${0##*/} - Manage self signed certs for this localhost.
SYNOPSIS
${0##*/} [-cndsh]
DESCRIPTION
-c
Create a new self signed certificate.
-n \e[4mNAME\e[0m
The version to be released. Requies parameter: '-c'
-d \e[4mDAYS\e[0m
The duration in days that the certificate will be valid.
-s \e[4mSUBJ\e[0m
The subject for the certificate (in quotes). Example:
'/C=CA/ST=Ontario/L=Toronto/O=EvilKittens Co/OU=LifeQuality/CN=foo.co'
-h
Show this help menu.
EXAMPLES:
Generate a self signed cert for hell.com:
./make-ca-cert.sh -c -n hell.com -d 3650 -s '/C=CA/ST=Ontario/L=Toronto/O=Foo Co/OU=LifeQuality/CN=hell.com'
EOF
)
"
exit 1
}
[[ $# -eq 0 ]] && show_help
# This function enables syslog style error code handling with colors.
# Named loggerx so as to avoid clobbering logger if present.
# Note: There is no 9th severity level in RFC5424.
function loggerx() {
[[ $1 -eq 0 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;30;41mEMERGENCY\e[0m: ${*:2}"
[[ $1 -eq 1 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;31;43mALERT\e[0m: ${*:2}"
[[ $1 -eq 2 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;97;41mCRITICAL\e[0m: ${*:2}"
[[ $1 -eq 3 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;31mERROR\e[0m: ${*:2}"
[[ $1 -eq 4 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;33mWARNING\e[0m: ${*:2}"
[[ $1 -eq 5 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;30;107mNOTICE\e[0m: ${*:2}"
[[ $1 -eq 6 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;39mINFO\e[0m: ${*:2}"
[[ $1 -eq 7 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;97;46mDEBUG\e[0m: ${*:2}"
[[ $1 -eq 9 ]] && echo -e "$(date --utc +"%FT%T.%3NZ") - \e[01;32mSUCCESS\e[0m: ${*:2}"
}
function et() { loggerx 5 "TASK START: $task..."; }
function rc_handler() {
if [[ $1 -eq $2 ]] ; then
loggerx 9 "TASK END: $task."
else
loggerx 3 "TASK END: $task - exit code $2"
[[ "$3" == "KILL" ]] && exit "$2"
fi
}
function rc() {
result=$?
if [[ "$RC_LOG" == "true" ]]; then
rc_handler "$1" "$result" | tee -a "$LOG_FILE"
else
rc_handler "$1" "$result" "$2"
fi
}
# ------------------------------------------------------------------------------
# Arguments
# ------------------------------------------------------------------------------
OPTIND=1
while getopts "hcn:d:s:" opt; do
case $opt in
h)
show_help
;;
c)
arg_c='set'
;;
n)
arg_n='set'
NAME="$OPTARG"
;;
d)
arg_d='set'
DAYS="$OPTARG"
;;
s)
arg_s='set'
SUBJ="$OPTARG"
;;
*)
echo "ERROR: Invalid argument.!"
show_help
;;
esac
done
shift $((OPTIND-1))
# ----------------------------------------------------------------------------------------------------------------------
# Sanities
# ----------------------------------------------------------------------------------------------------------------------
if [[ -z $NAME ]]; then loggerx 3 "Missing argument: -n"; show_help; fi
if [[ -z $DAYS ]]; then loggerx 3 "Missing argument: -d"; show_help; fi
if [[ -z $SUBJ ]]; then loggerx 3 "Missing argument: -s"; show_help; fi
# ----------------------------------------------------------------------------------------------------------------------
# Main Operations
# ----------------------------------------------------------------------------------------------------------------------
## Setup ROOT CA Cert if missing
if [[ ! -f "$(hostname)CA.key" ]]; then
task="Create key: $(hostname)CA.key"; et
openssl genrsa -des3 -out "$(hostname)CA.key" 4096; rc 0
task="Create cert: $(hostname)CA.pem"; et
openssl req -x509 -new -nodes -key "$(hostname)CA.key" -sha256 -days 825 -out "$(hostname)CA.pem" ; rc 0
task="Installing self-signed root cert in /usr/local/share/ca-certificates/$(hostname)/"; et
sudo mkdir "/usr/local/share/ca-certificates/$(hostname)"
sudo cp "$(hostname)CA.pem" "/usr/local/share/ca-certificates/$(hostname)/$(hostname)CA.crt"
sudo update-ca-certificates
fi
## Setup server certs
if [[ ! -d "certs/$NAME" ]]; then
task="Creating directory: certs/$NAME"; et
mkdir "certs/$NAME"; rc 0
else
loggerx 2 "The directory certs/$NAME already exists. Delete this directory before retrying."
exit 1
fi
task="Create private key: certs/$NAME/server.key"; et
openssl genrsa -out "certs/$NAME/server.key" 4096; rc 0
task="Create certificate signing request: certs/$NAME/server.csr"; et
openssl req -new \
-key "certs/$NAME/server.key" \
-subj "$SUBJ" \
-out "certs/$NAME/server.csr"
rc 0
task="Create extension file: certs/$NAME/cert.ext"; et
cat <<EOF >>"certs/$NAME/cert.ext"
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = $NAME
DNS.2 = *.$NAME
IP.1 = 127.0.0.1
EOF
rc 0
task="Create certificate: certs/$NAME/server.crt"; et
openssl x509 -req -in "certs/$NAME/server.csr" \
-CA "$(hostname)CA.pem" \
-CAkey "$(hostname)CA.key" \
-CAcreateserial \
-days "$DAYS" \
-sha256 \
-out "certs/$NAME/server.crt" \
-extfile "certs/$NAME/cert.ext"
rc 0
task="Verify certificate: certs/$NAME/server.crt against the CA cert"; et
openssl verify -CAfile "$(hostname)CA.pem" -verify_hostname "$NAME" "certs/$NAME/server.crt"; rc 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment