#!/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 for # more details. # shellcheck disable=SC2140,SC2169 # shellcheck shell=dash PROGNAME=getsslD VERSION="0.2 commit 9444e69" # 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" 1>&2 return 0 elif [[ ! -d $(dirname "$key_loc") ]]; then printf 'Directory for storing %s does not exist.' "$key_loc" 1>&2 return 1 fi # Determine key type by length # Valid Lets Encrypt RSA key lengths 2048-8192 # Valid Lets 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 printf 'Invalid key length. Please check your configuration.' 1>&2 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 printf 'Error creating OpenSSL key, deleting key...' 1>&2 rm "$key_loc" printf 'Done.\n' 1>&2 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() { cat <<- _EOL_ 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: -v, --version Display $PROGNAME version information. _EOL_ return 0 } help_message_account() { cat <<- _EOL_ Usage: $PROGNAME account [COMMAND] [ARGS...] Manage Lets Encrypt account Commands: key Manage Lets Encrypt account key. _EOL_ return 0 } prep_workdir() { ## DAN FIX THIS # 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 printf '!! Could not create %s. Check volumes.' "$WORKING_DIR" 1>&2 exit 1 else printf '%s\n' "Done." fi fi return 0 } read_config() { # read any variables from config in working directory if [[ -s "$WORKING_DIR/getsslD.cfg" ]]; then printf 'Reading config from from %s/getsslD.cfg\n' "$WORKING_DIR" # shellcheck source=/dev/null . "$WORKING_DIR/getsslD.cfg" else printf '!! Unable to find %s/getsslD.cfg. Please generate or mount directory with file location.' "$WORKING_DIR" 1>&2 exit 1 fi } arg_parser() { # Check CLI arguments and process local key_type local key_length while [[ ! -z "${1+x}" ]]; do case $1 in -h | --help | "") help_message_top exit 0 ;; account) shift read_config prep_workdir case "$1" in # account subcommand -h | --help | "") help_message_account exit 0 ;; key) shift case "$1" in # key subcommand -h | --help | "") help_message_account_key exit 0 ;; create) shift case "$1" in # create subcommand -h | --help | "") help_message_account_key_create exit 0 ;; r | rsa) shift key_type="rsa" key_length="$1" printf 'Creating %s bit RSA account key...' "$key_length" create_key "$ACCOUNT_KEY_LOCATION" "$key_length" "$key_type" shift ;; e | ecc) shift key_type="ecc" key_length="$1" printf 'Creating %s bit ECC account key...' "$key_length" create_key "ACCOUNT_KEY_LOCATION" "$key_length" "$key_type" shift ;; *) printf 'Invalid command\n\n' help_message_account_key_create exit 1 ;; esac # End create subcommand ;; *) printf 'Invalid command\n\n' help_message_account_key exit 1 ;; esac # End key subcommands ;; *) printf 'Invalid command\n\n' help_message_account exit 1 ;; esac # End account subcommands ;; *) printf 'Invalid command\n\n' help_message_top exit 1 ;; esac # End main program done } ##### # Main logic ##### main() { if [[ "$1" == "-v" ]] || [[ "$1" == "--version" ]]; then printf '%s v%s\n' "$PROGNAME" "$VERSION" exit 0 fi if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "" ]]; then help_message_top exit 0 fi printf '%s' $get_date arg_parser "$@" } # Only run main if we are not testing. if [[ "$GETSSLD_TEST" != true ]]; then main "$@" fi