This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2630: Device specific link key process defined in Z-STack 3.0 for HA 1.2.2

Part Number: CC2630
Other Parts Discussed in Thread: Z-STACK

Hi,

is there an implementation of the Device specific link key joining process which comes with the 3.0 version for the 1.2.2 HA Stack?

Regards,

Philipp

  • No need to specify implementation. 3.0 device should join HA 1.2.2a network.
  • Hi YiKai,

    maybe i wasnt clear enough. What I meant is that i need the DSLK pairing for my device which is part of the z-stack 3.0 release but I have the CC2630 and can only use the 1.2.2 HA Stack. Does that mean I need to implement it on application level?

    Regards,

    Philipp
  • I couldn’t understand your question. What is DSLK?
  • DSLK is Device specific link key and is the encryption of the packets so the NWK key is not sent in clear during joining process. In 1.2.2 a global link key is used which is less secure. 3.0 Supports DSLK though and I wanted to know if there is a way to use this feature in 1.2.2.

    Regards,

    Philipp
  • No, you cannot support that in ZHA Stack.
  • Thank you for the fast reply, but this is rather important Topic for me. Is there a way to get feedback to this from a TI developer?

    Regards,

    Philipp
  • can you help to clarify this?
  • Install codes are specific to the Zigbee 3.0 Specification: www.ti.com/.../swra615.pdf

    I would doubt that there is enough flash memory to even implement a custom DSLK process. You could alternatively hard-code the ZC NV while programming and perform a secure rejoin, this wouldn't be on the CC2630 as it can only operate as a ZED.  On a similar topic would be white/blacklisting: http://wiki.tiprocessors.com/index.php/Black_list_implementation 

    Regards,
    Ryan

  • Part Number: CC2630

    Hi,

    is it possible to read/write the TrustCenterLinkKey from the Application using zclport_readNV/zclport_writeNV?

    Regards,

    Philipp

  • Hi Philipp,

    Yes it is possible, and you can further debug ZDSecMgr.c to determine where in the ZCD_NV_TCLK_TABLE it is stored.

    Regards,
    Ryan
  • In Z-Stack Home 1.2.2a for CC26xx, I think it should be ZCD_NV_TCLK_TABLE_START
  • Correct me if I'm wrong but as of my understanding the difference between GLK and DSLK is which key is used for the decryption of the Transport Key(NWK) command. The GLK is saved in the flash of the CC2630 at ZCD_NV_TCLK_TABLE_START. So if I could get the DSLK which i calculated from the Installation Code on another chip over SPI to the CC2630 and overwrite the GLK which is the default TCLK with it I would be able to decrypt the NWK key which is used for all communication after the joining?

    Would this be enough for complete DSLK and is this possible?

    Regards,

    Philipp

  • This would be the Code in the ZDSecMgr.c which as of my understanding saves the default key at ZCD_NV_TCLK_TABLE_START:

    / Initialize first element of the table with the default TCLK
    if((i == 0) && ( zgUseDefaultTCLK == TRUE ))
    {
    osal_memset( tcLinkKey.extAddr, 0xFF, Z_EXTADDR_LEN );
    osal_memcpy( tcLinkKey.key, defaultTCLinkKey, SEC_KEY_LEN);
    }

    // If the item doesn't exist in NV memory, create and initialize
    // it with the default value passed in, either defaultTCLK or 0
    rtrn = osal_nv_item_init( (ZCD_NV_TCLK_TABLE_START + i),
    sizeof(APSME_TCLinkKey_t), &tcLinkKey);

    in the initializeZStack(void) function i further try to read the value. The init works fine and returns 0 but when I reach the read the debugging session crashes and sometimes even the IAR workbench does.

    APSME_TCLinkKey_t tcLinkKey;
    state = zclport_initializeNVItem(ZCD_NV_TCLK_TABLE_START,0,sizeof(APSME_TCLinkKey_t),NULL);
    state = zclport_readNV(ZCD_NV_TCLK_TABLE_START,0,0,sizeof(APSME_TCLinkKey_t), &tcLinkKey);

    Regards,

    Phiipp
  • Hi Philipp,

    I merged your threads since they are dealing with the same support request. If your Zigbee parent has also updated its trust center link key for this specific child device then you may be able to alter the ZED global link key accordingly. I'm slightly confused here, why are you attempting to re-initialize the NV item at ZCD_NV_TCLK_TABLE_START when you should just be writing/reading from it? If you're curious as to the value why not just open the memory window in the IAR debugger?

    Regards,
    Ryan
  • Hi Ryan,

    sorry for the confusion here but i was trying to find out what the error was so i thought it may be necessary to init before reading. And I read it to check if I can access this memory space from the application. If I would be able to read the GLK i further would write the DSLK. Any thoughts on why the read leads to a crashing debug session?

    Regards,

    Philipp
  • Hi Philipp,

    Not without a further debug description. Can you provide a screenshot or log of your environment? Are you making sure to erase all device memory before re-programming? Is zclport_readNV returning a value other than 0x00 or entering a trap loop?

    Regards,
    Ryan
  • Read works but isn't returning anything. The variable is still full of 0. When i try a write I get the return value NV_ITEM_UNINIT. Does that mean I need to do an init on the Address?

    Regards,

    Philipp

  • Yes, you will need to initialize the address before you can read/write from it but you should not be re-initializing any addresses. You can check the Debugger's Memory View to read address contents and monitor their changes.

    Regards,
    Ryan
  • I found the Zstackapi functions for setting the TCLK and would now like to use them because it's the cleaner solution. While i can erase and read the TCLK for my IEEE Adress i cant write my own generated one. At the first read i received the GLK which is correct then I erased it wrote my own and read it. The response was all zeros which means the write was not successful. But all function calls return success. I'm calling these function during the zstack initialization before the DevStartReq. I atteched a screenshot of the watch with my write Request(pReq)  and the read response (getRsp). Do you know  a reason why write wouldnt work in this case?

  • Can you please provide a code excerpt that you are trying to execute? Are you removing the previous TCLK with Zstackapi_secApsLinkKeyRemoveReq before trying to set the new one?

    Regards,
    Ryan
  • Yes this is working correctly because at first the GLK was readable and after remove only 0x00.

    static void TempSensor_initializeZStack(void) { const unsigned char * ieeeFlashAddr = (void *) 0x500012F0; uint8_t newTCLinkKey[SEC_KEY_LEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,\ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; zstack_secApsLinkKeyRemoveReq_t rReq = {0}; rReq.tcLinkKey = true; memcpy(&(rReq.ieeeAddr),ieeeFlashAddr,8); zstack_ZStatusValues ret = Zstackapi_secApsLinkKeyRemoveReq(ztsEntity, &rReq); zstack_secApsLinkKeySetReq_t pReq = {0}; pReq.tcLinkKey = true; memcpy(&(pReq.ieeeAddr),ieeeFlashAddr,8); memcpy(&(pReq.key), &(newTCLinkKey), SEC_KEY_LEN); ret = Zstackapi_secApsLinkKeySetReq(ztsEntity, &pReq); zstack_secApsLinkKeyGetReq_t getReq = {0}; getReq.tcLinkKey = true; memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,8); zstack_secApsLinkKeyGetRsp_t getRsp; ret = Zstackapi_secApsLinkKeyGetReq(ztsEntity, &getReq, &getRsp); // Initialize the ZStack Thread bool startDev = true; // default to start the ZStack thread // Setup the endpoints TempSensor_registerEndpoints(); // Setup indications from ZStack TempSensor_setupZStackIndications(); if(startDev) { zstack_devStartReq_t startReq = {0}; // Start the ZStack Thread startReq.startDelay = 0; (void)Zstackapi_DevStartReq(ztsEntity, &startReq); } // Register the ZCL General Cluster Library callback functions zclGeneral_RegisterCmdCallbacks(MSTI_EP, &cmdCallbacks); // Register the application's attribute list zcl_registerAttrList(MSTI_EP, MSTI_MAX_ATTRIBUTES, ztsAttrs);

  • If you're trying to remove the TCLK, maybe see about setting the IEEE address to 0xFFFFFFFFFFFFFFFF, as this is stated inside the Zstackapi_asecApsLinkKeySetReq API.

    Is there any reason why you're not using Zstackapi_secApsLinkKeySetReq() to set the TCLK to newTCLinkKey?

    Best,
    Sean
  • I tried this at first but reading for IEEE address of 0xFFFFFFFFFFFFFFFF only returned a random key while the read for my address returned the GLK which i wanted to overwrite, so this seemed to be the correct way to do it.

    I don't get the question because I use this function to set the key, or what do you mean?

    Regards,

    Philipp

  • Hi Philipp,

    I was also unable to get the desired results, in passing this information to the Software Development Team we discovered a bug with the processSecApsLinkKey[Remove/Get/Set]Req() APIs. We are currently testing a workaround and will provide an update soon.

    Regards,
    Ryan
  • It is necessary to also make some fixes  in file zstacktask.c


    Function processSecApsLinkKeyGetReq Change verification of result to true instead of 0

    -- if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == 0)
    ++ if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == true )


    Function processSecApsLinkKeySetReq
    Change verifications of result to true instead of 0 and remove verification of y > 0 to allow writing the first entry

    -- if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == 0)
    ++ if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == true )

     

    -- else if ( (y == 0) && (osal_memcmp( pPtr->pReq->ieeeAddr, dummyKey, Z_EXTADDR_LEN ) == 0) )
    ++ else if ( (y == 0) && (osal_memcmp( pPtr->pReq->ieeeAddr, dummyKey, Z_EXTADDR_LEN ) == true) )

     

    -- if ( y > 0 )
    ++


    Function processSecApsLinkKeyRemoveReq Change verification of result to true instead of 0


    -- if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == 0)
    ++ if ( osal_memcmp( pPtr->pReq->ieeeAddr, tcLinkKey.extAddr, Z_EXTADDR_LEN ) == true )

  • Hi,

    I implemented the workaround as you suggested but the results aren't as expected. The code is the same as in my previously posted snippet. Writing the key returns a status of 0x09 and when i try to read it to make sure it was correctly written the returned value is not the key that i wrote. I then tried to just read the key after a erase of the flash memory. This should have returned the DEFAULT_TC_LINK_KEY as defined in nwk_globals.h but returned with a key not matching anything i have seen (see picture). How should the API behave after this workaround?

    Regards,

    Philipp

  • Hi  Philipp,

    The issue with your code is that you are looking to remove get, set and remove the key with ieeeFlashAddr equal to (void *) 0x500012F0. TCLK is stored in ZCD_NV_TCLK_TABLE_START NV item with IEEE address value of 0xFFFFFFFFFFFFFFFF in APSME_TCLinkKeyInit(), this is in ZDSecMgr.c, so you need that value to initially manipulate this element with the get, set or remove API's, then the API's will store your new key with IEEE value of 0x0000000000000000. I made some changes to your code to make it work with the provided API's. You still need the fixes provided by Dalila.

    Use the next code to test the API's:

      uint8_t ieeeFlashAddr[Z_EXTADDR_LEN];
      uint8_t newTCLinkKey[SEC_KEY_LEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,\
                                                 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
      zstack_secApsLinkKeyGetReq_t getReq = {0};
      zstack_secApsLinkKeyGetRsp_t getRsp;
      zstack_secApsLinkKeyRemoveReq_t rReq = {0};
      zstack_secApsLinkKeySetReq_t pReq = {0};
      zstack_ZStatusValues  ret;
      
      memset(ieeeFlashAddr, 0xFF, Z_EXTADDR_LEN);
      getReq.tcLinkKey = true;
      memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
      ret =  Zstackapi_secApsLinkKeyGetReq(ztsEntity,
                                              &getReq,
                                              &getRsp);
      
      rReq.tcLinkKey = true;
      memcpy(&(rReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
      ret = Zstackapi_secApsLinkKeyRemoveReq(ztsEntity, &rReq);
      
      memset(ieeeFlashAddr, 0x00, Z_EXTADDR_LEN);
      pReq.tcLinkKey = true;
      memcpy(&(pReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
      memcpy(&(pReq.key), &(newTCLinkKey), SEC_KEY_LEN);
      ret = Zstackapi_secApsLinkKeySetReq(ztsEntity, &pReq);
      
      getReq.tcLinkKey = true;
      memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
      ret =  Zstackapi_secApsLinkKeyGetReq(ztsEntity,
                                              &getReq,
                                              &getRsp);

    So the API's work as expected you just need to take care of the IEEE you are using to request the TCLK.

    Regards,

  • Hi Jose,

    Thanks these changes from you work. Though the Problem I'm facing now is that while I'm able to write the key, the joining of a Network which is encrypting the NWK key with the same TCLK that I wrote to the memory using this API doesn't work. The sniffer shows that a NKW key is transmitted but the z-stack seems like it is not able to decrypt. It sends out a few data requests but stops after a few seconds indicating that in ran into an exception. Besides that it never sends a Device Announce Broadcast. I thought about it like it is defined in Z-Stack 3  Dev Guide Chapter 10.5.2. The Coordinator is encrypting with a key derived from an installation code and the joining device has the same key now as the TCLK. The same concept as normal but with a custom key and not the GLK. After the NWK key exchange the communication should be entirely encrypted with it but it doesn't seem I ever get there. Is there something missing in my concept?

    Regards,

    Philipp

  • Can you send me this capture?
  • Do you mean the logs from the sniffer?

    Regards,

    Philipp

  • I think Jose means to ask you to provide sniffer log.
  • Which Format should the file have because I cant upload the original .isd from the Ember Desktop?
  • You can ZIP it to attach the zip file.
  • yes, share a sniffer log of this behavior please.
  • Hey Philipp,

    Please convert your .isd to .dcf so that we can view the sniffer log in Ubiqua.

    Thanks,
    Ryan
  • Hi Ryan,

    I converted the File, once with forced Ubiqua DC format and once conform to original Daintree specification.

    Regards,

    Philipp

    5126.DSLK.zip

  • Can you tell the device and application used for Zigbee coordinator in this sniffer logs?
  • The Device is a Telegesis ETRX3USB+8M with a Firmware based on the stack version EmberZNet 5.4.0.

  • From the sniffer log is clear that the Zigbee coordinator is sending the transport key encrypted with the default TCLK 5A:69:67:42:65:65:41:6C:6C:69:61:6E:63:65:30:39 (look at packet 21). Since you have changed the default TCLK of your End Device to 10:0F:0E:0D:0C:0B:0A:09:08:07:06:05:04:03:02:01 this device is not able to decrypt the transport key frame and the association process cannot be completed. You need to change the default TCLK of coordinator as well.

  • My bad I sent the wrong logs. These are the ones with the NWK key correctly encrypted. We used the following key in the code:

    uint8_t newTCLinkKey[SEC_KEY_LEN] = { 0x64, 0xE9, 0x12, 0x9D, 0xE2, 0x7C, 0xE3, 0x85,\
    0x8E, 0x4C, 0xE1, 0x23, 0xF9, 0x8C, 0x72, 0x86 };

    And the same can be seen as encryption for the NWK key in the logs.

    DSLK_Joining.zip

  • I'm not able to decrypt the trasport key frame on packet 56 in the log with this TCLK. Can you double check the value of the key for coordinator.

  • Hi Philipp,

    Can you please provide an update on this issue?

    Thanks,
    Ryan
  • Hi Ryan,

    I tested this again and faced the same problem. I'm able to join the network with another device, but not using the aforementioned setup. I attached a screenshot from the sniffer log with the decrypted NWK-Key package. I'm not sure why you are not possible to decrypt the packet with the key I sent.

    This is the current code I have for setting the TCLK:

    uint8_t ieeeFlashAddr[Z_EXTADDR_LEN];
    uint8_t newTCLinkKey[SEC_KEY_LEN] = { 0x64, 0xE9, 0x12, 0x9D, 0xE2, 0x7C, 0xE3, 0x85,\
    0x8E, 0x4C, 0xE1, 0x23, 0xF9, 0x8C, 0x72, 0x86 };
    zstack_secApsLinkKeyGetReq_t getReq = {0};
    zstack_secApsLinkKeyGetRsp_t getRsp;
    zstack_secApsLinkKeyRemoveReq_t rReq = {0};
    zstack_secApsLinkKeySetReq_t pReq = {0};
    zstack_ZStatusValues ret;

    memset(ieeeFlashAddr, 0xFF, Z_EXTADDR_LEN);
    getReq.tcLinkKey = true;
    memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    ret = Zstackapi_secApsLinkKeyGetReq(ztsEntity,
    &getReq,
    &getRsp);

    rReq.tcLinkKey = true;
    memcpy(&(rReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    ret = Zstackapi_secApsLinkKeyRemoveReq(ztsEntity, &rReq);

    memset(ieeeFlashAddr, 0x00, Z_EXTADDR_LEN);
    pReq.tcLinkKey = true;
    memcpy(&(pReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    memcpy(&(pReq.key), &(newTCLinkKey), SEC_KEY_LEN);
    ret = Zstackapi_secApsLinkKeySetReq(ztsEntity, &pReq);

    getReq.tcLinkKey = true;
    memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    ret = Zstackapi_secApsLinkKeyGetReq(ztsEntity,
    &getReq,
    &getRsp);

    Could it be that the order of the newTCLinkKey is wrong. Maybe it needs to be in reverse order?

    Is there some sort of possibility to detect where the error is happening by debugging the CC2630?

    Regards,

    Philipp

  • Can you share the .dcf logs of this new tests? I need the logs in order to help you. 

  • The logs show the same results as the ones I sent you before. Because of that I haven't saved them. If necessary I can redo the tests though.

  • Yes I need to have them.
  • I did the tests again and those are the results. Is the format correct for you?

    DSLK_Joining_2.zip

  • Hi Philipp,

    I just noticed that there is a typo in the code that sets the key:

     

    uint8_t ieeeFlashAddr[Z_EXTADDR_LEN];
    
     uint8_t newTCLinkKey[SEC_KEY_LEN] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,\
    
                                                0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
    
     zstack_secApsLinkKeyGetReq_t getReq = {0};
    
     zstack_secApsLinkKeyGetRsp_t getRsp;
    
     zstack_secApsLinkKeyRemoveReq_t rReq = {0};
    
     zstack_secApsLinkKeySetReq_t pReq = {0};
    
     zstack_ZStatusValues  ret;
    
     memset(ieeeFlashAddr, 0xFF, Z_EXTADDR_LEN);
    
     getReq.tcLinkKey = true;
    
     memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    
     ret =  Zstackapi_secApsLinkKeyGetReq(ztsEntity,
    
                                             &getReq,
    
                                             &getRsp);
    
     rReq.tcLinkKey = true;
    
     memcpy(&(rReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    
     ret = Zstackapi_secApsLinkKeyRemoveReq(ztsEntity, &rReq);
    
     memset(ieeeFlashAddr, 0xFF, Z_EXTADDR_LEN);                                     // Changed memset from 0x00 to 0xFF
    
     pReq.tcLinkKey = true;
    
     memcpy(&(pReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    
     memcpy(&(pReq.key), &(newTCLinkKey), SEC_KEY_LEN);
    
     ret = Zstackapi_secApsLinkKeySetReq(ztsEntity, &pReq);
    
     getReq.tcLinkKey = true;
    
     memcpy(&(getReq.ieeeAddr),ieeeFlashAddr,Z_EXTADDR_LEN);
    
     ret =  Zstackapi_secApsLinkKeyGetReq(ztsEntity,
    
                                             &getReq,
    
                                             &getRsp);

    Ieee address needs to be 0xFFFFFFFFFFFFFFFF for Zstackapi_secApsLinkKeySetReq(), I just noticed this typo, sorry about that.

    Now you will be able to decrypt the transport key an see something like this.

  • Hi Jose,

    when I try to write to 0xFF I get a zstack_ZStatusValues of 0x09 returned. This value is not defined in the Enum, thus I'm not sure what this error means.

    Regards,

    Philipp