How to Use testssl.sh for Certificate Chain Validation and CA Trust Checking
testssl.sh validates X.509 certificate chains by retrieving server-presented certificates, building an intermediate bundle, and verifying the complete chain against five built-in CA trust stores (Mozilla, Microsoft, Apple, Java, Linux) using OpenSSL, with support for custom root CAs via the --add-ca option or ADDTL_CA_FILES environment variable.
The drwetter/testssl.sh repository provides a comprehensive SSL/TLS testing framework that automates certificate chain validation and CA trust verification. Unlike basic OpenSSL commands, testssl.sh systematically checks your server's certificate chain against multiple trust stores and identifies specific validation failures such as incomplete chains or untrusted roots. This guide explains the underlying implementation and practical commands for effective certificate chain validation.
How testssl.sh Validates Certificate Chains
Retrieving the Server Certificate Chain
The validation process begins in utils/checkcert.sh, which connects to the target server and extracts the complete certificate chain. The script uses openssl s_client to capture every certificate the server presents, storing them as individual level*.crt files (e.g., level0.crt for the leaf, level1.crt for the intermediate) according to the extraction logic at lines 239-242【utils/checkcert.sh#L239‑L242】.
These collected certificates are concatenated into a single intermediatecerts.pem file within the temporary directory. This intermediate bundle represents every certificate the server provided aside from the leaf certificate itself, which is stored separately as HOSTCERT.
Verifying Against Trust Stores
The core validation logic resides in testssl.sh between lines 8008 and 8030【testssl.sh#L8008‑L8030】. The script iterates over five built-in CA bundles located in the etc/ directory—representing Mozilla, Microsoft, Apple, Java, and Linux trust stores—and executes OpenSSL verification for each.
The verification command follows this structure:
openssl verify -purpose sslserver \
-CAfile <(cat ${ADDTL_CA_FILES//,/ } "$bundle_fname") \
-untrusted $TEMPDIR/intermediatecerts.pem \
$HOSTCERT
If the server presents a complete chain, openssl verify returns exit code 0 and the store is marked as trusted. When validation fails, the script captures the error code through verify_retcode_helper and translates it into human-readable messages such as "chain incomplete" or "self-signed in chain"【testssl.sh#L8059‑L8085】.
Command-Line Options for Custom CA Trust Checking
testssl.sh provides flexible mechanisms to inject custom root certificates into the validation process, essential for testing internal applications with private PKI infrastructures.
Using the --add-ca Flag
To validate chains against a custom root CA, use the --add-ca option documented in the man page at lines 157-159【doc/testssl.1.md#L157‑L159】:
./testssl.sh --add-ca /path/to/corporate-root.pem internal.example.com:443
The specified PEM file is concatenated with each built-in trust store during verification, effectively extending the trust anchor without modifying system stores.
Environment Variable Configuration
For multiple custom CAs or repeated testing sessions, set the ADDTL_CA_FILES environment variable with comma-separated paths:
export ADDTL_CA_FILES="/opt/certs/root1.pem,/opt/certs/root2.pem"
./testssl.sh --add-ca "$ADDTL_CA_FILES" mail.internal:443
You can also override the default CA bundle location using CA_BUNDLES_PATH to point to alternative trust store directories【testssl.sh#L8002‑L8007】.
Understanding Certificate Chain Validation Output
The grading logic between lines 8059 and 8085 assigns severity ratings based on validation results【testssl.sh#L8059‑L8085】. A grade of B indicates chain construction problems (such as missing intermediates), while T flags other trust issues.
Typical output appears as:
[+] Trust via hostname + chain of trust against supplied certificates
OK: Mozilla Linux
NOT ok: Microsoft (chain incomplete)
When "OK" appears, the certificate chain successfully validates against that specific trust store. "NOT ok" entries include specific error codes that help diagnose whether the server failed to send intermediate certificates or if the root CA is absent from that particular store.
Summary
- testssl.sh automates certificate chain validation by extracting server certificates via
utils/checkcert.shand verifying them against five major trust stores inetc/*.pem. - The verification engine at
testssl.sh#L8008‑L8030usesopenssl verifywith the-untrustedflag to process intermediate certificates and checks against bundled Mozilla, Microsoft, Apple, Java, and Linux CA files. - Custom root CAs integrate seamlessly through the
--add-cacommand-line option orADDTL_CA_FILESenvironment variable, documented indoc/testssl.1.md. - Validation failures are graded (B for incomplete chains, T for trust issues) with specific error codes extracted via
verify_retcode_helperbetween lines 8059-8085. - For targeted testing, use
./testssl.sh -cto display only certificate chain and trust validation results.
Frequently Asked Questions
How do I test a server that uses an internal or self-signed CA?
Use the --add-ca flag to specify your private root certificate file. testssl.sh concatenates this file with each built-in trust store during verification, allowing you to validate chains that rely on corporate or self-signed roots without modifying system certificate stores【doc/testssl.1.md#L157‑L159】.
What does a grade "B" mean in certificate chain validation?
A B grade indicates a chain construction problem, most commonly an incomplete chain where the server fails to send necessary intermediate certificates. The script detects this via OpenSSL verify error codes processed in the grading logic at lines 8059-8085, distinguishing it from T grades that indicate broader trust issues【testssl.sh#L8059‑L8085】.
Can I limit output to only certificate chain validation results?
Yes. Run testssl.sh with the -c flag to restrict output specifically to certificate chain and trust-store validation. This mode suppresses other TLS/SSL tests and provides focused results showing which of the five built-in stores (Mozilla, Microsoft, Apple, Java, Linux) successfully validate your server's chain.
Where does testssl.sh store intermediate certificates during validation?
During execution, the script stores extracted intermediate certificates in $TEMPDIR/intermediatecerts.pem (where $TEMPDIR is a temporary directory created at runtime). The utils/checkcert.sh component creates this file by concatenating individual level*.crt files extracted from the server's chain【utils/checkcert.sh#L239‑L242】.
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 →