#!/bin/ash
|
|
# ---------------------------------------------------------------------------
|
|
# getsslD - Obtain SSL certificates from the letsencrypt.org ACME server.
|
|
# Runs in a Docker conatainer.
|
|
# Based on the work of getssl by srvrco https://github.com/srvrco/getssl
|
|
# and acme.sh by Neil Pang http://Neilpang/acme.sh
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License at <http://www.gnu.org/licenses/> for
|
|
# more details.
|
|
|
|
PROGNAME=getsslD
|
|
VERSION="0.2"
|
|
|
|
# Default values, accepts environment variables if set, otherwise default are used
|
|
WORKING_DIR=${WORKING_DIR:="/ssl}"
|
|
ACCOUNT_KEY_LOCATION=${ACCOUNT_KEY_LOCATION:="$WORKING_DIR/account.key"}
|
|
ACCOUNT_KEY_LENGTH=${ACCOUNT_KEY_LENGTH:="4096"}
|
|
ACCOUNT_KEY_TYPE=${ACCOUNT_KEY_TYPE:="rsa"}
|
|
|
|
|
|
|
|
#####
|
|
# Functions
|
|
#####
|
|
|
|
|
|
create_key() {
|
|
# Create an openSSL key
|
|
|
|
local key_loc=${1}
|
|
local key_len=${2}
|
|
local key_type=${3}
|
|
local valid_key_type
|
|
|
|
# Check for existing key
|
|
if [[ -s "${key_loc}" ]]; then
|
|
printf 'Key exists at %s skipping generation.\n' "${key_loc}"
|
|
return 0
|
|
elif [[ ! -d $(dirname "${key_loc}") ]]; then
|
|
print_error "Directory for storing ${key_loc} does not exist."
|
|
return 1
|
|
else
|
|
printf 'Creating %s bit %s account key in %s...' "${key_len}" "${key_type}" "${key_loc}"
|
|
fi
|
|
|
|
# Determine key type by length
|
|
# Valid Let's Encrypt RSA key lengths 2048-8192
|
|
# Valid Let's Encrypt ECC key lengths 256, 384, 521
|
|
|
|
if [[ "${key_len}" -ge 2048 ]] && [[ "${key_len}" -le 8192 ]] && [[ "${key_type}" == "rsa" ]]; then
|
|
valid_key_type="RSA"
|
|
fi
|
|
|
|
if [[ "${key_type}" == "ecc" ]]; then
|
|
if [[ "${key_len}" -eq 256 ]] ; then
|
|
valid_key_type="prime256v1"
|
|
elif [[ "${key_len}" -eq 384 ]]; then
|
|
valid_key_type="secp384r1"
|
|
elif [[ "${key_len}" -eq 521 ]]; then
|
|
valid_key_type="secp521r1"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z ${valid_key_type+x} ]]; then
|
|
print_error "Invalid key length. Please check your configuration."
|
|
return 1
|
|
fi
|
|
|
|
case "$valid_key_type" in
|
|
RSA)
|
|
openssl genrsa -out "${key_loc}" "${key_len}" >& /dev/null
|
|
printf '%s\n' "Done."
|
|
return 0
|
|
;;
|
|
prime256v1|secp384r1|secp521r1)
|
|
openssl ecparam -genkey -out "${key_loc}" -name "${valid_key_type}" >& /dev/null
|
|
printf '%s\n' "Done."
|
|
return 0
|
|
;;
|
|
esac
|
|
|
|
# Error inside case statement openssl generation
|
|
print_error "Error creating OpenSSL key, deleting key..."
|
|
rm "${key_loc}"
|
|
print_error "Done.\n"
|
|
return 1
|
|
}
|
|
|
|
get_date() {
|
|
# get current date and time in UTC YYYY-MM-DDTHH:MM:SSZ
|
|
echo $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
}
|
|
|
|
help_message_top() {
|
|
# Print help message
|
|
|
|
cat <<- _EOF_
|
|
Usage: "${PROGNAME}" [option] [COMMAND] [ARGS...]
|
|
Obtain SSL certificates from the letsencrypt.org ACME server.
|
|
|
|
Commands:
|
|
account Create or modify Lets Encrypt account.
|
|
|
|
Options to long options apply to short options also.
|
|
Options:
|
|
-r, --rsa Use RSA algorith for key generation
|
|
-e, --ecc Use elliptic curve algorithm for key or cert generation
|
|
|
|
_EOF_
|
|
return 0
|
|
}
|
|
|
|
prep_workdir() {
|
|
# Prepare working directory for key/cert functions
|
|
|
|
if [[ ! -d "${WORKING_DIR}" ]]; then
|
|
printf '%s' "Creating getsslD certificate storage directory - ${WORKING_DIR}..."
|
|
if ! mkdir -p "${WORKING_DIR}" >& /dev/null; then
|
|
print_error "Could not create ${WORKING_DIR}. Check volumes.\n"
|
|
exit 1
|
|
else
|
|
printf '%s\n' "Done."
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
print_error() {
|
|
# Output error messages to STDERR
|
|
local error=$1
|
|
|
|
printf '!! %s\n' "${1}" 1>&2
|
|
return 0
|
|
}
|
|
|
|
arg_parser() {
|
|
# Check CLI arguments and process
|
|
local key_type
|
|
local key_length
|
|
|
|
while [[ -n ${1} ]]; do
|
|
case ${1} in
|
|
-r | --rsa)
|
|
shift
|
|
key_type="rsa"
|
|
;;
|
|
-e | --ecc)
|
|
shift
|
|
key_type="ecc"
|
|
;;
|
|
-h | --help)
|
|
help_message_top
|
|
exit 0
|
|
;;
|
|
-v | --version)
|
|
printf '%s version %s\n' ${PROGNAME} ${VERSION}
|
|
exit 0
|
|
;;
|
|
account)
|
|
# Remove account command
|
|
shift
|
|
case $1 in
|
|
key)
|
|
# Remove key subcommand
|
|
shift
|
|
# If no key type specified on the command line
|
|
# https://stackoverflow.com/a/13864829
|
|
if [[ -z "${key_type+x}" ]]; then
|
|
# No key types specified use default of RSA or environment variable
|
|
key_type="${ACCOUNT_KEY_TYPE:=rsa}"
|
|
printf 'No key type specified, using default of %s\n' "${key_type}"
|
|
fi
|
|
# We have a key type need length
|
|
# If no key length specified on the command line
|
|
if [[ -z "${1}" ]]; then
|
|
# No length specified, use default of 4096 or environment variable
|
|
key_length="${ACCOUNT_KEY_LENGTH:=4096}"
|
|
printf 'No key length specified, using default of %s\n' "${key_length}"
|
|
else
|
|
key_length="${1}"
|
|
fi
|
|
|
|
create_key "${ACCOUNT_KEY_LOCATION}" "${key_length}" "${key_type}"
|
|
exit 0
|
|
;;
|
|
esac # End account subcommands
|
|
;;
|
|
*)
|
|
printf 'Invalid command\n\n'
|
|
help_message_top
|
|
exit 1
|
|
;;
|
|
esac # End options
|
|
done
|
|
}
|
|
|
|
#####
|
|
# Main logic
|
|
#####
|
|
|
|
main() {
|
|
|
|
# read any variables from config in working directory
|
|
if [[ -s "$WORKING_DIR/getsslD.cfg" ]]; then
|
|
printf '%s\n'"Reading config from from $WORKING_DIR/getsslD.cfg"
|
|
. "$WORKING_DIR/getsslD.cfg"
|
|
fi
|
|
|
|
arg_parser $*
|
|
|
|
}
|
|
|
|
# Only run main if we are not testing.
|
|
if [[ "${GETSSLD_TEST}" != true ]]; then
|
|
main $@
|
|
fi
|