Browse Source

Merge branch 'master' into msldaps

pull/457/head
Yannic Haupenthal 6 years ago
parent
commit
87f428d9b0
No known key found for this signature in database GPG Key ID: 30BEEF01A79FDDD7
12 changed files with 553 additions and 60 deletions
  1. +7
    -0
      dns_scripts/dns_add_challtestsrv
  2. +6
    -0
      dns_scripts/dns_del_challtestsrv
  3. +43
    -0
      docker-compose.yml
  4. +97
    -60
      getssl
  5. +22
    -0
      test/Dockerfile-rhel6
  6. +23
    -0
      test/Dockerfile-ubuntu
  7. +20
    -0
      test/README.md
  8. +43
    -0
      test/run-test.sh
  9. +54
    -0
      test/test-config/getssl-dns01.cfg
  10. +53
    -0
      test/test-config/getssl-http01.cfg
  11. +93
    -0
      test/test-config/nginx-ubuntu-no-ssl
  12. +92
    -0
      test/test-config/nginx-ubuntu-ssl

+ 7
- 0
dns_scripts/dns_add_challtestsrv View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Simple script to update the challtestserv mock DNS server when testing DNS responses
fulldomain="${1}"
token="${2}"
curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt

+ 6
- 0
dns_scripts/dns_del_challtestsrv View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Simple script to update the challtestserv mock DNS server when testing DNS responses
fulldomain="${1}"
curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\"}" http://10.30.50.3:8055/clear-txt

+ 43
- 0
docker-compose.yml View File

@ -0,0 +1,43 @@
version: '3'
services:
pebble:
image: letsencrypt/pebble:latest
# TODO enable -strict
command: pebble -config /test/config/pebble-config.json -dnsserver 10.30.50.3:8053
environment:
# with Go 1.13.x which defaults TLS 1.3 to on
GODEBUG: "tls13=1"
# don't reuse authorizations (breaks testing force renew)
PEBBLE_AUTHZREUSE: 0
ports:
- 14000:14000 # HTTPS ACME API
- 15000:15000 # HTTPS Management API
networks:
acmenet:
ipv4_address: 10.30.50.2
challtestsrv:
image: letsencrypt/pebble-challtestsrv:latest
command: pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 10.30.50.3
ports:
- 8055:8055 # HTTP Management API
networks:
acmenet:
ipv4_address: 10.30.50.3
getssl:
build:
context: .
dockerfile: test/Dockerfile-ubuntu
container_name: getssl
volumes:
- .:/getssl
networks:
acmenet:
ipv4_address: 10.30.50.4
networks:
acmenet:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.30.50.0/24

+ 97
- 60
getssl View File

@ -189,10 +189,18 @@
# 2019-10-02 issue #425 Case insensitive processing of agreement url because of HTTP/2 (2.12)
# 2019-10-07 update DNS checks to allow use of CNAMEs (2.13)
# 2019-11-18 Rebased master onto APIv2 and added Content-Type: application/jose+json (2.14)
# 2019-11-20 #453 and #454 Add User-Agent to all curl requests
# 2019-11-22 #456 Fix shellcheck issues
# 2019-11-23 #459 Fix missing chain.crt
# 2019-12-18 #462 Use POST-as-GET for ACMEv2 endpoints
# 2020-01-07 #464 and #486 "json was blank" (change all curl request to use POST-as-GET)
# 2020-01-08 Error and exit if rate limited, exit if curl returns nothing
# 2020-01-10 Change domain and getssl templates to v2 (2.15)
# 2020-01-17 #473 and #477 Don't use POST-as-GET when sending ready for challenge for ACMEv1 (2.16)
# ----------------------------------------------------------------------------------------
PROGNAME=${0##*/}
VERSION="2.14"
VERSION="2.16"
# defaults
ACCOUNT_KEY_LENGTH=4096
@ -207,7 +215,7 @@ CODE_LOCATION="https://raw.githubusercontent.com/srvrco/getssl/master/getssl"
CSR_SUBJECT="/"
CURL_USERAGENT="${PROGNAME}/${VERSION}"
DEACTIVATE_AUTH="false"
DEFAULT_REVOKE_CA="https://acme-v01.api.letsencrypt.org"
DEFAULT_REVOKE_CA="https://acme-v02.api.letsencrypt.org"
DNS_EXTRA_WAIT=""
DNS_WAIT=10
DOMAIN_KEY_LENGTH=4096
@ -280,24 +288,30 @@ check_challenge_completion() { # checks with the ACME server if our challenge is
keyauthorization=$3
debug "sending request to ACME server saying we're ready for challenge"
send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"
# check response from our request to perform challenge
if [[ $API -eq 1 ]]; then
if [[ ! -z "$code" ]] && [[ ! "$code" == '202' ]] ; then
send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"
if [[ -n "$code" ]] && [[ ! "$code" == '202' ]] ; then
error_exit "$domain:Challenge error: $code"
fi
else # APIv2
if [[ ! -z "$code" ]] && [[ ! "$code" == '200' ]] ; then
error_exit "$domain:Challenge error: $code"
send_signed_request "$uri" "{}"
if [[ -n "$code" ]] && [[ ! "$code" == '200' ]] ; then
detail=$(echo "$response" | grep "detail" | awk -F\" '{print $4}')
error_exit "$domain:Challenge error: $code:Detail: $detail"
fi
fi
# loop "forever" to keep checking for a response from the ACME server.
while true ; do
debug "checking"
if ! get_cr "$uri" ; then
error_exit "$domain:Verify error:$code"
debug "checking if challenge is complete"
if [[ $API -eq 1 ]]; then
if ! get_cr "$uri" ; then
error_exit "$domain:Verify error:$code"
fi
else # APIv2
send_signed_request "$uri" ""
fi
status=$(json_get "$response" status)
@ -469,12 +483,13 @@ check_getssl_upgrade() { # check if a more recent version of code is available a
# Obtain all locally stored old versions in getssl_versions
declare -a getssl_versions
shopt -s nullglob
for getssl_version in $0.v*; do
for getssl_version in "$0".v*; do
getssl_versions[${#getssl_versions[@]}]="$getssl_version"
done
shopt -u nullglob
# Explicitly sort the getssl_versions array to make sure
shopt -s -o noglob
# shellcheck disable=SC2207
IFS=$'\n' getssl_versions=($(sort <<< "${getssl_versions[*]}"))
shopt -u -o noglob
# Remove entries until given number of old versions to keep is reached
@ -500,7 +515,7 @@ clean_up() { # Perform pre-exit housekeeping
if [[ $VALIDATE_VIA_DNS == "true" ]]; then
# Tidy up DNS entries if things failed part way though.
shopt -s nullglob
for dnsfile in $TEMP_DIR/dns_verify/*; do
for dnsfile in "$TEMP_DIR"/dns_verify/*; do
# shellcheck source=/dev/null
. "$dnsfile"
debug "attempting to clean up DNS entry for $d"
@ -508,10 +523,10 @@ clean_up() { # Perform pre-exit housekeeping
done
shopt -u nullglob
fi
if [[ ! -z "$DOMAIN_DIR" ]]; then
if [[ -n "$DOMAIN_DIR" ]]; then
rm -rf "${TEMP_DIR:?}"
fi
if [[ ! -z "$TEMP_UPGRADE_FILE" ]] && [[ -f "$TEMP_UPGRADE_FILE" ]]; then
if [[ -n "$TEMP_UPGRADE_FILE" ]] && [[ -f "$TEMP_UPGRADE_FILE" ]]; then
rm -f "$TEMP_UPGRADE_FILE"
fi
}
@ -531,7 +546,7 @@ copy_file_to_location() { # copies a file, using scp, sftp or ftp if required.
scp $from ${to:4}"
fi
debug "userid $TOKEN_USER_ID"
if [[ "$cert" == "challenge token" ]] && [[ ! -z "$TOKEN_USER_ID" ]]; then
if [[ "$cert" == "challenge token" ]] && [[ -n "$TOKEN_USER_ID" ]]; then
servername=$(echo "$to" | awk -F":" '{print $2}')
tofile=$(echo "$to" | awk -F":" '{print $3}')
debug "servername $servername"
@ -592,7 +607,7 @@ copy_file_to_location() { # copies a file, using scp, sftp or ftp if required.
error_exit "cannot copy $from to $to"
fi
fi
if [[ "$cert" == "challenge token" ]] && [[ ! -z "$TOKEN_USER_ID" ]]; then
if [[ "$cert" == "challenge token" ]] && [[ -n "$TOKEN_USER_ID" ]]; then
chown "$TOKEN_USER_ID" "$to"
fi
fi
@ -742,7 +757,7 @@ get_auth_dns() { # get the authoritative dns server for a domain (sets primary_n
else
res=$($DNS_CHECK_FUNC CNAME "$gad_d" "@$gad_s"| grep "^$gad_d")
fi
if [[ ! -z "$res" ]]; then # domain is a CNAME so get main domain
if [[ -n "$res" ]]; then # domain is a CNAME so get main domain
gad_d=$(echo "$res"| awk '{print $5}' |sed 's/\.$//g')
fi
if [[ -z "$gad_s" ]]; then #checking for CNAMEs
@ -858,10 +873,12 @@ get_certificate() { # get certificate for csr, if all domains validated.
else # APIv2
send_signed_request "$FinalizeLink" "{\"csr\": \"$der\"}" "needbase64"
debug "order link was $OrderLink"
cd=$(curl --user-agent "$CURL_USERAGENT" --silent "$OrderLink")
CertData=$(json_get "$cd" "certificate")
send_signed_request "$OrderLink" ""
CertData=$(json_get "$response" "certificate")
debug "CertData is at $CertData"
curl --user-agent "$CURL_USERAGENT" --silent "$CertData" > "$CERT_FILE"
send_signed_request "$CertData" "" "" "$FULL_CHAIN"
info "Full certificate saved in $FULL_CHAIN"
awk -v CERT_FILE="$CERT_FILE" -v CA_CERT="$CA_CERT" 'BEGIN {outfile=CERT_FILE} split_after==1 {outfile=CA_CERT;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > outfile}' "$FULL_CHAIN"
info "Certificate saved in $CERT_FILE"
fi
}
@ -1158,7 +1175,7 @@ json_get() { # get values from json
# remove newlines, so it's a single chunk of JSON
json_data=$( echo "$1" | tr '\n' ' ')
# if $3 is defined, this is the section which the item is in.
if [[ ! -z "$3" ]]; then
if [[ -n "$3" ]]; then
jg_section=$(echo "$json_data" | awk -F"[}]" '{for(i=1;i<=NF;i++){if($i~/\"'"${3}"'\"/){print $i}}}')
if [[ "$2" == "uri" ]]; then
jg_subsect=$(echo "$jg_section" | awk -F"[,]" '{for(i=1;i<=NF;i++){if($i~/\"'"${2}"'\"/){print $(i)}}}')
@ -1178,17 +1195,17 @@ json_get() { # get values from json
echo "$jg_result"
fi
else
if [[ ! -z "$6" ]]; then
if [[ -n "$6" ]]; then
full=$(json_awk "$1")
section=$(echo "$full" | grep "\"$2\"" | grep "\"$3\"" | grep "\"$4\"" | awk -F"," '{print $2}')
echo "$full" | grep "^..${5}\",$section" | awk '{print $2}' | tr -d '"'
elif [[ ! -z "$5" ]]; then
elif [[ -n "$5" ]]; then
full=$(json_awk "$1")
section=$(echo "$full" | grep "\"$2\"" | grep "\"$3\"" | grep "\"$4\"" | awk -F"," '{print $2}')
echo "$full" | grep "^..${2}\",$section" | grep "$5" | awk '{print $2}' | tr -d '"'
elif [[ ! -z "$3" ]]; then
elif [[ -n "$3" ]]; then
json_awk "$1" | grep "^..${2}...${3}" | awk '{print $2}' | tr -d '"'
elif [[ ! -z "$2" ]]; then
elif [[ -n "$2" ]]; then
json_awk "$1" | grep "^..${2}" | awk '{print $2}' | tr -d '"'
else
json_awk "$1"
@ -1209,7 +1226,7 @@ os_esed() { # Use different sed version for different os types (extended regex)
purge_archive() { # purge archive of old, invalid, certificates
arcdir="$1/archive"
debug "purging archives in ${arcdir}/"
for padir in $arcdir/????_??_??_??_??; do
for padir in "$arcdir"/????_??_??_??_??; do
# check each directory
if [[ -d "$padir" ]]; then
tstamp=$(basename "$padir"| awk -F"_" '{print $1"-"$2"-"$3" "$4":"$5}')
@ -1232,7 +1249,7 @@ purge_archive() { # purge archive of old, invalid, certificates
}
reload_service() { # Runs a command to reload services ( via ssh if needed)
if [[ ! -z "$RELOAD_CMD" ]]; then
if [[ -n "$RELOAD_CMD" ]]; then
info "reloading SSL services"
if [[ "${RELOAD_CMD:0:4}" == "ssh:" ]] ; then
sshhost=$(echo "$RELOAD_CMD"| awk -F: '{print $2}')
@ -1276,16 +1293,16 @@ requires() { # check if required function is available
if [[ "$i" == "${!#}" ]]; then # if on last variable then exit as not found
error_exit "this script requires one of: ${*:1:$(($#-1))}"
fi
res=$(which "$i" 2>/dev/null)
res=$(command -v "$i" 2>/dev/null)
debug "checking for $i ... $res"
if [[ ! -z "$res" ]]; then # if function found, then set variable to function and return
if [[ -n "$res" ]]; then # if function found, then set variable to function and return
debug "function $i found at $res - setting ${!#} to $i"
eval "${!#}=\$i"
return
fi
done
else # only one value, so check it.
result=$(which "$1" 2>/dev/null)
result=$(command -v "$1" 2>/dev/null)
debug "checking for required $1 ... $result"
if [[ -z "$result" ]]; then
error_exit "This script requires $1 installed"
@ -1338,6 +1355,7 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
url=$1
payload=$2
needbase64=$3
outfile=$4 # save response into this file (certificate data)
debug url "$url"
@ -1345,6 +1363,7 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
dp="$TEMP_DIR/curl.dump"
CURL="curl "
# shellcheck disable=SC2072
if [[ "$($CURL -V | head -1 | cut -d' ' -f2 )" > "7.33" ]]; then
CURL="$CURL --http1.1 "
fi
@ -1376,8 +1395,8 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
# Build another header which also contains the previously received nonce and encode it as urlbase64
if [[ $API -eq 1 ]]; then
protected='{"alg": "'"$jwkalg"'", "jwk": '"$jwk"', "nonce": "'"${nonce}"'", "url": "'"${url}"'"}'
protected64="$(printf '%s' "${protected}" | urlbase64)"
protected='{"alg": "'"$jwkalg"'", "jwk": '"$jwk"', "nonce": "'"${nonce}"'", "url": "'"${url}"'"}'
protected64="$(printf '%s' "${protected}" | urlbase64)"
else # APIv2
if [[ -z "$KID" ]]; then
debug "KID is blank, so using jwk"
@ -1386,7 +1405,6 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
else
debug "using KID=${KID}"
protected="{\"alg\": \"$jwkalg\", \"kid\": \"$KID\",\"nonce\": \"${nonce}\", \"url\": \"${url}\"}"
debug "protected = $protected"
protected64="$(printf '%s' "${protected}" | urlbase64)"
fi
fi
@ -1417,13 +1435,25 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
code="500"
loop_limit=5
while [[ "$code" -eq 500 ]]; do
if [[ "$needbase64" ]] ; then
if [[ "$outfile" ]] ; then
$CURL -X POST -H "Content-Type: application/jose+json" --data "$body" "$url" > "$outfile"
response=$(cat "$outfile")
elif [[ "$needbase64" ]] ; then
response=$($CURL -X POST -H "Content-Type: application/jose+json" --data "$body" "$url" | urlbase64)
else
response=$($CURL -X POST -H "Content-Type: application/jose+json" --data "$body" "$url")
fi
if [[ "$response" == "" ]]; then
error_exit "ERROR curl \"$url\" returned nothing"
fi
responseHeaders=$(cat "$CURL_HEADER")
if [[ "$needbase64" && ${response##*()} != "{"* ]]; then
# response is in base64 too, decode
response=$(echo "$response" | base64 -d 2>&1)
fi
debug responseHeaders "$responseHeaders"
debug response "$response"
code=$(awk ' $1 ~ "^HTTP" {print $2}' "$CURL_HEADER" | tail -1)
@ -1432,7 +1462,9 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
response_status=$(json_get "$response" status \
| head -1| awk -F'"' '{print $2}')
else # APIv2
if [[ ${response##*()} == "{"* ]]; then
if [[ "$outfile" && "$response" ]]; then
debug "response written to $outfile"
elif [[ ${response##*()} == "{"* ]]; then
response_status=$(json_get "$response" status)
else
debug "response not in json format"
@ -1449,6 +1481,9 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p
error_exit "500 error from ACME server: $response"
fi
fi
if [[ "$code" -eq 429 ]]; then
error_exit "429 rate limited error from ACME server"
fi
done
if [[ $response == *"error:badNonce"* ]]; then
debug "bad nonce"
@ -1546,7 +1581,7 @@ write_domain_template() { # write out a template file for a domain.
# The staging server is best for testing
#CA="https://acme-staging-v02.api.letsencrypt.org/directory"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
#CA="https://acme-v02.api.letsencrypt.org"
#PRIVATE_KEY_ALG="rsa"
@ -1599,7 +1634,7 @@ write_getssl_template() { # write out the main template file
# The staging server is best for testing (hence set as default)
CA="https://acme-staging-v02.api.letsencrypt.org/directory"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
#CA="https://acme-v02.api.letsencrypt.org"
#AGREEMENT="$AGREEMENT"
@ -1678,11 +1713,11 @@ while [[ -n ${1+defined} ]]; do
_UPGRADE_CHECK=0 ;;
-w)
shift; WORKING_DIR="$1" ;;
-* | --*)
-*)
usage
error_exit "Unknown option $1" ;;
*)
if [[ ! -z $DOMAIN ]]; then
if [[ -n $DOMAIN ]]; then
error_exit "invalid command line $DOMAIN - it appears to contain more than one domain"
fi
DOMAIN="$1"
@ -1765,6 +1800,7 @@ ACCOUNT_KEY="${ACCOUNT_KEY:=$WORKING_DIR/account.key}"
DOMAIN_STORAGE="${DOMAIN_STORAGE:=$WORKING_DIR}"
DOMAIN_DIR="$DOMAIN_STORAGE/$DOMAIN"
CERT_FILE="$DOMAIN_DIR/${DOMAIN}.crt"
FULL_CHAIN="$DOMAIN_DIR/fullchain.crt"
CA_CERT="$DOMAIN_DIR/chain.crt"
TEMP_DIR="$DOMAIN_DIR/tmp"
if [[ "$os" == "mingw" ]]; then
@ -1790,7 +1826,7 @@ if [[ ${_CHECK_ALL} -eq 1 ]]; then
error_exit "DOMAIN_STORAGE not found - $DOMAIN_STORAGE"
fi
for dir in ${DOMAIN_STORAGE}/*; do
for dir in "${DOMAIN_STORAGE}"/*; do
if [[ -d "$dir" ]]; then
debug "Checking $dir"
cmd="$0 -U" # No update checks when calling recursively
@ -1838,7 +1874,7 @@ if [[ ${_CREATE_CONFIG} -eq 1 ]]; then
| openssl s_client -servername "${DOMAIN}" -connect "${DOMAIN}:443" 2>/dev/null \
| openssl x509 2>/dev/null)
EX_SANS="www.${DOMAIN}"
if [[ ! -z "${EX_CERT}" ]]; then
if [[ -n "${EX_CERT}" ]]; then
EX_SANS=$(echo "$EX_CERT" \
| openssl x509 -noout -text 2>/dev/null| grep "Subject Alternative Name" -A2 \
| grep -Eo "DNS:[a-zA-Z 0-9.-]*" | sed "s@DNS:$DOMAIN@@g" | grep -v '^$' | cut -c 5-)
@ -1908,14 +1944,15 @@ if [[ -z "$URL_new_reg" ]] && [[ -z "$URL_newAccount" ]]; then
URL_newOrder=$(echo "$ca_all_loc" | grep "newOrder" | awk -F'"' '{print $4}')
fi
if [[ ! -z "$URL_new_reg" ]]; then
if [[ -n "$URL_new_reg" ]]; then
API=1
elif [[ ! -z "$URL_newAccount" ]]; then
elif [[ -n "$URL_newAccount" ]]; then
API=2
else
info "unknown API version"
graceful_exit
fi
debug "Using API v$API"
# if check_remote is true then connect and obtain the current certificate (if not forcing renewal)
if [[ "${CHECK_REMOTE}" == "true" ]] && [[ $_FORCE_RENEW -eq 0 ]]; then
@ -1924,7 +1961,7 @@ if [[ "${CHECK_REMOTE}" == "true" ]] && [[ $_FORCE_RENEW -eq 0 ]]; then
EX_CERT=$(echo \
| openssl s_client -servername "${DOMAIN}" -connect "${DOMAIN}:${REMOTE_PORT}" ${REMOTE_EXTRA} 2>/dev/null \
| openssl x509 2>/dev/null)
if [[ ! -z "$EX_CERT" ]]; then # if obtained a cert
if [[ -n "$EX_CERT" ]]; then # if obtained a cert
if [[ -s "$CERT_FILE" ]]; then # if local exists
CERT_LOCAL=$(openssl x509 -noout -fingerprint < "$CERT_FILE" 2>/dev/null)
else # since local doesn't exist leave empty so that the domain validation will happen
@ -1999,7 +2036,7 @@ if [[ -s "$CERT_FILE" ]]; then
enddate_s=$(date_epoc "$enddate")
if [[ $(date_renew) -lt "$enddate_s" ]] && [[ $_FORCE_RENEW -ne 1 ]]; then
issuer=$(openssl x509 -in "$CERT_FILE" -noout -issuer 2>/dev/null)
if [[ "$issuer" == *"Fake LE Intermediate"* ]] && [[ "$CA" == "https://acme-v01.api.letsencrypt.org" ]]; then
if [[ "$issuer" == *"Fake LE Intermediate"* ]] && [[ "$CA" == "https://acme-v02.api.letsencrypt.org" ]]; then
debug "upgrading from fake cert to real"
else
info "${DOMAIN}: certificate is valid for more than $RENEW_ALLOW days (until $enddate)"
@ -2121,7 +2158,7 @@ if [[ $API -eq 2 ]]; then
for d in $alldomains; do
dstring="${dstring}{\"type\":\"dns\",\"value\":\"$d\"},"
done
dstring="${dstring: : -1}]"
dstring="${dstring::${#dstring}-1}]"
# request NewOrder currently seems to ignore the dates ....
# dstring="${dstring},\"notBefore\": \"$(date -d "-1 hour" --utc +%FT%TZ)\""
# dstring="${dstring},\"notAfter\": \"$(date -d "2 days" --utc +%FT%TZ)\""
@ -2157,7 +2194,7 @@ for d in $alldomains; do
debug "completed send_signed_request"
# check if we got a valid response and token, if not then error exit
if [[ ! -z "$code" ]] && [[ ! "$code" == '201' ]] ; then
if [[ -n "$code" ]] && [[ ! "$code" == '201' ]] ; then
error_exit "new-authz error: $response"
fi
else
@ -2186,7 +2223,7 @@ for d in $alldomains; do
uri=$(json_get "$response" "uri" "dns-01")
debug uri "$uri"
else # APIv2
response=$(curl --user-agent "$CURL_USERAGENT" --silent "${AuthLink[$dn]}" 2>/dev/null)
send_signed_request "${AuthLink[$dn]}" ""
debug "authlink response = $response"
# get the token from the http-01 component
token=$(json_get "$response" "challenges" "type" "dns-01" "token")
@ -2243,13 +2280,13 @@ for d in $alldomains; do
uri=$(json_get "$response" "uri" "http-01")
debug uri "$uri"
else # APIv2
response=$(curl --user-agent "$CURL_USERAGENT" --silent "${AuthLink[$dn]}" 2>/dev/null)
send_signed_request "${AuthLink[$dn]}" ""
debug "authlink response = $response"
# get the token from the http-01 component
token=$(json_get "$response" "challenges" "type" "http-01" "token")
debug token "$token"
# get the uri from the http component
uri=$(json_get "$response" "challenges" "type" "http-01" "url")
uri=$(json_get "$response" "challenges" "type" "http-01" "url" | head -n1)
debug uri "$uri"
fi
@ -2272,7 +2309,7 @@ for d in $alldomains; do
done
umask "$ORIG_UMASK"
wellknown_url="${CHALLENGE_CHECK_TYPE}://$d/.well-known/acme-challenge/$token"
wellknown_url="${CHALLENGE_CHECK_TYPE}://${d}/.well-known/acme-challenge/$token"
debug wellknown_url "$wellknown_url"
if [[ "$SKIP_HTTP_TOKEN_CHECK" == "true" ]]; then
@ -2325,7 +2362,7 @@ done # end of ... loop through domains for cert ( from SANS list)
# perform validation if via DNS challenge
if [[ $VALIDATE_VIA_DNS == "true" ]]; then
# loop through dns-variable files to check if dns has been changed
for dnsfile in $TEMP_DIR/dns_verify/*; do
for dnsfile in "$TEMP_DIR"/dns_verify/*; do
if [[ -e "$dnsfile" ]]; then
debug "loading DNSfile: $dnsfile"
# shellcheck source=/dev/null
@ -2378,7 +2415,7 @@ if [[ $VALIDATE_VIA_DNS == "true" ]]; then
fi
# loop through dns-variable files to let the ACME server check the challenges
for dnsfile in $TEMP_DIR/dns_verify/*; do
for dnsfile in "$TEMP_DIR"/dns_verify/*; do
if [[ -e "$dnsfile" ]]; then
debug "loading DNSfile: $dnsfile"
# shellcheck source=/dev/null
@ -2421,17 +2458,17 @@ copy_file_to_location "domain certificate" "$CERT_FILE" "$DOMAIN_CERT_LOCATION"
copy_file_to_location "private key" "$DOMAIN_DIR/${DOMAIN}.key" "$DOMAIN_KEY_LOCATION"
copy_file_to_location "CA certificate" "$CA_CERT" "$CA_CERT_LOCATION"
if [[ "$DUAL_RSA_ECDSA" == "true" ]]; then
if [[ ! -z "$DOMAIN_CERT_LOCATION" ]]; then
if [[ -n "$DOMAIN_CERT_LOCATION" ]]; then
copy_file_to_location "ec domain certificate" \
"${CERT_FILE%.*}.ec.crt" \
"${DOMAIN_CERT_LOCATION%.*}.ec.crt"
fi
if [[ ! -z "$DOMAIN_KEY_LOCATION" ]]; then
if [[ -n "$DOMAIN_KEY_LOCATION" ]]; then
copy_file_to_location "ec private key" \
"$DOMAIN_DIR/${DOMAIN}.ec.key" \
"${DOMAIN_KEY_LOCATION%.*}.ec.key"
fi
if [[ ! -z "$CA_CERT_LOCATION" ]]; then
if [[ -n "$CA_CERT_LOCATION" ]]; then
copy_file_to_location "ec CA certificate" \
"${CA_CERT%.*}.ec.crt" \
"${CA_CERT_LOCATION%.*}.ec.crt"
@ -2439,7 +2476,7 @@ if [[ "$DUAL_RSA_ECDSA" == "true" ]]; then
fi
# if DOMAIN_CHAIN_LOCATION is not blank, then create and copy file.
if [[ ! -z "$DOMAIN_CHAIN_LOCATION" ]]; then
if [[ -n "$DOMAIN_CHAIN_LOCATION" ]]; then
if [[ "$(dirname "$DOMAIN_CHAIN_LOCATION")" == "." ]]; then
to_location="${DOMAIN_DIR}/${DOMAIN_CHAIN_LOCATION}"
else
@ -2453,7 +2490,7 @@ if [[ ! -z "$DOMAIN_CHAIN_LOCATION" ]]; then
fi
fi
# if DOMAIN_KEY_CERT_LOCATION is not blank, then create and copy file.
if [[ ! -z "$DOMAIN_KEY_CERT_LOCATION" ]]; then
if [[ -n "$DOMAIN_KEY_CERT_LOCATION" ]]; then
if [[ "$(dirname "$DOMAIN_KEY_CERT_LOCATION")" == "." ]]; then
to_location="${DOMAIN_DIR}/${DOMAIN_KEY_CERT_LOCATION}"
else
@ -2467,7 +2504,7 @@ if [[ ! -z "$DOMAIN_KEY_CERT_LOCATION" ]]; then
fi
fi
# if DOMAIN_PEM_LOCATION is not blank, then create and copy file.
if [[ ! -z "$DOMAIN_PEM_LOCATION" ]]; then
if [[ -n "$DOMAIN_PEM_LOCATION" ]]; then
if [[ "$(dirname "$DOMAIN_PEM_LOCATION")" == "." ]]; then
to_location="${DOMAIN_DIR}/${DOMAIN_PEM_LOCATION}"
else
@ -2489,8 +2526,8 @@ reload_service
if [[ "$DEACTIVATE_AUTH" == "true" ]]; then
debug "in deactivate list is $deactivate_url_list"
for deactivate_url in $deactivate_url_list; do
resp=$(curl --user-agent "$CURL_USERAGENT" "$deactivate_url" 2>/dev/null)
d=$(json_get "$resp" "hostname")
send_signed_request "$deactivate_url" ""
d=$(json_get "$response" "hostname")
info "deactivating domain $d"
debug "deactivating $deactivate_url"
send_signed_request "$deactivate_url" "{\"resource\": \"authz\", \"status\": \"deactivated\"}"


+ 22
- 0
test/Dockerfile-rhel6 View File

@ -0,0 +1,22 @@
FROM roboxes/rhel6
# FROM centos:centos6
# bionic = latest 18 version
# Update and install required software
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y install git curl dnsutils wget # nginx-light
WORKDIR /root
#RUN mkdir /etc/nginx/pki
#RUN mkdir /etc/nginx/pki/private
#COPY ./test/test-config/nginx-ubuntu-sites-enabled-default /etc/nginx/sites-enabled/default
# BATS (Bash Automated Testings)
# RUN git clone https://github.com/bats-core/bats-core.git
# RUN bats-core/install.sh /usr/local
EXPOSE 80 443
# Run eternal loop - for testing
CMD ["/bin/bash", "-c", "while :; do sleep 10; done"]

+ 23
- 0
test/Dockerfile-ubuntu View File

@ -0,0 +1,23 @@
FROM ubuntu:xenial
# bionic = latest 18 version
# Update and install required software
RUN apt-get update
# TODO work out why default version of awk fails
RUN apt-get install -y git curl dnsutils wget gawk nginx-light # linux-libc-dev make gcc binutils
RUN apt-get install -y vim dos2unix # for debugging
# TODO test with drill, dig, host
WORKDIR /root
RUN mkdir /etc/nginx/pki
RUN mkdir /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default
# BATS (Bash Automated Testings)
# RUN git clone https://github.com/bats-core/bats-core.git
# RUN bats-core/install.sh /usr/local
EXPOSE 80 443
# Run eternal loop - for testing
CMD ["/bin/bash", "-c", "while :; do sleep 10; done"]

+ 20
- 0
test/README.md View File

@ -0,0 +1,20 @@
# Testing
This directory contains a simple test script which tests creating certificates with Pebble (testing version of the LetsEncrypt server)
Start up pebble, the challdnstest server for DNS challenges
`docker-compose -f "docker-compose.yml" up -d --build`
Run the tests
`docker exec -it getssl /getssl/test/run-test.sh`
Debug (need to set CURL_CA_BUNDLE as pebble uses a local certificate, otherwise you get a "unknown API version" error)
`docker exec -it getssl /bin/bash`
`export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt`
`/getssl/getssl -d getssl`
# TODO
1. Move to BATS (bash automated testing) instead of run-test.sh
2. Test RHEL6, Debian as well
3. Test SSH, SFTP
4. Test wildcards

+ 43
- 0
test/run-test.sh View File

@ -0,0 +1,43 @@
#! /bin/bash
set -e
# Test setup
if [[ -d /root/.getssl ]]; then
rm -r /root/.getssl
fi
wget --no-clobber https://raw.githubusercontent.com/letsencrypt/pebble/master/test/certs/pebble.minica.pem
# cat /etc/pki/tls/certs/ca-bundle.crt /root/pebble.minica.pem > /root/pebble-ca-bundle.crt
cat /etc/ssl/certs/ca-certificates.crt /root/pebble.minica.pem > /root/pebble-ca-bundle.crt
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
curl -X POST -d '{"host":"getssl", "addresses":["10.30.50.4"]}' http://10.30.50.3:8055/add-a
# Test #1 - http-01 verification
echo Test \#1 - http-01 verification
cp /getssl/test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default
service nginx restart
/getssl/getssl -c getssl
cp /getssl/test/test-config/getssl-http01.cfg /root/.getssl/getssl/getssl.cfg
/getssl/getssl -f getssl
# Test #2 - http-01 forced renewal
echo Test \#2 - http-01 forced renewal
/getssl/getssl getssl -f
# Test cleanup
rm -r /root/.getssl
# Test #3 - dns-01 verification
echo Test \#3 - dns-01 verification
cp /getssl/test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default
service nginx restart
/getssl/getssl -c getssl
cp /getssl/test/test-config/getssl-dns01.cfg /root/.getssl/getssl/getssl.cfg
/getssl/getssl getssl
# Test #4 - dns-01 forced renewal
echo Test \#4 - dns-01 forced renewal
/getssl/getssl getssl -f

+ 54
- 0
test/test-config/getssl-dns01.cfg View File

@ -0,0 +1,54 @@
# Uncomment and modify any variables you need
# see https://github.com/srvrco/getssl/wiki/Config-variables for details
# see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs
#
# The staging server is best for testing
#CA="https://acme-staging.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
CA="https://pebble:14000/dir"
VALIDATE_VIA_DNS=true
DNS_ADD_COMMAND="/getssl/dns_scripts/dns_add_challtestsrv"
DNS_DEL_COMMAND="/getssl/dns_scripts/dns_del_challtestsrv"
# AUTH_DNS_SERVER=10.30.50.3
#PRIVATE_KEY_ALG="rsa"
# Additional domains - this could be multiple domains / subdomains in a comma separated list
# Note: this is Additional domains - so should not include the primary domain.
SANS=""
# Acme Challenge Location. The first line for the domain, the following ones for each additional domain.
# If these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
# An ssh key will be needed to provide you with access to the remote server.
# Optionally, you can specify a different userid for ssh/scp to use on the remote server before the @ sign.
# If left blank, the username on the local server will be used to authenticate against the remote server.
# If these start with ftp: then the next variables are ftpuserid:ftppassword:servername:ACL_location
# These should be of the form "/path/to/your/website/folder/.well-known/acme-challenge"
# where "/path/to/your/website/folder/" is the path, on your web server, to the web root for your domain.
ACL=('/var/www/html/.well-known/acme-challenge')
# 'ssh:server5:/var/www/getssltest.hopto.org/web/.well-known/acme-challenge'
# 'ssh:sshuserid@server5:/var/www/getssltest.hopto.org/web/.well-known/acme-challenge'
# 'ftp:ftpuserid:ftppassword:getssltest.hopto.org:/web/.well-known/acme-challenge')
#Set USE_SINGLE_ACL="true" to use a single ACL for all checks
USE_SINGLE_ACL="false"
# Location for all your certs, these can either be on the server (full path name)
# or using ssh /sftp as for the ACL
DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt"
DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key"
CA_CERT_LOCATION="/etc/nginx/pki/chain.crt"
DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert
DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert
# The command needed to reload apache / nginx or whatever you use
RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl /etc/nginx/sites-enabled/default && service nginx restart"
# Define the server type. This can be https, ftp, ftpi, imap, imaps, pop3, pop3s, smtp,
# smtps_deprecated, smtps, smtp_submission, xmpp, xmpps, ldaps or a port number which
# will be checked for certificate expiry and also will be checked after
# an update to confirm correct certificate is running (if CHECK_REMOTE) is set to true
#SERVER_TYPE="https"
#CHECK_REMOTE="true"

+ 53
- 0
test/test-config/getssl-http01.cfg View File

@ -0,0 +1,53 @@
# Uncomment and modify any variables you need
# see https://github.com/srvrco/getssl/wiki/Config-variables for details
# see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs
#
# The staging server is best for testing
#CA="https://acme-staging.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
CA="https://pebble:14000/dir"
#VALIDATE_VIA_DNS=true
#DNS_ADD_COMMAND="/getssl/dns_scripts/dns_add_challtestsrv"
#DNS_DEL_COMMAND="/getssl/dns_scripts/dns_del_challtestsrv"
#PRIVATE_KEY_ALG="rsa"
# Additional domains - this could be multiple domains / subdomains in a comma separated list
# Note: this is Additional domains - so should not include the primary domain.
SANS=""
# Acme Challenge Location. The first line for the domain, the following ones for each additional domain.
# If these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
# An ssh key will be needed to provide you with access to the remote server.
# Optionally, you can specify a different userid for ssh/scp to use on the remote server before the @ sign.
# If left blank, the username on the local server will be used to authenticate against the remote server.
# If these start with ftp: then the next variables are ftpuserid:ftppassword:servername:ACL_location
# These should be of the form "/path/to/your/website/folder/.well-known/acme-challenge"
# where "/path/to/your/website/folder/" is the path, on your web server, to the web root for your domain.
ACL=('/var/www/html/.well-known/acme-challenge')
# 'ssh:server5:/var/www/getssltest.hopto.org/web/.well-known/acme-challenge'
# 'ssh:sshuserid@server5:/var/www/getssltest.hopto.org/web/.well-known/acme-challenge'
# 'ftp:ftpuserid:ftppassword:getssltest.hopto.org:/web/.well-known/acme-challenge')
#Set USE_SINGLE_ACL="true" to use a single ACL for all checks
USE_SINGLE_ACL="false"
# Location for all your certs, these can either be on the server (full path name)
# or using ssh /sftp as for the ACL
DOMAIN_CERT_LOCATION="/etc/nginx/pki/server.crt"
DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key"
CA_CERT_LOCATION="/etc/nginx/pki/chain.crt"
DOMAIN_CHAIN_LOCATION="" # this is the domain cert and CA cert
DOMAIN_PEM_LOCATION="" # this is the domain_key, domain cert and CA cert
# The command needed to reload apache / nginx or whatever you use
RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-ssl /etc/nginx/sites-enabled/default && service nginx restart"
# Define the server type. This can be https, ftp, ftpi, imap, imaps, pop3, pop3s, smtp,
# smtps_deprecated, smtps, smtp_submission, xmpp, xmpps, ldaps or a port number which
# will be checked for certificate expiry and also will be checked after
# an update to confirm correct certificate is running (if CHECK_REMOTE) is set to true
#SERVER_TYPE="https"
#CHECK_REMOTE="true"

+ 93
- 0
test/test-config/nginx-ubuntu-no-ssl View File

@ -0,0 +1,93 @@
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
listen 80 default_server;
listen 5002 default_server;
listen [::]:5002 default_server;
# SSL configuration
#
listen 443 default_server;
listen [::]:443 default_server;
listen 5001 default_server;
listen [::]:5001 default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
# ssl_certificate /etc/nginx/pki/server.crt;
# ssl_certificate_key /etc/nginx/pki/private/server.key;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php7.0-fpm:
# fastcgi_pass unix:/run/php/php7.0-fpm.sock;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}

+ 92
- 0
test/test-config/nginx-ubuntu-ssl View File

@ -0,0 +1,92 @@
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# http://wiki.nginx.org/Pitfalls
# http://wiki.nginx.org/QuickStart
# http://wiki.nginx.org/Configuration
#
# Generally, you will want to move this file somewhere, and start with a clean
# file but keep this around for reference. Or just disable in sites-enabled.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##
# Default server configuration
#
server {
listen 80 default_server;
listen 5002 default_server;
listen [::]:5002 default_server;
# SSL configuration
#
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
listen 5001 ssl default_server;
listen [::]:5001 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name _;
ssl_certificate /etc/nginx/pki/server.crt;
ssl_certificate_key /etc/nginx/pki/private/server.key;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php7.0-fpm:
# fastcgi_pass unix:/run/php/php7.0-fpm.sock;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
# listen 80;
# listen [::]:80;
#
# server_name example.com;
#
# root /var/www/example.com;
# index index.html;
#
# location / {
# try_files $uri $uri/ =404;
# }
#}

Loading…
Cancel
Save