![]() |
Developing with ZBOSS for Zigbee
|
There are following big features in ZBOSS r23 codebase:
There are also number of minor refactorings and improvements.
Zigbee r23 specification is officially released, Zigbee Platform certification program is started. ZBOSS is officially a r23 Golden Unit and r23 Zigbee Certified Platform. For now (06/2023) Zigbee Platform can be certified as r23, but BDB 3.1, which must describe usage of new r23 features, is not ready yet.
So it is only possible to certify Zigbee Product using BDB 3.0.1. It is confirmed by CSA officials that is is legal to use a certified r23 ZCP to certify a Zigbee Product. Zigbee stack must not use r23 features during Product certification.
So certified r23 ZBOSS CAN be used to develop a certified BDB 3.0.1 (Zigbee 3.0) Product.
r23 features which exist in the stack core is an uncertifieable behavior from the BDB 3.0.1 point of view.
Storing initial join & key update methods in TCLK keypair. Ability to get initial join & key update methods - locally and via ZDO command.
ZBOSS now implements SE-like (with TCLK hash) TC swapout.
r23 specification does not define exactly which new r23 features are indeed included into "All Hubs iunitiative". Suppose that are all features got from WWAH specification:
Following (already listed) settings close the holes in r22 security.
If device is in Restricted mode, some ZDO commands can be accepted only if received from TC and encrypted by TCLK.
ZBOSS now set APS ACK req bit in APS commands, except Tunnel with Transport key.
The application need not care about that change
New parameter nwk_broadcast_addr - broadcast address to be used for tx to a group. In r22 APS Group tx was possible only to rx-on-when-idle devices, in r23 broadcast address is configurable.
r23 significantly improved Zigbee Centralized security.
DLK is the significant Zigbee security improvement which closes long-standing security hole in Zigbee known as a "well-known key" AKA "ZigBeeAlliance09" key.
DLK means "Dynamic Link Key" (while DSR has no ideas what is so "dynamic" in it). Indeed DLK means establishing a shared key between device and TC over an insecure radio channel utilizing an elliptic-curve Diffie-Hellman math (curve25519). In contrast to methods used in pervious Zigbee versions that procedure has no risk of obtaining or calculating the key by the attacker which can observe the radio exchange. DLK can be anonymous (in such case man-in-the-middle attack could be theoretically possible while unlikely) or use an installcode or passcode which preventing such kind of attack.
TCLK (Trust Center Link Key) is an unique APS key established between TC (Trust Center) and any every in the network. Starting from Zigbee r21 standard every joined device must establish a TCLK during or after joining. That is true for both Zigbee 3.0 and SE profile (while SE uses its own certificate-based protocol, it still establishes the same unique TCLK). TCLK can be used for securing any APS traffic between the device and TC.
TCLK has critical meaning in Zigbee security because it provides a secure way for a device to do Unsecured AKA Trust center Rejoin after it missed NWK key update.
Before introducing of DLK Zigbee first used a Provisional key to send NWK key to just joined device. Later Joiner updates Provisional key to the unique verified TCLK using either APS commands (in Zigbee 3.0) or CBKE protocol over ZCL (in SE).
Provisioning key was either derived from the Installcode, which is good enough, or the well-known key was used, which is quite weak.
When DLK is used, the produced TCLK is Verified and need not be changed.
DLK requires Joiner and TC to be r23 devices supporting DLK.
Note that DLK is Optional in r23. DSR recommends to always build ZBOSS r23 with DLK support compiled in.
ZBOSS has no an explicit API to start DLK to establish a TCLK first time. That means, DLK starts automatically when it is possible. An application need not care about DLK start.
DLK can be done before or after Joiner authentication. DLK before Joiner authentication is called "off-network DLK". That is the most secure DLK form. In that case TCLK establishment is done without sending NWK key to the Joiner making device Interview possible.
"On-network DLK" is TCLK establishment after NWK key is sent to a Joiner.
If Joiner joins to the intermediate Parent Router, that Parent Router must be r23 device to make "off-network DLK" possible. If Parent Router is pre-r23 device, only "On-network DLK" is possible.
"Off-network DLK" is always possible when Joiner joins directly to TC.
Routers between Parent Router and TC, if exist, just route NWK traffic, so need not be r23 devices.
The new configurable memory setting ZB_CONFIG_ZDO_KEY_NEGOTIATIONS_NUM defines max number of parallel DLK sessions which TC can handle.
Since SE profile still uses r22, DLK is disabled if SE commissioning is in use.
TC can force updating TCLK of some device by calling zb_zdo_secur_update_device_tclk().
To have DLK working, Joined device and TC must support DLK and be agree about supported key negotiation methods and pre-shared secrets. Joiner presents methods and secrets it supports, TC matches them with methods/secrets TC supports and chooses the best combination. DLK then starts automatically at join.
ZBOSS provides an API to configure locally supported key negotiation methods and PSK secrets which then will be exposed to other side.
Key negotiation method is a method/math used to generate TCLK.
There are following key negotiation methods in r23 (zb_tlv_key_negotiation_methods_t) :
KEY_REQUEST_ZB_30 is old pre-r23 method based on APS commands Request Key, Verify Key and Confirm Key.
25519 curve can be used with AESMMO128 or SHA256 hash function. ZBOSS supports both of them. Both hash functions are Optional. DSR recommends to enable both of them for better interoperability.
P256 curve is used in Zigbee Direct only and never used in DLK between Zigbee devices.
By default, when ZBOSS is in r23 mode (which is the default for r23 ZBOSS), it has following negotiations methods enabled: KEY_REQUEST_ZB_30, 25519_HASH_AESMMO128, 25519_HASH_SHA256.
There are no reasons to change default settings for production using, but application may want to update key negotiation settings for debug or testing purposes.
ZBOSS provides following API:
That API must be called before zboss_start()/zboss_start_no_autostart() call.
Supported PSK secrets are (zb_tlv_psk_secrets_t) :
PSK secret (passphrase) can be either generated from pre-configures stuff (installcode/passcode) or set up after authentication (authentication token). PSK secret is stored in APS keypair. PSK secret created from installcode/passcode can be updated while established authentication token can not.
If AUTH_TOKEN secret is enabled, ZBOSS uses the authentication token established after DLK complete using ZDO Get Authentication Token command. Authentication Token is then used for subsequent DLK as a pre-shared secret to prevent man-in-the-middle attacks. It supposed to be more secure than an installcode or a passcode. Note that ZBOSS always establishes Authentication Token after DLK complete. Disabling AUTH_TOKEN secret can be meaningful only for testing or debug purposes. DSR recommends to have it ON in production.
Once authentication token is established, it is stored in APS keypair and used as a passphrase in next DLK procedures if any.
Updating of a passphrase which is the established authentication token is impossible. The only way to forget an authentication token at TC is removing an APS keypair. So, if Joiner clears its key storage by some internal action loosing its Authentication token, further DLK procedures will fail until TC cleared APS keypair for it forgetting the Authentication token.
Installcode and passcode are quite similar secrets to be used for initial key establishment.
Enabling installcodes/passcodes means globally enabling all installcodes. TC additionally checks that it has installcode/passcode for that particular device and supposes installcode/passcode capability if no PSK material for that device found. Joiner checks that it has installcode/passcode configured and does not expose that PSK capability of no appropriate PSK material is set using production configuration block of by in the application.
To add installcode/passcode at Joiner from the application, use zb_secur_ic_set() call. It is possible to add one passcode and one installcode. ZBOSS stores both of them. Note that ZBOSS does not persist it in NVRAM.
To add a passcode at Joiner, pass ZB_IC_TYPE_PASSCODE to zb_secur_ic_set() (ic_types):
In contrast to Installcode, the passcode is short (4 bytes length), does not contain CRC on its tail, used in DLK procedure "as is", without creating a B6 hash.
The passcode can be used for DLK only - means can't be used to create a Provisional key for Zigbee 3.0-like NWK key transport.
That API must be called before zboss_start()/zboss_start_no_autostart() call.
It is not recommended to use that API in production.
After "off-network" DLK, when Joined and TC established TCLK but TC not yet authenticated Joiner by setting NWK key to it, TC can start the procedure called "Device interview".
Device interview is a dialog between Joined and TC via APS. That includes ZDO and ZCL communication. Device interview must be started and finished by TC. By default Device interview is disabled at TC.
TC has API to globally enable/disable Device interview by calling zb_tc_enable_device_interview() and check the current state using zb_tc_is_device_interview_enabled() call.
If Device Interview is enabled, when DLK completed, application on TC receives ZB_ZDO_SIGNAL_DEVICE_READY_FOR_INTERVIEW signal. Signal parameters holds Joiner addresses (short and long). The TC application then can proceed with Device interview procedure by exchanging APS data with Joiner (using ZDO calls or ZCL traffic). TC can keep data exchange during device interview forever. The only requirement is to send packets frequently enough to do not go out of APS Security timeout (10s in r23 by default).
TC completes Device Interview by either authenticating Joiner by calling zb_tc_auth_device_after_interview() or rejecting its authentication by calling zb_tc_reject_device_after_interview().
When Device Interview finished by either explicit call from TC or timeout, TC gets ZB_ZDO_SIGNAL_DEVICE_INTERVIEW_FINISHED signal. Check status in the parameters section of the signal.
Tha call zb_tc_is_interview_active_for_device() can be used to check the state of Device Interview for particular Joiner.
The only special API for Joiner is ZB_ZDO_SIGNAL_DEVICE_INTERVIEW_STARTED signal which it receives when Device Interview starts.
When Device Interview finishes, Joiner receives the usual ZB_BDB_SIGNAL_DEVICE_FIRST_START signal. Means, for Joiner the end of Device Interview is same as authentication complete.
That feature minimizes possibility of reply attack by using of special protocol for APS security counters synchronization. That r23 feature is backward compatible. ZBOSS switches it on automatically. It does not require any updates in applications using ZBOSS.
The initial use case for that feature is using a mixed ZB 3.0 / SE network where SE devices can check the "trust level" of other devices in the net and make some decisions at the application level.
The difference between SE and BDB security in Zigbee before r23 is that SE device joins network strictly using Installcodes and establishes TCLK using CBKE. So SE device must be sure it communicates to the device which established it security in SE way. r23 now provides such functionality.
In r23 TC stores in APS keypair information about 2 facts: using PSK during initial join and TCLK establishment method. r23 defines a ZDO command to ask that information from TC ZDO Security Get Authentication Level Request.
ZBOSS API to get is zb_zdo_get_auth_level_req() call. From the application point of view it works the same way at ZC and any other device. Indeed, at ZC it works locally while at other devices it sends ZDO request and waits for the response.
TC swapout requires from ZC to backup its TCLK database offline. It later can be restored to another device to be acting as a TC. TC DB format is in ZBOSS internal format. It is not documented.
When it is time to backup TCLK DB, ZBOSS sends ZB_TCSWAP_DB_BACKUP_REQUIRED_SIGNAL signal. It is up to TC application to do backup immediately or later.
Switch on/off backup of the established authentication token: zb_tcsw_enable_passkey_backup(). By default such backup is enabled.
Check whether TC DB backup is required: zb_tcsw_need_backup().
Start TC DB backup: zb_tcsw_start_backup_db().
Get TC DB porting into the buffer in RAM: zb_tcsw_get_portion(). TC application then need to take care on saving DB porting to some external storage. To check that TC backup is in progress may call zb_tcsw_is_busy() or check retcode of zb_tcsw_get_portion().
When new TC is started, it must know by some mean that it is restored after TC swapout. The backup method is out of ZBOSS API scope.
Swapped TC must initially start not doing Formation, using zb_zdo_start_no_autostart() call. When it got ZB_ZDO_SIGNAL_SKIP_STARTUP signal, it is time to start TC DB restore.
Start DB restore by calling zb_tcsw_start_restore_db(). Then feed ZBOSS by DB portions using zc_tcsw_restore_portion(). When feeding complete, call zc_tcsw_restore_finish().
After TC DB restore completed, continue ZBOSS start (do Formation) by calling zboss_start_continue().
The only API is ZB_TC_SWAPPED_SIGNAL which ZBOSS sends to inform the application that it successfully completed TC rejoin after ZC has been swapped.
TC rejoin initiation is usually done by BDB or SE ZBOSS commissioning layer, but can be initiated by the application as well. Related signals which are not a part of TC swapout API but might be useful for the application are ZB_BDB_SIGNAL_STEERING, ZB_BDB_SIGNAL_TC_REJOIN_DONE, ZB_TCLK_UPDATED_SIGNAL.
PANID conflict resolution API is simplified in r23 ZBOSS compared to r22 ZBOSS. PANID conflict detection can not now be disabled. zb_enable_panid_conflict_resolution() call is now empty.
Automatic panid conflict resolution is removed from r23, zb_enable_auto_pan_id_conflict_resolution() function is removed from ZBOSS API (note it was not recommended for use even in pervious versions).
In r23 ZBOSS PANID conflict resolution API can be used by ZC only.
Signal ZB_NWK_SIGNAL_PANID_CONFLICT_DETECTED informs the application about panid conflict detection.
If the application decides to start panid conflict resolution, it must schedule for execution zb_start_pan_id_conflict_resolution() passing there a valid buffer as a parameter.
WWAH is a set of extended features initially required to work with Amazon Alexa. The features mainly provides fine-grained security control in hub-centric network: the network having the main application and еру security center - the Hub which is normally at TC.
ZBOSS r22 already has WWAH support accessed via WWAH ZCL cluster ZBOSS has full support for Server role only (which is all devices except the Alexa Hub itself).
WWAH has 2 groups of settings: related to Zigbee Core and to Application layer. Zigbee r23 штсщкзщкфеуы some Core-level WWAH settings, but uses ZDO commands instead of ZCL cluster. Not all WWAH features are included into r23 All Hubs. Some settings are a bit different.
ZBOSS supports both r23 ZDO and WWAH ZCL cluster interfaces at the same time. It is possible to build ZBOSS with r23 All Hubs support but without WWAH while the build with WWAH but without r23 All Hubs is not possible.
Most of common settings are transparrent. That mean, setting set via ZDO is visible via ZCL WWAH cluster and vice versa. Note that WWAH specification is sometimes a bit different from r23 All Hubs. If the application includes and enables WWAH Server cluster, WWAH specification has the priority, else ZBOSS uses r23 specification.
WWAH cluster has a mode called "Configuration mode". r23 specification defines a "Restricted mode". It has the reverse meaning. So Restricted mode == !(Configuration mode). ZBOSS uses both terms. The logic in WWAH and r23 is also a bit different.
In r23 if device is in Restricted mode, some ZDO commands can be accepted only from TC if encrypted by TCLK. Limit accepting of following ZDO commands in the r23 Restricted mode:
WWAH defines the opposite: Configuration mode means all ZDO commands are allowed. WWAH defines the list of ZDO commands which can be accepted from non-TC devices when device is NOT in Configuration mode:
API to enable/disable Restricted mode is zb_zdo_send_configuration_parameters() call. Set or clear zb_zdo_configuration_parameters_t::restricted_mode_enabled bit in zb_zdo_configuration_parameters_t to switch Restricted mode.
That API can be called in centralized network only at TC; in distributed network - at any device.
TC can switch on/off Mgmt Leave accepting by ZR - nwkLeaveRequestAllowed. It can be done using Security_Set_Configuration_req.
API to enable/disable Restricted mode is zb_zdo_send_configuration_parameters() call. Set or clear zb_zdo_configuration_parameters_t::leave_req_allowed bit in zb_zdo_configuration_parameters_t.
WWAH has similar setting, but it disables "MGMT Leave Without Rejoin" only while r23 disables any Leave.
For code example see All Hubs Restricted vs WWAH Configuration mode..
That API can be called in centralized network only at TC; in distributed network - at any device.
That flag indicates whether or not the device will require that the APS Transport Key command SHALL be APS encrypted with the device’s unique Trust Center Link Key. By default that setting is FALSE. The obvious usage of that setting is to disable accepting of the Transport Key sending NWK by broadcast.
API to enable/disable Link Key encrypetion for Transport Key is zb_zdo_send_configuration_parameters() call. Set or clear zb_zdo_configuration_parameters_t::require_link_key_encr_for_tk bit in zb_zdo_configuration_parameters_t.
For code example see All Hubs Restricted vs WWAH Configuration mode..
WWAH has similar setting called TCSecurityOnNwkKeyRotationEnabled. In WWAH that flag also disables reception of broadcast NWK Update command. So, that flag can be set either via WWAH cluster or via r23 ZDO command. If WWAH cluster is enabled in the application, reception of the broadcast NWK Update command is disabled according to WWAH specification. If application does not define WWAH cluster, ZBOSS works according to r23 specification ehere that command reception does not depend on requireLinkKeyEncryptionForApsTransportKey.
ZC can disable pan id and/or channel change by the device. Use zb_zdo_send_configuration_parameters() call setting zb_zdo_configuration_parameters_t::disable_channel_change and/or zb_zdo_configuration_parameters_t::disable_panid_change bits in zb_zdo_configuration_parameters_t.
That call asks sets nwkNextPanId and nwkNextChannelChange ate device to the current values, so device ignores channel/panid change by NWK Update command.
If zb_zdo_configuration_parameters_t::disable_channel_change and/or zb_zdo_configuration_parameters_t::disable_panid_change bits on a call to zb_zdo_send_configuration_parameters() are not set, ZC does not change nwkNextPanId and nwkNextChannelChange at the device. That means, zb_zdo_send_configuration_parameters() call can be used to disable panid/channel change but can't be used to enable pre-r23 change behavior where any channel change vis NWK Update command will be accepted.
For code example see All Hubs Restricted vs WWAH Configuration mode..
To enable pre-r23 behavior call zb_zdo_send_next_panid_change() providing the value of zb_zdo_next_panid_change_parameters_t::next_panid_change 0xffff in zb_zdo_next_panid_change_parameters_t as a parameter.
Similary, to enable pre-r23 behavior call zb_zdo_send_next_channel_change() providing the value of zb_zdo_next_channel_change_parameters_t::next_channel_change 0 in zb_zdo_next_channel_change_parameters_t as a parameter.
ZBOSS provides an API to secure changing of panid/channel. That API works in Centralized security mode only, and can be called by TC only.
Note that normally panid change is required for panid conflict resolution, so it is started internally by ZBOSS. Still, user to change panid API extsts.
The calls sequence is same for both channel and panid change:
Panid change:
First call zb_prepare_network_for_panid_change() providing in zb_zdo_next_panid_change_parameters_t::next_panid_change field of zb_panid_change_parameters_t in parameters section the panid value, and callback to be called when the preparation phase done. When ZBOSS completed the preparation stage, it calls the callback passed to zb_prepare_network_for_panid_change(). The user application calls zb_start_panid_change() to complete the process of panid change.
Channel change:
First call zb_prepare_network_for_channel_change() providing in zb_zdo_next_channel_change_parameters_t::next_channel_change field of zb_zdo_next_channel_change_parameters_t in parameters section the panid value, and callback to be called when the preparation phase done. When ZBOSS completed the preparation stage, it calls the callback passed to zb_prepare_network_for_channel_change(). The user application calls zb_start_channel_change() to complete the process of panid change.
zb_zdo_decommission_req() sends Secur_Decommission_req command. The command informs the device that 3-rd device has left, so it is high time to clear its keys and bindings.
Call zb_zdo_clear_all_bind_req() to clear all bindings on a remote device.
Router Information Global TLV, included into beacon payload in r23, contains 3 bits which defines the priority of potential parent: hub connectivity, preferred parent, uptime (high to low priority).
ZBOSS also supports WWAH-like beacon payload extension where Hub connectivity and Long Uptime bits are set in 2 reserved bits of Zigbee beacon payload.
ZBOSS tracks hub connectivity automatically. It can also be overwritten by the call to zb_set_tc_connectivity(). Local value of hub connectivity can be checked by calling zb_get_tc_connectivity().
Locally preferred parent bit - zb_set_nwk_preferred_parent().
ZBOSS automatically tracks "long uptime" bit setting it 24h after ZR/ZC started. No API to change it.
Call zdo_mgmt_beacon_survey_req() to ask the remote device to do active scan and fill the response according to the procedure defined in r23 2.4.3.3.12 Mgmt_NWK_Beacon_Survey_req and respond by 5 best potential parents.
That is like asking the question "if you join now, which parent will you choose"? DSR has no ideas how that result is to be used.
There are WWAH features/settings not covered by the r23 specification. Some of them are at BDB or ZCL level. That functions are present only if ZBOSS is compiled with WWAH support.
zb_nwk_use_r22_joining() - keep r23 features, but do not use NWK commissioning. That is a debug feature.
zboss_use_r22_behavior() - behave like r22 stack: switch off all r23 features.
zboss_use_r23_behavior() - behave like r23 stack. That is the default setting.
New field zb_apsde_data_req_t.nwk_broadcast_addr - broadcast address to be used for tx to a group. Assign there 0 to use the default ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE.
The signal ZB_TCLK_UPDATED_SIGNAL is sent when local device completed its TCLK update. That normally done at initial join or after rejoin and TC swapout detection.
The signal ZB_SIGNAL_JOIN_DONE is sent when that device is just just joined/rejoined (maybe not authenticated yet).
That API is designed for ZB Direct. All ZBOSS samples still use the original single signal handler.
API:
zb_signal_handler_add_back() zb_signal_handler_add_front() zb_signal_handler_remove()
r23 ZBOSS codebase now uses new API to issue a broadcast packet exposing the key in unencrypted form to be used by Wireshark. That is pure debug feature enabled in debug ZBOSS builds only. Note: broadcasting keys zeroeds you network security, so use it only at debug time and never keep it in production!
ZBOSS now provides the signal ZB_DEBUG_SIGNAL_TCLK_READY which the application receives when TCLK has been established. That means ant TCLK, so ZC can use that signal to be informad about generation of any TCLK in the network while all other devices get that signal only on their own TCLK establishment.
Application than may call zb_debug_broadcast_aps_key() function to broadcast the key
In release ZBOSS build zb_debug_broadcast_aps_key() exisis but does nothing.
That feature is intended to improve routing. No additional API need to be used by the application. Some data structures has been changed. zb_neighbor_tbl_ent_t has been optimized to decrease RAM usage.
In pre-r23 implementations ZBOSS has neighbor table which contained "normal" and "extended" entries. Extended entries were produced by Active scan result.
Now ZBOSS has a separate data structure - Discovery table which has the same meaning as Extended neighbor: it holds the result of Active scan.
To simplify porting applications between ZBOSS r22 to r23, an alias zb_ext_neighbor_tbl_ent_t is created to zb_nwk_disc_tbl_ent_t.
Note that in ZED-only build neighbor table size is now 1 while discovery table size is > 1.
For ZBOSS compiled with the configurable memory feature ZB_CONFIG_NWK_DISC_TABLE_SIZE setting is introduced.
That is pure internal change. Transparent NVRAM migration when updating FW from r22 to r23 ZBOSS is implemented, so it is possible to update FW via OTA between ZBOSS r22 and r23 without loosing an NVRAM contents.
DSR provided dissectors for r23 commands to the Wireshark tream, so r23 support by DSR is already included into the official Wireshark nightly builds.