|
|
@@ -0,0 +1,228 @@
|
|
|
+#!/bin/bash
|
|
|
+
|
|
|
+# Config
|
|
|
+CA_NAME="ca"
|
|
|
+DAYS=1825
|
|
|
+ROOT_POLICY="policy_root"
|
|
|
+ROOT_EXT="v3_ca"
|
|
|
+INTER_POLICY="policy_inter"
|
|
|
+INTER_EXT="v3_intermediate_ca"
|
|
|
+REQ_POLICY="policy_req"
|
|
|
+REQ_EXT="v3_req"
|
|
|
+
|
|
|
+# Support intermediate CAs
|
|
|
+INTER="${1}"
|
|
|
+if [ -n "${INTER}" ] && [ "${INTER}" != "@" ]; then
|
|
|
+ if [ ! -d "${INTER}" ]; then
|
|
|
+ echo "Intermediate CA directory does not exist: ${INTER}" 1>&2
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+ PREFIX="${INTER}/"
|
|
|
+else
|
|
|
+ INTER="@"
|
|
|
+ PREFIX=""
|
|
|
+fi
|
|
|
+
|
|
|
+# Calculate all our file paths
|
|
|
+CONF="openssl.conf"
|
|
|
+CA_CERT="${PREFIX}${CA_NAME}.pem"
|
|
|
+CERTS="${PREFIX}certs"
|
|
|
+KEYS="${PREFIX}keys"
|
|
|
+DB_DIR="${PREFIX}db"
|
|
|
+CRL="${DB_DIR}/crl/number"
|
|
|
+INDEX="${DB_DIR}/index.txt"
|
|
|
+SERIAL="${DB_DIR}/serial"
|
|
|
+
|
|
|
+# Export the CA directory for OpenSSL config path substitution
|
|
|
+export CA_DIR="${INTER}"
|
|
|
+
|
|
|
+# Decide what we're doing
|
|
|
+GEN_CA=1
|
|
|
+GEN_CERT=0
|
|
|
+if basename "${0}" | grep -q -i genCert; then
|
|
|
+ GEN_CA=0
|
|
|
+ GEN_CERT=1
|
|
|
+fi
|
|
|
+
|
|
|
+# If we're generating a normal certificate we need a name
|
|
|
+if [ $GEN_CERT -gt 0 ]; then
|
|
|
+ CN="${2}"
|
|
|
+ if [ -z "${CN}" ]; then
|
|
|
+ echo "Certificate name not specified" 1>&2
|
|
|
+ echo "Usage: ${0} INTERMEDIATE CERT" 1>&2
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+ CERT="${CERTS}/${CN}.pem"
|
|
|
+ KEY="${KEYS}/${CN}.key"
|
|
|
+fi
|
|
|
+
|
|
|
+# If we're generating a CA we know the name
|
|
|
+if [ $GEN_CA -gt 0 ]; then
|
|
|
+ CERT="${CA_CERT}"
|
|
|
+ KEY="${KEYS}/${CA_NAME}.key"
|
|
|
+ # If we're signing with the root override the CA_CERT path
|
|
|
+ CA_CERT="${CA_NAME}.pem"
|
|
|
+fi
|
|
|
+
|
|
|
+# Remind admins what is happening
|
|
|
+if [ $GEN_CA -gt 0 ]; then
|
|
|
+ echo
|
|
|
+ echo "Generating new CA at ${PWD}/${PREFIX}"
|
|
|
+ echo
|
|
|
+fi
|
|
|
+if [ $GEN_CERT -gt 0 ]; then
|
|
|
+ echo
|
|
|
+ echo "Generating certificate for ${CN} with ${INTER}"
|
|
|
+ echo
|
|
|
+fi
|
|
|
+
|
|
|
+# Ensure this operation will be safe
|
|
|
+if [ ! -r "${CONF}" ]; then
|
|
|
+ echo "Expected OpenSSL config: ${CONF}" 1>&2
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+if [ -e "${CERT}" ]; then
|
|
|
+ echo "Output certificate exists: ${CERT}" 1>&2
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+if [ -e "${KEY}" ]; then
|
|
|
+ echo "Output key exists: ${KEY}" 1>&2
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+if [ $GEN_CA -gt 0 ]; then
|
|
|
+ if [ -e "${SERIAL}" ] && [ "`cat "${SERIAL}"`" != "01" ]; then
|
|
|
+ echo "Serial file exists and is not 0x01: ${SERIAL}" 1>&2
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+ if [ -e "${CRL}" ] && [ "`cat "${CRL}"`" != "01" ]; then
|
|
|
+ echo "CRL number file exists and is not 0x01: ${CRL}" 1>&2
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+ if [ -e "${INDEX}" ] && [ -s "${INDEX}" ]; then
|
|
|
+ echo "Index file exists and is not empty: ${INDEX}" 1>&2
|
|
|
+ exit 1
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+function makeDirExist {
|
|
|
+ if [ -d "${1}" ] || [ "${1}" == "." ]; then
|
|
|
+ return
|
|
|
+ fi
|
|
|
+ mkdir "${1}"
|
|
|
+ if [ -n "${2}" ]; then
|
|
|
+ chmod "${2}" "${1}"
|
|
|
+ fi
|
|
|
+ if [ -n "${3}" ]; then
|
|
|
+ chown "${3}" "${1}"
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+# Ensure the CA paths are available and valid
|
|
|
+if [ $GEN_CA -gt 0 ]; then
|
|
|
+ makeDirExist "${CERTS}" '0755'
|
|
|
+ makeDirExist "${KEYS}" '0700'
|
|
|
+
|
|
|
+ # Setup the DB files
|
|
|
+ makeDirExist "${DB_DIR}" '0755'
|
|
|
+ echo "01" > "${SERIAL}"
|
|
|
+ touch "${INDEX}"
|
|
|
+
|
|
|
+ # And CRL for good measure
|
|
|
+ makeDirExist "`dirname "${CRL}"`" '0755'
|
|
|
+ echo "01" > "${CRL}"
|
|
|
+fi
|
|
|
+
|
|
|
+# Generate a new, encrypted key (user is prompted for password entry)
|
|
|
+openssl ecparam -name secp521r1 -genkey | openssl ec -aes256 -out "${KEY}"
|
|
|
+if [ ! -s "${KEY}" ]; then
|
|
|
+ echo "Unable to generate private key" 1>&2
|
|
|
+ exit 3
|
|
|
+fi
|
|
|
+
|
|
|
+# Generate and sign the certificate
|
|
|
+if [ -r "${CA_CERT}" ]; then
|
|
|
+ CSR="${CERT}.csr"
|
|
|
+ if [ -e "${CSR}" ]; then
|
|
|
+ "CSR exists: ${CSR}" 1>&2
|
|
|
+ exit 3
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Generate a CSR
|
|
|
+ openssl req -new \
|
|
|
+ -config "${CONF}" \
|
|
|
+ -key "${KEY}" \
|
|
|
+ -out "${CSR}"
|
|
|
+ if [ ! -r "${CSR}" ]; then
|
|
|
+ echo "Unable to generate CSR"
|
|
|
+ exit 3
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Remind admins what is happening
|
|
|
+ echo
|
|
|
+ echo "Signing ${CSR} with ${CA_CERT}"
|
|
|
+ echo -en "Request:\n\t"
|
|
|
+ openssl req -in "${CSR}" -text | grep 'Subject:'
|
|
|
+ echo -en "CA:\n\t"
|
|
|
+ openssl x509 -in "${CA_CERT}" -text | grep 'Subject:'
|
|
|
+ echo
|
|
|
+
|
|
|
+ # Sign with a CA
|
|
|
+ DIR="${CA_DIR}"
|
|
|
+ EXT="${REQ_EXT}"
|
|
|
+ POLICY="${REQ_POLICY}"
|
|
|
+ if [ "${INTER}" == "@" ] || [ $GEN_CA -gt 0 ]; then
|
|
|
+ DIR="."
|
|
|
+ EXT="${INTER_EXT}"
|
|
|
+ POLICY="${INTER_POLICY}"
|
|
|
+ fi
|
|
|
+ CA_DIR="${DIR}" openssl ca -notext \
|
|
|
+ -config "${CONF}" \
|
|
|
+ -policy "${POLICY}" \
|
|
|
+ -extensions "${EXT}" \
|
|
|
+ -days "${DAYS}" \
|
|
|
+ -in "${CERT}.csr" \
|
|
|
+ -out "${CERT}"
|
|
|
+
|
|
|
+ # Generate a chain certificate for validation
|
|
|
+ if [ $GEN_CA -gt 0 ] && [ -r "${CERT}" ]; then
|
|
|
+ cat "${CERT}" "${CA_CERT}" > "${INTER}/ca-chain.pem"
|
|
|
+ fi
|
|
|
+
|
|
|
+ # Drop the CSR
|
|
|
+ rm -f "${CERT}.csr"
|
|
|
+
|
|
|
+ # Generate keys ansible can decrypt
|
|
|
+ if [ "${INTER}" != "@" ] && [ $GEN_CA -le 0 ] && [ -s "${CERT}" ]; then
|
|
|
+ echo
|
|
|
+ echo "Encrypting ${KEY} for Ansible"
|
|
|
+ echo
|
|
|
+ ANSIBLE_KEY="`echo "${KEY}" | sed 's%.key$%.ansible%'`"
|
|
|
+ openssl ec -in "${KEY}" -out "${ANSIBLE_KEY}"
|
|
|
+ ansible-vault encrypt --encrypt-vault-id "${INTER}" "${ANSIBLE_KEY}"
|
|
|
+ if ! head -n 1 "${ANSIBLE_KEY}" | grep -q "^\$ANSIBLE_VAULT"; then
|
|
|
+ echo "Unable to generate ansible-encrypted key" 1>&2
|
|
|
+ rm -f "${ANSIBLE_KEY}"
|
|
|
+ fi
|
|
|
+ fi
|
|
|
+else
|
|
|
+ # Remind admins what is happening
|
|
|
+ echo
|
|
|
+ echo "Self-signing new root CA"
|
|
|
+ echo
|
|
|
+
|
|
|
+ # Root CA - self-sign
|
|
|
+ openssl req -new -x509 \
|
|
|
+ -config "${CONF}" \
|
|
|
+ -extensions "${ROOT_EXT}" \
|
|
|
+ -days "${DAYS}" \
|
|
|
+ -key "${KEY}" \
|
|
|
+ -out "${CERT}"
|
|
|
+fi
|
|
|
+if [ ! -s "${CERT}" ]; then
|
|
|
+ echo "Unable to generate certificate" 1>&2
|
|
|
+ rm -f "${KEY}"
|
|
|
+ if [ -n "${ANSIBLE_KEY}" ]; then
|
|
|
+ rm -f "${ANSIBLE_KEY}"
|
|
|
+ fi
|
|
|
+ exit 3
|
|
|
+fi
|