Last active
February 22, 2021 10:21
-
-
Save allex/c070a927b5ef5cb34a1f713a0f169dae to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# GistID: c070a927b5ef5cb34a1f713a0f169dae | |
# Directories | |
cur=$(pwd) | |
tmp=$(mktemp -d) | |
scriptName=$(basename "$0") | |
# Certificate Variables | |
OUTPATH="./" | |
VERBOSE=0 | |
DURATION=3650 # 10 years | |
safeExit() { | |
if [ -d "$tmp" ]; then | |
if [ $VERBOSE -eq 1 ]; then | |
echo "Removing temporary directory '${tmp}'" | |
fi | |
rm -rf "$tmp" | |
fi | |
trap - INT TERM EXIT | |
exit | |
} | |
# Help Screen | |
help() { | |
echo -n "${scriptName} [OPTIONS] -c=US --state=California | |
Generate self-signed TLS certificate using OpenSSL | |
Options: | |
-c|--country Country Name (2 letter code) | |
-s|--state State/Province Name (full name) | |
-l|--locality Locality Name (eg, city) | |
-o|--organization Organization Name (eg, company) | |
-u|--unit Organizational Unit Name (eg, section) | |
-n|--common-name Common Name (e.g. server FQDN or YOUR name) | |
-e|--email Email Address | |
-p|--path Path to output generated keys | |
-d|--duration Validity duration of the certificate (in days) | |
-h|--help Display this help and exit | |
-v|--verbose Verbose output | |
" | |
} | |
# Test output path is valid | |
testPath() { | |
if [ ! -d $OUTPATH ]; then | |
echo "The specified directory \"${OUTPATH}\" does not exist" | |
exit 1 | |
fi | |
} | |
# Process Arguments | |
while [ "$1" != "" ]; do | |
PARAM=$(echo "$1" | awk -F= '{print $1}') | |
VALUE=$(echo "$1" | awk -F= '{print $2}') | |
case $PARAM in | |
-h|--help) help; safeExit ;; | |
-c|--country) C=$VALUE ;; | |
-s|--state) ST=$VALUE ;; | |
-l|--locality) L=$VALUE ;; | |
-o|--organization) O=$VALUE ;; | |
-u|--unit) OU=$VALUE ;; | |
-n|--common-name) CN=$VALUE ;; | |
-e|--email) emailAddress=$VALUE ;; | |
-p|--path) OUTPATH=$VALUE; testPath ;; | |
-d|--duration) DURATION=$VALUE ;; | |
-v|--verbose) VERBOSE=1 ;; | |
*) echo "ERROR: unknown parameter \"$PARAM\""; help; exit 1 ;; | |
esac | |
shift | |
done | |
# Prompt for variables that were not provided in arguments | |
checkVariables() { | |
# Country | |
if [ -z "$C" ]; then | |
echo -n "[C] Country Name (2 letter code) [CN]: " | |
read -r C | |
fi | |
# State | |
if [ -z "$ST" ]; then | |
echo -n "[ST] State/Province Name (full name) [Beijing]: " | |
read -r ST | |
fi | |
# Locality | |
if [ -z "$L" ]; then | |
echo -n "[L] Locality Name (eg, city) []: " | |
read -r L | |
fi | |
# Organization | |
if [ -z "$O" ]; then | |
echo -n "[O] Organization Name (eg, company) [iallex]: " | |
read -r O | |
fi | |
# Organizational Unit | |
if [ -z "$OU" ]; then | |
echo -n "[OU] Organizational Unit Name (eg, section) []: " | |
read -r OU | |
fi | |
# Common Name | |
if [ -z "$CN" ]; then | |
echo -n "[CN] Common Name (e.g. server FQDN or YOUR name) []: " | |
read -r CN | |
fi | |
# Email Address | |
if [ -z "$emailAddress" ]; then | |
echo -n "Email Address []: " | |
read -r emailAddress | |
fi | |
} | |
# Show variable values | |
showVals() { | |
echo "Country: ${C}"; | |
echo "State: ${ST}"; | |
echo "Locality: ${L}"; | |
echo "Organization: ${O}"; | |
echo "Organization Unit: ${OU}"; | |
echo "Common Name: ${CN}"; | |
echo "Email: ${emailAddress}"; | |
echo "Output Path: ${OUTPATH}"; | |
echo "Certificate Duration (Days): ${DURATION}"; | |
echo "Verbose: ${VERBOSE}"; | |
} | |
# Init | |
init() { | |
cd "$tmp" || exit | |
pwd | |
} | |
# Cleanup | |
cleanup() { | |
echo "Cleaning up" | |
cd "$cur" || exit | |
rm -rf "$tmp" | |
} | |
buildCsrCnf() { | |
# ; csr config for server key | |
cat << EOF > "${tmp}/tmp.csr.cnf" | |
[req] | |
default_bits = 2048 | |
prompt = no | |
default_md = sha256 | |
distinguished_name = dn | |
[dn] | |
C=${C} | |
ST=${ST} | |
L=${L} | |
O=${O} | |
OU=${OU} | |
CN=${CN} | |
emailAddress=${emailAddress} | |
EOF | |
"${VISUAL:-${EDITOR:-vi}}" -- "${tmp}/tmp.csr.cnf" | |
} | |
buildExtCnf() { | |
# ; extensions for server certificate | |
cat << EOF > "${tmp}/v3.ext" | |
authorityKeyIdentifier=keyid,issuer | |
basicConstraints=CA:FALSE | |
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment | |
subjectAltName = @alt_names | |
[alt_names] | |
DNS.1 = ${CN} | |
DNS.2 = im.l | |
IP.1 = 127.0.0.1 | |
EOF | |
"${VISUAL:-${EDITOR:-vi}}" -- "$tmp/v3.ext" | |
} | |
# Build TLS Certificate | |
build() { | |
# Santizie domain name for file name | |
FILENAME=`printf "${CN/\*\./}"|sed "s# \+#_#g"` | |
# Generate CA key & crt | |
openssl genrsa -out "${tmp}/tmp.key" 2048 | |
openssl req -x509 -new -nodes \ | |
-key "${tmp}/tmp.key" \ | |
-sha256 \ | |
-days "${DURATION}" \ | |
-out "${OUTPATH}${FILENAME}_CA.pem" \ | |
-subj "/C=${C}/${ST:+ST=${ST}/}${L:+L=${L}/}O=${O}/OU=${OU}/CN=${CN}/emailAddress=${emailAddress}" | |
# CSR Configuration | |
buildCsrCnf | |
# Create v3.ext configuration file | |
buildExtCnf | |
# Server key | |
openssl req -new -sha256 -nodes \ | |
-out "${OUTPATH}${FILENAME}.csr" \ | |
-newkey rsa:2048 -keyout "${OUTPATH}${FILENAME}.key" \ | |
-config <( cat "${tmp}/tmp.csr.cnf" ) | |
# Server certificate | |
openssl x509 -req \ | |
-in "${OUTPATH}${FILENAME}.csr" \ | |
-CA "${OUTPATH}${FILENAME}_CA.pem" \ | |
-CAkey "${tmp}/tmp.key" \ | |
-CAcreateserial \ | |
-out "${OUTPATH}${FILENAME}.crt" \ | |
-days "${DURATION}" \ | |
-sha256 \ | |
-extfile "${tmp}/v3.ext" | |
} | |
checkVariables | |
build | |
showVals | |
safeExit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment