mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-10-31 13:55:25 +01:00 
			
		
		
		
	First try for QUIC (OpenSSL only)
This is an implementation for QUIC (RFC 9000, RFC 9114). It's purely OpenSSL based for now. As some distros support newer (>= 3.2) versions this works on some distros now and will work on more as time goes by. It has been tested with MacOS and Linux. If there's an OpenSSL version in /usr/bin/ it will automagically use that version. A new short sub function named sub_quic() was introduced for handling this as run_protocols() is already "full". It appears below TLS 1.3. A check against HTTPS RR #2484 is planned but not implemented yet. PR #2484 has to be worked on and merged before. New variables were introduces (HAS_QUIC/ +HAS2_QUIC). Also there's QUIC_WAIT as we run the connect in the background and we need a wait time. HAS_UDS2 was renamed to HAS2_UDS as HAS2 should signal this is for OPENSSL2 and UDS2 doesn't make sense. To clarify: - check for a proxy and then don't do the check? - short unit test (t/31_isJSON_valid.t cjecks cloudflare but ...)
This commit is contained in:
		
							
								
								
									
										82
									
								
								testssl.sh
									
									
									
									
									
								
							
							
						
						
									
										82
									
								
								testssl.sh
									
									
									
									
									
								
							| @@ -205,6 +205,7 @@ MAX_OSSL_FAIL=${MAX_OSSL_FAIL:-2}       # If this many failures for s_client con | |||||||
| MAX_STARTTLS_FAIL=${MAX_STARTTLS_FAIL:-2}   # max number of STARTTLS handshake failures in plaintext phase | MAX_STARTTLS_FAIL=${MAX_STARTTLS_FAIL:-2}   # max number of STARTTLS handshake failures in plaintext phase | ||||||
| MAX_HEADER_FAIL=${MAX_HEADER_FAIL:-2}   # If this many failures for HTTP GET are encountered we don't try again to get the header | MAX_HEADER_FAIL=${MAX_HEADER_FAIL:-2}   # If this many failures for HTTP GET are encountered we don't try again to get the header | ||||||
| MAX_WAITSOCK=${MAX_WAITSOCK:-10}        # waiting at max 10 seconds for socket reply. There shouldn't be any reason to change this. | MAX_WAITSOCK=${MAX_WAITSOCK:-10}        # waiting at max 10 seconds for socket reply. There shouldn't be any reason to change this. | ||||||
|  | QUIC_WAIT=${QUIC_WAIT:-3}               # QUIC is UDP. Thus we run the connect in the background. This is how long to wait | ||||||
| CCS_MAX_WAITSOCK=${CCS_MAX_WAITSOCK:-5} # for the two CCS payload (each). There shouldn't be any reason to change this. | CCS_MAX_WAITSOCK=${CCS_MAX_WAITSOCK:-5} # for the two CCS payload (each). There shouldn't be any reason to change this. | ||||||
| HEARTBLEED_MAX_WAITSOCK=${HEARTBLEED_MAX_WAITSOCK:-8}      # for the heartbleed payload. There shouldn't be any reason to change this. | HEARTBLEED_MAX_WAITSOCK=${HEARTBLEED_MAX_WAITSOCK:-8}      # for the heartbleed payload. There shouldn't be any reason to change this. | ||||||
| STARTTLS_SLEEP=${STARTTLS_SLEEP:-10}    # max time wait on a socket for STARTTLS. MySQL has a fixed value of 1 which can't be overwritten (#914) | STARTTLS_SLEEP=${STARTTLS_SLEEP:-10}    # max time wait on a socket for STARTTLS. MySQL has a fixed value of 1 which can't be overwritten (#914) | ||||||
| @@ -339,6 +340,8 @@ HAS_TLS1=false | |||||||
| HAS_TLS11=false | HAS_TLS11=false | ||||||
| HAS_TLS12=false | HAS_TLS12=false | ||||||
| HAS_TLS13=false | HAS_TLS13=false | ||||||
|  | HAS_QUIC=false | ||||||
|  | HAS2_QUIC=false                         # for automagically determined second OPENSSL version | ||||||
| HAS_X448=false | HAS_X448=false | ||||||
| HAS_X25519=false | HAS_X25519=false | ||||||
| HAS_SIGALGS=false | HAS_SIGALGS=false | ||||||
| @@ -367,7 +370,7 @@ HAS_AES128_GCM=false | |||||||
| HAS_AES256_GCM=false | HAS_AES256_GCM=false | ||||||
| HAS_ZLIB=false | HAS_ZLIB=false | ||||||
| HAS_UDS=false | HAS_UDS=false | ||||||
| HAS_UDS2=false | HAS2_UDS=false | ||||||
| HAS_ENABLE_PHA=false | HAS_ENABLE_PHA=false | ||||||
| HAS_DIG=false | HAS_DIG=false | ||||||
| HAS_DIG_R=true | HAS_DIG_R=true | ||||||
| @@ -5468,6 +5471,7 @@ add_proto_offered() { | |||||||
| # arg1:    protocol string or hex code for TLS protocol | # arg1:    protocol string or hex code for TLS protocol | ||||||
| # echos:   0 if proto known being offered, 1: known not being offered, 2: we don't know yet whether proto is being offered | # echos:   0 if proto known being offered, 1: known not being offered, 2: we don't know yet whether proto is being offered | ||||||
| # return value is always zero | # return value is always zero | ||||||
|  | # | ||||||
| has_server_protocol() { | has_server_protocol() { | ||||||
|      local proto |      local proto | ||||||
|      local proto_val_pair |      local proto_val_pair | ||||||
| @@ -5502,6 +5506,7 @@ has_server_protocol() { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # the protocol check needs to be revamped. It sucks, see above | # the protocol check needs to be revamped. It sucks, see above | ||||||
|  | # | ||||||
| run_protocols() { | run_protocols() { | ||||||
|      local using_sockets=true |      local using_sockets=true | ||||||
|      local supported_no_ciph1="supported but couldn't detect a cipher (may need debugging)" |      local supported_no_ciph1="supported but couldn't detect a cipher (may need debugging)" | ||||||
| @@ -6125,10 +6130,55 @@ run_protocols() { | |||||||
|           [[ $? -ne 0 ]] && exit $ERR_CLUELESS |           [[ $? -ne 0 ]] && exit $ERR_CLUELESS | ||||||
|      fi |      fi | ||||||
| 
 | 
 | ||||||
|  |      sub_quic | ||||||
|  | 
 | ||||||
|      return $ret |      return $ret | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # We do QUIC check first purely via OpenSSL, supposed it is supported by openssl | ||||||
|  | # | ||||||
|  | sub_quic() { | ||||||
|  |      local alpn="" | ||||||
|  |      local use_openssl="" | ||||||
|  |      local sclient_outfile="$TEMPDIR/$NODEIP.quic_connect.txt" | ||||||
|  |      local sclient_errfile="$TEMPDIR/$NODEIP.quic_connect_err.txt" | ||||||
|  |      local jsonID="QUIC" | ||||||
|  | 
 | ||||||
|  |      pr_bold " QUIC       "; | ||||||
|  | 
 | ||||||
|  |      [[ $DEBUG -ne 0 ]] && sclient_errfile=/dev/null | ||||||
|  | 
 | ||||||
|  |      if "$HAS2_QUIC" || "$HAS_QUIC"; then | ||||||
|  |           # Be aware: A proxy is not supported at all | ||||||
|  |           # The s_client call would block if either the remote side doesn't support QUIC or outbound traffic is blocked | ||||||
|  |           if "$HAS2_QUIC"; then | ||||||
|  |                use_openssl="$OPENSSL2" | ||||||
|  |           else | ||||||
|  |                use_openssl="$OPENSSL" | ||||||
|  |           fi | ||||||
|  |           OPENSSL_CONF='' $use_openssl s_client -quic -alpn h3 -connect $NODEIP:$PORT -servername $NODE </dev/null \ | ||||||
|  |                2>$sclient_errfile  >$sclient_outfile & | ||||||
|  |           wait_kill $! $QUIC_WAIT | ||||||
|  |           if [[ $? -ne 0 ]]; then | ||||||
|  |                outln "not offered" | ||||||
|  |                fileout "$jsonID" "INFO" "not offered" | ||||||
|  |           else | ||||||
|  |                pr_svrty_best "offered (OK)" | ||||||
|  |                fileout "$jsonID" "OK" "offered" | ||||||
|  |                alpn="$(awk -F':' '/^ALPN protocol/ { print $2 }' < $sclient_outfile)" | ||||||
|  |                alpn="$(strip_spaces $alpn)" | ||||||
|  |                outln ": $(awk '/^Protocol:/ { print $2 }'  < $sclient_outfile) ($alpn)" | ||||||
|  |           fi | ||||||
|  |      else | ||||||
|  |           prln_local_problem "No OpenSSL QUIC support" | ||||||
|  |           fileout "$jsonID" "WARN" "not tested due to lack of local OpenSSL support" | ||||||
|  |      fi | ||||||
|  | 
 | ||||||
|  |      return 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| # list ciphers (and makes sure you have them locally configured) | # list ciphers (and makes sure you have them locally configured) | ||||||
| # arg[1]: non-TLSv1.3 cipher list (or anything else) | # arg[1]: non-TLSv1.3 cipher list (or anything else) | ||||||
| # arg[2]: TLSv1.3 cipher list | # arg[2]: TLSv1.3 cipher list | ||||||
| @@ -19900,7 +19950,7 @@ run_starttls_injection() { | |||||||
|           outln "Need socat for this check" |           outln "Need socat for this check" | ||||||
|           return 1 |           return 1 | ||||||
|      fi |      fi | ||||||
|      if ! "$HAS_UDS2" && ! "$HAS_UDS"; then |      if ! "$HAS2_UDS" && ! "$HAS_UDS"; then | ||||||
|           fileout "$jsonID" "WARN" "Need OpenSSL with Unix-domain socket s_client support for this check" "$cve" "$cwe" "$hint" |           fileout "$jsonID" "WARN" "Need OpenSSL with Unix-domain socket s_client support for this check" "$cve" "$cwe" "$hint" | ||||||
|           outln "Need an OpenSSL with Unix-domain socket s_client support for this check" |           outln "Need an OpenSSL with Unix-domain socket s_client support for this check" | ||||||
|           return 1 |           return 1 | ||||||
| @@ -19926,7 +19976,7 @@ run_starttls_injection() { | |||||||
| 
 | 
 | ||||||
|      if "$HAS_UDS"; then |      if "$HAS_UDS"; then | ||||||
|           openssl_bin="$OPENSSL" |           openssl_bin="$OPENSSL" | ||||||
|      elif "$HAS_UDS2"; then |      elif "$HAS2_UDS"; then | ||||||
|           openssl_bin="$OPENSSL2" |           openssl_bin="$OPENSSL2" | ||||||
|      fi |      fi | ||||||
|      # normally the interesting fallback we grep later for is in fd2 but we'll catch also stdout here |      # normally the interesting fallback we grep later for is in fd2 but we'll catch also stdout here | ||||||
| @@ -20684,7 +20734,7 @@ find_openssl_binary() { | |||||||
|      local s_client_has=$TEMPDIR/s_client_has.txt |      local s_client_has=$TEMPDIR/s_client_has.txt | ||||||
|      local s_client_has2=$TEMPDIR/s_client_has2.txt |      local s_client_has2=$TEMPDIR/s_client_has2.txt | ||||||
|      local s_client_starttls_has=$TEMPDIR/s_client_starttls_has.txt |      local s_client_starttls_has=$TEMPDIR/s_client_starttls_has.txt | ||||||
|      local s_client_starttls_has2=$TEMPDIR/s_client_starttls_has2 |      local s_client2_starttls_has=$TEMPDIR/s_client2_starttls_has | ||||||
|      local openssl_location="" cwd="" |      local openssl_location="" cwd="" | ||||||
|      local curve="" ossl_tls13_supported_curves |      local curve="" ossl_tls13_supported_curves | ||||||
|      local ossl_line1="" yr="" |      local ossl_line1="" yr="" | ||||||
| @@ -20831,7 +20881,7 @@ find_openssl_binary() { | |||||||
|      HAS_AES256_GCM=false |      HAS_AES256_GCM=false | ||||||
|      HAS_ZLIB=false |      HAS_ZLIB=false | ||||||
|      HAS_UDS=false |      HAS_UDS=false | ||||||
|      HAS_UDS2=false |      HAS2_UDS=false | ||||||
|      TRUSTED1ST="" |      TRUSTED1ST="" | ||||||
|      HAS_ENABLE_PHA=false |      HAS_ENABLE_PHA=false | ||||||
| 
 | 
 | ||||||
| @@ -20868,16 +20918,20 @@ find_openssl_binary() { | |||||||
|           $OPENSSL s_client -tls1_3 -sigalgs PSS+SHA256:PSS+SHA384 $NXCONNECT </dev/null 2>&1 | grep -aiq "unknown option" || HAS_SIGALGS=true |           $OPENSSL s_client -tls1_3 -sigalgs PSS+SHA256:PSS+SHA384 $NXCONNECT </dev/null 2>&1 | grep -aiq "unknown option" || HAS_SIGALGS=true | ||||||
|      fi |      fi | ||||||
| 
 | 
 | ||||||
|  |      if [[ -x $OPENSSL2 ]] && OPENSSL_CONF='' $OPENSSL2 s_client -quic 2>&1 | grep -qi 'QUIC requires ALPN'; then | ||||||
|  |           HAS2_QUIC="true" | ||||||
|  |      elif OPENSSL_CONF='' $OPENSSL s_client -quic 2>&1 | grep -qi 'QUIC requires ALPN'; then | ||||||
|  |           HAS_QUIC="true" | ||||||
|  |      fi | ||||||
|  | 
 | ||||||
|      $OPENSSL s_client -noservername </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NOSERVERNAME=true |      $OPENSSL s_client -noservername </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NOSERVERNAME=true | ||||||
|      $OPENSSL s_client -ciphersuites </dev/null 2>&1 | grep -aiq "unknown option" || HAS_CIPHERSUITES=true |      $OPENSSL s_client -ciphersuites </dev/null 2>&1 | grep -aiq "unknown option" || HAS_CIPHERSUITES=true | ||||||
| 
 |  | ||||||
|      $OPENSSL ciphers @SECLEVEL=0:ALL > /dev/null 2> /dev/null && HAS_SECLEVEL=true |  | ||||||
| 
 |  | ||||||
|      $OPENSSL s_client -comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_COMP=true |      $OPENSSL s_client -comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_COMP=true | ||||||
|      $OPENSSL s_client -no_comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NO_COMP=true |      $OPENSSL s_client -no_comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NO_COMP=true | ||||||
| 
 | 
 | ||||||
|      OPENSSL_NR_CIPHERS=$(count_ciphers "$(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL' 'ALL')") |      $OPENSSL ciphers @SECLEVEL=0:ALL > /dev/null 2> /dev/null && HAS_SECLEVEL=true | ||||||
| 
 | 
 | ||||||
|  |      OPENSSL_NR_CIPHERS=$(count_ciphers "$(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL' 'ALL')") | ||||||
|      if [[ $OPENSSL_NR_CIPHERS -le 140 ]]; then |      if [[ $OPENSSL_NR_CIPHERS -le 140 ]]; then | ||||||
|           [[ "$OSSL_NAME" =~ LibreSSL ]] && [[ ${OSSL_VER//./} -ge 210 ]] && HAS_DH_BITS=true |           [[ "$OSSL_NAME" =~ LibreSSL ]] && [[ ${OSSL_VER//./} -ge 210 ]] && HAS_DH_BITS=true | ||||||
|           if "$SSL_NATIVE"; then |           if "$SSL_NATIVE"; then | ||||||
| @@ -20981,9 +21035,9 @@ find_openssl_binary() { | |||||||
|           # We also check, whether there's $OPENSSL2 which has TLS 1.3 |           # We also check, whether there's $OPENSSL2 which has TLS 1.3 | ||||||
|           if [[ ! "$OSSL_NAME" =~ LibreSSL ]] && [[ ! $OSSL_VER =~ 1.1.1 ]] && [[ $OSSL_VER_MAJOR -lt 3 ]]; then |           if [[ ! "$OSSL_NAME" =~ LibreSSL ]] && [[ ! $OSSL_VER =~ 1.1.1 ]] && [[ $OSSL_VER_MAJOR -lt 3 ]]; then | ||||||
|                OPENSSL_CONF='' $OPENSSL2 s_client -help 2>$s_client_has2 |                OPENSSL_CONF='' $OPENSSL2 s_client -help 2>$s_client_has2 | ||||||
|                OPENSSL_CONF='' $OPENSSL2 s_client -starttls foo 2>$s_client_starttls_has2 |                OPENSSL_CONF='' $OPENSSL2 s_client -starttls foo 2>$s_client2_starttls_has | ||||||
|                grep -q 'Unix-domain socket' $s_client_has2 && HAS_UDS2=true |                grep -q 'Unix-domain socket' $s_client_has2 && HAS2_UDS=true | ||||||
|                grep -q 'xmpp-server' $s_client_starttls_has2 && HAS_XMPP_SERVER2=true |                grep -q 'xmpp-server' $s_client2_starttls_has && HAS_XMPP_SERVER2=true | ||||||
|                # Likely we don't need the following second check here, see 6 lines above |                # Likely we don't need the following second check here, see 6 lines above | ||||||
|                if grep -wq 'tls1_3' $s_client_has2; then |                if grep -wq 'tls1_3' $s_client_has2; then | ||||||
|                     OPENSSL_CONF='' OPENSSL2_HAS_TLS_1_3=true |                     OPENSSL_CONF='' OPENSSL2_HAS_TLS_1_3=true | ||||||
| @@ -21339,6 +21393,8 @@ HAS_TLS1: $HAS_TLS1 | |||||||
| HAS_TLS11: $HAS_TLS11 | HAS_TLS11: $HAS_TLS11 | ||||||
| HAS_TLS12: $HAS_TLS12 | HAS_TLS12: $HAS_TLS12 | ||||||
| HAS_TLS13: $HAS_TLS13 | HAS_TLS13: $HAS_TLS13 | ||||||
|  | HAS_QUIC: $HAS_QUIC | ||||||
|  | HAS2_QUIC: $HAS2_QUIC | ||||||
| HAS_X448: $HAS_X448 | HAS_X448: $HAS_X448 | ||||||
| HAS_X25519: $HAS_X25519 | HAS_X25519: $HAS_X25519 | ||||||
| HAS_SIGALGS: $HAS_SIGALGS | HAS_SIGALGS: $HAS_SIGALGS | ||||||
| @@ -21363,7 +21419,7 @@ HAS_SIEVE: $HAS_SIEVE | |||||||
| HAS_NNTP: $HAS_NNTP | HAS_NNTP: $HAS_NNTP | ||||||
| HAS_IRC: $HAS_IRC | HAS_IRC: $HAS_IRC | ||||||
| HAS_UDS: $HAS_UDS | HAS_UDS: $HAS_UDS | ||||||
| HAS_UDS2: $HAS_UDS2 | HAS2_UDS: $HAS2_UDS | ||||||
| HAS_ENABLE_PHA: $HAS_ENABLE_PHA | HAS_ENABLE_PHA: $HAS_ENABLE_PHA | ||||||
| 
 | 
 | ||||||
| HAS_DIG: $HAS_DIG | HAS_DIG: $HAS_DIG | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Dirk
					Dirk