Skip to content

Commit a4d6f9a

Browse files
authored
Merge pull request #2822 from testssl/quic
First try for QUIC (OpenSSL only and only checking the protocol)
2 parents 6047f21 + 89bd3c7 commit a4d6f9a

9 files changed

Lines changed: 2760 additions & 1263 deletions

File tree

.github/workflows/codespell.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ jobs:
1212
- uses: actions/checkout@v4
1313
- uses: codespell-project/actions-codespell@master
1414
with:
15-
skip: ca_hashes.txt,tls_data.txt,*.pem,OPENSSL-LICENSE.txt,CREDITS.md,openssl.cnf,fedora-dirk-ipv6.diff
15+
skip: ca_hashes.txt,tls_data.txt,*.pem,OPENSSL-LICENSE.txt,CREDITS.md,openssl.cnf,fedora-dirk-ipv6.diff,testssl.1
1616
ignore_words_list: borken,gost,ciph,ba,bloc,isnt,chello,fo,alle,anull

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
## Change Log
33

4+
### Features implemented / improvements in 3.3dev
5+
6+
* QUIC protocol check
7+
48
### Features implemented / improvements in 3.2
59

610
* Rating (SSL Labs)

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Contributing / participating is always welcome!
55

66
Please note the following:
77

8-
* Please read the [coding convention](https://github.com/testssl/testssl.sh/blob/3.2/Coding_Convention.md).
8+
* Please read the [coding convention](https://github.com/testssl/testssl.sh/blob/3.3dev/Coding_Convention.md).
99
* If you have something new and/or bigger which you like to contribute, better open an issue first before you get frustrated.
1010
* Please one pull request per feature or bug fix or improvement. Please do not mix issues.
1111
* Documentation pays off in the long run. So please your document your code and the pull request and/or commit message.

doc/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ $(NAME).$(MANSECTION): $(NAME).$(MANSECTION).md
1515

1616
$(NAME).$(MANSECTION).html: template.html $(NAME).$(MANSECTION).md
1717
$(PANDOC) --standalone --to html5 --template template.html --metadata title="$(TITLE)" $(NAME).$(MANSECTION).md -o $@
18+
19+
# Source is Markdown

doc/testssl.1

Lines changed: 1414 additions & 552 deletions
Large diffs are not rendered by default.

doc/testssl.1.html

Lines changed: 1260 additions & 693 deletions
Large diffs are not rendered by default.

doc/testssl.1.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Any single check switch supplied as an argument prevents testssl.sh from doing a
175175

176176
`-f, --fs, --nsa, --forward-secrecy` Checks robust forward secrecy key exchange. "Robust" means that ciphers having intrinsic severe weaknesses like Null Authentication or Encryption, 3DES and RC4 won't be considered here. There shouldn't be the wrong impression that a secure key exchange has been taking place and everything is fine when in reality the encryption sucks. Also this section lists the available elliptical curves and Diffie Hellman groups, as well as FFDHE groups (TLS 1.2 and TLS 1.3).
177177

178-
`-p, --protocols` checks TLS/SSL protocols SSLv2, SSLv3, TLS 1.0 through TLS 1.3 and for HTTP: SPDY (NPN) and ALPN, a.k.a. HTTP/2. For TLS 1.3 several drafts (from 18 on) and final are supported and being tested for. Note the supplied openssl-bad version doesn't support TLS 1.3 . As the check for TLS 1.3 will be done in sockets this normally does not pose a problem. However if a TLS-1.3-only host is encountered and to have a complete test coverage (e.g. header checks) `/usr/bin/openssl` (or the content of `OPENSSL2`) is checked for existence and support of TLS 1.3 and if those tests succeeded it will be switched to this binary. A message will notify you.
178+
`-p, --protocols` checks TLS/SSL protocols SSLv2, SSLv3, TLS 1.0 through TLS 1.3. And for HTTP also QUIC (HTTP/3), SPDY (NPN) and ALPN (HTTP/2). For TLS 1.3 the final version and several drafts (from 18 on) are tested. QUIC needs OpenSSL >= 3.2 which can be automatically picked up when in `/usr/bin/openssl` (or when defined environment variable OPENSSL2). If a TLS-1.3-only host is encountered and the openssl-bad version is used testssl.sh will e.g. for HTTP header checks switch to `/usr/bin/openssl` (or when defined via ENV to OPENSSL2). Also this will be tried for the QUIC check.
179179

180180
`-P, --server-preference, --preference` displays the servers preferences: cipher order, with used openssl client: negotiated protocol and cipher. If there's a cipher order enforced by the server it displays it for each protocol (openssl+sockets). If there's not, it displays instead which ciphers from the server were picked with each protocol.
181181

@@ -520,6 +520,7 @@ Please note that for plain TLS-encrypted ports you must not specify the protocol
520520
* RFC 8143: Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)
521521
* RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
522522
* RFC 8701: Applying Generate Random Extensions And Sustain Extensibility (GREASE) to TLS Extensibility
523+
* RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport
523524
* W3C CSP: Content Security Policy Level 1-3
524525
* TLSWG Draft: The Transport Layer Security (TLS) Protocol Version 1.3
525526

t/baseline_data/default_testssl.csvfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"TLS1_1","testssl.sh/81.169.166.184","443","LOW","offered (deprecated)","",""
99
"TLS1_2","testssl.sh/81.169.166.184","443","OK","offered","",""
1010
"TLS1_3","testssl.sh/81.169.166.184","443","OK","offered with final","",""
11+
"QUIC","testssl.sh/81.169.166.184","443","WARN","not tested due to lack of local OpenSSL support","",""
1112
"NPN","testssl.sh/81.169.166.184","443","INFO","offered with h2, http/1.1 (advertised)","",""
1213
"ALPN_HTTP2","testssl.sh/81.169.166.184","443","OK","h2","",""
1314
"ALPN","testssl.sh/81.169.166.184","443","INFO","http/1.1","",""

testssl.sh

Lines changed: 75 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ trap "child_error" USR1
122122

123123
########### Internal definitions
124124
#
125-
declare -r VERSION="3.2.1"
125+
declare -r VERSION="3.3dev"
126126
declare -r SWCONTACT="dirk aet testssl dot sh"
127127
[[ "$VERSION" =~ dev|rc|beta ]] && \
128128
SWURL="https://testssl.sh/dev/" ||
@@ -205,6 +205,7 @@ MAX_OSSL_FAIL=${MAX_OSSL_FAIL:-2} # If this many failures for s_client con
205205
MAX_STARTTLS_FAIL=${MAX_STARTTLS_FAIL:-2} # max number of STARTTLS handshake failures in plaintext phase
206206
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
207207
MAX_WAITSOCK=${MAX_WAITSOCK:-10} # waiting at max 10 seconds for socket reply. There shouldn't be any reason to change this.
208+
QUIC_WAIT=${QUIC_WAIT:-3} # QUIC is UDP. Thus we run the connect in the background. This is how long to wait
208209
CCS_MAX_WAITSOCK=${CCS_MAX_WAITSOCK:-5} # for the two CCS payload (each). There shouldn't be any reason to change this.
209210
HEARTBLEED_MAX_WAITSOCK=${HEARTBLEED_MAX_WAITSOCK:-8} # for the heartbleed payload. There shouldn't be any reason to change this.
210211
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
339340
HAS_TLS11=false
340341
HAS_TLS12=false
341342
HAS_TLS13=false
343+
HAS_QUIC=false
344+
HAS2_QUIC=false # for automagically determined second OPENSSL version
342345
HAS_X448=false
343346
HAS_X25519=false
344347
HAS_SIGALGS=false
@@ -367,7 +370,7 @@ HAS_AES128_GCM=false
367370
HAS_AES256_GCM=false
368371
HAS_ZLIB=false
369372
HAS_UDS=false
370-
HAS_UDS2=false
373+
HAS2_UDS=false
371374
HAS_ENABLE_PHA=false
372375
HAS_DIG=false
373376
HAS_DIG_R=true
@@ -5468,6 +5471,7 @@ add_proto_offered() {
54685471
# arg1: protocol string or hex code for TLS protocol
54695472
# echos: 0 if proto known being offered, 1: known not being offered, 2: we don't know yet whether proto is being offered
54705473
# return value is always zero
5474+
#
54715475
has_server_protocol() {
54725476
local proto
54735477
local proto_val_pair
@@ -5502,6 +5506,7 @@ has_server_protocol() {
55025506

55035507

55045508
# the protocol check needs to be revamped. It sucks, see above
5509+
#
55055510
run_protocols() {
55065511
local using_sockets=true
55075512
local supported_no_ciph1="supported but couldn't detect a cipher (may need debugging)"
@@ -6125,10 +6130,59 @@ run_protocols() {
61256130
[[ $? -ne 0 ]] && exit $ERR_CLUELESS
61266131
fi
61276132

6133+
sub_quic
6134+
61286135
return $ret
61296136
}
61306137

61316138

6139+
# We do QUIC check first purely via OpenSSL, supposed it is supported by openssl
6140+
#
6141+
sub_quic() {
6142+
local alpn=""
6143+
local use_openssl=""
6144+
local proxy_hint_str=""
6145+
local sclient_outfile="$TEMPDIR/$NODEIP.quic_connect.txt"
6146+
local sclient_errfile="$TEMPDIR/$NODEIP.quic_connect_err.txt"
6147+
local jsonID="QUIC"
6148+
6149+
[[ $DEBUG -ne 0 ]] && sclient_errfile=/dev/null
6150+
6151+
pr_bold " QUIC ";
6152+
6153+
if "$HAS2_QUIC" || "$HAS_QUIC"; then
6154+
# Proxying QUIC is not supported
6155+
# The s_client call would block if either the remote side doesn't support QUIC or outbound traffic is blocked
6156+
if "$HAS2_QUIC"; then
6157+
use_openssl="$OPENSSL2"
6158+
else
6159+
use_openssl="$OPENSSL"
6160+
fi
6161+
OPENSSL_CONF='' $use_openssl s_client -quic -alpn h3 -connect $NODEIP:$PORT -servername $NODE </dev/null \
6162+
2>$sclient_errfile >$sclient_outfile &
6163+
wait_kill $! $QUIC_WAIT
6164+
if [[ $? -ne 0 ]]; then
6165+
if [[ -n "$PROXY" ]]; then
6166+
proxy_hint_str="(tried directly, is not proxyable):"
6167+
fi
6168+
outln "$proxy_hint_str not offered or timed out"
6169+
fileout "$jsonID" "INFO" "$proxy_hint_str not offered"
6170+
else
6171+
pr_svrty_best "offered (OK)"
6172+
fileout "$jsonID" "OK" "offered"
6173+
alpn="$(awk -F':' '/^ALPN protocol/ { print $2 }' < $sclient_outfile)"
6174+
alpn="$(strip_spaces $alpn)"
6175+
outln ": $(awk '/^Protocol:/ { print $2 }' < $sclient_outfile) ($alpn)"
6176+
fi
6177+
else
6178+
prln_local_problem "No OpenSSL QUIC support"
6179+
fileout "$jsonID" "WARN" "not tested due to lack of local OpenSSL support"
6180+
fi
6181+
6182+
return 0
6183+
}
6184+
6185+
61326186
# list ciphers (and makes sure you have them locally configured)
61336187
# arg[1]: non-TLSv1.3 cipher list (or anything else)
61346188
# arg[2]: TLSv1.3 cipher list
@@ -19900,7 +19954,7 @@ run_starttls_injection() {
1990019954
outln "Need socat for this check"
1990119955
return 1
1990219956
fi
19903-
if ! "$HAS_UDS2" && ! "$HAS_UDS"; then
19957+
if ! "$HAS2_UDS" && ! "$HAS_UDS"; then
1990419958
fileout "$jsonID" "WARN" "Need OpenSSL with Unix-domain socket s_client support for this check" "$cve" "$cwe" "$hint"
1990519959
outln "Need an OpenSSL with Unix-domain socket s_client support for this check"
1990619960
return 1
@@ -19926,7 +19980,7 @@ run_starttls_injection() {
1992619980

1992719981
if "$HAS_UDS"; then
1992819982
openssl_bin="$OPENSSL"
19929-
elif "$HAS_UDS2"; then
19983+
elif "$HAS2_UDS"; then
1993019984
openssl_bin="$OPENSSL2"
1993119985
fi
1993219986
# normally the interesting fallback we grep later for is in fd2 but we'll catch also stdout here
@@ -20684,7 +20738,7 @@ find_openssl_binary() {
2068420738
local s_client_has=$TEMPDIR/s_client_has.txt
2068520739
local s_client_has2=$TEMPDIR/s_client_has2.txt
2068620740
local s_client_starttls_has=$TEMPDIR/s_client_starttls_has.txt
20687-
local s_client_starttls_has2=$TEMPDIR/s_client_starttls_has2
20741+
local s_client2_starttls_has=$TEMPDIR/s_client2_starttls_has
2068820742
local openssl_location="" cwd=""
2068920743
local curve="" ossl_tls13_supported_curves
2069020744
local ossl_line1="" yr=""
@@ -20831,7 +20885,7 @@ find_openssl_binary() {
2083120885
HAS_AES256_GCM=false
2083220886
HAS_ZLIB=false
2083320887
HAS_UDS=false
20834-
HAS_UDS2=false
20888+
HAS2_UDS=false
2083520889
TRUSTED1ST=""
2083620890
HAS_ENABLE_PHA=false
2083720891

@@ -20868,16 +20922,20 @@ find_openssl_binary() {
2086820922
$OPENSSL s_client -tls1_3 -sigalgs PSS+SHA256:PSS+SHA384 $NXCONNECT </dev/null 2>&1 | grep -aiq "unknown option" || HAS_SIGALGS=true
2086920923
fi
2087020924

20925+
if [[ -x $OPENSSL2 ]] && OPENSSL_CONF='' $OPENSSL2 s_client -quic 2>&1 | grep -qi 'QUIC requires ALPN'; then
20926+
HAS2_QUIC="true"
20927+
elif OPENSSL_CONF='' $OPENSSL s_client -quic 2>&1 | grep -qi 'QUIC requires ALPN'; then
20928+
HAS_QUIC="true"
20929+
fi
20930+
2087120931
$OPENSSL s_client -noservername </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NOSERVERNAME=true
2087220932
$OPENSSL s_client -ciphersuites </dev/null 2>&1 | grep -aiq "unknown option" || HAS_CIPHERSUITES=true
20873-
20874-
$OPENSSL ciphers @SECLEVEL=0:ALL > /dev/null 2> /dev/null && HAS_SECLEVEL=true
20875-
2087620933
$OPENSSL s_client -comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_COMP=true
2087720934
$OPENSSL s_client -no_comp </dev/null 2>&1 | grep -aiq "unknown option" || HAS_NO_COMP=true
2087820935

20879-
OPENSSL_NR_CIPHERS=$(count_ciphers "$(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL' 'ALL')")
20936+
$OPENSSL ciphers @SECLEVEL=0:ALL > /dev/null 2> /dev/null && HAS_SECLEVEL=true
2088020937

20938+
OPENSSL_NR_CIPHERS=$(count_ciphers "$(actually_supported_osslciphers 'ALL:COMPLEMENTOFALL' 'ALL')")
2088120939
if [[ $OPENSSL_NR_CIPHERS -le 140 ]]; then
2088220940
[[ "$OSSL_NAME" =~ LibreSSL ]] && [[ ${OSSL_VER//./} -ge 210 ]] && HAS_DH_BITS=true
2088320941
if "$SSL_NATIVE"; then
@@ -20981,9 +21039,9 @@ find_openssl_binary() {
2098121039
# We also check, whether there's $OPENSSL2 which has TLS 1.3
2098221040
if [[ ! "$OSSL_NAME" =~ LibreSSL ]] && [[ ! $OSSL_VER =~ 1.1.1 ]] && [[ $OSSL_VER_MAJOR -lt 3 ]]; then
2098321041
OPENSSL_CONF='' $OPENSSL2 s_client -help 2>$s_client_has2
20984-
OPENSSL_CONF='' $OPENSSL2 s_client -starttls foo 2>$s_client_starttls_has2
20985-
grep -q 'Unix-domain socket' $s_client_has2 && HAS_UDS2=true
20986-
grep -q 'xmpp-server' $s_client_starttls_has2 && HAS_XMPP_SERVER2=true
21042+
OPENSSL_CONF='' $OPENSSL2 s_client -starttls foo 2>$s_client2_starttls_has
21043+
grep -q 'Unix-domain socket' $s_client_has2 && HAS2_UDS=true
21044+
grep -q 'xmpp-server' $s_client2_starttls_has && HAS_XMPP_SERVER2=true
2098721045
# Likely we don't need the following second check here, see 6 lines above
2098821046
if grep -wq 'tls1_3' $s_client_has2; then
2098921047
OPENSSL_CONF='' OPENSSL2_HAS_TLS_1_3=true
@@ -21179,7 +21237,7 @@ single check as <options> ("$PROG_NAME URI" does everything except -E and -g):
2117921237
-E, --cipher-per-proto checks those per protocol
2118021238
-s, --std, --categories tests standard cipher categories by strength
2118121239
-f, --fs, --forward-secrecy checks forward secrecy settings
21182-
-p, --protocols checks TLS/SSL protocols (including SPDY/HTTP2)
21240+
-p, --protocols checks TLS/SSL protocols, for HTTP: including QUIC/HTTP/3 and ALPN/HTTP2 (and SPDY)
2118321241
-g, --grease tests several server implementation bugs like GREASE and size limitations
2118421242
-S, --server-defaults displays the server's default picks and certificate info
2118521243
-P, --server-preference displays the server's picks: protocol+cipher
@@ -21339,6 +21397,8 @@ HAS_TLS1: $HAS_TLS1
2133921397
HAS_TLS11: $HAS_TLS11
2134021398
HAS_TLS12: $HAS_TLS12
2134121399
HAS_TLS13: $HAS_TLS13
21400+
HAS_QUIC: $HAS_QUIC
21401+
HAS2_QUIC: $HAS2_QUIC
2134221402
HAS_X448: $HAS_X448
2134321403
HAS_X25519: $HAS_X25519
2134421404
HAS_SIGALGS: $HAS_SIGALGS
@@ -21363,7 +21423,7 @@ HAS_SIEVE: $HAS_SIEVE
2136321423
HAS_NNTP: $HAS_NNTP
2136421424
HAS_IRC: $HAS_IRC
2136521425
HAS_UDS: $HAS_UDS
21366-
HAS_UDS2: $HAS_UDS2
21426+
HAS2_UDS: $HAS2_UDS
2136721427
HAS_ENABLE_PHA: $HAS_ENABLE_PHA
2136821428

2136921429
HAS_DIG: $HAS_DIG

0 commit comments

Comments
 (0)