From 8dce14187d091d2371975df0fee787ba43e68240 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Thu, 9 Jul 2026 13:13:15 +0200 Subject: [PATCH 1/5] Fix confusion when scanning TLS-1.3-only hosts When scanning hosts which offer only TLS 1.3 under some circumstances (e.g. using MacOS) the scan stopped and prompted the user . It happened always when $OPENSSL supported TLS 1.3. It did not when this was not the case. This fixes that (see #3083) for 3.3dev by just skipping the rest in determine_optimal_proto() when TLS13_ONLY is true. Also it fixes missing line feeds for servoce detecttion and order in which DNS HTTPS RR are displayed. --- testssl.sh | 146 ++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 75 deletions(-) diff --git a/testssl.sh b/testssl.sh index 5fc40d1..82e0baa 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2623,13 +2623,13 @@ service_detection() { fi jsonID="service" + if [[ $SERVICE == HTTP ]] || "$ASSUME_HTTP" || [[ -n "$MTLS" ]]; then + dns_https_rr + fi case $SERVICE in HTTP) - if [[ $SERVICE == HTTP ]]; then - dns_https_rr - fi pr_bold " Service detected" - out ": $CORRECT_SPACES $SERVICE" + outln ": $CORRECT_SPACES $SERVICE" fileout "${jsonID}" "INFO" "$SERVICE" ;; IMAP|POP|SMTP|NNTP|MongoDB) @@ -2637,32 +2637,28 @@ service_detection() { out ": $CORRECT_SPACES $SERVICE, thus skipping HTTP specific checks" fileout "${jsonID}" "INFO" "$SERVICE, thus skipping HTTP specific checks" ;; -#FIXME: \/ \/ dns_https_rr *) pr_bold " Service detected:"; out " $CORRECT_SPACES" - if [[ ! -z $MTLS ]]; then - out " not identified, but mTLS authentication is set ==> trying HTTP checks" + if [[ -n "$MTLS" ]]; then + outln " not identified, but mTLS authentication is set ==> trying HTTP checks" SERVICE=HTTP fileout "${jsonID}" "DEBUG" "Couldn't determine service -- ASSUME_HTTP set" - dns_https_rr elif [[ "$CLIENT_AUTH" == required ]] && [[ -z $MTLS ]]; then - out " certificate-based authentication without providing client certificate and private key => skipping all HTTP checks" | tee $TMPFILE + outln " certificate-based authentication without providing client certificate and private key => skipping all HTTP checks" | tee $TMPFILE fileout "${jsonID}" "INFO" "certificate-based authentication without providing client certificate and private key => skipping all HTTP checks" else out " Couldn't determine what's running on port $PORT" if "$ASSUME_HTTP"; then SERVICE=HTTP - out " -- ASSUME_HTTP set though" + outln " -- ASSUME_HTTP set though" fileout "${jsonID}" "DEBUG" "Couldn't determine service -- ASSUME_HTTP set" - dns_https_rr else - out ", assuming no HTTP service => skipping all HTTP checks" + outln ", assuming no HTTP service => skipping all HTTP checks" fileout "${jsonID}" "DEBUG" "Couldn't determine service, skipping all HTTP checks" fi fi ;; esac - outln tmpfile_handle ${FUNCNAME[0]}.txt return 0 } @@ -23891,80 +23887,80 @@ determine_optimal_proto() { TLS12_CIPHER_OFFERED="$(get_cipher $TMPFILE)" TLS12_CIPHER_OFFERED="$(openssl2hexcode "$TLS12_CIPHER_OFFERED")" [[ ${#TLS12_CIPHER_OFFERED} -eq 9 ]] && TLS12_CIPHER_OFFERED="${TLS12_CIPHER_OFFERED:2:2},${TLS12_CIPHER_OFFERED:7:2}" || TLS12_CIPHER_OFFERED="" - fi - if [[ "$optimal_proto" == -ssl2 ]]; then - prln_magenta "$NODEIP:$PORT appears to only support SSLv2." - fileout "$jsonID" "WARN" "$NODEIP:$PORT appears to only support SSLv2." - ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes" - [[ $? -ne 0 ]] && exit $ERR_CLUELESS - elif "$all_failed" && ! "$ALL_FAILED_SOCKETS"; then - if ! "$HAS_TLS13" && "$TLS13_ONLY"; then - if "$HAS2_TLS13"; then - if "$OSSL_SHORTCUT" || [[ "$WARNINGS" == batch ]]; then - # switch w/o asking - OPEN_MSG=" $NODE:$PORT appeared to support TLS 1.3 ONLY. Thus switched automagically from\n \"$OPENSSL\" to \"$OPENSSL2\"." - fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 automagically" - OPENSSL="$OPENSSL2" - find_openssl_binary - prepare_arrays - else - # now we need to ask the user - ignore_no_or_lame " Type \"yes\" to proceed with \"$OPENSSL2\" OR accept all scan problems" "yes" - if [[ $? -eq 0 ]]; then - fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 by the user" + if [[ "$optimal_proto" == -ssl2 ]]; then + prln_magenta "$NODEIP:$PORT appears to only support SSLv2." + fileout "$jsonID" "WARN" "$NODEIP:$PORT appears to only support SSLv2." + ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes" + [[ $? -ne 0 ]] && exit $ERR_CLUELESS + elif "$all_failed" && ! "$ALL_FAILED_SOCKETS"; then + if ! "$HAS_TLS13" && "$TLS13_ONLY"; then + if "$HAS2_TLS13"; then + if "$OSSL_SHORTCUT" || [[ "$WARNINGS" == batch ]]; then + # switch w/o asking + OPEN_MSG=" $NODE:$PORT appeared to support TLS 1.3 ONLY. Thus switched automagically from\n \"$OPENSSL\" to \"$OPENSSL2\"." + fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 automagically" OPENSSL="$OPENSSL2" find_openssl_binary prepare_arrays else - fileout "$jsonID" "WARN" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 was denied by user" + # now we need to ask the user + ignore_no_or_lame " Type \"yes\" to proceed with \"$OPENSSL2\" OR accept all scan problems" "yes" + if [[ $? -eq 0 ]]; then + fileout "$jsonID" "INFO" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 by the user" + OPENSSL="$OPENSSL2" + find_openssl_binary + prepare_arrays + else + fileout "$jsonID" "WARN" "$NODE:$PORT appears to support TLS 1.3 ONLY, switching from $OPENSSL to $OPENSSL2 was denied by user" + fi fi fi - fi - elif ! "$HAS_SSL3" && [[ "$(has_server_protocol "ssl3")" -eq 0 ]] && [[ "$(has_server_protocol "tls1_3")" -ne 0 ]] && \ - [[ "$(has_server_protocol "tls1_2")" -ne 0 ]] && [[ "$(has_server_protocol "tls1_1")" -ne 0 ]] && - [[ "$(has_server_protocol "tls1")" -ne 0 ]]; then - prln_warning " $NODE:$PORT appears to support SSLv3 ONLY. You better use --openssl=" - fileout "$jsonID" "WARN" "$NODE:$PORT appears to support SSLv3 ONLY, but $OPENSSL does not support SSLv3." - ignore_no_or_lame " Type \"yes\" to proceed and accept all scan problems" "yes" - [[ $? -ne 0 ]] && exit $ERR_CLUELESS - MAX_OSSL_FAIL=10 - else - outln - prln_warning " Your $OPENSSL cannot connect to $NODEIP:$PORT." - if [[ -x $OPENSSL2 ]] ; then - outln " Restarting with --openssl=$OPENSSL2 likely helps" - fileout "$jsonID" "WARN" "$OPENSSL cannot connect to $NODEIP:$PORT. Recommended using --openssl=$OPENSSL2" + elif ! "$HAS_SSL3" && [[ "$(has_server_protocol "ssl3")" -eq 0 ]] && [[ "$(has_server_protocol "tls1_3")" -ne 0 ]] && \ + [[ "$(has_server_protocol "tls1_2")" -ne 0 ]] && [[ "$(has_server_protocol "tls1_1")" -ne 0 ]] && + [[ "$(has_server_protocol "tls1")" -ne 0 ]]; then + prln_warning " $NODE:$PORT appears to support SSLv3 ONLY. You better use --openssl=" + fileout "$jsonID" "WARN" "$NODE:$PORT appears to support SSLv3 ONLY, but $OPENSSL does not support SSLv3." + ignore_no_or_lame " Type \"yes\" to proceed and accept all scan problems" "yes" + [[ $? -ne 0 ]] && exit $ERR_CLUELESS + MAX_OSSL_FAIL=10 else - fileout "$jsonID" "WARN" "Your $OPENSSL cannot connect to $NODEIP:$PORT." + outln + prln_warning " Your $OPENSSL cannot connect to $NODEIP:$PORT." + if [[ -x $OPENSSL2 ]] ; then + outln " Restarting with --openssl=$OPENSSL2 likely helps" + fileout "$jsonID" "WARN" "$OPENSSL cannot connect to $NODEIP:$PORT. Recommended using --openssl=$OPENSSL2" + else + fileout "$jsonID" "WARN" "Your $OPENSSL cannot connect to $NODEIP:$PORT." + fi + outln + ignore_no_or_lame " If you continue the results are likely not correct. Really proceed ? (\"yes\" to continue)" "yes" + [[ $? -ne 0 ]] && exit $ERR_CLUELESS fi + elif "$all_failed"; then outln - ignore_no_or_lame " If you continue the results are likely not correct. Really proceed ? (\"yes\" to continue)" "yes" + if "$IPv6_OK"; then + pr_bold " Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT " + fileout "$jsonID" "WARN" "Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT doesn't seem to be a TLS/SSL enabled server." + else + pr_bold " $NODEIP:$PORT " + fileout "$jsonID" "WARN" "$NODEIP:$PORT doesn't seem to be a TLS/SSL enabled server." + fi + tmpfile_handle ${FUNCNAME[0]}.txt + prln_bold "doesn't seem to be a TLS/SSL enabled server"; + ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes" + [[ $? -ne 0 ]] && exit $ERR_CLUELESS + elif ! "$all_failed" && "$ALL_FAILED_SOCKETS" && ! "$SSL_NATIVE"; then + # Edge case: connecting with tls_sockets/sslv2_sockets didn't work, but connecting with $OPENSSL s_client did. + # See #2807 + prln_warning "This shouldn't happen (pls report): Testing $NODE:$PORT only succeeded using $OPENSSL." + prln_warning "But testssl.sh also needs bash sockets to perform its checks correctly.\n" + outln "You can try to continue using the --ssl-native option but the results are likely not complete." + outln "Or you can restart using --ssl-native with another openssl version (--openssl )." + fileout "$jsonID" "WARN" "Sockets didn't work. Testing NODE:$PORT only succeeded using $OPENSSL." + ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes" [[ $? -ne 0 ]] && exit $ERR_CLUELESS fi - elif "$all_failed"; then - outln - if "$IPv6_OK"; then - pr_bold " Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT " - fileout "$jsonID" "WARN" "Your $OPENSSL is not IPv6 aware, or $NODEIP:$PORT doesn't seem to be a TLS/SSL enabled server." - else - pr_bold " $NODEIP:$PORT " - fileout "$jsonID" "WARN" "$NODEIP:$PORT doesn't seem to be a TLS/SSL enabled server." - fi - tmpfile_handle ${FUNCNAME[0]}.txt - prln_bold "doesn't seem to be a TLS/SSL enabled server"; - ignore_no_or_lame " The results might look ok but they could be nonsense. Really proceed ? (\"yes\" to continue)" "yes" - [[ $? -ne 0 ]] && exit $ERR_CLUELESS - elif ! "$all_failed" && "$ALL_FAILED_SOCKETS" && ! "$SSL_NATIVE"; then - # Edge case: connecting with tls_sockets/sslv2_sockets didn't work, but connecting with $OPENSSL s_client did. - # See #2807 - prln_warning "This shouldn't happen (pls report): Testing $NODE:$PORT only succeeded using $OPENSSL." - prln_warning "But testssl.sh also needs bash sockets to perform its checks correctly.\n" - outln "You can try to continue using the --ssl-native option but the results are likely not complete." - outln "Or you can restart using --ssl-native with another openssl version (--openssl )." - fileout "$jsonID" "WARN" "Sockets didn't work. Testing NODE:$PORT only succeeded using $OPENSSL." - ignore_no_or_lame " Type \"yes\" to proceed and accept false negatives or positives" "yes" - [[ $? -ne 0 ]] && exit $ERR_CLUELESS fi tmpfile_handle ${FUNCNAME[0]}.txt From d7f5095042de3199f64fa7fb04e6c1c62c44325b Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Fri, 10 Jul 2026 13:40:03 +0200 Subject: [PATCH 2/5] Exempt MacOS with LibreSSL to run STARTTLS via LDAP --- t/21_baseline_starttls.t | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/t/21_baseline_starttls.t b/t/21_baseline_starttls.t index 0946a52..7feffc6 100755 --- a/t/21_baseline_starttls.t +++ b/t/21_baseline_starttls.t @@ -122,14 +122,17 @@ $socket_out =~ s/ error querying OCSP responder .*\n//g; unlike($socket_out, qr/$socket_regex_bl/, ""); $tests++; -#7 -# https://ldapwiki.com/wiki/Public%20LDAP%20Servers -$uri="db.debian.org:389"; -printf "\n%s\n", "STARTTLS LDAP unit tests via sockets --> $uri ..."; -$socket_out = `$prg $check2run -t ldap $uri 2>&1`; -# $socket_json = json('tmp.json'); -unlike($socket_out, qr/$socket_regex_bl/, ""); -$tests++; +# /usr/bin/openssl on MacOS doesn't seem to be availabe (anymore) +if ( $os ne "darwin" ){ + #7 + # https://ldapwiki.com/wiki/Public%20LDAP%20Servers + $uri="db.debian.org:389"; + printf "\n%s\n", "STARTTLS LDAP unit tests via sockets --> $uri ..."; + $socket_out = `$prg $check2run -t ldap $uri 2>&1`; + # $socket_json = json('tmp.json'); + unlike($socket_out, qr/$socket_regex_bl/, ""); + $tests++; +} # For NNTP there doesn't seem to be reliable host out there #$uri="144.76.182.167:119"; From cbd2b4da1e0a26befb2ebc957b6a1275128bd38f Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Fri, 10 Jul 2026 13:46:05 +0200 Subject: [PATCH 3/5] Add HAS_LDAP to global vars ... and bail out if it is not supported. --- testssl.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index 82e0baa..aad955a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -361,6 +361,7 @@ HAS_ALPN=false HAS_NPN=false HAS_FALLBACK_SCSV=false HAS_PROXY=false +HAS_LDAP=false HAS_XMPP=false HAS_XMPP_SERVER=false HAS_POSTGRES=false @@ -21486,6 +21487,7 @@ find_openssl_binary() { HAS_NPN=false HAS_FALLBACK_SCSV=false HAS_PROXY=false + HAS_LDAP=false HAS_XMPP=false HAS_XMPP_SERVER=false HAS_XMPP_SERVER2=false @@ -21621,6 +21623,8 @@ find_openssl_binary() { grep -q 'xmpp' $s_client_starttls_has && HAS_XMPP=true grep -Eq 'xmpp-server|xmpp\[-server\]' $s_client_starttls_has && HAS_XMPP_SERVER=true + # Seems like LibreSSL on MacOS somehow lost this with 26.5.2? + grep -q 'ldap' $s_client_has && HAS_LDAP=false grep -q 'postgres' $s_client_starttls_has && HAS_POSTGRES=true grep -q 'mysql' $s_client_starttls_has && HAS_MYSQL=true grep -q 'lmtp' $s_client_starttls_has && HAS_LMTP=true @@ -24091,7 +24095,7 @@ determine_service() { if "$HAS_XMPP"; then # small hack -- instead of changing calls all over the place STARTTLS="$STARTTLS -xmpphost $NODE" - else + llelse # If the XMPP name cannot be provided using -xmpphost, # then it needs to be provided to the -connect option NODEIP="$NODE" @@ -24101,6 +24105,11 @@ determine_service() { #FIXME: make use of HAS_XMPP_SERVER2 fatal "Your $OPENSSL does not support the \"-starttls xmpp-server\" option" $ERR_OSSLBIN fi + elif [[ "$protocol" == ldap ]]; then + # Check if openssl version supports postgres. + if ! "$HAS_LDAP"; then + fatal "Your $OPENSSL does not support the \"-starttls ldap\" option" $ERR_OSSLBIN + fi elif [[ "$protocol" == postgres ]]; then # Check if openssl version supports postgres. if ! "$HAS_POSTGRES"; then From d1da2c1dea65597efb95c98a36e84ab0833dc30f Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Fri, 10 Jul 2026 13:55:33 +0200 Subject: [PATCH 4/5] fix spelling --- t/21_baseline_starttls.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/21_baseline_starttls.t b/t/21_baseline_starttls.t index 7feffc6..ee1a0ac 100755 --- a/t/21_baseline_starttls.t +++ b/t/21_baseline_starttls.t @@ -122,7 +122,7 @@ $socket_out =~ s/ error querying OCSP responder .*\n//g; unlike($socket_out, qr/$socket_regex_bl/, ""); $tests++; -# /usr/bin/openssl on MacOS doesn't seem to be availabe (anymore) +# /usr/bin/openssl on MacOS doesn't seem to be available (anymore) if ( $os ne "darwin" ){ #7 # https://ldapwiki.com/wiki/Public%20LDAP%20Servers From 0ddba7301e65e9c011148d8a1c488ce75cb6f212 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Fri, 10 Jul 2026 15:22:34 +0200 Subject: [PATCH 5/5] =?UTF-8?q?Fix=20double=20mistake=20=F0=9F=99=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index aad955a..fa167e9 100755 --- a/testssl.sh +++ b/testssl.sh @@ -21624,7 +21624,7 @@ find_openssl_binary() { grep -Eq 'xmpp-server|xmpp\[-server\]' $s_client_starttls_has && HAS_XMPP_SERVER=true # Seems like LibreSSL on MacOS somehow lost this with 26.5.2? - grep -q 'ldap' $s_client_has && HAS_LDAP=false + grep -q 'ldap' $s_client_starttls_has && HAS_LDAP=true grep -q 'postgres' $s_client_starttls_has && HAS_POSTGRES=true grep -q 'mysql' $s_client_starttls_has && HAS_MYSQL=true grep -q 'lmtp' $s_client_starttls_has && HAS_LMTP=true