A small, fast, chainable TLS / QUIC cipher-configuration and post-quantum
readiness scanner. One static binary. The tool reads the negotiated cipher
configuration of remote endpoints. The fields: protocol versions, cipher
suites, key-exchange groups, signature algorithms, certificate properties.
A fixed rubric rates every observation on the post-quantum readiness scale.
The record carries the rating as pq=<label>(<score>). The tool reads the
import toolset's forms and writes them out: stdin → stdout, streaming
JSONL, the chain subfinder → httpx → naabu → nuclei.
Status: the 2026.01 release is live and attested.
The specification (docs/spec.md) is in force.
- fast mode — one engineered handshake per target (a browser-grade hello; the hybrid ML-KEM key share preferred). The record: the negotiated parameters, the certificate chain, ALPN, the session features.
- deep mode — one probe plan per target; every suite, version, group and signature algorithm probes one per handshake (offer-one / observe-accept). The checks: HRR detection, resumption, 0-RTT.
- pq mode — the forced PQ-group offer set (the registered PQ codepoints). The classifier reads the PQ signatures and the certificates. Every target takes one readiness rating; the HNDL risk flag rides on a draft acceptance.
- the two planes — TCP (crypto/tls + uTLS) and QUIC (quic-go) on UDP/443. HTTP/1.1 and h2 negotiate by ALPN. h3 runs through the direct QUIC handshake.
- chainable — the inputs: hosts,
host:port/ip:port,scheme://host[:port]spec lines (the scheme strips), the piped stdin, the subfinder/httpx/naabu/masscan output forms. The outputs: JSONL, CSV, text, URLs.
Rows tagged historical carry the capture of their evidence run; google.com is the live reference target for re-measurement.
Measured baselines (spec
§7.8):
the SLO suite re-runs on every perf-suite merge; this table carries the
current numbers. The linked evidence comments carry the verbatim run
transcripts.
| Metric | Target | Measured | Run |
|---|---|---|---|
| fast-mode handshakes/s (aggregate, W=8, loopback fixture) | ≥ 2,500/s/core | 2,750 (the runner re-run, 2026-10-22) | go test ./internal/microbench/ -run SLO -v — evidence #10 |
| external control decomposition (cloudflare.com:443, forced hybrid) | — | connect 18.9 ms / handshake 23.4 ms / total 42.4 ms | go run ./cmd/bench -target cloudflare.com:443 -host cloudflare.com -n 20 -mode seq — evidence #10 |
| external control decomposition (google.com:443, the reference live target) | — | connect 20.7 ms / handshake 140.3 ms / total 161.0 ms | go run ./cmd/bench -target google.com:443 -host google.com -n 20 -mode seq |
| QUIC plane ground truth (live, cloudflare.com) | — | 4588 X25519MLKEM768 negotiated inside QUIC v1 (ALPN h3) at 27.6 ms/handshake |
PQSCAN_INTEGRATION=1 go test ./internal/quicx/ -run Integration -v — evidence #9 |
| obsolete-Kyber compat oracle (live) | — | share-less offer of group 25497 answered by an HRR demanding the draft group | PQSCAN_INTEGRATION=1 go test ./internal/tlsx/ -run Integration -v — evidence #8 |
# subfinder gives the target names; pqscan scans them
subfinder -d example.com -silent | pqscan -mode fast -jsonl -o assets.jsonl
# naabu gives the live ports; the cipher pass reads them
naabu -l domains.txt -p 443,8443,993 -silent | pqscan -mode fast -jsonl
# deep: the offer-one matrix on one asset (versions, suites, groups, HRR)
pqscan -u google.com -mode deep -deep full -jsonl
# the weekly PQ job over the target list; jq reports every below-ready target
pqscan -l targets.txt -jsonl \
| jq -r 'select(.pq.score < 60) | [.target.host,.pq.label,(.pq.hndl|tostring)] | @tsv'A defect report needs the diagnostics. Re-run the same arguments with
-debug -debug-out diag.json and
open an issue —
the templates require the diagnostics attached.
The canonical specification is
docs/spec.md. Every issue links the sections it
implements through the heading anchors.
| Section | Anchor |
|---|---|
| Problem statement | docs/spec.md#1-problem-statement |
| Goals and non-goals | docs/spec.md#2-goals-and-non-goals |
| Related work | docs/spec.md#3-related-work--honest-survey |
| Language decision | docs/spec.md#4-language-decision-go-or-rust |
| Feature set | docs/spec.md#5-feature-set |
| Chaining recipes | docs/spec.md#6-chaining-reference-implementations |
| Async architecture and throughput | docs/spec.md#7-the-hard-part-async-architecture-and-throughput-first-class |
| CLI surface | docs/spec.md#8-cli-surface |
| Milestones | docs/spec.md#9-milestones |
| Test and verification | docs/spec.md#10-test-and-verification-strategy |
| PQC codepoints (registry snapshot) | docs/spec.md#appendix-a-pqc-codepoint-reference-snapshot |
The milestone list is historical. The record lives in the repository's milestones and the closed issues. The releases and the live CLI surface carry the current state.
CONTRIBUTING.md— the working agreement (Conventional Commits, signed commits, one logical change per PR).AGENTS.md— the single source of truth for contributors and coding agents.SECURITY.md— vulnerability reporting (private advisory).CODE_OF_CONDUCT.md.
Engineering standard — watched RED (ADR-0002): every behavioural change goes in as a RED→GREEN pair. The failing test exists and runs first. The PR records the RED output verbatim. See CONTRIBUTING.md for the hypothesis-first procedure.
Scan only the systems the operator owns or holds authorisation to test. The tool's etiquette defaults (the rate caps, the per-subnet concurrency, the circuit breakers) are published defaults and security-relevant.
MIT.