Conversation
Five changes to the pairing flow, all on the plaintext pre-commit HTTP path: - Terminal pairing signals (cancel/decline/expire/fail) are now authenticated. A bystander who only observed an inviteId on the wire could previously drive the inviter or joiner to tear down a pending invite. Each signal now carries an HMAC (signalTag) keyed by the session's ephemeral Key Exchange secret, which only the two parties that ran the Initial Exchange hold; handlePairing verifies it before dispatching the phase. eap-noob exposes that secret via Server/Peer.EphemeralKey. - A repeated Key Exchange on a session that already holds its ephemeral secret is refused. The EAP peer's onKeyExchangeRequest has no state guard, so without this an attacker who learned the inviteId could POST a fresh Type-3, overwrite the session key, and then forge the signal MAC the change above relies on. - The Completion Exchange is rate-limited per invite. The PIN is six digits, so each attempt materially reduces the guesses needed; N attempts tolerate honest typos, and beyond that the invite and its EAP session are torn down. The kickoff POST is not counted. The endpoint is unauthenticated and the inviteId is on the wire, so an on-path attacker can still burn the budget — that is the documented active-MITM boundary, noted in the README. - The PIN Noob is derived through PBKDF2 with a fresh per-invite salt (carried inside the MAC-covered ServerInfo transcript, so it cannot be swapped) instead of a single unsalted hash. This raises the cost of checking PIN candidates against a captured NoobId from milliseconds to ~10^6 x iteration cost. Empty salt keeps the legacy derivation so an older peer still pairs. - handleCancelInvite no longer unlocks sess.mu on a path that still held it, fixing a double-unlock/leak when the session had no Key Exchange secret. Signed-off-by: woodsonl <65194841+woodsonl@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
All four changes are on the plaintext pre-commit HTTP path between the inviter
and the joiner.
Terminal signals carry an HMAC. The
cancel,decline,expire, andfailphases of the pairing endpoint were accepted from any caller that namedan
inviteId. Each signal now carries asignalTag: an HMAC keyed by thesession's ephemeral Key Exchange secret, which both parties derive during the
Initial Exchange.
handlePairingverifies the tag before dispatching thephase.
eap-noobexposes that secret asServer/Peer.EphemeralKey.The Completion Exchange is rate-limited per invite. The PIN is six digits,
so each attempt reduces the number of guesses left. The handler counts attempts
per invite, allows a few for typos, and past that tears down the invite and its
EAP session.
The PIN Noob is derived with PBKDF2. It was a single unsalted hash. It is
now PBKDF2 with a fresh per-invite salt, carried inside the MAC-covered
ServerInfotranscript so the salt cannot be swapped. An empty salt keeps theprevious derivation so an older peer still pairs.
A mutex is no longer double-unlocked.
handleCancelInviteunlockedsess.muon a path that still held it, when the session had no Key Exchangesecret.
Release intent
Changelog title
Pairing signals are authenticated and PIN attempts are limited
Changelog body
Pairing lifecycle signals between an inviter and a joiner are now
authenticated, so a third party who saw an invite identifier cannot tear the
pairing down. Repeated wrong-PIN attempts against one invite are capped, and
the PIN-derived value used during pairing is stretched with a per-invite salt.
Bumps
Scope
Included: the signal authentication, the per-invite completion-attempt cap, the
PBKDF2 PIN Noob, the
handleCancelInvitemutex fix, and theEphemeralKeyexport in
eap-noobthat the signal MAC needs.Excluded: the other pairing behavior is unchanged. The wire format gains an
optional
signalTagandpinSalt; a peer that does not send them is handledby the existing unknown-invite paths.
Validation
go build ./...andgo test ./...inservices/eap-noobandservices/nvpair-cluster-managerservices/nvpair-cluster-manager/pairing_signal_gate_test.gocovers signalrejection without a valid tag and acceptance with one.
services/nvpair-cluster-manager/cm_unit_test.gocovers the salted PIN Noobround-trip, salt independence, and the empty-salt legacy path.
Risk
Pairing wire format. A
signalTagis now required forcancel,decline,expire, and the plain-HTTPfailpath; both sides of a pairing run thiscode after the change, so a mixed-version pair is the only concern. The salt
field is optional and empty means the previous derivation, so an older peer
still completes pairing.
Checklist
git commit -s), certifying the Developer Certificate of Origin.services/versions.jsonis written by automation — do not edit it by hand.