Wiki / Protocols

Touchlink (Zigbee Light Link)

Proximity commissioning for Zigbee lighting: hands the network key over the air, wrapped in a key the specification publishes.

A touchlink commissioning exchange
CAN_H CAN_L 120Ω 120Ω

Touchlink is the proximity commissioning procedure of Zigbee Light Link (ZLL), later folded into Zigbee 3.0. You hold a controller close to a bulb, it joins. The convenience comes from a design decision that is also the attack: the network key is handed over the air, wrapped only in a key whose value is fixed for the whole ecosystem.

What it is

Touchlink frames are inter-PAN: they carry no network layer state, are addressed with 64-bit IEEE addresses and a PAN identifier of 0xFFFF, and are not encrypted at all. They ride profile 0xC05E on cluster 0x1000, the ZLL Commissioning cluster. The proximity is enforced by nothing but transmit power, which is why the attack is usually described as "touchlink from across the street with a better antenna".

A commissioning burst is short:

Command ID Direction Carries
Scan Request 0x00 initiator to all inter-PAN transaction identifier
Scan Response 0x01 device to initiator response identifier, key bitmask, current PAN
Identify Request 0x06 initiator to device how long to blink
Network Start Request 0x10 initiator to device key index, encrypted network key
Network Join Router Request 0x12 initiator to device key index, encrypted network key
Reset to Factory New 0x07 initiator to device nothing, and that is the point

The key transport

The network key is wrapped twice, and neither wrap involves a secret the device chose. Both stages are plain AES-128 in ECB. The wrapping key is derived from two 32-bit identifiers expanded into a single 16-octet block, and the ZLL key selected by the frame's key index field; the network key is then wrapped under that derived key. The exact expansion order and the direction of each stage are spelled out in the ZLL specification, section 8.7.5.2.3, and implemented in the Z3sec research toolkit.

The two identifiers are the interesting part. The inter-PAN transaction identifier is in the frame that carries the key. The response identifier is not: it is in the Scan Response of the device the request was addressed to, which is why a capture of the key transport alone is not enough.

Key index ZLL key used Status
0 development key, built from the two identifiers and two fixed four-letter strings no secret at all
4 ZLL master key leaked in 2015, still in use
15 ZLL certification key published in the specification

A device left in certification mode therefore transports its network key under a key anyone can look up, and the whole mesh follows.

Why it matters

Two separate problems sit here. The first is the key transport above: a passive listener who catches one commissioning burst holds the network key for good. The second is that touchlink commands need no authentication at all, so Reset to Factory New (0x07) is an unauthenticated remote wipe of any bulb in range, and Network Join Router Request lets an attacker move a device onto a network of their own. Ronen and Shamir's ZLL work, and the "IoT goes nuclear" bulb worm, both start here.

How to assess it

# every touchlink frame in a capture
tshark -r capture.pcap -Y 'zbee_zcl_general.touchlink'

# the fields the unwrap needs
tshark -r capture.pcap -Y 'zbee_zcl_general.touchlink' \
       -T fields -e zbee_zcl_general.touchlink.transaction_id \
                 -e zbee_zcl_general.touchlink.key_index

Wireshark dissects the exchange completely, names the key index, and prints the encrypted network key. It stops there: no standard tool implements the unwrap, so you write it, with a handful of lines around an ECB cipher. Z3sec is the reference research implementation.

Pitfalls

  • Pair on the transaction identifier AND the target. Several devices answer the same scan, each with a different response identifier, and only the one addressed by the key transport gives the right key.
  • The identifiers are big endian inside the wrap, and little endian on the wire. Getting this backwards yields a plausible-looking 16-octet key that decrypts nothing.
  • Verify, do not assume: the right network key makes the CCM* message integrity codes of the following frames verify. If none verify, your pairing or your endianness is wrong.
  • Touchlink lives on the ZLL profile 0xC05E. The same cluster number under another profile is a different cluster.

Further reading