RFC 9031
Constrained Join Protocol (CoJP) for 6TiSCH
Part 1 of 12 ๐
RFC 9031: Constrained Join Protocol (CoJP) for 6TiSCH ๐
Okay so the title block is giving a full squad. RFC 9031 is titled Constrained Join Protocol (CoJP) for 6TiSCH. It was written by M. Vuฤiniฤ (who edited it, at Inria), J. Simon (Analog Devices), K. Pister (University of California Berkeley), and M. Richardson (Sandelman Software Works). It's a Standards Track document from the IETF, dated May 2021, with ISSN 2070-1721. The title block doesn't list anything it obsoletes or updates. ๐ฆ
Abstract โจ
Okay so this doc is about the smallest possible setup a brand-new device, called a "pledge", needs in order to securely join a 6TiSCH network (that's IPv6 over the Time-Slotted Channel Hopping mode of IEEE 802.15.4) ๐ธ The pledge and the JRC (Join Registrar/Coordinator, a central entity) have to share a symmetric key. How that key gets provisioned is out of scope for this doc.
With one CoAP (Constrained Application Protocol) request-response exchange, secured by OSCORE (Object Security for Constrained RESTful Environments), the pledge asks to be admitted to the network, and the JRC hands it link-layer keying material plus other parameters. The JRC may update those parameters at any time through another OSCORE-secured request-response exchange. ๐ฅ
The spec defines the Constrained Join Protocol and its CBOR (Concise Binary Object Representation) data structures, and it explains how to configure the rest of the 6TiSCH communication stack so the join happens securely. Additional security mechanisms may be added on top of this minimal framework. ๐
Status of This Memo ๐
This is an Internet Standards Track document. ๐
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has had public review and has been approved for publication by the Internet Engineering Steering Group (IESG). More info on Internet Standards is in Section 2 of RFC 7841.
Info about the current status of this document, any errata, and how to send feedback is at https://www.rfc-editor.org/info/rfc9031. โจ
Copyright Notice ยฉ๏ธ
Copyright (c) 2021 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication. Please read these carefully, because they describe your rights and restrictions for this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they are provided without warranty as described in the Simplified BSD License. ๐ซถ
Table of Contents ๐๏ธ
1. Introduction
2. Terminology
3. Provisioning Phase
4. Join Process Overview
4.1. Step 1 - Enhanced Beacon
4.2. Step 2 - Neighbor Discovery
4.3. Step 3 - Constrained Join Protocol (CoJP) Execution
4.4. The Special Case of the 6LBR Pledge Joining
5. Link-Layer Configuration
5.1. Distribution of Time
6. Network-Layer Configuration
6.1. Identification of Unauthenticated Traffic
7. Application-Layer Configuration
7.1. Statelessness of the JP
7.2. Recommended Settings
7.3. OSCORE
8. Constrained Join Protocol (CoJP)
8.1. Join Exchange
8.2. Parameter Update Exchange
8.3. Error Handling
8.4. CoJP Objects
8.5. Recommended Settings
9. Security Considerations
10. Privacy Considerations
11. IANA Considerations
11.1. Constrained Join Protocol (CoJP) Parameters
11.2. Constrained Join Protocol (CoJP) Key Usage
11.3. Constrained Join Protocol (CoJP) Unsupported Configuration
Codes
12. References
12.1. Normative References
12.2. Informative References
Appendix A. Example
Appendix B. Lightweight Implementation Option
Acknowledgments
Authors' Addresses
1. Introduction ๐ง
This doc defines a "secure join" solution for a new device, the "pledge", so it can securely join a 6TiSCH network. "Secure join" is the term for network access authentication, authorization, and parameter distribution, as defined in [RFC9030]. CoJP (the Constrained Join Protocol defined here) handles the parameter distribution a pledge needs in order to become a joined node. Mutual authentication during network access and implicit authorization both come from a secure channel configured according to this doc. The doc also specifies how different layers of the 6TiSCH protocol stack should be configured so there's a smaller Denial of Service (DoS) attack surface during the join process. ๐
This doc assumes a 6TiSCH network as described by [RFC7554] and [RFC8180]. By design, nodes in a 6TiSCH network [RFC7554] keep their radio turned off most of the time to save energy. That means the link a new device uses to join has limited bandwidth [RFC8180], so the secure join solution here keeps the number of over-the-air exchanges to a minimum. ๐
The microcontrollers inside 6TiSCH nodes have tiny amounts of code memory, so reusing existing protocols from the 6TiSCH stack is a must-do vibe ๐ At the application layer, the stack already uses CoAP [RFC7252] for web transfer and OSCORE [RFC8613] for end-to-end security. The secure join solution here reuses both of those protocols as its building blocks. ๐งฉ
CoJP is a generic protocol that can be used as-is in all modes of IEEE Std 802.15.4 [IEEE802.15.4], including the Time-Slotted Channel Hopping (TSCH) mode that 6TiSCH is based on. CoJP may also be used in other low-power networking technologies where communication overhead and code footprint really matter. In that case, companion documents may be needed to define the configuration parameters specific to that technology. The overall process is described in Section 4, and the stack configuration is specific to 6TiSCH. ๐ธ
CoJP assumes there's a Join Registrar/Coordinator (JRC), a central entity. The configuration here assumes that the pledge and the JRC share a unique symmetric cryptographic key, called the PSK (pre-shared key). The PSK configures OSCORE to give CoJP a secure channel. How the PSK gets installed is out of scope for this doc. It might happen during the provisioning phase, or through a key exchange protocol that runs before CoJP. ๐
When a pledge wants to join a 6TiSCH network, it first synchronizes to the network by starting the passive scan defined in [IEEE802.15.4]. Then the pledge exchanges CoJP messages with the JRC. For that end-to-end conversation to work, the messages get forwarded by nodes called Join Proxies, which are already part of the 6TiSCH network. These messages let the JRC and the pledge mutually authenticate, based on the properties OSCORE provides. They also let the JRC configure the pledge with link-layer keying material, a short identifier, and other parameters. Once this secure join process completes successfully, the joined node can talk to its neighbors to request extra bandwidth using the 6TiSCH Operation Sublayer (6top) Protocol [RFC8480], and it can start sending application traffic. ๐ฆ
2. Terminology ๐
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. โจ
The reader is expected to be familiar with the terms and concepts defined in [RFC9030], [RFC7252], [RFC8613], and [RFC8152]. ๐ค
The specification also includes a set of informative specifications using the Concise Data Definition Language (CDDL) [RFC8610]. ๐
These terms, defined in [RFC9030], get used a lot in this doc:
- pledge
- joined node
- Join Proxy (JP)
- Join Registrar/Coordinator (JRC)
- Enhanced Beacon (EB)
- join protocol
- join process
These terms, defined in [RFC8505], are also used throughout:
- 6LoWPAN Border Router (6LBR)
- 6LoWPAN Node (6LN)
The term "6LBR" is used interchangeably with the term "DODAG root" defined in [RFC6550], on the assumption that the two entities are co-located, as recommended by [RFC9030]. ๐
The term "pledge", as used throughout the document, explicitly means non-6LBR devices trying to join the network using their IEEE Std 802.15.4 network interface. A device that tries to join as the 6LBR of the network, and does so over a different network interface, is explicitly called the "6LBR pledge". When the text applies equally to the pledge and the 6LBR pledge, the "(6LBR) pledge" form is used. ๐
We also use the generic terms "pledge identifier" and "network identifier". See Section 3. ๐ซถ
3. Provisioning Phase โจ
okay so before a (6LBR) pledge even tries to join, it needs some parameters loaded in, and the JRC gets the same ones ๐ There are lots of ways to do this. You can write them in with a JTAG (Joint Test Action Group) interface, use a serial (craft) console, push buttons on different devices at the same time, or configure over-the-air inside a Faraday cage ๐ง The vendor, the manufacturer, or the integrator can all be the one doing it, ngl it's giving teamwork.
How the provisioning actually happens is out of scope for this doc ๐ The only assumption is that the JRC and the (6LBR) pledge can have a secure, private chat and swap those parameters ๐
Here's what gets provisioned to the (6LBR) pledge:
- pledge identifier: This identifies the (6LBR) pledge, and it MUST be unique across every pledge identifier that a JRC manages. This uniqueness is a big deal for security, as Section 9 covers ๐จ It's usually the globally unique 64-bit Extended Unique Identifier (EUI-64) of the IEEE Std 802.15.4 device, so the hardware manufacturer provisions it. The pledge identifier is used to build the (6LBR) pledge's IPv6 addresses and to recognize it during the join protocol. Depending on the setup, it can also keep identifying the node after it has joined ๐ฆ For privacy reasons (see Section 10), you can use a pledge identifier that isn't the EUI-64. For example, it could be a random byte string, but you have to make sure that string is still unique, no cap ๐
- Pre-Shared Key (PSK): This is a symmetric cryptographic key that the (6LBR) pledge and the JRC share. To find the PSK for a given pledge, the JRC also needs to store the matching pledge identifier ๐๏ธ Every (6LBR) pledge MUST get its own unique PSK ๐ The PSK MUST be cryptographically strong, with at least 128 bits of entropy, and it has to be indistinguishable by feasible computation from a random uniform string of the same length. Main character energy ๐ How the PSK gets generated or provisioned is out of scope for this spec. It could happen during a provisioning step, or a companion document could specify a key-agreement protocol instead. The common mistakes people make when generating PSKs are covered in Section 9, so go read that ๐ If you're recommissioning a device for a new owner, the PSK MUST be changed ๐ Also, the PSK is NOT the same thing as the link-layer keys K1 and K2 from [RFC8180] ๐ The PSK is a long-term secret that protects the secure join protocol in this document, and the link-layer keys are transported as part of that secure join protocol, so they're different things, iykyk โจ
- Optionally, a network identifier: This identifies the 6TiSCH network. The network identifier MUST be carried within Enhanced Beacon (EB) frames. Typically, the 16-bit Personal Area Network Identifier (PAN ID) defined in [IEEE802.15.4] gets used as the network identifier ๐ธ BUT the PAN ID isn't a stable network identifier, because it can change during the network's lifetime if a collision with another network gets detected ๐ญ Companion documents can specify a different network identifier for join purposes, but that's out of scope here. Provisioning the network identifier to a pledge is RECOMMENDED ๐ Still, due to operational constraints, the network identifier might not be known at provisioning time. If this parameter isn't provisioned to the pledge, the pledge will try to join one advertised network at a time, and that seriously drags out the join process ๐ข This parameter MUST be provisioned to the 6LBR pledge. Non-negotiable ๐
- Optionally, any non-default algorithms: The default algorithms are in Section 7.3.3. If algorithm identifiers aren't provisioned, the defaults are implied ๐ง
Also, a 6LBR pledge that isn't co-located with the JRC needs these extra parameters:
- Global IPv6 address of the JRC: The (6LBR) pledge uses this address to reach the JRC during the join process ๐ It can also find the JRC's IPv6 address through other mechanisms, like DHCPv6 [RFC8415], the Generic Autonomic Signaling Protocol (GRASP) [RFC8990], or Multicast DNS (mDNS) [RFC6762]. Those mechanisms are out of scope for this document ๐ Pledges don't need this address provisioned, though, because they discover it dynamically through CoJP โจ
4. Join Process Overview ๐ฆ
okay this section is the play-by-play of what a pledge does when it wants into a 6TiSCH network ๐ When a pledge wants admission, this exchange happens:
- The pledge listens for an Enhanced Beacon (EB) frame [IEEE802.15.4] ๐ก The frame gives it network synchronization info, like when it can send a frame to whoever's sending the beacons and when it can expect to receive one. That sender acts as a Join Proxy (JP) for the pledge ๐ซถ The EB gives the JP's link-layer address, and it might also give the JP's link-local IPv6 address.
- The pledge configures its link-local IPv6 address and advertises it to the JP with Neighbor Discovery โจ The advertisement step can be skipped if the link-local address was derived from a known unique interface identifier, like an EUI-64 address.
- The pledge sends a Join Request to the JP so it can securely identify itself to the network ๐ The JP forwards that Join Request to the JRC.
- If the request gets processed successfully, the pledge gets a Join Response from the JRC (passed along by the JP) ๐ The Join Response carries the configuration parameters the pledge needs to join the network.
From the pledge's point of view, joining is super local ๐ฅน It only talks to the JP, so it doesn't need to know how far away it is from the 6LBR or how to route to the JRC. It only needs the particulars of the 6TiSCH network after it has set up one or more link-layer keys ๐
Here's the transaction diagram for the join process, Figure 1 ๐
+--------+ +-------+ +--------+
| pledge | | JP | | JRC |
| | | | | |
+--------+ +-------+ +--------+
| | |
|<---Enhanced Beacon (1)---| |
| | |
|<-Neighbor Discovery (2)->| |
| | |
|-----Join Request (3a)----|----Join Request (3a)---->| \
| | | | CoJP
|<----Join Response (3b)---|----Join Response (3b)----| /
| | |
Figure 1: Overview of a successful join process. ๐ธ
As for other nodes in the network, the 6LBR node can act as the JP ๐ง The 6LBR can also be co-located with the JRC, which is giving multitasking ๐
The details of each step are in the sections below ๐
4.1. Step 1 - Enhanced Beacon ๐ก
The pledge syncs to the network by listening for and receiving an EB that a node already in the network sent ๐ฅฐ All of this is fully defined by [IEEE802.15.4] and described in [RFC7554].
Once the pledge hears an EB, it syncs to the joining schedule using the cells in that EB ๐ฆ The pledge can hear multiple EBs, and choosing which one to use is out of scope for this document. It's discussed in [RFC7554] ๐ Implementers should make use of info like this: which network identifier the EB has, the value of the Join Metric field in EBs, whether the EB's source link-layer address has been tried before, and the signal strength each EB arrived at, etc. The pledge can also be preconfigured to look for EBs with a specific network identifier ๐ฏ
If the pledge doesn't have a network identifier provisioned, it tries to join one network at a time, as described in Section 8.1.1 ๐
Once the pledge picks an EB, it syncs to it and drops into a low-power mode ๐ด It follows the schedule in the EB, which shows the slots the pledge can use for the join process. While the rest of the join process is happening, the node that sent the EB acts as the JP ๐ซถ
At this point, the pledge can either move on to step 2 or keep listening for more EBs โจ
4.2. Step 2 - Neighbor Discovery ๐
The pledge builds its link-local IPv6 address from the interface identifier, per [RFC4944] ๐ง The pledge MAY do the Neighbor Solicitation / Neighbor Advertisement exchange with the JP, per Section 5.6 of [RFC8505] ๐ Per [RFC8505], there's no need to run duplicate address detection for the link-local address, so skip that ๐ The pledge and the JP use their link-local IPv6 addresses for everything else in the join process.
Heads up: Neighbor Discovery exchanges at this stage aren't protected with link-layer security, because the pledge doesn't have the keys yet ๐ญ How the JP accepts these unprotected frames is covered in Section 5 ๐
4.3. Step 3 - Constrained Join Protocol (CoJP) Execution ๐
The pledge kicks off the join exchange of the Constrained Join Protocol (CoJP) ๐ The join exchange has two messages: the Join Request (Step 3a, Section 4.3.1) and the Join Response, which only happens if the security processing of the request succeeds (Step 3b, Section 4.3.2) โจ
All CoJP messages go over a secure end-to-end channel that gives confidentiality, data authenticity, and replay protection ๐ก๏ธ Frames that carry CoJP messages aren't protected with link-layer security between the pledge and the JP, because the pledge doesn't have the link-layer keys in use yet ๐ How the JP and pledge accept these unprotected frames is covered in Section 5. Once nodes that have already joined the network exchange frames carrying CoJP messages, link-layer security gets applied based on the network's security configuration ๐
4.3.1. Step 3a - Join Request ๐จ
The Join Request is a message the pledge sends to the JP, and the JP forwards it to the JRC ๐ In the Join Request, the pledge says what role it wants to play in the network and the identifier of the network it wants to join ๐ฏ The JP forwards the Join Request to the JRC over the existing links. How that actually happens is out of scope for this document, but some networks might want to set aside specific link-layer resources for this join traffic ๐ฆ
4.3.2. Step 3b - Join Response ๐
okay so the Join Response is the JRC's reply to the pledge, and it gets forwarded through the JP ๐ฆ. The packet travels from the JRC to the JP over the operating routes in the network, and then the JP delivers it to the pledge. The JP is an application-layer proxy here, so check Section 7 for the deets ๐ซถ
The Join Response is packed with everything the pledge needs to become a fully operational network node ๐ That includes the link-layer key(s) currently in use in the network, the short address assigned to the pledge, and the IPv6 address of the JRC (which the pledge needs so it can operate as a JP later), plus some other bits โจ
4.4. The Special Case of the 6LBR Pledge Joining ๐ง
the 6LBR pledge does Section 4.3 of the join process just like any other pledge, just over a different network interface ๐ There's no JP in the middle between the 6LBR pledge and the JRC, as described in Section 6 ๐ The other steps of the join process don't apply to the 6LBR pledge. How the 6LBR pledge gets an IPv6 address and kicks off CoJP is out of scope for this document ๐คทโโ๏ธ
5. Link-Layer Configuration ๐
okay the big thing in an operational 6TiSCH network is that all frames use link-layer frame security [RFC8180] ๐ The IEEE Std 802.15.4 security attributes include frame authenticity and, optionally, frame confidentiality (aka encryption) ๐
Any node sending EB frames MUST be prepared to act as a JP for potential pledges ๐
The pledge doesn't do an authenticity check on EB frames at first, because it doesn't have the link-layer key(s) in use yet ๐ It can still parse the contents of the EBs and sync to the network, since EBs aren't encrypted [RFC8180] โจ
When the pledge sends frames during the join, it sends them unencrypted and unauthenticated at the link layer ๐ซ So for the join to even be possible, the JP has to accept these unsecured frames for the whole duration of the join ๐ช This can be done by setting the secExempt attribute in the IEEE Std 802.15.4 security configuration tables. The lower layer is expected to give the upper layer a way to tell that unsecured frames are coming in from a device. The upper layer can use that info to figure out that a join is in progress and that the unsecured frames should be processed. How the JP makes that call and talks to the lower layer is out of scope for this spec ๐
The JP can also look at stuff like the value of the join rate parameter (Section 8.4.2) set by the JRC, a physical button press, etc ๐
When the pledge first syncs with the network, it has no means of verifying the authenticity of EB frames. Because an attacker can craft a frame that looks like a legit EB frame, this opens up a DoS vector, as discussed in Section 9 ๐ฑ
heads up bestie: this is the sneaky part. Anyone can forge something that looks like a real EB, so the pledge can't just trust what it hears during that first sync. Read Section 9 ๐ซถ
5.1. Distribution of Time โฐ
Nodes in a 6TiSCH network keep a global notion of time known as the Absolute Slot Number โจ It's used in building the link-layer nonce, as defined in [IEEE802.15.4]. The pledge first syncs with the EB frame sent by the JP and takes the Absolute Slot Number value from the TSCH Synchronization Information Element. At the moment of sync, the EB frame can neither be authenticated nor have its freshness verified ๐ฅบ During the join, the pledge sends frames that are unprotected at the link layer but protected end-to-end instead. The pledge doesn't get the time info as the output of the join process, because that info is local to the network and may not be known at the JRC โณ
This enables an attack on the pledge ๐ค The attacker replays legit EB frames obtained from the network to the pledge and acts as a man-in-the-middle between the pledge and the JP. Those EB frames make the pledge believe the replayed Absolute Slot Number value is the current notion of time in the network. By forwarding the join traffic to the legitimate JP, the attacker lets the pledge join the network. Depending on conditions around the JRC reusing the pledge's short address or the pledge trying to rejoin, this may cause the pledge to reuse the link-layer nonce in the first frame it sends protected after the join process is completed ๐
For this reason, all frames originated at the JP and destined to the pledge during the join process MUST be authenticated at the link layer using the key that is normally in use in the network ๐ Link-layer security processing at the pledge for these frames will fail, because the pledge doesn't have the key yet ๐ The pledge acknowledges these frames without link-layer security, and the JP accepts the unsecured acknowledgment thanks to the secExempt attribute set for the pledge. The frames should be passed to the upper layer for processing using the promiscuous mode of [IEEE802.15.4] or another appropriate mechanism ๐ซง When the upper-layer processing on the pledge is completed and the link-layer keys are configured, the upper layer MUST trigger the security processing of the corresponding frame ๐ Once the security processing of the frame carrying the Join Response message is successful, the current Absolute Slot Number kept locally at the pledge SHALL be declared as valid ๐
6. Network-Layer Configuration ๐
The pledge and the JP SHOULD keep a separate neighbor cache for untrusted entries, and use it to store each other's information during the join process ๐๏ธ Mixing neighbor entries belonging to pledges with nodes that are part of the network opens up the JP to a DoS attack, because the attacker can fill the JP's neighbor table and block the discovery of legitimate neighbors ๐ฌ
Once the pledge obtains link-layer keys and becomes a joined node, it can securely communicate with its neighbors, obtain the network IPv6 prefix, and form its global IPv6 address ๐ The joined node then goes through an independent process to bootstrap its neighbor cache entries, possibly with a node that formerly acted as a JP, following [RFC8505]. From the point of view of the JP, there's no relationship between the neighbor cache entry belonging to a pledge and the joined node that formerly acted as a pledge ๐
The pledge doesn't communicate with the JRC at the network layer ๐ This lets the pledge join without knowing the IPv6 address of the JRC. Instead, the pledge talks to the JP at the network layer using link-local addressing, and talks to the JRC at the application layer, as specified in Section 7 ๐
The JP communicates with the JRC over global IPv6 addresses ๐ The JP discovers the network IPv6 prefix and configures its global IPv6 address upon successful completion of the join process and the obtention of link-layer keys. The pledge learns the IPv6 address of the JRC from the Join Response, as specified in Section 8.1.2, and uses it once joined in order to operate as a JP ๐ฆ
As a special case, the 6LBR pledge may have an additional network interface that it uses to obtain configuration parameters from the JRC and to start advertising the 6TiSCH network ๐ก This additional interface needs to be configured with a global IPv6 address, by a mechanism that is out of scope of this document. The 6LBR pledge uses this interface to directly communicate with the JRC using global IPv6 addressing ๐
The JRC can be co-located on the 6LBR ๐ In this special case, the IPv6 address of the JRC can be omitted from the Join Response message for space optimization ๐ชถ The 6LBR then MUST set the DODAGID field in the RPL DODAG Information Objects (DIOs) [RFC6550] to its IPv6 address. The pledge learns the address of the JRC once it's joined and upon receiving the first RPL DIO message, and then uses it to operate as a JP ๐ธ
6.1. Identification of Unauthenticated Traffic ๐ต๏ธโโ๏ธ
The traffic proxied by the JP comes from unauthenticated pledges, and there may be an arbitrary amount of it ๐ฆ In particular, an attacker may send fraudulent traffic in an attempt to overwhelm the network ๐ช๏ธ
When operating as part of a 6TiSCH minimal network [RFC8180] using distributed scheduling algorithms, the traffic from unauthenticated pledges may cause intermediate nodes to request additional bandwidth. An attacker could use this property to cause the network to overcommit bandwidth (and energy) to the join process ๐ค
The JP is aware of what traffic originates from unauthenticated pledges, so it can avoid allocating additional bandwidth itself ๐ง The JP implements a data cap on outgoing join traffic by implementing the recommendation of 1 packet per 3 seconds in Section 3.1.3 of [RFC8085]. This can be achieved with the congestion control mechanism specified in Section 4.7 of [RFC7252]. This cap will not protect intermediate nodes, because they cannot tell join traffic from regular traffic ๐ Despite the data cap implemented separately on each JP, the aggregate join traffic from many JPs may cause intermediate nodes to decide to allocate additional cells. It's undesirable to do so in response to traffic originated from unauthenticated pledges ๐ซ To let intermediate nodes avoid this, the traffic needs to be tagged ๐ท๏ธ [RFC2597] defines a set of per-hop behaviors that may be encoded into the Diffserv Code Points (DSCPs). Based on the DSCP, intermediate nodes can decide whether to act on a given packet โจ
6.1.1. Traffic from JP to JRC ๐ค
The JP SHOULD set the DSCP of packets that it produces as part of the forwarding process to the AF43 code point (See Section 6 of [RFC2597]). A JP that does not require a specific DSCP value on forwarded traffic should set it to zero so that it is compressed out ๐๏ธ
A Scheduling Function (SF) running on 6TiSCH nodes SHOULD NOT allocate additional cells as a result of traffic with code point AF43 ๐
โโ๏ธ Companion SF documents SHOULD specify how this recommended behavior is achieved ๐
6.1.2. Traffic from JRC to JP ๐ฅ
The JRC SHOULD set the DSCP of Join Response packets addressed to the JP to the AF42 code point ๐
AF42 has a lower drop probability than AF43, giving this traffic priority in buffers over the traffic going towards the JRC ๐
The 6LBR links are often the most congested within a DODAG, and from that point down, there is progressively less (or equal) congestion ๐ If the 6LBR paces itself when sending Join Response traffic, then it ought to never exceed the bandwidth allocated to the best effort traffic cells. If the 6LBR has the capacity (if it is not constrained), then it should provide some buffers in order to satisfy the Assured Forwarding behavior ๐ซง
Companion SF documents SHOULD specify how traffic with code point AF42 is handled with respect to cell allocation ๐ If the recommended behavior described in this section is not followed, the network may become prone to the attack discussed in Section 6.1. ๐
7. Application-Layer Configuration ๐
okay so the CoJP join exchange in Figure 1 rides on CoAP [RFC7252] and gets its secure channel from OSCORE [RFC8613] ๐ the (6LBR) pledge is the CoAP client and the JRC is the CoAP server ๐ the JP implements CoAP forward proxy functionality [RFC7252], and since the JP can also be a constrained device, it cannot implement a cache ๐
the pledge tells the JP it wants it as a proxy by including the Proxy-Scheme option in the CoAP requests it sends to the JP โจ it also adds the Uri-Host option, with its value set to the well-known JRC's alias from Section 8.1.1 ๐
the JP resolves that alias to the IPv6 address of the JRC it learned when it acted as a pledge and joined the network ๐ฆ this is what lets the JP reach the JRC at the network layer and forward the requests on behalf of the pledge. main character energy for the JP ๐
7.1. Statelessness of the JP
the CoAP proxy from [RFC7252] keeps per-client state so it can send the response back toward whoever originally asked ๐ง that state includes at least the CoAP token, the IPv6 address of the client, and the UDP source port number. and bestie, since the JP can be a constrained device that acts as a CoAP proxy, its memory is limited, which makes it prone to a DoS attack ๐ญ
this DoS vector on the JP can be mitigated by making the JP act as a stateless CoAP proxy ๐ก๏ธ here "state" means all the info tied to individual pledges. the JP can wrap the state it needs for a given pledge throughout the network stack in a "state object" and include it as a CoAP token in the forwarded request to the JRC ๐ the JP MAY use the CoAP token as defined in [RFC7252] if the size of the serialized state object permits, or use the extended CoAP token defined in [RFC8974] to carry the state object. the JRC and any other potential proxy on the JP-JRC path MUST support extended token lengths, as defined in [RFC8974] ๐งฉ since the CoAP token gets echoed back in the response, the JP can decode the state object and set up what it needs to forward the response to the pledge ๐ what the JP has to encode in the state object to work fully statelessly for a given pledge is implementation specific ๐ธ
It is RECOMMENDED that the JP operates in a stateless manner and signals the per-pledge state within the CoAP token for every request that it forwards into the network on behalf of unauthenticated pledges ๐ when the JP is stateless, the security considerations from [RFC8974] apply, and the type of CoAP message that the JP forwards on behalf of the pledge MUST be non-confirmable (NON), no matter what message type it received from the pledge ๐ซ using a non-confirmable message means the JP doesn't have to keep CoAP message exchange state, so the retransmission burden is entirely shifted to the pledge ๐ซถ a JP that operates statelessly still needs to keep congestion control state with the JRC, see Section 9 ๐ recommended CoAP settings for the join process, for both the pledge and the JP, are in Section 7.2.
ngl, a fully (per-pledge) stateless JP can be tricky to build in some networking stack implementations ๐งต in those cases, the JP may act as a stateful proxy that stores the per-pledge state until the response arrives or times out. but yep, that comes at the price of a DoS vector ๐
7.2. Recommended Settings
this section gives RECOMMENDED values of CoAP settings during the join process ๐
+===================+===============+
| Name | Default Value |
+===================+===============+
| ACK_TIMEOUT | 10 seconds |
+-------------------+---------------+
| ACK_RANDOM_FACTOR | 1.5 |
+-------------------+---------------+
| MAX_RETRANSMIT | 4 |
+-------------------+---------------+
| NSTART | 1 |
+-------------------+---------------+
| DEFAULT_LEISURE | 5 seconds |
+-------------------+---------------+
| PROBING_RATE | 1 byte/second |
+-------------------+---------------+
Table 1: Recommended CoAP settings.
these values can be configured to suit the deployment ๐ฏ the defaults were picked to work across a wide range of deployments, including dense networks ๐๏ธ
the PROBING_RATE at the JP is controlled by the join rate parameter, see Section 8.4.2 ๐ซ following [RFC7252], the average data rate when sending to the JRC must not exceed PROBING_RATE. for security reasons, the average data rate SHOULD be measured over a rather short window, e.g., ACK_TIMEOUT, see Section 9 โฑ๏ธ
7.3. OSCORE
before the (6LBR) pledge and the JRC start swapping CoAP messages protected with OSCORE, they need to derive the OSCORE security context from the provisioned parameters, as discussed in Section 3 ๐
the OSCORE security context MUST be derived per Section 3 of [RFC8613] ๐งช
- The Master Secret MUST be the PSK. ๐๏ธ
- The Master Salt MUST be the empty byte string. ๐ซง
- The ID Context MUST be set to the pledge identifier. ๐ชช
- The ID of the pledge MUST be set to the empty byte string. This identifier is used as the OSCORE Sender ID of the pledge in the security context derivation, since the pledge initially acts as a CoAP client. ๐โโ๏ธ
- The ID of the JRC MUST be set to the byte string
0x4a5243("JRC"in ASCII). This identifier is used as the OSCORE Recipient ID of the pledge in the security context derivation, as the JRC initially acts as a CoAP server. ๐ง - The Algorithm MUST be set to the value from [RFC8152], agreed to out-of-band by the same mechanism used to provision the PSK. The default is AES-CCM-16-64-128. ๐
- The key derivation function MUST be agreed out-of-band by the same mechanism used to provision the PSK. Default is HKDF SHA-256 [RFC5869]. ๐
since the pledge's OSCORE Sender ID is the empty byte string, when building the OSCORE option the pledge sets the kid flag in the OSCORE flag bits but indicates a 0-length kid ๐ค the pledge carries its pledge identifier in the kid context field of the OSCORE option. the derivation in [RFC8613] gives OSCORE keys and a Common Initialization Vector (IV) for each side of the conversation ๐ถ nonces are built by XORing the Common IV with the current sequence number. for the nitty-gritty on nonce and OSCORE option construction, check [RFC8613] ๐
Implementations MUST ensure that multiple CoAP requests, including ones to different JRCs, properly increment the sequence numbers, so the same sequence number is never reused in distinct requests protected under the same PSK ๐จ the pledge typically sends requests to different JRCs if it isn't provisioned with the network identifier and tries to join one network at a time. if they don't comply, the AEAD algorithm's security guarantees break because of nonce reuse ๐
this OSCORE security context is used for the initial joining of the (6LBR) pledge, where the pledge acts as a CoAP client, and also for any later parameter updates, where the JRC acts as a CoAP client and the joined node acts as a CoAP server, as discussed in Section 8.2 ๐ when the pledge and the JRC swap roles between CoAP client and CoAP server, the same OSCORE security context as initially derived stays in use, and the derived parameters don't change (like the Sender ID when sending and the Recipient ID when receiving, see Section 3.1 of [RFC8613]) ๐งท a (6LBR) pledge is expected to have exactly one OSCORE security context with the JRC ๐
7.3.1. Replay Window and Persistency
both the (6LBR) pledge and the JRC MUST implement a replay-protection mechanism ๐ using the default OSCORE replay-protection mechanism from Section 3.2.2 of [RFC8613] is RECOMMENDED ๐
Implementations MUST ensure that mutable OSCORE context parameters (Sender Sequence Number, Replay Window) are stored in persistent memory ๐พ a technique from Appendix B.1.1 of [RFC8613] that prevents reuse of sequence numbers MUST be implemented. every update to the OSCORE Replay Window MUST be written to persistent memory โ๏ธ
this is a big deal bestie. it's how you guarantee nonce uniqueness and resistance to replay attacks across reboots and rejoins ๐จ
traffic between the (6LBR) pledge and the JRC is rare, so security outweighs the cost of writing to persistent memory ๐ซถ
7.3.2. OSCORE Error Handling
Errors raised by OSCORE during the join process MUST be silently dropped, with no error response being signaled ๐คซ the pledge MUST silently discard any response that isn't protected with OSCORE, including error codes ๐ โโ๏ธ
these errors can happen for a bunch of reasons, like a failed lookup of an appropriate security context (for example, the pledge trying to join the wrong network), failed decryption, a positive Replay Window lookup, or formatting errors (maybe from malicious alterations in transit) ๐ silently dropping OSCORE messages blocks a DoS attack on the pledge, where an attacker could send bogus error responses to force the pledge to try joining one network at a time until every network has been tried ๐ก๏ธ๐
7.3.3. Mandatory-to-Implement Algorithms
the mandatory-to-implement AEAD algorithm for OSCORE is AES-CCM-16-64-128 from [RFC8152] ๐ it's the algorithm used for securing IEEE Std 802.15.4 frames, and hardware acceleration for it is present in virtually all compliant radio chips ๐ก with this choice, CoAP messages are protected with an 8-byte CCM authentication tag, and the algorithm uses 13-byte long nonces ๐ง
the mandatory-to-implement hash algorithm is SHA-256 [RFC4231] ๐ธ the mandatory-to-implement key derivation function is HKDF [RFC5869], instantiated with a SHA-256 hash โจ see Appendix B for implementation guidance when code footprint is important ๐ง
8. Constrained Join Protocol (CoJP) โจ
okay bestie, CoJP is a lightweight protocol that runs over CoAP [RFC7252] and a secure channel from OSCORE [RFC8613] ๐ It lets a (6LBR) pledge ask to get into a network that the JRC manages ๐ฆ Then the JRC hands the pledge the parameters it needs. The JRC can also update those parameters later, by reaching out to the joined node that used to be a (6LBR) pledge. For example, network-wide rekeying happens by updating the keying material on each node ๐
CoJP leans on OSCORE's security properties, and it's iconic ๐ซถ That means end-to-end confidentiality, data authenticity, replay protection, and a secure binding of responses to requests.
+-----------------------------------+
| Constrained Join Protocol (CoJP) |
+-----------------------------------+
+-----------------------------------+ \
| Requests / Responses | |
|-----------------------------------| |
| OSCORE | | CoAP
|-----------------------------------| |
| Messaging Layer | |
+-----------------------------------+ /
+-----------------------------------+
| UDP |
+-----------------------------------+
Figure 2: Abstract layering of CoJP.
When a (6LBR) pledge requests admission to a given network, it goes through the CoJP join exchange, which has two parts:
- The Join Request message, sent by the (6LBR) pledge to the JRC, potentially proxied by the JP. The Join Request message and its mapping to CoAP is specified in Section 8.1.1.
- The Join Response message, sent by the JRC to the (6LBR) pledge, if the JRC successfully processes the Join Request using OSCORE and it determines through a mechanism that is out of scope of this specification that the (6LBR) pledge is authorized to join the network. The Join Response message is potentially proxied by the JP. The Join Response message and its mapping to CoAP is specified in Section 8.1.2.
When the JRC needs to update the parameters of a joined node that formerly acted as a (6LBR) pledge, it runs the CoJP parameter update exchange, which is just one message:
- The Parameter Update message, sent by the JRC to the joined node that formerly acted as a (6LBR) pledge. The Parameter Update message and its mapping to CoAP is specified in Section 8.2.1.
The payload of CoJP messages is encoded with CBOR [RFC8949]. The CBOR data structures that may appear as the payload of different CoJP messages are specified in Section 8.4.
8.1. Join Exchange
This section specifies the messages exchanged when the (6LBR) pledge requests admission and configuration parameters from the JRC.
8.1.1. Join Request Message
The Join Request message that the (6LBR) pledge sends SHALL be mapped to a CoAP request:
- The request method is
POST. - The type is Confirmable (
CON). - The
Proxy-Schemeoption is set to"coap". - The
Uri-Hostoption is set to"6tisch.arpa". This is an anycast type of identifier of the JRC that is resolved to its IPv6 address by the JP or the 6LBR pledge. - The
Uri-Pathoption is set to"j". - The
OSCOREoption SHALL be set according to [RFC8613]. The OSCORE security context used is the one derived in Section 7.3. The OSCORE'kid context'allows the JRC to retrieve the security context for a given pledge. - The payload is a
Join_RequestCBOR object, as defined in Section 8.4.1.
Since the Join Request is a confirmable message, the transmission at (6LBR) pledge will be controlled by CoAP's retransmission mechanism. The JP, when operating in a stateless manner, forwards this Join Request as a non-confirmable (NON) CoAP message, as specified in Section 7. If the CoAP implementation at the (6LBR) pledge declares the message transmission a failure, the (6LBR) pledge SHOULD attempt to join a 6TiSCH network advertised with a different network identifier. See Section 7.2 for recommended values of CoAP settings to use during the join exchange.
If all join attempts to advertised networks have failed, the (6LBR) pledge SHOULD signal the presence of an error condition, through some out-of-band mechanism.
BCP 190 [RFC8820] provides guidelines on URI design and ownership. It recommends that whenever a third party wants to mandate a URI to web authority that it SHOULD go under "/.well-known" (per [RFC8615]). In the case of CoJP, the Uri-Host option is always set to "6tisch.arpa", and based upon the recommendations in Section 1 of [RFC8820], it is asserted that this document is the owner of the CoJP service. As such, the concerns of [RFC8820] do not apply, and thus the Uri-Path is only "j".
8.1.2. Join Response Message
The Join Response message that the JRC sends SHALL be mapped to a CoAP response:
- The Response Code is
2.04 (Changed). - The payload is a
ConfigurationCBOR object, as defined in Section 8.4.2.
8.2. Parameter Update Exchange
During the network lifetime, parameters returned as part of the Join Response may need to be updated. One typical example is the update of link-layer keying material for the network, a process known as rekeying. This section specifies a generic mechanism when this parameter update is initiated by the JRC.
At the time of the join, the (6LBR) pledge acts as a CoAP client and requests the network parameters through a representation of the "/j" resource exposed by the JRC. In order for the update of these parameters to happen, the JRC needs to asynchronously contact the joined node. The use of the CoAP Observe option for this purpose is not feasible due to the change in the IPv6 address when the pledge becomes the joined node and obtains a global address.
Instead, once the (6LBR) pledge receives and successfully validates the Join Response and so becomes a joined node, it becomes a CoAP server. The joined node creates a CoAP service at the Uri-Host value of "6tisch.arpa", and the joined node exposes the "/j" resource that is used by the JRC to update the parameters. Consequently, the JRC operates as a CoAP client when updating the parameters. The request/response exchange between the JRC and the (6LBR) pledge happens over the already-established OSCORE secure channel.
8.2.1. Parameter Update Message
The Parameter Update message that the JRC sends to the joined node SHALL be mapped to a CoAP request:
- The request method is
POST. - The type is Confirmable (
CON). - The
Uri-Hostoption is set to"6tisch.arpa". - The
Uri-Pathoption is set to"j". - The
OSCOREoption SHALL be set according to [RFC8613]. The OSCORE security context used is the one derived in Section 7.3. When a joined node receives a request with the Sender ID set to0x4a5243(ID of the JRC), it is able to correctly retrieve the security context with the JRC. - The payload is a
ConfigurationCBOR object, as defined in Section 8.4.2.
The JRC has implicit knowledge of the global IPv6 address of the joined node, as it knows the pledge identifier that the joined node used when it acted as a pledge and the IPv6 network prefix. The JRC uses this implicitly derived IPv6 address of the joined node to directly address CoAP messages to it.
If the JRC does not receive a response to a Parameter Update message, it attempts multiple retransmissions as configured by the underlying CoAP retransmission mechanism triggered for confirmable messages. Finally, if the CoAP implementation declares the transmission a failure, the JRC may consider this as a hint that the joined node is no longer in the network. How the JRC decides when to stop attempting to contact a previously joined node is out of scope of this specification, but the security considerations on the reuse of assigned resources apply, as discussed in Section 9.
8.3. Error Handling
8.3.1. CoJP CBOR Object Processing
CoJP CBOR objects are transported within both CoAP requests and responses. This section describes handling the cases in which certain CoJP CBOR object parameters are not supported by the implementation or their processing fails. See Section 7.3.2 for the handling of errors that may be raised by the underlying OSCORE implementation.
When such a parameter is detected in a CoAP request (Join Request message, Parameter Update message), a Diagnostic Response message MUST be returned. A Diagnostic Response message maps to a CoAP response and is specified in Section 8.3.2.
When a parameter that cannot be acted upon is encountered while processing a CoJP object in a CoAP response (Join Response message), a (6LBR) pledge SHOULD reattempt to join. In this case, the (6LBR) pledge SHOULD include the Unsupported Configuration CBOR object within the Join Request object in the following Join Request message. The Unsupported Configuration CBOR object is self-contained and enables the (6LBR) pledge to signal any parameters that the implementation of the networking stack may not support. A (6LBR) pledge MUST NOT attempt more than COJP_MAX_JOIN_ATTEMPTS number of attempts to join if the processing of the Join Response message fails each time. If the COJP_MAX_JOIN_ATTEMPTS number of attempts is reached without success, the (6LBR) pledge SHOULD signal the presence of an error condition through some out-of-band mechanism.
Note that COJP_MAX_JOIN_ATTEMPTS relates to the application-layer handling of the CoAP response and is different from CoAP's MAX_RETRANSMIT setting, which drives the retransmission mechanism of the underlying CoAP message.
8.3.2. Diagnostic Response Message
The Diagnostic Response message is returned for any CoJP request when the processing of the payload failed. The Diagnostic Response message is protected by OSCORE as any other CoJP message.
The Diagnostic Response message SHALL be mapped to a CoAP response:
- The Response Code is
4.00 (Bad Request). - The payload is an
Unsupported ConfigurationCBOR object, as defined in Section 8.4.5, containing more information about the parameter that triggered the sending of this message.
8.3.3. Failure Handling โจ
okay so the parameter update exchange can happen literally any time during the network's life, and that can span several YEARS ๐ญ. Over that long, stuff can go sideways. A joined node or the JRC might reboot or straight up die ๐.
This document says the mutable parameters in the security context have to get written to persistent memory (see Section 7.3.1) by both the JRC and the pledges (joined nodes) ๐ซถ. Pledges are usually little constrained devices that handle those writes in a predictable way, so their mutable security-context parameters can be retrieved after a reboot. That means no risk of AEAD nonce reuse from reinitialized Sender Sequence Numbers, and no replay attack from a reinitialized Replay Window ๐ก๏ธ. The JRC is a different story. It may be running on a generic machine, where writes to persistent memory can get unpredictable delays because of caching ๐. If the JRC reboots before that cached data is written out, the mutable security-context parameters are likely lost, and that poses the risk of AEAD nonce reuse ๐ฑ.
If a complete device failure happens and the mutable security-context parameters can't be retrieved, it's expected that the failed joined node gets replaced with a brand new physical device, using a new pledge identifier and a PSK ๐. When the failure hits the JRC, the static info on provisioned pledges, like PSKs and pledge identifiers, might be recoverable through backups ๐พ. But the info about joined nodes (their assigned short identifiers and mutable security-context parameters) is likely gone. If that's the case, the network administrator MUST force all the networks managed by the failed JRC to rejoin through out-of-band means during the JRC reinitialization. For example, reinitialize the 6LBR nodes and freshly generate dynamic cryptographic keys and other parameters that influence the security properties of the network ๐.
Yes, this is the scary part bestie. A failed JRC with lost joined-node info means the whole network has to rejoin the hard way. ๐ญ
To recover from that kind of failure, the reinitialized JRC can kick off a renegotiation of the OSCORE security context using the procedure in Appendix B.2 of [RFC8613] ๐. Since it knows about the failure, the reinitialized JRC answers the first Join Request from each pledge it manages with a 4.01 (Unauthorized) error and a random nonce ๐ฒ. The pledge checks that error response, then starts the CoJP join exchange with a new OSCORE security context derived from an ID Context. That ID Context is the concatenation of two nonces: one the pledge got from the JRC, and one the pledge generated locally ๐งฉ. After the JRC verifies the Join Request with the new ID Context and the derived OSCORE security context, the JRC should consequently map the new ID Context to the previously used pledge identifier ๐บ๏ธ. How the JRC handles that mapping is out of scope for this document.
Using the procedure in Appendix B.2 of [RFC8613] is RECOMMENDED for handling these failure events, or any other event that could lead to the loss of mutable security-context parameters ๐ . The nonces exchanged using this procedure MUST be at least 8 bytes long ๐.
The procedure needs both the pledge and the JRC to have good sources of randomness ๐ฐ. That's usually not a problem on the JRC side, but the constrained device hosting the pledge might have limitations here ๐ฅบ. If the pledge doesn't support the procedure outlined in Appendix B.2 of [RFC8613], the network administrator MUST reprovision the concerned devices with freshly generated parameters through out-of-band means ๐งพ.
8.4. CoJP Objects ๐ง
This section lays out the structure of the CoJP CBOR objects that can be carried as the payload of CoJP messages ๐. Some of these objects can be received either during the CoJP join exchange, when the device is operating as a (CoJP) pledge, or during the parameter update exchange, when the device is operating as a joined (6LBR) node ๐.
8.4.1. Join Request Object ๐ธ
The Join_Request structure is built on a CBOR map object ๐บ๏ธ.
The parameters that can show up in a Join_Request object are summarized below. The labels can be found in the "Constrained Join Protocol (CoJP) Parameters" registry, Section 11.1 ๐.
- role: The identifier of the role the pledge wants to play in the network once it joins, encoded as an unsigned integer ๐. The possible values are in Table 3. This parameter MAY be included. If it's omitted, the default value of 0, i.e., the role "6TiSCH Node", MUST be assumed ๐.
- network identifier: The identifier of the network, as discussed in Section 3, encoded as a CBOR byte string ๐. When it's present in the Join_Request, it hints to the JRC which network the pledge wants to join, which lets the JRC manage multiple networks ๐ฆ. The pledge gets the value of the network identifier from the received EB frames. This parameter MUST be included in a Join_Request object no matter what the role parameter value is ๐.
- unsupported configuration: The identifier of the parameters that the implementation doesn't support, encoded as an Unsupported_Configuration object, described in Section 8.4.5 ๐. This parameter MAY be included. If a (6LBR) pledge previously tried to join and got a valid Join Response message over OSCORE but couldn't act on its payload (Configuration object), it SHOULD include this parameter to help with recovery and debugging ๐.
Table 2 sums up the parameters that may appear in a Join_Request object ๐.
+===========================+=======+==================+
| Name | Label | CBOR Type |
+===========================+=======+==================+
| role | 1 | unsigned integer |
+---------------------------+-------+------------------+
| network identifier | 5 | byte string |
+---------------------------+-------+------------------+
| unsupported configuration | 8 | array |
+---------------------------+-------+------------------+
Table 2: Summary of Join_Request parameters.
Here's the CDDL fragment that represents the text above for the Join_Request ๐ง:
Join_Request = {
? 1 : uint, ; role
5 : bstr, ; network identifier
? 8 : Unsupported_Configuration ; unsupported configuration
}
+========+=======+==============================+===========+
| Name | Value | Description | Reference |
+========+=======+==============================+===========+
| 6TiSCH | 0 | The pledge requests to play | RFC 9031 |
| Node | | the role of a regular 6TiSCH | |
| | | node, i.e., non-6LBR node. | |
+--------+-------+------------------------------+-----------+
| 6LBR | 1 | The pledge requests to play | RFC 9031 |
| | | the role of 6LoWPAN Border | |
| | | Router (6LBR). | |
+--------+-------+------------------------------+-----------+
Table 3: Role values.
8.4.2. Configuration Object โจ
okay so the Configuration structure is built on a CBOR map object ๐ and there's a whole lineup of parameters that can live inside it ๐ . You can look up the labels in the "Constrained Join Protocol (CoJP) Parameters" registry, which is Section 11.1, so bookmark that bestie ๐
link-layer key set: this is an array full of cryptographic keys and their identifiers ๐ that are either being used in the network right now or are scheduled to be used later. Individual keys are encoded as described in Section 8.4.3. The link-layer key set parameter MAY be included in a Configuration object. When it's there, it MUST contain at least one key ๐ซถ. This parameter is also how rekeying gets done in the network ๐ The installation and use of keys is different for the 6LBR and for other (regular) nodes, and Sections 8.4.3.1 and 8.4.3.2 explain it all.
short identifier: a compact identifier assigned to the pledge ๐ง The structure is described in Section 8.4.4. The short identifier parameter MAY be included in a Configuration object ๐ธ
JRC address: this is the IPv6 address of the JRC, encoded as a byte string that's exactly 16 bytes long ๐ If the byte string is any other length, the parameter MUST be discarded ๐ If the JRC is NOT co-located with the 6LBR and has a different IPv6 address than the 6LBR, this parameter MUST be included. In the special case where the JRC is co-located with the 6LBR and has the same IPv6 address as the 6LBR, this parameter MAY be included. And if the JRC address parameter isn't in the Configuration object at all, that means the JRC has the same IPv6 address as the 6LBR ๐ฆ The joined node can then find the JRC's address through network control traffic. See Section 6.
blacklist: this is an array of pledge identifiers that the JRC has blacklisted ๐ซ, with each pledge identifier encoded as a byte string. The blacklist parameter MAY be included in a Configuration object. When it's present, the array MUST contain zero or more byte strings encoding pledge identifiers. The joined node MUST silently drop any link-layer frames that come from the pledge identifiers in the blacklist parameter ๐คซ When this parameter is received, its value MUST overwrite any previously set values, so the newest list wins ๐ This is how the JRC lets the JP node filter out traffic from misconfigured or malicious pledges before it gets forwarded into the network ๐ก๏ธ And if the JRC wants to take a pledge identifier off the blacklist, it just leaves that identifier out of the blacklist parameter value it sends next.
Heads up: since the blacklist parameter carries pledge identifiers, privacy considerations apply ๐ Go read Section 10 before you do anything with it, seriously.
join rate: this is the average data rate (in bytes/second) of join traffic forwarded into the network, encoded as an unsigned integer ๐ It's the limit that shouldn't be exceeded when a joined node is operating as a JP. The join rate parameter MAY be included in a Configuration object. It lets the JRC set up different nodes in the network as JPs and, if there's an attack, throttle how fast the JP forwards unauthenticated traffic into the network ๐ฆ When this parameter is present in a Configuration object, its value MUST be used to set the PROBING_RATE of CoAP at the joined node for communication with the JRC โ๏ธ If this parameter is set to zero, a joined node MUST silently drop any join traffic coming from unauthenticated pledges ๐ If this parameter is omitted, the value of positive infinity SHOULD be assumed โพ๏ธ A node operating as a JP MAY use another mechanism, which is out of scope for this specification, to configure the PROBING_RATE of CoAP when there's no join rate parameter in the Configuration object.
Table 4 is the cheat sheet for the parameters that can show up in a Configuration object ๐
+====================+=======+==================+
| Name | Label | CBOR Type |
+====================+=======+==================+
| link-layer key set | 2 | array |
+--------------------+-------+------------------+
| short identifier | 3 | array |
+--------------------+-------+------------------+
| JRC address | 4 | byte string |
+--------------------+-------+------------------+
| blacklist | 6 | array |
+--------------------+-------+------------------+
| join rate | 7 | unsigned integer |
+--------------------+-------+------------------+
Table 4: Summary of Configuration parameters.
Here's the CDDL fragment that represents everything above for the Configuration ๐งฉ The structures Link_Layer_Key and Short_Identifier are specified in Sections 8.4.3 and 8.4.4, respectively.
Configuration = {
? 2 : [ +Link_Layer_Key ], ; link-layer key set
? 3 : Short_Identifier, ; short identifier
? 4 : bstr, ; JRC address
? 6 : [ *bstr ], ; blacklist
? 7 : uint ; join rate
}
And Table 5 is the full map of CoJP parameter labels, including the ones that aren't in the Configuration list above, like role and network identifier ๐๏ธ
+===============+=======+==========+====================+===========+
| Name | Label | CBOR | Description | Reference |
| | | type | | |
+===============+=======+==========+====================+===========+
| role | 1 | unsigned | Identifies the | RFC 9031 |
| | | integer | role parameter | |
+---------------+-------+----------+--------------------+-----------+
| link-layer | 2 | array | Identifies the | RFC 9031 |
| key set | | | array carrying | |
| | | | one or more | |
| | | | link-layer | |
| | | | cryptographic | |
| | | | keys | |
+---------------+-------+----------+--------------------+-----------+
| short | 3 | array | Identifies the | RFC 9031 |
| identifier | | | assigned short | |
| | | | identifier | |
+---------------+-------+----------+--------------------+-----------+
| JRC address | 4 | byte | Identifies the | RFC 9031 |
| | | string | IPv6 address | |
| | | | of the JRC | |
+---------------+-------+----------+--------------------+-----------+
| network | 5 | byte | Identifies the | RFC 9031 |
| identifier | | string | network | |
| | | | identifier | |
| | | | parameter | |
+---------------+-------+----------+--------------------+-----------+
| blacklist | 6 | array | Identifies the | RFC 9031 |
| | | | blacklist | |
| | | | parameter | |
+---------------+-------+----------+--------------------+-----------+
| join rate | 7 | unsigned | Identifier the | RFC 9031 |
| | | integer | join rate | |
| | | | parameter | |
+---------------+-------+----------+--------------------+-----------+
| unsupported | 8 | array | Identifies the | RFC 9031 |
| configuration | | | unsupported | |
| | | | configuration | |
| | | | parameter | |
+---------------+-------+----------+--------------------+-----------+
Table 5: CoJP parameters map labels.
8.4.3. Link-Layer Key ๐โจ
okay so bestie, the Link_Layer_Key structure is the whole bundle of settings the link-layer security module needs to get going ๐. It holds the key identifier, the actual cryptographic key value, the link-layer algorithm identifier, the security level and frame types it should be used with for both outgoing and incoming security operations, plus any extra info needed to configure the key ๐ . The vibe is totally "everything you need, nothing you don't" ๐ซถ.
For encoding compactness, the Link_Layer_Key object is NOT wrapped in a top-level CBOR object ๐. Instead it gets transported as a sequence of CBOR elements [RFC8742], and some of those elements are optional ๐ง.
Here are the parameters that can show up in a Link_Layer_Key object, in order ๐:
key_id: The identifier of the key, encoded as a CBOR unsigned integer. This parameter MUST be included. If the decoded CBOR unsigned integer value is larger than the maximum link-layer key identifier, the key is considered invalid. If the key is considered invalid, the key MUST be discarded, and the implementation MUST signal the error as specified in Section 8.3.1. ๐ซ
key_usage: The identifier of the link-layer algorithm, security level, and link-layer frame types that can be used with the key, encoded as an integer. This parameter MAY be included. Possible values and the corresponding link-layer settings are specified in the IANA "Constrained Join Protocol (CoJP) Key Usage" registry (Section 11.2). If the parameter is omitted, the default value of 0 (6TiSCH-K1K2-ENC-MIC32) from Table 6 MUST be assumed. This default value has been chosen because it results in byte savings in the most constrained settings; its selection does not imply a recommendation for its general usage. ๐ฆ
key_value: The value of the cryptographic key, encoded as a byte string. This parameter MUST be included. If the length of the byte string is different than the corresponding key length for a given algorithm specified by the key_usage parameter, the key MUST be discarded, and the implementation MUST signal the error as specified in Section 8.3.1. ๐ฅ
key_addinfo: Additional information needed to configure the link-layer key, encoded as a byte string. This parameter MAY be included. The processing of this parameter is dependent on the link-layer technology in use and a particular keying mode. ๐ธ
To be able to decode the keys that are present in the link-layer key set and to identify individual parameters of a single Link_Layer_Key object, the CBOR decoder needs to differentiate between elements based on the CBOR type. For example, a uint that follows a byte string signals to the decoder that a new Link_Layer_Key object is being processed. ๐
The CDDL fragment for the Link_Layer_Key that represents the text above follows ๐ :
Link_Layer_Key = (
key_id : uint,
? key_usage : int,
key_value : bstr,
? key_addinfo : bstr,
)
Here's Table 6 ๐ (the Key Usage values), kept exactly as the spec has it:
+======================+=====+======================+===============+
|Name |Value|Algorithm |Description |
+======================+=====+======================+===============+
|6TiSCH-K1K2-ENC-MIC32 |0 |IEEE802154-AES-CCM-128|Use MIC-32 for |
| | | |EBs, ENC-MIC-32|
| | | |for DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1K2-ENC-MIC64 |1 |IEEE802154-AES-CCM-128|Use MIC-64 for |
| | | |EBs, ENC-MIC-64|
| | | |for DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1K2-ENC-MIC128|2 |IEEE802154-AES-CCM-128|Use MIC-128 for|
| | | |EBs, ENC- |
| | | |MIC-128 for |
| | | |DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1K2-MIC32 |3 |IEEE802154-AES-CCM-128|Use MIC-32 for |
| | | |EBs, DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1K2-MIC64 |4 |IEEE802154-AES-CCM-128|Use MIC-64 for |
| | | |EBs, DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1K2-MIC128 |5 |IEEE802154-AES-CCM-128|Use MIC-128 for|
| | | |EBs, DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1-MIC32 |6 |IEEE802154-AES-CCM-128|Use MIC-32 for |
| | | |EBs. |
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1-MIC64 |7 |IEEE802154-AES-CCM-128|Use MIC-64 for |
| | | |EBs. |
+----------------------+-----+----------------------+---------------+
|6TiSCH-K1-MIC128 |8 |IEEE802154-AES-CCM-128|Use MIC-128 for|
| | | |EBs. |
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-MIC32 |9 |IEEE802154-AES-CCM-128|Use MIC-32 for |
| | | |DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-MIC64 |10 |IEEE802154-AES-CCM-128|Use MIC-64 for |
| | | |DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-MIC128 |11 |IEEE802154-AES-CCM-128|Use MIC-128 for|
| | | |DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-ENC-MIC32 |12 |IEEE802154-AES-CCM-128|Use ENC-MIC-32 |
| | | |for DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-ENC-MIC64 |13 |IEEE802154-AES-CCM-128|Use ENC-MIC-64 |
| | | |for DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
|6TiSCH-K2-ENC-MIC128 |14 |IEEE802154-AES-CCM-128|Use ENC-MIC-128|
| | | |for DATA and |
| | | |ACKNOWLEDGMENT.|
+----------------------+-----+----------------------+---------------+
Table 6: Key Usage values. ๐
8.4.3.1. Rekeying of 6LBRs ๐
okay this one is a big deal ๐ญ. When the 6LBR receives the Configuration object containing a link-layer key set, it MUST immediately install and start using the new keys for all outgoing traffic, and it MUST remove any old keys it installed from the previous key set after a delay of COJP_REKEYING_GUARD_TIME has passed. This mechanism is how the JRC forces the 6LBR to start sending traffic with the new key. โญ
The JRC is the one who decides, once it has determined that the new key has been made available to all (or some overwhelming majority) of nodes. Any node the JRC has not reached at that point is either nonfunctional or in extended sleep such that it will not be reached. ๐ To get the key update, a node like that will need to go through the join process anew. ๐ซถ
8.4.3.2. Rekeying of 6LNs ๐ฆ
when a regular 6LN receives the Configuration object with a link-layer key set, it MUST install the new keys โจ. The 6LN will use both the old and the new keys to decrypt and authenticate any incoming traffic that arrives, based upon the key identifier in the packet. It MUST continue to use the old keys for all outgoing traffic until it has detected that the network has switched to the new key set. ๐ง
The detection of the network switch is based upon the receipt of traffic secured with the new keys. Upon the reception and the successful security processing of a link-layer frame secured with a key from the new key set, a 6LN MUST then switch to sending all outgoing traffic using the keys from the new set. The 6LN MUST remove any keys it had installed from the previous key set after waiting COJP_REKEYING_GUARD_TIME since it started using the new key set. ๐ฅ
Sending traffic with the new keys signals to other downstream nodes to switch to their new key, causing a ripple of key updates around each 6LBR. ๐๐
8.4.3.3. Use in IEEE Std 802.15.4 ๐โจ
Okay, bestie, this bit is for when Link_Layer_Key is used with [IEEE802.15.4] ๐. The big idea is that the keying mode is signaled by the parameter values in the object itself. The key_id value together with key_addinfo tells you which of the four Key ID modes of [IEEE802.15.4] is in play and how it works ๐.
- Key ID Mode 0x00 (Implicit, pairwise):
key_idMUST be set to0.key_addinfoMUST be present, and it MUST be set to the link-layer address(es) of a single peer that the key should be used with ๐ซถ. Depending on how the network is configured,key_addinfomay carry the peer's long link-layer address (the pledge identifier), its short link-layer address, or both joined together with the long address coming first. Which address types show up is decided by the length of the byte string ๐. - Key ID Mode 0x01 (Key Index):
key_idMUST be set to a value different from0.key_addinfoMUST NOT be present ๐ โโ๏ธ. - Key ID Mode 0x02 (4-byte Explicit Key Source):
key_idMUST be set to a value different from0.key_addinfoMUST be present, and it MUST be set to a byte string that is exactly 4 bytes long. In this mode,key_addinfocarries the Key Source parameter used to configure [IEEE802.15.4] ๐. - Key ID Mode 0x03 (8-byte Explicit Key Source):
key_idMUST be set to a value different from0.key_addinfoMUST be present, and it MUST be set to a byte string that is exactly 8 bytes long. Again,key_addinfocarries the Key Source parameter used to configure [IEEE802.15.4] ๐ธ.
No matter the mode, the key_usage parameter decides how a particular key gets used for incoming and outgoing security policies. It's giving policy ๐
.
For Key ID Modes 0x01 through 0x03, key_id sets the "secKeyIndex" parameter of [IEEE802.15.4]. That value gets signaled in every outgoing frame secured with the given key ๐ฆ. The highest value key_id can have is 254. The value 255 is reserved in [IEEE802.15.4], so it's considered invalid ๐ซ.
Key ID Mode 0x00 (Implicit, pairwise) lets the JRC act as a trusted third party and hand out pairwise keys between nodes in the network ๐. How the JRC finds out about the network topology is out of scope for this spec. It could happen through 6LBR-JRC signaling, for example ๐ง. Pairwise keys could also come from a key agreement protocol run directly between the peers, where authentication is based on the symmetric cryptographic material the JRC gave to both of them. That protocol is also out of scope for this spec ๐.
Implementations MUST use different link-layer keys when they use different authentication tag (MIC) lengths. The reason is that reusing the same key with different tag lengths might be unsafe. So, for example, the same key can't be used for both MIC-32 and MIC-64 levels ๐ญ. See Annex B.4.3 of [IEEE802.15.4] for more information.
8.4.4. Short Identifier ๐งธ
The Short_Identifier object represents an identifier assigned to the pledge. It's encoded as a CBOR array object, and it contains these things, in order:
identifier: The short identifier assigned to the pledge, encoded as a byte string. This parameter MUST be included. The identifier MUST be unique across the whole set of identifiers assigned in a network managed by a JRC. If the identifier is invalid, the decoder MUST silently ignore theShort_Identifierobject ๐คซ.lease_time: How long the identifier stays valid, measured in hours from when the CBOR object is received, encoded as a CBOR unsigned integer. This parameter MAY be included. The node MUST stop using the assigned short identifier once thelease_timeinterval expires โณ. It's up to the JRC to renew the lease before the previous interval runs out. To renew, the JRC runs the parameter update exchange with the node and includes theShort_Identifierin the Configuration object, as described in Section 8.2 ๐. If the lease expires, the node SHOULD start a new join exchange, as described in Section 8.1. If this parameter is left out, the value of positive infinity MUST be assumed, which means the identifier stays valid for as long as the node is in the network โพ๏ธ.
Here's the CDDL fragment that captures the text above ๐:
Short_Identifier = [
identifier : bstr,
? lease_time : uint
]
8.4.4.1. Use in IEEE Std 802.15.4 ๐
When Short_Identifier is used with [IEEE802.15.4], these considerations apply, okay?
The identifier MUST be used to set the short address of the IEEE Std 802.15.4 module ๐ก. When operating in TSCH mode, the identifier MUST be unique across the whole set of identifiers assigned in multiple networks that share link-layer key(s). If the byte string for the identifier parameter isn't 2 bytes long, the identifier is considered invalid. The values 0xfffe and 0xffff are reserved by [IEEE802.15.4], so using them is considered invalid too ๐ซ.
The security properties that the [IEEE802.15.4] link layer offers in TSCH mode depend on the short identifier (the short address) being unique. The short address is one of the inputs used to build the nonce that protects link-layer frames ๐. If something gets misconfigured and the same short address is assigned twice under the same link-layer key, the loss of security properties is imminent ๐. For this reason, it is not safe to let the pledge generate the short identifier locally, because that is likely to cost you the link-layer security properties.
The JRC MUST make sure that at any given time there are never two of the same short identifiers in use under the same link-layer key ๐จ. If the lease_time parameter of a given Short_Identifier object is set to positive infinity, take care that the identifier isn't handed to another node until the JRC is certain it's no longer in use. That might mean using out-of-band signaling. If the lease_time parameter expires for any reason, the JRC should take into consideration any ongoing transmissions from the joined node that might still be sitting in queues, before it assigns the same identifier to another node ๐ซฃ.
Care is also needed when the pledge (joined node) sets up the lease expiration. The units of lease_time are hours counted from when the CBOR object is received, so the pledge needs to convert that time into the matching Absolute Slot Number in the network โฐ. The joined node (pledge) MUST only use the Absolute Slot Number as its time reference when it decides whether the assigned short identifier is still valid ๐ง .
8.4.5. Unsupported Configuration Object ๐โโ๏ธ
The Unsupported_Configuration object is encoded as a CBOR array, and it has at least one Unsupported_Parameter object inside. Each Unsupported_Parameter object is a sequence of CBOR elements with no enclosing top-level CBOR object, which keeps things compact ๐ฆ. These are the parameters that can show up in an Unsupported_Parameter object, in order:
code: Says what the capability for acting on the parameter signaled byparameter_labelis, encoded as an integer. This parameter MUST be included. The possible values are specified in the IANA "Constrained Join Protocol (CoJP) Unsupported Configuration Codes" registry (Section 11.3) ๐ท๏ธ.parameter_label: Identifies the parameter. This parameter MUST be included. The possible values are specified in the label column of the IANA "Constrained Join Protocol (CoJP) Parameters" registry" (Section 11.1) ๐.parameter_addinfo: Extra info about the parameter that can't be acted upon. This parameter MUST be included. Ifcodeis set to "Unsupported",parameter_addinfogives extra information to the JRC ๐ฌ. If the parameter named byparameter_labelcan't be acted upon no matter what its value is,parameter_addinfoMUST be set to null. That tells the JRC it SHOULD NOT try to configure the parameter again ๐. If the pledge can act on the parameter but can't apply the setting that the parameter value indicates, the pledge can hint this to the JRC. In that case,parameter_addinfoMUST be set to the value of the parameter that can't be acted upon, following the normative parameter structure specified in this document ๐ฏ. For example, the link-layer key set object can be included to signal that either a subset or the whole key set that was received can't be acted upon. In that case, the value ofparameter_addinfofollows the link-layer key set structure defined in Section 8.4.2 ๐๏ธ. Ifcodeis set to "Malformed",parameter_addinfoMUST be set to null, which again tells the JRC it SHOULD NOT try to configure the parameter again ๐ต.
Here's the CDDL fragment for the Unsupported_Configuration and Unsupported_Parameter objects that represents the text above ๐:
Unsupported_Configuration = [
+ parameter : Unsupported_Parameter
]
Unsupported_Parameter = (
code : int,
parameter_label : int,
parameter_addinfo : nil / any
)
And here are the values for the code field. Table 7 is the one to check:
+=============+=======+==============================+===========+
| Name | Value | Description | Reference |
+=============+=======+==============================+===========+
| Unsupported | 0 | The indicated setting is not | RFC 9031 |
| | | supported by the networking | |
| | | stack implementation. | |
+-------------+-------+------------------------------+-----------+
| Malformed | 1 | The indicated parameter | RFC 9031 |
| | | value is malformed. | |
+-------------+-------+------------------------------+-----------+
Table 7: Unsupported Configuration code values.
8.5. Recommended Settings โ๏ธ
This section gives RECOMMENDED values of CoJP settings ๐. Here they are:
+==========================+===============+
| Name | Default Value |
+==========================+===============+
| COJP_MAX_JOIN_ATTEMPTS | 4 |
+--------------------------+---------------+
| COJP_REKEYING_GUARD_TIME | 12 seconds |
+--------------------------+---------------+
Table 8: Recommended CoJP settings.
The COJP_REKEYING_GUARD_TIME value SHOULD take into account possible retransmissions at the link layer, because wireless links aren't always perfect ๐ถ๐
9. Security Considerations ๐
Okay bestie, this is the serious part ๐ญ Since this document uses the pledge identifier to set the ID Context parameter of OSCORE, an important security requirement is that the pledge identifier is unique across all the pledge identifiers a JRC manages ๐. That uniqueness keeps the (key, nonce) pairs unique for the AEAD algorithm OSCORE uses ๐, and it lets the JRC grab the right security context when a Join Request shows up ๐ฏ. Managing identifiers gets easier if you use the globally unique EUI-64, but ngl that comes with privacy risks, which we'll get into in Section 10 ๐.
This doc also makes it a hard rule that the (6LBR) pledge and the JRC get unique PSKs ๐๏ธ. Provisioning a PSK to every pledge can be a real operational overhead ๐ฎโ๐จ, but it's vital for the security of the network ๐ . The PSK sets the OSCORE Master Secret during security context derivation, and that derivation produces OSCORE keys that matter for mutual authentication of the (6LBR) pledge and the JRC ๐ค. The resulting security context shared between the pledge (joined node) and the JRC is used for joining, and it's long-lived: it can be used for the whole life of a joined node for parameter update exchanges โณ. If an attacker learns the PSK, a man-in-the-middle attack becomes possible ๐.
Here's a tea moment โ: OSCORE gives replay protection, but it doesn't give an indication of freshness when an attacker can drop and/or reorder traffic ๐. The Join Request has no randomness and the sequence number is predictable, so the JRC could in principle anticipate a Join Request from a particular pledge and pre-calculate the response ๐ฎ. In that scenario, the JRC doesn't have to be alive when the request arrives ๐ป. This could matter if the JRC was temporarily compromised and the legitimate owner later got control back ๐ค.
Generating and provisioning PSKs unsafely is a huge no-no ๐ซ. Sharing a single PSK across a group of devices is a classic pitfall that leads to poor security ๐ โโ๏ธ. Compromising one device is likely to compromise the entire batch, and then the attacker could impersonate a legit device, join the network, generate bogus data, and mess with network operation ๐ฑ. Some vendors also scramble or hash device serial numbers or EUI-64 identifiers to make "unique" PSKs, but without any secret involved, the effort to break those methods is pretty low ๐ฅด. That means an attacker could impersonate any device in the batch without even compromising one ๐. Using cryptographically secure random number generators to generate the PSK is RECOMMENDED ๐ฒ, and see [NIST800-90A] for different mechanisms using deterministic methods ๐.
The JP forwards the unauthenticated join traffic into the network ๐ก. A data cap on the JP stops it from forwarding more traffic than the network can handle, and it enables throttling during an attack ๐ง. This traffic can only be aimed at the JRC, so the JRC needs to be ready to handle unsanitized inputs ๐งฑ. The data cap can be configured by the JRC by including a join rate parameter in the Join Response, and it's implemented through the CoAP's PROBING_RATE setting ๐๏ธ. A data cap at a JP forces attackers to use more than one JP if they want to overwhelm the network ๐ฅ. Marking join traffic packets with a nonzero DSCP lets the network carry the traffic if it has capacity, but it encourages the network to drop the extra traffic instead of adding bandwidth because of it ๐ฆ.
The shared nature of the "minimal" cell used for join traffic makes the network prone to DoS by congesting the JP with bogus traffic ๐. An attacker like this is limited by its maximum transmit power โก. Having redundant JPs alleviates the issue and gives the pledge the chance to use the best available link for joining ๐. How a network node decides to become a JP is out of scope for this specification ๐คทโโ๏ธ.
At the beginning of the join process, the pledge has no way to verify the content of the EB, so it has to accept it at "face value" ๐ซฃ. If the pledge tries to join an attacker's network, the Join Response will either fail the security check or time out โฐ. The pledge may implement a temporary blacklist to filter out undesired EBs and try the next seemingly valid EB ๐. This blacklist helps, but it's effectively limited by the node's available memory ๐ง . Note that this temporary blacklist is different from the one communicated as part of the CoJP Configuration object, since it helps the pledge fight a DoS attack ๐ก๏ธ. Bogus beacons prolong the pledge's join time, and so does the time spent in "minimal" duty cycle mode [RFC8180] ๐ข. The blacklist communicated as part of the CoJP Configuration object helps the JP fight a DoS attack by a malicious pledge ๐ฅท.
During the network lifetime, the JRC may at any time start a parameter update exchange with a joined node ๐ฃ. The Parameter Update message uses the same OSCORE security context as the join exchange, except the server and client roles are swapped ๐. So every Parameter Update message carries the well-known OSCORE Sender ID of the JRC ๐ชช. A passive attacker can use that Sender ID to identify Parameter Update traffic if the link-layer protection doesn't provide confidentiality ๐. A countermeasure against this traffic-analysis attack is to use encryption at the link layer ๐. Note that join traffic doesn't get link-layer protection at the first hop, since the pledge isn't yet in possession of cryptographic keys ๐ โโ๏ธ. EB traffic in the network isn't encrypted either, which makes it super easy for a passive attacker to spot these types of traffic ๐๏ธ.
10. Privacy Considerations ๐ต๏ธโโ๏ธ
The join solution in this document relies on the uniqueness of the pledge identifier across all pledge identifiers managed by a JRC ๐. This identifier is transferred in the clear as an OSCORE 'kid context' ๐ญ. Using the globally unique EUI-64 as the pledge identifier simplifies management but comes with certain privacy risks ๐ฌ. The implications are thoroughly discussed in [RFC7721], and they include correlation of activities over time, location tracking, address scanning, and device-specific vulnerability exploitation ๐ง. Since the join process happens rarely compared to the network lifetime, the long-term threats from using EUI-64 as the pledge identifier are minimal ๐. After the join process completes, though, using EUI-64 in the form of a Layer 2 or Layer 3 address stretches those privacy threats into the long term ๐ฉ.
As an optional mitigation technique ๐ซ, the Join Response message may contain a short address assigned by the JRC to the (6LBR) pledge ๐ฆ. The assigned short address SHOULD be uncorrelated with the long-term pledge identifier ๐ . The short address is encrypted in the response ๐. Once the join process completes, the new node may use the short addresses for all further Layer 2 (and Layer 3) operations ๐ธ. This reduces the privacy threats, because the short Layer 2 address (visible even when the network is encrypted) doesn't disclose the manufacturer the way EUI-64 does ๐. However, an eavesdropper with access to the radio medium during the join process may be able to correlate the assigned short address with the extended address based on timing information with a non-negligible probability ๐ณ. That probability decreases as the number of pledges joining concurrently increases ๐.
11. IANA Considerations ๐
This document allocates a well-known name under the .arpa name space according to the rules given in [RFC3172] and [RFC6761] ๐. The name 6tisch.arpa is requested ๐. No subdomains are expected, and adding any such subdomains requires the publication of an IETF Standards Track RFC ๐
โโ๏ธ. No A, AAAA, or PTR record is requested.
11.1. Constrained Join Protocol (CoJP) Parameters
This section defines a subregistry within the "IPv6 Over the TSCH Mode of IEEE 802.15.4 (6TiSCH)" registry with the name "Constrained Join Protocol (CoJP) Parameters" ๐งฉ.
The columns of the registry are:
- Name: A descriptive name that makes the item easier to reference ๐ท๏ธ. It isn't used in the encoding. The name MUST be unique.
- Label: The value used to identify this parameter. The label is an integer. The label MUST be unique.
- CBOR Type: This field contains the CBOR type for the field.
- Description: This field contains a brief description for the field. The description MUST be unique.
- Reference: This field contains a pointer to the public specification for the field, if one exists.
This registry is populated with the values in Table 5 ๐.
The amending formula for this subregistry is: Different ranges of values use different registration policies [RFC8126]. Here's how the ranges break down ๐:
- Integer values from -256 to 255 are designated as Standards Action.
- Integer values from -65536 to -257 and from 256 to 65535 are designated as Specification Required.
- Integer values greater than 65535 are designated as Expert Review.
- Integer values less than -65536 are marked as Private Use.
11.2. Constrained Join Protocol (CoJP) Key Usage
This section defines a subregistry within the "IPv6 Over the TSCH Mode of IEEE 802.15.4 (6TiSCH)" registry with the name "Constrained Join Protocol (CoJP) Key Usage" ๐.
The columns of this registry are:
- Name: A descriptive name that enables easier reference to the item. It isn't used in the encoding. The name MUST be unique.
- Value: The value used to identify the key usage setting. These values MUST be unique. The value is an integer.
- Algorithm: A descriptive name of the link-layer algorithm in use, which uniquely determines the key length. The name isn't used in the encoding. The algorithm MUST be unique.
- Description: A description of the key usage setting. The field should describe in enough detail how the key is to be used with different frame types, specific for the link-layer technology in question. The description MUST be unique.
- Reference: This contains a pointer to the public specification for the field, if one exists.
This registry is populated with the values in Table 6 ๐ฏ.
The amending formula for this subregistry is: Different ranges of values use different registration policies [RFC8126]. Here's how the ranges break down ๐:
- Integer values from -256 to 255 are designated as Standards Action.
- Integer values from -65536 to -257 and from 256 to 65535 are designated as Specification Required.
- Integer values greater than 65535 are designated as Expert Review.
- Integer values less than -65536 are marked as Private Use.
11.3. Constrained Join Protocol (CoJP) Unsupported Configuration Codes ๐
okay so this section sets up a little subregistry inside the "IPv6 Over the TSCH Mode of IEEE 802.15.4 (6TiSCH)" registry, and it's called "Constrained Join Protocol (CoJP) Unsupported Configuration Codes" ๐ very organised, very giving librarian energy ๐
Every entry in this registry has four columns:
- Name: a descriptive name so people can refer to the item more easily. It's not used in the encoding. The name MUST be unique. ๐
- Value: the value that identifies the diagnostic code. These values MUST be unique. The value is an integer. ๐ข
- Description: a descriptive human-readable name. The description MUST be unique. It is not used in the encoding. ๐
- Reference: a pointer to the public specification for the field, if one exists. ๐
This registry is going to be populated with the values in Table 7 ๐ธ
Now for the rules about adding new stuff (the amending formula, aka the registration policy bit ๐). Different ranges of values use different registration policies [RFC8126], so it's not one-size-fits-all bestie:
- Integer values from
-256to255are designated as Standards Action. - Integer values from
-65536to-257and from256to65535are designated as Specification Required. - Integer values greater than
65535are designated as Expert Review. - Integer values less than
-65536are marked as Private Use.
no cap this is a lot of number ranges but the pattern is clean โจ
12. References ๐
12.1. Normative References
- [IEEE802.15.4] IEEE, "IEEE Standard for Low-Rate Wireless Networks", IEEE Standard 802.15.4-2015, DOI 10.1109/IEEESTD.2016.7460875, April 2016, <
https://ieeexplore.ieee.org/document/7460875>. ๐ฆ - [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <
https://www.rfc-editor.org/info/rfc2119>. - [RFC2597] Heinanen, J., Baker, F., Weiss, W., and J. Wroclawski, "Assured Forwarding PHB Group", RFC 2597, DOI 10.17487/RFC2597, June 1999, <
https://www.rfc-editor.org/info/rfc2597>. - [RFC3172] Huston, G., Ed., "Management Guidelines & Operational Requirements for the Address and Routing Parameter Area Domain ("arpa")", BCP 52, RFC 3172, DOI 10.17487/RFC3172, September 2001, <
https://www.rfc-editor.org/info/rfc3172>. - [RFC5869] Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)", RFC 5869, DOI 10.17487/RFC5869, May 2010, <
https://www.rfc-editor.org/info/rfc5869>. - [RFC6761] Cheshire, S. and M. Krochmal, "Special-Use Domain Names", RFC 6761, DOI 10.17487/RFC6761, February 2013, <
https://www.rfc-editor.org/info/rfc6761>. - [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained Application Protocol (CoAP)", RFC 7252, DOI 10.17487/RFC7252, June 2014, <
https://www.rfc-editor.org/info/rfc7252>. - [RFC7554] Watteyne, T., Ed., Palattella, M., and L. Grieco, "Using IEEE 802.15.4e Time-Slotted Channel Hopping (TSCH) in the Internet of Things (IoT): Problem Statement", RFC 7554, DOI 10.17487/RFC7554, May 2015, <
https://www.rfc-editor.org/info/rfc7554>. - [RFC8085] Eggert, L., Fairhurst, G., and G. Shepherd, "UDP Usage Guidelines", BCP 145, RFC 8085, DOI 10.17487/RFC8085, March 2017, <
https://www.rfc-editor.org/info/rfc8085>. - [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017, <
https://www.rfc-editor.org/info/rfc8126>. - [RFC8152] Schaad, J., "CBOR Object Signing and Encryption (COSE)", RFC 8152, DOI 10.17487/RFC8152, July 2017, <
https://www.rfc-editor.org/info/rfc8152>. - [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <
https://www.rfc-editor.org/info/rfc8174>. - [RFC8180] Vilajosana, X., Ed., Pister, K., and T. Watteyne, "Minimal IPv6 over the TSCH Mode of IEEE 802.15.4e (6TiSCH) Configuration", BCP 210, RFC 8180, DOI 10.17487/RFC8180, May 2017, <
https://www.rfc-editor.org/info/rfc8180>. - [RFC8505] Thubert, P., Ed., Nordmark, E., Chakrabarti, S., and C. Perkins, "Registration Extensions for IPv6 over Low-Power Wireless Personal Area Network (6LoWPAN) Neighbor Discovery", RFC 8505, DOI 10.17487/RFC8505, November 2018, <
https://www.rfc-editor.org/info/rfc8505>. - [RFC8613] Selander, G., Mattsson, J., Palombini, F., and L. Seitz, "Object Security for Constrained RESTful Environments (OSCORE)", RFC 8613, DOI 10.17487/RFC8613, July 2019, <
https://www.rfc-editor.org/info/rfc8613>. - [RFC8820] Nottingham, M., "URI Design and Ownership", BCP 190, RFC 8820, DOI 10.17487/RFC8820, June 2020, <
https://www.rfc-editor.org/info/rfc8820>. - [RFC8949] Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", STD 94, RFC 8949, DOI 10.17487/RFC8949, December 2020, <
https://www.rfc-editor.org/info/rfc8949>. - [RFC8974] Hartke, K. and M. Richardson, "Extended Tokens and Stateless Clients in the Constrained Application Protocol (CoAP)", RFC 8974, DOI 10.17487/RFC8974, January 2021, <
https://www.rfc-editor.org/info/rfc8974>. - [RFC9030] Thubert, P., Ed., "An Architecture for IPv6 over the Time-Slotted Channel Hopping Mode of IEEE 802.15.4 (6TiSCH)", RFC 9030, DOI 10.17487/RFC9030, May 2021, <
https://www.rfc-editor.org/info/rfc9030>. ๐
12.2. Informative References
- [NIST800-90A] National Institute of Standards and Technology, "Recommendation for Random Number Generation Using Deterministic Random Bit Generators", Special Publication 800-90A, Revision 1, DOI 10.6028/NIST.SP.800-90Ar1, June 2015, <
https://doi.org/10.6028/NIST.SP.800-90Ar1>. - [RFC4231] Nystrom, M., "Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512", RFC 4231, DOI 10.17487/RFC4231, December 2005, <
https://www.rfc-editor.org/info/rfc4231>. - [RFC4944] Montenegro, G., Kushalnagar, N., Hui, J., and D. Culler, "Transmission of IPv6 Packets over IEEE 802.15.4 Networks", RFC 4944, DOI 10.17487/RFC4944, September 2007, <
https://www.rfc-editor.org/info/rfc4944>. - [RFC6550] Winter, T., Ed., Thubert, P., Ed., Brandt, A., Hui, J., Kelsey, R., Levis, P., Pister, K., Struik, R., Vasseur, JP., and R. Alexander, "RPL: IPv6 Routing Protocol for Low-Power and Lossy Networks", RFC 6550, DOI 10.17487/RFC6550, March 2012, <
https://www.rfc-editor.org/info/rfc6550>. - [RFC6762] Cheshire, S. and M. Krochmal, "Multicast DNS", RFC 6762, DOI 10.17487/RFC6762, February 2013, <
https://www.rfc-editor.org/info/rfc6762>. - [RFC7721] Cooper, A., Gont, F., and D. Thaler, "Security and Privacy Considerations for IPv6 Address Generation Mechanisms", RFC 7721, DOI 10.17487/RFC7721, March 2016, <
https://www.rfc-editor.org/info/rfc7721>. - [RFC8415] Mrugalski, T., Siodelski, M., Volz, B., Yourtchenko, A., Richardson, M., Jiang, S., Lemon, T., and T. Winters, "Dynamic Host Configuration Protocol for IPv6 (DHCPv6)", RFC 8415, DOI 10.17487/RFC8415, November 2018, <
https://www.rfc-editor.org/info/rfc8415>. - [RFC8480] Wang, Q., Ed., Vilajosana, X., and T. Watteyne, "6TiSCH Operation Sublayer (6top) Protocol (6P)", RFC 8480, DOI 10.17487/RFC8480, November 2018, <
https://www.rfc-editor.org/info/rfc8480>. - [RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, June 2019, <
https://www.rfc-editor.org/info/rfc8610>. - [RFC8615] Nottingham, M., "Well-Known Uniform Resource Identifiers (URIs)", RFC 8615, DOI 10.17487/RFC8615, May 2019, <
https://www.rfc-editor.org/info/rfc8615>. - [RFC8742] Bormann, C., "Concise Binary Object Representation (CBOR) Sequences", RFC 8742, DOI 10.17487/RFC8742, February 2020, <
https://www.rfc-editor.org/info/rfc8742>. - [RFC8990] Bormann, C., Carpenter, B., Ed., and B. Liu, Ed., "GeneRic Autonomic Signaling Protocol (GRASP)", RFC 8990, DOI 10.17487/RFC8990, May 2021, <
https://www.rfc-editor.org/info/rfc8990>. ๐ซถ
Appendix A. Example ๐ง
Okay bestie, Figure 3 shows a successful join protocol exchange, and it's so satisfying to watch ๐ฆ The pledge sets up its OSCORE context and derives the OSCORE keys and nonces from the PSK. Then it uses that context to protect the Join Request. The request has a Proxy-Scheme option, the well-known host name of the JRC in the Uri-Host option, and the pledge's EUI-64 as both its pledge identifier and its OSCORE 'kid context' ๐
The Proxy-Scheme option is what kicks things off. When the JP sees it, the JP forwards the request to the JRC and sets the CoAP token to the internal state it needs. The JP already knows the IPv6 address of the JRC, because it learned it back when it was a pledge and joined the network ๐ธ Once the JRC gets the request, it finds the right context by looking at the 'kid context' parameter. The OSCORE data authenticity verification makes sure nobody messed with the request in transit, and replay protection comes from persistently handling the mutable context parameters. Iconic, honestly ๐
When the JP gets the Join Response, it checks the state inside the CoAP token before it decides where to forward. Then it sets its internal state to whatever the token says and sends the Join Response to the correct pledge. Quick note: the JP can't decrypt the CoJP object (the configuration) in the payload, and it doesn't need to. Back at the pledge, the Join Response gets matched to the Join Request and checked for replay protection using the OSCORE processing rules ๐ In this example, the Join Response doesn't include the IPv6 address of the JRC, so the pledge figures out that the JRC is co-located with the 6LBR. Main character energy ๐
<-----E2E OSCORE------>
Client Proxy Server
Pledge JP JRC
| | |
| Join | | Code: 0.02 (POST)
| Request | | Token: -
+--------->| | Proxy-Scheme: coap
| | | Uri-Host: 6tisch.arpa
| | | OSCORE: kid: -,
| | | kid_context: EUI-64,
| | | Partial IV: 1
| | | Payload: { Code: 0.02 (POST),
| | | Uri-Path: "j",
| | | join_request, <Tag> }
| | |
| | Join | Code: 0.02 (POST)
| | Request | Token: opaque state
| +--------->| OSCORE: kid: -,
| | | kid_context: EUI-64,
| | | Partial IV: 1
| | | Payload: { Code: 0.02 (POST),
| | | Uri-Path: "j",
| | | join_request, <Tag> }
| | |
| | |
| | Join | Code: 2.04 (Changed)
| | Response | Token: opaque state
| |<---------+ OSCORE: -
| | | Payload: { Code: 2.04 (Changed),
| | | configuration, <Tag> }
| | |
| | |
| Join | | Code: 2.04 (Changed)
| Response | | Token: -
|<---------+ | OSCORE: -
| | | Payload: { Code: 2.04 (Changed),
| | | configuration, <Tag> }
| | |
Figure 3: Example of a successful join protocol exchange. { ... }
denotes authenticated encryption, <Tag> denotes the
authentication tag.
Here's the join_request object we're working with ๐
join_request:
{
5 : h'cafe' / PAN ID of the network pledge is attempting to join /
}
Since the role parameter isn't present, the default role of "6TiSCH Node" is implied. โจ
The join_request object gets converted to h'a10542cafe', which is 5 bytes. Bestie, that's so compact ๐ฅน
And here's the configuration object:
configuration:
{
2 : [ / link-layer key set /
1, / key_id /
h'e6bf4287c2d7618d6a9687445ffd33e6' / key_value /
],
3 : [ / short identifier /
h'af93' / assigned short address /
]
}
Since the key_usage parameter isn't present in the link-layer key set object, the default value of "6TiSCH-K1K2-ENC-MIC32" is implied. Since the key_addinfo parameter isn't present and key_id is different from 0, Key ID Mode 0x01 (Key Index) is implied. ๐ Similarly, since the lease_time parameter isn't present in the short identifier object, the default value of positive infinity is implied. Forever vibes โพ๏ธ
The configuration object gets converted to h'a202820150e6bf4287c2d7618d6a9687445ffd33e6038142af93', which is 26 bytes. Slay ๐
Appendix B. Lightweight Implementation Option ๐
Okay so, sometimes you're working in an environment where squeezing the implementation footprint matters a lot ๐ฅบ In that case, you can implement this specification without putting HKDF [RFC5869] and SHA [RFC4231] on your constrained devices. Both of them are used during the OSCORE security context derivation phase, and that derivation can also be done by the JRC or a provisioning device on behalf of the (6LBR) pledge during the provisioning phase. When that happens, the derived OSCORE security context parameters get written straight into the (6LBR) pledge, so the PSK never has to be provisioned to the (6LBR) pledge at all ๐ฆ
Here's why the HKDF part matters. Using HKDF to derive the OSCORE security context parameters means the resulting OSCORE keys have good security properties, and they stay unique as long as the input varies between pledges. This specification keeps that uniqueness by requiring unique pledge identifiers and a unique PSK for each (6LBR) pledge. From the AEAD nonce reuse viewpoint, having a unique pledge identifier is a sufficient condition. ๐
But, and this is a big but ๐, Section 9 talks about how using one PSK shared across many devices is a common security pitfall. If that shared PSK gets compromised on a single device, the entire batch is compromised too. With the implementation and deployment scheme described above, the PSK doesn't need to be written to individual pledges. So even if a shared PSK is used, the scheme gives you a level of security comparable to the scenario where each pledge has its own unique PSK. Still, there's a latent risk: the shared PSK could be compromised on the provisioning device, and that would compromise all the devices in the batch. Be careful with that one, besties ๐ญ๐ซถ
Acknowledgments ๐ซถ
The work on this document has been partially supported by the European Union's H2020 Programme for research, technological development and demonstration under grant agreements: No. 644852, project ARMOUR; No. 687884, project F-Interop and open-call project SPOTS; No. 732638, project Fed4FIRE+ and open-call project SODA. ๐ช๐บโจ
The following individuals provided input to this document (in alphabetic order): Christian Amsรผss, Tengfei Chang, Roman Danyliw, Linda Dunbar, Vijay Gurbani, Klaus Hartke, Barry Leiba, Benjamin Kaduk, Tero Kivinen, Mirja Kรผhlewind, John Mattsson, Hilarie Orman, Alvaro Retana, Adam Roach, Jim Schaad, Gรถran Selander, Yasuyuki Tanaka, Pascal Thubert, William Vignat, Xavier Vilajosana, รric Vyncke, and Thomas Watteyne. Thank you all, you're literally the best ๐๐ธ
Authors' Addresses ๐
Maliลกa Vuฤiniฤ (editor) Inria 2 Rue Simone Iff 75012 Paris France
Email: malisa.vucinic@inria.fr
Jonathan Simon Analog Devices 32990 Alvarado-Niles Road, Suite 910 Union City, CA 94587 United States of America
Email: jonathan.simon@analog.com
Kris Pister University of California Berkeley 512 Cory Hall Berkeley, CA 94720 United States of America
Email: pister@eecs.berkeley.edu
Michael Richardson Sandelman Software Works 470 Dawson Avenue Ottawa ON K1Z5V7 Canada
Email: mcr+ietf@sandelman.ca
๐ฆ where this page comes from
- ietf: rfc9031 2021-05
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms