Skip to content

Instantly share code, notes, and snippets.

@pkutzner
Last active December 11, 2015 23:53
Show Gist options
  • Save pkutzner/646407e099b57075b43d to your computer and use it in GitHub Desktop.
Save pkutzner/646407e099b57075b43d to your computer and use it in GitHub Desktop.
Script to generate 2 CSR/Key pairs (and pins) for use with HPKP. Asks for pertinent information interactively.
#!/bin/bash -
#===============================================================================
#
# FILE: gen_pkp_csrs.sh
#
# USAGE: ./gen_pkp_csrs.sh
#
# DESCRIPTION: Generates SSL CSR/Key pairs.
# This script generates both the primary CSR/Key pair for a given
# URL and SAN(s) (if specified), as well as a backup pair for use
# with HTTPS Public Key Pinning (HPKP). It will also generate
# the requiesite hashes for the public keys (for the PKP headers)
# in form of files with the extension '.pin'
#
# OPTIONS: None
# REQUIREMENTS: openssl, libressl, or gnutls
# BUGS: ---
# NOTES: Code makes heavy use of Bash shorthand for brevity.
# See "Greycat's Wiki (http://mywiki.wooledge.org/BashGuide) for
# more information, specifically parameter expansion:
# http://mywiki.wooledge.org/BashGuide/Parameters#Parameter_Expansion
# AUTHOR: Preston Kutzner (pkutzner at marketingresources dot com)
# ORGANIZATION: Marketing Resources, Inc.
# CREATED: 12/11/2015 14:41
# REVISION: 1.0
# LICENSE: BSD
# Copyright(c) 2015, Preston Kutzner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED, IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCURMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWERVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#===============================================================================
set -o nounset # Treat unset variables as an error
set -o pipefail
readonly default_bits=4096
readonly default_days=365
DELCONF=0
echo
read -p "Company Name = " O_VAL
read -p "Department = " OU_VAL
read -p "City = " L_VAL
read -p "State = " ST_VAL
read -p "URL = " CN_VAL_FIRST
read -p "Verify URL = " CN_VAL_SECOND
read -p "Key bits (ENTER=${default_bits}) = " BITSIZE
read -p "Valid days (ENTER=${default_days}) = " DAYS
read -p "Do you have SANs to add? (y/n): " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
i=1
echo
read -p "Enter SAN $i: " -r
SANS=("${REPLY}")
while [[ ! -z $REPLY ]]; do
(( i++ ))
read -p "Enter SAN $i (Enter=DONE): " -r
[[ ! -z $REPLY ]] && SANS+=("$REPLY")
done
else
SANS=''
fi
[ "${CN_VAL_FIRST}" != "${CN_VAL_SECOND}" ] && { echo "Inputs don't match, exiting!"; exit 1; }
CN_VAL="${CN_VAL_FIRST}"
CONF_FILE="/tmp/${CN_VAL//./_}_openssl.conf"
cat > "${CONF_FILE}" <<EOF
[ req ]
req_extensions = v3_req
distinguished_name = req_distinguished_name
default_days = ${DAYS:-$default_days}
default_md = sha256
string_mask = nombstr
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (city, district)
0.organizationName = Organization Name (e.g. company)
organizationalUnitName = Organizational Unit Name (department, division)
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
EOF
if [[ ! -z $SANS ]]; then
i=1
{
echo "subjectAltName = @alt_names";
echo;
echo "[ alt_names ]";
for name in "${SANS[@]}"; do
echo "DNS.$i = $name";
(( i++ ));
done;
} >> "${CONF_FILE}"
fi
echo
echo -n "Generating CSR key... "
openssl genrsa -out "${CN_VAL//./_}.key" ${BITSIZE:-$default_bits} >/dev/null 2>&1
echo "done."
echo
echo -n "Generating CSR key pin hash... "
openssl rsa -in "${CN_VAL//./_}.key" -pubout -outform der 2>/dev/null | openssl dgst -sha256 -binary | openssl enc -base64 -out "${CN_VAL//./_}.key.pin" >/dev/null 2>&1
echo "done."
echo
echo -n "Generating CSR... "
openssl req -new -key "${CN_VAL//./_}.key" -subj "/C=US/ST=${ST_VAL}/L=${L_VAL}/O=${O_VAL}/OU=${OU_VAL}/CN=${CN_VAL}" -out "${CN_VAL//./_}.csr" -config "${CONF_FILE}" >/dev/null 2>&1
[ $? ] || DELCONF=1
echo "done."
echo
echo -n "Generating backup CSR key... "
openssl genrsa -out "${CN_VAL//./_}-backup.key" ${BITSIZE:-$default_bits} >/dev/null 2>&1
echo "done."
echo
echo -n "Generating backup CSR key pin hash... "
openssl rsa -in "${CN_VAL//./_}-backup.key" -pubout -outform der 2>/dev/null | openssl dgst -sha256 -binary | openssl enc -base64 -out "${CN_VAL//./_}-backup.key.pin" >/dev/null 2>&1
echo "done."
echo
echo -n "Generating backup CSR... "
openssl req -new -key "${CN_VAL//./_}-backup.key" -subj "/C=US/ST=${ST_VAL}/L=${L_VAL}/O=${O_VAL}/OU=${OU_VAL}/CN=${CN_VAL}" -out "${CN_VAL//./_}-backup.csr" -config "${CONF_FILE}" >/dev/null 2>&1
[ $? ] || DELCONF=1
echo "done."
echo
read -p "Do you want to review the contents of the initial CSR? (y/n): " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] && { openssl req -in "${CN_VAL//./_}.csr" -text -verify -noout | more; }
read -p "Do you want to review the contents of the backup CSR? (y/n): " -n 1 -r
echo
[[ $REPLY =~ ^[Yy]$ ]] && { openssl req -in "${CN_VAL//./_}-backup.csr" -text -verify -noout | more; }
[ $DELCONF ] && rm -f "${CONF_FILE}"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment