From f723ec97a772da54d9d12df8b506d682e1cf810d Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 28 Nov 2018 14:58:17 -0500 Subject: [PATCH] Fix #1159 part 2 This PR provides an additional fix for the issue raised by #1159. It defines a third option for the degree of processing that should be performed by tls_sockets(): "all+". When "all+" is provided, the processing is exactly the same as for "all" with the exception of the creation of the supported_groups extension. For a TLSv1.3 ClientHello, curves that are not supported by $OPENSSL are omitted from the supported_groups extension rather than offering these curves as the least preferred option. The "all+" option is used in run_server_defaults() where, unlike with almost every other call to tls_sockets(), a successful connection is of no use unless the response can be decrypted. This is also the case for run_alpn(), and so the call to tls_sockets() was also changed to "all+" there. But, the change has no effect at the moment, since run_alpn() sends a TLSv1.2 ClientHello. --- testssl.sh | 80 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/testssl.sh b/testssl.sh index ee6f1a3..6890ece 100755 --- a/testssl.sh +++ b/testssl.sh @@ -8394,7 +8394,7 @@ run_server_defaults() { c0,14, 00,39, c0,09, c0,13, 00,33, 00,9d, 00,9c, 13,02, 13,03, 13,01, 13,04, 13,05, 00,3d, 00,3c, 00,35, 00,2f, 00,ff" \ - "all" + "all+" success[0]=$? if [[ ${success[0]} -eq 0 ]] || [[ ${success[0]} -eq 2 ]]; then mv $HOSTCERT $HOSTCERT.nosni @@ -9016,7 +9016,7 @@ run_alpn() { alpn_extn="${len:0:2},${len:2:2},$alpn_extn" len="$(printf "%04x" $((${#proto}+3)))" alpn_extn="00,10,${len:0:2},${len:2:2},$alpn_extn" - tls_sockets "03" "$TLS12_CIPHER" "all" "$alpn_extn" + tls_sockets "03" "$TLS12_CIPHER" "all+" "$alpn_extn" if [[ -r "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" ]]; then cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE else @@ -10503,7 +10503,7 @@ check_tls_serverhellodone() { fi # A version of {0x7F, xx} represents an implementation of a draft version of TLS 1.3 [[ "${DETECTED_TLS_VERSION:0:2}" == "7F" ]] && DETECTED_TLS_VERSION="0304" - if [[ 0x$DETECTED_TLS_VERSION -ge 0x0304 ]] && [[ "$process_full" == "ephemeralkey" ]]; then + if [[ 0x$DETECTED_TLS_VERSION -ge 0x0304 ]] && [[ "$process_full" == ephemeralkey ]]; then tls_serverhello_ascii_len=2*$(hex2dec "${tls_handshake_ascii:2:6}") if [[ $tls_handshake_ascii_len -ge $tls_serverhello_ascii_len+8 ]]; then tm_out "" @@ -10567,7 +10567,7 @@ check_tls_serverhellodone() { # If the response is TLSv1.3 and the full response is to be processed, but the # key and IV have not been provided to decrypt the response, then return 3 if # the entire ServerHello has been received. - if [[ "$DETECTED_TLS_VERSION" == "0304" ]] && [[ "$process_full" == "all" ]] && \ + if [[ "$DETECTED_TLS_VERSION" == "0304" ]] && [[ "$process_full" =~ all ]] && \ [[ -z "$key_and_iv" ]] && [[ $tls_handshake_ascii_len -gt 0 ]]; then return 3 fi @@ -10623,8 +10623,8 @@ tls_alert() { } # arg1: ASCII-HEX encoded reply -# arg2: (optional): "all" - process full response (including Certificate and certificate_status handshake messages) -# "ephemeralkey" - extract the server's ephemeral key (if any) +# arg2: (optional): "all" or "all+" - process full response (including Certificate and certificate_status handshake messages) +# "ephemeralkey" - extract the server's ephemeral key (if any) # arg3: (optional): CIPHER_SUITES string (lowercase, and in the format output by code2network()) # If present, parse_tls_serverhello() will check that the cipher in the ServerHello appears in # the CIPHER_SUITES string. @@ -10673,7 +10673,7 @@ parse_tls_serverhello() { fi for (( i=0; i> $TMPFILE let offset=$extns_offset+12+$i @@ -11444,7 +11444,7 @@ parse_tls_serverhello() { fi # Now parse the Certificate message. - if [[ "$process_full" == "all" ]]; then + if [[ "$process_full" =~ all ]]; then # not sure why we need this [[ -e "$HOSTCERT" ]] && rm "$HOSTCERT" [[ -e "$TEMPDIR/intermediatecerts.pem" ]] && rm "$TEMPDIR/intermediatecerts.pem" @@ -11580,7 +11580,7 @@ parse_tls_serverhello() { $OPENSSL ocsp -respin /dev/stdin -resp_text >> $TMPFILE 2>$ERRFILE fi echo "===============================================================================" >> $TMPFILE - elif [[ "$process_full" == "all" ]]; then + elif [[ "$process_full" =~ all ]]; then echo "OCSP response: no response sent" >> $TMPFILE echo "===============================================================================" >> $TMPFILE fi @@ -11869,6 +11869,8 @@ generate_key_share_extension() { # ARG1: TLS version low byte (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # ARG2: CIPHER_SUITES string (lowercase, and in the format output by code2network()) # ARG3: "all" - process full response (including Certificate and certificate_status handshake messages) +# "all+" - same as "all", but do not offer any curves with TLSv1.3 that are not supported by +# $OPENSSL, since response MUST be decrypted. # "ephemeralkey" - extract the server's ephemeral key (if any) # ARG4: (optional) additional request extensions # ARG5: (optional): "true" if ClientHello should advertise compression methods other than "NULL" @@ -12001,7 +12003,7 @@ prepare_tls_clienthello() { 00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11" elif [[ 0x$tls_low_byte -gt 0x03 ]]; then # Supported Groups Extension - if [[ "$process_full" != "all" ]] || \ + if [[ ! "$process_full" =~ all ]] || \ [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.1"* ]]; then extension_supported_groups=" 00,0a, # Type: Supported Groups, see RFC 8446 @@ -12009,17 +12011,31 @@ prepare_tls_clienthello() { 00,1d, 00,17, 00,1e, 00,18, 00,19, 01,00, 01,01" # OpenSSL prior to 1.1.1 does not support X448, so list it as the least - # preferred option if the response needs to be decrypted. + # preferred option if the response needs to be decrypted, and do not + # list it at all if the response MUST be decrypted. + elif [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]] && [[ "$process_full" == all+ ]]; then + extension_supported_groups=" + 00,0a, # Type: Supported Groups, see RFC 8446 + 00,0e, 00,0c, # lengths + 00,1d, 00,17, 00,18, 00,19, + 01,00, 01,01" elif [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]]; then extension_supported_groups=" 00,0a, # Type: Supported Groups, see RFC 8446 00,10, 00,0e, # lengths 00,1d, 00,17, 00,18, 00,19, 01,00, 01,01, 00,1e" - else # OpenSSL prior to 1.1.0 does not support either X25519 or X448, # so list them as the least referred options if the response - # needs to be decrypted. + # needs to be decrypted, and do not list them at all if the + # response MUST be decrypted. + elif [[ "$process_full" == all+ ]]; then + extension_supported_groups=" + 00,0a, # Type: Supported Groups, see RFC 8446 + 00,0c, 00,0a, # lengths + 00,17, 00,18, 00,19, + 01,00, 01,01" + else extension_supported_groups=" 00,0a, # Type: Supported Groups, see RFC 8446 00,10, 00,0e, # lengths @@ -12279,8 +12295,8 @@ prepare_tls_clienthello() { # arg1: The server's response # arg2: CIPHER_SUITES string (lowercase, and in the format output by code2network()) # arg3: (optional) additional request extensions -# arg4: "all" - process full response (including Certificate and certificate_status handshake messages) -# "ephemeralkey" - extract the server's ephemeral key (if any) +# arg4: "all" or "all+" - process full response (including Certificate and certificate_status handshake messages) +# "ephemeralkey" - extract the server's ephemeral key (if any) # Return 0 if the response is not a HelloRetryRequest. # Return 1 if the response is a malformed HelloRetryRequest or if a new ClientHello cannot be sent. # Return 2 if the response is a HelloRetryRequest, and sending a new ClientHello succeeded. @@ -12490,6 +12506,8 @@ resend_if_hello_retry_request() { # (00: SSLv3, 01: TLS 1.0, 02: TLS 1.1, 03: TLS 1.2) # arg2: (optional) list of cipher suites # arg3: (optional): "all" - process full response (including Certificate and certificate_status handshake messages) +# "all+" - same as "all", but do not offer any curves with TLSv1.3 that are not supported by +# $OPENSSL, since response MUST be decrypted. # "ephemeralkey" - extract the server's ephemeral key (if any) # arg4: (optional) additional request extensions # arg5: (optional) "true" if ClientHello should advertise compression methods other than "NULL" @@ -12558,7 +12576,7 @@ tls_sockets() { # if the ephemeral key is needed (which comes last for TLS 1.2 and # below), then we need to check if response appears to be complete, # and if it isn't then try to get another packet from the server. - if [[ "$process_full" == all ]] || [[ "$process_full" == ephemeralkey ]]; then + if [[ "$process_full" =~ all ]] || [[ "$process_full" == ephemeralkey ]]; then hello_done=1; skip=true fi for (( 1 ; hello_done==1; 1 )); do