# Certificate Decoder

> Decode certificates, chains and CSRs: names, validity, extensions, chain order.

Category: Keys & Certificates · Page: https://util.caruana.me/tools/cert/

## API, MCP and A2A

### Decode certificates and CSRs (`cert_decode`)

`GET|POST https://util.caruana.me/api/cert/decode` · MCP tool `cert_decode` · A2A skill `cert_decode` · [reference](https://util.caruana.me/reference/cert_decode/)

Decodes every certificate (PEM, DER, Base64 DER, or PKCS#7 bundle) and CSR in the input. For chains it checks, for each adjacent pair, that the issuer name matches and that the signature verifies with the next certificate's key. With `hostname` it reports which certificates cover that name under RFC 6125 wildcard rules. It does not establish trust: there is no root store, and revocation (OCSP/CRL) is not checked.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string | no | PEM text (one or more blocks) or Base64 DER. Use exactly one of `input`, `input_base64`, or a file upload (.pem, .crt, .cer, .der, .p7b, .csr). |
| `input_base64` | string | no | Data as Base64 (either alphabet), for binary content over JSON or MCP. |
| `hostname` | string (≤ 253 chars) | no | Report whether each certificate's DNS SANs cover this host name. |
| `at` | string | no | Evaluate validity at this ISO 8601 time instead of now, e.g. `2026-01-01T00:00:00Z`. |

Privacy: The server receives the certificate data, decodes it in memory, and returns the decoded fields. Certificates and CSRs are public by design, but the input is not stored or logged (only the per-call metadata row is recorded). The server makes no network requests (it does not fetch OCSP, CRLs or issuer certificates). Private keys in the input are rejected.


## User guide

The tool sits in a window that works like a desktop app: menus on the top row and the **full-screen** icon at its right (**Esc** leaves full screen). The set-up options described below are in **Settings → Options…**, an overlay, and the **Settings** menu also lists the common choices directly. To keep the options in view instead, choose **View → Inline config**; the page remembers that choice. **Help → Keyboard shortcuts…** lists the keys.

1. **Paste** one or more PEM blocks, or **open a file**: `.pem`, `.crt`, `.cer`, binary `.der`, a `.p7b` bundle, or a `.csr`.
2. Optionally enter a **host name** to check whether the certificate covers it.
3. Read the cards. There is one per certificate, labelled _Leaf_, _Intermediate CA_ or _Root (self-signed)_, plus one per CSR.

**Checking a server's chain.** Paste the chain in the order the server sends it, leaf first. The summary tells you whether each certificate is signed by the next one, flags gaps or wrong order, and notes expired certificates. A typical healthy server chain is _leaf → intermediate_, without the root.

**Getting a server's chain** (on your own machine):

```sh
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
```

Paste everything between and including the `BEGIN`/`END CERTIFICATE` lines.

**Checking a CSR before sending it to a CA.** Paste the `CERTIFICATE REQUEST`. Confirm the subject, the SANs and the key type. _Signature valid_ proves the request was made by whoever holds the matching private key.

> **What this does not tell you.** A chain that "looks correct" here is structurally sound. Whether it is **trusted** depends on the client's root store, and whether it has been **revoked** depends on OCSP/CRL. This tool checks neither. Use your browser, `openssl verify -CAfile …`, or an online TLS scanner for those.

## Specification

**Input.**

- **PEM labels:** `CERTIFICATE`, `X509 CERTIFICATE`, `PKCS7`, `CERTIFICATE REQUEST` and `NEW CERTIFICATE REQUEST`, in any number and order.
- **Other forms:** raw DER (from a file), or Base64 DER pasted without armor.
- **Private keys:** input containing any `PRIVATE KEY` block is rejected.

**Certificate fields.**

| Field                          | Source                                                                                                                                                                  |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Subject, issuer                | RFC 4514 string form of the distinguished names                                                                                                                         |
| Validity                       | `notBefore`/`notAfter`. Status (_valid_, _expired_, _not yet valid_) and whole days remaining are evaluated at the current time (the API's `at` parameter overrides it) |
| Subject alternative names      | DNS, IP, email, URI, directory name and other GeneralName types                                                                                                         |
| Public key                     | Algorithm, size (RSA modulus bits or curve), RFC 7469 SPKI pin                                                                                                          |
| Signature                      | Algorithm and hash, e.g. _RSA PKCS#1 v1.5 with SHA-256_, _ECDSA with SHA-384_, _Ed25519_                                                                                |
| Key usage / extended key usage | RFC 5280 §4.2.1.3 / §4.2.1.12, with common purposes named                                                                                                               |
| Basic constraints              | CA flag and path length                                                                                                                                                 |
| Policies                       | OIDs, with CA/Browser Forum DV/OV/IV/EV policies named                                                                                                                  |
| AIA, CRL distribution points   | OCSP and CA-issuer URLs; CRL URLs (shown, never fetched)                                                                                                                |
| SCTs                           | Whether Certificate Transparency SCTs are embedded (OID 1.3.6.1.4.1.11129.2.4.2)                                                                                        |
| Fingerprints                   | SHA-256 and SHA-1 over the DER                                                                                                                                          |

**Chain checks.** For each adjacent pair (certificate _n_, certificate _n+1_):

1. The issuer name of _n_ must equal the subject name of _n+1_, compared as the RFC 4514 string.
2. The signature on _n_ must verify with the public key of _n+1_, using Web Crypto.

The last certificate is reported as a root if it is self-signed: its subject equals its issuer and it verifies with its own key.

**Host-name check.**

- **Rules:** RFC 6125 §6.4. Case-insensitive; a wildcard is allowed only as the entire left-most label and matches exactly one label (`*.example.com` matches `a.example.com`, but not `example.com` or `a.b.example.com`).
- **Names checked:** only DNS SANs. The subject CN is ignored, as modern clients do.

**CSRs** (RFC 2986). The decoder reports the subject, the requested SANs (from the `extensionRequest` attribute), the public key, and whether the self-signature verifies.

**Not performed.** Trust-anchor validation, revocation checking, name constraints, policy processing, and Certificate Transparency log lookups.
