From ed8f26b2f68dfaa0aa315c2a7a9b89266cedbc6d Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 28 Jan 2019 18:31:57 +0100 Subject: [PATCH] Improve standard cipher lists section To finalize #1157 following was done * move 3DES one line above * put 128 bit CBC ciphers (ARIA, Camellie and AES) SEED and IDEA into 128Bit * the remaining 256 bit ciphers NOT supporting AEAD Mac into high Also 128 bit ciphers are getting a small complaint (LOW, yellow) if available instead of red (for SEED and IDEA before) To ease the (future) output rated_output() is included, but it's not being used yet. Also often I have docker hosts for testing. If I use them while the external network is down, I still experience DNS timeouts. I added for dig timeout values which proved to be reasonable in my tests with and without network. Also if an IPv4 or an IPv6 address was supplied testssl.sh doesn't do (futile) DNS lookups anymore. --- testssl.sh | 109 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 27 deletions(-) diff --git a/testssl.sh b/testssl.sh index 0e82f6c8..a908ae45 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2987,7 +2987,7 @@ sub_cipherlists() { if [[ -n "$6" ]] || listciphers "$1" "$2" $proto; then if [[ -z "$6" ]] || ( "$FAST" && listciphers "$1" "$2" -tls1 ); then for proto in -no_ssl2 -tls1_2 -tls1_1 -tls1 -ssl3; do - if [[ "$proto" == "-tls1_2" ]]; then + if [[ "$proto" == -tls1_2 ]]; then # If $OPENSSL doesn't support TLSv1.3 or if no TLSv1.3 # ciphers are being tested, then a TLSv1.2 ClientHello # was tested in the first iteration. @@ -3061,24 +3061,23 @@ sub_cipherlists() { fileout "${jsonID}_$5" "MEDIUM" "not offered" fi ;; - 1) if [[ $sclient_success -eq 0 ]]; then # High is good to offer pr_svrty_good "offered (OK)" fileout "${jsonID}_$5" "OK" "offered" else - # FIXME: the rating could be readjusted if we knew the result of STRONG before + # FIXME: we penalize the absence of high but don't know the result of strong encryption yet (next) pr_svrty_medium "not offered" fileout "${jsonID}_$5" "MEDIUM" "not offered" fi ;; 0) if [[ $sclient_success -eq 0 ]]; then # medium is not that bad - pr_svrty_medium "offered" - fileout "${jsonID}_$5" "MEDIUM" "offered" + pr_svrty_low "offered" + fileout "${jsonID}_$5" "LOW" "offered" else - out "not offered (OK)" - fileout "${jsonID}_$5" "OK" "not offered" + out "not offered" + fileout "${jsonID}_$5" "INFO" "not offered" fi ;; -1) if [[ $sclient_success -eq 0 ]]; then @@ -3122,6 +3121,48 @@ sub_cipherlists() { return $ret } +# Generic function for a rated output, no used yet. +# arg1: rating from 2 to -4 if available or not +# arg2: no/yes: decides whether positive or negative logic will be applied and "not" will be printed +# arg3: jsonID +# +rated_output() { + local jsonID=$3 + local logic="" + + if [[ $2 == no ]] || [[ $2 == negative ]]; then + logic="not " + fi + case $1 in + 2) pr_svrty_best "${logic}offered (OK)" + fileout "${jsonID}" "OK" "${logic}offered" + ;; + 1) pr_svrty_good "${logic}offered (OK)" + fileout "${jsonID}" "OK" "${logic}offered" + ;; + 0) out "${logic}offered" + fileout "${jsonID}" "INFO" "${logic}offered" + ;; + -1) pr_svrty_low "${logic}offered" + fileout "${jsonID}" "LOW" "${logic}offered" + ;; + -2) pr_svrty_medium "${logic}offered" + fileout "${jsonID}" "MEDIUM" "${logic}offered" + ;; + -3) pr_svrty_high "${logic}offered (NOT ok)" + fileout "${jsonID}" "HIGH" "${logic}offered" + ;; + -4) pr_svrty_critical "${logic}offered (NOT ok)" + fileout "${jsonID}" "CRITICAL" "${logic}offered" + ;; + *) pr_warning "FIXME: error around $LINENO, (please report this)" + fileout "${jsonID}" "WARN" "return condition $2 when $1 unclear" + return 1 + ;; + esac + return 0 +} + openssl2rfc() { local rfcname="" @@ -5381,22 +5422,22 @@ run_cipherlists() { # ~ egrep -w '64|56|RC2|RC4' etc/cipher-mapping.txt | grep -v export local low_ciphers="00,15, 00,12, 00,0f, 00,0c, 00,09, 00,1e, 00,22, fe,fe, ff,e1, c0,11, c0,07, 00,66, c0,0c, c0,02, 00,05, 00,04, 00,92, 00,8a, 00,20, 00,24, c0,33, 00,8e, 00,ff" local sslv2_low_ciphers="01,00,80, 03,00,80, 08,00,80, 06,00,40, 06,01,40, FF,80,00" - # ~ egrep -w 128 etc/cipher-mapping.txt | egrep -v "Au=None|AEAD|ARIA|Camellia|AES|RC2|RC4" - local medium_ciphers="00,9a, 00,99, 00,98, 00,97, 00,96, 00,07, 00,21, 00,25, 00,ff" - local sslv2_medium_ciphers="05,00,80" # ~ egrep -w '3DES' etc/cipher-mapping.txt local tdes_ciphers="c0,12, c0,08, c0,1c, c0,1b, c0,1a, 00,16, 00,13, 00,10, 00,0d, c0,0d, c0,03, 00,0a, 00,93, 00,8b, 00,1f, 00,23, c0,34, 00,8f, fe,ff, ff,e0, 00,ff" local sslv2_tdes_ciphers="07,00,c0, 07,01,c0" - # ~ equivalent to 'egrep -w "GOST|128|256" etc/cipher-mapping.txt | grep -v '=None' | egrep -vw 'RC4|AEAD|IDEA|SEED|RC2'. Attention: 127 ciphers currently - local high_ciphers="c0,28, c0,24, c0,14, c0,0a, c0,22, c0,21, c0,20, 00,b7, 00,b3, 00,91, c0,9b, c0,99, c0,97, 00,af, c0,95, 00,6b, 00,6a, 00,69, 00,68, 00,39, 00,38, 00,37, 00,36, c0,77, c0,73, 00,c4, 00,c3, 00,c2, 00,c1, 00,88, 00,87, 00,86, 00,85, c0,2a, c0,26, c0,0f, c0,05, c0,79, c0,75, 00,3d, 00,35, 00,c0, c0,38, c0,36, 00,84, 00,95, 00,8d, c0,3d, c0,3f, c0,41, c0,43, c0,45, c0,49, c0,4b, c0,4d, c0,4f, c0,65, c0,67, c0,69, c0,71, 00,80, 00,81, ff,00, ff,01, ff,02, ff,03, ff,85, c0,27, c0,23, c0,13, c0,09, c0,1f, c0,1e, c0,1d, 00,67, 00,40, 00,3f, 00,3e, 00,33, 00,32, 00,31, 00,30, c0,76, c0,72, 00,be, 00,bd, 00,bc, 00,bb, 00,45, 00,44, 00,43, 00,42, c0,29, c0,25, c0,0e, c0,04, c0,78, c0,74, 00,3c, 00,2f, 00,ba, c0,37, c0,35, 00,b6, 00,b2, 00,90, 00,41, c0,9a, c0,98, c0,96, 00,ae, c0,94, 00,94, 00,8c, c0,3c, c0,3e, c0,40, c0,42, c0,44, c0,48, c0,4a, c0,4c, c0,4e, c0,64, c0,66, c0,68, c0,70" - # no SSLv2 here and in strong - # ~ equivalent to 'grep AEAD etc/cipher-mapping.txt | grep -v Au=None' + # ~ egrep -w 128 etc/cipher-mapping.txt | egrep -v "Au=None|AEAD|RC2|RC4" + local medium_ciphers="00,07, 00,21, 00,25, 00,2F, 00,30, 00,31, 00,32, 00,33, 00,3C, 00,3E, 00,3F, 00,40, 00,41, 00,42, 00,43, 00,44, 00,45, 00,67, 00,8C, 00,90, 00,94, 00,96, 00,97, 00,98, 00,99, 00,9A, 00,AE, 00,B2, 00,B6, 00,BA, 00,BB, 00,BC, 00,BD, 00,BE, C0,04, C0,09, C0,0E, C0,13, C0,1D, C0,1E, C0,1F, C0,23, C0,25, C0,27, C0,29, C0,35, C0,37, C0,3C, C0,3E, C0,40, C0,42, C0,44, C0,48, C0,4A, C0,4C, C0,4E, C0,64, C0,66, C0,68, C0,70, C0,72, C0,74, C0,76, C0,78, C0,94, C0,96, C0,98, C0,9A, 00, FF" + # Attention we have a SSLv2 cipher here: IDEA-CBC-MD5 / SSL_CK_IDEA_128_CBC_WITH_MD5 + local sslv2_medium_ciphers="05,00,80" + # ~ egrep -w "256" etc/cipher-mapping.txt | grep -v '=None' | egrep -vw 'RC4|AEAD|IDEA|SEED|RC2|GOST' + local high_ciphers="00,35, 00,36, 00,37, 00,38, 00,39, 00,3D, 00,68, 00,69, 00,6A, 00,6B, 00,84, 00,85, 00,86, 00,87, 00,88, 00,8D, 00,91, 00,95, 00,AF, 00,B3, 00,B7, 00,C0, 00,C1, 00,C2, 00,C3, 00,C4, C0,05, C0,0A, C0,0F, C0,14, C0,20, C0,21, C0,22, C0,24, C0,26, C0,28, C0,2A, C0,36, C0,38, C0,3D, C0,3F, C0,41, C0,43, C0,45, C0,49, C0,4B, C0,4D, C0,4F, C0,65, C0,67, C0,69, C0,71, C0,73, C0,75, C0,77, C0,79, C0,95, C0,97, C0,99, C0,9B" + # ~ grep AEAD etc/cipher-mapping.txt | grep -v Au=None local strong_ciphers="13,01, 13,02, 13,03, 13,04, 13,05, cc,14, cc,13, cc,15, c0,30, c0,2c, 00,a5, 00,a3, 00,a1, 00,9f, cc,a9, cc,a8, cc,aa, c0,af, c0,ad, c0,a3, c0,9f, 00,ad, 00,ab, cc,ae, cc,ad, cc,ac, c0,ab, c0,a7, c0,32, c0,2e, 00,9d, c0,a1, c0,9d, 00,a9, cc,ab, c0,a9, c0,a5, c0,51, c0,53, c0,55, c0,57, c0,59, c0,5d, c0,5f, c0,61, c0,63, c0,6b, c0,6d, c0,6f, c0,7b, c0,7d, c0,7f, c0,81, c0,83, c0,87, c0,89, c0,8b, c0,8d, c0,8f, c0,91, c0,93, 16,b7, 16,b8, 16,b9, 16,ba, c0,2f, c0,2b, 00,a4, 00,a2, 00,a0, 00,9e, c0,ae, c0,ac, c0,a2, c0,9e, 00,ac, 00,aa, c0,aa, c0,a6, c0,a0, c0,9c, 00,a8, c0,a8, c0,a4, c0,31, c0,2d, 00,9c, c0,50, c0,52, c0,54, c0,56, c0,58, c0,5c, c0,5e, c0,60, c0,62, c0,6a, c0,6c, c0,6e, c0,7a, c0,7c, c0,7e, c0,80, c0,82, c0,86, c0,88, c0,8a, c0,8c, c0,8e, c0,90, c0,92, 00,ff" local cwe="CWE-327" local cwe2="CWE-310" local cve="" - # decoding the SSLv3-TLS1.2 ciphers, e.g: + # decoding the >= SSLv3 ciphers in the code above , e.g: # echo "00,15, c0,11, fe,fe' | sed -e 's/00,/0x00,0x/g' -e 's/c0,/0xc0,0x/g' -e 's/cc,/0xcc,0x/g' -e 's/13,/0x13,0x/g' -e 's/16,/0x16,0x/g' -e 's/fe,/0xfe,0x/g' -e 's/ff,/0xff,0x/g' -e 's/, /\n/g' | \ # while read ci; do grep -wi $ci etc/cipher-mapping.txt; done @@ -5414,7 +5455,7 @@ run_cipherlists() { outln pr_headlineln " Testing cipher categories " outln - # argv[1]: cipher list to test in OpenSSL syntax (see ciphers(1ssl) or run 'openssl ciphers -v/-V)' + # argv[1]: cipher list to test in OpenSSL syntax (see ciphers(1ssl) or run 'openssl ciphers -v/-V)', TLS 1.3 ciphers will be treated automatically # argv[2]: string on console / HTML or "finding" # argv[3]: rating whether ok to offer # argv[4]: string to be appended for fileout @@ -5428,15 +5469,15 @@ run_cipherlists() { ret=$((ret + $?)) sub_cipherlists 'LOW:DES:RC2:RC4:!ADH:!EXP:!NULL' "" " LOW: 64 Bit + DES, RC[2,4] (w/o export) " -2 "LOW" "$low_ciphers" "$sslv2_low_ciphers" "$cve" "$cwe" ret=$((ret + $?)) - sub_cipherlists 'MEDIUM:!aNULL:!AES:!CAMELLIA:!ARIA:!CHACHA20:!3DES:!RC2:!RC4' \ - "" " Weak 128 Bit ciphers (SEED, IDEA) " -1 "128Bit" "$medium_ciphers" "$sslv2_medium_ciphers" "$cve" "$cwe2" + sub_cipherlists '3DES:!aNULL:!ADH' "" " Triple DES Ciphers " -1 "3DES" "$tdes_ciphers" "$sslv2_tdes_ciphers" "$cve" "$cwe2" ret=$((ret + $?)) - sub_cipherlists '3DES:!aNULL:!ADH' "" " Triple DES Ciphers (Medium) " 0 "3DES" "$tdes_ciphers" "$sslv2_tdes_ciphers" "$cve" "$cwe2" + sub_cipherlists 'MEDIUM:!aNULL:AES128:CAMELLIA128:ARIA128:!CHACHA20:!3DES:!RC2:!RC4:!AESCCM8:!AESCCM:!AESGCM:!ARIAGCM' \ + "" " 128 Bit ciphers (SEED, IDEA, 128 Bit CBC) " 0 "128Bit" "$medium_ciphers" "$sslv2_medium_ciphers" "$cve" "$cwe2" ret=$((ret + $?)) - sub_cipherlists 'HIGH:!NULL:!aNULL:!DES:!3DES:!AESGCM:!CHACHA20:!AESGCM:!CamelliaGCM:!AESCCM8:!AESCCM' \ - "" " High encryption (AES+Camellia, no AEAD) " 1 "HIGH" "$high_ciphers" "" + sub_cipherlists 'HIGH:!NULL:!aNULL:!DES:!3DES:!AESGCM:!CHACHA20:!CamelliaGCM:!AESCCM:!AESCCM8:!AES128:!CAMELLIA128:!ARIAGCM:!ARIACCM' \ + "" " High encryption (AES/Aria/Camellia, !AEAD)" 1 "HIGH" "$high_ciphers" "" ret=$((ret + $?)) - sub_cipherlists 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM' 'ALL' \ + sub_cipherlists 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM:ARIAGCM' 'ALL' \ " Strong encryption (AEAD ciphers) " 2 "STRONG" "$strong_ciphers" "" ret=$((ret + $?)) outln @@ -16482,6 +16523,11 @@ get_a_record() { echo 127.0.0.1 return 0 fi + if is_ipv4addr "$1"; then + # This saves walking through this. Also it avoids hangs e.g. if you run docker locally without reachabale DNS + echo $1 + return 0 + fi OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 check_resolver_bins if [[ "$NODE" == *.local ]]; then @@ -16495,7 +16541,7 @@ get_a_record() { fi if [[ -z "$ip4" ]]; then if type -p dig &> /dev/null ; then - ip4=$(filter_ip4_address $(dig +short -t a "$1" 2>/dev/null | awk '/^[0-9]/')) + ip4=$(filter_ip4_address $(dig +timeout=2 +tries=2 +short -t a "$1" 2>/dev/null | awk '/^[0-9]/')) fi fi if [[ -z "$ip4" ]]; then @@ -16523,6 +16569,14 @@ get_aaaa_record() { [[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 + if is_ipv6addr "$1"; then + # This saves walking through this. Also it avoids hangs e.g. if you run docker locally without reachabale DNS + echo "$1" + return 0 + elif is_ipv4addr "$1"; then + # we need also this here as get_aaaa_record is always called after get_a_record and we want to handle this at a low level + return 0 + fi check_resolver_bins if [[ -z "$ip6" ]]; then if [[ "$NODE" == *.local ]]; then @@ -16533,10 +16587,10 @@ get_aaaa_record() { else fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." $ERR_DNSBIN fi + elif type -p dig &> /dev/null; then + ip6=$(filter_ip6_address $(dig +short +timeout=2 +tries=2 -t aaaa "$1" 2>/dev/null | awk '/^[0-9]/')) elif type -p host &> /dev/null ; then ip6=$(filter_ip6_address $(host -t aaaa "$1" | awk '/address/ { print $NF }')) - elif type -p dig &> /dev/null; then - ip6=$(filter_ip6_address $(dig +short -t aaaa "$1" 2>/dev/null | awk '/^[0-9]/')) elif type -p drill &> /dev/null; then ip6=$(filter_ip6_address $(drill aaaa "$1" | awk '/ANSWER SECTION/,/AUTHORITY SECTION/ { print $NF }' | awk '/^[0-9]/')) elif type -p nslookup &>/dev/null; then @@ -16567,7 +16621,7 @@ get_caa_rr_record() { OPENSSL_CONF="" check_resolver_bins if type -p dig &> /dev/null; then - raw_caa="$(dig $1 type257 +short)" + raw_caa="$(dig +timeout=3 +tries=3 $1 type257 +short)" # empty if no CAA record elif type -p drill &> /dev/null; then raw_caa="$(drill $1 type257 | awk '/'"^${1}"'.*CAA/ { print $5,$6,$7 }')" @@ -16739,7 +16793,8 @@ determine_rdns() { rDNS=$(dig -x $nodeip @224.0.0.251 -p 5353 +notcp +noall +answer | awk '/PTR/ { print $NF }') fi elif type -p dig &> /dev/null; then - rDNS=$(dig -x $nodeip +noall +answer | awk '/PTR/ { print $NF }') # +short returns also CNAME, e.g. openssl.org + # 1+2 should suffice. It's a compromise for if e.g. network is down but we have a docker/localhost server + rDNS=$(dig -x $nodeip +timeout=1 +tries=2 +noall +answer | awk '/PTR/ { print $NF }') # +short returns also CNAME, e.g. openssl.org elif type -p host &> /dev/null; then rDNS=$(host -t PTR $nodeip 2>/dev/null | awk '/pointer/ { print $NF }') elif type -p drill &> /dev/null; then