How to Test TLS 1.3 Support and Available Cipher Suites with testssl.sh
testssl.sh detects TLS 1.3 support by verifying that the local OpenSSL binary accepts the -tls1_3 flag, then probes the server using run_prototest_openssl and enumerates available cipher suites through iterative handshake tests against the ciphers_to_test array.
The drwetter/testssl.sh repository provides a comprehensive Bash-based SSL/TLS testing framework that automatically identifies TLS 1.3 capabilities and catalogs supported cipher suites. Understanding how to leverage these specific features allows security professionals to verify modern encryption standards and ensure servers reject obsolete protocol versions.
How TLS 1.3 Detection Works Internally
The script implements a tightly-coupled, three-stage verification process defined in the main testssl.sh file.
OpenSSL Capability Verification
Before testing any server, testssl.sh validates that the bundled or specified OpenSSL binary supports TLS 1.3. At line 21211, the script executes a capability check that sets the Boolean flag HAS_TLS13 if the binary recognizes the -tls1_3 option. If this flag remains unset, all TLS 1.3 related tests are silently skipped and a warning is emitted at line 6235: "$OPENSSL doesn't support \"s_client -tls1_3\"".
Server Protocol Probing
Once local capabilities are confirmed, the run_prototest_openssl function (lines 5509-5522) probes the target server. The function constructs an OpenSSL command via s_client_options and executes:
$OPENSSL s_client $(s_client_options "-state $protos $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI")
Unlike older protocol tests, the protos variable remains empty for TLS 1.3 (line 5522) because no -no_tls1_3 flag is required in the exclusion logic. After the connection completes, the get_protocol helper reads the ServerHello response (lines 1075-1090) and forces protocol="TLSv1.3" when the handshake succeeds and the response matches the TLS 1.3 pattern.
Cipher Suite Enumeration
After confirming TLS 1.3 availability, testssl.sh iterates through the ciphers_to_test array (lines 10448-10453), which contains identifiers such as tls1_3_RSA, tls1_3_ECDSA, tls1_3_EdDSA, and tls1_3_MLDSA. For each entry, the script invokes run_onecipher (indirectly via the loop in test_one_proto), appending -ciphersuites $cipherlist to the OpenSSL command. Successful handshakes (indicated by ret=0) are stored in the ciphers associative array and rendered in the final report section.
Additionally, the file utils/update_client_sim_data.pl (line 170) ensures that client simulation tests also include the -tls1_3 flag, maintaining consistency across all TLS 1.3 assessments.
Testing TLS 1.3 from the Command Line
Basic Automatic Detection
Run the default scan to automatically detect TLS 1.3 and display supported cipher suites:
./testssl.sh --openssl ./bin/openssl example.com:443
The output includes a dedicated "TLS 1.3" line indicating support status, followed by the "Cipher suites (TLS 1.3)" section listing available options such as TLS_AES_256_GCM_SHA384 and TLS_CHACHA20_POLY1305_SHA256.
Isolate TLS 1.3 Testing
To test only TLS 1.3 and skip older protocol versions:
./testssl.sh -p -E -tls1_3 example.com:443
-p: Displays the protocol matrix-E: Enumerates ciphers per protocol-tls1_3: Restricts testing to TLS 1.3 only
Detailed Cipher Listing
Show every individual TLS 1.3 cipher accepted by the server:
./testssl.sh -e --show-each -tls1_3 example.com:443
The -e (or --each-cipher) flag combined with --show-each prints each cipher on a separate line, providing granular visibility into server configuration.
Using Custom OpenSSL Builds
When testing with a specific OpenSSL binary that supports advanced TLS 1.3 features (such as QUIC in OpenSSL 3.2):
./testssl.sh --openssl /usr/local/openssl-3.2/bin/openssl -tls1_3 example.com:443
The --openssl flag overrides the default binary selection, essential when the system OpenSSL lacks TLS 1.3 support but a custom build includes it.
Automated CI Integration
For scripted validation in deployment pipelines:
#!/usr/bin/env bash
HOST="example.com:443"
if ./testssl.sh -p -tls1_3 "$HOST" | grep -q "TLS 1.3 *:.*YES"; then
echo "✅ TLS 1.3 is supported"
else
echo "❌ TLS 1.3 not supported"
exit 1
fi
This pattern gates deployments based on TLS 1.3 availability, exiting with status 1 if the protocol is unsupported.
Summary
- testssl.sh automatically detects local OpenSSL TLS 1.3 support via the
HAS_TLS13flag at line 21211 before attempting server connections. - The
run_prototest_opensslfunction (lines 5509-5522) handles protocol negotiation, whilerun_onecipherenumerates individual cipher suites through iterative handshakes against theciphers_to_testarray. - Use the
-tls1_3flag to isolate testing to TLS 1.3 only, and combine with-por-Efor protocol-specific cipher enumeration. - The
--opensslflag allows specifying custom OpenSSL binaries when the system default lacks TLS 1.3 capabilities. - Client simulation data in
utils/update_client_sim_data.pl(line 170) ensures consistent TLS 1.3 testing across all assessment modes.
Frequently Asked Questions
How does testssl.sh determine if my OpenSSL supports TLS 1.3?
testssl.sh checks for TLS 1.3 support at startup by attempting to run openssl s_client -tls1_3 and sets the HAS_TLS13 Boolean flag at line 21211 in testssl.sh. If this flag is false, the script skips all TLS 1.3 tests and emits a warning at line 6235 indicating the binary does not support the required flag.
Can I test TLS 1.3 cipher suites without testing other protocols?
Yes. Append the -tls1_3 flag to your command to restrict testing to TLS 1.3 only. Combine this with -E to enumerate ciphers specifically for this protocol, or use -e --show-each to list every supported TLS 1.3 cipher individually without the broader protocol scan.
What TLS 1.3 cipher suites does testssl.sh check for?
The script checks for standard TLS 1.3 cipher suites defined in the ciphers_to_test array (lines 10448-10453), including TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256, and identifiers for RSA, ECDSA, EdDSA, and MLDSA authentication mechanisms.
Why does testssl.sh require a specific OpenSSL binary for TLS 1.3 testing?
TLS 1.3 support depends entirely on the OpenSSL version being used. The script uses the bundled binary or a user-specified path via --openssl because system OpenSSL installations may lack the -tls1_3 flag or specific cipher implementations required for proper testing. The bundled binaries in bin/openssl are pre-compiled to ensure consistent TLS 1.3 detection capabilities across different operating systems.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →