diff --git a/getssl b/getssl index 8d1eee1..bb48e09 100755 --- a/getssl +++ b/getssl @@ -529,6 +529,17 @@ check_challenge_completion_dns() { # perform validation via DNS challenge # check for token at public dns server, waiting for a valid response. for ns in $primary_ns; do info "checking DNS at $ns" + + # add +noidnout if idn-domain so search for domain in results works + if [[ "${d}" == xn--* || "${d}" == *".xn--"* ]]; then + if [[ "$DNS_CHECK_FUNC" == "nslookup" || "$DNS_CHECK_FUNC" == "host" || ("$DNS_CHECK_FUNC" == "dig" && "$DIG_SUPPORTS_NOIDNOUT" == "false") ]]; then + info "Warning: idn domain but $DNS_CHECK_FUNC doesn't support +noidnout" + else + debug "adding +noidnout to DNS_CHECK_OPTIONS" + DNS_CHECK_OPTIONS="$DNS_CHECK_OPTIONS +noidnout" + fi + fi + ntries=0 check_dns="fail" while [[ "$check_dns" == "fail" ]]; do @@ -537,14 +548,18 @@ check_challenge_completion_dns() { # perform validation via DNS challenge | grep ^_acme -A2\ | grep '"'|awk -F'"' '{ print $2}') elif [[ "$DNS_CHECK_FUNC" == "drill" ]] || [[ "$DNS_CHECK_FUNC" == "dig" ]]; then - debug "$DNS_CHECK_FUNC" TXT "${rr}" "@${ns}" - check_result=$($DNS_CHECK_FUNC TXT "${rr}" "@${ns}" \ + # shellcheck disable=SC2086 + debug "$DNS_CHECK_FUNC" $DNS_CHECK_OPTIONS TXT "${rr}" "@${ns}" + # shellcheck disable=SC2086 + check_result=$($DNS_CHECK_FUNC $DNS_CHECK_OPTIONS TXT "${rr}" "@${ns}" \ | grep -i "^${rr}" \ | grep 'IN\WTXT'|awk -F'"' '{ print $2}') debug "check_result=$check_result" if [[ -z "$check_result" ]]; then - debug "$DNS_CHECK_FUNC" ANY "${rr}" "@${ns}" - check_result=$($DNS_CHECK_FUNC ANY "${rr}" "@${ns}" \ + # shellcheck disable=SC2086 + debug "$DNS_CHECK_FUNC" $DNS_CHECK_OPTIONS ANY "${rr}" "@${ns}" + # shellcheck disable=SC2086 + check_result=$($DNS_CHECK_FUNC $DNS_CHECK_OPTIONS ANY "${rr}" "@${ns}" \ | grep -i "^${rr}" \ | grep 'IN\WTXT'|awk -F'"' '{ print $2}') debug "check_result=$check_result" @@ -649,6 +664,7 @@ check_config() { # check the config files for all obvious errors tmplist=$(mktemp 2>/dev/null || mktemp -t getssl.XXXXXX) || error_exit "mktemp failed" for d in "${alldomains[@]}"; do # loop over domains (dn is domain number) debug "checking domain $d" + if [[ "$(grep "^${d}$" "$tmplist")" = "$d" ]]; then info "${DOMAIN}: $d appears to be duplicated in domain, SAN list" config_errors=true @@ -672,6 +688,14 @@ check_config() { # check the config files for all obvious errors fi # check domain exists using all DNS utilities. DNS_CHECK_OPTIONS may bind IP address or provide TSIG + + # add +noidnout if idn-domain so search for domain in results works + if [[ "${d}" == xn--* || "${d}" == *".xn--"* ]]; then + if [[ "$HAS_DIG_OR_DRILL" != "dig" || "$DIG_SUPPORTS_NOIDNOUT" == "true" ]]; then + DNS_CHECK_OPTIONS="$DNS_CHECK_OPTIONS +noidnout" + fi + fi + found_ip=false if [[ -n "$HAS_DIG_OR_DRILL" ]]; then debug "DNS lookup using $HAS_DIG_OR_DRILL $DNS_CHECK_OPTIONS ${d}" @@ -1125,6 +1149,7 @@ error_exit() { # give error message on error exit find_dns_utils() { HAS_NSLOOKUP=false HAS_DIG_OR_DRILL="" + DIG_SUPPORTS_NOIDNOUT=false HAS_HOST=false if [[ -n "$(command -v nslookup 2>/dev/null)" ]]; then debug "HAS NSLOOKUP=true" @@ -1141,6 +1166,11 @@ find_dns_utils() { else HAS_DIG_OR_DRILL="dig" fi + + if [[ $(${HAS_DIG_OR_DRILL} +noidnout >/dev/null 2>&1) ]]; then + DIG_SUPPORTS_NOIDNOUT=true + fi + debug "HAS DIG_OR_DRILL=$HAS_DIG_OR_DRILL" fi diff --git a/test/37-idn.bats b/test/37-idn.bats new file mode 100644 index 0000000..7b91827 --- /dev/null +++ b/test/37-idn.bats @@ -0,0 +1,80 @@ +#! /usr/bin/env bats + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +load '/getssl/test/test_helper.bash' + +setup_file() { + if [ -z "$STAGING" ]; then + export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt + GETSSL_CMD_HOST=${GETSSL_HOST/getssl/xn--t-r1a81lydm69gz81r} + curl --silent -X POST -d '{"host":"'$GETSSL_CMD_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a + fi +} + +# This is run for every test +setup() { + GETSSL_CMD_HOST=${GETSSL_HOST/getssl/xn--t-r1a81lydm69gz81r} + + # use the test description to move tools we don't want to test out of the way + DNS_TOOL=${BATS_TEST_DESCRIPTION##*:} + for tool in dig drill host nslookup + do + if [[ "$tool" != "$DNS_TOOL" && -f /usr/bin/$tool ]]; then + mv /usr/bin/$tool /usr/bin/${tool}.getssl + fi + done +} + +teardown() { + # use the test description to move tools we didn't want to test back + DNS_TOOL=${BATS_TEST_DESCRIPTION##*-} + for tool in dig drill host nslookup + do + if [[ "$tool" != "$DNS_TOOL" && -f /usr/bin/${tool}.getssl ]]; then + mv /usr/bin/${tool}.getssl /usr/bin/${tool} + fi + done +} + +teardown_file() { + if [ -z "$STAGING" ]; then + curl --silent -X POST -d '{"host":"'$GETSSL_CMD_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a + fi +} + +@test "Check that DNS-01 verification works if the domain is idn:dig" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + + CONFIG_FILE="getssl-dns01.cfg" + + setup_environment + init_getssl + create_certificate -d + + assert_success + assert_output --partial "dig" + check_output_for_errors "debug" +} + +@test "Check that DNS-01 verification works if the domain is idn:drill" { + if [ -n "$STAGING" ]; then + skip "Using staging server, skipping internal test" + fi + if [ ! -f /usr/bin/drill ]; then + # Can't find drill package for centos8 / rockylinux8 + skip "Drill not installed on this system" + fi + + CONFIG_FILE="getssl-dns01.cfg" + + setup_environment + init_getssl + create_certificate -d + + assert_success + assert_output --partial "drill" + check_output_for_errors "debug" +} diff --git a/test/idn-domain.md b/test/idn-domain.md new file mode 100644 index 0000000..2f25f0e --- /dev/null +++ b/test/idn-domain.md @@ -0,0 +1,22 @@ +# Convert getssl.test into IDN version using confusable letters + + + +## Unicode characters + +* ɡ 0261 LATIN SMALL LETTER SCRIPT G +* е 0435 CYRILLIC SMALL LETTER IE +* t +* ѕ 0455 CYRILLIC SMALL LETTER DZE +* ꜱ A731 LATIN LETTER SMALL CAPITAL S +* ᛁ 16C1 RUNIC LETTER ISAZ IS ISS I + +## IDN version of getssl.test + +ɡеtѕꜱᛁ.test + +## ACE version of IDN ɡеtѕꜱᛁ.test + + + +xn--t-r1a81lydm69gz81r.test diff --git a/test/run-test.cmd b/test/run-test.cmd index 61b360e..88e692d 100644 --- a/test/run-test.cmd +++ b/test/run-test.cmd @@ -12,6 +12,7 @@ IF NOT x%OS:duck=%==x%OS% GOTO duckdns IF NOT x%OS:dynu=%==x%OS% GOTO dynu IF NOT x%OS:bash=%==x%OS% GOTO bash SET ALIAS=%OS%.getssl.test +SET IDN=%OS%.xn--t-r1a81lydm69gz81r.test SET STAGING= SET GETSSL_OS=%OS% GOTO Run @@ -55,6 +56,7 @@ docker run -it ^ --rm ^ --network %CurrDirName%_acmenet ^ --network-alias %ALIAS% ^ + --network-alias %IDN% ^ --network-alias a.%OS%.getssl.test ^ --network-alias b.%OS%.getssl.test ^ --network-alias c.%OS%.getssl.test ^ diff --git a/test/run-test.sh b/test/run-test.sh index ef7e403..8f405e1 100755 --- a/test/run-test.sh +++ b/test/run-test.sh @@ -15,6 +15,7 @@ else fi ALIAS="$OS.getssl.test" +IDN="$OS.xn--t-r1a81lydm69gz81r.test" STAGING="" GETSSL_OS=$OS @@ -39,6 +40,7 @@ docker run \ --rm \ --network ${PWD##*/}_acmenet \ --network-alias $ALIAS \ + --network-alias $IDN \ --network-alias "a.$OS.getssl.test" \ --network-alias "b.$OS.getssl.test" \ --network-alias "c.$OS.getssl.test" \