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.

CC1352P: Understanding Keys and Security - ApiMac_secAddKeyInitFrameCounter

Part Number: CC1352P

Hello,

I've been struggling to fully understand the TI 15.4 Stack implementation of key storage and retrieval. Before I jump into some in depth questions, is it possible to obtain the source for some of the "Simplified Security Interfaces" functions. In particular, it would be hugely helpful to understand what exactly ApiMac_secAddKeyInitFrameCounter is performing. It's a bit of a black box, and the documentation regarding this function is a little lacking.

In the related thread, it ends with the acknowledgment of at least one known bug in the function and I am hesitant to use this without a better understanding of what it is actually doing.

Thanks,

Ryan

  • Hi Bryan,

    I think that I should have been a bit more specific in my reply.

    As you correctly mentioned OAD requires some external intelligent controller to do get the update. But if I remember correctly, the update is received (over the air) and then stored in external or external flash. To actually apply the update, you rely on the Boot Image Manager (BIM). So my suggestion is to look into how the BIM works as this might be closer to what you need.

    For the CC13x0 devices (CC13x0_SDK_4.20) there is a BIM example located in TI 15.4-Stack examples folder, that might provide a starting point for your particular application, since it also uses SPI for communication.

    BR,
    Andres

  • Hi Andres,

    Sorry for the long delay in responding. I'm not sure how OADs are related to my question. I'm am specifically trying to find out exactly what the function ApiMac_secAddKeyInitFrameCounter is actually doing. There is very little documentation for this function, and it's not performing as expected.

    Is it possible to obtain the source code for the 15.4 Stack? They are only included as compiled libraries, and for a secure product it is absolutely necessary we understand what these functions are performing.

  • Hi Ryan,

    Apologies. My reply doesn’t make sense. It was most likely a reply to another E2E thread. I’m terribly sorry about this.

    Let me get back to you on your source code request. Now, having said this. I checked the change logs and the bug mentioned in the E2E thread that you linked was fixed in later versions of the SDK.

    BR,
    Andres 

  • Hi Andres,

    Thanks, looking forward to your reply. Related to the function mentioned above, we are having trouble understanding how the frame counters are being used (and stored) for replay protection.

    For example, we call ApiMac_secAddKeyInitFrameCounter when adding a new key, which appears to work from the perspective of adding new key material. We can send and receive messages using the key entered using this function. However, the frame counter value appears to always be set back to zero regardless of the value passed to the add key function.

    We can call ApiMac_mlmeGetSecurityReqStruct(ApiMac_securityAttribute_keyEntry, &key_entry); and can see that the key has been stored as expected, however, the frame counter is always initialized to zero. When sending messages we can see that the key counter is being incremented with each sent message.

    However, our problem is restoring this frame counter if a device is reset. We are storing the frame counter in non-volatile memory, but have no way to re-insert this value into the MAC layer. We call ApiMac_secAddKeyInitFrameCounter as shown in the example with the recovered frame counter, but it is not being stored correctly at the MAC layer.

    Additionally, there seems to be no way to update or access the frame counter on the receiving end. If we want true replay protection then a copy of the frame counter must exist on both the sending and receiving end. Where is the frame counter on the receiving end being stored? When a message is received, and the frame counter of the incoming message read, what is it compared against to ensure the new message is in fact new? We would want to read, store, and recover the frame counter on the receiving end as well.

    Thanks,

    Ryan

  • Hi Andres,

    I think I'm about to answer some of my own questions posted earlier today.

    It still looks like ApiMac_secAddKeyInitFrameCounter isn't capable of updating the frame counter, and instead always initializes it to zero. However, I can call ApiMac_mlmeSetSecurityReqStruct(ApiMac_securityAttribute_keyEntry, &key_entry) and update the frame counter directly. This is confirmed to work.

    It also looks like maybe the frame counter on the receiving end is stored as part of the Device Table, and can be set and retrieved using ApiMac_mlmeSetSecurityReqStruct(ApiMac_securityAttribute_deviceEntry, &device_entry) (and Get respectively)?

    Now that I can get and set the frame counters on both the sender and receiver I am able to run some tests. The problem I am now seeing is that messages are being accepted even if the incoming frame counter is lower than the stored frame counter on the receiving end. Is there a setting somewhere I am missing that enables this check at the MAC layer? Or is this something I need to check manually?

    Additionally, we have multiple keys for each end device on our network, typically a default key used during provisioning, and a session key used for data transfer. I can see that there is a frame counter associated with each key in the key table, and they are incremented on the sender side each time a message is sent using that key. However, on the receiving end I only see one place to store a frame counter in the device table, and this key is set to whatever the frame counter was on the last received message + 1. I'm not seeing a place where the frame counter is stored and incremented on the receiving end for each key. So, back to one of my original questions - Where are the frame counters on the receiving end being stored, and how/where is this check being made?

    I also think it's still important to understand what ApiMac_secAddKeyInitFrameCounter is actually doing. The header file states that this function "Adds the MAC security key, adds the associated lookup list for the key, initializes the frame counter to the value provided". If this function does not actually initialize the frame counter to the value provided, and always resets it to zero, then this is very misleading. Can you confirm this on your end?

    Thanks,

    Ryan

  • Hi Ryan,

    Thank you for your patience and for the work you’ve done. I appreciate it.

    It still looks like ApiMac_secAddKeyInitFrameCounter isn't capable of updating the frame counter, and instead always initializes it to zero. However, I can call ApiMac_mlmeSetSecurityReqStruct(ApiMac_securityAttribute_keyEntry, &key_entry) and update the frame counter directly. This is confirmed to work.

    If that’s the case, then there might be a problem with either the ApiMac_secAddKeyInitFrameCounter() API or the documentation. I will verify this and then inform R&D if that’s the case.

    Is there a setting somewhere I am missing that enables this check at the MAC layer? Or is this something I need to check manually?

    I believe that this is something that you must check yourself. Since the example only covers the most basic use-cases, there are some things that need to be added so that the application makes use of all the features that the TI 15.4 Stack offers.

    However, on the receiving end I only see one place to store a frame counter in the device table, and this key is set to whatever the frame counter was on the last received message + 1.

    Can you point me to the place this is happening on the example? Reading the IEEE 802.15.4 standard I see that previous versions of the standard used a single frame counter for outgoing frames for each device, but the from the 2015 version, the standard allows multiple outgoing frame counters, each of which is associated with a key. This is also mentioned in the documentation for the ApiMac_keyDescriptor_t struct in api_mac.h. It could be that this use-case (multiple frame counters) was implemented at the stack-level, but not at the example application level. So I’ll need to check this.

    Regarding the source code request, I've asked and unfortunately I cannot provide it to you. I'll be back once I have done all the necessary tests. Thank you.

    BR,
    Andres

  • Hi Andres,

    I've done some more testing around the frame counters, and I'll try and detail what I've found below. The information regarding IEEE 802.15.4 are from IEEE Std 802.15.4Tm ‐2020.

    According to the IEEE 802.15.4 the frame counter should be checked on each incoming message if macSecurityEnabled is true (can confirm that it is), and if TSCH mode is not being used (can confirm we are not using this mode). 9.2.4 Incoming frame security procedure step 'h' states to check that the frame counter field of the frame is not less than that of "FrameCounterCheck". 

    In my application I can easily read the frame counter of the incoming frame, but I can't seem to locate what the TI API is using for the "FrameCounterCheck" value. Since all frames are being accepted, it would appear that is value is always set to zero (wherever it is).

    Directly from the standard:

    1) If secFrameCounterPerKey of the KeyDescriptor is FALSE, the FrameCounterCheck value shall be set to be the secDeviceMinFrameCounter element of the DeviceDescriptor.

    2) If secFrameCounterPerKey of the KeyDescriptor is TRUE and there is a secKeyDeviceFrameCounter in the secKeyDeviceFrameCounterList in which secDeviceExtAddress matches secExtAddress of the DeviceDescriptor, then the procedure shall set the FrameCounterCheck value

    I don't see any of these fields as part of the TI 15.4 stack. I see no reference to secFrameCounterPerKey, nor is there an secKeyDeviceFrameCounter element in the secKeyDeviceFrameCounterList.

    There is, however, an ApiMac_frameCntr_t pointer type as part of the ApiMac_securityDeviceDescriptor_t type. This is part of a device table entry. I can query this list using ApiMac_mlmeGetSecurityReqStruct(ApiMac_securityAttribute_deviceEntry, &device_entry) and it appears to return an array of ApiMac_frameCntr_t that matches the size specified in API_MAX_NODE_KEY_ENTRIES (testing with this = 3).

    This is where things get a little weird. I get inconsistent results in this array of frame counters. When I add my first key, all values in this table are zero. When I add a second key, I see the first element now has data, keyIdx = 1, and frameCounter = my last received frame counter value +1 for my key at index 1. This seems to align with my second key (index = 1) and the frame counter is a match. However, the frame counter for the key at index 0 is not preset. Also, despite there being a correct frame counter on the receiving end I can confirm that it is not being used as the value to check against on incoming messages.

    Obviously I'm not understanding the TI implementation of frame counter settings, storage, and check values on the receiving device. There is very little documentation, and it's not strictly matching the IEEE standard, so I'm pretty stuck at this point.

    Again, I ask you to reconsider releasing the source for these libraries. They are not well documented and this is putting developers like myself in a tough spot.

    I'm hoping you're able to provide more details on my above questions, and more details around TI's implementation of frame counters and sequential freshness.

    Thanks,

    Ryan

  • Hi Ryan,

    Thank you for your further testing. I really appreciate the time that you are putting into this.

    I’m going to need some time to either familiarize myself with the security APIs of the TI 15.4-Stack, or to contact the appropriate expert. Would you be willing to provide some example code that I could use to see what you are experiencing?

    And I understand your frustration when it comes to releasing the source code, but this is something that as far as I understand requires some special agreements that are outside of what I can do.

    BR,
    Andres

  • Hi Andres,

    There isn't really one particular piece of code we can share that demonstrates the question. We may be able to add some additional debug go to the original collector and sensor examples to demonstrate this, but it could take some time.

    The the meantime, the place to look would be the function that handles the parsing and security check on incoming messages. If you have access to the source, you should be able to see the procedure for checking the frame counter value, and from there trace back the source of that frame counter value used in the comparison. Even if you're only able to share snippets of source code, this would be hugely helpful in understanding the frame counter implementation.

    Another question might simply be: Does TI's support secFrameCounterPerKey mode? That is, one frame counter per key. It looks like changes were made to support this in a past update, but they were not documented.

    Also, there is still the confirmation that ApiMac_secAddKeyInitFrameCounter does not set the frame counter, but rather just initializes it to zero. This should be a relatively easy thing to check either by calling the function in your example code, or inspecting the source for this function.

    Thanks,

    Ryan

  • Hi Andres,

    Quick follow-up. Previously I wrote:

    "This is where things get a little weird. I get inconsistent results in this array of frame counters. When I add my first key, all values in this table are zero. When I add a second key, I see the first element now has data, keyIdx = 1, and frameCounter = my last received frame counter value +1 for my key at index 1. This seems to align with my second key (index = 1) and the frame counter is a match. However, the frame counter for the key at index 0 is not preset. Also, despite there being a correct frame counter on the receiving end I can confirm that it is not being used as the value to check against on incoming messages."

    The first key added was the default network key used during the commissioning process, so it makes sense that this wasn't stored in the device table, since it isn't linked to a specific device MAC address.

    There is an additional function ApiMac_secGetDefaultSourceKey that can access this default frame counter. Despite this functions name, its description is "Reads the frame counter value associated with a MAC security key indexed by the designated key identifier and the default key source." I can read the default frame counter using this function, but it is only for the sender side

    But, there are still a couple big holes here:

    1) Where is frame counter for the default key stored on the receiving end? How do I read and write to it? It looks like the example code uses ApiMac_secAddDevice, but using this seems to have no effect on the rx frame counter. Nor do I have any tools to read the currently stored default rx frame counter.

    2) Why aren't the incoming messages being blocked when the rx frame counter is higher than the tx frame counter? How do I update the rx frame counters associated with each key. I can view them using ApiMac_mlmeGetSecurityReqStruct(ApiMac_securityAttribute_deviceEntry, &device_entry), I can also set them using ApiMac_mlmeSetSecurityReqStruct(ApiMac_securityAttribute_deviceEntry, &device_entry) but as soon as a new message (even with a lower frame counter) is received, it accepts the message and overwrite the frame counter value I just set.

    Thanks,

    Ryan

  • Hi Andres,

    I just did a full reinstall of the latest CC1352P SDK, and a clean install of the sensor and collector examples. Out of the box, frame counter checks don't appear to be working. When sending messages from the sensor to the collector, when security is enabled, I can send messages with the same, smaller, or larger frame counters and all are accepted on the receiving end.

    I can also confirm that in the out of the box example, the frame counter is not being restored properly. The example code uses ApiMac_secAddKeyInitFrameCounter to restore the frame counter after it is pulled from NV memory. This "restored" frame counter doesn't appear anywhere, and is not used in any new messages that are sent. The frame counter is always reset to zero on a recovered sensor or collector.

    Can you please confirm this as soon as possible? Can you provide any setup in the examples that causes a message to be rejected due to a bad frame counter?

    I am using simplelink_cc13xx_cc26xx_sdk_5_30_01_01, on the CC1352P1_LAUNCHXL, examples collector_sm and sensor_sm.

    Thanks,

    Ryan

  • Hi Ryan,

    I'll test the examples that you mentioned and if I see the same thing that you are seeing, I'll pass the information that you have provided to RnD so that this is taken care of.

    I'll get back to you.

    BR,
    Andres

  • Hi again,

    I'm doing some tests and I'm also using a packet sniffer to verify what I'm seeing, and I do agree that there is something unexpected happening with the frame counter. Let me do some debugging to make sense of what's happening and I'll get back to you.

    Thank you for your patience.

    BR,
    Andres

  • Hi Andres,

    Did you have any update on this?

    Thanks,
    Ryan

  • Hi Ryan,

    I did some tests using the different modes (Beacon, Non-Beacon, FH) to see how the frame counter is handled in each case (on both sides).

    I have contacted RnD about my findings, so that we can discuss this more thoroughly and I can give you an appropriate reply in a couple of days.

    BR,
    Andres

  • Hi Andres,

    This has been open for over a month and there has been no answer to my question. In its current state a core piece of the TI 15.4 stack is unusable. Can you please provide a response asap, or at the very least assign a support engineer to work with us directly. This is significantly effecting our ability to complete our design.

    Thanks,
    Ryan

  • Hi Ryan,

    I checked several scenarios such as the sensor going into an orphan state and rejoining, or the collector being reset to better understand what's happening. I used a packet sniffer for this purpose. I also followed the code to see how the frame counter is used in the examples.

    I agree that the frame counter is not being used properly. At least the way that you expect it. In most cases, such as when either of the devices is reset, the frame counter that ends up being used is not the one in NV, but an initial value (i.e., 0). Consider for instance what happens on the sensor's side.

    In Sensor_init() you first make a call to Ssf_getFrameCounter() which checks the NV to see if there is a previous value for the frame counter. Next you used that value in Jdllc_securityInit() which makes a call to ApiMac_secAddKeyInitFrameCounter() and ultimately to macWrapperAddDevice() which adds the MAC security key, the associated lookup list for the key, and initializes the frame counter to the value provided.

    The issue is that afterwards in the Sensor_process(). If the device is rejoining a network it makes a call to Jdllc_addSecDevice() and always passes a frame counter value of zero. So the frame counter will always be reset.I'm seeing similar things in the collector example.

    The way I see it, the issue that you are facing are most likely relates to the way the examples are handling the logical link layer. This also explains why keeping the frame counter value in NV is not doing much.

    Now, you also had a question about how the frame counter is being kept in NV. My understanding is that the frame counter is updated considering a frame counter save window. Meaning that you don't write to NV with every new message, but you do it every certain amount of messages.

    Furthermore, as you pointed out, the examples don't seem to be rejecting messages due to a wrong frame counter value. This is something that I'm trying to understand to see if there is something that I'm missing.

    BR,
    Andres

  • Hi Andres,

    Can you provide some basics around how we are supposed to read and update the frame counter from the apimac layer? 

    In the simplest example, set the frame counter on the transmitting device to a value lower than that of the receiving device. This message should be rejected, but it is not. Can you confirm? This would show that the problem is indeed in the stack itself.

    The frame counter update window is understood. We've stripped back everything from the example code to test basic core security functionality and it fails.

    I don't believe this is a problem at the example code level, it is within the TI 15.4 Stack. Could you please escalate this to a higher priority or put me on a path with someone at TI that bring this to a solution. We could have solved this in a matter of days if we had limited access to the source. Instead, we are being forced to completely bypass TI's core security features and implement our own. This is not ideal, as it would be far more efficient if this was handled at the stack layer as intended.

    Additionally, it worries us that such a core piece of your security code does not appear to be working, and that there isn't support available at TI that understands how this should be working. Please put us on a path to being able to review the code source for ourselves. We willing for follow whatever procedures are necessary.

    This is not going to be resolved in this forum. Again, please put on us a path with the appropriate contact at TI so that this can be resolved as soon as possible.

    Thanks,
    Ryan

  • Hi Ryan,

    I have checked the source code and with RnD, and ApiMac_secAddKeyInitFrameCounter() is an initialization function of the security table. It will take in some of the data to initialize it, however, it won’t let you update the frame counter for a specific entry.

    This is not something we support and will not probably support. To explain, the initialization just means mostly passing in security keys, and other things. The “frameCounter” parameter being set in Cllc_SecurityInit(), gets used to set a specific Key Entry’s frame counter. This explains why you are having problems restoring the frame counter if a device is reset.

    Having said this, since you mentioned that you have successfully used ApiMac_mlmeSetSecurityReqStruct() to update the frame counter directly (and that you can get and set the frame counter on both ends), can you please share the project files that show that messages are being accepted even if the incoming frame counter is lower than the stored frame counter on the receiving end? If that’s the case, I’ll reproduce the issue directly, check again with RnD and if necessary I’ll file a bug ticket.

    BR,
    Andres