# TLS Checker

> Connect to a host and check its certificate chain, trust, host name and protocol (server-side).

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

## API, MCP and A2A

### Check a server's TLS certificate (`tls_check`)

`GET|POST https://util.caruana.me/api/tls/check` · MCP tool `tls_check` · A2A skill `tls_check` · [reference](https://util.caruana.me/reference/tls_check/)

Connects to `host:port` with OpenSSL 3, using SNI, and verifies the presented chain against the Mozilla root store, including host name verification (RFC 6125). It reports OpenSSL's verdict and every verify error with its chain depth, plus the negotiated protocol, cipher and key-exchange group. The chain is then decoded exactly as `cert_decode` would, with ordering, signature and expiry notes. Only direct TLS is supported (no STARTTLS). Revocation (OCSP/CRL) is not checked.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `host` | string (≤ 253 chars) | yes | Public DNS name or IP address. Private, loopback, link-local, CGNAT and documentation addresses are refused, both as given and after DNS resolution. |
| `port` | 443 \| 8443 \| 465 \| 636 \| 853 \| 993 \| 995 \| 5061 | no | TCP port. Only ports that speak TLS directly are allowed. |
| `servername` | string (≤ 253 chars) | no | SNI and verification name, if different from `host` (for example when `host` is an IP address). |

Privacy: The server receives the host name and port, and forwards them to the TLS checker operated by this service, which connects to that host. Nothing else is sent, and nothing is stored or logged apart from the per-call metadata row. The target host sees a TLS connection from the checker's network, not from you.


## 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). **Help → Keyboard shortcuts…** lists the keys.

1. Enter your **client ID and secret** (get them on the [credentials page](/credentials/)). Optionally choose to remember them: _This tab_ or _This device_ (until you click _Forget_).
2. Enter the **host** (for example `example.com`) and, if needed, a **port**. Leave **servername** empty unless you are connecting to an IP address and need a specific name checked.
3. Press **Send request** and read the result:
   - **`trusted: true`**: the chain leads to a root in the Mozilla trust store, and the certificate covers the host name.
   - **`verification.errors`**: why it isn't trusted, by chain position (`depth` 0 is the server's own certificate). Common codes:
     - `10`: expired.
     - `18`: self-signed.
     - `19`: self-signed certificate in the chain, meaning an untrusted root.
     - `20`: issuer not found, usually a missing intermediate.
     - `62`: host name mismatch.
   - **`certificates`**: each certificate decoded, as in the [Certificate Decoder](/tools/cert/). **`notes`** points out ordering gaps and expiry.
   - **`protocol`, `cipher`, `key_exchange_group`**: what the connection negotiated. `X25519MLKEM768` means a post-quantum hybrid key exchange.

**From code:** `POST /api/tls/check` with `{"host": "example.com"}`, the MCP tool `tls_check`, or the A2A skill `tls_check`. See the [reference](/reference/tls_check/).

## Specification

**How the check runs.**

1. The API passes the host and port to a TLS checker operated by this service. The checker is a container running OpenSSL 3 on the operator's own server, reached through an authenticated Cloudflare Tunnel.
2. The checker resolves the host once and connects to that exact address, so it cannot be redirected by DNS changes mid-check (DNS rebinding).
3. It runs `openssl s_client -showcerts` with SNI, the Mozilla CA bundle as the trust store, and `-verify_hostname` for RFC 6125 host-name verification.
4. The handshake is allowed to complete, so OpenSSL reports its final verdict and every individual verify error.

**What is refused.**

- **Non-public addresses:** private, loopback, link-local, CGNAT (100.64/10), documentation, multicast and reserved ranges, for IPv4 and IPv6 (including IPv4-mapped and NAT64 forms). This applies to the address given and to the address the name resolves to.
- **Ports** other than 443, 8443, 465, 636, 853, 993, 995 and 5061. These speak TLS directly; STARTTLS ports such as 25 and 587 are not supported.
- **Malformed host names.** The connection target is never passed through a shell.

**Limits.**

- **Timing:** 10 seconds per connection, and at most 8 concurrent checks on the checker.
- **Rate limits:** the normal API limits apply.

**Not checked.** Revocation (OCSP, CRL), Certificate Transparency compliance, cipher-suite policy, and protocol downgrade behaviour.

**What the target sees.** A TLS connection from the checker's network, not from you. The checker sends nothing except a standard TLS ClientHello and closes the connection after the handshake.
