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 viatls_sockets "04"andtls_sockets "03", checking return codes and implementing fallback logic at lines 11058-11067. - OpenSSL mode: Constructs an
openssl s_clientcommand with the filtered cipher list (-cipher $fs_cipher_list) and appends a-curvesoption 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 totrue, 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 fors_clientcommands.CURVEShandling: Automatically derived fromOSSL_SUPPORTED_CURVESwith 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-secrecyto enable Forward Secrecy testing. - Implementation: The
run_fsfunction filters for DHE/ECDHE/TLS 1.3 ciphers and attempts handshakes via sockets or OpenSSL. - Minimum Threshold: The
CLIENT_MIN_FSvariable (default 5) determines the minimum client-side cipher support required to run the test. - Output Control: Set
WIDE=trueto display detailed cipher and curve information; missing FS caps the grade at "B". - Backend Selection: Use
SSL_NATIVE=trueto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →