-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ieee802154_security: add internal descriptor organization for replay protection #18575
base: master
Are you sure you want to change the base?
ieee802154_security: add internal descriptor organization for replay protection #18575
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand it correctly that with this we have a separate key for each pair of devices?
So for a simple star topology CONFIG_IEEE802154_SEC_DEFAULT_DEVSTORE_SIZE
would be 1 for the leaf nodes and n
for the border router, where n
is the number of leaf nodes?
} ieee802154_sec_dev_lookup_t; | ||
|
||
/** | ||
* @brief Lookup table for peer devices to securely communicate with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't quite fully wrap my head around this, but could netstats_nb_t
help here? (as in #16312)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I understand it correctly that with this we have a separate key for each pair of devices?
This would be the implicit key mode, which means after key exchange phase with a peer, the key to use is implicitly known by both, from the peer device address.
This requires 1 Keydescriptor + 1 KeyLookupDescriptor + 1 DeviceDescriptor per peer.
There are explicit keys, also called group keys. Let´s say a PAN coordinator is able to distribute some kind of key database in a network (or preconfigured).
The keys are somehow advertised with an indentifier (index). Each node will know key at index 1
is <KEY1>
and key at index 2
is <KEY2>
and so on.
So devices in that PAN use for example key_mode = IEEE802154_SEC_SCF_KEYMODE_INDEX
and kex_index = i
in the frame security header.
And if two peers are aware of the same key database, they will know which key is key i
.
This requires 1 KeyDescriptor + 1 KeyLookupDescriptor + n DeviceDescriptors, for n
peers.
We do need a DeviceDescriptor for each peer we communicate with, anyway to check the incoming frame counter.
I made a sketch in sys/net/link_layer/ieee802154/security.c
. But I noticed there is one missing edge.
So for a simple star topology CONFIG_IEEE802154_SEC_DEFAULT_DEVSTORE_SIZE would be 1 for the leaf nodes and n for the border router, where n is the number of leaf nodes?
Yes, given that communication always happens through the border router as a PAN coordinator. But I think RIOT is not exposing the concept of a PAN coordinator at the moment.
I didn't quite fully wrap my head around this, but could netstats_nb_t help here? (as in #16312)
I would not extend netstats_nb_t
because this is volatile information but ieee802154_sec_dev_lookup_t
must go into persistent storage.
The DeviceDescriptor and especially the frame counter in it must remain, even if a neighbor is thrown out of the neighbor cache.
I think the neighbor cache could be useful to bootstrap peering.
In the manner of: "If I see a neighbor that I don´t have a security DeviceDescrptor for, I start some kind of peering phase and key negotiation."
IIUC this only adds replay protection. At least from the perspective of the gaps in our L2 security story, this doesn't fix them: The trouble occurs when a device uses the same (key, mac, seqno) combination twice, because that is when the nonce reuse happens; at receive time, best you could do is scream loudly that some peer is horribly broken and the key must now be changed. What is the value of replay protection anyway, given that IP packets may generally be duplicated outside the local network? (I.e., any UDP based protocol needs to deal with duplicates anyway). |
This does not fix our nonce reuse, true.
The L2 security only secures communication in the link local network. From a security perspective reusing the same none is probably worse than not having replay protection. When I should come up with an example why replay protection is not useless, I would say that it prevents that some frame froma remote control can be replayed to get access to a door. |
The data structures I see here on a first glance are bit fields; the data structure on the sending side is a persisted counter (ideally with precommittment to reduce flash operations / wear). What are the data structures that can be reused for sequence number persistence?
Exactly, it will be encrypted twice -- which means that the IP based application will need to have a mechanism to deal with retransmissions anyway.
… hope that there was a motivating example in the first place? The IEEE 802.15.4 standard is vast, implementing things just because they are there sounds like a recipe for bloat (either in compiled code or in options to sift through when deciding what to use). Freshness with door lock control is well understood in applications, eg. in OSCORE's replay protection or RFC9175's Echo based freshness. IPv6 ND replay is something I don't know well enough to understand its fallout, and it may well be a justifying use case, but I'd like to ask you to look a bit more into where this actually makes a difference. To illustrate why I think that replay protection at this level is problematic, consider that there is an upper limit to the number of replay peers (call it N), and that any peers not in that list needs to be regarded as trust-any initially1. Thus, if there is an attack in which an LL replayed packet can cause trouble, all the attacker needs to circumvent the security afforded by the LL replay protection is to gather N packets using the same key from peers outside the device's radio range (which allows them to be arbitrarily old), send those, thus flush the cache, and then inject the replayed packet. Footnotes
|
Contribution description
At the RIOT summit I got the impression, that there is a big interest in extending the
gnrc
IEEE 802.15.4 security implementation.I remembered that I had a branch lying around, where I implemented the replay protection, but I did not release it as a PR because I was not satisfied with the quality, nor was I sure if I correctly understood the descriptor relations and lookup procedures from the specification. But after the summit I gave it another look.
This PR does not concern dynamic key management in the sense of key generation, distribution and update. But it implements a constrained variant of the internal descriptor organization, explained in the specification, to keep track of peer devices and key selection, to realize replay protection. I think the descriptors are more of a prerequisite for IEEE 802.15.4 key management.
Additionally, I wrote a shell tool
iwpansec
that can be used to manage keys and devices statically for testing.Regarding LL security, it shall serve the same purpose as wpan-tools in Linux. But of course it is more limited than that. Ideally, devices should be discovered dynamically, (maybe from the neighbor cache), and keys and parameters should be exchanged properly between devices. But for testing, the tool should be fine.
More explanation can be found in the code comments.
Testing procedure
This is not so heavily tested yet.
Setup two boards running our
gnrc_networking
example, add each others device addresses and enter the (pseudo-)peering command, which does not actually send a peering request but assumes that the peering succeeds.board 1:
board 2:
The boards should be able to ping each other after that.
Now, reset one board and repeat the setup on that board.
The ping intentionally no longer works, because the other board identifies the frame as a replay.
I know replay protection is not so useful until we store the data structures on persistent storage,
but it is good for testing and if I had to implement the persistent storage for LL security and proper key management,
I would go on from here.
Issues/PRs references
I think before we tackle #16844, we must know what exactly must be stored persistently. This implementation adds the internal data structures that must be stored.