This PR fixes an issue with sub_session_resumption() when using OpenSSL 1.1.1.
As noted in #1335, some servers will return a session ticket for TLSv1.2, but not for TLSv1.3.
OpenSSL 1.1.1 does not support the "-no_ssl2" option, and so when using OpenSSL 1.1.1 sub_session_resumption() adds $OPTIMAL_PROTO to the $OPENSSL s_client command line. When determine_optimal_proto_sockets_helper() is called, $OPTIMAL_PROTO will generally be set to "-tls1_2" (or "-tls1_1" or "-tls1") unless the server is a TLSv1.3-only server. As a result sub_session_resumption() will specify that same protocol on the command line if OpenSSL 1.1.1 is being used.
If "--ssl-native" is used, however, then determine_optimal_proto() will set $OPTIMAL_PROTO to "-tls1_3" if the server supports TLSv1.3 (and doesn't use STARTTLS). Similarly, if the version of determine_optimal_proto() in #1336 is used, then $OPTIMAL_PROTO will usually be empty. In either case, sub_session_resumption() will send a TLSv1.3 ClientHello, even if the server only supports session tickets for TLSv1.2 and below.
This PR appears to fix the problem. This PR makes no changes when using a version of OpenSSL that supports "-no_ssl2". When using a version of OpenSSL that does not support "-no_ssl2", however, rather than using $OPTIMAL_PROTO, this PR has sub_session_resumption() use whatever protocol version the server connected with when $sessticket_lifetime_hint was set.
There is a problem if a TLSv1.3-only server is tested using the OpenSSL 1.0.2-chacha binary and $OSSL_SHORTCUT is true.
$HAS_NO_SSL2 is set to true when find_openssl_binary() is called with OpenSSL 1.0.2-chacha. /usr/bin/openssl does not have the -no_ssl2 option, but the second call to find_openssl_binary(), after setting $OPENSSL to /usr/bin/openssl, does not set $HAS_NO_SSL2 to false. So, later calls to $OPENSSL s_client include the -no_ssl2 option, resulting in connection failures.
This PR fixes the problem by modifying find_openssl_binary() to ensure that every OpenSSL-dependent variable is set by this function.
This PR fixes two issues with finding session tickets when using OpenSSL 1.1.1.
First, if OpenSSL connects to the server using TLSv1.3 and it receives more than one Post-Handshake New Session Ticket, then the "TLS session ticket lifetime hint" will appear more than once in $TMPFILE. This will cause the line to appear more than once in $sessticket_lifetime_hint, which causes problems when trying to extract the $lifetime and $unit from $sessticket_lifetime_hint.
This PR fixes the first problem by changing the awk expression in the lines that set sessticket_lifetime_hint so that only the first line with "session ticket lifetime" is extracted.
The second issue is that some servers (e.g., google.com) return a session ticket for TLSv1.2, but not for TLSv1.3. For such servers, testssl.sh will miss the session ticket if $OPTIMAL_PROTO is empty or "-tls1_3" and the --ssl-native flag is not set.
This PR addresses the second issue with the changes in lines 9047 - 9053 -- the code that is intended to provide a last chance to find a session ticket.
If $OPENSSL supports TLSv.1.3 and the server returns session tickets for TLSv1.3 connections, then the session ticket would have already been found by get_server_certificate(), since get_server_certificate() uses $OPENSSL for TLSv1.3 if $OPENSSL supports TLSv1.3. So, in such circumstances, the code in liens 9047 - 9053 should not try again with TLSv1.3. So, if $OPENSSL supports TLSv1.3 and $OPTIMAL_PROTO is empty or is set to "-tls1_3" (either of which would result in a TLSv1.3 ClientHello), the "$OPENSSL s_client" call is changed to specify -no_tls1_3 rather than $OPTIMAL_PROTO.
The code on line 9047 is also changed to only make this final try is $TLS13_ONLY is false. If $TLS13_ONLY is true, then either:
* $OPENSSL does not support TLSv1.3 and the connection attempt would fail anyway; or
* $OPENSSL supports TLSv1.3, in which case any session ticket would have been found by get_server_certificate(), since get_server_certificate() uses $OPENSSL for TLSv1.3 if $OPENSSL supports TLSv1.3.
In either case, there is no reason to try again to find a session ticket.
This commit adds some more checks to determine_optimal_sockets_params(). These additional checks will almost never need to be run, and so will not slow down the typical run of testssl.sh, but adding them will provide information that can be useful for other parts of testssl.sh.
These additional checks will only be run if the server does not support TLSv1.3 and a TLSv1.2 ClientHello is not successful. This means that either:
* The server is not an TLS/SSL enabled server.
* The server only supports SSLv2.
* The server supports some protocol in SSLv3 - TLSv1.1, but does not handle version negotiation correctly.
Adding these additional checks helps in at least the following ways.
If determine_optimal_proto() (assuming it is reverted to using OpenSSL) is unable to connect to the server using OpenSSL, it will be possible determine whether the problem is the the server does not support TLS/SSL or that a different version of OpenSSL is needed to test the server.
If the code in #1205 for run_server_preference() is unable to connect when checking for a cipher order, the reason for the failure will be known, making it possible to determine the correct response to the failure.
This PR adds a new helper function that is run just prior to determine_optimal_proto() and that determines the what information tls_sockets() should include in a ClientHello.
For a TLSv1.3 ClientHello, determine_optimal_sockets_params() determines whether tls_sockets() should use 0x33 or 0x28 are the extension number for the key_share extension. 0x33 should be used with servers that support RFC 8446 or drafts 23-28. 0x28 should be used with servers that support drafts 18-22.
For a TLSv1.2 ClientHello, determine_optimal_sockets_params() determines what cipher list tls_sockets() should send. For most servers, the list of ciphers in $TLS12_CIPHER works best. But, there are some servers that do not support any ciphers in $TLS12_CIPHER, but do support one or more ciphers in $TLS12_CIPHER_2ND_TRY.
In some rare cases a server does not support any of the ciphers in $TLS12_CIPHER, but does support at least one cipher in $TLS12_CIPHER_2ND_TRY. In such cases, TLS12_CIPHER should be changed to $TLS12_CIPHER_2ND_TRY so that subsequent tests using $TLS12_CIPHER will succeed.
This PR fixes a few issues with run_protocol():
* In the case that the call to `tls_sockets "03" "$TLS12_CIPHER"` had a return value of 2, the code determining what results to print was looking at `$DETECTED_TLS_VERSION`. However, the value of this variable was set by the later call to `tls_sockets "04" "$tls13_ciphers_to_test"`. This caused incorrect results in the case of a server that supports TLSv1.3 and TLS1.1 (or earlier), but not TLSv1.2. This PR saves the value of `$DETECTED_TLS_VERSION` in `$tls12_detected_version` and then uses this variable later rather than `$DETECTED_TLS_VERSION`.
* When running in debug mode with a server that does not support TLSv1.3, testssl.sh was printing
TLS 1.3 -- downgradednot offered and downgraded to a weaker protocol"
This PR fixes the output by not printing the "--downgraded"
* As noted in #1329, run_protocols() was treating a downgrade from TLSv1.2 as less bad if the server supports TLSv1.3. This PR changes this code back to treat any downgrade from TLSv1.2 as equally bad.
* In order to be consistent with the TLSv1.3 test, this PR changes the TLS1.2 test output to say "not offered and downgraded to a weaker protocol" if a TLSv1.2 ClientHello results in a downgraded connection.
This PR fixes a problem in run_protocols() that was introduced by 7ec3c6ab99.
7ec3c6ab99 changes run_protocols() to perform the initial testing for TLSv1.3 support before testing for TLSv1.2 support. The problem with this is that the code for testing TLSv1.3 makes use of the results of the TLSv1.2 testing.
In the current code, Line 5183 looks at the value of $subret to determine whether the TLSv1.2 ClientHello resulted in a successful connection. However, $subet has not yet been set (it has just been initialized to 0 at the beginning of the function). Since $subret will always be 0, the code will try to extract a cipher from $TEMPDIR/$NODEIP.parse_tls_serverhello.txt. This may work, since $TEMPDIR/$NODEIP.parse_tls_serverhello.txt may have been populated by a prior function call, but this is not how the code was intended to work.
This PR fixes the problem by doing the TLSv1.2 testing before the TLSv1.3 testing is done. It still waits until both have been tested, however, before outputting the results, so that the output for TLSv1.2 can be modified depending on whether TLSv1.3 is supported.
In order to not repeatedly call check_resolver_bins() the function
was moved to top level. As each check in check_resolver_bins now
is only executed once, it should also work faster. Each get_*_record()
now uses HAS_ variables only.
Also check_resolver_bins() contain now the check whether
idn/idn2 support is available.
Then the IDN URI conversion snipplet was moved to the final function
parse_hn_port() which does operations in the URI supplied.
This PR adds a few quotes to some arguments which when previous code
was executed properly weren't needed.
Also it improves the IDN code from @teward, so that when idn2 is
available, a conversion will be tried, and when idn is available
and/or idn2 failed, a conversion will be tried.
Finally it'll be tried to continue without conversion, hoping that
the DNS client binaries can cope with the IDN URI.
This is not good enough yet and needs to be complemented, see discussion
@ #1321.
The Finding of other_headers such as "Referrer-Policy" during file output are displayed as `$header: $HEADERVALUE` instead of only `$HEADERVALUE` as the good_headers. This leads to duplicate information e.g. in the JSON output file.
... and thus this commit addresses #916.
It does that via a (quite) pre-test which checks for a general availabilty
of TLS 1.3 before the TLS 1.2 protocol test is being run and decides
based on that how a missing TLS 1.2 will be echoed.
Later on the complete TLS 1.3 test will be continued using the results
from the TLS 1.3 pre-test.
This commit addresses #1251 and gives a slight warning when still
using those protocols as government standards are or are at least
to expect also to deprecate those protocols. PCI DSS requires not
to use TLS 1.0 anymore and browser vendors supposedly will deprecate
TLS 1.0/1.1 next year.
This is a WIP for testing. It was committed already in May
(22ad490ea7b2868a4fd45862ca0bf8a3d8f24ea6) but somehow it was
lost.
Comments would be appeciated.
Open:
- how to treat non-HTTP protocols
- TLS 1.3 only hosts will mark the absence of TLS 1.2 as
a medium finding
In cases where TLS 1.3 is the only protocol supported by the server (as e.g.
in #1312), testssl.sh has some limits with the supplied binary.
For now (3.0) there's no perfect technical solution. This PR however improves
the verbosity what's going on and recommends to use an openssl binary
supporting TLS 1.3. And if the "secret" variable OSSL_SHORTCUT is set to true,
it automatically chooses that if available (it's a hack to do so and not
recommended. I just did it as a PoC).
In the next development we should consider probing this upfront!
Furthermore this PR removes some unnecessary quotes in double square brackets.
This commit proactively tries to address cases where the server side
adds Null Bytes after or during ClientHello in cases where it should be text only.
Now VAR2=$(< $VAR1) is being replaced by VAR2=$(cat -v $VAR1) which is normally
not best practice and also considered a useless use of "cat", see
https://web.archive.org/web/20160711205930/http://porkmail.org/era/unix/award.html#uucaletter.
Especially with bash 3.2 (Mac OS X) AND when on the server side binary chars it
was reported to not work ok, see #1292.
Performance measurements showed no to barely measureable penalty (at max 1s displayed difference
in 9 tries).
Travis updated the container images so that the perl
reference to 5.18 was outdated. We use now 5.26 which
works, however we should consider to be more flexible.
JSON::Validator didn't compile in the container. Thus
we switched to just use 'JSON'. That also supports JSON
pretty. For the future we should just test for valid JSON
in all unit test files as it is more effective.