Bluetooth Mesh: Key Refresh Procedure

 

Bluetooth Mesh: Key Refresh Procedure
How BLE Mesh networks rotate security keys without going offline
3
Phases
128-bit
Device UUID
NetKey + AppKey
Keys Rotated

Why Do We Need Key Refresh?

Imagine you have a smart home with 20 lights, locks, and sensors all talking over Bluetooth Mesh. One day, you remove a device — maybe a bulb you sold or a sensor that got stolen. That removed device still knows the encryption keys your network uses. If someone gets their hands on it, they could spy on your mesh traffic or even control your devices.

This is called the “trash-can attack” — someone fishes a discarded device out of the trash and uses its stored keys to attack your live network.

The Key Refresh Procedure solves this by rotating all network keys across the entire mesh, so the old device’s keys become useless.

Key Terms

NetKey AppKey Device UUID Key Refresh Flag Configuration Client Secure Network Beacon Blacklisting Phase 1 / Phase 2 / Phase 3 Low Power Node IV Update

📌 What is a Device UUID?

In Bluetooth Classic, every device has a unique hardware address called BD_ADDR. In Bluetooth Mesh, that’s not required. Instead, every node gets a 128-bit number called a Device UUID.

During the Key Refresh procedure, the Configuration Client uses the device key (established during provisioning) to securely send new keys to each specific node — this is why every node’s UUID must be unique.

Node Device UUID (128-bit) Device Key (from provisioning)
Light Bulb A 550e8400-e29b-41d4-… DevKey_A
Door Lock B 6ba7b810-9dad-11d1-… DevKey_B
Sensor C (removed) 6ba7b811-9dad-11d1-… ⚠ Blacklisted

Each node has a unique UUID; blacklisted nodes won’t receive new keys

🔄 The 3-Phase Key Refresh Procedure

The whole process happens in three clean phases. The network never goes fully offline — devices keep communicating throughout. Here’s the big picture:

Normal
Operation
Phase 1
Key Distribution
Phase 2
Use New Keys
Phase 3
Revoke Old Keys
Normal
Operation
TX Key: Key A1 Key A1 Key A2 Key A2 Key A2
RX Key: Key A1 A1 + A2 A1 + A2 Key A2 Key A2

A1 = old key  |  A2 = new key  |  Purple = dual-key receive window

Notice that during Phases 1 and 2, nodes accept both old and new keys for receiving. This is the transition window that keeps the network alive while all nodes slowly update.

Phase 1 — Key Distribution

The Configuration Client (think of it as the mesh network manager — typically a phone or gateway running BlueZ mesh tools) starts Phase 1. It decides which nodes will get the new keys and which ones will be blacklisted.

It sends two types of config messages to each non-blacklisted node:

  • Config NetKey Update — delivers the new network key
  • Config AppKey Update — delivers new application key(s) bound to the NetKey

Config Client Node (e.g. Light Bulb)
Sends Config NetKey Update
{Device Key encrypted}
Stores New NetKey (Key A2)
Still TXing with Key A1
Sends Config AppKey Update
{Device Key encrypted}
Stores New AppKey
RX accepts A1 and A2
Confirms all nodes updated? ✓ Phase 1 Complete → move to Phase 2

Low Power Nodes (LPN) caution: LPNs sleep most of the time and only wake up to poll their Friend node. The Config Client must check the PollTimeout timer and retry key delivery accordingly — LPNs can take much longer to receive the new keys.

💻 BlueZ: Checking Key Refresh Phase

Using BlueZ’s mesh tools, you can interact with the Configuration Client model via D-Bus. Here’s how to inspect and trigger key operations:

# Start BlueZ mesh daemon (ensure bluetooth.service is running)
sudo systemctl start bluetooth

# Launch interactive mesh-cfgclient tool
sudo mesh-cfgclient

# Inside mesh-cfgclient shell:
# List known nodes and their addresses
list-nodes

# Get the current key refresh phase for a node at address 0x0005
get-composition 0005

# Send a NetKey Update to node 0x0005 (Phase 1 trigger)
# net-update <node-addr> <net-index>
net-update 0005 0000

# Send AppKey Update bound to NetKey index 0x0000
# app-update <node-addr> <net-index> <app-index>
app-update 0005 0000 0000

# Once all nodes are updated, push Phase 2 beacon
# key-refresh-phase <node-addr> <net-index> <transition>
# transition=2 moves to Phase 2
key-refresh-phase 0005 0000 2

# transition=3 triggers Phase 3 (revoke old keys)
key-refresh-phase 0005 0000 3

Note: The exact CLI commands depend on your BlueZ version. The underlying D-Bus interface is org.bluez.mesh.Management1. For scripted automation, use the Python bluetooth-mesh library which wraps these D-Bus calls.

// Python bluetooth-mesh library example (Phase 1 via D-Bus)
// Install: pip3 install bluetooth-mesh

import asyncio
from bluetooth_mesh.application import Application
from bluetooth_mesh.messages.config import ConfigNetKeyUpdateMessage

async def send_netkey_update(app, node_addr, net_index, new_key_bytes):
    # Build the Config NetKey Update message
    msg = ConfigNetKeyUpdateMessage.build(dict(
        net_key_index=net_index,
        net_key=new_key_bytes
    ))
    # Send using device key of target node
    await app.send_dev(
        destination=node_addr,
        app_index=0,
        data=msg
    )
    print(f"NetKey Update sent to node 0x{node_addr:04X}")

asyncio.run(send_netkey_update(app, 0x0005, 0x0000, new_key))

Phase 2 — Switch to New Keys

Once every non-blacklisted node has the new keys stored, the Config Client kicks off Phase 2. It does this in one of two ways:

Method How It Works
Secure Network Beacon Config Client broadcasts a beacon secured with the new NetKey with Key Refresh Flag = 1. All nodes that receive this switch to Phase 2.
Config Key Refresh Phase Set (transition=0x02) Config Client sends this unicast message directly to specific nodes to explicitly move them to Phase 2.

In Phase 2, each node:

  • Transmits packets using new keys only
  • Receives packets using both old and new keys (so no one gets locked out mid-transition)
  • Only processes Secure Network Beacons secured with the new NetKey

Direction Key Used in Phase 2
📤 Transmit (TX) Key A2 (new only)
📥 Receive (RX) Key A1 + Key A2 (both)

Phase 3 — Revoke Old Keys

This is the final step. The Config Client sends another Secure Network Beacon (or a Config Key Refresh Phase Set with transition=3) signalling all nodes to drop the old keys entirely.

After Phase 3:

  • All nodes transmit and receive using only Key A2
  • The blacklisted nodes still only have Key A1 — they are now completely cut off
  • The mesh is back to normal operation, just with fresh keys

Before Key Refresh
All nodes know Key A1
⚠ Removed node also has Key A1
After Key Refresh
All active nodes know Key A2
✓ Removed node locked out (still has A1 only)

# Inside mesh-cfgclient: trigger Phase 3 (revoke old keys)
# This sends Config Key Refresh Phase Set with transition=3
# which tells each node to permanently drop Key A1

key-refresh-phase 0005 0000 3

# Alternatively, the Secure Network beacon with Key Refresh Flag=0
# transmitted using the NEW key automatically triggers Phase 3
# on any node that receives it while still in Phase 1

# Verify the current key refresh state of a node
get-key-refresh-phase 0005 0000
# Expected output: Phase 0 (normal operation with new key)

📊 Phase State Machine Summary

Here is how the four states (Phase 0 through Phase 3) connect to each other and what triggers each transition:

From State To State Trigger / Message
Phase 0 (Normal) Phase 1 Config NetKey Update message (Device Key encrypted)
Phase 1 Phase 2 Secure Network Beacon with Key Refresh Flag=1 (new NetKey) OR Config Key Refresh Phase Set transition=2
Phase 1 Phase 3 Secure Network Beacon with Key Refresh Flag=0 (new NetKey) — skips Phase 2
Phase 2 Phase 3 Config Key Refresh Phase Set transition=3 OR Secure Network Beacon with Key Refresh Flag=0 (new NetKey)
Phase 3 Phase 0 (Normal) Old keys revoked — back to single key operation with Key A2

⚠️ Rules & Gotchas

The spec has strict rules about when update messages are valid. Violating these causes errors:

Message Valid When Generates Error When
Config NetKey Update Phase 0 (new key value) OR Phase 1 (same key value) Phase 2 or Phase 3
Config AppKey Update Phase 1 only (same AppKey value on valid index) Normal operation, Phase 2, Phase 3, or Phase 1 with different AppKey value
Key Refresh vs IV Update Both can run simultaneously — completely independent Neither affects the other

Also: if a node is in Phase 1 and receives a Secure Network Beacon with Key Refresh Flag=0 using the new NetKey, it jumps straight to Phase 3 — skipping Phase 2 entirely. This is an optimisation for smaller networks.

Explore More on EmbeddedPathashala

Continue learning Bluetooth Mesh, BLE Stack internals, and Linux Kernel programming

Bluetooth Series Linux Kernel Course

Leave a Reply

Your email address will not be published. Required fields are marked *