How testssl.sh Tests for Forward Secrecy (FS): Configuration and Implementation

testssl.sh tests for Forward Secrecy by filtering cipher suites to isolate only DHE, ECDHE, and TLS 1.3 offerings, then attempting handshakes via bash sockets or the native OpenSSL client to verify server support. The test is triggered with the -f flag and controlled by environment variables including WIDE, SSL_NATIVE, and CLIENT_MIN_FS.

When auditing TLS configurations with drwetter/testssl.sh, verifying Forward Secrecy ensures that session keys remain secure even if the server's private key is compromised later. The script implements this check in the run_fs function, which negotiates ciphers using ephemeral Diffie-Hellman or Elliptic Curve Diffie-Hellman exchanges according to the source code at testssl.sh line 11068.

Enabling Forward Secrecy Testing

To activate the FS audit, pass -f, --fs, or --forward-secrecy when invoking the script. The option table at line 21557 defines these flags, and the case handling at line 24811 dispatches execution to the dedicated run_fs function. When enabled, the script creates a JSON identifier FS at line 11002 to track results for machine-readable output.

The FS Testing Architecture

The run_fs function (starting at line 11068) orchestrates the Forward Secrecy validation through a multi-stage pipeline that selects appropriate ciphers and chooses between socket-based or OpenSSL-based execution.

Cipher Collection and Filtering

The script iterates over the complete cipher list (TLS_CIPHER_RFC_NAME, TLS_CIPHER_HEXCODE) and applies strict filtering logic at lines 11024-11025. A cipher qualifies as FS-capable only if it meets these criteria:

  • Uses DHE, ECDHE, or TLS 1.3 (identified by hex code "${hexc:2:2}" == "13")
  • Is not classified as NULL, DES, RC4, or PSK
  • Is supported by the local OpenSSL installation or available through bash sockets

Before testing begins, the script verifies the client can offer at least CLIENT_MIN_FS ciphers (default value 5, declared at line 225). If the available FS ciphers fall below this threshold, the test aborts with a warning at lines 11071-11075.

Socket vs. OpenSSL Execution Modes

The script selects its testing backend based on the SSL_NATIVE, FAST, and TLS_NR_CIPHERS flags (lines 11004-11006):

  • Socket mode (using_sockets=true): Sends TLS 1.2 and TLS 1.3 ClientHello packets containing the collected FS cipher hex codes via tls_sockets "04" and tls_sockets "03", checking return codes and implementing fallback logic at lines 11058-11067.
  • OpenSSL mode: Constructs an openssl s_client command with the filtered cipher list (-cipher $fs_cipher_list) and appends a -curves option to exhaustively test all supported elliptic curves (lines 11090-11108). When more than 28 curves are present, the script automatically splits them into two batches (lines 11177-11188).

Result Interpretation and Grading

After handshake completion, the script extracts the negotiated cipher using fs_cipher=$(get_cipher $TMPFILE). If no handshake succeeds, testssl.sh reports "No ciphers supporting Forward Secrecy (FS) offered" at lines 11114-11116. Successful negotiation marks FS as offered with JSON status OK (line 11122).

When WIDE mode is enabled, the output expands to include specific cipher names, hex codes, key exchange types, and curve information (lines 11123-11127). If the runtime detection HAS_DH_BITS returns false, the script cannot display DH/ECDH key-size information and emits a warning at lines 11012-11015.

According to the grading logic at line 11116, missing Forward Secrecy capability caps the overall security grade at "B" regardless of other strengths.

Configuration Options and Environment Variables

The behavior of the FS test is controlled through several environment variables and command-line options:

  • CLIENT_MIN_FS (default: 5): Sets the minimum number of FS ciphers required on the client side to run the test. Declared at line 225.
  • WIDE: When set to true, prints the complete list of offered FS ciphers/curves with additional columns for hex codes and key exchange details.
  • SSL_NATIVE: Forces the use of the native OpenSSL client instead of bash sockets, useful on platforms where socket reliability is uncertain.
  • FAST: Shortcut that disables socket usage, running a reduced FS test for quicker results.
  • HAS_DH_BITS: Runtime-detected boolean indicating whether the OpenSSL build supports displaying DH/ECDH key-size information.
  • OPENSSL: Specifies the path to the OpenSSL binary used for s_client commands.
  • CURVES handling: Automatically derived from OSSL_SUPPORTED_CURVES with internal batching logic when curve count exceeds 28; no user-visible switch controls this.

Practical Usage Examples

Run a basic Forward Secrecy test against a target host:

./testssl.sh -f example.com:443

Enable the wide view to see curve information and hex codes:

WIDE=true ./testssl.sh -f example.com:443

Force OpenSSL-native mode when socket implementations are unreliable:

SSL_NATIVE=true ./testssl.sh -f example.com:443

Adjust the minimum required client FS ciphers (for example, requiring at least 10):

CLIENT_MIN_FS=10 ./testssl.sh -f example.com:443

Summary

  • Invocation: Use -f, --fs, or --forward-secrecy to enable Forward Secrecy testing.
  • Implementation: The run_fs function filters for DHE/ECDHE/TLS 1.3 ciphers and attempts handshakes via sockets or OpenSSL.
  • Minimum Threshold: The CLIENT_MIN_FS variable (default 5) determines the minimum client-side cipher support required to run the test.
  • Output Control: Set WIDE=true to display detailed cipher and curve information; missing FS caps the grade at "B".
  • Backend Selection: Use SSL_NATIVE=true to bypass bash sockets and use the system OpenSSL client directly.

Frequently Asked Questions

What ciphers qualify as Forward Secrecy in testssl.sh?

According to the filtering logic at lines 11024-11025, testssl.sh classifies ciphers as FS-capable if they use DHE, ECDHE, or TLS 1.3 key exchange (identified by hex code 13), and explicitly excludes NULL authentication, DES, RC4, and PSK variants.

Why does testssl.sh cap the grade at B when FS is missing?

The grading logic at line 11116 enforces a maximum grade of "B" when the server fails to offer Forward Secrecy, regardless of other security strengths. This reflects the cryptographic principle that without FS, compromised long-term private keys could decrypt past sessions.

How do I see the specific elliptic curves offered by the server?

Set the environment variable WIDE=true when running the test. This activates the detailed output block at lines 11123-11127, which displays the negotiated curves alongside cipher names, hex codes, and key exchange mechanisms. If HAS_DH_BITS is false, curve size information will be unavailable.

What happens if my OpenSSL client supports fewer than 5 FS ciphers?

If the available client ciphers fall below the CLIENT_MIN_FS threshold (default 5, defined at line 225), the script skips the test and emits a warning at lines 11071-11075. You can override this by setting CLIENT_MIN_FS to a lower value or ensuring your OpenSSL binary supports a broader cipher suite.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →