#!/bin/sh # # make-csr is a shell script designed to automatically generate a # certificate signing request (CSR) from an Apache or a Nginx vhost # # Author: Victor Laborie # Licence: AGPLv3 # set -u usage() { cat <&2 echo "${PROGNAME}: $1" fi } error() { >&2 echo "${PROGNAME}: $1" exit 1 } default_key_size() { grep default_bits "${SSL_CONFIG_FILE}" | cut -d'=' -f2 | xargs } sed_selfsigned_cert_path_for_apache() { local apache_ssl_vhost_path="$1" mkdir -p $(dirname "${apache_ssl_vhost_path}") if [ ! -f "${apache_ssl_vhost_path}" ]; then cat > "${apache_ssl_vhost_path}" < "${nginx_ssl_vhost_path}" < /dev/null } openssl_key(){ local key="$1" local key_dir=$(dirname "${key}") local size="$2" [ -w "${key_dir}" ] || error "Directory ${key_dir} is not writable" "${OPENSSL_BIN}" genrsa -out "${key}" "${size}" 2> /dev/null } openssl_csr_san() { local csr="$1" local csr_dir=$(dirname "${csr}") local key="$2" local cfg="$3" [ -w "${csr_dir}" ] || error "Directory ${csr_dir} is not writable" "${OPENSSL_BIN}" req -new -sha256 -key "${key}" -reqexts SAN -config "${cfg}" -out "${csr}" } openssl_csr_single() { local csr="$1" local csr_dir=$(dirname "${csr}") local key="$2" local cfg="$3" [ -w "${csr_dir}" ] || error "Directory ${csr_dir} is not writable" "${OPENSSL_BIN}" req -new -sha256 -key "${key}" -config "${cfg}" -out "${csr}" } make_key() { local key="$1" local size="$2" openssl_key "${key}" "${size}" debug "Private key stored at ${key}" chown root: "${key}" chmod 600 "${key}" } make_csr() { local domains=$@ local nb=$# local config_file="/tmp/make-csr-${VHOST}.conf" local san= mkdir -p -m 0755 "${CSR_DIR}" || error "Unable to mkdir ${CSR_DIR}" if [ "${nb}" -eq 1 ]; then cat "${SSL_CONFIG_FILE}" - > "${config_file}" < "${config_file}" <&2 echo "invalid arguments" >&2 usage exit 1 fi # read VHOST from first argument readonly VHOST="$1" # remove the first argument shift # read domains from remaining arguments readonly DOMAINS=$@ else # We don't have STDIN, so we should have only 1 argument if [ "$#" != 1 ]; then >&2 echo "invalid arguments" >&2 usage exit 1 fi # read VHOST from first argument readonly VHOST="$1" # read domains from input DOMAINS= while read -r line ; do DOMAINS="${DOMAINS} ${line}" done # trim the string to remove leading/trailing spaces DOMAINS=$(echo "${DOMAINS}" | xargs) fi [ -w "${CSR_DIR}" ] || error "Directory ${CSR_DIR} is not writable" [ -w "${SELF_SIGNED_DIR}" ] || error "Directory ${SELF_SIGNED_DIR} is not writable" [ -w "${SSL_KEY_DIR}" ] || error "Directory ${SSL_KEY_DIR} is not writable" [ -r "${SSL_CONFIG_FILE}" ] || error "File ${SSL_CONFIG_FILE} is not readable" # check for important programs readonly OPENSSL_BIN=$(command -v openssl) || error "openssl command not installed" SELF_SIGNED_FILE="${SELF_SIGNED_DIR}/${VHOST}.pem" SSL_KEY_FILE="${SSL_KEY_DIR}/${VHOST}.key" CSR_FILE="${CSR_DIR}/${VHOST}.csr" make_key "${SSL_KEY_FILE}" "${SSL_KEY_SIZE}" make_csr ${DOMAINS} command -v apache2ctl >/dev/null && sed_selfsigned_cert_path_for_apache "/etc/apache2/ssl/${VHOST}.conf" command -v nginx >/dev/null && sed_selfsigned_cert_path_for_nginx "/etc/nginx/ssl/${VHOST}.conf" } readonly PROGNAME=$(basename "$0") readonly PROGDIR=$(readlink -m $(dirname "$0")) readonly ARGS=$@ readonly VERBOSE=${VERBOSE:-"0"} # Read configuration file, if it exists [ -r /etc/default/evoacme ] && . /etc/default/evoacme # Default value for main variables CSR_DIR=${CSR_DIR:-'/etc/ssl/requests'} SSL_CONFIG_FILE=${SSL_CONFIG_FILE:-"${CRT_DIR}/openssl.cnf"} SELF_SIGNED_DIR=${SELF_SIGNED_DIR:-'/etc/ssl/self-signed'} SSL_KEY_DIR=${SSL_KEY_DIR:-'/etc/ssl/private'} SSL_KEY_SIZE=${SSL_KEY_SIZE:-$(default_key_size)} main ${ARGS}