nrf5340 zigbee network steering join failed

Product is a zigbee router.

Use nrf connect sdk 2.4, update it is not an option.

The zigbee join work fine most of zb3.0 coordinator, BUT with an old coordinator it failed:

15.4 association is ok

product request TC key

Coordinator response with "ZigBeeAlliance09" tc key

product signal network steering failed and leave network

How to configure stack to accept this tc key as a valid key ?

Regards,

Sébastien

Parents
  • Hi,

    If I enable legacy device support, then the tc link key exchange is not done and so the TC reject me !

    My device announce he has a revision stack that is zb3.0 stack so the TC wait for a TC link exchange and au key confirm

    I have not found an option to force my device to accept this tc link key.

    another way can be to enable legacy mode and as soon as I am in the network manage by myself TC link key request and confirm exchange, is it a good way ?

    regards,

    sébastien

  • Hi,

    First test (capture :2025_10_21_capture_entry_network_failed_legacy_with_require_tclink_missing_key_confirm.pcapng , use key 5a6967426565416c6c69616e63653039)

    code:

    zb_set_network_router_role_legacy(CONFIG_ZIGBEE_CHANNEL_MASK);
    zb_aib_tcpol_set_update_trust_center_link_keys_required(true);

    error output :

    <err> zdo_com_classic_prod: zdo_classic_handle_comm_signal, ZB_COMM_SIGNAL_TCLK_UPDATE_FAILED

    2025_10_21_capture_entry_network_failed_legacy_with_require_tclink_missing_key_confirm.pcapng

  • Second test, use same key for capture 2025_10_21_entry_zb3_failed_due_to_tclink_key.pcapng

    code:

    zb_set_network_router_role(CONFIG_ZIGBEE_CHANNEL_MASK);

    2025_10_21_entry_zb3_failed_due_to_tclink_key.pcapng

  • My understanding:

    As our product announce with as rev22 of the stack (in node descriptor), I assume TC wait for a valid TCLink Key and Key confirm exchange.

    In first case the tc link key is present (with failure) but not the key confirm, so the TC request we leave the network

    In second case TC link exchange is present but it seems that our product refuse this key and decide to leave the network.

    I can not change the behavior of the TC, how can I adapt my product code to do waht the TC want ?

    Regards,

    Sébastien

  • (updated.)

    Hi,

    As the team can see in the ZBOSS sources, the joining device is rejecting the ZC key because it's the same one as the provisional.

    Log: received link key identical to provisional link key - drop packet and fail tclk exchange

    There is no way to skip this check in the configuration of the ZR. We guess it's something specific to your vendor ZC. 

    However, it seems there is nothing to do with that ZC, and simply newer devices are not compatible due to security reasons

    According to the Zigbee specification, when a device sends a request key command for an application link key, the Trust Center is expected to generate and send a new, random key in the transport key response. 

    Sending a transport key message with the same key as the previously provisioned key is not compliant with Zigbee’s key establishment procedure for link keys.

    • For application link keys: after a request key, the Trust Center generates a fresh, randomly created key and distributes it securely to both devices.
    • For network keys: the Trust Center may send the same network key multiple times (such as during rejoining), but for link keys requested after association, a new key must be created for the application security relationship.

    Thus, it is not valid per the specification for the Trust Center to respond to a request key for a link key with a transport key message carrying the same previously provisioned key. The goal is to establish fresh unique keys for security.

     

    Legacy devices

    For legacy Trust Center devices (pre-Zigbee 3.0), it was generally allowed—and sometimes common practice—to reuse or resend the same trust center link key or network key when responding to a key request.

    This was due to limited device resources and simpler security requirements in older implementations.

    • The legacy Zigbee specifications did not strictly forbid reusing keys in all scenarios, especially for network keys.
    • Modern security best practices, even for legacy stacks, recommend generating and distributing fresh keys whenever possible, particularly for application link keys.

    However, legacy devices often permitted key reuse for practicality and compatibility reasons.

    In summary, while legacy Trust Centers often reused the same key after a request, this practice is discouraged and improved upon in Zigbee 3.0 and later standards, which mandate unique new keys for each key establishment event.

    So, it is non-compliant in the Zigbee 3.0 specification to send the same key after a request key command, but legacy Trust Centers often allowed it for practical reasons in earlier Zigbee versions.

    The evolution of the security model strongly favors fresh keys for every link key exchange to prevent key compromise and replay attacks.

    -Amanda H.

Reply
  • (updated.)

    Hi,

    As the team can see in the ZBOSS sources, the joining device is rejecting the ZC key because it's the same one as the provisional.

    Log: received link key identical to provisional link key - drop packet and fail tclk exchange

    There is no way to skip this check in the configuration of the ZR. We guess it's something specific to your vendor ZC. 

    However, it seems there is nothing to do with that ZC, and simply newer devices are not compatible due to security reasons

    According to the Zigbee specification, when a device sends a request key command for an application link key, the Trust Center is expected to generate and send a new, random key in the transport key response. 

    Sending a transport key message with the same key as the previously provisioned key is not compliant with Zigbee’s key establishment procedure for link keys.

    • For application link keys: after a request key, the Trust Center generates a fresh, randomly created key and distributes it securely to both devices.
    • For network keys: the Trust Center may send the same network key multiple times (such as during rejoining), but for link keys requested after association, a new key must be created for the application security relationship.

    Thus, it is not valid per the specification for the Trust Center to respond to a request key for a link key with a transport key message carrying the same previously provisioned key. The goal is to establish fresh unique keys for security.

     

    Legacy devices

    For legacy Trust Center devices (pre-Zigbee 3.0), it was generally allowed—and sometimes common practice—to reuse or resend the same trust center link key or network key when responding to a key request.

    This was due to limited device resources and simpler security requirements in older implementations.

    • The legacy Zigbee specifications did not strictly forbid reusing keys in all scenarios, especially for network keys.
    • Modern security best practices, even for legacy stacks, recommend generating and distributing fresh keys whenever possible, particularly for application link keys.

    However, legacy devices often permitted key reuse for practicality and compatibility reasons.

    In summary, while legacy Trust Centers often reused the same key after a request, this practice is discouraged and improved upon in Zigbee 3.0 and later standards, which mandate unique new keys for each key establishment event.

    So, it is non-compliant in the Zigbee 3.0 specification to send the same key after a request key command, but legacy Trust Centers often allowed it for practical reasons in earlier Zigbee versions.

    The evolution of the security model strongly favors fresh keys for every link key exchange to prevent key compromise and replay attacks.

    -Amanda H.

Children
  • I agree with this analysis.

    As it stands, I can't use the stack in zb3.0 mode due to the poor behavior of the TC, nor in legacy mode due to the same poor behavior.

    My question was whether I could (fully accepting the security risks) force the stack to accept the tclk. From what I understand, it's not possible to ignore this check.

    The solution I envision, but which seems far too risky, would be to use an older, more permissive stack.

    Thank you for your response.

    Sébastien

Related