diff --git a/dns_scripts/dns_add_cloudflare b/dns_scripts/dns_add_cloudflare index ef3d6fc..78af21e 100755 --- a/dns_scripts/dns_add_cloudflare +++ b/dns_scripts/dns_add_cloudflare @@ -3,40 +3,111 @@ email=${CF_EMAIL:-''} key=${CF_KEY:-''} -fulldomain="${1:?Need full domain name as first parameter}" -token="${2:?Need Let’s Encrypt challenge token as second parameter}" +fulldomain="${1}" +token="${2}" API='https://api.cloudflare.com/client/v4/zones' -PARAMS=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' ) +curl_params=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' ) + +# check initial parameters + +if [[ -z "$fulldomain" ]]; then + echo "DNS script requires full domain name as first parameter" + exit 1 +fi + +if [[ -z "$token" ]]; then + echo "DNS script requires challenge token as second parameter" + exit 1 +fi + +if [[ -z "$CF_EMAIL" ]]; then + echo "CF_EMAIL parameter not set" + exit 1 +fi + +if [[ -z "$CF_KEY" ]]; then + echo "CF_KEY parameter not set" + exit 1 +fi + # get a list of all domain names from cloudflare # If you have a lot, you may need add "&page=1&per_page=1000" and/or "&status=active" -resp=$(curl --silent "${PARAMS[@]}" -X GET "$API") +resp=$(curl --silent "${curl_params[@]}" -X GET "$API") re='"result":\[(([^][]*\[[^][]*])*[^][]*)]' # find result section -[[ "${resp// }" =~ $re ]] && resp="${BASH_REMATCH[1]}" -while [[ "$resp" ]]; do # iterate through domains returned - re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)' - [[ "$resp" =~ $re ]]; first="${BASH_REMATCH[1]}"; resp="${BASH_REMATCH[3]}" +if [[ "${resp// }" =~ $re ]]; then + resp="${BASH_REMATCH[1]}" +fi +# iterate through all sections to obtain a list of domains +while [[ "$resp" ]]; do + re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)' + if [[ "$resp" =~ $re ]]; then + first="${BASH_REMATCH[1]}" + resp="${BASH_REMATCH[3]}" + fi # remove subsections - leave only domain level - while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"; done - re='"name":"([^"]*)"'; [[ "$first" =~ $re ]] && domains=( "${domains[@]}" "${BASH_REMATCH[1]}" ) - re='"id":"([^"]*)"'; [[ "$first" =~ $re ]] && ids=( "${ids[@]}" "${BASH_REMATCH[1]}" ) + while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do + first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" + done + re='"name":"([^"]*)"' + if [[ "$first" =~ $re ]]; then + domains=( "${domains[@]}" "${BASH_REMATCH[1]}" ) + else + echo "Error getting domain name" + exit 1 + fi + re='"id":"([^"]*)"' + if [[ "$first" =~ $re ]]; then + ids=( "${ids[@]}" "${BASH_REMATCH[1]}" ) + else + echo "Error getting domain id" + exit 1 + fi done -# select right cloudflare domain (longest one) -domain=$fulldomain. -# shellcheck disable=SC2076 -while [[ "$domain" && ! "${domains[@]/#/@}" == *"@${domain%?}"* ]]; do domain=${domain#*.}; done -domain=${domain%?} -[ -z "$domain" ] && { echo 'domain name not found on your cloudflare account'; exit 1; } - -for i in "${!domains[@]}"; do [[ ${domains[i]} == "$domain" ]] && break; done -domain_id=${ids[i]} - -resp=$(curl --silent "${PARAMS[@]}" -X POST "$API/$domain_id/dns_records" \ - --data "{\"type\":\"TXT\",\"name\":\"_acme-challenge.${fulldomain%.$domain}\",\"content\":\"$token\",\"ttl\":300}") -# code 81057 = The record already exists. -if [[ "${resp// }" == *'"success":false'* && ! "${resp// }" == *'"code":81057[^0-9]'* ]]; then - re='"message":"([^"]+)"'; [[ "$resp" =~ $re ]] - echo "Error: DNS challenge not added: ${BASH_REMATCH[1]:-unknown error}"; exit 2 +# split required domain name into an array +dnarray=(${fulldomain//./ }) +# get number of parts in required domain name +NumParts=${#dnarray[@]} +# build a test domain name, starting with the largest, and reduce it +# until a match is found, set domain = first ( longest) match. +domain="" +i=1 +while [ $i -lt "$NumParts" ]; do + testdomain="${dnarray[i-1]}" + for ((j=i; j/dev/null \ | grep "primary name server" \ | awk '{print $NF}') - if [ -z "$all_auth_dns_servers" ]; then + if [[ -z "$all_auth_dns_servers" ]]; then error_exit "couldn't find primary DNS server - please set AUTH_DNS_SERVER in config" fi primary_ns="$all_auth_dns_servers" @@ -524,25 +525,25 @@ get_auth_dns() { # get the authoritative dns server for a domain (sets primary_n res=$(nslookup -debug=1 -type=soa -type=ns "$1" ${gad_s}) - if [ "$(echo "$res" | grep -c "Non-authoritative")" -gt 0 ]; then + if [[ "$(echo "$res" | grep -c "Non-authoritative")" -gt 0 ]]; then # this is a Non-authoritative server, need to check for an authoritative one. gad_s=$(echo "$res" | awk '$2 ~ "nameserver" {print $4; exit }' |sed 's/\.$//g') - if [ "$(echo "$res" | grep -c "an't find")" -gt 0 ]; then + if [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then # if domain name doesn't exist, then find auth servers for next level up gad_s=$(echo "$res" | awk '$1 ~ "origin" {print $3; exit }') gad_d=$(echo "$res" | awk '$1 ~ "->" {print $2; exit}') fi fi - if [ -z "$gad_s" ]; then + if [[ -z "$gad_s" ]]; then res=$(nslookup -debug=1 -type=soa -type=ns "$gad_d") else res=$(nslookup -debug=1 -type=soa -type=ns "$gad_d" "${gad_s}") fi - if [ "$(echo "$res" | grep -c "canonical name")" -gt 0 ]; then + if [[ "$(echo "$res" | grep -c "canonical name")" -gt 0 ]]; then gad_d=$(echo "$res" | awk ' $2 ~ "canonical" {print $5; exit }' |sed 's/\.$//g') - elif [ "$(echo "$res" | grep -c "an't find")" -gt 0 ]; then + elif [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then gad_s=$(echo "$res" | awk ' $1 ~ "origin" {print $3; exit }') gad_d=$(echo "$res"| awk '$1 ~ "->" {print $2; exit}') fi @@ -570,7 +571,7 @@ get_certificate() { # get certificate for csr, if all domains validated. # convert certificate information into correct format and save to file. CertData=$(awk ' $1 ~ "^Location" {print $2}' "$CURL_HEADER" |tr -d '\r') debug "certdata location = $CertData" - if [ "$CertData" ] ; then + if [[ "$CertData" ]] ; then echo -----BEGIN CERTIFICATE----- > "$gc_certfile" curl --silent "$CertData" | openssl base64 -e >> "$gc_certfile" echo -----END CERTIFICATE----- >> "$gc_certfile" @@ -578,7 +579,7 @@ get_certificate() { # get certificate for csr, if all domains validated. fi # If certificate wasn't a valid certificate, error exit. - if [ -z "$CertData" ] ; then + if [[ -z "$CertData" ]] ; then response2=$(echo "$response" | fold -w64 |openssl base64 -d) debug "response was $response" error_exit "Sign failed: $(echo "$response2" | grep "detail")" @@ -590,7 +591,7 @@ get_certificate() { # get certificate for csr, if all domains validated. | cut -d ';' -f 1 \ | sed 's///g') - if [ "$IssuerData" ] ; then + if [[ "$IssuerData" ]] ; then echo -----BEGIN CERTIFICATE----- > "$gc_cafile" curl --silent "$IssuerData" | openssl base64 -e >> "$gc_cafile" echo -----END CERTIFICATE----- >> "$gc_cafile" @@ -630,7 +631,7 @@ get_os() { # function to get the current Operating System get_signing_params() { # get signing parameters from key skey=$1 - if [ "$(grep -c "RSA PRIVATE KEY" "$skey")" -gt 0 ]; then # RSA key + if [[ "$(grep -c "RSA PRIVATE KEY" "$skey")" -gt 0 ]]; then # RSA key pub_exp64=$(openssl rsa -in "${skey}" -noout -text \ | grep publicExponent \ | grep -oE "0x[a-f0-9]+" \ @@ -645,9 +646,9 @@ get_signing_params() { # get signing parameters from key jwk='{"e":"'"${pub_exp64}"'","kty":"RSA","n":"'"${pub_mod64}"'"}' jwkalg="RS256" signalg="sha256" - elif [ "$(grep -c "EC PRIVATE KEY" "$skey")" -gt 0 ]; then # Elliptic curve key. + elif [[ "$(grep -c "EC PRIVATE KEY" "$skey")" -gt 0 ]]; then # Elliptic curve key. crv="$(openssl ec -in "$skey" -noout -text 2>/dev/null | awk '$2 ~ "CURVE:" {print $3}')" - if [ -z "$crv" ]; then + if [[ -z "$crv" ]]; then gsp_keytype="$(openssl ec -in "$skey" -noout -text 2>/dev/null \ | grep "^ASN1 OID:" \ | awk '{print $3}')" @@ -716,7 +717,7 @@ hex2bin() { # Remove spaces, add leading zero, escape as hex string and parse wi } info() { # write out info as long as the quiet flag has not been set. - if [ ${_QUIET} -eq 0 ]; then + if [[ ${_QUIET} -eq 0 ]]; then echo "$@" fi } @@ -725,9 +726,9 @@ json_get() { # get the value corresponding to $2 in the JSON passed as $1. # 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 [[ ! -z "$3" ]]; then jg_section=$(echo "$json_data" | awk -F"[}]" '{for(i=1;i<=NF;i++){if($i~/\"'"${3}"'\"/){print $i}}}') - if [ "$2" == "uri" ]; then + if [[ "$2" == "uri" ]]; then jg_subsect=$(echo "$jg_section" | awk -F"[,]" '{for(i=1;i<=NF;i++){if($i~/\"'"${2}"'\"/){print $(i)}}}') jg_result=$(echo "$jg_subsect" | awk -F'"' '{print $4}') else @@ -739,7 +740,7 @@ json_get() { # get the value corresponding to $2 in the JSON passed as $1. # check number of quotes jg_q=${jg_result//[^\"]/} # if 2 quotes, assume it's a quoted variable and just return the data within the quotes. - if [ ${#jg_q} -eq 2 ]; then + if [[ ${#jg_q} -eq 2 ]]; then echo "$jg_result" | awk -F'"' '{print $2}' else echo "$jg_result" @@ -761,7 +762,7 @@ purge_archive() { # purge archive of old, invalid, certificates debug "purging archives in ${arcdir}/" for padir in $arcdir/????_??_??_??_??; do # check each directory - if [ -d "$padir" ]; then + if [[ -d "$padir" ]]; then tstamp=$(basename "$padir"| awk -F"_" '{print $1"-"$2"-"$3" "$4":"$5}') if [[ "$os" == "bsd" ]]; then direpoc=$(date -j -f "%F %H:%M" "$tstamp" +%s) @@ -773,7 +774,7 @@ purge_archive() { # purge archive of old, invalid, certificates current_epoc=$(date "+%s") # as certs currently valid for 90 days, purge anything older than 100 purgedate=$((current_epoc - 60*60*24*100)) - if [ "$direpoc" -lt "$purgedate" ]; then + if [[ "$direpoc" -lt "$purgedate" ]]; then echo "purge $padir" rm -rf "${padir:?}" fi @@ -782,7 +783,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 [[ ! -z "$RELOAD_CMD" ]]; then info "reloading SSL services" if [[ "${RELOAD_CMD:0:4}" == "ssh:" ]] ; then sshhost=$(echo "$RELOAD_CMD"| awk -F: '{print $2}') @@ -822,7 +823,7 @@ revoke_certificate() { #revoke a certificate requires() { # check if required function is available result=$(which "$1" 2>/dev/null) debug "checking for required $1 ... $result" - if [ -z "$result" ]; then + if [[ -z "$result" ]]; then error_exit "This script requires $1 installed" fi } @@ -838,7 +839,7 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p CURL_HEADER="$TEMP_DIR/curl.header" dp="$TEMP_DIR/curl.dump" CURL="curl --silent --dump-header $CURL_HEADER " - if [ ${_USE_DEBUG} -eq 1 ]; then + if [[ ${_USE_DEBUG} -eq 1 ]]; then CURL="$CURL --trace-ascii $dp " fi @@ -873,7 +874,7 @@ 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 [[ "$needbase64" ]] ; then response=$($CURL -X POST --data "$body" "$url" | urlbase64) else response=$($CURL -X POST --data "$body" "$url") @@ -892,7 +893,7 @@ send_signed_request() { # Sends a request to the ACME server, signed with your p info "error on acme server - trying again ...." sleep 2 loop_limit=$((loop_limit - 1)) - if [ $loop_limit -lt 1 ]; then + if [[ $loop_limit -lt 1 ]]; then error_exit "500 error from ACME server: $response" fi fi @@ -905,27 +906,27 @@ sign_string() { #sign a string with a given key and algorithm and return urlbase key=$2 signalg=$3 - if [ "$(grep -c "RSA PRIVATE KEY" "$key")" -gt 0 ]; then # RSA key + if [[ "$(grep -c "RSA PRIVATE KEY" "$key")" -gt 0 ]]; then # RSA key signed64="$(printf '%s' "${str}" | openssl dgst -"$signalg" -sign "$key" | urlbase64)" - elif [ "$(grep -c "EC PRIVATE KEY" "$key")" -gt 0 ]; then # Elliptic curve key. + elif [[ "$(grep -c "EC PRIVATE KEY" "$key")" -gt 0 ]]; then # Elliptic curve key. signed=$(printf '%s' "${str}" | openssl dgst -"$signalg" -sign "$key" -hex | awk '{print $2}') debug "EC signature $signed" - if [ "${signed:4:4}" == "0220" ]; then #sha256 + if [[ "${signed:4:4}" == "0220" ]]; then #sha256 R=$(echo "$signed" | cut -c 9-72) part2=$(echo "$signed" | cut -c 73-) - elif [ "${signed:4:4}" == "0221" ]; then #sha256 + elif [[ "${signed:4:4}" == "0221" ]]; then #sha256 R=$(echo "$signed" | cut -c 11-74) part2=$(echo "$signed" | cut -c 75-) - elif [ "${signed:4:4}" == "0230" ]; then #sha384 + elif [[ "${signed:4:4}" == "0230" ]]; then #sha384 R=$(echo "$signed" | cut -c 9-104) part2=$(echo "$signed" | cut -c 105-) - elif [ "${signed:4:4}" == "0231" ]; then #sha384 + elif [[ "${signed:4:4}" == "0231" ]]; then #sha384 R=$(echo "$signed" | cut -c 11-106) part2=$(echo "$signed" | cut -c 107-) - elif [ "${signed:6:4}" == "0241" ]; then #sha512 + elif [[ "${signed:6:4}" == "0241" ]]; then #sha512 R=$(echo "$signed" | cut -c 11-140) part2=$(echo "$signed" | cut -c 141-) - elif [ "${signed:6:4}" == "0242" ]; then #sha512 + elif [[ "${signed:6:4}" == "0242" ]]; then #sha512 R=$(echo "$signed" | cut -c 11-142) part2=$(echo "$signed" | cut -c 143-) else @@ -933,17 +934,17 @@ sign_string() { #sign a string with a given key and algorithm and return urlbase fi debug "R $R" - if [ "${part2:0:4}" == "0220" ]; then #sha256 + if [[ "${part2:0:4}" == "0220" ]]; then #sha256 S=$(echo "$part2" | cut -c 5-68) - elif [ "${part2:0:4}" == "0221" ]; then #sha256 + elif [[ "${part2:0:4}" == "0221" ]]; then #sha256 S=$(echo "$part2" | cut -c 7-70) - elif [ "${part2:0:4}" == "0230" ]; then #sha384 + elif [[ "${part2:0:4}" == "0230" ]]; then #sha384 S=$(echo "$part2" | cut -c 5-100) - elif [ "${part2:0:4}" == "0231" ]; then #sha384 + elif [[ "${part2:0:4}" == "0231" ]]; then #sha384 S=$(echo "$part2" | cut -c 7-102) - elif [ "${part2:0:4}" == "0241" ]; then #sha512 + elif [[ "${part2:0:4}" == "0241" ]]; then #sha512 S=$(echo "$part2" | cut -c 5-136) - elif [ "${part2:0:4}" == "0242" ]; then #sha512 + elif [[ "${part2:0:4}" == "0242" ]]; then #sha512 S=$(echo "$part2" | cut -c 5-136) else error_exit "error in EC signing couldn't get S from $signed" @@ -1184,19 +1185,19 @@ fi AGREEMENT=$(curl -I "${CA}/terms" 2>/dev/null | awk '$1 ~ "Location:" {print $2}'|tr -d '\r') # if nothing in command line, print help and exit. -if [ -z "$DOMAIN" ] && [ ${_CHECK_ALL} -ne 1 ]; then +if [[ -z "$DOMAIN" ]] && [[ ${_CHECK_ALL} -ne 1 ]]; then help_message graceful_exit fi # if the "working directory" doesn't exist, then create it. -if [ ! -d "$WORKING_DIR" ]; then +if [[ ! -d "$WORKING_DIR" ]]; then debug "Making working directory - $WORKING_DIR" mkdir -p "$WORKING_DIR" fi # read any variables from config in working directory -if [ -s "$WORKING_DIR/getssl.cfg" ]; then +if [[ -s "$WORKING_DIR/getssl.cfg" ]]; then debug "reading config from $WORKING_DIR/getssl.cfg" # shellcheck source=/dev/null . "$WORKING_DIR/getssl.cfg" @@ -1214,29 +1215,29 @@ TEMP_DIR="$DOMAIN_DIR/tmp" export OPENSSL_CONF=$SSLCONF # if "-a" option then check other parameters and create run for each domain. -if [ ${_CHECK_ALL} -eq 1 ]; then +if [[ ${_CHECK_ALL} -eq 1 ]]; then info "Check all certificates" - if [ ${_CREATE_CONFIG} -eq 1 ]; then + if [[ ${_CREATE_CONFIG} -eq 1 ]]; then error_exit "cannot combine -c|--create with -a|--all" fi - if [ ${_FORCE_RENEW} -eq 1 ]; then + if [[ ${_FORCE_RENEW} -eq 1 ]]; then error_exit "cannot combine -f|--force with -a|--all because of rate limits" fi - if [ ! -d "$DOMAIN_STORAGE" ]; then + if [[ ! -d "$DOMAIN_STORAGE" ]]; then error_exit "DOMAIN_STORAGE not found - $DOMAIN_STORAGE" fi for dir in ${DOMAIN_STORAGE}/*; do - if [ -d "$dir" ]; then + if [[ -d "$dir" ]]; then debug "Checking $dir" cmd="$0 -U" # No update checks when calling recursively - if [ ${_USE_DEBUG} -eq 1 ]; then + if [[ ${_USE_DEBUG} -eq 1 ]]; then cmd="$cmd -d" fi - if [ ${_QUIET} -eq 1 ]; then + if [[ ${_QUIET} -eq 1 ]]; then cmd="$cmd -q" fi # check if $dir looks like a domain name (contains a period) @@ -1253,9 +1254,9 @@ fi # end of "-a" option (looping through all domains) # if "-c|--create" option used, then create config files. -if [ ${_CREATE_CONFIG} -eq 1 ]; then +if [[ ${_CREATE_CONFIG} -eq 1 ]]; then # If main config file does not exists then create it. - if [ ! -s "$WORKING_DIR/getssl.cfg" ]; then + if [[ ! -s "$WORKING_DIR/getssl.cfg" ]]; then info "creating main config file $WORKING_DIR/getssl.cfg" if [[ ! -s "$SSLCONF" ]]; then SSLCONF="$WORKING_DIR/openssl.cnf" @@ -1264,21 +1265,23 @@ if [ ${_CREATE_CONFIG} -eq 1 ]; then write_getssl_template "$WORKING_DIR/getssl.cfg" fi # If domain and domain config don't exist then create them. - if [ ! -d "$DOMAIN_DIR" ]; then + if [[ ! -d "$DOMAIN_DIR" ]]; then info "Making domain directory - $DOMAIN_DIR" mkdir -p "$DOMAIN_DIR" fi - if [ -s "$DOMAIN_DIR/getssl.cfg" ]; then + if [[ -s "$DOMAIN_DIR/getssl.cfg" ]]; then info "domain config already exists $DOMAIN_DIR/getssl.cfg" else info "creating domain config file in $DOMAIN_DIR/getssl.cfg" # if domain has an existing cert, copy from domain and use to create defaults. - EX_CERT=$(echo | openssl s_client -servername "${DOMAIN}" -connect "${DOMAIN}:443" 2>/dev/null \ - | openssl x509 2>/dev/null) + EX_CERT=$(echo \ + | 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 - 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-) + if [[ ! -z "${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-) EX_SANS=${EX_SANS//$'\n'/','} fi write_domain_template "$DOMAIN_DIR/getssl.cfg" @@ -1290,20 +1293,20 @@ fi # end of "-c|--create" option to create config file. # if domain directory doesn't exist, then create it. -if [ ! -d "$DOMAIN_DIR" ]; then +if [[ ! -d "$DOMAIN_DIR" ]]; then debug "Making working directory - $DOMAIN_DIR" mkdir -p "$DOMAIN_DIR" fi # define a temporary directory, and if it doesn't exist, create it. TEMP_DIR="$DOMAIN_DIR/tmp" -if [ ! -d "${TEMP_DIR}" ]; then +if [[ ! -d "${TEMP_DIR}" ]]; then debug "Making temp directory - ${TEMP_DIR}" mkdir -p "${TEMP_DIR}" fi # read any variables from config in domain directory -if [ -s "$DOMAIN_DIR/getssl.cfg" ]; then +if [[ -s "$DOMAIN_DIR/getssl.cfg" ]]; then debug "reading config from $DOMAIN_DIR/getssl.cfg" # shellcheck source=/dev/null . "$DOMAIN_DIR/getssl.cfg" @@ -1352,31 +1355,31 @@ fi # 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 +if [[ "${CHECK_REMOTE}" == "true" ]] && [[ $_FORCE_RENEW -eq 0 ]]; then debug "getting certificate for $DOMAIN from remote server" # shellcheck disable=SC2086 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 [ -s "$CERT_FILE" ]; then # if local exists + if [[ ! -z "$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 CERT_LOCAL="" fi CERT_REMOTE=$(echo "$EX_CERT" | openssl x509 -noout -fingerprint 2>/dev/null) - if [ "$CERT_LOCAL" == "$CERT_REMOTE" ]; then + if [[ "$CERT_LOCAL" == "$CERT_REMOTE" ]]; then debug "certificate on server is same as the local cert" else # check if the certificate is for the right domain EX_CERT_DOMAIN=$(echo "$EX_CERT" | openssl x509 -text \ | sed -n -e 's/^ *Subject: .* CN=\([A-Za-z0-9.-]*\).*$/\1/p; /^ *DNS:.../ { s/ *DNS://g; y/,/\n/; p; }' \ | sort -u | grep "^$DOMAIN\$") - if [ "$EX_CERT_DOMAIN" == "$DOMAIN" ]; then + if [[ "$EX_CERT_DOMAIN" == "$DOMAIN" ]]; then # check renew-date on ex_cert and compare to local ( if local exists) enddate_ex=$(echo "$EX_CERT" | openssl x509 -noout -enddate 2>/dev/null| cut -d= -f 2-) enddate_ex_s=$(date_epoc "$enddate_ex") debug "external cert has enddate $enddate_ex ( $enddate_ex_s ) " - if [ -s "$CERT_FILE" ]; then # if local exists + if [[ -s "$CERT_FILE" ]]; then # if local exists enddate_lc=$(openssl x509 -noout -enddate < "$CERT_FILE" 2>/dev/null| cut -d= -f 2-) enddate_lc_s=$(date_epoc "$enddate_lc") debug "local cert has enddate $enddate_lc ( $enddate_lc_s ) " @@ -1384,9 +1387,9 @@ if [[ "${CHECK_REMOTE}" == "true" ]] && [ $_FORCE_RENEW -eq 0 ]; then enddate_lc_s=0 debug "local cert doesn't exist" fi - if [ "$enddate_ex_s" -eq "$enddate_lc_s" ]; then + if [[ "$enddate_ex_s" -eq "$enddate_lc_s" ]]; then debug "certificates expire at the same time" - elif [ "$enddate_ex_s" -gt "$enddate_lc_s" ]; then + elif [[ "$enddate_ex_s" -gt "$enddate_lc_s" ]]; then # remote has longer to expiry date than local copy. debug "remote cert has longer to run than local cert - ignoring" else @@ -1416,13 +1419,13 @@ fi # if there is an existing certificate file, check details. -if [ -s "$CERT_FILE" ]; then +if [[ -s "$CERT_FILE" ]]; then debug "certificate $CERT_FILE exists" enddate=$(openssl x509 -in "$CERT_FILE" -noout -enddate 2>/dev/null| cut -d= -f 2-) debug "local cert is valid until $enddate" if [[ "$enddate" != "-" ]]; then enddate_s=$(date_epoc "$enddate") - if [[ $(date_renew) -lt "$enddate_s" ]] && [ $_FORCE_RENEW -ne 1 ]; then + if [[ $(date_renew) -lt "$enddate_s" ]] && [[ $_FORCE_RENEW -ne 1 ]]; then info "certificate for $DOMAIN is still valid for more than $RENEW_ALLOW days (until $enddate)" # everything is OK, so exit. graceful_exit @@ -1436,7 +1439,7 @@ fi # create account key if it doesn't exist. -if [ -s "$ACCOUNT_KEY" ]; then +if [[ -s "$ACCOUNT_KEY" ]]; then debug "Account key exists at $ACCOUNT_KEY skipping generation" else info "creating account key $ACCOUNT_KEY" @@ -1445,11 +1448,11 @@ fi # if not reusing priavte key, then remove the old keys -if [ "$REUSE_PRIVATE_KEY" != "true" ]; then - if [ -s "$DOMAIN_DIR/${DOMAIN}.key" ]; then +if [[ "$REUSE_PRIVATE_KEY" != "true" ]]; then + if [[ -s "$DOMAIN_DIR/${DOMAIN}.key" ]]; then rm -f "$DOMAIN_DIR/${DOMAIN}.key" fi - if [ -s "$DOMAIN_DIR/${DOMAIN}.ec.key" ]; then + if [[ -s "$DOMAIN_DIR/${DOMAIN}.ec.key" ]]; then rm -f "$DOMAIN_DIR/${DOMAIN}.ecs.key" fi fi @@ -1465,7 +1468,7 @@ fi #create SAN -if [ -z "$SANS" ]; then +if [[ -z "$SANS" ]]; then SANLIST="subjectAltName=DNS:${DOMAIN}" else SANLIST="subjectAltName=DNS:${DOMAIN},DNS:${SANS//,/,DNS:}" @@ -1478,7 +1481,7 @@ alldomains=$(echo "$DOMAIN,$SANS" | sed "s/,/ /g") # check domain and san list for duplicates echo "" > "$TEMP_DIR/sanlist" for d in $alldomains; do - if [ "$(grep "^${d}$" "$TEMP_DIR/sanlist")" = "$d" ]; then + if [[ "$(grep "^${d}$" "$TEMP_DIR/sanlist")" = "$d" ]]; then error_exit "$d appears to be duplicated in domain, SAN list" else echo "$d" >> "$TEMP_DIR/sanlist" @@ -1486,9 +1489,9 @@ for d in $alldomains; do # check nslookup for domains (ignore if using DNS check, as site may not be published yet) if [[ $VALIDATE_VIA_DNS != "true" ]]; then debug "checking nslookup for ${d}" - if [ "$(nslookup -query=AAAA "${d}"|grep -c "^${d}.*has AAAA address")" -ge 1 ]; then + if [[ "$(nslookup -query=AAAA "${d}"|grep -c "^${d}.*has AAAA address")" -ge 1 ]]; then debug "found IPv6 record for ${d}" - elif [ "$(nslookup "${d}"| grep -c ^Name)" -ge 1 ]; then + elif [[ "$(nslookup "${d}"| grep -c ^Name)" -ge 1 ]]; then debug "found IPv4 record for ${d}" else error_exit "DNS lookup failed for $d" @@ -1513,7 +1516,7 @@ fi # currently the code registers every time, and gets an "already registered" back if it has been. get_signing_params "$ACCOUNT_KEY" -if [ "$ACCOUNT_EMAIL" ] ; then +if [[ "$ACCOUNT_EMAIL" ]] ; then regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' else regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' @@ -1521,16 +1524,16 @@ fi info "Registering account" regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' -if [ "$ACCOUNT_EMAIL" ] ; then +if [[ "$ACCOUNT_EMAIL" ]] ; then regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' fi # send the request to the ACME server. send_signed_request "$CA/acme/new-reg" "$regjson" -if [ "$code" == "" ] || [ "$code" == '201' ] ; then +if [[ "$code" == "" ]] || [[ "$code" == '201' ]] ; then info "Registered" echo "$response" > "$TEMP_DIR/account.json" -elif [ "$code" == '409' ] ; then +elif [[ "$code" == '409' ]] ; then debug "Already registered" else error_exit "Error registering account ... $(json_get "$response" detail)" @@ -1564,7 +1567,7 @@ for d in $alldomains; do error_exit "DNS_DEL_COMMAND not defined for domain $d" fi else - if [ -z "${DOMAIN_ACL}" ]; then + if [[ -z "${DOMAIN_ACL}" ]]; then error_exit "ACL location not specified for domain $d in $DOMAIN_DIR/getssl.cfg" else debug "domain $d has ACL = ${DOMAIN_ACL}" @@ -1576,7 +1579,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 [[ ! -z "$code" ]] && [[ ! "$code" == '201' ]] ; then error_exit "new-authz error: $response" fi @@ -1589,7 +1592,7 @@ for d in $alldomains; do debug "deactivate list is now $deactivate_url_list" fi # increment domain-counter - let dn=dn+1; + ((dn++)) else PREVIOUSLY_VALIDATED="false" if [[ $VALIDATE_VIA_DNS == "true" ]]; then # set up the correct DNS token for verification @@ -1617,7 +1620,7 @@ for d in $alldomains; do fi # find a primary / authoritative DNS server for the domain - if [ -z "$AUTH_DNS_SERVER" ]; then + if [[ -z "$AUTH_DNS_SERVER" ]]; then get_auth_dns "$d" else primary_ns="$AUTH_DNS_SERVER" @@ -1625,7 +1628,7 @@ for d in $alldomains; do debug primary_ns "$primary_ns" # make a directory to hold pending dns-challenges - if [ ! -d "$TEMP_DIR/dns_verify" ]; then + if [[ ! -d "$TEMP_DIR/dns_verify" ]]; then mkdir "$TEMP_DIR/dns_verify" fi @@ -1665,7 +1668,7 @@ for d in $alldomains; do debug wellknown_url "$wellknown_url" # check that we can reach the challenge ourselves, if not, then error - if [ ! "$(curl -k --silent --location "$wellknown_url")" == "$keyauthorization" ]; then + if [[ ! "$(curl -k --silent --location "$wellknown_url")" == "$keyauthorization" ]]; then error_exit "for some reason could not reach $wellknown_url - please check it manually" fi @@ -1698,7 +1701,7 @@ for d in $alldomains; do fi fi # increment domain-counter - let dn=dn+1; + ((dn++)) fi done # end of ... loop through domains for cert ( from SANS list) @@ -1706,7 +1709,7 @@ done # end of ... loop through domains for cert ( from SANS list) 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 - if [ -e "$dnsfile" ]; then + if [[ -e "$dnsfile" ]]; then debug "loading DNSfile: $dnsfile" # shellcheck source=/dev/null . "$dnsfile" @@ -1716,7 +1719,7 @@ if [[ $VALIDATE_VIA_DNS == "true" ]]; then debug "checking dns at $ns" ntries=0 check_dns="fail" - while [ "$check_dns" == "fail" ]; do + while [[ "$check_dns" == "fail" ]]; do if [[ "$os" == "cygwin" ]]; then check_result=$(nslookup -type=txt "_acme-challenge.${d}" "${ns}" \ | grep ^_acme -A2\ @@ -1733,7 +1736,8 @@ if [[ $VALIDATE_VIA_DNS == "true" ]]; then else if [[ $ntries -lt 100 ]]; then ntries=$(( ntries + 1 )) - info "checking DNS at ${ns} for ${d}. Attempt $ntries/100 gave wrong result, waiting $DNS_WAIT secs before checking again" + info "checking DNS at ${ns} for ${d}. Attempt $ntries/100 gave wrong result, "\ + "waiting $DNS_WAIT secs before checking again" sleep $DNS_WAIT else debug "dns check failed - removing existing value" @@ -1752,7 +1756,7 @@ if [[ $VALIDATE_VIA_DNS == "true" ]]; then # loop through dns-variable files to let the ACME server check the challenges for dnsfile in $TEMP_DIR/dns_verify/*; do - if [ -e "$dnsfile" ]; then + if [[ -e "$dnsfile" ]]; then debug "loading DNSfile: $dnsfile" # shellcheck source=/dev/null . "$dnsfile" @@ -1795,19 +1799,19 @@ 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 [[ ! -z "$DOMAIN_CERT_LOCATION" ]]; then copy_file_to_location "ec domain certificate" "${CERT_FILE::-4}.ec.crt" "${DOMAIN_CERT_LOCATION::-4}.ec.crt" fi - if [ ! -z "$DOMAIN_KEY_LOCATION" ]; then + if [[ ! -z "$DOMAIN_KEY_LOCATION" ]]; then copy_file_to_location "ec private key" "$DOMAIN_DIR/${DOMAIN}.ec.key" "${DOMAIN_KEY_LOCATION::-4}.ec.key" fi - if [ ! -z "$CA_CERT_LOCATION" ]; then + if [[ ! -z "$CA_CERT_LOCATION" ]]; then copy_file_to_location "ec CA certificate" "${CA_CERT::-4}.ec.crt" "${CA_CERT_LOCATION::-4}.ec.crt" fi fi # if DOMAIN_CHAIN_LOCATION is not blank, then create and copy file. -if [ ! -z "$DOMAIN_CHAIN_LOCATION" ]; then +if [[ ! -z "$DOMAIN_CHAIN_LOCATION" ]]; then if [[ "$(dirname "$DOMAIN_CHAIN_LOCATION")" == "." ]]; then to_location="${DOMAIN_DIR}/${DOMAIN_CHAIN_LOCATION}" else @@ -1817,7 +1821,7 @@ if [ ! -z "$DOMAIN_CHAIN_LOCATION" ]; then copy_file_to_location "full chain" "$TEMP_DIR/${DOMAIN}_chain.pem" "$to_location" fi # if DOMAIN_KEY_CERT_LOCATION is not blank, then create and copy file. -if [ ! -z "$DOMAIN_KEY_CERT_LOCATION" ]; then +if [[ ! -z "$DOMAIN_KEY_CERT_LOCATION" ]]; then if [[ "$(dirname "$DOMAIN_KEY_CERT_LOCATION")" == "." ]]; then to_location="${DOMAIN_DIR}/${DOMAIN_KEY_CERT_LOCATION}" else @@ -1827,7 +1831,7 @@ if [ ! -z "$DOMAIN_KEY_CERT_LOCATION" ]; then copy_file_to_location "private key and domain cert pem" "$TEMP_DIR/${DOMAIN}_K_C.pem" "$to_location" fi # if DOMAIN_PEM_LOCATION is not blank, then create and copy file. -if [ ! -z "$DOMAIN_PEM_LOCATION" ]; then +if [[ ! -z "$DOMAIN_PEM_LOCATION" ]]; then if [[ "$(dirname "$DOMAIN_PEM_LOCATION")" == "." ]]; then to_location="${DOMAIN_DIR}/${DOMAIN_PEM_LOCATION}" else @@ -1854,7 +1858,7 @@ if [[ "$DEACTIVATE_AUTH" == "true" ]]; then debug "deactivating $deactivate_url" send_signed_request "$deactivate_url" "{\"resource\": \"authz\", \"status\": \"deactivated\"}" # check response - if [ "$code" == "200" ]; then + if [[ "$code" == "200" ]]; then debug "Authorization deactivated" else error_exit "$domain: Deactivation error: $code" @@ -1864,15 +1868,15 @@ fi # end of deactivating authorizations - - # Check if the certificate is installed correctly if [[ ${CHECK_REMOTE} == "true" ]]; then sleep "$CHECK_REMOTE_WAIT" # shellcheck disable=SC2086 - CERT_REMOTE=$(echo | openssl s_client -servername "${DOMAIN}" -connect "${DOMAIN}:${REMOTE_PORT}" ${REMOTE_EXTRA} 2>/dev/null | openssl x509 -noout -fingerprint 2>/dev/null) + CERT_REMOTE=$(echo \ + | openssl s_client -servername "${DOMAIN}" -connect "${DOMAIN}:${REMOTE_PORT}" ${REMOTE_EXTRA} 2>/dev/null \ + | openssl x509 -noout -fingerprint 2>/dev/null) CERT_LOCAL=$(openssl x509 -noout -fingerprint < "$CERT_FILE" 2>/dev/null) - if [ "$CERT_LOCAL" == "$CERT_REMOTE" ]; then + if [[ "$CERT_LOCAL" == "$CERT_REMOTE" ]]; then info "${DOMAIN} - certificate installed OK on server" else error_exit "${DOMAIN} - certificate obtained but certificate on server is different from the new certificate"