OpenSSL for Certificate Investigations: A Practical Guide


Hi all – so in this article, we’re going to go deep into using openssl to investigate certificates. I’m participating in a CTF and decided to delve deep into it, answer the CTF questions, and write about it.

There are many reasons why we would investigate a certificate chain, but let’s start with an error. A certificate error can look deceptively simple. The browser says the connection is not private, an application reports that it cannot establish trust, or a service suddenly stops talking to another service. Somewhere in the middle is a certificate, and it is up to you to figure out what is actually wrong.

Is the certificate expired? Was it issued for a different hostname? Is the server missing an intermediate certificate? Is the client using a different trust store? Or is the connection reaching a completely different server than the one you expected?

OpenSSL gives you a way to investigate those questions from the command line. In this guide, we will walk through the commands, what their output means, and how to use the results to follow the evidence.

Before We Start

OpenSSL is a toolkit for working with cryptography, certificates, and TLS connections. We are focusing on certificate investigations, including web services, APIs, mail servers, certificate files, and mutual TLS.

Check the version you are using:

openssl version -a

The examples use OpenSSL 3.x and a Bash-style shell, such as those found on Linux, macOS, or Windows Subsystem for Linux. Options and output can vary by version, and the openssl command on some systems may be LibreSSL rather than OpenSSL. Use openssl <command> -help to check what your installation supports.

Replace example hostnames, IP addresses, paths, and filenames with the ones relevant to your investigation. Connect only to systems you are authorized to test. When handling an incident, preserve the original evidence and record where and when you collected it.

First, Understand What You Are Looking At

A certificate binds a public key to a set of identities and other information. An X.509 certificate may include a subject, issuer, validity dates, public key, and extensions that describe how it can be used.

For a typical TLS connection, the certificate chain looks like this:

  1. Leaf certificate: The certificate presented for the service.
  2. Intermediate certificate: A certificate authority, or CA, certificate that issued the leaf certificate. There may be more than one intermediate.
  3. Root certificate: A trust anchor the client has been configured to trust.

The server normally presents the leaf and any needed intermediates. The client normally already has the root in its trust store. A chain can look plausible on screen and still fail validation, so keep inspection and verification separate as you investigate.

Read a Certificate File

If you already have a PEM-encoded certificate, start with:

openssl x509 -in certificate.pem -noout -text

-text displays the certificate in a human-readable format, while -noout suppresses the encoded certificate. There is a lot in the output, but these are good places to focus:

FieldWhat it can tell you
SubjectThe identity information included in the certificate.
IssuerThe name of the CA that claims to have issued it. The name alone does not establish trust.
ValidityThe Not Before and Not After dates.
Subject Alternative Name (SAN)The DNS names, IP addresses, or other identities included in the certificate.
Public KeyThe subject’s public-key algorithm and key size or curve.
Signature AlgorithmThe algorithm used by the issuer to sign the certificate; this is distinct from the subject’s public-key algorithm.
Basic ConstraintsWhether the certificate is marked as a CA certificate.
Key Usage / Extended Key UsageThe purposes for which the key or certificate can be used, when those extensions are present.
Authority Information Access / CRL Distribution PointsLocations that may help identify the issuer or revocation information.

When comparing a leaf with its issuer, the leaf’s Authority Key Identifier and the issuer’s Subject Key Identifier can also help you identify a likely relationship. Matching names or identifiers are clues; signature and chain verification are what test that relationship.

Pull Out Just the Details You Need

To see the subject, issuer, serial number, and validity dates without the full output:

openssl x509 -in certificate.pem -noout \
-subject -issuer -serial -dates

The serial number is useful when working with a CA, checking revocation information, or correlating records. Identify it together with the issuer: serial numbers are assigned by an issuing CA and should not be treated as globally unique on their own.

Check the Names on the Certificate

If a certificate works for one hostname but not another, start with the SAN extension:

openssl x509 -in certificate.pem -noout -ext subjectAltName

You might see something like this:

X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com, DNS:api.example.com

These are the names included in the certificate. A request for portal.example.com would not match the names shown above.

You can ask OpenSSL to check a particular hostname:

openssl x509 -in certificate.pem -noout \
-checkhost api.example.com

For an IP address:

openssl x509 -in certificate.pem -noout \
-checkip 192.0.2.10

An IP address needs a matching IP-address SAN; a DNS name that happens to resolve to that address is a different identity. A wildcard such as *.example.com generally covers a single subdomain level, such as api.example.com, but not example.com or api.dev.example.com.

What this check does not do: -checkhost or -checkip checks the identity against the certificate. It does not establish that the chain is trusted, the certificate is currently valid, or it has not been revoked. Hostname matching can also differ between OpenSSL versions and clients; modern browser certificates should include the names in SAN rather than relying on the older Common Name field.

Check Expiration and Validity

To view both ends of the validity period:

openssl x509 -in certificate.pem -noout -dates

The output might look like:

notBefore=Nov 1 00:00:00 2026 GMT
notAfter=Jan 30 23:59:59 2027 GMT

The certificate is outside its validity period if the evaluation time is before notBefore or after notAfter. Check the client’s system clock too: a clock that is wrong can make a valid certificate appear expired or not yet valid. An intermediate certificate can also expire even when the leaf certificate has time remaining.

To check whether the certificate will expire within the next 30 days:

openssl x509 -in certificate.pem -noout -checkend 2592000

The number is in seconds: 30 × 24 × 60 × 60. OpenSSL returns a nonzero status if the certificate has expired or will expire within that window. This is an expiration check, not a complete validation, and it does not check the notBefore date.

Identify a Certificate by Its Fingerprint

A fingerprint is a digest of the complete certificate. It is useful when you need to compare what two systems received or confirm whether a certificate changed after a deployment.

openssl x509 -in certificate.pem -noout -fingerprint -sha256

For example, if two servers are supposed to present the same certificate but the SHA-256 fingerprints differ, they are presenting different certificate objects. That can be expected during a staged rollout or load-balanced deployment, or it can reveal an inconsistency worth investigating.

A certificate fingerprint is not the same as a public-key fingerprint. A renewed certificate will usually have a different certificate fingerprint even when the same key is reused. A matching fingerprint also does not, by itself, prove the certificate is trustworthy.

Inspect the Certificate a Server Actually Presents

The certificate in a configuration file is not necessarily the one a client sees. A load balancer, reverse proxy, CDN, TLS-inspection device, or older backend may present a different certificate.

Use s_client to connect to a service:

openssl s_client -connect api.example.com:443 \
-servername api.example.com </dev/null

-connect specifies where to connect. -servername supplies the Server Name Indication (SNI), which tells the server which hostname the client wants. This matters when multiple services share an IP address.

The output includes the certificate, connection details, and verification messages. Read the messages carefully: s_client is a diagnostic tool and can continue after certificate-verification errors unless you tell it to stop. A completed connection alone does not mean the certificate was trusted.

The </dev/null part closes standard input for a noninteractive check. In some situations, especially with TLS 1.3, it can close the connection too early. If the output appears incomplete, run the command interactively without it, or consult the OpenSSL guidance for noninteractive use.

Compare Individual Backends

If a service has multiple addresses, connect to a specific IP while keeping the expected hostname in SNI:

openssl s_client -connect 192.0.2.10:443 \
-servername api.example.com </dev/null

Repeat for other authorized addresses and compare the leaf certificates and fingerprints. This is helpful when an old certificate is still installed on one node or traffic takes different paths through a load-balanced environment.

SNI requests a certificate for a hostname; it does not independently verify that hostname. For that, use -verify_hostname in the verification example below.

See the Certificates Sent by the Server

To display all certificates the server sends:

openssl s_client -connect api.example.com:443 \
-servername api.example.com -showcerts </dev/null

The list is what the server sent, in the order it sent it. It is not necessarily the verified chain OpenSSL ultimately builds. The first certificate is normally the leaf; intermediates follow when the server provides them. The root usually is not sent, and its absence alone is not a problem.

To save the output for closer inspection:

openssl s_client -connect api.example.com:443 \
-servername api.example.com -showcerts </dev/null > session.txt

Verification diagnostics may appear separately on standard error, so keep them with your investigation notes. In an empty working directory, split the PEM certificates into individual files:

awk '/-----BEGIN CERTIFICATE-----/ {n++; file=sprintf("cert-%02d.pem", n)}
/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/ {print > file}' \
session.txt

This creates files such as cert-01.pem and cert-02.pem. Inspect each one to establish its role:

openssl x509 -in cert-01.pem -noout -subject -issuer -dates
openssl x509 -in cert-02.pem -noout -subject -issuer -dates

If the server only sends one certificate, there will be no cert-02.pem. Use a fresh directory or move previous results first; the extraction command uses the same output names each time.

Verify a Live Server’s Chain and Hostname

For a live connection, explicitly request hostname verification and stop on verification errors:

openssl s_client -connect api.example.com:443 \
-servername api.example.com \
-verify_hostname api.example.com \
-verify_return_error </dev/null

The options answer different questions:

  • -servername requests the certificate associated with the hostname through SNI.
  • -verify_hostname checks that the certificate matches the expected hostname.
  • -verify_return_error makes verification errors fail the connection instead of allowing the diagnostic client to continue.

If you connect by IP and intend to verify the IP identity itself, use -verify_ip with that IP instead. If you connect to an IP to reach a particular backend but the intended identity is a DNS name, keep using the DNS name with -servername and -verify_hostname.

The result depends on the trust certificates and verification settings available to that OpenSSL installation. Your browser, operating system, container, Java application, or appliance may use a different trust store and reach a different result. Successful chain and hostname verification also does not automatically mean revocation was checked.

For an internal CA, you can supply an appropriate trusted CA file:

openssl s_client -connect api.example.com:443 \
-servername api.example.com \
-verify_hostname api.example.com \
-verify_return_error -CAfile trusted-roots.pem </dev/null

Obtain trust anchors through an authenticated, approved source. Do not trust a certificate simply because the server sent it or because adding it makes the error disappear.

Investigate the Root Certificate

When a certificate chain fails, it is tempting to focus on the certificate presented by the server. But the root of the chain deserves attention too: Which root did the client use? Is it the one you expected? Does the affected application trust it?

Remember that the server usually sends the leaf certificate and any intermediates, but not the root. That means s_client -showcerts can tell you what the server sent without necessarily revealing the root the client used.

Trace the Chain Directly from the Website

You do not need a copy of the root certificate, or access to the certificate authority’s website, to start an investigation. If you can reach the website itself, connect to its hostname and inspect the certificates presented during the TLS handshake.

For example, run this command in PowerShell, replacing www.example.com with the hostname you want to investigate:

openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts

Use the hostname only, without https:// or a page path. The -connect option identifies the destination and HTTPS port, -servername supplies the hostname using SNI, and -showcerts displays the certificates sent by the server. Once the output appears, type uppercase Q and press Enter, or use Ctrl+C, to close the connection.

What should you look for? OpenSSL may display verification lines resembling these:

depth=2 CN = Example Root CA
verify return:1
depth=1 CN = Example Intermediate CA
verify return:1
depth=0 CN = www.example.com
verify return:1

In this example, depth=0 is the website’s certificate, depth=1 is an intermediate, and depth=2 is the root OpenSSL used when building the chain. The number of levels can vary, and a configured trust anchor can sometimes be an intermediate.

The highest depth is useful only in context. Check whether verification completed successfully and review any errors. If chain building fails, the diagnostic lines may show only part of the path. The server-provided certificate list is not itself a verified chain, and the root usually comes from the client’s trust store rather than the server.

Also, s_client can continue after verification errors for diagnostic purposes. To check the expected hostname and stop on a verification error, run:

openssl s_client -connect www.example.com:443 -servername www.example.com -showcerts -verify_hostname www.example.com -verify_return_error

If the check succeeds, look for Verify return code: 0 (ok). This result applies to the trust settings available to that OpenSSL installation; it does not necessarily match another application’s trust store or mean revocation was checked.

Want a shorter view of the website certificate? The following PowerShell command displays the leaf certificate’s subject, issuer, validity dates, and SHA-256 fingerprint:

"Q" | openssl s_client -connect www.example.com:443 -servername www.example.com 2>$null | openssl x509 -noout -subject -issuer -dates -fingerprint -sha256

The issuer displayed here is the issuer of the leaf certificate, which is often an intermediate CA, not necessarily the root. The command also suppresses connection diagnostics to keep the output short, so use the earlier commands if you need to investigate errors.

Keep the connection path in mind. Antivirus products and corporate security tools can perform TLS inspection and present a certificate issued by an inspection CA. If the issuer is unexpected, determine whether TLS inspection is part of the path before concluding that the website itself uses that CA. If a security tool blocks the connection entirely, OpenSSL may be unable to retrieve a certificate from that device, like it did to me.

If you test a different hostname (e.g., www.example.com instead of example.com) the result applies to the hostname and network path you tested. The two hosts can present different certificates.

Identify the Chain Using Saved Certificate Files

Start with the certificates you saved from the server earlier. This example assumes cert-01.pem is the leaf and cert-02.pem is its intermediate:

openssl verify -show_chain -purpose sslserver \
-verify_hostname api.example.com \
-untrusted cert-02.pem cert-01.pem

OpenSSL uses the trust locations available to that installation and, if verification succeeds, displays the chain it built. Illustrative output might look like this:

cert-01.pem: OK
Chain:
depth=0: CN = api.example.com (untrusted)
depth=1: CN = Example Issuing CA (untrusted)
depth=2: CN = Example Root CA

Here, the last certificate is the trust anchor OpenSSL used for this check. As before, “untrusted” identifies certificates supplied for chain building rather than trust anchors; it does not mean the leaf or intermediate was found to be malicious.

If there are multiple intermediates, combine the needed PEM certificates into one file and pass that file to -untrusted. If the root directly issued the leaf and there is no intermediate, omit -untrusted. If verification fails, -show_chain may not display a completed chain; investigate the error before drawing a conclusion.

Important: This shows the path built by this OpenSSL installation, with its trust settings. It does not prove another application built the same path. To identify the chain the affected client actually used, review its certificate viewer, connection logs, or TLS diagnostics, then compare the result with your OpenSSL test.

Find the Root in the Relevant Trust Store

Once you have a candidate root name, look for the corresponding certificate in the affected client’s trust store. Depending on the application, that might be an operating-system store, an application-specific bundle, a Java truststore, or a container’s certificate store.

Do not assume that two certificates with the same subject name are identical. Compare the certificate details and SHA-256 fingerprints, particularly when dealing with renewed or cross-signed CA certificates.

If you have a copy of the client’s trusted certificates as a PEM bundle, you can repeat the chain-building test using only the trust anchors in that bundle:

openssl verify -trusted client-roots.pem \
-untrusted cert-02.pem \
-purpose sslserver -verify_hostname api.example.com \
-show_chain cert-01.pem

Replace client-roots.pem with the relevant bundle and adjust the intermediate file as needed. This tests OpenSSL with the supplied trust anchors; it does not necessarily reproduce every policy, revocation setting, or chain-building choice made by the application.

On some Debian- or Ubuntu-based systems, a system CA bundle is available at /etc/ssl/certs/ca-certificates.crt. The location can differ by distribution, and an application or container may use a different bundle altogether.

Find a Candidate in a PEM Bundle

If your trust store is a concatenated bundle of ordinary PEM certificates, you can split a copy into individual certificates for inspection. Run this in an empty working directory:

mkdir root-candidates
awk '/-----BEGIN CERTIFICATE-----/ {
n++; file=sprintf("root-candidates/root-%04d.pem", n)
}
file {print > file}
/-----END CERTIFICATE-----/ {close(file); file=""}' \
client-roots.pem

Then display each certificate’s subject, issuer, and SHA-256 fingerprint:

for cert in root-candidates/*.pem; do
printf '\n%s\n' "$cert"
openssl x509 -in "$cert" -noout -subject -issuer -fingerprint -sha256
done

Match candidate subjects with the anchor shown by -show_chain, then examine the candidates more closely. The displayed subject name alone is not enough to distinguish certificates with the same name. This split command is for ordinary BEGIN CERTIFICATE blocks; other store formats and OpenSSL trusted-certificate blocks require different handling. Keep the original bundle and its trust settings intact.

Find and Export a Root on Windows

If the affected application uses Windows certificate stores, PowerShell can help you find a candidate. Replace Example Root CA with part of the name you are investigating:

Get-ChildItem -Path Cert:\LocalMachine\Root, Cert:\CurrentUser\Root |
Where-Object { $_.Subject -like '*Example Root CA*' } |
Select-Object Subject, Issuer, NotAfter, Thumbprint, PSParentPath

The Windows certificate provider’s Thumbprint property is SHA-1. Use it to select the certificate in the store, but do not compare it directly with an OpenSSL SHA-256 fingerprint.

After identifying the candidate, replace THUMBPRINT with its actual Windows thumbprint and export the public certificate:

$root = Get-Item 'Cert:\LocalMachine\Root\THUMBPRINT'
Export-Certificate -Cert $root -FilePath .\root.cer -Type CERT

Change LocalMachine to CurrentUser if that is where you found the certificate. This exports a DER-encoded public certificate, not its private key. Convert it to PEM so you can use the following OpenSSL examples:

openssl x509 -inform DER -in root.cer -out root.pem

Finding a certificate in a Windows store is useful evidence, but confirm that the affected application uses that store and account. A browser, Java application, container, or other client may use different trust settings.

Inspect the Root’s Details

With the candidate saved as root.pem, display its full contents:

openssl x509 -in root.pem -noout -text

For a focused view:

openssl x509 -in root.pem -noout \
-subject -issuer -serial -dates -fingerprint -sha256

And to inspect common CA extensions:

openssl x509 -in root.pem -noout \
-ext basicConstraints,keyUsage,subjectKeyIdentifier

Pay attention to:

  • Subject and issuer: A self-signed root commonly has the same subject and issuer, but matching names alone do not prove its signature is valid or that the certificate is trusted. A cross-signed CA certificate can have a different issuer.
  • Validity dates: Check notBefore and notAfter. OpenSSL checks the trust anchor’s validity period during ordinary chain verification; other clients can apply their own policies.
  • Basic Constraints: A CA certificate commonly includes CA:TRUE.
  • Key Usage: If this extension is present for a CA issuing certificates, it must permit certificate signing, shown as Certificate Sign or keyCertSign.
  • Public key and signature algorithm: Review them against the policies and capabilities relevant to the environment.
  • SHA-256 fingerprint: Compare it with the expected fingerprint obtained through an independent, authenticated source.

Not every certificate includes every extension, and a matching name or fingerprint alone does not tell you whether a particular application trusts the certificate for the intended use.

Check a Self-Signed Root’s Signature

For a candidate expected to be a self-signed root, you can ask OpenSSL to check its self-signature:

openssl verify -trusted root.pem -check_ss_sig root.pem

If OpenSSL reports root.pem: OK, the certificate passed the checks for this test, including the requested self-signature check for an apparently self-signed anchor. You explicitly supplied root.pem as trusted for the test, so the result does not prove your operating system, browser, or application trusts it. It also does not establish that you obtained the certificate from the right source.

The -check_ss_sig option applies to a self-signed chain terminator; it does not verify a cross-signed certificate’s signature as a self-signature. For a cross-signed path, investigate the issuer and validate the complete chain against the intended trust anchor.

Why Two Clients Can Use Different Roots

A CA can have multiple certificates associated with the same identity or key, and an intermediate may have more than one available path to a trusted anchor. Different trust stores, available intermediates, cached certificates, or client policies can lead clients to build different chains.

If one client succeeds and another fails, collect the chain and trust-store details from both. Compare the certificates by fingerprint and issuer, not just their display names. This can reveal that one client lacks the required root, is building to an expired or unexpected path, or is using a different set of trust settings.

Build and Verify a Chain from Files

Sometimes you have the leaf and intermediate certificates separately and want to see whether they build to a specific root.

Assume you have:

  • leaf.pem: the service certificate.
  • intermediate.pem: the relevant intermediate certificate, or a PEM file containing the needed intermediates.
  • root.pem: the root you intend to trust, obtained independently.

Run:

openssl verify -trusted root.pem -untrusted intermediate.pem \
-purpose sslserver -verify_hostname api.example.com \
-show_chain leaf.pem

Here, -trusted supplies the trust anchor for this check, and -untrusted supplies certificates OpenSSL may use to build the chain without treating them as trust anchors. In the output, “untrusted” describes where those certificates came from; it does not mean OpenSSL found them malicious.

-purpose sslserver checks for a TLS server use, and -verify_hostname checks the expected name. If validation succeeds, OpenSSL reports leaf.pem: OK and shows the chain it built. Revocation is a separate check, covered below.

What If You Are Investigating a Past Incident?

OpenSSL can evaluate the chain at a specified Unix timestamp:

openssl verify -trusted root.pem -untrusted intermediate.pem \
-purpose sslserver -verify_hostname api.example.com \
-attime 1794000000 leaf.pem

Replace the timestamp with the time relevant to your investigation. This changes the time used for certificate validation; it does not recreate a historical trust store, server configuration, or revocation status. You need those historical records separately if they matter to the conclusion.

Investigate Services That Use STARTTLS

Not every service starts the connection with TLS immediately. Some begin with a plaintext protocol exchange and then upgrade to TLS using STARTTLS.

For an SMTP submission server on port 587:

openssl s_client -connect mail.example.com:587 \
-servername mail.example.com -starttls smtp \
-verify_hostname mail.example.com -verify_return_error </dev/null

For IMAP using STARTTLS:

openssl s_client -connect mail.example.com:143 \
-servername mail.example.com -starttls imap \
-verify_hostname mail.example.com -verify_return_error </dev/null

Support for other protocols varies by OpenSSL version; check openssl s_client -help. Use the appropriate service port and protocol. An implicit TLS port, such as IMAPS on 993, normally begins TLS immediately and does not use the STARTTLS exchange.

Test TLS Versions and Mutual TLS

If a connection fails before you can inspect a certificate, the issue may involve protocol negotiation. These commands try specific TLS versions:

openssl s_client -connect api.example.com:443 \
-servername api.example.com -tls1_2 -brief </dev/null
openssl s_client -connect api.example.com:443 \
-servername api.example.com -tls1_3 -brief </dev/null

These are diagnostic tests, not a full assessment of every protocol or cipher the server supports. A failed connection can have multiple causes, including local client policy or network restrictions. Add hostname and trust verification when that is part of what you are testing.

For a service that requests a client certificate, provide the client certificate and its matching private key:

openssl s_client -connect api.example.com:443 \
-servername api.example.com \
-verify_hostname api.example.com -verify_return_error \
-cert client-cert.pem -key client-key.pem </dev/null

Keep the private key protected and use only credentials you are authorized to use. Supplying a client certificate does not prove the server requested or accepted it, and a successful TLS handshake does not prove the application authorized the requested operation. Some setups also require the client to provide an intermediate chain; check your OpenSSL version’s -cert_chain option.

Investigate Revocation

An unexpired certificate is not necessarily still valid for use. A CA may revoke a certificate before its expiration date, for example after a key compromise. Two mechanisms you may encounter are OCSP and certificate revocation lists.

Check for an OCSP Staple

Some servers send a signed OCSP response during the TLS handshake. Request it with:

openssl s_client -connect api.example.com:443 \
-servername api.example.com -status </dev/null

Look for an OCSP response and, if present, the certificate status and response timestamps. A response status of successful means the responder processed the request; it is not by itself the certificate’s good status.

-status requests and displays a staple. Its presence alone is not proof that the response is valid, fresh, or applies to the certificate you are investigating. If no staple is returned, that alone does not mean the certificate is revoked.

Query an OCSP Responder Directly

First, check whether the certificate lists an OCSP responder:

openssl x509 -in leaf.pem -noout -ocsp_uri

If it does, and you have the correct issuing intermediate and a trusted root, an example query is:

openssl ocsp -issuer intermediate.pem -cert leaf.pem \
-url http://ocsp.example.com \
-CAfile root.pem -verify_other intermediate.pem -resp_text

Replace the URL with the actual responder URL, and keep -issuer before -cert. Review response verification, the status for the certificate, and the relevant timestamps. A good status means the responder reports that certificate as not revoked under its response; it is not proof that the site is legitimate or the private key is secure.

OCSP availability varies: some certificates do not contain a responder URL, and not every CA or client uses OCSP in the same way. A query also contacts the responder and can disclose the certificate being checked. Follow your organization’s network and investigation practices before making the request.

Inspect and Apply a Certificate Revocation List

To see any CRL distribution points in the certificate:

openssl x509 -in leaf.pem -noout -ext crlDistributionPoints

If you have obtained the correct issuer’s CRL in PEM format, inspect it:

openssl crl -in issuer.crl.pem -noout -text

Check the issuer, update times, and any listed serial numbers. If the CRL is DER encoded, convert it first:

openssl crl -inform DER -in issuer.crl -out issuer.crl.pem

To validate a leaf using the CRL alongside its chain:

openssl verify -trusted root.pem -untrusted intermediate.pem \
-CRLfile issuer.crl.pem -crl_check \
-purpose sslserver -verify_hostname api.example.com leaf.pem

This checks the leaf against an applicable CRL as part of verification. -crl_check_all checks the chain and requires the applicable CRLs for the certificates being checked. A missing, expired, or unsuitable CRL can make the check fail; that is not the same conclusion as “the certificate is revoked.” Treat distribution-point URLs from an untrusted certificate as leads, and retrieve material in accordance with your network and investigation practices.

Inspect Certificate Transparency Information

Certificate Transparency (CT) provides public logs that help make the issuance of many publicly trusted TLS certificates visible. A certificate or TLS connection may include signed certificate timestamps, or SCTs, associated with those logs.

To request and display SCT information during a connection, where supported:

openssl s_client -connect api.example.com:443 \
-servername api.example.com -ct </dev/null

You may also see embedded SCT information in the output of openssl x509 -text. SCTs are useful evidence to investigate, but viewing them is not the same as searching CT logs for all certificates associated with a domain. Use a CT log search service for that separate step, and do not treat a logged certificate as proof of malicious activity by itself.

Check Whether a Certificate and Private Key Match

If you administer the system and have authorized access to the private key, compare a SHA-256 digest of each public key. This works with common key types, including RSA and EC:

openssl x509 -in certificate.pem -pubkey -noout | \
openssl pkey -pubin -outform DER | openssl dgst -sha256
openssl pkey -in private-key.pem -pubout -outform DER | \
openssl dgst -sha256

The digests should match if the certificate contains the public key corresponding to that private key. A mismatch can explain why a service refuses to load the pair. OpenSSL may prompt for the key’s passphrase; avoid placing passphrases in shell history, scripts, or tickets.

Perform this comparison in a trusted environment. Do not upload a private key to a website or paste it into a support ticket. The commands output a digest of the public key, not the private-key contents.

Inspect a Certificate Signing Request

A certificate signing request, or CSR, can help you investigate what was requested before the CA issued a certificate:

openssl req -in request.csr -noout -text -verify

Compare the requested subject, public key, and any requested extensions with the issued certificate. The CSR’s signature demonstrates possession of the corresponding private key when it was signed; it does not establish that the requested identity was authorized or that the issued certificate is trusted. The CA may issue a certificate with different values or extensions.

Work with Common Certificate Formats

Filename extensions are not a reliable way to identify the contents. A .crt file, for example, may contain PEM or DER data.

PEM and DER

PEM is text encoded and often begins with -----BEGIN CERTIFICATE-----. DER is binary. Convert DER to PEM:

openssl x509 -inform DER -in certificate.der -out certificate.pem

Convert PEM to DER:

openssl x509 -in certificate.pem -outform DER -out certificate.der

PKCS#7 / P7B

A PKCS#7 file can hold certificates, often a chain. For a PEM-encoded P7B:

openssl pkcs7 -in bundle.p7b -print_certs -out certificates.pem

For a DER-encoded file, add -inform DER. Inspect the resulting certificates individually and verify the chain; a bundle is not automatically trusted.

PKCS#12 / PFX

A PKCS#12 file can contain a certificate, private key, and CA certificates. To inspect its structure without outputting the key:

openssl pkcs12 -in bundle.p12 -info -noout

To extract the end-entity certificate without extracting private keys:

openssl pkcs12 -in bundle.p12 -clcerts -nokeys -out client-cert.pem

To extract CA certificates without private keys:

openssl pkcs12 -in bundle.p12 -cacerts -nokeys -out ca-certs.pem

OpenSSL will usually prompt for the bundle password. Older bundles may require the version-specific -legacy option; use it only when needed to read the file. Treat the original PFX or P12 as sensitive because it may contain a private key.

Common Errors and Where to Look

Error or observationWhat to investigate
certificate has expiredCheck the validity dates of the leaf and each intermediate, along with the client’s clock.
certificate is not yet validCheck notBefore and the client’s date and time.
hostname mismatchCheck the requested hostname, SAN entries, SNI, and whether traffic reached the intended service.
unable to get local issuer certificateLook for a missing or mismatched intermediate or an unavailable trust anchor.
self-signed certificate in certificate chainDetermine whether an expected private CA is involved and whether the client trusts the correct root. Investigate an unexpected issuer.
unsuitable certificate purposeCheck key usage, extended key usage, CA constraints, and the purpose being validated.
unable to get certificate CRLCheck whether the correct, current CRL is available. This error alone does not establish revocation.
handshake failureCheck certificates, but also protocol versions, cipher compatibility, client-certificate requirements, and network devices.

These messages are starting points, not diagnoses. The same message can have more than one cause, and a single investigation can reveal more than one problem.

Putting It Together: An Application Cannot Establish Trust

Suppose an application reports that it cannot establish a trusted connection to api.example.com. Here is a practical way to work through it:

  1. Capture what the service presents. Use s_client with the correct SNI and -showcerts. Record the hostname, IP address, port, time, and network path.
  2. Inspect the leaf. Check the SAN, issuer, validity dates, serial number, and SHA-256 fingerprint.
  3. Inspect the supplied intermediates. Are the expected certificates present? Are they valid, and do they lead toward the expected CA?
  4. Verify the chain and hostname. Use the trust store relevant to the affected client where possible. Compare the result with a verification using an independently obtained root and intermediate.
  5. Compare paths and clients. Check individual backends, the application host or container, and any proxy or TLS-inspection path. A browser and an application may behave differently because they use different trust stores or obtain intermediates differently.
  6. Investigate revocation when required. Determine whether the client checks it and whether the applicable OCSP response or CRL is available and valid.
  7. Fix the actual cause. Depending on the evidence, that might mean installing the missing intermediate on the server, deploying the correct certificate, correcting the client clock, or updating an approved trust store.

Keep the evidence connected to the conclusion. “The certificate looks fine” is less useful than “the leaf is valid and matches the hostname, but this server did not provide the intermediate the affected client needs.”

Final Thoughts

OpenSSL is most useful when you approach a certificate problem as a series of questions. What did the server present? Does the certificate match the name? Can the client build a trusted chain? Is the certificate valid for the intended purpose and time? Was revocation checked?

Each command answers part of that story. Together, they can help you move from a vague certificate error to an explanation you can test, document, and fix.

References


Discover more from Cyberhunt

Subscribe to get the latest posts sent to your email.



Leave a Reply

Discover more from Cyberhunt

Subscribe now to keep reading and get access to the full archive.

Continue reading