`$OPENSSL_LOCATION` is used in `fileout_pretty_json_banner()`, `html_banner()`, `mybanner()`, and `prepare_logging()`, but the value of `$OPENSSL_LOCATION` is populated in `mybanner()`. This is usually okay, since `mybanner()` is always called before the other three functions are called. However, if `$QUIET` is `true`, then `mybanner()` returns immediately, without populating `$OPENSSL_LOCATION`, even though the value of `$OPENSSL_LOCATION` may be needed by one or more of the other functions.
This PR addresses this problem by populating `$OPENSSL_LOCATION` in `find_openssl_binary()` rather than `mybanner()`.
With the commit made on March 26, "partly (1/2) fixing #653," an HTML banner isn't added to the HTML files anymore. A banner should be added to the top of the HTML file if mass testing is being performed and a separate HTML file is being created for each test.
The `$APPEND` flag being `true` is an indicator that mass testing is being performed and that this is one of the individual tests being run. Given that `$APPEND` is `true`, `$HTMLHEADER` being `true` indicates that testssl.sh is creating the file name for the HTML output. So, it is when both flags are `true` that the HTML banner should be created.
`std_cipherlists()` does not include line breaks between tests in the output to the terminal when `$DEBUG` is 1, and it does not include line break between tests in the HTML output whenever `$DEBUG` is greater than 0.
In `create_client_simulation_tls_clienthello()` the variable `sni_extension_found` should be set if the ClientHello includes an SNI extension. Instead it was being set if and only if the ClientHello included some extension other than SNI.
This bug wasn't detected before for two reasons:
* It is rare to have a ClientHello that includes an SNI extension, but no other extensions.
* The code still works correctly if `sni_extension_found` is set even if there is no SNI in the ClientHello.
So, the bug only creates a problem if the browser's ClientHello include an SNI extension and no other extensions (see "BingPreview Jun 2014" in the client_simulation branch).
When HTML output is not being created, the print functions last step is to call `html_out()`, which responds to `return` rather than `return 0`. This causes problems for lines of code that rely on receiving a return value of 0. For example:
```
[[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for LUCKY13 vulnerability " && outln
```
This PR fixes two minor bugs:
* In `run_hpkp()`, the call to `$OPENSSL s_client` includes the option `-showcerts` twice. This PR removes one of them.
* In `get_server_certificate()`, the first call to `$OPENSSL s_client` includes `$addcmd`, but `$addcmd` has not yet been initialized. Instead, `$SNI` should be used.
Currently there is code to extract TLS extensions in three places, in `get_server_certificate()` and two places in `determine_tls_extensions()`. This PR replaces them with one new function, `extract_new_tls_extensions()`.
In order for the new function to work correctly whether OpenSSL or `tls_sockets()` is being used, this PR also changes `parse_tls_serverhello()` so that extensions are formatted in the file it creates in the same way as they are formatted by OpenSSL.
- in gerneral better performance measurements , starts from the real beginning (almost)
- allows results to put into file (MEASURE_TIME_FILE=google.txt testssl.sh google.com)
- PS4 improved: has now a performance debugging options (big solution)
- PS4 with proper alignment
- SCAN_TIME is now global so that it can be used not only by JSON-PRETTY (small performance debugging options uses it)
- prepare_debug() has now debugging stuff only, rest went to prepare_arrays()
This PR is the same as #661, except that it applies to the 2.9dev_html branch. It also fixes a bug in `prettyprint_local()` when a pattern to match is provided as input.
While doing some performance testing I discovered that `normalize_ciphercode()` is very slow. This PR simplifies the function and speeds it up significantly. This PR also addresses the TODO item in `normalize_ciphercode()` by eliminating the global variable HEXC.
When I view testssl.sh in KDE's text editor (kate), the code after "INFO" line in `show_finding()` isn't highlighted correctly, and the highlighting doesn't correct again until `pr_liteblueln()`. This PR fixes the highlighting issue by adding spaces between "]]" and ")". To be "safe," I also added spaces between "(" and "[[", and similarly added spaces in `is_json_format()`.
This PR ensures that each HTML file produced by testssl.sh only includes a single header, at the top, and a single footer, at the end. It also tries to ensure that the short-version banner is only placed at the top of the HTML file if (1) mass testing is being performed and (2) the results of each test is being placed in a separate file.
It also moves some of the logic out of main and into `html_header()`.
So far I haven't seen any HTML reserved characters (&, <, >, ", ') in the strings processed by `emphasize_stuff_in_headers()`, so this PR may be unnecessary. However, this PR will ensure that any such characters will be properly escaped in the HTML output.
"=~" doesn't need quotes if there's a text string one wants to match against (and shellcheck complains
about this)
pr_magenta shouldn't be used anymore as the logic what color we use should be done
some place else.
This branch is for getting the HTML patch from @dcooper16 into 2.9dev
Change to David's PR:
* removed HTMLHEADER. We always want that (in fact for flat JSON this is missing and needs to be added)
* not sure what this change does to --file
* changing of names They were redundant sometimes (pr_*_term )
* some formatting for readbility
Open points:
* there's a loop and a segfault --> tm_done_best
* HTMLHEADER: --file
* the former sed statement aroung L1900 for the header was way more readable. The combined
html+terminal version is just too much. Maybe a switch whether HTML is requested
is better so that this can be separated.
* Then e.g. "<span style=\"color:olive;font-weight:bold" can be kept in a variable
* any reason we need the text length here?
* what went into main here is too much. Actuallly what I put already in there bothered
me as too much logic and not obvious dependencies are in here. Now it's worse :-)
Can't this be just similar to JSON or CSV -- a seperate function with hooks
not in main()?
* minor thing: TERM_WIDTH is for HTML is maybe not the best. But that can be
tackled later
This PR attempts to address #631. It allows four choices for the `--mapping` option. "openssl" (default), "rfc", "no-openssl", and "no-rfc".
* "openssl" is the current default
* "no-rfc" shows only the OpenSSL names (just as it currently does)
* "rfc" shows the RFC name rather than the OpenSSL name for things that are not in wide now (just as it currently does). But now, in wide mode, it shows the RFC name first (further to the left) and the OpenSSL name second.
* "rfc-only" shows only the RFC name.
If the `--mapping` option is not provided, this is the same as "openssl". If the "cipher-mapping.txt" file cannot be found, then testssl.sh runs as if "no-rfc" had been requested.
It seems that the head command on OS X does not accept a negative number as a value for the "-n" parameter. This PR provides an alternative method for removing the "generator: " line without using "head."
Some sites have a long list of IP addresses and some IP addresses have a long list of DNS names that map to them.
This PR changes `display_rdns_etc()` to use `out_row_aligned_max_width()` to print the other IP addresses in `$IP46ADDRs` and to print `$rDNS`.
RFC 7633 introduces the TLS Features certificate extension, which contains "Features:
> The object member "Features" is a sequence of TLS extension identifiers (features, in this specification's terminology) as specified in the IANA Transport Layer Security (TLS) Extensions registry. If these features are requested by the client in its ClientHello message, then the server MUST return a ServerHello message that satisfies this request.
The main purpose of this certificate extension is to implement "must staple." If the extension is present in a TLS server's certificate and it includes status_request, then the server MUST include a stapled OCSP response if the client requests one. (The same applies for the status_request_v2 extension.)
This PR adds a check to `certificate_info()` of whether the server supports must staple (i.e., whether its certificate includes a TLS Features extension with "status_request"). It also changes the output for "OCSP stapling" in the case that the server did not staple an OCSP response. It indicates that:
* it is a critical issue if the certificate specifies "must staple"
* it is a low severity issue if the certificate does not specify "must staple," but the certificate does include an OCSP URI.
* it is not an issue at all if the certificate does not specify "must staple" and certificate does not include an OCSP URI.
`run_server_preference()` prints out the server's Negotiated cipher in a different color depending on the quality of the cipher. However, there is a "FIXME" since CBC ciphers are supposed to be flagged, but it is not easy to identity all CBC ciphers from their OpenSSL names.
This PR partially addresses this. It creates a separate function for printing a cipher based on its quality. Whenever possible it determines the quality of the cipher based on the RFC name. However, if it is provided an OpenSSL name and no cipher-mapping.txt file is available, it will follow the current (imperfect) logic for determining the cipher's quality.
The function also returns a value that indicates the quality of the cipher provided, with higher numbers indicating better ciphers. This return value is used by `run_server_preference()` to determine how to populate the "severity" field when calling `fileout()`.
In the case that `tls_sockets()` is being used and the server incorrectly fails the connection rather than downgrading, testssl.sh is printing "not offered" on one line and then the error message on the next line, but all the text should appear on one line (as it does when testing TLS 1 and TLS 1.1).
Since the test for TLS 1.2 in `run_protocols()` now uses `tls_sockets()` whenever `$ssl_native` is `true` (i.e., there is no longer a requirement for `$EXPERIMENTAL` to be true as well), the `$EXPERIMENTAL` flag should no longer be checked if the return value is 1.
Rearrange code so that in the case of just a single test, `parse_hn_port()` is not called earlier than it was previously unless it needs to be called in order to create the HTML file name.
Doing this ensures that the banner is displayed even if the `$URI` cannot be parsed (except in the case that the `$URI` needs to be parsed in order to create a file name) and that any error messages created by `parse_hn_port()` will be included in the HTML, if possible.
Add option for testssl.sh to create the HTML file name. If testssl.sh creates the file name, then, in the case of mass testing, a separate HTML file is created for each test (i.e., for each line in the file provided to `--file`).
I have a test server that I configured to support only SSLv3 and TLSv1.2. When I set `SSLHonorCipherOrder` to `off` I get the following results:
```
ECDHE-RSA-AES256-SHA: SSLv3 ECDHE-RSA-AES256-GCM-SHA384: TLSv1.2
```
The current code, when printing TLSv1.2 checks whether `${cipher[4]}` is empty, and since it is assume no previous protocol (SSLv2, SSLv3, TLSv1, TLSv1.1) was supported and so doesn't output a newline before outputting the cipher and protocol for TLSv1.2.
This PR fixes that by changing to code to look at the previous non-empty cipher (if there is one), even if that does not come from the previous protocol.
When a list of cipher suites is being displayed using `neat_list()`, testssl.sh shows the cipher suite's OpenSSL name and (in most cases) the RFC name as well. However, in all other cases only the OpenSSL name is shown.
This PR adds the option to have cipher suite's RFC names shown instead of the OpenSSL name, by including `--mapping rfc` in the command line. [Note: if the cipher-mapping.txt file cannot be found, then the `--mapping rfc` option is ignored and the OpenSSL names are shown.]
This PR seems to be related to issue #9, but #9 may be been referring to the output created by `neat_list()`.
Gray should appear for COLOR=1 or COLOR=2.
Since `pr_grey()` is basically the same as `out()` for COLOR=0, `mybanner()` should just call `pr_grey()` without checking the value of `$COLOR`.
Change `emphasize_stuff_in_headers()` to use olive and bold olive rather than brown and yellow. This matches what `aha` creates and appears similar to what is displayed in the terminal on a Mac. Also, yellow text is very difficult to read.
Found more places where output should only go to terminal, or where it was only going to the terminal (e.g., printf) but should also be in the HTML. Also added the ability to include active URLs in the HTML output.
To Do: Handle automatic generation of HTML file name and support for parallel testing.
Introduced "trick" so that if the `--file` option is used, `html_header()` will only be called once before anything is printed and `html_footer()` will only be called once after all printing is complete. With this, `html_header()` now delete the output file if it exists.
Also introduced the `html_reserved()`, which is called for all text to be sent to `out_html()`. `html_reserved()` converts any HTML reserved characters (", ', &, <, >) to their corresponding entity names (", ', &, <, >).
This PR addresses the issue raised in #623. This PR is based on the function `out_row_aligned_max_width()` that I proposed in #623, but the `out_row_aligned_max_width()` in this PR is a little different. It takes a fourth parameter, which is the function to use to print each word in the text string to be printed. This is used in `run_pfs()` so that the "Elliptic curves offered" can be printed using this function (some servers support 25 curves), while still having the curves printed using color-coding to indicate the quality of each curve.
I somewhat arbitrarily have each line wrap at 120 characters, but that could be changed (e.g., to `$TERM_WIDTH`).
For the most part I used the RGB values for xterm from https://en.wikipedia.org/wiki/ANSI_escape_code#Colors for the HTML colors, but with a few exceptions. For example, I did not use "yellow" for `pr_svrty_low()`, since that color is very difficult to read. I also used a different color for `pr_svrty_medium()` so that `pr_svrty_medium()` would appear more red than `pr_svrty_low()`.
These color choices could use more adjustment.
This PR adds the option to generate HTML. The code was created as follows:
* For each output function (`out()`, `outln()`, `pr_liteblue()`, etc.) I created two functions: one that just outputs to the terminal and one that outputs to the terminal and to the HTML file (if an HTML file is to be created).
* I modified the code so that any output that should appear in the HTML file in addition to being displayed on the terminal is sent through one of the display functions: out()`, `outln()`, `pr_liteblue()`, etc.
* I created a new function `retstring()` to use in place of `out()` when a function is creating a string to be "captured" by the calling function.
* I modified the code so that no string returned by a function includes color-coding escape characters.
In the revised code that was created to address #587, nothing is printed after "OCSP URI" if there is neither an OCSP URI nor a CRL URI. Instead, "--" should be printed.
I still believe that there is an inconsistency in the reporting of the output, however. At the moment, the "Certificate Revocation List" and "OCSP URI" lines indicate it is acceptable as long as the certificate contains either a CRL URI or an OCSP URI. However, the "OCSP stapling" line reports a minor finding if an OCSP response was not included in the server's reply. Shouldn't we just assume that if the certificate doesn't include an OCSP URI, then it wouldn't be possible for the server to obtain an OCSP response to staple to its reply? If so, then it seems that no OCSP stapling should only be considered a finding if an OCSP URI is present.
This PR fixes issue #601.
The fix for OCSP URLs was easy. I don't entirely understand the first `awk` command in the line to extract the CRL URLs, but I tested it on several certificates and it seems to work correctly (ensuring that the only "URI" lines in the input to the second `awk` command are from the CRL Distribution Points extension).
RFC 4492 introduced the Supported Elliptic Curves Extension, but this extension was renamed Supported Groups in RFC 7919. Following RFC 7919 (and TLSv1.3), `parse_tls_serverhello()` refers to this extension as "supported groups/#10". Since, at the moment, OpenSSL's s_client refers to this extension as "elliptic curves/#10", the extension sometimes appears twice in the "TLS extensions" line, if it is detected by both OpenSSL (in `get_server_certificate()`) and `tls_sockets()` (in `determine_tls_extensions()`):
```
TLS extensions (standard) "renegotiation info/#65281" "elliptic curves/#10" "EC point formats/#11" "supported groups/#10"
```
This PR fixes the problem of the extension appearing twice in the "TLS extensions" line by replacing any instances of "elliptic curves/#10" with "supported_groups/#10" in the `$tls_extensions` line extracted from `$OPENSSL s_client`. This PR also changes "supported groups/#10" to "supported_groups/#10" in `parse_tls_serverhello()`, since the current development branch of OpenSSL uses "supported_groups" to refer to this extension (see https://github.com/openssl/openssl/pull/1825).
This PR increases the width of the "Encryption" column printed by `neat_list()` in order to allow room to print "CamelliaGCM."
This is the alternative fix to the problem that was first addressed in #524. This PR obsoletes PR #530.
This PR changes testssl.sh so that when ciphers are being listed in wide mode (i.e., using `neat_list()`) and the `--show-each` option is set, ciphers that are not available are printed in light grey, whereas ciphers that are available continue to be printed in black. This makes it easier to distinguish between ciphers that are available and those that are not (the "available/"not a/v" column remains).
This PR does not change the way that ciphers that are available are printed, but it includes a hook that would allow that to change. For example, for ciphers that are available, the name of the cipher suite could be printed in a different color depending on its quality (as is done for the "Negotiated cipher" in `run_server_preference()`). The same could be done for the "Encryption" and "Bits" columns.
- run_logjam(): determine dh bit size and based on this mark the common primes as more or less vulnerable
- run_logjam(): renamed remaining dhe variable to dh
- further house keeping in run_logjam()
In some cases, the "TLS extensions" line output for the "--server-defaults" option will not show `"encrypt-then-mac/#22"` even if the server supports this extension. The reason is that a server will only include this extension in the ServerHello message if it supports the extension and the selected cipher is a CBC cipher. So, if `determine_tls_extensions()` connects to the server with a non-CBC cipher, then it will not detect if the server supports the encrypt-then-mac extension.
It is possible that support for the extension will be detected by `get_server_certificate()`, but only if one of the calls to that function results in a CBC cipher being selected and OpenSSL 1.1.0 is being used (as prior versions did not support the encrypt-then-mac extension).
In this PR, if `determine_tls_extensions()` is called and `$TLS_EXTENSIONS` does not already contain `"encrypt-then-mac/#22"`, then an attempt will be made to connect to the server with only CBC ciphers specified in the ClientHello. If the connection is not successful (presumably because the server does not support any CBC ciphers), then a second connection attempt will be made with the "default" ciphers being specified in the ClientHello.
en.wikipedia.org is an example of a server that supports the encrypt-then-mac extension, but for which the support is not currently detected (unless OpenSSL 1.1.0 is used) since in the call to `determine_tls_extension()` a non-CBC cipher is selected.
This PR changes `read_dhbits_from_file()` so that, when the "quiet" parameter is absent, the selected curve is shown in addition to the number of bits. This PR only affects the output of `run_client_simulation()` and the `Negotiated cipher` in `run_server_preference()`.
There are two places in `run_client_simulation()` in which `$OPENSSL s_client` is called, after which there is a `debugme echo` line to display the `$OPENSSL s_client` command line when testssl.sh is being run in debug mode, and then `sclient_connect_successful $? $TMPFILE` is called to determine whether `$OPENSSL s_client` successfully established a connection.
So, `sclient_connect_successful()` is being passed the result of the `debugme()` call, which always returns 0, rather than the result of the `$OPENSSL s_client` call.
This PR fixes the problem by moving the `debugme()` line to before the call to `$OPENSSL s_client`, so that `sclient_connect_successful()` is passed the results of the `$OPENSSL s_client` call.
Starting with OpenSSL 1.1.0, s_client will not offer TLS compression methods, even if OpenSSL is compiled with zlib support, unless the `-comp` flag is included in the command line.
This PR changes `run_crime()` to use `tls_sockets()` rather than failing if `$OPENSSL` lacks zlib support, unless `$SSL_NATIVE` is `true`.
At the moment, the ClientHello created by `socksend_tls_clienthello()` only specifies the NULL compression method. So, this PR adds a new parameter to `socksend_tls_clienthello()` and `tls_sockets()` to allow to caller to request that additional compression methods (DEFLATE and LZS) be specified in the ClientHello.
This PR makes another change to `run_crime()`. At the moment, if `$OPENSSL s_client` fails to connect to the server, `run_crime()` will report that the server is not vulnerable, since the output from `$OPENSSL s_client` includes the line "Compression: NONE" (see below). This PR changes that by checking whether the connection was successful, and reporting a "test failed (couldn't connect)" warning if it wasn't successful, rather than reporting "not vulnerable (OK)".
```
CONNECTED(00000003)
140338777061024:error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version:s23_clnt.c:769:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 389 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1483645971
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
```
This PR fixes a few bugs in `sslv2_sockets()`. The main issue is that a server may not send the entire ServerHello in a single packet. If it doesn't and the full response is being parsed (i.e., certificate and list of ciphers), then `parse_sslv2_serverhello()` will encounter errors, since it assumes that it has the entire ServerHello. This PR compares the length of the response to the length of the ServerHello as specified in the first two bytes of the response and requests more data from the server if the response appears incomplete.
This PR also modifies `parse_sslv2_serverhello()` to check for more errors. It compares the length of the response it has been provided to the specified length (`$v2_hello_length`) and returns an error if the response is shorter than `$v2_hello_length` and the full response is supposed to be parsed. It will also check whether there was an error in converting the certificate from DER to PEM format and will return an error if there was (and it will suppress the error message).
Some servers respond to an SSLv2 ClientHello with a list of all SSLv2 ciphers that the server supports rather than just a list of ciphers that it supports in common with the client (i.e., that appear in the ClientHello). This PR changes the sockets version of `std_cipherlists()` so that, if `sslv2_sockets()` is successful, it checks whether there are any ciphers in common between the ClientHello and the ServerHello before declaring that the server supports the specified cipher list.
Some servers respond to an SSLv2 ClientHello with a list of all SSLv2 ciphers that the server supports rather than just a list of ciphers that it supports in common with the client (i.e., that appear in the ClientHello). This PR changes the sockets version of `run_freak()` so that, if `sslv2_sockets()` is successful, it checks whether there are any ciphers in common between the ClientHello and the ServerHello before declaring that the server supports an export RSA cipher.
If `determine_tls_extensions()` does not create a temporary file (`$TEMPDIR/$NODEIP.determine_tls_extensions.txt`) then `run_server_defaults()` will display error messages when an attempt is made to copy this file or to search (grep) it. This may happen if `$OPTIMAL_PROTO` is `-ssl2` or if `determine_tls_extensions()` uses sockets and `parse_tls_serverhello()` encountered an error and did not create a temporary file (`$TEMPDIR/$NODEIP.parse_tls_serverhello.txt`). This PR fixes this by only trying to copy and search `$TEMPDIR/$NODEIP.determine_tls_extensions.txt` is `$OPTIMAL_PROTO` is not `-ssl2` and `determine_tls_extensions()` was successful (return value 0).
In response to your request in #572, this PR provides a starting point for addressing #120. It adds code to `run_logjam()` to try connecting to the server using any cipher that uses an ephemeral DH key. If successful, it gets the server's ephemeral key (in OpenSSL's PEM format) and then extracts the prime from the key and places it in `$dh_p`. So, all that needs to be done at this point is to compare `$dh_p` against a set of "bad" primes. I'm not sure if I'll be able to work on that part soon, so if someone else has the time, that would be great.
I actually found the `-msg` option easy to use. I moved the code in `parse_tls_serverhello()` that extracts the DH ephemeral public key from the ServerKeyExchange message into a separate function. Then, if using OpenSSL with the `-msg` option, I extract the ServerKeyExchange message from `$TMPFILE` and call this new function to extract the key and convert it to PEM format. That way the new code in `run_logjam()` can use either `$OPENSSL` or `tls_sockets()`.
This PR changes `run_http2()` so that it uses `tls_sockets()` rather than failing, if `$OPENSSL` does not support the `-alpn` option. If `$OPENSSL` supports the `-alpn` option (or if `$SSL_NATIVE` is true), then this PR has no effect.
This PR change `run_std_cipherlists()` to use sockets. As noted in isse #554, I have some questions about the definitions of the cipher lists, but I wrote the code so that the ciphers that are tested when using sockets are the same as those that are tested when using OpenSSL. For a few of the cipherlists, the sockets version tests a few additional ciphers; but these are ciphers that are not supported by OpenSSL, and whose definitions are consistent with the ciphers that OpenSSL includes.
As written, `std_cipherlists` will use sockets for testing by default, except in two cases:
* If the `$SSL_NATIVE` is true, then only OpenSSL is used, and if OpenSSL doesn't support any ciphers in the cipherlist, then the test is skipped.
* If `$FAST` is true (but `$SSL_NATIVE` is false), then OpenSSL is used whenever it supports at least one cipher from the cipherlist, and `tls_sockets()` (or `sslv2_sockets()`) is only used when OpenSSL doesn't support any ciphers from the cipherlist.
This PR changes `run_ssl_poodle()` to use sockets. This PR is particularly useful when $OPENSSL is OpenSSL 1.1.0, since OpenSS 1.1.0 does not support SSLv3 by default. But, it is also useful if $OPENSSL supports some, but not all, of the CBC ciphers.
As with `run_beast()`, there is a small change to `$cbc_cipher_list`. The following two ciphers were added:
```
0x00,0x0B - EXP-DH-DSS-DES-CBC-SHA SSLv3 Kx=DH/DSS Au=DH Enc=DES(40) Mac=SHA1 export
0x00,0x0E - EXP-DH-RSA-DES-CBC-SHA SSLv3 Kx=DH/RSA Au=DH Enc=DES(40) Mac=SHA1 export
```
The ciphers that were removed are all SSLv2 ciphers:
```
0x07,0x00,0xC0 - DES-CBC3-MD5 SSLv2 Kx=RSA Au=RSA Enc=3DES(168) Mac=MD5
0x06,0x00,0x40 - DES-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=DES(56) Mac=MD5
0x04,0x00,0x80 - EXP-RC2-CBC-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export
0x05,0x00,0x80 - IDEA-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=IDEA(128) Mac=MD5
0x03,0x00,0x80 - RC2-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=RC2(128) Mac=MD5
```
(EXP-RC2-CBC-MD5 is both an SSLv2 and an SSLv3 cipher. Previously it was listed twice in `$cbc_cipher_list`, now it appears once.)
In a few places testssl.sh tries to determine $OPENSSL s_client's capabilities by calling `$OPENSSL s_client` without specifying a host to which to connect. For example:
```
$OPENSSL s_client -no_ssl2 2>&1
```
This idea is that `$OPENSSL s_client` should reveal something about its capabilities without actually trying to connect to a host.
This works in most cases. However, the manual pages for s_client states:
```
-connect host:port
This specifies the host and optional port to connect to. If not specified then an attempt is made to connect to the local host on port 4433.
```
So, the above call is actually trying to connect to the local host on port 4433. If the local host is running `$OPENSSL s_server`, then `$OPENSSL s_server` will by default be listening on port 4433, and the connection attempt will most likely succeed. Since the `OPENSSL s_client` command does not include a `< /dev/null`, the `OPENSSL s_client` will just hang waiting for additional input.
Adding `-connect x` to the `$OPENSSL s_client` prevents $OPENSSL from trying to connect to a host, but seems to still provide the necessary information about OpenSSL's capabilities.
This PR adds ",exp" to the bits column when `run_rc4()` is run in the "--wide" mode and the cipher is an export cipher. This makes the wide mode of `run_rc4()` align with other functions, such as `run_allciphers()`.
This PR adds the use of sockets to `run_server_preference()` to determine the "Negotiated cipher per proto." It only uses sockets in two cases:
* For SSLv2, if $OPENSSL does not support SSLv2.
* For SSLv2, if $OPENSSL does not support SSLv3.
This PR will have no effect if the provided OpenSSL binaries are used.
When `test_just_one()` uses `neat_list()` with a cipher that is not available and that uses DH for key exchange, the columns do not line up correctly. `test_just_one()` adds "TBD" in gray to "DH", and while `neat_list()` tries to adjust for the presence of color codes, it doesn't seem to correctly handle the gray color code here.
Rather than try to fix this in `neat_list()`, I propose to just remove the "TBD". Adding it is inconsistent with other functions (like `run_allciphers()`), and it seems inappropriate, since there is nothing "to be determined," as the cipher suite isn't supported by the server.
If adding "TBD" were appropriate anywhere, it would seem to be in cases in which the server does support the cipher, but the number of bits in the ephemeral key couldn't be determined because the version of OpenSSL being used can't show DH/ECDH bits. (Not that I'm proposing this. I think the one-line warning, "(Your $OPENSSL cannot show DH/ECDH bits)", is enough.
Here is an example of `test_just_one()` with some ciphers not supported by the server that use DH key exchange:
```
Testing single cipher with word pattern "CAMELLIA" (ignore case)
Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (RFC)
---------------------------------------------------------------------------------------------------------------------------
xc077 ECDHE-RSA-CAMELLIA256-SHA384 ECDH TBD Camellia 256 TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 not a/v
xc073 ECDHE-ECDSA-CAMELLIA256-SHA384 ECDH TBD Camellia 256 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 not a/v
xc4 DHE-RSA-CAMELLIA256-SHA256 DH TBD Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 not a/v
xc3 DHE-DSS-CAMELLIA256-SHA256 DH TBD Camellia 256 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 not a/v
xc2 DH-RSA-CAMELLIA256-SHA256 DH/RSA Camellia 256 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 not a/v
xc1 DH-DSS-CAMELLIA256-SHA256 DH/DSS Camellia 256 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 not a/v
x88 DHE-RSA-CAMELLIA256-SHA DH 2048 Camellia 256 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA available
x87 DHE-DSS-CAMELLIA256-SHA DH TBD Camellia 256 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA not a/v
x86 DH-RSA-CAMELLIA256-SHA DH/RSA Camellia 256 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA not a/v
x85 DH-DSS-CAMELLIA256-SHA DH/DSS Camellia 256 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA not a/v
xc5 ADH-CAMELLIA256-SHA256 DH TBD Camellia 256 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 not a/v
x89 ADH-CAMELLIA256-SHA DH TBD Camellia 256 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA not a/v
xc079 ECDH-RSA-CAMELLIA256-SHA384 ECDH/RSA Camellia 256 TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 not a/v
xc075 ECDH-ECDSA-CAMELLIA256-SHA384 ECDH/ECDSA Camellia 256 TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 not a/v
xc0 CAMELLIA256-SHA256 RSA Camellia 256 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 not a/v
x84 CAMELLIA256-SHA RSA Camellia 256 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA not a/v
xc076 ECDHE-RSA-CAMELLIA128-SHA256 ECDH TBD Camellia 128 TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xc072 ECDHE-ECDSA-CAMELLIA128-SHA256 ECDH TBD Camellia 128 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xbe DHE-RSA-CAMELLIA128-SHA256 DH TBD Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xbd DHE-DSS-CAMELLIA128-SHA256 DH TBD Camellia 128 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xbc DH-RSA-CAMELLIA128-SHA256 DH/RSA Camellia 128 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xbb DH-DSS-CAMELLIA128-SHA256 DH/DSS Camellia 128 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 not a/v
x45 DHE-RSA-CAMELLIA128-SHA DH 2048 Camellia 128 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA available
x44 DHE-DSS-CAMELLIA128-SHA DH TBD Camellia 128 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA not a/v
x43 DH-RSA-CAMELLIA128-SHA DH/RSA Camellia 128 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA not a/v
x42 DH-DSS-CAMELLIA128-SHA DH/DSS Camellia 128 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA not a/v
xbf ADH-CAMELLIA128-SHA256 DH TBD Camellia 128 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 not a/v
x46 ADH-CAMELLIA128-SHA DH TBD Camellia 128 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA not a/v
xc078 ECDH-RSA-CAMELLIA128-SHA256 ECDH/RSA Camellia 128 TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xc074 ECDH-ECDSA-CAMELLIA128-SHA256 ECDH/ECDSA Camellia 128 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
xba CAMELLIA128-SHA256 RSA Camellia 128 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 not a/v
x41 CAMELLIA128-SHA RSA Camellia 128 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA not a/v
```
The Postgres protocol uses STARTTLS with a custom start packet. This
functionality is supported by openssl s_client in the current openssl
master branch but not yet in any released version.
This patch detects whether the given openssl binary supports postgres
and runs the default tests against a postgres server.
Example of no openssl support:
~/bin/testssl$ ./testssl.sh --quiet
--openssl=/opt/openssl/openssl-1.1.0c/bin/openssl --starttls=postgres
test.postgres.server.com:5432
Start 2016-12-07 18:03:24 -->> ip.add.re.ss:5432
(test.postgres.server.com:5432) <<--
Fatal error: Your /opt/openssl/openssl-1.1.0c/bin/openssl does not
support the "-starttls postgres" option
Example of openssl support:
~/bin/testssl$ ./testssl.sh --quiet
--openssl=/opt/openssl/openssl-2016-12-07/bin/openssl --startt ls=postgres
test.postgres.server.com:5432
Start 2016-12-07 18:06:03 -->> ip.add.re.ss:5432
(test.postgres.server.com:5432) <<--
Service set: STARTTLS via POSTGRES
Testing protocols (via openssl, SSLv2 via sockets)
SSLv2 not offered (OK)
SSLv3 offered (NOT ok)
TLS 1 offered
TLS 1.1 offered
TLS 1.2 offered (OK)
SPDY/NPN (SPDY is an HTTP protocol and thus not tested here)
HTTP2/ALPN (HTTP/2 is a HTTP protocol and thus not tested
here)
...
This PR implements `run_pfs()` in a manner similar to `run_allciphers()`. It uses OpenSSL followed by `tls_sockets()` to test for both supported PFS cipher suites as well as elliptic curves offered.
I made an attempt at addressing #548 by using different colors to print the different curve names, depending on strength. The colors chosen are exactly the same as those that would be chosen by `read_dhbits_from_file()`:
```
# bits <= 163: pr_svrty_medium
163 < # bits <= 193: pr_svrty_minor
193 < # bits <= 224: out
# bits > 224: pr_done_good
```
I also added code for #464 to create a list of the DH groups from RFC 7919 that a server supports. However, since no servers seem to support this at the moment (except with TLS 1.3), I marked this code to only run if the $EXPERIMENTAL flag is set.
For several elliptic curves the number of bits, as indicated by OpenSSL, is slightly different than the name implies. For example, for sect239k1 OpenSSL outputs: `Server Temp Key: ECDH, sect239k1, 238 bits`.
This PR aligns the output created by `parse_tls_serverhello()` with OpenSSL.
When the cipher-mapping.txt file is read, the contents of the "Mac=..." column is placed in `TLS_CIPHER_EXPORT` rather than the contents of the "export" column. This PR fixes that.
This PR address a problem in `run_drown()` when the server does not support SSLv2, but does support multiple certificates or doesn't have an RSA certificate.
One example of the problem can be seen with www.facebook.com. If `run_server_preferences()` is run before `run_drown()`, then the results of `run_drown()` are:
```
DROWN (2016-0800, CVE-2016-0703) not vulnerable on this port (OK)
make sure you don't use this certificate elsewhere with SSLv2 enabled services
https://censys.io/ipv4?q=A626B154CC65634181250B810B1BD4C89EC277CEA08D785EEBE7E768BDA7BB00 SHA256 A3F474FB17509AE6C5B6BA5E46B79E0DE6AF1BF1EEAA040A6114676E714C9965 could help you to find out
```
If only `run_drown()` is performed, then the result is:
```
DROWN (2016-0800, CVE-2016-0703) not vulnerable on this port (OK)
make sure you don't use this certificate elsewhere with SSLv2 enabled services
https://censys.io/ipv4?q=A626B154CC65634181250B810B1BD4C89EC277CEA08D785EEBE7E768BDA7BB00 could help you to find out
```
However, A626B154CC65634181250B810B1BD4C89EC277CEA08D785EEBE7E768BDA7BB00 is the fingerprint of Facebook's ECDSA certificate, not its RSA certificate.
In addition, as noted in the "FIXME," `run_drown()` will display the warning "make sure you don't use this certificate elsewhere with SSLv2 enabled services" even if the server doesn't have an RSA certificate, even though SSLv2 can only use RSA certificates.
This PR fixes this issue by only showing the warning if the server has an RSA certificate and by ensuring that the `$cert_fingerprint_sha2` used to construct the "https://censys.io/ipv4?q=..." URL only contains a single SHA256 fingerprint and that it is the fingerprint of the server's RSA certificate.
This PR modifies `cipher_pref_check()` to use `tls_sockets()`. As with similar PRs for `run_allciphers()`, `run_cipher_per_proto()`, and `run_rc4()`, it also makes use of `$OPENSSL s_client`, since `$OPENSSL s_client` is faster than `tls_sockets()`.
With this PR, `cipher_pref_check()` first uses `$OPENSSL s_client` to obtain an ordered list of ciphers. It then makes one call to `tls_sockets()` (or a few calls if proto is TLSv1.2 and `$SERVER_SIZE_LIMIT_BUG` is `true`) to find if the server supports any ciphers that are not detected by `$OPENSSL s_client`. If not, then it is done. If it finds one, then it throws out the previous results and starts over with `tls_sockets()`. [If proto is TLSv1.2 and `$SERVER_SIZE_LIMIT_BUG` is `true`, then it doesn't throw out the `$OPENSSL s_client` results. Instead, it continues with `tls_sockets()` to get the full list of supported ciphers, and then uses `tls_sockets()` to order that list.]
The result is that this PR works almost as fast as the current `cipher_pref_check()` if `$OPENSSL s_client` finds all of the supported ciphers, at the cost of a performance penalty when testing servers that support ciphers that would have otherwise been missed using just OpenSSL.
Note that in this PR I removed SSLv2 from the list of protocols tested. This is because https://community.qualys.com/thread/16255 states that "in SSLv2 the client selects the suite to use." It seems that in SSLv2, the client sends a list of ciphers that it supports, the server responds with a list of ciphers that the client and server have in common, and then "the client selects the suite to use." So, showing a cipher order for SSLv2 is a bit misleading.
As noted in #543, this PR does not modify the second part of `cipher_pref_check()`, which deals with NPN protocols.
This PR implements `run_rc4()` in a similar manner to `run_allciphers()` and `run_cipher_per_proto()` (in PR #541). The change doesn't seem to have much of an impact on speed, but when sockets are used it can detect ciphers that aren't locally supported by OpenSSL.
This PR fixes two minor bugs in run_allciphers():
* If `$SSL_NATIVE` or `$FAST` is `true`, then the cipher mapping file will not be used (unless `$OPENSSL ciphers` does not support the `-V` option), so there is no "fallback" to openssl, even if `[[ $TLS_NR_CIPHERS == 0 ]]`.
* If `$using_sockets` is `false` and `$SHOW_EACH_C` is `true`, then `ossl_supported` should be checked to see if the cipher was tested, not `TLS_CIPHER_OSSL_SUPPORTED`.
This function reorganizes `run_server_defaults()` based on the suggestion in #515.
The current `determine_tls_extensions()` is renamed to `get_server_certificate()`, and two changes are made to it:
*it no longer includes an extra call to `$OPENSSL s_client` to check for the ALPN extension; and
* rather than setting `$TLS_EXTENSIONS` to be the extensions found during this call to the function, it adds any newly found extensions to those already in `$TLS_EXTENSIONS`.
The PR then adds a new function, `determine_tls_extensions()`, which borrows some logic from the old `determine_tls_extensions()`, but this new `determine_tls_extensions()` only looks for additional TLS extensions, including ALPN.
`run_server_defaults()` makes multiple calls to `get_server_certificate()` (as it previously did to `determine_tls_extensions()`) in order to collect all of the server's certificates, and then it makes one call to `determine_tls_extensions()`, which checks for support for extensions that were not checked for by `get_server_certificate()` (e.g., ALPN, extended master secret, signed certificate timestamps).
The new `determine_tls_extensions()` will check for most of the extensions that are checked for by
`run_server_defaults()`, including the heartbeat extension, so the call to `determine_tls_extensions()` from `run_heartbleed()` will still work.
> The dh_bits are still not shown, maybe because of #531.
This PR fixes the issue of dh_bits not being shown if the cipher-mapping.txt file is missing. The problem is that the code in `parse_tls_serverhello()` that parses the ServerKeyExchange message assumes that `$rfc_cipher_suite` has the RFC version of the name the cipher suite. However, if the cipher-mapping.txt file is missing, `$rfc_cipher_suite` will have the OpenSSL name of the cipher suite. This PR changes the code to recognize either the RFC or OpenSSL names for ciphers with ephemeral DH or ECDH keys.
When `tls_sockets()` is used with the "full" option and the chosen cipher suite involves an ephemeral finite-field DH key (DH), this PR extracts the public key from the ServerKeyExchange message and adds it to `$TMPFILE`. In addition (and the primary reason for this PR), it compares the ephemeral public key's parameters to those specified in RFC 7919, and indicates whether one the groups from that RFC was used. This will allow `run_pfs()` to be extended to indicate which, if any, RFC 7919 DH groups a server supports.
This PR adds parsing of the CertificateStatus message to `parse_tls_serverhello()`. If the caller requests that the "full" response be parsed, then the CertificateStatus message is parsed, and the OCSP response is added to $TMPFILE, in a manner similar to the output of `$OPENSSL s_client` when the `-status` option is used.
The string "CamelliaGCM" is too long for the "Encryption" column printed by `neat_list()`. So, either "CamelliaGCM" needs to be shortened to "Camellia" (as this PR does), or the "Encryption" column needs to be made wider.
Client simulations can still use sockets even if the cipher mapping file is missing. If the cipher file is present, then `parse_tls_serverhello()` write the RFC name for the cipher and then `run_client_simulation()` converts that to the OpenSSL name (so that the output is the same as if OpenSSL were used). This PR changes `parse_tls_serverhello()` so that it writes the OpenSSL name for the cipher if the mapping file is missing, which `run_client_simulation()` can then just display.
This PR also unsets `ADD_RFC_STR` if the mapping file is missing, so that `neat_list()` won't try to display the RFC names for the ciphers.
This PR speeds up the implementation of `run_allciphers()` by introducing a number of changes:
* Rather than check for implemented ciphers in a hierarchical manner (as introduced in #326), this PR follows the approach of `cipher_pref_check()`. Testing a block of ciphers, marking the selected cipher as implemented, and then testing same block of ciphers, minus those that have previously been selected, until a test fails. Thus the number of calls to `$OPENSSL s_client` is just one more than the number of ciphers implemented. (Since some servers cannot handle ClientHellos with more than 128 messages, the tests are performed on blocks of 128 or few ciphers. So, if OpenSSL supports 197 ciphers, the number of calls to `$OPENSSL s_client` is 2 plus the number of ciphers supported by the server.
* If $using_sockets is true, then OpenSSL is used first to find all supported ciphers that OpenSSL supports (since OpenSSL is faster than `tls_sockets()`), and then `tls_sockets()` is only used to test those cipher suites that were not found to be supported by OpenSSL.
* The `prepare_debug()` function, which reads in `$CIPHERS_BY_STRENGTH_FILE` determines which ciphers are supported by the version of OpenSSL being used. If a version of OpenSSL older than 1.0 is being used, then this is used to determine which ciphers to test using OpenSSL rather than using `$OPENSSL ciphers -V`.
Following the approach of `cipher_pref_check()` reduces the number of queries to the server. Using OpenSSL before `tls_sockets()` reduces the number of calls to `tls_sockets()` to 3 plus the number of ciphers supported by the server that are not supported by OpenSSL, so the cost penalty over just using OpenSSL is fairly small.
The `tls_sockets()` and `sslv2_sockets()` use `get_pub_key_size()` to extract the size of the server's public key if the full response is being processed, and `get_pub_key_size()` uses `$OPENSSL pkey` to extract the server's public key from the certificate. However, OpenSSL 0.9.8 does not support the "pkey" command. This PR changes `get_pub_key_size()` to suppress the error message displayed by OpenSSL when the "pkey" command is not supported.
This PR adds parsing of the Certificate message to `parse_tls_serverhello()`. If the caller requests that the "full" response be parsed, then the Certificate message is parsed, the server's certificate is placed in $HOSTCERT and the intermediate certificates are placed in $TEMPDIR/intermediatecerts.pem. The certificates are also added to $TMPFILE, in a manner similar to the output of `$OPENSSL s_client` when the `-showcerts` option is used.
This PR uses `tls_sockets()` to determine whether a server supports certain extensions that may not be supported by `$OPENSSL`. At the moment it checks for max_fragment_length, client_certificate_url, truncated_hmac, ALPN, signed_certificate_timestamp, encrypt_then_mac, and extended_master_secret.
In https://github.com/dcooper16/testssl.sh/blob/extended_tls_sockets/testssl.sh, `run_server_defaults()` is re-written to use `tls_sockets()` instead of `$OPENSSL`, with just one call to `$OPENSSL s_client` to get the session ticket, which reduces the dependence on `$OPENSSL`, but this PR limits the number of calls to `tls_sockets()`, which is still slow.
Note: I included ALPN in the `tls_sockets()` ClientHello since a single call to `tls_sockets()` cannot test for both NPN and ALPN, and since support for NPN was added to OpenSSL before support for ALPN was added, I figured it was more likely that `determine_tls_extensions()` had already determined whether the server supported NPN.
This PR fixes the same issues as were fixed in PR #513, but also makes two changes to `parse_tls_serverhello()`:
* It changes the number of bits for curve X25519 from 256 to 253 to match OpenSSL.
* It removes the "ECDH, " from the "Server Temp Key: " line in order to match OpenSSL's output.
This PR fixes two issues related to curve X25519.
First, while OpenSSL 1.1.0 supports curve X25519, it is not included in the output of `$OPENSSL ecparam -list_curves`. I tried several versions of OpenSSL (and one version of LibreSSL), and every version output either "Error with command" or "unknown option" in response to `$OPENSSL s_client -curves $curve` if it either did not support the `-curves` option or did not support `$curve`. (When the `-curve` option was supported with `$curve`, a "connect" error was output.)
The second issue is that the "Server Temp Key" line in the output of `s_client` is different for curve X25519. For other elliptic curves, the output is
```
Server Temp Key: ECDH, P-256, 256 bits
```
For X25519 it is:
```
Server Temp Key: X25519, 253 bits
```
So, `read_dhbits_from_file()` needs to allow for `$what_dh` being "X25519" rather than "ECDH" and `run_pfs()` needs to allow for the possibility that the curve name will be the first field rather than the second.
The PR changes `run_allciphers()` to use `tls_sockets()` (and `sslv2_sockets()`)rather than `$OPENSSL` unless `$SSL_NATIVE` is set or `$STARTTLS` is non-empty. Using sockets allows `run_allciphers()` to test all ciphers, rather than just those supported by `$OPENSSL`.
Using sockets results in `run_allciphers()` running more slowly, partially since it is testing more ciphers, but mostly since `tls_sockets()` is currently slower than `$OPENSSL` (as noted in #413).
This PR makes similar changes to `run_client_simulation()` as were made to `tls_sockets()`, so that `run_client_simulation()` retrieves the entire server response, even if it is split across multiple packets, and it has `parse_tls_serverhello()` extract information about the server's ephemeral public key, if present.
The PR also changes `run_client_simulation()` to use information about the ephemeral public key. It includes the length of the public key in the output and, if it is a DH public key, checks that the size is within the acceptable range (`${minDhBits[i]} <= dh_bits <= ${maxDhBits[i]}`).
This PR adds initial parsing of the ServerKeyExchange message to `parse_tls_serverhello()`. For ephemeral DH keys, it extracts the length of the key. For ephemeral ECDH keys that are encoded using the named_curve option, it extracts the length of the key and the name of the curve.
This PR allows the caller to provide additional extensions to `tls_sockets()` to be included in the ClientHello. If the caller provides an extension that would have already been included in the ClientHello, then the caller's value for the extension is used rather than the default value.
This PR extended `parse_tls_serverhello()` in a few ways:
* If the "full" response is to be parsed, then additional checks are performed to verify that `$tls_hello_ascii` contains the entire response
* The extensions field is parsed and the list of extensions found is placed in `$TLS_EXTENSIONS` (if the "full" response is being parsed).
* Initial support for TLS 1.3 is added:
- Accounts for differences between TLS 1.2 ServerHello and TLS 1.3 ServerHello (as outlined in PR #499).
- Recognizes new alerts and handshake message types.
- Allows for server response to include message fragments of type "application data"
I forgot that `parse_tls_serverhello()` is also called by `client_simulation_sockets()`. Since PR #499 changed the input to `parse_tls_serverhello()`, the change needs to be made in `client_simulation_sockets()` as well.
Now that the mapping file is no longer used, `$ADD_RFC_STR` should not be unset just because the mapping file cannot be found.
In addition, since `show_rfc_style()` is now used in `parse_tls_serverhello()`, it cannot return an empty string just because the user set "--mapping no-rfc" on the command line. Instead, `neat_list()` should check the value of `$ADD_RFC_STR` and not call `show_rfc_style()` if it has been unset.
Finally, since `show_rfc_style()` no longer returns strings with extra spaces, there is no need to call `strip_spaces()`
In some cases the server's response to a ClientHello spans more than one packet. If the goal is just to determine whether the connection was successful and to extract a few pieces of information from the ServerHello message, then this is unlikely to be a problem. However, if there is a desire to extract the server's certificate chain (Certificate message) or to determine the type and size of the server's ephemeral public key (ServerKeyExchange message), then the entire response needs to be obtained, even if it spans multiple packets.
This PR adds a new function, `check_tls_serverhellodone()`, that checks whether the entire response has been received (e.g., whether the ServerHelloDone message has been received). If the response indicates that the response is incomplete, then `tls_sockets()` requests more data from the server until the response is complete or until the server doesn't provide any more data in response.
The PR only changes the behavior of `tls_sockets()` if the caller indicates that it wants to extract the ephemeral key or that it wants the entire response to be parsed. Otherwise, only the first packet returned by the server is sent to `parse_tls_serverhello()`. [The value of `$process_full` is not used at the moment, but will be in a subsequent PR that modifies `parse_tls_serverhello()`.]
This PR also changes `tls_sockets()` to send a close_notify to the server if the connection was successfully established.
PR #346 added a test for version tolerance to `run_protocols()`, but I think it may now be more appropriate to remove that test. Draft -16 of TLS 1.3, which was posted on September 22, changed the way that version negotiation is handled for TLS 1.3 and above. The current version tolerance test sends a ClientHello with the version field set to "03, 05", to represent a TLS 1.4 ClientHello. While this was consistent with RFC 5246 and with drafts of TLS 1.3 up to -15, draft -16 changed the version field to `legacy_version` and declared that its value should be "03, 03" for TLS 1.2 and above. (For TLS 1.3 and above a Supported Versions extension is included to inform the server which versions of TLS the client supports.) The change in draft -16 was made as a result of the problems with servers not handling version negotiation correctly.
Since the current draft suggests that a server should never be presented with a ClientHello with a version higher than "03, 03" (even for clients that support TLS versions higher than 1.2), it seems there is no reason to include the version tolerance test anymore.
For servers that do not support TLS 1.2, the additional checks that were added by PR #346 will already detect if the server cannot perform version negotiation correctly.
This PR adds the option for `parse_sslv2_serverhello()` to extract information from the ServerHello (server key size and cipher suites supported) and write the information to `$TMPFILE` as well as to write the server's certificate to `$HOSTCERT`.
The mapping file is now only used in `show_rfc_style()`. This PR changes `show_rfc_style()` to use the `$TLS_CIPHER_HEXCODE` and `$TLS_CIPHER_RFC_NAME` arrays.
Note that `get_install_dir()` still searches for the mapping-rfc.txt in order to determine `$INSTALL_DIR`. `$INSTALL_DIR` is only used to determine the location of the CA bundles in `determine_trust()`:
```
local ca_bundles="$INSTALL_DIR/etc/*.pem"
```
This PR changes `sslv2_sockets()` so that a list of ciphers may optionally be passed as an argument. This will support the use of `sslv2_sockets()` in some places where `$OPENSSL s_client` is currently used.
s_client's manpage states for -nextprotoneg:
"Empty list of protocols is treated specially and will cause the client
to advertise support for the TLS extension but disconnect just after
reciving ServerHello with a list of server supported protocols."
Consequently, the previous workaround of just quoting an empty variable
is insufficient and the "-nextprotoneg" parameter has to be removed
entirely from the command-line in case of an empty argument.
In other locations where "-nextprotoneg" is used
- its argument cannot be empty ($NPN_PROTOs is initialized to a non-
empty value and set read-only) or
- its argument is intended to be empty (line 3724) or
- the command will not be invoked at all (for-loop parameter, line 3725)
This fixes#467 - again.
Additionally this patch prefers usage of -alpn over -nextprotoneg if the
openssl binary used supports it.
Refactor the while loop so it doesn't use a subshell anymore. Also use
"read -r" to prevent backslash escaping.
```
In testssl.sh line 1193:
app_banners="$app_bannersline"
^-- SC2030: Modification of app_banners is local (to subshell caused by pipeline).
In testssl.sh line 1195:
fileout "app_banner" "WARN" "Application Banners found: $app_banners"
^-- SC2031: app_banners was modified in a subshell. That change might be lost.
```
Found by ShellCheck.
This commit fixes the following two instances of referenced but not assigned
variables:
```
In testssl.sh line 1159:
rp_banners="$rp_bannersline"
^-- SC2154: rp_bannersline is referenced but not assigned.
In testssl.sh line 1193:
app_banners="$app_bannersline"
^-- SC2154: app_bannersline is referenced but not assigned.
```
Found by ShellCheck.
The argument to -nextprotoneg is provided in sometimes empty an unquoted
variables. Because of the missing quotes, the next word on the line "-status"
gets parsed as "-nextprotoneg"'s argument instead of enabling the OCSP status
check.
This fixes#467.
Fix referenced but not assigned variable 'sign_algo'.
In testssl.sh line 4309:
fileout "${json_prefix}algorithm" "DEBUG" "Signature Algorithm: $sign_algo"
^-- SC2154: sign_algo is referenced but not assigned.
Found by ShellCheck.
Two instances of referenced but not assigned variables ('req' instead of
'ret').
In testssl.sh line 4130:
if [[ $req -eq 0 ]]; then
^-- SC2154: req is referenced but not assigned.
Found by ShellCheck.
Changed `Enc=CHACHA20/POLY1305(256)` to `Enc=ChaCha20(256)` and `Enc=GOST-28178-89-CNT(256)` to `Enc=GOST(256)` in order to shorten the names that are printed, so that they fit in the allocated column.
Added the four experimental post-quantum cipher suites mentioned in #462.
`socksend_tls_clienthello()` always includes a server name extension in the ClientHello (for TLS 1.0 and above), even if `$SNI` is empty. If `$NODE` is an IP address, then the IP address is placed in the extension, even though RFC 6066 says that only DNS names are supported in the extension.
This PR changes `socksend_tls_clienthello()` so that the server name extension is only included in the ClientHello is `$SNI` is not empty.
This PR is an attempt to address issue #447. If more than one certificate is being displayed, then a parenthetical saying "(in response to request w/o SNI)" is added for any certificate that was obtained using `$SNI=""`.
In addition, if the certificate was obtained without SNI, then `certificate_info()` doesn't call `$OPENSSL s_client` in order to obtain the non-SNI host certificate and it does not display a separate "Trust (hostname)" finding for the non-SNI certificate.
When `certificate_info()` is given a certificate with a DH public key it displays something like:
```
Server key size fixme: dhKeyAgreement 3072 bits (FIXME: can't tell whether this is good or not)
```
This PR fixes that so that the output is:
```
Server key size DH 3072 bits
```
This PR is in response to issue #454. I tried repeating the reported problem by creating a certificate in which the extendedKeyUsage extension was present and only included the anyExtendedKeyUsage OID. In running the test, I discovered two problems.
First, when `determine_trust()` is calling `verify_retcode_helper()` to display the reason that path validation failed, it assumes that there are at least two certificate bundles provided. (I was running the test using just one certificate bundle, containing my local root.) So, I changed `determine_trust()` to use `${verify_retcode[1]}` rather than `${verify_retcode[2]}` in the case that all bundles failed (it seems that 2 vs. 1 was an arbitrary choice).
Once that was fixed, testssl.sh output "NOT ok (unknown, pls report) 26". So, the second thing this PR fixes is to output "NOT ok (unsupported certificate purpose)" if OpenSSL responds with an unsupported certificate purpose error.
With OpenSSL 1.1.0, `s_client -no_ssl2` fails with an "unknown option" error. At the moment the `-no_ssl2` option is only used in two functions, `run_client_simulation()` and `run_crime()`. In `run_crime()`, the `-no_ssl2` option is only included if the OpenSSL version is 0.9.8.
This PR checks whether the OpenSSL version in use supports the `-no_ssl2` option, and if it doesn't, it removes it from the calls to `s_client` in `run_client_simulation()`.
If the version of OpenSSL being used doesn't support `s_client -ssl3` (e.g., OpenSSL 1.1.0), `run_beast()` doesn't display a warning that testing for CBC in SSLv3 isn't locally supported.
This PR adds a "Local problem" warning if the OpenSSL being used doesn't support `s_client -ssl3`.
The test for whether a server only supports SSLv2 was broken, since `$OPTIMAL_PROTO` will be `-ssl2` whether SSLv2 is the only protocol that succeeds or no protocol succeeds.
This PR sets $OPTIMAL_PROTO (or $STARTTLS_OPTIMAL_PROTO) to "" if no protocol succeeds.
If the version of OpenSSL being used doesn't support `s_client -ssl3` (e.g., OpenSSL 1.1.0), `run_ssl_poodle()` displays `not vulnerable (OK)` even though it can't test whether the server is vulnerable.
This PR fixes it so that a "Local problem" warning is displayed is `s_client -ssl3` isn't supported.
The PR also removes the `$SNI` from the call to `$OPENSSL s_client` since OpenSSL ignores the `-servername` directive for `-ssl3` anyways.
If testssl.sh is called with `--devel 22` and the response from `sslv2_sockets()` is not 0, then `tls_sockets()` will be called, and the result of the `tls_sockets()` command will be output rather than the result of the `sslv2_sockets()` command.
This PR addresses the "FIXME" in `run_protocols()`:
```
sslv2_sockets #FIXME: messages/output need to be moved to this (higher) level
```
It also changes `run_drown()` to call `sslv2_sockets()` in order to avoid duplicate code.
This PR is in response to issue #352, where it was noted that Bash does not support binary data in strings.
I replaced all calls to `sockread()` with calls to `sockread_serverhello()`, and then, since is now used everywhere and not just to read ServerHello messages, I renamed `sockread_serverhello()` to `sockread()`.
I tested the revised code against several servers, including one that is vulnerable to CCS and Heartbleed, and got the same results as with the current code (although the hexdumps displayed in debug mode differ).
One concern I have is the code in `run_ccs_injection()`. The current code is:
```
byte6=$(echo "$SOCKREPLY" | "${HEXDUMPPLAIN[@]}" | sed 's/^..........//')
lines=$(echo "$SOCKREPLY" | "${HEXDUMP[@]}" | count_lines )
debugme echo "lines: $lines, byte6: $byte6"
if [[ "$byte6" == "0a" ]] || [[ "$lines" -gt 1 ]]; then
pr_done_best "not vulnerable (OK)"
...
```
I revised this to:
```
if [[ -s "$SOCK_REPLY_FILE" ]]; then
byte6=$(hexdump -ve '1/1 "%.2x"' "$SOCK_REPLY_FILE" | sed 's/^..........//')
lines=$(hexdump -ve '16/1 "%02x " " \n"' "$SOCK_REPLY_FILE" | count_lines )
debugme echo "lines: $lines, byte6: $byte6"
fi
rm "$SOCK_REPLY_FILE"
if [[ "$byte6" == "0a" ]] || [[ "$lines" -gt 1 ]]; then
...
```
In the revised code `byte6` is initialized to `0a` so that the response is `not vulnerable (OK)` if `$SOCK_REPLY_FILE` is empty. This has worked okay since for all of the servers that I tested that weren't vulnerable `$SOCK_REPLY_FILE` was empty. Since I haven't seen any other examples, I don't understand why check for vulnerability was written the way it was. So, I'm a bit concerned that the test in the revised code may produce incorrect results now that `hexdump -ve '1/1 "%.2x"' "$SOCK_REPLY_FILE"` is an accurate hexdump of the reply.