You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(moshpit): put the pinned-TLS proxy on the path, and stop trusting CAs as leaves (#343)
* fix(trust): refuse to install a CA:TRUE certificate as a trust anchor
`dns trust <name>` installed whatever the socket served, provided the registry
published a matching pin. The pin proves the registry vouches for that *key*; it
says nothing about whether trusting it is bounded.
A certificate installed here is installed as a trust anchor, and an anchor
marked CA:TRUE may issue for any name. The code claimed the opposite — "its SAN
limits it to this one name" — but a SAN describes what a certificate speaks for,
not what a key trusted as an authority may sign. This is the same hole
requireNameConstraints closes on the root path, arriving by the other door.
It went unnoticed because openssl's `req -x509` defaults to CA:TRUE, so every
origin created by setup-origin.sh serves exactly the shape that must be refused,
and it is indistinguishable from a correct one until someone trusts it.
The refusal names a remedy that costs nothing: re-issue as CA:FALSE reusing the
key, and the published pin does not move. A gate with no way forward is a gate
people route around.
An unreadable certificate is treated as a CA — the safe direction to fail in.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(dns): turn proxy mode on in `dns enable`, so a stock client just works
`addressAnswer` could already point every live name at the local pinned-TLS
proxy, `dns start --proxy` could already switch it on, and `dns enable` already
installed the root the proxy signs with. Nothing ever connected them. So names
resolved straight to their origin, a stock client got a certificate no CA had
signed, and the trust store was populated for a proxy that was never on the
path — which reads, correctly, as "this is still broken".
`dns enable` now probes for the proxy and starts the bridge in proxy mode when
it finds one.
The probe is a TLS handshake, not a connect. `proxyReachable` answers "is
something listening", and on one common class of machine the two answers differ
in the worst way: an origin runs nginx on 0.0.0.0:443, which covers loopback, so
a connect succeeds and proxy mode would point every live Moshpit name on the
machine at a web server that has never heard of them. That is not a certificate
problem, it is every name serving the wrong site at once.
So `proxyServes` completes a handshake and checks who issued the certificate.
The proxy mints a leaf per name from the root it generated here; nginx serves
the origin's own self-signed certificate, issued by itself. Nothing is trusted
in the process — the peer certificate is read, not verified, and only the issuer
name is taken from it.
Refusing is the default in every uncertain case. Proxy mode with nothing behind
it resolves every name and then refuses every connection, which looks like the
sites are down while `dig` stays healthy.
A bridge this run did not start keeps its own mode, so the probe is skipped
rather than run and then discarded — announcing a proxy and retracting it two
lines later is worse than not looking.
`--no-proxy` opts out.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
0 commit comments