docs: the CA travels in the enrol link, and why not the two alternatives
DECISIONS.md gets the decision with both rejected options and what the longer link measures (89 -> 652 bytes, a 45x23 QR -> 93x47), RUST.md ticks the enrolment queue item and marks the log-upload route superseded rather than editing it, and IRIS.md says what changed for anyone building the Android app. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
d8562d96a3
commit
729098756d
3 files changed
+107
-18
No files matched your search
@@ -534,3 +534,55 @@ marked **DEFERRED** are ones the agent chose not to decide alone.
|
||||
pass," and "The three remaining I5 verifications, closed 2026-09-05,"
|
||||
have the full account. The iris-vs-Masonry choice itself is still
|
||||
Iris's to make.
|
||||
|
||||
## 2026-09-07: the enrolment link carries the CA, so an APK need not be built where its server runs
|
||||
|
||||
**Problem.** Every phone build pinned the CA of the machine that compiled
|
||||
it -- the Compose app from `GeneratePinnedCert`, the iris app from
|
||||
`build.rs` reading `$XDG_CONFIG_HOME/ai-app/certs/ca.pem`. That is fine
|
||||
while the two are the same machine and impossible when they are not, which
|
||||
is exactly the iris client's situation: cross-compiled in this VM,
|
||||
delivered to a phone, run against `ai-server` on the host. Baking the
|
||||
host/port/token as well made it worse -- a token in a built artifact.
|
||||
|
||||
**Decided: the CA rides in the enrolment link**, as `&ca=<base64url of the
|
||||
DER>` (`wg_app_link::enroll::ca_param`), optional and per mint. The app
|
||||
that opens the link pins what the link said, and an APK built anywhere
|
||||
works against whatever server it is pointed at.
|
||||
|
||||
Two alternatives were worked out and rejected.
|
||||
|
||||
- **A CA *fingerprint* in the link, pinned at the TLS handshake.** The
|
||||
smallest link (43 more characters) and the strongest shape, but `ureq`
|
||||
3.4 exposes no hook for a custom `rustls` `ServerCertVerifier`: its
|
||||
`TlsConfig` builds the `ClientConfig` itself, so this needs a hand-written
|
||||
`Connector` on the `unversioned` API and `rustls` as a direct dependency
|
||||
of `client-core`. A lot of machinery in the one crate that must stay
|
||||
light.
|
||||
- **A fingerprint in the link plus an unauthenticated `GET /ca.pem`.**
|
||||
Small code, but it needs a first connection with verification disabled,
|
||||
and it breaks a documented, tested posture -- `auth.rs`'s "gates every
|
||||
route with zero unauthenticated endpoints", which is a load-bearing
|
||||
decision rather than an implementation detail. Not something to change
|
||||
silently for this.
|
||||
|
||||
**What it costs**, measured rather than guessed: on this project's P-256
|
||||
CA the link goes from 89 bytes to 652, and `print_enrollment`'s terminal
|
||||
QR from 45x23 to 93x47 characters. That is why the parameter is the
|
||||
minter's choice per call: `ai-server` passes it (its iris client needs it),
|
||||
`dev-updater` passes `None` (its app is built on the machine it talks to,
|
||||
and its QR stays scannable in an 80-column terminal). The URI printed under
|
||||
the QR is the fallback either way, and is the path Dev Updater's Enroll
|
||||
button already uses -- it opens the link with `ACTION_VIEW`, so Android
|
||||
offers whichever apps registered the scheme, which needed no change here.
|
||||
|
||||
The CA is a public certificate, so putting it in the QR leaks nothing the
|
||||
token did not already: photographing the terminal still costs exactly the
|
||||
token, which is rotatable.
|
||||
|
||||
**The log upload's destination is moot**, so it is not wired to this. On
|
||||
the same day Iris decided Dev Updater will read an APK's runtime log from
|
||||
an on-device ContentProvider instead, which removes `log_upload`,
|
||||
`POST /client-log` and the `AI_APP_LOG_*` baking altogether -- so the
|
||||
enrolment landed without touching any of them, for that change to delete
|
||||
whole.
|
||||
Reference in new issue
Block a user