Back to Catalog
kanywst GitHub avatar

y509

TUI for X.509 certificate chains verification and analysis

Overview

TUI for X.509 certificate chains verification and analysis

TUI for X.509 certificate chains: verifies trust, and catches the missing intermediates and bad ordering that break curl but not browsers

From the maintainer

Origin story

A certificate chain that works in the browser and fails in curl. The cause is almost always structural: the server never sent an intermediate, or sent its root, or sent them out of order. Browsers hide it by chasing the AIA URL to fetch the missing piece; curl, Go and Java do not, so the bug sits in production for months until a client library upgrade trips over it. The tools for this all answer the wrong question. openssl s_client dumps the raw handshake and leaves you counting BEGIN CERTIFICATE lines by eye. Everything else answers "does this verify", which is exactly the question that says yes while the chain is still broken for half your clients. I wanted the two questions separated, and I wanted the answer in a pane I could scroll rather than a wall of text.

First workflow

Point it at a server that is misconfigured on purpose: y509 validate incomplete-chain.badssl.com:443 It reports the chain as valid, and then separately reports that the chain as presented is broken: the issuer was never sent, so a client that does not chase AIA cannot build a chain. It also prints the URL to fetch the missing intermediate from. That gap between the two answers is the whole tool in one screen. Then open the same host without validate, y509 incomplete-chain.badssl.com:443, to browse the chain interactively: a list of certificates on the left, tabbed detail on the right, search across subject/issuer/SAN, filters for expired and expiring, and export or copy any certificate as PEM.

Design choice

Trust and presentation are two separate answers, and the certificates are never sorted. Every other tool sorts a chain into leaf-to-root order before showing it, because that reads better. But sorting destroys the evidence: the order the server actually sent them in is the bug. y509 keeps them exactly as they arrived, and derives the presentation report from that raw order. The handshake also deliberately verifies nothing. A chain that fails to verify is the reason you opened the tool, so rejecting it at the transport would defeat the purpose. The same split shows up in validate --json: trust.level and presentation.ok are independent fields. An exit code cannot carry that distinction. It collapses "internal PKI" and "does not link up" into one non-zero, and says nothing at all about how the chain was served.

Roadmap

STARTTLS coverage is expanding beyond smtp/imap/postgres to ftp, ldap and mysql, which closes the gap against certigo. Windows binaries are landing, along with a GitHub Action so the mis-served check can gate CI rather than only being run by hand. Nixpkgs packaging is in review; Homebrew and FreeBSD ports are already there. Longer term the interesting direction is expiry: as CA/Browser Forum maximum lifetimes shrink toward 47 days, renewals get frequent enough that a leaf-only certificate reaching production becomes a matter of when, not if.

Latest Release

v1.2.0
Released: Sep 9, 2026

Changelog

  • 8311385132eb05189156f2f8b3a3435722867cc3 feat(completions): generate all four shells, and ship fish (#104)
  • 98b5cc2f3b1ac14b2cfa3fe4b3d7d43adf2157f1 feat(connect): add STARTTLS for nntp and lmtp (#103)
  • 51e50b6a570b59d03a8130cb120b33f66e359b51 feat(json): report the handshake alongside the chain (#102)
  • a1f326230db719161bddb02794cdd8dd83b01cab docs: refresh the badssl example for the current Let's Encrypt intermediate (#101)
  • e204fdb8dac92589cfa008094a1dd5286fa8d815 docs(site): catch the landing page up with v1.1.1 (#100)

Discussions

0 comments
Loading comments...
Alvin By Alvin