Rework pairing attempt gating - #194
Conversation
maximmaxim345
left a comment
There was a problem hiding this comment.
Have two security concerns with this PR, left inline comments for both of them.
|
Edit: the |
Dynamic pairing code: replace gesture-gated escalation with a time-based backoff after 5 failures, and drop the counter's persistence across reboots - rebooting requires the same physical presence a gesture proves. Static pairing code: the window admits up to 5 attempts per gesture instead of one, so a typo no longer costs a walk to the device. The pairing window is now a static-code-only concept. Co-Authored-By: Claude Fable 5 <[email protected]>
5390ded to
8260423
Compare
|
Good example of something to add to the implementation guide. cooldown strategy should be client concern so we should not mandate it at all |
No escalation and no backoff: how a client throttles failed dynamic pairing attempts is its own concern. Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
The change to static pairing code to 5 attempts per window is fine. The change to dynamic pairing code going from gesture-gating after escalation to cool down is not a good idea. We could, if anything, in light of the other changes go in the opposite direction now and gesture-gate already from the first attempt. |
@arturpragacz was thinking about this a bit. What I'm definitely against is 3067218 in its form. That's basically dropping the constants were IMO good enough, so a client implemented to spec can be brute forced in under a day. Gesture gating is a good idea, but forcing it onto any manufacturer also feels invasive. What I'm fearing is that we have a protocol thats secure, but with limited adoption because of that. I think there is no "best" solution here so we need to compromise somewhere... I have another idea though that should allow security conscious devices to stay secure (or even more secure as before this PR and other recent changes), but still allows manufacturers more flexibility. What do you think about ce32049: What if we keep With the recommended cooldown from ce32049, from my calculations it's a 50% chance of getting in after ~20 years. With no limit it's about 20 ms per attempt, so a 98.7% chance of getting in within a day. |
As written a client with no limit at all is conformant, a server that aborts before the code finishes playing is never counted, and a count kept per server is bypassed by rotating keys. After 20 consecutive failed attempts the client now MUST hold attempts back until a deliberate operator action, with a power cycle qualifying so no device is locked out. Counting starts when emission starts and the count is global. The cooldown schedule is dropped: how a client paces attempts before the limit is its own choice, reported through `retry_after_ms` and `message`. Also caps `message` at 200 characters and lets a server cancel instead of outlasting `retry_after_ms`.
|
|
||
| - `pairing_index`: integer - see [Pairing index](#messages) | ||
| - `retry_after_ms?`: integer - the client will be ready in this many milliseconds without operator action; absent when an operator action is needed | ||
| - `message?`: string - a short plain-text sentence for the operator, at most 200 characters, such as what to do to proceed, preferably in one of the server's [`languages`](messaging.md#server--client-serverhello). It comes from an unauthenticated peer: the server shows it as text attributed to the device, truncates it to that length, and MUST NOT interpret markup or links in it |
There was a problem hiding this comment.
We could define this as an enum with all the ways that we envision this can be reasonably implemented.
That would both make translations easier and allow us to show some graphics, etc.
But it would be more work, and there's a risk that we miss some use cases.
There was a problem hiding this comment.
Yea, but I don't think we have enough information about this. We can think of ways that might happen (like popup on screen, press play button, hold play button, hold pairing button, hold power button, ...) but thats just too many possibilities to list out.
So we would need to at least group them to something simpler like "press button", but thats just not enough information to be useful.
We could add a reason and optional message, but I don't know how we might show that in a server UI... (since the message text is actually whats useful).
For translations, it's up to the client with the language sent through server/hello. (with highly specialized messages I don't think the server could even know about pre-translated versions for all cases)
Automatically translating it is an idea but I'm starting to overthink this problem.
With no recommended cooldown and a hard stop at 20 attempts the duration served no security purpose, and `message` already tells the operator what the client waits for.
Reworks how code-based pairing attempts are gated, from the #183 lockout discussion.
Dynamic pairing code: the persisted failure counter and its escalation to gesture-gating are gone. A failed attempt is one where the client started emitting the code and the attempt ended without a successful
server_kcverification. After 20 consecutive failed attempts the client MUST hold attempts back until a deliberate, manufacturer-defined operator action; which action is the manufacturer's choice, with guidance tracked in #205. The count is global across servers and addresses and resets on success or on that action. How a client paces attempts before the limit is its own choice, and it MAY be stricter, including a gesture from the first attempt. Since any deliberate action qualifies, no device is locked out, and since a client with no limit is not conformant, manufacturers have a spec section to point a test lab at (ETSI EN 303 645 provision 5.1-5, EN 18031-1 AUM-6).Static pairing code: the window admits up to 5 attempts instead of one, all on the connection that carries the first, so a typo no longer costs a walk to the device. It closes on a completed pairing, the fifth failed attempt, drop of that connection, operator cancellation, or lifetime expiry, and the lifetime pauses while an attempt is in progress. The pairing window is now a static-code-only concept and its section moves under the Static Pairing Code Flow.
client/pair-pendingnow covers both cases, a gesture awaited or a dynamic attempt held back, and gains an optionalmessage: a plain-text sentence for the operator of at most 200 characters, preferably in one of the server'slanguages, shown as device text with no markup interpreted. The server SHOULD surface the pending state and the message to the operator and apply its own timeout.An abandoned attempt does not count against a window and counts as a failed dynamic attempt only if the code was already being emitted.