A TLS certificate binds a domain name to a public key. Here is how I read one, trace its chain, fix common errors, and check CSRs and CAA records.
Password entropy measures how hard a secret is to guess, in bits. Here is the formula, why Password1! fails it, and how to generate something strong.
9 min read
A JWT is a signed bundle of JSON claims. Here is how to read one, why decoding is not verifying, and how to check for the classic JWT security flaws.
9 min read
A TLS certificate is a signed statement that a public key belongs to a domain name. A certificate authority (CA) checked that someone controlled the name, then signed the pairing. That is the whole promise.
Need the answer for one domain? Paste it into the free SSL Certificate Checker. It fetches the live certificate on port 443 and shows issuer, SAN, validity, days to expiry and fingerprint. Below: how to read those fields, why chains break, and what changes in 2026.
Every output here was captured on 8 October 2026 (IST), against public hosts: example.com and the badssl.com test hosts.
SSL is the old protocol. RFC 7568 says SSLv3 MUST NOT be used; RFC 8996 does the same for TLS 1.0 and 1.1. Browsers speak TLS 1.2 or TLS 1.3. "SSL certificate" survived as the shop name. The file is an X.509 certificate, defined in RFC 5280.
What it proves:
It does not prove the site is honest or patched. And it is public by design: anyone can download yours. It holds no secret.
This pulls the certificate a server presents and prints what I check first:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName -fingerprint -sha256
subject=CN=example.com
issuer=C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
notBefore=Sep 26 22:49:11 2026 GMT
notAfter=Dec 25 22:56:35 2026 GMT
X509v3 Subject Alternative Name:
DNS:example.com, DNS:*.example.com
sha256 Fingerprint=85:CA:6A:B0:68:E9:BC:CE:88:B6:C4:AA:3C:47:F7:D1:72:28:13:4A:45:7F:87:0D:38:00:E6:22:3A:0D:F0:7A
-servername sends SNI. Drop it on a shared host and you may get another site's certificate. Swap the last command for openssl x509 -noout -text to see every field.
| Field | What it is | What I check |
|---|---|---|
| Subject / CN | The old "Common Name" | Ignore it for matching. RFC 9525 says CN "MUST NOT be used to identify a service" |
| Subject Alternative Name | Every hostname covered | The exact host users type must be here, or under a wildcard |
| Issuer | The CA certificate that signed it | The intermediate you expect |
| notBefore / notAfter | Validity window (RFC 5280 §4.1.2.5) | Days left. Above: 26 Sep to 25 Dec 2026, about 90 days |
| Public key | RSA or ECDSA | RSA 2048+ or ECDSA P-256/P-384/P-521 |
| Key Usage / EKU | What the key may do | EKU includes TLS Web Server Authentication |
| Serial number | CA-assigned ID | At most 20 octets (RFC 5280), at least 64 random bits |
| Fingerprint | Hash of the whole cert | Computed by your tool, not stored in the cert |
| SCTs | Proof of Certificate Transparency logging | Two, or three if over 180 days |
On this cert, -text showed a 256-bit id-ecPublicKey, TLS Web Server Authentication, and two Log IDs under CT Precertificate SCTs. Two fits Chrome's CT policy: two SCTs from distinct logs, run by at least two operators, for a cert of 180 days or less, three above that.
The key, serial and SAN rules come from the CA/Browser Forum TLS Baseline Requirements (§6.1.5, §7.1). SAN is mandatory; CN is "NOT RECOMMENDED" and, if present, must repeat a SAN value. If an error says "name mismatch" and the CN looks right, read the SAN list. That is the only list that counts.
Browsers trust a set of root CAs, not example.com. The server must hand over a path from the leaf to one of them:
echo | openssl s_client -connect example.com:443 -servername example.com -showcerts 2>&1 \
| grep -E '^ *[0-9] s:|^ +i:|Verify return code'
0 s:CN=example.com
i:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
1 s:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
i:C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
2 s:C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
i:C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022
3 s:C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022
i:C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services
Verify return code: 0 (ok)
s: is the subject, i: the issuer, and each issuer is the next subject. Depth 0 is the leaf; 1 and 2 are intermediates. Depth 3 is a cross-certificate: the SSL.com root signed by an older root, so clients that only trust the older one can still build a path. No self-signed root is sent.
That matches RFC 8446 §4.4.2: the server's own certificate comes first, each following one SHOULD certify the one before it, and a trust anchor MAY be omitted because the client already has it.
"Works in my browser, fails in curl" usually means a missing intermediate. Firefox preloads disclosed intermediate CAs, so the browser fills the gap. OpenSSL, and curl built on it, don't fetch missing intermediates: they use what the server sent plus the local trust store. Fix the server: configure the leaf plus intermediates file from your CA (often "full chain"), not the leaf alone.
A certificate signing request (CSR) is what you send a CA. Per RFC 2986 it holds a distinguished name, a public key and optional attributes, signed with your private key. The key never leaves your server. I use this for a P-256 key with two names:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout example.com.key -out example.com.csr \
-subj "/CN=example.com" -addext "subjectAltName=DNS:example.com,DNS:www.example.com"
Decode it before you submit: openssl req -in example.com.csr -noout -text, or paste it into the CSR Decoder, which parses it in your browser. Check the SAN list (a missing www is the classic mistake), the key type and size, and the signature. A CSR is public. Never paste the .key file anywhere.
In April 2025 the CA/Browser Forum adopted Ballot SC-081: issuers 25 yes, 0 no, 5 abstaining; Apple, Google, Microsoft and Mozilla all yes. The schedule sits in §6.3.2 of the Baseline Requirements:
| Issued on or after | Maximum validity |
|---|---|
| (before 15 March 2026) | 398 days |
| 15 March 2026 | 200 days |
| 15 March 2027 | 100 days |
| 15 March 2029 | 47 days |
CAs SHOULD stay a day under each cap (199, 99, 46); the BR counts a day as exactly 86,400 seconds. The ballot also cuts domain-validation reuse (§4.2.1): 398 days, then 200 from 15 March 2026, 100 from 15 March 2027, and 10 from 15 March 2029.
Let's Encrypt's lifetime page says 90 days is still its default, with 6-day certificates opt-in. Its 45-day plan moves the default to 64 days on 10 February 2027 and 45 days on 16 February 2028.
My take: if anyone renews a public certificate by hand from a calendar reminder, 2027 is when that habit breaks. Automate with an ACME client. Let's Encrypt suggests renewing about two-thirds of the way through a certificate's life, not on a fixed 60-day timer.
A CAA record lists which CAs may issue for your domain. RFC 8659 defines three tags:
issue: CAs allowed to issue. issue ";" allows none.issuewild: CAs allowed to issue wildcards. If present, it overrides issue for wildcard requests.iodef: where a CA can report a request it refused.example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issuewild ";"
example.com. CAA 0 iodef "mailto:security@example.com"
The CA checks the exact name, then climbs one label at a time until it finds a CAA set. No CAA anywhere means any CA may issue. The Baseline Requirements (§3.2.2.8, §4.2.2.1) make the check mandatory. On 8 October 2026, google.com published one record, 0 issue "pki.goog", and example.com published none. Run your domain through the CAA Record Checker, and use DNS Lookup for the rest of the zone.
A flag of 128 marks a tag critical: a CA that doesn't understand it must not issue. Leave it at 0 unless you know why.
CT logs are public, append-only records of issued certificates (RFC 6962, revised as experimental RFC 9162). Chrome rejects publicly trusted certificates without enough SCTs, so in practice public certs get logged.
That cuts both ways. Defenders search their domain on a CT search site such as crt.sh and look for an issuer they never used. Recon reads every SAN as a hostname, staging ones included. The web reconnaissance tutorial lists CT as a passive recon source. Keep it to domains you own or are scoped to test.
badssl.com runs deliberately broken hosts. OpenSSL 3.5 on five of them:
for h in expired wrong.host self-signed untrusted-root incomplete-chain; do echo | openssl s_client -connect $h.badssl.com:443 -servername $h.badssl.com -verify_hostname $h.badssl.com 2>&1 | grep -o "Verify return code.*" | sed "s/^/$h: /"; done
expired: Verify return code: 10 (certificate has expired)
wrong.host: Verify return code: 62 (hostname mismatch)
self-signed: Verify return code: 18 (self-signed certificate)
untrusted-root: Verify return code: 19 (self-signed certificate in certificate chain)
incomplete-chain: Verify return code: 21 (unable to verify the first certificate)
Keep -verify_hostname. Without it s_client checks the chain, not the name: on wrong.host it printed 0 (ok).
| Symptom | Cause | Fix | Where it shows |
|---|---|---|---|
| Expired (10) | Renewal failed | Renew, fix automation | Checker countdown |
| Hostname mismatch (62) | Name not in SAN | Reissue with every hostname | Checker SAN; decode CSR first |
| Self-signed (18) | Default or test cert | CA-issued cert | Checker: issuer = subject |
| Untrusted root (19) | Private CA | Public CA, or push root to managed devices only | OpenSSL chain |
| Incomplete chain (21) | No intermediates sent | Serve full chain | OpenSSL; browsers may hide it |
| Weak key / SHA-1 | Old issuance or appliance | RSA 2048+ or ECDSA, SHA-256+ | openssl x509 -text |
In a pentest report these are usually low-severity configuration findings, but they train users to click through warnings. I check them in the TLS block of my penetration testing checklist.
Once the certificate is clean, HSTS tells browsers to always use it. HTTP security headers explained covers it; the HTTP Header Checker shows if you send it.
It shouldn't be; RFC 7568 prohibits SSLv3. The name stuck, so "SSL certificate" and "TLS certificate" mean the same X.509 file.
Public TLS certificates issued from 15 March 2026: at most 200 days. Then 100 days from 15 March 2027 and 47 from 15 March 2029. Let's Encrypt's default is 90 days today.
*.example.com matches exactly one label: www.example.com, not example.com or a.b.example.com (RFC 9525 §6.3). A SAN cert lists names explicitly. The example.com cert above does both.
For domain validation, browsers check the same things. Paid adds identity validation (OV/EV), support and tooling. Encryption strength comes from the key and TLS settings, not the price.
No. The connection is encrypted and the name was validated. A phishing domain can hold a valid certificate for its own name. Check the domain, not the padlock.
Run your own domain through the SSL Certificate Checker and compare it with the table above.
Share this article
An IPv4 address is one 32-bit number. Here is how to read it as decimal, hex, binary or integer, size a CIDR block, and spot private ranges.
9 min read
Sign in to leave a comment.