Read the certificate chain a server sends and say whether it is complete, in order and in date, and build the OpenSSL commands that fetch it.
Initializing in your browser…
Decode an X.509 certificate field by field, check which host names it covers, and verify that each certificate in a chain was signed by the one above it
Build a PKCS#10 certificate signing request with subject alternative names, RSA, ECDSA or Ed25519. Signed and verified in the page before you send it to a CA.
Generate SSL/TLS certificates for local development, with hostnames placed in the Subject Alternative Name where browsers look. Exports PKCS#8, PKCS#1 and PKCS#12, with fingerprints and install config.
Your site loads perfectly in Chrome on your laptop and a customer reports that their Android app cannot reach it at all. The certificate is valid and not expired, so nothing obvious is wrong.
The chain the server sends, saved with the command the page gives you
openssl s_client -connect example.test:443 -servername example.test -showcerts \ </dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > chain.pem $ grep -c "BEGIN CERTIFICATE" chain.pem 1
What the page says about that one certificate
A client cannot build a path from this 1. C = GB, O = Toolbox TLS Test, CN = localhost Server certificate Issued by C = GB, O = Toolbox TLS Test, CN = Toolbox TLS Test Intermediate RSA 2048 bits SHA-256 with RSA 89 days left issuer not in this file [error] Only the leaf certificate is here Nothing above it in this file is a CA that signed it, so a client holding only root certificates cannot build a path. Measured against a real TLS client, a server sending only its own certificate is refused with UNABLE_TO_VERIFY_LEAF_SIGNATURE, and so is one sending the leaf and the root with the intermediate left out. RFC 8446 section 4.4.2 [ok] Covers localhost Exact match.
The count is the whole finding: one certificate where there should be two. The leaf is in date, covers the name and is signed by a real CA, so every check that looks at the certificate on its own passes. What is missing is the intermediate that links it to a root, and a client holding only root certificates has nothing to build a path with.
The reason this reaches production so often is that desktop Chrome hides it. When the path is short by one, Chrome reads the authorityInfoAccess URL out of the leaf, fetches the missing intermediate itself, and connects. Android does not. curl does not. Java does not. Nor does any server-to-server call, which is why the first report usually comes from an API client rather than from a browser.
That is measured here rather than quoted. Serving this same leaf to a real TLS client with the intermediate left out is refused with UNABLE_TO_VERIFY_LEAF_SIGNATURE; adding the intermediate is accepted; adding the root but not the intermediate is refused again. Six bundles were served and the module is checked to give the same verdict as the client did for each one.
Two details in the command matter as much as the output. -showcerts is what makes the server send every certificate rather than only its own, so without it you cannot see this fault at all. And </dev/null is what makes the command finish: openssl s_client reads standard input and sends it to the server, so left alone it waits for you to type. The same command measured about 130 ms with the redirect and was still running after eight seconds without it.
Paste the chain a server sends and this tool says whether it is complete, in the order the wire requires, in date, and covering the right name. It checks every link with Web Crypto in your browser, and it builds the OpenSSL commands that pull the chain down in the first place. It does not fetch the certificate for you, because no web page can: fetch hands a page the response, never the handshake, and no browser API exposes the peer chain.
The most common real TLS misconfiguration is not an expired certificate. It is an incomplete chain: the server sends its own certificate and forgets the intermediate. Desktop Chrome usually papers over that by fetching the missing intermediate from the authorityInfoAccess URL in the leaf, so the site looks fine to the person who set it up, and then fails on Android, on curl, on a Java client and on every server-to-server call. That behaviour was measured rather than assumed here: serving the same leaf to a real TLS client with the intermediate left out is refused with UNABLE_TO_VERIFY_LEAF_SIGNATURE, and so is serving the leaf with the root but no intermediate.
So the chain is what this page reads. Paste what "openssl s_client -showcerts" prints, or load a .pem, .crt or .der file, and every certificate is placed: which one is the server certificate, which are intermediates, which is a root, and which is in the file but on no path at all. Each link is verified in your browser with Web Crypto against the public key of the certificate above it, so the answer is a signature check rather than a guess from the names. Four rules are then applied and each is quoted with the document it comes from. RFC 8446 section 4.4.2 says the sender's certificate MUST come first and each following certificate SHOULD certify the one before it, so a bundle in the wrong order is named as an error. The same paragraph says the self-signed root MAY be omitted, so a root in the file is a note rather than a fault. RFC 5280 section 4.2.1.9 says a certificate without CA:TRUE cannot sign the one below it, and that a path length constraint has to accommodate the CAs beneath it.
The expiry reading is the one people most often get wrong, and it is not the leaf's notAfter. A chain stops working at the earliest expiry anywhere on it, which is quite often an intermediate, so that date is what the page reports and it names which certificate it belongs to. Dates at the other end are checked too: a certificate whose notBefore has not arrived is refused by every client, and "openssl x509 -checkend 0" will not tell you, because -checkend answers only the notAfter question. That was measured on OpenSSL 3.6.3 and the page says which command does catch it.
Six commands are built for whatever host you type, and every one of them terminates. That is not a given: "openssl s_client" reads standard input and sends it to the server, so without a redirect the command sits waiting for you to type something and never returns. Measured here, the same command finishes in about 130 ms with "</dev/null" and is still running after eight seconds without it. The commands cover saving the whole chain to a file, reading the leaf, the two dates, the Subject Alternative Names, whether your own machine trusts the chain, and an exit-status check for a cron job. The host you type is checked before it is written into a command: only the characters a host name and a port can legally contain get through, so nothing typed here can become a second command.
There is also a reachability probe, and what it can honestly report is narrower than it looks. Three HEAD requests go out in no-cors mode, which is the only mode that reaches a host that has not opted in with CORS headers. The response is opaque: no status, no headers, no certificate. If the requests complete, the host answered and your browser accepted its certificate, which is a statement about your machine's trust store rather than about the certificate itself, since a corporate proxy that re-signs traffic looks exactly the same. If they fail, the browser says "Failed to fetch" and nothing else, and that single message covers an expired certificate, a self-signed one, a name mismatch, a missing intermediate, a closed port, a name that does not resolve and a firewall. The page lists all of them rather than picking one, and points you at the address bar, where the browser does name the error.
Almost always a missing intermediate. Paste the chain and the report says whether a client holding only root certificates could build a path from it.
The leaf may have 80 days left while an intermediate has 12. The page reports the earliest date on the chain and names the certificate it belongs to.
Load fullchain.pem and confirm the order, the links and the dates before a server ever sees it.
Copy a command that fetches the chain, the dates or the SANs and actually returns, instead of one that waits for input forever.
Because no web page can. fetch gives a page the response, never the handshake, and there is no browser API that exposes the peer chain. Anything claiming to read a live certificate from a browser is either running a server you cannot see, or not doing what it says.
That the host answered and that your browser accepted its certificate. That is your machine's trust decision: a corporate proxy that re-signs traffic, or a certificate you clicked through earlier, looks identical. When it fails, the browser reports "Failed to fetch" for every cause, so the page lists the causes rather than choosing one.
Most often the intermediate is missing. Desktop Chrome fetches it from the authorityInfoAccess URL and connects anyway; Android, curl, Java and most server-to-server clients do not. Paste the chain and the report will say whether a client with only root certificates could build a path.
Yes. RFC 8446 section 4.4.2 says the sender's certificate must come first and each following certificate should certify the one before it. In practice a bundle in the wrong order usually will not load at all, because the server checks the first certificate against the private key, so the error you see names the key rather than the order.
It does not need to be. RFC 8446 says the self-signed root may be omitted, since a client that does not already hold it will not trust it anyway. Sending it is harmless and adds a certificate to every handshake.
Because openssl s_client reads standard input and sends it to the server. Without the redirect it sits waiting for you to type, so the command never returns. Measured here: about 130 ms with the redirect, still running after eight seconds without it.
No. Certificates are decoded and their signatures verified locally with Web Crypto, and nothing is written to the URL or a share link. The only thing that touches the network is the reachability check, which goes directly to the host you typed.
The reachability check sends three HTTPS HEAD requests from your browser directly to the domain you type, so that site sees the requests (and your IP). Nothing is sent to any other server, and any certificate you paste in is read entirely in your browser and never leaves it.