Currently, the function neat_list() uses the variable "export", but does not define it. The result is that "export" variable in the calling function is used.
This PR fixes that by defining "export" as a local variable in neat_list() and by setting its value via a new parameter to the function.
This PR also removes a "FIXME" from run_rc4() since the problem has already been fixed.
This PR fixes a minor bug in get_pub_key_size(). If the key size is being determined manually and length encoding requires 4 bytes, then the current code computes the length incorrectly. This is a very insignificant bug, since does not apply to RSA or ECC keys, and the key would have to be at least 16 megabytes long for it to require 4 bytes to encode.
This PR also cleans up get_pub_key_size() a bit by replacing `i=$i+...` with `i+=...` and by enclosing math in `$(( ... ))`.
Hostnames can contain a trailing dot (and sometimes they should).
If they are supplied to testssl.sh however they will be also interpreted
as a URL PATH when the servive is HTTP.
This commit fixes that.
This switch had no effect. There was probably a regression
problem as it worked before.
Besides fixing that the large case statement in parse_cmd_line()
was simplified, in a sense that banner and help functions were
moved to a separate case statement.
This PR adds support for post-handshake messages when using sockets with TLS 1.3 connections. If a TLS 1.3 connection is established and the connection is to remain open after tls_sockets() finishes, then after the client's Finished message is sent the master secret and the application traffic keys are computed. This PR also adds two new functions to send and receive application data over a TLS 1.3 connection.
This PR also includes two proofs-of-concept for the use of the new functions. receive_app_data() is called immediately after the client's Finished message is sent. Some server's will send new session tickets immediately after the handshake is complete. If they do, then the code will decrypt and parse the session ticket messages.
This PR also modifies service_detection() to try using sockets if the server only supports TLS 1.3 and $OPENSSL does not support TLS 1.3. After the handshake is complete, this code sends an HTTP GET request and reads the response. The code is fairly slow and it doesn't always work. However, since it is only used in cases in which $OPENSSL cannot work, it can't hurt to try using sockets.
Due to a bug, the shellcheck program will complain if a variable is defined as an array but is later used as an ordinary string, even if the two uses are locally defined variables in different contexts. The error message is:
SC2178: Variable was used as an array but is now assigned a string.
While the warnings are not highlighting any actual problems in testssl.sh, this PR gets rid of the warnings by renaming a few variables.
The implementation of AES-GCM in #1473 is much slower than the original version, even when the authentication tag is not being computed. This PR modifies the code in gcm() in order to significantly speed up the encryption/decryption time (when authentication tags are not being computed).
This PR adds processing of the Finished messages in TLS 1.3 handshakes. It also addresses some shellcheck issues.
If in debug mode, the HMAC of the transcript hash of the handshake context ($msg_transcript) is computed and compared against the Finished message sent by the server.
If the full server response is parsed and the connection with the server is not to be closed when tls_sockets() completes, then the TLS 1.3 handshake is completed by creating the client Finished message and sending it to the server.
This PR reorganizes the code for deriving TLS 1.3 symmetric keys in order to facilitate implementing the full key schedule. For example, rather than having a single function to derive the handshake traffic keys, this PR creates one function to derive the handshake secret and a separate function to derive the handshake traffic keys. The second function has been generalized so that it can derive either client or server traffic keys. Separating into two functions also makes the handshake_secret available for later use to derive the master secret and then the application traffic secrets and the application traffic keys.
This PR also changes where there message transcript is created, a message transcript will also be needed to derive the application traffic secrets. This PR includes the code to add the messages to the initial message transcript that will be needed for the input to the application traffic secret derivation function.
RFC 8446 specifies cipher suites that use three symmetric encryption algorithms, all of which are Authenticated Encryption with Associated Data (AEAD) algorithms. In each of these algorithms when data is encryption an authentication tag is created, which allows the recipient to verify that the data has not been modified. The authentication may also cover some additional data that was not encrypted.
The current implementations of these algorithms in testssl.sh decrypt the ciphertext, but do not check that the authentication tag is correct (which involves the recipient computing the correct tag for the received data and then comparing it to the provided tag). While testssl.sh can get away with not checking authentication tags when receiving data, the ability to compute authentication tags is needed in order to send encrypted data as TLS servers would reject any encrypted data that did not have a correct authentication tag. Being able to send encrypted data is necessary to be able to complete the TLS 1.3 handshake.
This PR replaces the current implementations of the symmetric encryption algorithms with full implementations of each of the algorithms. These full implementations include the ability to encrypt data for sending, and can also verify the authentication tag when decrypting data. Since the Bash implementations of these algorithms is very slow, the decryption code is designed to only compute and check authentication tags in debug mode.
While the implementation of the code to compute authentication tags for AES-CCM was based on NIST Special Publication 800-38C, I was not able to implement the code for AES-GCM or Poly1305 from their specifications (NIST Special Publication 800-38D and RFC 8439, respectively). So, I would very much like to thank the implementers of https://github.com/mko-x/SharedAES-GCM and https://github.com/floodyberry/poly1305-donna. The implementations of AES-GCM and Poly1305 in the PR were developed by translating the C code in https://github.com/mko-x/SharedAES-GCM and https://github.com/floodyberry/poly1305-donna into Bash. I don't understand what that code is doing, but it seems to work. :-)
I have only tested this code on a computer with a 64-bit operating system. While I have not tested it, I believe that the decryption code will work with 32-bit integers if not in debug mode (i.e., if not trying to compute the authentication tags). I also believe that the AES-CCM code for computing authentication tags will work with 32-bit integers. However, AES-GCM and Poly1305 code for computing authentication tags will definitely only work on systems that have 64-bit integers. So, on systems that do not have 64-bit integers, encryption will not work for AES-GCM or ChaCha20-Poly1305, and decryption will not work for these algorithms if in debug mode.
For a fresh start it seemed a good idea to cleanup
the order of functions and some variables so that
those with the same functionality are somewhat grouped.
Some of the functions have now a header and a foooter
to make it easier to spot and use then. Also for added future
functions the hope is that they will be put where they better
fit
This PR simplifies the code for determining which draft version of TLS 1.3 a server is offering by making use of a simple regular expression and $BASH_REMATCH rather than looping through every possible draft version.
PR #1463 changed run_ssl_poodle() to only run the test if it is known that the server supports SSLv3. However, support for SSLv3 may be unknown at the time run_ssl_poodle() is run (e.g., if the server supports TLS 1 and SSLv3, and run_ssl_poodle() is the first test performed). So, run_ssl_poodle() should perform testing unless it is known that SSLv3 is not supported.
There's a check for >825 days certificate lifetime. That
check emits a debug statement when the lifetime is within
this limit. It does that also when the certificate expired.
This commit adds now the word "total"
DEBUG: all is fine with total certificate life time
to make sure the life time left not is what should be understood.
Several vulnerability checks add a time penalty when the server
side only support TLS 1.3 as The TLS 1.3 RFC 8446 and implementations
known so far don't support the flaws being checked for.
This PR adds "shortcut" checks for all TLS 1.3, assuming that the
TLS 1.3 implementation is correct which seems at this time a valid
assumpution. That either saves a TCP connect or at least some logic to
be executed. Also in some cases a TLS 1.3 only server emitted unnecessary
warnings, see #1444.
If $DEBUG -eq 1 then it outputs information that a shortcut was
used. It doesn't do that in other cases because the screen output
seems too obtrusive.
It also adds a shortcut for beast when SSL 3 or TLS 1.0 is is known
not to be supported.
This commit radds 747fb039ed which
was accidenially reverted in 45f28d8166.
It fixes#1462.
See also #1459.
* Replace "! -z" with "-n"
* Replace "openssl' with "$OPENSSL"
* Redirect stderr output of $OPENSSL to /dev/null to supress "WARNING: can't open config file: /usr/local/etc/ssl/openssl.cnf" message (see #833)
* Remove unnecessary spaces from $GET_REQ11 string.
The CA browser form agreed on a validity period of 825 days or less
(https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.5.3-redlined.pdf,
p4).
PR #1427 addressed that. However when an issuer signed/issued a certificate
with exactly 825 days, the check reported incorrectly that the life time
is too long.
This commit addressed that by adding a second to the calulation. Also the
output takes into account that it must be over ('>') 825 days, not '>='.
See #1070, kudos @poupas.
In addition it checks whether the first result was positive (in
terms of a finding). If so it does 4 rounds and checks the
result. So that other servers won't be penalized with 4 seconds.
derive-handshake-traffic-keys() uses the variables `derived_secret`, `server_write_key`, and `server_write_iv`, but they are not declared as local variables of the function. This PR fixes that.
As noted in #1273, there are some environments that will not allow writing to /dev/stdout. PR #1277 was an attempt to address that problem (along with an unrelated problem), but it appears that work on #1277 has been abandoned.
At the moment, "/dev/stdout" is only used as a parameter to asciihex_to_binary_file (in fact, most calls to asciihex_to_binary_file specify "/dev/stdout" as the file parameter). This PR removes the file parameter from asciihex_to_binary_file (and so renames it asciihex_to_binary). In most cases, this just means removing "/dev/stdout" as a parameter to the function. In the few cases in which a parameter other than "/dev/stdout" was provided to asciihex_to_binary_file, this PR just uses a redirect (">" or ">>") to accomplish the same result as providing the output file to asciihex_to_binary_file().
Note that #1273 and #1277 raised the issue of trying to write to /tmp, and this PR does not attempt to address that.
This PR fixes two problems that occur when testing a server that supports TLSv1.3 using OpenSSL 1.1.1 in --ssl-native mode.
First, when testing whether the server has a cipher order, the value of $sclient_success is checked after each call to tls_sockets(), but $sclient_success. As the goal is just to verify that the connection was successful (and didn't downgrade), $? can be checked rather than $sclient_success. [When not in --ssl-native mode, this problem is masked since $sclient_success is set to 0 earlier in the function.]
The second problem is that line 6646 tries to copy "$TEMPDIR/$NODEIP.parse_tls13_serverhello.txt", but this file is currently only created (on line 6287) if tls_sockets() is used to determine the negotiated protocol. This PR fixes the problem by also populating "$TEMPDIR/$NODEIP.parse_tls13_serverhello.txt" when OpenSSL is used to determine the negotiated protocol.
As stated in #1435 when specifying ``-connect-timeout=20`` AND
``--parallel`` there asa problem with the file handles of child
processes (__testssl.sh: line 10454: 5: Bad file descriptor__).
This commit mitigates that in a sense that both switches can't
be used together. There's a check now in parse_cmd_line().
In addition it addresses a problem when fatal() is called and
e.g. JSON files haven't been created yet (error message ~
__testssl.sh: line 825: : No such file or directory__). It
introduces a global CMDLINE_PARSED which remembers the state
whether ``parse_cmd_line()`` has been fully executed or
not. Only when the former is the case it allows writing to files.
That implies that in main parse_cmd_line() has to be followed
by json_header() and similar.
See #1429.
OpenBSD 6.6 had an offset with the HTTP header time of -3600 seconds.
This PR fixes that by adding the GMT time zone to parse_date()'s
HAS_FREEBSDDATE incarnation. That doesn't matter to FreeBSD.
Also now for older OpenBSDs the local and remote time are now
in the same format:
```
HTTP clock skew remote: Thu, 09 Jan 2020 12:52:32 GMT
local: Thu, 09 Jan 2020 12:52:02 GMT
``
so that a time difference is easier to spot.
OpenBSD's grep seems to interpret "-w <EXPR>:" differently
than Linux or MacOSX/FreeBSD in a sense that this doesn't
matchs, see #1430.
This PR fixes that by squashing the w option in all occuorrences.
In addition it removes the SOCKETHEADER if-statement which was
introduced looking forward a while back. It's not happening soon
at least and the variable was not initialized either.
... and reorder manpages also so that --warnings, --connect-timeout
and --openssl-timeout appear in the "input parameter" section.
The HTML manpage looks in the diff view quite different as previously
another computer was used for converting the source format with ronn(1).
The manpage in (g)roff format was manually edited with .RE / .RS
for provide indented bulletpoints.
See also #1419
* It'll be a warning now when a host certificate was issued after
March 1st, 2018 which has a lifetime >825 days, independent
whether it is an internal certificate or not. This can
change later, as browsers treat those certificates different
as "official ones"
* Still the 5 or 10 year threshold overrides this
* For older OpenBSDs there's now a better date format support
used in the expiration and validity period of a host certificate.
It mimics in bash the conversion of other date binaries. It is
not accurate so it might be off a day or at maximum two, probably
as a month has 30.42 days and not 30.
* The date output for OpenBSD is now in line with other OS. Previously
we just echoed the lines in openssl x509 output whereas now we
convert that
The expression 'grep -aw "Public-Key:"' hiccuped on the colon
under OpenBSD, so that any bitsize on a certificate had wrong
values, see #1425. (FreeBSD was fine)
This PR fixes that. It updates the expression by using awk and
bash internal functions.
The same problem occured in run_robot(). The strong typing of
pubkeybits had to be relaxed to a dynamic typing, unless we
choose to define a second string variable.
* old OpenBSD kinda works
* let's encrypt section moved so that OpenBSD can use it too
* Days are wrong
* Date format is not the same as with e.g. GNUdate (but should be)
* variables y m d not declared
* date warning for openbsd completely missing
As noted in #1418 LLMNR (Link-Local Multicast Name Resolution)
resolution times out when using x as an argument to "-connect".
This commit fixes that by replacing "-connect x" by "-connect invalid."
which is supposedly also generally more "DNS query friendly", see
https://tools.ietf.org/html/rfc6761#section-6.4 .
In addition this commit adds a check in get_common_prime() whether
the openssl version used has pkey support. If not with old openssl
versions and previously testssl.sh terminated after presenting garbledoutput.
(This was found as tested how very old version of openssl versions
handle "-connect invalid.")
If the server is known not to support TLS 1.3 (as well as TLS 1.2, TLS 1.1, and TLS 1), then mention TLS 1.3 in the list of not supported protocols. While lack of TLS 1.3 support is not part of the reason that no fallback is possible, it is part of the reason that the result is reported as prln_svrty_high.
If $high_proto is set to something other than SSLv3, support for SSLv3 will not have been determined by determine_optimal_sockets_params(), but it may have been determined later (e.g., by run_protocols()). So, this commit changes the loop to always check for SSLv3 support (without calling "$OPENSSL s_client" if $HAS_SSL3 is false). The check for whether the fallback test can be performed is moved until after the loop
This PR fixes a couple of places where "$OPENSSL s_client" is called with "-ssl3" even if SSLv3 is not supported.
The fix in ciphers_by_strength() is easy, as the issue only occurs if "$using_sockets" is true. If SSLv3 (or TLSv1.3) is not supported, then testing using "$OPENSSL s_client" is skipped and all of the supported ciphers are found using tls_sockets().
The fix for run_tls_fallback_scsv() is more complicated. While it is easy to avoid calling "$OPENSSL s_client" with "-ssl3" if SSLv3 is not supported, it is not easy to determine the correct message to present to the user if support for SSLv3 (and possibly also TLSv1.3) is unknown.
For the case in which $high_proto cannot be set, I believe that I have covered all of the possibilities, but an not sure if the correct message/rating is used in every case.
For the case in which it is not possible to determine whether SSLv3 is the $low_proto, more could be done. If $high_proto is TLS 1.1 or TLS 1, then this PR is okay, as it is possible that SSLv3 would be the fallback protocol, but there is no way to tell. However, it seems unlikely that a server would support TLS 1.2 and SSLv3, but not TLS 1.1 or TLS 1. So, perhaps if $high_proto is TLS 1.2 and the server does not support TLS 1.1 or TLS 1, it should just be assumed that SSLv3 is not supported, even if it cannot be tested.
At the moment, testssl.sh does not correctly derive the handshake traffic keys in the case that the server responds to the initial ClientHello with a HelloRetryRequest. The handshake traffic keys are computed incorrectly because the wrong messages are provided to derive-handshake-traffic-keys() for input to the Transcript-Hash calculation:
* TLS_CLIENT_HELLO is not updated to contain the value of the second ClientHello, and so the first ClientHello is being provided to derive-handshake-traffic-keys() as both the first and the second ClientHello.
* In middlebox compatibility mode the server may send a dummy ChangeCipherSpec message immediately after the HelloRetryRequest. Since it is part of the server's response to the initial ClientHello, the ChangeCipherSpec message is included in the $hrr that is sent to derive-handshake-traffic-keys(), but it should not be included in the computation of the Transcript-Hash.
This PR fixes the above two problems by updating TLS_CLIENT_HELLO when a second ClientHello is sent and by removing any ChangeCipherSpec message (140303000101) from the end of the server's initial response.
* Severity of RC4 in run_cipherlists() is now high as everywhere else
* Same for RC2 and DES. Only Export, NULL and ADH remain critical
* 3DES and IDEA in run_cipherlists() is now medium (see #1393)
* CBC3 SEED 3DES IDEA added in pr_cipher_quality()
* MD5 added to pr_cipher_quality() and labled as high
* double RC2 switch statemnet removed in pr_cipher_quality()
* timeouts are not default anymore but need a cmdline param (or ENV param)
* check whether "timeout" exists
Also:
* allow OPENSSL_TIMEOUT to be passed via ENV similar to others
* replace timeout variable in run_robot() by robottimeout, to avoid
misunderstandings by a human
ToDos: see inline. Mainly if timeout isn't available, testssl.sh doesn't
work.
Not to self: help function still says 60 second is default.
When printing a long HTTP security header, this commit causes every row after the first one to be indented by two additional spaces. In the case of very long headers, this extra indentation makes it a little easier for readers to see where the next security header begins.
When printing out HTTP security headers, run_security_headers() uses out_row_aligned_max_width(), since some headers are very long and need to be wrapped. At the moment, however, the first line is too long. The problem is that while "$header $HEADERVALUE" is printed in the indented area, only $HEADERVALUE is passed to out_row_aligned_max_width().
This PR fixes the problem by passing "$header $HEADERVALUE" to out_row_aligned_max_width() so that the the first line is wrapped at the correct place.
testssl.sh hiccups when a user supplied after --json*/--html/-csv
a filename instead of using the corresponding --json*file/--htmlfile/-csvfile
arguments, see #1397.
This PR adresses that in a sense that it tries to detect to following
argument of --json*/--html/-csv. If that matches a suspected filename
it bails out using fatal().
This is not intended to be perfect (when the pattern doesn't match)
but catches the user error in an early stage. See also #1398
Currently sub_cipherlists() and pr_cipher_quality() use different numbers for the same cipher quality ratings. sub_cipherlists() uses:
-2 = pr_svrty_critical, -1= pr_svrty_high, 0 = pr_svrty_low, 1 = pr_svrty_good, 2 = pr_svrty_best
while pr_cipher_quality() uses:
1 = pr_svrty_critical, 2 = pr_svrty_high, 3 = pr_svrty_medium, 4 = pr_svrty_low
5 = neither good nor bad, 6 = pr_svrty_good, 7 = pr_svrty_best
This PR changes sub_cipherlists() (and run_cipherlists()) to use the same numbers for cipher quality as pr_cipher_quality(). It does not change any of the ratings assigned to ciphers by run_cipherlists() or pr_cipher_quality(), so the two are still not in alignment. But, hopefully using the same numbering in both functions will make it a bit easier to compare them and bring them into alignment.
This resolves a regression introduced with IDN support (see also #1370).
* in check_resolver_bins() the determination of HAS_DIG_NOIDNOUT=true was wrong
* in get_*_record() the check for the bool variable was wrong
* in get_*_record() we shouldn't use quotes as they might be expand to a quoted arg
This PR fixes some indentation issues. The PR is a bit long, but it only makes changes to indentation (except for one comment line, where a trailing space character is removed).
This PR fixes#1385.
sub_session_resumption() returns 3 when $CLIENT_AUTH is true. However, the comment at the beginning of the function indicates that 6 will be returned. run_server_defaults() is prepared to handle a return value of 6 (to indicate client auth), but is not expecting 3 as a possible return value.
In cases where the probes for reading memory from the server side were not
successful (=not vulnerable) the TCP connection was not shut down properly --
leading to and undefined state and probably causing problems to a consecutive
check. The server side then assumably from time to time just didn't return
anything which caused a integration test (t/08_isHTML_valid.t) to fail
randomly.
This PR properly terminates the TCP socket connection. Also, as sending the
close notification before closing the socket was duplicated in testssl.sh
that went to a separate function.
See comment in #1375:
https://github.com/drwetter/testssl.sh/pull/1375#issuecomment-554424814
This PR enhances support for the latest versions of OpenSSL and LibreSSL.
The development version of OpenSSL at https://github.com/openssl/openssl/ is version 3.0.0-dev. So, checks for OpenSSL versions need to support this version as well. At the same time, the latest versions of LibreSSL are 3.0.0, 3.0.1, and 3.0.2, so version number alone will no longer be sufficient to distinguish between OpenSSL and LibreSSL.
In addition to checks for these new version numbers, this PR addresses a couple of other issues:
- In LibreSSL, the "$OPENSSL ciphers" command will not accept any protocol version other than "-tls1" as a parameter (and even including "-tls1" as an option is described as "deprecated"). So, this PR ensures that "$OPENSSL ciphers" is not passed any protocol version option other than "-tls1" is LibreSSL is being used.
- In OpenSSL 3.0.0-dev, the "$OPENSSL dgst" can no longer be used to compute HMACs, but a new "$OPENSSL mac" function has been created. So, this PR changes hmac() to use "$OPENSSL mac" with OpenSSL 3.0.0-dev.
Note that I have not tested the modified version of sub_session_resumption(). I am just assuming that OpenSSL 3.0.0-dev works the same as OpenSSL 1.1.1 and that all versions of LibreSSL work the same as OpenSSL 1.1.0 and earlier.