Join our Newsletter — 33% off our NHI Course
Home› Guides› OpenSSL for Security Teams: Inspect Certificates and Debug…
Guide Network Security

OpenSSL for Security Teams: Inspect Certificates and Debug TLS Failures Fast

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 8 November 2026 12 min read
On this page

Most TLS outages and "certificate not trusted" tickets are diagnosed slowly because teams guess instead of looking at what the server actually sends. The OpenSSL command line gives security and operations teams a direct view of the handshake, the certificate list, the chain a client would build and the exact verification error. This guide covers the commands that matter for defenders: s_client, x509, verify, req and pkcs12, how to read their output, how to map common client errors such as Java's SSLPeerUnverifiedException to a root cause, and how to keep OpenSSL itself patched. It is written for security engineers, SREs and PKI owners. For the protocol itself, read the How TLS Works Guide first.

This is an independent guide from NHI Mgmt Group, based on the OpenSSL project's public documentation as of November 2026. It is not sponsored or reviewed by the OpenSSL project. Product features change, so confirm settings against the OpenSSL project's current documentation.

Key takeaways

  • s_client shows what was sent, not what is trusted. -showcerts prints the certificates in the order the server sent them and the manual states plainly that this is not a verified chain.
  • Verification does not fail the connection by default. With -verify the handshake continues after errors so you can see every problem; add -verify_return_error when you want a test to fail hard.
  • Always send the right SNI and check the name. Use -servername and -verify_hostname, otherwise you can inspect the wrong virtual host and miss a hostname mismatch.
  • Most chain failures are one of four errors. Missing intermediate, untrusted root, expired certificate and hostname mismatch account for the bulk of tickets, and each has a distinct OpenSSL message.
  • Track the OpenSSL release line you run. OpenSSL 3.0 and 1.1.1 are out of public support; 3.5 is the current LTS with support to 8 April 2030, according to the project's release strategy page.

What the tool does

OpenSSL is an open source toolkit for TLS and general purpose cryptography, licensed under the Apache License 2.0. The openssl binary exposes subcommands that wrap the library. For defenders five of them do almost all of the work.

SubcommandWhat it doesOptions defenders use most
s_clientActs as a TLS client against any host and port, prints the handshake, certificates and session details-connect, -servername, -showcerts, -verify_return_error, -verify_hostname, -starttls, -status, -alpn, -brief
x509Parses and prints a certificate, checks expiry and names-noout, -text, -subject, -issuer, -dates, -enddate, -serial, -fingerprint, -ext, -ocsp_uri, -checkend, -checkhost, -checkip
verifyBuilds and validates a chain offline against a trust store-CAfile, -CApath, -untrusted, -purpose, -verify_hostname, -attime, -x509_strict, -crl_check
reqCreates and inspects certificate signing requests (CSRs)-new, -key, -subj, -addext, -text, -verify, -noout
pkcs12Builds and parses PFX/PKCS#12 bundles of key, certificate and chain-export, -in, -inkey, -certfile, -info, -nokeys, -legacy

File formats (PEM, DER, PFX, JKS) are covered in the Certificate and Key File Formats guide, so this page assumes you know which one you hold.

Defender use cases

1. See exactly what a server presents

The baseline command is openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts </dev/null. The manual describes the defaults that matter: if -servername is missing, SNI is populated from the -connect name when it looks like a DNS name (the default since OpenSSL 1.1.1), so a target given as an IP address does not get the hostname you meant. On shared load balancers or CDNs that means you may be looking at a default certificate, not the one real clients get. Redirecting standard input from /dev/null closes the session cleanly instead of waiting for input.

Read three parts of the output: the Certificate chain block (each entry shows s: subject and i: issuer, so you can see whether every issuer is followed by its own certificate), the Server certificate block and the final Verify return code line. A return code of 0 (ok) means the chain built to a trust anchor in the trust store OpenSSL used, which may not be the trust store your application uses.

2. Test non-HTTPS services

Mail, directory and database services often negotiate TLS after a plaintext greeting. -starttls supports the keywords smtp, pop3, imap, ftp, xmpp, xmpp-server, irc, postgres, mysql, lmtp, nntp, sieve and ldap. For example openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com. Implicit TLS ports (465, 993, 636) need no -starttls.

3. Check expiry before it becomes an outage

openssl x509 -in cert.pem -noout -enddate prints notAfter. For scripts, -checkend 2592000 exits non-zero if the certificate expires within 30 days (the argument is in seconds), which makes it a simple monitoring probe when piped from s_client. With shorter certificate lifetimes coming, read the Certificate Expiry Outages and 47-Day TLS Certificates Guide.

4. Validate a chain offline

openssl verify -CAfile root.pem -untrusted intermediates.pem -verify_hostname app.example.com leaf.pem reproduces what a client does without touching the network. -attime checks validity at a chosen time (useful to prove a certificate will fail after a migration date), and -purpose sslserver catches certificates issued with the wrong extended key usage.

5. Inspect and repair PKCS#12 bundles

openssl pkcs12 -in bundle.pfx -info -nokeys lists the certificates without exporting the key. OpenSSL 3.x creates PKCS#12 files with AES-256-CBC and PBKDF2 by default; the -legacy option loads the legacy provider and uses RC2 or 3DES for certificates and 3DES for keys. Older Java and Windows importers sometimes reject the modern format, so -legacy is a compatibility switch to use deliberately, never a default.

6. Confirm CSR content before submission

openssl req -in request.csr -noout -text -verify checks the CSR signature and shows the subject and requested extensions. Confirm the subjectAltName list, because modern clients match names against SAN entries, not the subject common name.

Diagnosing chain and hostname validation errors

Application errors are usually a wrapper around one of a handful of X.509 verification results. The OpenSSL error strings below come from the library's documentation of X509_STORE_CTX_get_error.

OpenSSL messageUsual root causeHow to confirmFix
unable to get local issuer certificateServer does not send its intermediate, or the client trust store lacks the roots_client -showcerts: last i: issuer has no matching certificateConfigure the full chain file on the server; update the client trust store if the root is missing
unable to verify the first certificateOnly the leaf is sent and its issuer cannot be foundChain block shows a single entryServe leaf plus intermediates (not the root)
self-signed certificate / self-signed certificate in certificate chainPrivate CA or interception proxy root not trusted by this clientIssuer equals subject at depth 0, or a private root appears in the sent listDistribute the private root to the right trust store; see the Certificate trust stores and root CA management guide
certificate has expired / certificate is not yet validExpired leaf or intermediate, or wrong system clockx509 -noout -dates on each certificate; check NTP on the clientRenew and redeploy; fix time sync
hostname mismatchName not in SAN, wrong SNI, or default certificate serveds_client -servername host -verify_hostname host; x509 -noout -ext subjectAltNameReissue with correct SANs or fix the virtual host and SNI routing
unsuitable certificate purposeEKU lacks serverAuth (or clientAuth for mTLS)x509 -noout -ext extendedKeyUsageReissue from the correct template

Java's SSLPeerUnverifiedException: the Java SE documentation describes it as indicating that the peer's identity has not been verified, thrown when the peer could not identify itself, for example no certificate, a cipher suite without authentication, or no peer authentication during the handshake. In practice it often surfaces after an earlier trust failure, or when code asks for peer certificates on a session that did not authenticate. Reproduce the connection with s_client using the same hostname, then compare the chain with the Java trust store (keytool -list -cacerts), because Java does not use the operating system store by default.

Mutual TLS: when the server requests a client certificate, s_client prints Acceptable client certificate CA names. Supply -cert and -key to test. Client certificates are workload identities and should be inventoried like any other credential; see the mTLS Guide.

Deployment and safe use

  1. Know which OpenSSL you are running. openssl version -a shows the version, build date and OPENSSLDIR (where the default trust store and configuration live). Operating systems, language runtimes and containers often bundle different copies.
  2. Use a controlled trust store for tests. Pass -CAfile or -verifyCAfile explicitly so results match the client you are debugging rather than the host's default store.
  3. Never "fix" errors by disabling verification. The manual notes that plain -verify never fails the connection; scripts and health checks should use -verify_return_error so they fail when validation fails.
  4. Protect private keys. Keep keys out of shell history and ticket attachments, prefer -nokeys when only certificates are needed, set file permissions to the owning service account, and use pass phrase options such as -passin file: or env: rather than typing secrets on the command line, where they appear in process listings.
  5. Treat pasted output as sensitive. Certificates are public, but s_client output can include session tickets and internal hostnames; redact before sharing externally.
  6. Stay on a supported release line. The OpenSSL release strategy states that feature releases ship every April and October, an LTS is designated every two years from 3.5 with at least five years of support, and non-LTS releases after 3.5 are supported for 13 months. As checked on 8 November 2026, 3.5 (LTS) is supported to 8 April 2030, 4.0 to 14 May 2027 and 4.1 to 23 November 2027, while 3.0 and 1.1.1 receive only paid extended support.

Detection and hardening value

OpenSSL is also a dependency you must patch. Its vulnerability page rates issues Low, Moderate or High. Apply OpenSSL security updates promptly from the OpenSSL vulnerabilities page, and check fixed versions per release line rather than assuming one upgrade covers every branch. Recent releases also change defaults that affect testing: OpenSSL 3.5.0 made hybrid post-quantum groups preferred with default key shares X25519MLKEM768 and X25519, and 4.0.0 added authority key identifier checks under -x509_strict. See the Hybrid Post-Quantum TLS Key Exchange Guide.

MeasureWhat to watchTarget
Certificates expiring within 30 daysx509 -checkend probe per endpointZero unplanned, every one ticketed
Endpoints serving an incomplete chains_client -verify_return_error with a minimal trust storeZero
Hostname mismatches on public names-verify_hostname sweep from the asset inventoryZero
Hosts on unsupported OpenSSL linesSBOM or package inventory for 1.1.1 and 3.0Falling each quarter, with exceptions documented
Time to patch High OpenSSL advisoriesAdvisory date to fleet coverageWithin your critical patch SLA

Framework mapping

FrameworkReferenceHow OpenSSL work supports it
NIST SP 800-53 Rev. 5SC-8 Transmission Confidentiality and Integrity; SC-17 Public Key Infrastructure Certificates; SC-23 Session AuthenticityEvidence that TLS is configured and certificates validate
NIST SP 800-53 Rev. 5SC-12 Cryptographic Key Establishment and Management; SI-2 Flaw RemediationKey handling for PKCS#12 and CSRs; patching OpenSSL itself
NIST CSF 2.0PR.DS-02 (data in transit protected); ID.AM-02 (software inventories)Endpoint checks; tracking OpenSSL versions
MITRE ATT&CKT1557 Adversary-in-the-Middle; T1588.004 Digital CertificatesStrict validation is what defeats interception with untrusted or attacker-obtained certificates

Alternatives

ToolChoose it whenTrade-off
OpenSSL CLIYou need the raw handshake, a specific error or offline chain checksOutput is verbose and options vary between versions
testssl.sh (GPLv2)You want a full protocol, cipher and known-flaw review of one service, including STARTTLS, with JSON or CSV outputSlower; tests many handshakes against the target, so agree scope first
SSLyze (Python library and CLI)You want scans in CI/CD against Mozilla's recommended configurations or at scalePython dependency; less useful for a single odd error
keytool (Java), certutil (Windows)The problem is inside a Java keystore or the Windows certificate storePlatform specific; do not show the network view

Small teams: a cron job running s_client and x509 -checkend against a list of hostnames covers expiry and chain monitoring. Large estates: feed the same checks from the asset inventory and certificate lifecycle tooling, and keep OpenSSL for root cause analysis. See the Machine Identity, PKI and Certificate Lifecycle Guide.

Common failure patterns

  • Testing without SNI: connecting by IP or without -servername returns a default certificate and a false all-clear.
  • Reading -showcerts as proof of trust: the sent list can be complete, out of order or contain an unneeded root; only the verify result tells you whether a client will trust it.
  • Different trust stores: OpenSSL on the admin laptop trusts a root that the Java runtime, container image or appliance does not, so the test passes and production fails.
  • Turning verification off to make it work: code that sets "trust all" or skips hostname checks to clear an exception removes the protection against interception entirely.
  • Forgotten bundled OpenSSL: the OS package is patched while an application ships its own older library, so vulnerability scans of the OS miss it.

Practitioner checklist

  • Run openssl version -a on every build image and record the release line.
  • Always pass -servername and -verify_hostname when testing a named service.
  • Use -verify_return_error in every script or health check.
  • Test with the same trust store as the failing client (-CAfile, Java cacerts, OS store).
  • Serve leaf plus intermediates on every TLS endpoint and verify with a minimal trust store.
  • Probe expiry with x509 -checkend at 30 days and alert on failures.
  • Keep private keys out of shell history, tickets and chat; use -nokeys where possible.
  • Plan migration off OpenSSL 1.1.1 and 3.0 to a supported line such as 3.5 LTS.
  • Subscribe to OpenSSL security advisories and map them to SBOM entries.

Standards and references

Related NHI Mgmt Group resources: How TLS Works Guide · Certificate and Key File Formats · mTLS Guide · Certificate Revocation Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 8 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org