Repository navigation
Conversation
- With a Computer stored and no pairing window open, the panel advertises to the Computer only, so a nearby device can't connect and start the repeat pairing that makes the library delete the Computer's bond. A window opens it to anyone; the tick puts the filter back within a second of the window lapsing or being canceled. - Pairing keys are saved only while a passkey is showing, i.e. for a pairing from a window. A Just Works pairing that claims the Computer's identity address can no longer overwrite its keys, and strangers' bonds no longer fill the store. Assisted-by: Claude Code:claude-opus-5-5
- Turn on the controller's address resolution. NimBLE loads bonded peers' IRKs into the resolving list but enables resolution only when the panel itself uses a private address, so a Mac reconnecting from a new private address had no key and wouldn't pass the allow list. - With a real IRK, put the Computer in network privacy mode: only private addresses made from its IRK get through the allow list, not its copyable identity address. - A rejected stranger that claimed the Computer's address no longer deletes the Computer's bond at disconnect (AppSec finding). - Log when the allow list can't be set. Assisted-by: Claude Code:claude-opus-5-5
…es (#144) - AppSec: a Computer that sends an IRK but connects from its public address (BlueZ by default) would be locked out in network mode. The panel now records, in its NVS, that the Computer connected from a resolvable private address, and only then switches it to network mode. - After a host resync, resolution and the privacy mode are applied again. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
…#144) - NimBLE already turns address resolution on at every sync (ble_hs_pvcy_set_our_irk from ble_hs_startup_go); the extra calls could only fail Bluetooth's start over nothing. - After a resync, advertise when no Computer is here or a window is open, not only if it was advertising before: the reset ends it. - advertise() runs under a lock: openPairing() calls it on the net task. Assisted-by: Claude Code:claude-opus-5-5
This was referenced Oct 26, 2026
Open
Open
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.
Closes #144.
Changes
Allow list. With a Computer stored and no pairing window open, advertising only accepts connections from the Computer (
ble_gap_wl_setwith its identity address, plussetScanFilter(false, true)). That stops a nearby device from connecting and starting the repeat pairing that makes the library delete the Computer's bond.A Computer that turns its privacy off after being seen on private addresses is refused in network mode until it pairs again in a window.
A host that pairs from a private address but reconnects from its public one would be refused until it pairs again (network mode is set at pairing). Macs always use private addresses.
If the allow list can't be set, the panel advertises to anyone, so a failure can never lock the Computer out.
Key-save gate.
ble_hs_cfg.store_write_cbis wrapped, andOUR_SEC/PEER_SECwrites are refused unless a passkey is showing, which only happens in a window. So a Just Works pairing claiming the Computer's identity address can't overwrite its keys, and strangers' bonds don't fill the store. That also fixes the "full store refuses the real Computer's keys" note from the firmware: Bluetooth keyboard hardening after #140 (#141) #143 re-review. Deletes are not vetoed, because the library'sRETRYwould spin the host task.Private-address resolution: correction. An earlier version of this PR said main never turns the controller's address resolution on, and that a Mac couldn't reconnect. That was wrong. NimBLE turns it on at every sync (
ble_hs_startup_go→ble_hs_pvcy_set_our_irk) and restores bonded IRKs to the resolving list, so the allow list matches a Mac's resolved identity. The redundant calls have been removed.Network privacy mode, for a Computer seen on private addresses. NimBLE puts every resolving-list peer in device mode, which also lets a peer's identity address through when it's sent in the clear. Once the Computer has connected from a resolvable private address (recorded in the panel NVS as
ble/private), and it sent a real IRK, it's switched to network mode, so only addresses made from its secret IRK pass. A Computer that sends an IRK but connects from its public address (BlueZ by default) stays in device mode; network mode would lock it out (AppSec). A host resync puts peers back in device mode and ends advertising, so the tick re-applies the mode and advertises again.The disconnect delete re-checks (AppSec): a rejected stranger that claimed the Computer's address no longer deletes the Computer's bond, because
isComputer()is checked when the disconnect lands.Known limits
Tests:
pio test -e nativepasses 73/73, addingtest_only_the_computer_may_connect_outside_a_window,test_only_a_window_pairing_saves_keys,test_a_resolvable_private_address(fake RPAs) andtest_a_computer_seen_on_private_addresses_is_matched_by_them_only.pio run -e crowpanelbuilds. RPA resolution happens in the controller, so no native test can exercise it; that's for hardware.Hardware, black2 only, through the panel-owner rule:
btmgmt privacy, if main OKs it), black2 reconnects from a new private address with the filter on, which stands in for the Mac.Before merging: merge main with #157 in. #157's
persistBond()rewrites the Computer's keys afterg_pairinghas been cleared, so this PR's key-save gate would refuse them, after the deletes have run, leaving the new Computer keyless. The gate needs a host-task flag aroundpersistBond(). Then rerun the private-address reconnect test on top.No auto-merge until the firmware and AppSec reviews pass and these hardware checks are done.