From 39c38f98fe1e506bea02f587b65f5f234f021236 Mon Sep 17 00:00:00 2001 From: Pierre Rouanet Date: Mon, 14 Sep 2026 14:40:45 +0200 Subject: [PATCH] btd: net.connect does not travel over an authenticated link, and the comment said it did MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `NetConnect` arm justified routing a wifi passphrase over the radio by claiming the characteristic sets `encrypt_authenticated_write` and that the PIN agent makes the bond an authenticated one. Neither is true. `bluez.rs` sets `encrypt_write`, and sets it from `--require-pairing`, which is off by default — so on an ordinary board nothing on this link is encrypted. And the stronger flag could not be satisfied if it were set: the agent publishes as `NoInputNoOutput`, so the bond is just-works and unauthenticated by construction. `pairing.rs` already records why a headless robot cannot do better, and `bluez.rs` says the same thing a few lines from the flag. The route is unchanged and still correct — a robot with no network cannot be given one any other way. What changes is that the comment now names the PIN check and the radio range as what actually stands behind it, and points at §8.1 as the blocker rather than implying it is already closed. Found while testing `--require-pairing` against an iPhone. Assisted-by: Claude:claude-opus-5 --- btd/src/route.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/btd/src/route.rs b/btd/src/route.rs index 1eb67679..1f713099 100644 --- a/btd/src/route.rs +++ b/btd/src/route.rs @@ -136,10 +136,22 @@ fn permits(call: &proto::Call) -> bool { // are permitted, including the two that change things. NetStatus => true, NetScan => true, - // Carries a wifi passphrase, which §7 requires to travel over a paired, encrypted link. - // It does: the characteristic sets `encrypt_authenticated_write` and the PIN agent makes - // the bond an authenticated one (`crate::pairing`). Routing this before that existed - // would have been the ordering mistake. + // Carries a wifi passphrase, and this arm used to claim that travels over a paired, + // authenticated link. It does not, and the claim was wrong in both halves. + // + // The characteristic sets `encrypt_write`, not `encrypt_authenticated_write` + // (`crate::bluez`) — and it sets it from `--require-pairing`, which is **off by default**, + // so on an ordinary board there is no encryption on this link at all. Nor could the + // stronger flag be satisfied if it were set: the agent leaves every handler `None`, which + // BlueZ publishes as `NoInputNoOutput`, so the bond is just-works and therefore encrypted + // but *unauthenticated*. `crate::pairing` records why a headless robot cannot do better, + // and `docs/design/app-path-design.md` §5.5 is the state of it. + // + // So what actually stands behind this route today is the PIN check in `crate::session` and + // the ten metres of radio range, and the passphrase crosses in clear. That is a known, + // accepted, pre-shipping cost — `btd` warns about it at every start — and §8.1 is the + // blocker that has to close before a robot goes to anyone. Routed anyway because a robot + // with no network cannot be given one any other way, which is what this transport is for. NetConnect(_) => true, NetForget(_) => true,