|
1 | | -### Secure temp sensor |
| 1 | +# Secure temp sensor |
2 | 2 |
|
3 | | -This example uses BLE to communicate temperature between a pair of pico Ws. This example is a variant of temp sensor, using LE secure to provide a secure connection. |
| 3 | +This example uses BLE to communicate temperature between a pair of Pico Ws. It is a variant of |
| 4 | +the temp sensor example, using LE Secure Connections to provide a secure connection. |
4 | 5 |
|
5 | | -secure_temp_server is a peripheral or server that transmits its temperature to another device |
6 | | -secure_temp_client is a client that reads a temperature from another device |
| 6 | +`secure_temp_server` is a peripheral/server that transmits its temperature to another device. |
| 7 | +`secure_temp_client` is a central/client that reads temperature from another device. |
7 | 8 |
|
8 | | -In server.c and client.c there is a define SECURITY_SETTING which you can change to explore different security options: |
| 9 | +## Security settings |
9 | 10 |
|
10 | | -security setting 0: Just works (pairing), no MITM (Man In The Middle) protection |
11 | | - client and server have no input or output support |
| 11 | +In `server.c` and `client.c` there is a `SECURITY_SETTING` define which you can change to explore |
| 12 | +different BLE security options. Both ends must be built with the same setting unless you are |
| 13 | +deliberately testing an asymmetric combination (see the table below). |
12 | 14 |
|
13 | | -security setting 1: Numeric comparison with MITM protection |
14 | | - client can query yes or no from the user, server has a display only |
15 | | - server displays passkey |
16 | | - client displays passkey and user can select Yes or No if they agree the passkey is from the server |
| 15 | +The settings map to Bluetooth IO capabilities as follows: |
17 | 16 |
|
18 | | -security setting 2: |
19 | | - client has a keyboard and display, server has a display only |
20 | | - server displays passkey |
21 | | - client user enters the passkey displayed by the server |
| 17 | +| Setting | IO capability | Description | |
| 18 | +|---------|--------------|-------------| |
| 19 | +| 0 | `NO_INPUT_NO_OUTPUT` | Just Works - no MITM protection | |
| 20 | +| 1 | `DISPLAY_YES_NO` | Numeric Comparison - MITM protection | |
| 21 | +| 2 | `KEYBOARD_DISPLAY` | Passkey Entry - MITM protection | |
| 22 | +| 3 | `DISPLAY_ONLY` | Display Only - MITM protection | |
22 | 23 |
|
23 | | -security setting 3: |
24 | | - client has a display only, server has a display and keyboard |
25 | | - Client displays passkey |
26 | | - server user enters the passkey displayed by the server |
| 24 | +The actual pairing method used depends on the IO capabilities of *both* devices, not just one. |
| 25 | +The Bluetooth SIG defines a matrix of initiator × responder capabilities that determines the |
| 26 | +method. Setting `SM_AUTHREQ_MITM_PROTECTION` requests MITM protection but does not guarantee it — |
| 27 | +if the negotiated method cannot provide it, pairing will fail. |
27 | 28 |
|
28 | | -You will need to use the console with both devices to see the passkeys and answer security prompts. Both stdio over UART and USB are enabled so you can use either. |
| 29 | +### Working combinations |
| 30 | + |
| 31 | +| Client setting | Server setting | Pairing method | MITM? | |
| 32 | +|---------------|---------------|----------------|-------| |
| 33 | +| 0 | 0 | Just Works | No | |
| 34 | +| 1 | 1 | Numeric Comparison | Yes | |
| 35 | +| 2 | 2 | Passkey Entry | Yes | |
| 36 | +| 2 | 3 | Passkey Display (server displays, client types) | Yes | |
| 37 | +| 3 | 2 | Passkey Display (client displays, server types) | Yes | |
| 38 | +| 3 | 3 | Fails (both display only, nobody can type) | — | |
| 39 | +| 0 | >0 | Fails (MITM required but not achievable) | — | |
| 40 | + |
| 41 | +Settings 0, 1 and 2 work symmetrically with the same setting on both ends. Setting 3 is |
| 42 | +`DISPLAY_ONLY` so it can only achieve MITM protection when paired with setting 2 on the other end. |
| 43 | + |
| 44 | +You will need a console on each device to see passkeys and answer prompts. Both stdio over UART |
| 45 | +and USB are enabled so you can use either. |
| 46 | + |
| 47 | +## Support scripts |
| 48 | + |
| 49 | +Python scripts are provided to make it easier to test with just one Pico W. |
| 50 | + |
| 51 | +> **Note:** Run these scripts on a native Linux host or a Raspberry Pi. WSL2 with a |
| 52 | +> usbip-attached Bluetooth adapter can connect and perform GATT discovery, but pairing |
| 53 | +> fails during the LE Secure Connections exchange (the DHKey check fails with |
| 54 | +> authentication failure / reason 12). This is a limitation of the WSL2 + usbip + BlueZ |
| 55 | +> path, not the example code. |
| 56 | +
|
| 57 | +### Client (`ble_temp_client.py`) |
| 58 | + |
| 59 | +Acts as a BLE central, connecting to a Pico W running `secure_temp_server`. |
| 60 | + |
| 61 | +``` |
| 62 | +pip install bleak |
| 63 | +python3 ble_temp_client.py [--security <0-3>] |
| 64 | +``` |
| 65 | + |
| 66 | +- Works with BlueZ running normally — no special setup required. |
| 67 | +- If connection fails with a disconnect during service discovery, clear stale bonding info: |
| 68 | + ``` |
| 69 | + bluetoothctl remove <addr> |
| 70 | + ``` |
| 71 | + The Pico clears its own bond automatically on key mismatch, but BlueZ needs to be told manually. |
| 72 | + |
| 73 | +### Server (`ble_temp_server.py`) |
| 74 | + |
| 75 | +Acts as a BLE peripheral, advertising a simulated temperature for a Pico W running |
| 76 | +`secure_temp_client` to connect to. |
| 77 | + |
| 78 | +Uses [Bumble](https://github.com/google/bumble) which talks directly over HCI, bypassing BlueZ. |
| 79 | + |
| 80 | +``` |
| 81 | +pip install bumble |
| 82 | +``` |
| 83 | + |
| 84 | +#### Using a USB Bluetooth dongle (recommended) |
| 85 | + |
| 86 | +The easiest option — the dongle is claimed by Bumble leaving the built-in adapter free for BlueZ |
| 87 | +and the client script. Find the transport ID with: |
| 88 | + |
| 89 | +``` |
| 90 | +python3 -m bumble.apps.usb_probe |
| 91 | +``` |
| 92 | + |
| 93 | +Then run: |
| 94 | + |
| 95 | +``` |
| 96 | +./ble_temp_server.py --usb <id> [--security <0-3>] |
| 97 | +``` |
| 98 | + |
| 99 | +#### Using the built-in adapter |
| 100 | + |
| 101 | +BlueZ must be stopped first to release the adapter: |
| 102 | + |
| 103 | +``` |
| 104 | +sudo systemctl stop bluetooth |
| 105 | +sudo systemctl mask bluetooth |
| 106 | +``` |
| 107 | + |
| 108 | +On Raspberry Pi OS, grant `cap_net_admin` to the Python binary so it can open the HCI socket |
| 109 | +without running as root: |
| 110 | + |
| 111 | +``` |
| 112 | +sudo setcap cap_net_admin+eip $(readlink -f venv/bin/python3) |
| 113 | +``` |
| 114 | + |
| 115 | +Then run: |
| 116 | + |
| 117 | +``` |
| 118 | +./ble_temp_server.py --builtin [--security <0-3>] |
| 119 | +``` |
| 120 | + |
| 121 | +When done, restore BlueZ: |
| 122 | + |
| 123 | +``` |
| 124 | +sudo systemctl unmask bluetooth |
| 125 | +sudo systemctl start bluetooth |
| 126 | +``` |
| 127 | + |
| 128 | +### Security mode prompts |
| 129 | + |
| 130 | +For settings 1-3 the scripts will prompt for interaction during pairing: |
| 131 | + |
| 132 | +- **Setting 1 (Numeric Comparison)**: The Pico displays a number; confirm it matches when prompted. |
| 133 | +- **Setting 2 (Passkey Entry)**: The server displays a passkey; type it into the Pico console. |
| 134 | +- **Setting 3 (Display Only)**: The Pico displays a passkey; type it when the script prompts. |
| 135 | + |
| 136 | +For asymmetric combinations (client=2, server=3 or client=3, server=2) the above still applies — |
| 137 | +one side displays and the other types, determined by who has `KEYBOARD_DISPLAY` capability. |
0 commit comments