OpenSSL is the Swiss Army knife for dealing with TLS/SSL certificates and keys. It’s not just for generating self-signed certs; it’s your go-to for understanding why your TLS handshake is failing, verifying certificate chains, and even decrypting traffic if you have the keys.

Let’s see how we can use it to inspect a certificate and its associated private key. Imagine you’ve just received a certificate and its private key, and you need to quickly verify their integrity and understand what they’re for.

# Inspect a certificate file
openssl x509 -in my_domain.crt -text -noout

# Inspect a private key file
openssl rsa -in my_domain.key -check

# Verify the private key matches the certificate
openssl x509 -noout -modulus -in my_domain.crt | openssl md5
openssl rsa -noout -modulus -in my_domain.key | openssl md5

The first command, openssl x509 -in my_domain.crt -text -noout, dumps all the human-readable details from your certificate. You’ll see the issuer, subject, validity dates, public key details, and crucially, any Subject Alternative Names (SANs) which are vital for modern TLS. The -text flag makes it readable, and -noout prevents it from printing the encoded certificate itself.

The second command, openssl rsa -in my_domain.key -check, performs a quick sanity check on your private key. It ensures the key is valid and not corrupted. For RSA keys, it checks for structural integrity. If it says "RSA key ok," you’re in good shape.

The third and fourth commands are key for debugging certificate/key mismatches. They extract the modulus of the public key from the certificate and the private key, respectively, and then pipe that modulus through MD5 hashing. If the two MD5 hashes match, it means the public key embedded in the certificate is indeed the public counterpart to the private key you have. This is a fundamental check; if these don’t match, your server won’t be able to use that key with that certificate.

Here’s a practical scenario: you’re setting up a web server and are getting "SSL certificate error" messages in the browser. You suspect the certificate and key might be mismatched or expired.

# Check certificate expiration
openssl x509 -in my_domain.crt -noout -dates

# Check if the certificate is for the correct domain (SANs)
openssl x509 -in my_domain.crt -noout -text | grep -A 1 'Subject Alternative Name'

# Test a TLS handshake with a specific server and port
openssl s_client -connect example.com:443 -servername example.com

The openssl x509 -in my_domain.crt -noout -dates command will output notBefore=... and notAfter=.... If the current date is outside this range, your certificate is expired or not yet valid.

The openssl x509 -in my_domain.crt -noout -text | grep -A 1 'Subject Alternative Name' command is crucial. Modern browsers rely on Subject Alternative Names (SANs) to match the certificate to the hostname. If your certificate only has a Common Name (CN) and not a SAN, or if the SAN doesn’t include the exact hostname you’re accessing (e.g., www.example.com vs. example.com), the browser will reject it. The grep -A 1 will show you the line with the SANs, if they exist.

Finally, openssl s_client -connect example.com:443 -servername example.com is your direct line to the TLS handshake. It initiates a connection to example.com on port 443 and, importantly, uses the -servername example.com flag. This tells the server which certificate to present if it hosts multiple domains on the same IP address. The output will show you the entire handshake process, including which certificate chain was accepted, cipher suites negotiated, and any errors encountered during the handshake. If you see certificate verification errors here, it’s a strong indicator of an issue with your server’s configuration or the certificate itself.

The most surprising thing about TLS certificate validation is that the trust isn’t solely based on the certificate’s content, but rather on a chain of trust. Your server’s certificate is signed by an Intermediate Certificate Authority (CA), which is in turn signed by a Root CA. The client (your browser) trusts a set of Root CAs inherently. When you connect, the client verifies this chain back to a trusted root. If any link in that chain is missing or invalid, the connection fails, even if your server’s certificate is perfectly valid on its own.

To illustrate this, let’s say you have a certificate signed by an intermediate CA, but you only configured your web server to send your end-entity certificate.

# View the certificate chain sent by a server (requires a running server)
# On the server, ensure your configuration includes the intermediate cert:
# Apache: SSLCertificateChainFile /path/to/intermediate.crt
# Nginx: ssl_certificate /path/to/your_domain.crt; ssl_certificate_intermediate.crt;

# Then, from a client machine:
openssl s_client -connect your_domain.com:443 -servername your_domain.com < /dev/null 2>/dev/null | openssl x509 -noout -text | grep "Issuer:"

# Compare this issuer to the issuer of your intermediate certificate:
openssl x509 -in intermediate.crt -noout -text | grep "Subject:"

If the Issuer: from the s_client output doesn’t match the Subject: of your intermediate certificate, your server is not sending the full chain. The s_client command, when run without input (the < /dev/null 2>/dev/null part silences the interactive prompt and error messages), will show you the certificate chain presented by the server. You can then inspect the issuer of the presented certificate and compare it to the subject of your intermediate certificate. If they don’t align, the server is missing the intermediate certificate in its configuration, breaking the trust chain.

One final, often overlooked, detail is how OpenSSL handles different key types and formats. While openssl rsa is common, you’ll also encounter openssl ec for Elliptic Curve keys. Furthermore, keys can be in PEM (Privacy-Enhanced Mail) format, which is base64 encoded with headers like -----BEGIN PRIVATE KEY-----, or DER (Distinguished Encoding Rules) format, which is binary. OpenSSL commands generally work with PEM by default, but you can specify -inform DER for binary inputs and -outform PEM for binary outputs. Many tools will automatically detect PEM, but explicitly knowing these flags can save you a lot of confusion when dealing with keys from different sources.

The next hurdle you’ll likely encounter is understanding and debugging TLS cipher suites.

Want structured learning?

Take the full Tls-ssl course →