fix(ble): notifications, write-with-response, LE secure connections check#202
Open
AlfioEmanueleFresta wants to merge 3 commits into
Open
fix(ble): notifications, write-with-response, LE secure connections check#202AlfioEmanueleFresta wants to merge 3 commits into
AlfioEmanueleFresta wants to merge 3 commits into
Conversation
618eae0 to
a1ef9d4
Compare
…eristics Per CTAP 2.2 §11.4, both fidoControlPoint and fidoServiceRevisionBitfield expose the standard Write property (GATT Write Request, with response). The previous code always issued WriteType::WithoutResponse, which is spec-incorrect and may silently drop bytes on conforming authenticators. Introduces a write_type_for() helper that inspects the characteristic's declared GATT properties and picks WithResponse when WRITE is set, falling back to WithoutResponse only when the authenticator explicitly advertises just that property. Unit tests cover the property-detection logic.
Per CTAP 2.2 §11.4 the fidoStatus characteristic is Notify-only. The previous receive path called peripheral.read() against it, which bluez rejects with NotPermitted and makes FIDO2-over-BLE non-functional on Linux. Other backends may tolerate the Read by returning stale cached data, which is not real notification-driven framing either way. Connection::new now subscribes to fidoStatus, obtains the peripheral's notification stream, filters it to the fidoStatus UUID, and stores it on the connection. frame_recv awaits the next notification with the caller-supplied operation timeout; on expiry it sends a BleCommand::Cancel on fidoControlPoint (best-effort, WithoutResponse) and returns Timeout. The channel's apdu_recv and cbor_recv now forward their timeout to frame_recv and map Error::Timeout to TransportError::Timeout.
Per CTAP 2.2 §11.4, BLE FIDO authenticator traffic MUST run on a bonded LE Secure Connections link. The previous connect path issued FIDO operations without verifying bonding state, so a session that fell back to an unauthenticated link would proceed in violation of the spec. Adds a pairing module that, on Linux, queries org.bluez.Device1.Paired and org.bluez.Device1.Bonded over DBus and refuses to proceed if either is false. The DBus call is dispatched on spawn_blocking so it doesn't stall the tokio runtime. On non-bluez backends or when DBus is unreachable the check falls back gracefully: macOS and Windows enforce bonding at the OS level for authenticated GATT characteristics, so deferring there is acceptable. The library itself cannot trigger pairing; the user is expected to pair the device beforehand (e.g. via bluetoothctl). manager::connect calls enforce_bonded after establishing the link and before discovering services.
a1ef9d4 to
d8142f1
Compare
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.
Three FIDO-BLE protocol-level fixes, one per commit.
fidoStatusadvertises only the Notify property, so a spec-conforming peripheral rejectsRead Valuerequests withNot Permitted. The library was reading instead of consuming notifications, which made FIDO2-over-BLE non-functional against spec-conformant peripherals on bluez.Connection::newnow subscribes tofidoStatus, filters the peripheral notification stream to that UUID, andframe_recvawaits the next notification with the caller-supplied operation timeout. On timeout it emits a best-effortBleCommand::CancelonfidoControlPointand returnsTransportError::Timeout.fidoControlPointandfidoServiceRevisionBitfieldare Write characteristics; usingWrite-Without-Responsemasked ATT-level errors (e.g. encryption-required) and was rejected outright by some authenticators. A newwrite_type_for()helper inspects the characteristic's declared GATT properties and only picksWithoutResponsewhen that is the sole property advertised. The U2F predecessor listsu2fStatusas notify-only andu2fControlPointas Write in FIDO U2F BT v1.2 §6.1.org.bluez.Device1.{Paired,Bonded}properties on connect via DBus, dispatched onspawn_blockingso it doesn't stall the runtime; non-bonded devices are refused withConnectionFailed. On non-bluez backends or when DBus is unreachable, the check falls through and defers to the OS pairing UI (mandatory for authenticated GATT characteristics on macOS / Windows). The library itself cannot trigger pairing; users are expected to pair via the OS (e.g.bluetoothctl pair <ADDR>).Test plan
Automated coverage is limited because BLE tests require hardware; this PR adds:
write_type_forcovering each GATT property combination.cargo buildandcargo test --libpass (139 tests).cargo fmt --checkandcargo clippy --lib --all-features -- -D warningsclean.Manual test plan (requires a paired BLE FIDO authenticator):
examples/webauthn_or_u2f, confirmMakeCredential+GetAssertionsucceed.bluetoothctl remove <ADDR>then re-discover without pairing); confirm the library refuses to proceed with a clear error.frame_recvreturns after the per-op timeout and aCancelpacket is emitted (visible viabtmon).Unknownand let GATT proceed.