# How to Test TLS 1.3 Support and Available Cipher Suites with testssl.sh

> Easily test TLS 1.3 support and available cipher suites with testssl.sh. Discover how this powerful tool verifies your server's security configuration and identifies supported protocols.

- Repository: [Dirk Wetter/testssl.sh](https://github.com/drwetter/testssl.sh)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/drwetter/testssl.sh/blob/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:

```bash
$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`](https://github.com/drwetter/testssl.sh/blob/main/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:

```bash
./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:

```bash
./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:

```bash
./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):

```bash
./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:

```bash
#!/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_TLS13` flag at line 21211 before attempting server connections.
- The `run_prototest_openssl` function (lines 5509-5522) handles protocol negotiation, while `run_onecipher` enumerates individual cipher suites through iterative handshakes against the `ciphers_to_test` array.
- Use the `-tls1_3` flag to isolate testing to TLS 1.3 only, and combine with `-p` or `-E` for protocol-specific cipher enumeration.
- The `--openssl` flag allows specifying custom OpenSSL binaries when the system default lacks TLS 1.3 capabilities.
- Client simulation data in [`utils/update_client_sim_data.pl`](https://github.com/drwetter/testssl.sh/blob/main/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`](https://github.com/drwetter/testssl.sh/blob/main/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.