From 953bfd25c2a07bc52db2326397fc5144724cda88 Mon Sep 17 00:00:00 2001 From: Tim Kimber Date: Thu, 12 Mar 2020 09:33:59 +0000 Subject: [PATCH] Fix bug with DNS-01 and multiple domains --- dns_scripts/dns_add_challtestsrv | 2 +- getssl | 49 ++++++++++++++----- test/9-multiple-domains-dns01.bats | 47 ++++++++++++++++++ .../getssl-multiple-domains-dns01.cfg | 37 ++++++++++++++ 4 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 test/9-multiple-domains-dns01.bats create mode 100644 test/test-config/getssl-multiple-domains-dns01.cfg diff --git a/dns_scripts/dns_add_challtestsrv b/dns_scripts/dns_add_challtestsrv index 601bcfc..98444b5 100755 --- a/dns_scripts/dns_add_challtestsrv +++ b/dns_scripts/dns_add_challtestsrv @@ -4,4 +4,4 @@ fulldomain="${1}" token="${2}" -curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt +curl --silent -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt diff --git a/getssl b/getssl index a73a601..93ff02d 100755 --- a/getssl +++ b/getssl @@ -750,13 +750,37 @@ create_order() { OrderLink=$(echo "$responseHeaders" | grep -i location | awk '{print $2}'| tr -d '\r\n ') debug "Order link $OrderLink" FinalizeLink=$(json_get "$response" "finalize") - dn=0 - for d in $alldomains; do - # get authorizations link - AuthLink[$dn]=$(json_get "$response" "identifiers" "value" "$d" "authorizations" "x") - debug "authorizations link for $d - ${AuthLink[$dn]}" - ((dn++)) - done + + if [[ $API -eq 1 ]]; then + dn=0 + for d in $alldomains; do + # get authorizations link + AuthLink[$dn]=$(json_get "$response" "identifiers" "value" "$d" "authorizations" "x") + debug "authorizations link for $d - ${AuthLink[$dn]}" + ((dn++)) + done + else + # Authorization links are unsorted, so fetch the authorization link, find the domain, save response in the correct array position + AuthLinks=$(json_get "$response" "authorizations") + AuthLinkResponse=() + AuthLinkResponseHeader=() + for l in $AuthLinks; do + debug "Requesting authorizations link for $l" + send_signed_request "$l" "" + # Get domain from response + authdomain=$(json_get "$response" "identifier" "value") + # find array position (This is O(n2) but that doubt we'll see performance issues) + dn=0 + for d in $alldomains; do + if [ "$d" == "$authdomain" ]; then + debug "Saving authorization response for $authdomain for domain alldomains[$dn]" + AuthLinkResponse[$dn]=$response + AuthLinkResponseHeader[$dn]=$responseHeaders + fi + ((dn++)) + done + done + fi } date_epoc() { # convert the date into epoch time @@ -823,7 +847,9 @@ for d in $alldomains; do error_exit "new-authz error: $response" fi else - send_signed_request "${AuthLink[$dn]}" "" + response=${AuthLinkResponse[$dn]} + responseHeaders=${AuthLinkResponseHeader[$dn]} + response_status=$(json_get "$response" status) fi if [[ $response_status == "valid" ]]; then @@ -841,16 +867,14 @@ for d in $alldomains; do if [[ $VALIDATE_VIA_DNS == "true" ]]; then # set up the correct DNS token for verification if [[ $API -eq 1 ]]; then # get the dns component of the ACME response - # get the token from the dns component + # get the token and uri from the dns component token=$(json_get "$response" "token" "dns-01") - # get the uri from the dns component uri=$(json_get "$response" "uri" "dns-01") debug uri "$uri" else # APIv2 debug "authlink response = $response" - # get the token from the http-01 component + # get the token and uri from the dns-01 component token=$(json_get "$response" "challenges" "type" "dns-01" "token") - # get the uri from the http component uri=$(json_get "$response" "challenges" "type" "dns-01" "url") debug uri "$uri" fi @@ -901,7 +925,6 @@ for d in $alldomains; do uri=$(json_get "$response" "uri" "http-01") debug uri "$uri" else # APIv2 - 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") diff --git a/test/9-multiple-domains-dns01.bats b/test/9-multiple-domains-dns01.bats new file mode 100644 index 0000000..1b2cd9e --- /dev/null +++ b/test/9-multiple-domains-dns01.bats @@ -0,0 +1,47 @@ +#! /usr/bin/env bats + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +load '/getssl/test/test_helper.bash' + + +# This is run for every test +setup() { + export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt +} + + +@test "Create certificates for multi-level domains using DNS-01 verification" { + # This tests we can create a certificate for .getssl.test and getssl.test (in SANS) + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + CONFIG_FILE="getssl-multiple-domains-dns01.cfg" + setup_environment + + # Add top level domain from SANS to DNS + curl --silent -X POST -d '{"host":"getssl.test", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a + + init_getssl + create_certificate + assert_success + refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' + refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' + refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' +} + + +@test "Force renewal of multi-level domains using DNS-01" { + # This tests we can renew a certificate for .getssl.test and getssl.test (in SANS) + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + run ${CODE_DIR}/getssl -f $GETSSL_HOST + assert_success + refute_output --regexp '[Ff][Aa][Ii][Ll][Ee][Dd]' + refute_output --regexp '[Ee][Rr][Rr][Oo][Rr]' + refute_output --regexp '[Ww][Aa][Rr][Nn][Ii][Nn][Gg]' + # Remove all the dns aliases + cleanup_environment + curl --silent -X POST -d '{"host":"getssl.tst"}' http://10.30.50.3:8055/clear-a +} diff --git a/test/test-config/getssl-multiple-domains-dns01.cfg b/test/test-config/getssl-multiple-domains-dns01.cfg new file mode 100644 index 0000000..e0d596c --- /dev/null +++ b/test/test-config/getssl-multiple-domains-dns01.cfg @@ -0,0 +1,37 @@ +# 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 +# +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 + +# Additional domains - this could be multiple domains / subdomains in a comma separated list +SANS="getssl.test" + +# Acme Challenge Location. The first line for the domain, the following ones for each additional domain. +ACL=( + '/var/www/html/.well-known/acme-challenge' + '/var/www/html/.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 ${NGINX_CONFIG} && /getssl/test/restart-nginx" + +# Define the server type and confirm correct certificate is installed +SERVER_TYPE="https" +CHECK_REMOTE="true"