RFC 8824

Static Context Header Compression (SCHC) for the Constrained Application Protocol (CoAP)

๐Ÿ“… published June 2021, from ietf

๐Ÿ“œ RFC 8824: SCHC for CoAP, bestie!! ๐Ÿฆ‹

Okay so babe, this one is Standards Track ๐Ÿ’…, which means it's an official Internet Standard and not just a vibe. It was written by A. Minaburo (Acklio), L. Toutain (IMT Atlantique), and R. Andreasen (Universidad de Buenos Aires) ๐ŸŒธ, and it was published in June 2021 ๐Ÿ’–. It's an ISSN 2070-1721 document, and it doesn't obsolete or update any other RFCs, so it's a fresh start, no drama ๐Ÿซถ.

The whole point? Shrinking CoAP headers so they can fit on tiny LPWAN devices ๐Ÿ”‹โœจ. It builds on the SCHC framework from [RFC8724] and applies it to CoAP's flexible, variable-length headers. Ngl, the way it leans into CoAP's request/response asymmetry to make tighter Rules is kind of iconic ๐Ÿงš.

1. Introduction โœจ

Okay so, CoAP [RFC7252] is a command/response protocol built for microcontrollers with tiny RAM and ROM, and it's designed around REST services ๐ŸŽ€. The thing is, even though Constrained Devices were the main focus when CoAP was designed, a CoAP header is still too chunky for LPWANs (Low-Power Wide-Area Networks) ๐Ÿ˜ญ. So applying Static Context Header Compression and fragmentation (SCHC) to CoAP headers is required if you want better performance or want to run CoAP over LPWAN tech ๐Ÿ’œ.

[RFC8724] is where the SCHC framework lives ๐Ÿฆ‹. It has a header compression mechanism for LPWANs that runs on a static context. Section 5 of [RFC8724] explains where compression and decompression happen in the architecture ๐ŸŒˆ. Bestie, the big prerequisite is that both endpoints have to know the static context before anything gets sent ๐Ÿซถ. How that context gets configured, provisioned, or exchanged is not this doc's job, so it's out of scope ๐Ÿ™ˆ.

CoAP is an application protocol, so CoAP compression means installing common Rules between the two SCHC instances ๐Ÿ’…. SCHC compression can happen at two levels: at IP and UDP in the LPWAN, and separately at the application level for CoAP ๐ŸŒธ. These two techniques can be independent, and they both follow the same principle described in [RFC8724] โœจ. Different entities handle CoAP compression at different levels, so the SCHC Rules driving compression and decompression are different too ๐Ÿ‘‘. [RFC8724] covers IP and UDP headers, and this document is the one that explains how to apply SCHC compression to CoAP headers ๐Ÿ“.

SCHC compresses and decompresses headers using contexts shared between Devices ๐Ÿงš. The SCHC context holds multiple Rules, and each Rule can match header fields to specific values or ranges of values ๐Ÿ’–. If a Rule matches, the matched header fields get replaced by the RuleID plus the Compression Residue, which holds the leftover bits from compression ๐Ÿ”ฅ. So different Rules can correspond to different protocol headers in the packets a Device expects to send or receive ๐ŸŽ€.

A Rule describes the packet's entire header as an ordered list of Field Descriptors, see Section 7 of [RFC8724] ๐Ÿ“œ. Each description has the Field ID (FID), Field Length (FL), and Field Position (FP), plus a Direction Indicator (DI) (upstream, downstream, or bidirectional) and some associated Target Values (TVs) ๐Ÿ’…. The DI is used during compression to pick the best TV for the FID when those values differ by transmission direction, so yes, a field can be described more than once ๐Ÿฆ‹.

Each header Field Descriptor is paired with a Matching Operator (MO) ๐ŸŒธ. The Rule gets selected if all the MOs fit the TVs for all the fields in the incoming header ๐Ÿซถ. A Rule cannot be selected if the message has a field the SCHC compressor doesn't know about ๐Ÿ™ˆ.

When that happens, a Compression/Decompression Action (CDA) tied to each field tells the compressor how to compress and decompress that field ๐Ÿ’œ. Compression mostly comes down to one of four actions ๐ŸŒˆ:

  • send the field value (value-sent),
  • send nothing (not-sent),
  • send some Least Significant Bits (LSBs) of the field, or
  • send an index (mapping-sent).

After compression there may still be some bits to send, and these are called "Compression Residue" ๐Ÿ“.

SCHC is a general mechanism used with different protocols, and the exact Rules depend on the protocol and the application ๐Ÿ‘‘. Section 10 of [RFC8724] describes the compression scheme for IPv6 and UDP headers, and this document is the one targeting CoAP header compression with SCHC โœจ.

1.1. 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 ๐ŸŽ€. Bestie, that capitals rule is important, so only the all-caps versions count as the real deal ๐Ÿ’€.


Part 1 of 7 is done, bestie! ๐Ÿฆ‹ Say "next" and I'll keep going with Section 2 ๐Ÿซถ๐Ÿ’œ

2. SCHC Applicability to CoAP โœจ

Okay so, SCHC compression for CoAP headers MAY be done alongside the lower layers (IPv6/UDP) or totally on its own ๐Ÿซถ. The SCHC adaptation layers from Section 5 of [RFC8724] can be used the way Figures 1, 2, and 3 show ๐Ÿฆ‹.

Figure 1 is giving "one Rule does it all" ๐Ÿ’…. A single Rule compresses the whole header stack from IPv6 all the way to CoAP. The Device and the Network Gateway (NGW) both do SCHC C/D (SCHC Compression/Decompression, see [RFC8724]) โœจ. The app talking to the Device doesn't do SCHC C/D at all, so it's not involved ๐ŸŒธ.

      (Device)            (NGW)                              (App)

      +--------+                                           +--------+
      |  CoAP  |                                           |  CoAP  |
      +--------+                                           +--------+
      |  UDP   |                                           |  UDP   |
      +--------+     +----------------+                    +--------+
      |  IPv6  |     |      IPv6      |                    |  IPv6  |
      +--------+     +--------+-------+                    +--------+
      |  SCHC  |     |  SCHC  |       |                    |        |
      +--------+     +--------+       +                    +        +
      |  LPWAN |     | LPWAN  |       |                    |        |
      +--------+     +--------+-------+                    +--------+
          ((((LPWAN))))             ------   Internet  ------

Figure 1: Compression/Decompression at the LPWAN Boundary

So in Figure 1, SCHC header compression happens above Layer 2 in the Device and the NGW ๐Ÿงš. The SCHC layer gets non-encrypted packets and can apply compression Rules to all the headers in the stack ๐Ÿ’–. On the other side, the NGW gets the SCHC packet and rebuilds the headers using the Rule and the Compression Residue ๐Ÿ”ฅ. After decompression, the NGW forwards the IPv6 packet toward the destination ๐ŸŽ€. The same thing happens the other way when a non-encrypted packet shows up at the NGW ๐ŸŒˆ. Thanks to IP forwarding based on the IPv6 prefix, the NGW knows which Device it is and compresses headers using that Device's Rules ๐Ÿ‘‘.

In Figure 2, SCHC compression happens in the CoAP layer, so the CoAP header gets compressed independently of the other layers ๐Ÿ’œ. The RuleID, Compression Residue, and CoAP payload are encrypted with a mechanism such as DTLS ๐Ÿ”’. Only the other end (App) can decipher the info ๐Ÿ™ˆ. If needed, the layers below use SCHC to compress the header as defined in [RFC8724] (shown with dotted lines in the figure) โœจ.

This use case needs an end-to-end context initialization between the Device and the application ๐Ÿฆ‹. The context initialization is out of scope for this document ๐Ÿ’….

      (Device)            (NGW)                               (App)

      +--------+                                           +--------+
      |  CoAP  |                                           |  CoAP  |
      +--------+                                           +--------+
      |  SCHC  |                                           |  SCHC  |
      +--------+                                           +--------+
      |  DTLS  |                                           |  DTLS  |
      +--------+                                           +--------+
      .  udp   .                                           .  udp   .
      ..........     ..................                    ..........
      .  ipv6  .     .      ipv6      .                    .  ipv6  .
      ..........     ..................                    ..........
      .  schc  .     .  schc  .       .                    .        .
      ..........     ..........       .                    .        .
      .  lpwan .     . lpwan  .       .                    .        .
      ..........     ..................                    ..........
          ((((LPWAN))))             ------   Internet  ------

Figure 2: Standalone CoAP End-to-End Compression/Decompression

Figure 3 is the OSCORE era ๐ŸŒธ. It shows Object Security for Constrained RESTful Environments (OSCORE) [RFC8613] in action. Here SCHC needs two Rules to compress the CoAP header ๐Ÿ“. The first Rule focuses on the Inner header. The result of that first compression then gets encrypted with OSCORE ๐Ÿ”. After that, a second Rule compresses the Outer header, including the OSCORE options ๐Ÿ’€.

      (Device)            (NGW)                              (App)

      +--------+                                           +--------+
      |  CoAP  |                                           |  CoAP  |
      |  Inner |                                           |  Inner |
      +--------+                                           +--------+
      |  SCHC  |                                           |  SCHC  |
      |  Inner |                                           |  Inner |
      +--------+                                           +--------+
      |  CoAP  |                                           |  CoAP  |
      |  Outer |                                           |  Outer |
      +--------+                                           +--------+
      |  SCHC  |                                           |  SCHC  |
      |  Outer |                                           |  Outer |
      +--------+                                           +--------+
      .  udp   .                                           .  udp   .
      ..........     ..................                    ..........
      .  ipv6  .     .      ipv6      .                    .  ipv6  .
      ..........     ..................                    ..........
      .  schc  .     .  schc  .       .                    .        .
      ..........     ..........       .                    .        .
      .  lpwan .     . lpwan  .       .                    .        .
      ..........     ..................                    ..........
          ((((LPWAN))))             ------   Internet  ------

Figure 3: OSCORE Compression/Decompression

When there are several SCHC instances, like in Figures 2 and 3, the Rules may come from different provisioning domains ๐ŸŒ.

This document focuses on CoAP compression, which is what the dashed boxes in the previous figures represent ๐ŸŽ€.

3. CoAP Headers Compressed with SCHC

Using SCHC over the CoAP header is the same deal as with IP and UDP. It uses the same description and compression/decompression techniques explained in [RFC8724] ๐Ÿ’–. For CoAP, the SCHC Rules description uses the direction information to optimize compression, which cuts down how many Rules you need to compress headers โœจ. The Field Descriptor MAY define both request/response headers and TVs in the same Rule, using the DI to show which header type it is ๐Ÿฆ‹.

Like with other header compression protocols, if the compressor can't find a correct Rule for a header, the packet MUST be sent uncompressed. It uses the RuleID dedicated to this purpose, and the Compression Residue is the complete header of the packet ๐Ÿ™…โ€โ™€๏ธ. See Section 6 of [RFC8724] ๐ŸŒธ.

3.1. Differences between CoAP and UDP/IP Compression

CoAP compression is different from IPv6 and UDP compression in a few ways ๐Ÿ’…:

  • The CoAP message format is asymmetric, so the headers differ for a request or a response ๐Ÿ“. For example, the Uri-Path option is mandatory in the request, but it might not be in the response. A request might contain an Accept option, and the response might include a Content-Format option ๐ŸŒˆ. With IPv6 and UDP, the returning path just swaps the values of some fields in the header ๐Ÿงš. But every direction has the same fields (for example, source and destination address fields) ๐Ÿ‘‘.

[RFC8724] defines the use of a DI in the Field Descriptor. That lets one Rule process a message header differently depending on the direction ๐Ÿ’œ.

  • Even when a field is "symmetric" (found in both directions), the values in each direction are different ๐Ÿ”ฅ. The compression may use a "match-mapping" MO to limit the range of expected values in a particular direction and shrink the Compression Residue's size ๐Ÿ’–. Through the DI, a Field Descriptor in the Rules splits the possible field value into two parts, one for each direction โœจ. For instance, if a client only sends Confirmable (CON) requests [RFC7252], the Type can be elided by compression, and the answer may use one single bit to carry either the ACK or Reset (RST) type ๐ŸŽ€. The field Code works the same way: the 0.0X code format value in the request and the Y.ZZ code format in the response ๐Ÿฆ‹.
  • In SCHC, the Rule defines each header field's length, so SCHC doesn't have to send it ๐Ÿ’…. In IPv6 and UDP headers, the fields have a fixed size that's known by definition ๐ŸŒธ. Some CoAP header fields have variable lengths, though, and the Rule description specifies that ๐Ÿ“. For example, in a Uri-Path or Uri-Query, the Token size may vary from 0 to 8 bytes, and CoAP options use the Type-Length-Value encoding format ๐ŸŒˆ.

When doing SCHC compression of a variable-length field, Section 7.4.2 of [RFC8724] offers the option of defining a function for the Field Length in the Field Descriptor, so the length is known before compression ๐Ÿงš. If the Field Length is unknown, the Rule sets it as a variable, and SCHC sends the compressed field's length in the Compression Residue ๐Ÿ‘‘.

  • A field can show up several times in the CoAP headers ๐Ÿ’œ. This is usually true for elements of a URI (path or queries) ๐Ÿ”ฅ. The SCHC specification [RFC8724] lets a FID appear several times in the Rule and uses the Field Position (FP) to identify the correct instance, which clears up the MO's ambiguity ๐Ÿ’–.
  • Field Lengths defined in CoAP can be too large for LPWAN traffic constraints โœจ. This is especially true for the Message ID field and the Token field ๐Ÿฆ‹. SCHC uses different MOs to do the compression, so see Section 7.4 of [RFC8724] ๐Ÿ’…. In this case, SCHC can apply the Most Significant Bits (MSBs) MO to cut down the information carried on LPWANs ๐ŸŒธ.

4. Compression of CoAP Header Fields

This section talks about compressing the different CoAP header fields ๐ŸŽ€. CoAP compression with SCHC follows the information in Section 7.1 of [RFC8724] ๐Ÿ’–.

4.1. CoAP Version Field

The CoAP version is bidirectional and MUST be elided during SCHC compression, since it always contains the same value ๐Ÿซถ. In the future, or if a new version of CoAP gets defined, new Rules will be needed to avoid ambiguities between versions ๐Ÿ”ฎ.

4.2. CoAP Type Field

CoAP [RFC7252] has four types of messages: two requests (CON, NON), one response (ACK), and one empty message (RST) ๐Ÿฆ‹.

The SCHC compression scheme SHOULD elide this field if, for instance, a client is only sending Non-confirmable (NON) messages or only CON messages โœจ. For the RST message, SCHC may use a dedicated Rule ๐ŸŒธ. For other usages, SCHC can use a "match-mapping" MO ๐Ÿ’….

The rewrite below picks up at Section 5 and works through Section 6.3. It covers the CoAP options, the Uri-Path and Uri-Query handling, and the extensions for Block, Observe and No-Response. The original's requirement keywords, tables, examples and citations are kept exactly as written.

4.3. CoAP Code Field ๐Ÿ’–

Okay so the Code field ๐ŸŽ€ tells you which Request Method CoAP is using. It's defined in an IANA registry [RFC7252], and compressing it works the same way as compressing the Type field. If the Device has a specific role, SCHC can split the code values into two Field Descriptors: one for the request codes in class 0, and one for the response values. SCHC uses the DI to find the right value in the packet. Literally so smart ๐Ÿง โœจ

If the Device only does CoAP client stuff, SCHC compression can shrink the request code down to just the set of requests the client can handle. Lowkey genius ๐Ÿ’…

For values we already know, SCHC can use a "match-mapping" MO. And if SCHC can't compress the Code field, it just sends the values in the Compression Residue. No stress ๐Ÿซถ

4.4. CoAP Message ID Field ๐Ÿฆ‹

SCHC can compress the Message ID field using the "MSB" MO together with the "LSB" CDA. See Section 7.4 of [RFC8724]. Bestie, check that one out ๐ŸŒธ

4.5. CoAP Token Fields ๐Ÿงš

CoAP sets up the Token with two CoAP fields: the Token Length, which lives in the mandatory header, and the Token Value, which comes right after the mandatory CoAP header. It's giving two-part energy ๐Ÿ‘‘

SCHC treats the Token Length like any other header field. If the value never changes, the size can be stored in the TV and elided during transmission. Otherwise, SCHC sends the Token Length in the Compression Residue. โœจ

For the Token Value, SCHC MUST NOT send it as variable-length data in the Compression Residue, because that would get confusing with the Token Length. So SCHC MUST use the Token Length value to set the size of the Compression Residue. SCHC has a special function called "tkl" that the Rule MUST use to complete the Field Descriptor. When decompressing, this function gives back the value from the Token Length field. Not me being all about the precision ๐Ÿ˜ญ๐Ÿ’œ

  1. CoAP Options ๐ŸŽ€

CoAP puts options after the basic header, and they're ordered by option number. See [RFC7252]. Each Option instance uses the format Delta-Type (D-T), Length (L), Value (V). The SCHC Rule builds the description of the option using the following:

  • in the FID: the option number, built from the D-T;
  • in the TV: the option value; and
  • for the Option Length: the information in Sections 7.4.1 and 7.4.2 of [RFC8724].

When the Option Length has a well-known size, the Rule can keep that length value, so SCHC compression doesn't send it. Otherwise, SCHC compression carries the length of the Compression Residue, along with the Compression Residue value. ๐ŸŒˆ

CoAP requests and responses don't carry the same options. So compression Rules can reflect that asymmetry by tagging the DI. Iconic behaviour, honestly ๐Ÿ’…

Note that length coding is different for CoAP options and for SCHC variable size Compression Residue. Don't mix them up, bestie ๐Ÿ™ˆ

The following sections show how SCHC compresses some specific CoAP options.

If CoAP introduces a new option, the SCHC Rules MAY be updated, and the new FID description MUST be assigned so it can be compressed. Otherwise, if no Rule describes this new option, SCHC compression doesn't happen, and SCHC sends the CoAP header uncompressed. โœจ

5.1. CoAP Content and Accept Options ๐ŸŒธ

If the client expects a single value, it can be stored in the TV and elided during transmission. Otherwise, if the client expects several possible values, a "match-mapping" MO SHOULD be used to keep the Compression Residue small. If not, SCHC has to send the option value in the Compression Residue, either fixed or variable length. ๐Ÿฆ‹

5.2. CoAP Option Max-Age, Uri-Host, and Uri-Port Fields ๐Ÿ’œ

These three fields get compressed the same way. When the values of these options are known, SCHC can elide these fields. If the option uses well-known values, SCHC can use a "match-mapping" MO. Otherwise, SCHC uses the "value-sent" MO, and the Compression Residue sends these options' values. ๐Ÿ“

5.3. CoAP Option Uri-Path and Uri-Query Fields ๐Ÿงš

Uri-Path and Uri-Query are repeatable options, which means they can show up several times in the CoAP header with different values. The SCHC Rule description uses the FP to tell the different instances in the path apart. Main character energy in the path ๐Ÿ‘‘

To compress repeatable field values, SCHC can use a "match-mapping" MO to shrink variable paths or queries. In these cases, you can regroup several elements into a single entry to squeeze out more compression. The numbering of elements doesn't change, and the first matching element sets the MO comparison. ๐ŸŒˆ

In Table 1, SCHC can use a single bit in the Compression Residue to code one of the two paths. If regrouping weren't allowed, 2 bits in the Compression Residue would be needed. SCHC sends the third path element as a variable size in the Compression Residue. โœจ

  +==========+=====+====+====+==========+=========+==============+
  |  Field   |  FL | FP | DI |    TV    |    MO   |     CDA      |
  +==========+=====+====+====+==========+=========+==============+
  | Uri-Path |     | 1  | Up | ["/a/b", | match-  | mapping-sent |
  |          |     |    |    | "/c/d"]  | mapping |              |
  +----------+-----+----+----+----------+---------+--------------+
  | Uri-Path | var | 3  | Up |          | ignore  | value-sent   |
  +----------+-----+----+----+----------+---------+--------------+

                   Table 1: Complex Path Example

The length of Uri-Path and Uri-Query might be known when the Rule is defined. Either way, SCHC MUST set the Field Length to a variable value. The Compression Residue size is expressed in bytes. ๐ŸŒธ

SCHC compression can use the MSB MO on a Uri-Path or Uri-Query element. Just be careful with the length, though, because the MSB value is in bits, and the size MUST always be a multiple of 8 bits. ๐Ÿ™ˆ

The length sent at the start of a variable-length Compression Residue tells you the LSB's size in bytes. ๐Ÿ’œ

For example, for a CORECONF path /c/X6?k=eth0, the Rule description can look like this (Table 2):

    +===========+=====+====+====+======+=========+============+
    |   Field   |  FL | FP | DI |  TV  |    MO   |    CDA     |
    +===========+=====+====+====+======+=========+============+
    | Uri-Path  |     | 1  | Up | "c"  | equal   | not-sent   |
    +-----------+-----+----+----+------+---------+------------+
    | Uri-Path  | var | 2  | Up |      | ignore  | value-sent |
    +-----------+-----+----+----+------+---------+------------+
    | Uri-Query | var | 1  | Up | "k=" | MSB(16) | LSB        |
    +-----------+-----+----+----+------+---------+------------+

                 Table 2: CORECONF URI Compression

Table 2 shows the Rule description for a Uri-Path and a Uri-Query. SCHC compresses the first part of the Uri-Path with a "not-sent" CDA. Then SCHC sends the second element of the Uri-Path with its length (i.e., 0x2 "X6"), followed by the query option (i.e., 0x4 "eth0"). ๐Ÿฆ‹

5.3.1. Variable Number of Path or Query Elements ๐ŸŒˆ

SCHC fixes the number of Uri-Path or Uri-Query elements in a Rule when the Rule is created. If the number varies, SCHC SHOULD do one of the following:

  • create several Rules to cover all the possibilities, or
  • create a Rule that defines several entries for Uri-Path to cover the longest path, and send a Compression Residue with a length of 0 to show that a Uri-Path entry is empty.

However, this adds 4 bits to the variable Compression Residue size. See Section 7.4.2 of [RFC8724]. Plan accordingly, bestie ๐Ÿง 

5.4. CoAP Option Size1, Size2, Proxy-URI, and Proxy-Scheme Fields โญ

The SCHC Rule description MAY define sending some field values by setting the TV to "not-sent", the MO to "ignore", and the CDA to "value-sent". A Rule MAY also use a "match-mapping" MO when there are different options for the same FID. Otherwise, the Rule sets the TV to the value, the MO to "equal", and the CDA to "not-sent". ๐Ÿ’–

5.5. CoAP Option ETag, If-Match, If-None-Match, Location-Path, and Location-Query Fields ๐Ÿ˜ญ

A Rule entry can't store the values of these fields. The Rule description MUST always send these values in the Compression Residue. No exceptions, periodt ๐Ÿ’…

  1. SCHC Compression of CoAP Extensions ๐Ÿ‘‘

6.1. Block ๐ŸŽ€

When a packet uses a Block option [RFC7959], SCHC compression MUST send its content in the Compression Residue. The SCHC Rule describes an empty TV with the MO set to "ignore" and the CDA set to "value-sent". The Block option allows fragmentation at the CoAP level that's compatible with SCHC fragmentation. Both fragmentation mechanisms are complementary, and the node can use them for the same packet as needed. โœจ

6.2. Observe ๐Ÿฆ‹

[RFC7641] defines the Observe Option. The SCHC Rule description won't define the TV, but it sets the MO to "ignore" and the CDA to "value-sent". SCHC doesn't limit the maximum size for this option (3 bytes). To reduce the transmission size, either the Device implementation MAY limit the delta between two consecutive values, or a proxy can modify the increment. ๐ŸŒธ

Since the Observe Option MAY use a RST message to tell a server that the client doesn't need the Observe response, a specific SCHC Rule SHOULD exist to allow that message to be compressed with the RST type. ๐Ÿงš

6.3. No-Response ๐ŸŒˆ

[RFC7967] defines a No-Response option that limits the responses a server makes to a request. Different behaviours exist when using this option to limit those responses. If both ends know the value, the SCHC Rule describes a TV with this value, the MO set to "equal", and the CDA set to "not-sent". ๐Ÿ’œ

Otherwise, if the value changes over time, the SCHC Rule sets the MO to "ignore" and the CDA to "value-sent". The Rule MAY also use a "match-mapping" MO to compress this option. ๐Ÿ“

6.4. OSCORE ๐Ÿ”

okay bestie, OSCORE [RFC8613] is the one that gives CoAP messages end-to-end protection ๐Ÿ’œ and this section is all about how SCHC Rules can compress OSCORE-protected messages. we're literally compressing encrypted stuff, so it's giving main character energy ๐Ÿ’…

so the OSCORE option value has its own little encoding, defined in Section 6.1 of [RFC8613]. the first byte is the boss ๐Ÿ‘‘: it holds flags that tell you what's inside the option. the three most significant bits are reserved and always set to 0 ๐Ÿง, then bit h says whether the kid context field is there, bit k says whether a kid field is there, and the three least significant bits, n, tell you how long the piv (Partial Initialization Vector) field is, in bytes. when n = 0, no piv is present. check out the layout ๐Ÿ‘‡

      0 1 2 3 4 5 6 7 <--------- n bytes ------------->
     +-+-+-+-+-+-+-+-+---------------------------------
     |0 0 0|h|k|  n  |      Partial IV (if any) ...
     +-+-+-+-+-+-+-+-+---------------------------------
     |               |                                |
     |<--  CoAP   -->|<------ CoAP OSCORE_piv ------> |
        OSCORE_flags

      <- 1 byte -> <------ s bytes ----->
     +------------+----------------------+-----------------------+
     | s (if any) | kid context (if any) | kid (if any)      ... |
     +------------+----------------------+-----------------------+
     |                                   |                       |
     | <------ CoAP OSCORE_kidctx ------>|<-- CoAP OSCORE_kid -->|

                       Figure 4: OSCORE Option

the flag byte is followed by the piv field, the kid context field, and then the kid field, in that order ๐ŸŽ€. and if the kid context field is present, its length in bytes is written in the first byte, which the figure calls "s" ๐ŸŒธ

now, to compress this well, the Rule has to know about the OSCORE option and the fields inside it โœจ. conceptually there are up to four distinct pieces of info in there: the flag bits, the piv, the kid context, and the kid. so the SCHC Rule splits the OSCORE option into four Field Descriptors so it can compress each one:

  • CoAP OSCORE_flags
  • CoAP OSCORE_piv
  • CoAP OSCORE_kidctx
  • CoAP OSCORE_kid

and yes, Figure 4 shows the OSCORE option format with those four fields layered right on top ๐Ÿฆ‹. quick note: the CoAP OSCORE_kidctx field directly includes the size octet, s ๐Ÿซถ


7. Examples of CoAP Header Compression ๐Ÿงš

7.1. Mandatory Header with CON Message ๐Ÿ’Œ

okay so in this first scenario ๐Ÿ˜ญ, the SCHC compressor on the NGW side gets a POST message from an Internet client, and the Device immediately acknowledges it. it's a whole little conversation ๐Ÿ’ฌ Table 3 lays out the SCHC Rule descriptions for this one ๐Ÿ‘€

   +===================================================================+
   |RuleID 1                                                           |
   +==========+===+==+==+======+===============+===============+=======+
   |  Field   | FL|FP|DI|  TV  |       MO      |      CDA      |  Sent |
   |          |   |  |  |      |               |               | [bits]|
   +==========+===+==+==+======+===============+===============+=======+
   |CoAP      |2  |1 |Bi|01    | equal         | not-sent      |       |
   |version   |   |  |  |      |               |               |       |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP Type |2  |1 |Dw|CON   | equal         | not-sent      |       |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP Type |2  |1 |Up|[ACK, | match-mapping | matching-sent |T      |
   |          |   |  |  |RST]  |               |               |       |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP TKL  |4  |1 |Bi|0     | equal         | not-sent      |       |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP Code |8  |1 |Bi|[0.00,| match-mapping | matching-sent |CC CCC |
   |          |   |  |  |...   |               |               |       |
   |          |   |  |  |5.05] |               |               |       |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP MID  |16 |1 |Bi|0000  | MSB(7)        | LSB           |MID    |
   +----------+---+--+--+------+---------------+---------------+=======+
   |CoAP Uri- |var|1 |Dw|path  | equal 1       | not-sent      |       |
   |Path      |   |  |  |      |               |               |       |
   +----------+---+--+--+------+---------------+---------------+=======+

        Table 3: CoAP Context to Compress Header without Token

in this example, SCHC compression elides the version and Token Length fields, and honestly that's such a flex ๐Ÿ’… the 25 Method and Response Codes defined in [RFC7252] get shrunk down to just 5 bits using a "match-mapping" MO โœจ the Uri-Path has a single element, which is indicated in the TV and then elided with the CDA "not-sent" ๐ŸŒˆ

so SCHC compression ends up sending only the Type, a mapped code, and the least significant bits of the Message ID (that's 9 bits in the example above) ๐Ÿ“

โš ๏ธ bestie, heads up: a client sitting in an Application Server that's sending a request to a server in the Device may not get compressed through this Rule ๐Ÿ™ˆ the reason is that the MID might not start with 7 bits equal to 0. the fix is that a CoAP proxy placed before SCHC C/D can rewrite the Message ID so it fits the value and matches the Rule ๐Ÿซถ

this is the glow-up we needed ๐Ÿ’–

7.2. OSCORE Compression

okay so OSCORE is all about end-to-end encryption for CoAP messages, bestie ๐Ÿ” The goal is to hide the message as much as possible while still letting proxies do their thing. That's the whole vibe.

Conceptually, the CoAP message gets split into an Inner Plaintext and an Outer OSCORE message ๐Ÿฆ‹ The Inner Plaintext holds the sensitive stuff that proxies don't need. It's still part of the message, so it stays encrypted until it reaches its final destination. The Outer Message is basically a shell that looks like a regular CoAP message. It carries every option and piece of info that proxies and caches need. Figure 5 below shows this split.

                         Original CoAP Packet
                      +-+-+---+-------+---------------+
                      |v|t|TKL| code  | Message ID    |
                      +-+-+---+-------+---------------+....+
                      | Token                              |
                      +-------------------------------.....+
                      | Options (IEU)            |
                      .                          .
                      .                          .
                      +------+-------------------+
                      | 0xFF |
                      +------+------------------------+
                      |                               |
                      |     Payload                   |
                      |                               |
                      +-------------------------------+
                             /                \
                            /                  \
                           /                    \
                          /                      \
        Outer Header     v                        v  Plaintext
     +-+-+---+--------+---------------+          +-------+
     |v|t|TKL|new code| Message ID    |          | code  |
     +-+-+---+--------+---------------+....+     +-------+-----......+
     | Token                               |     | Options (E)       |
     +--------------------------------.....+     +-------+------.....+
     | Options (IU)             |                | 0xFF  |
     .                          .                +-------+-----------+
     . OSCORE Option            .                |                   |
     +------+-------------------+                | Payload           |
     | 0xFF |                                    |                   |
     +------+                                    +-------------------+

Figure 5: CoAP Packet Split into OSCORE Outer Header and Plaintext

Figure 5 shows the packet format for the OSCORE Outer header and Plaintext.

CoAP sorts its options into three classes, and each one gets a different kind of protection from the protocol ๐Ÿ’…

  • Class E: Encrypted options moved to the Inner Plaintext.
  • Class I: Integrity-protected options included in the Additional Authenticated Data (AAD) for the encryption of the Plaintext, but otherwise left untouched in the Outer Message.
  • Class U: Unprotected options left untouched in the Outer Message.

These classes point out that the Outer option contains the OSCORE option and that the message is OSCORE protected ๐Ÿ”ฅ This option carries the info needed to retrieve the Security Context, and the endpoint uses that Security Context to decrypt the message correctly.

In the Outer header, the original code gets hidden and swapped for a default dummy value ๐Ÿ™ˆ As seen in Sections 4.1.3.5 and 4.2 of [RFC8613], the message code becomes POST for requests and Changed for responses when CoAP is not using the Observe Option. If CoAP does use Observe, the OSCORE message code becomes FETCH for requests and Content for responses.

The first byte of the Plaintext holds the original packet code. After that comes the message code, the class E options, and, if there is one, the original message payload, preceded by its payload marker.

Next, an Authenticated Encryption with Associated Data (AEAD) algorithm encrypts the Plaintext โœจ This integrity-protects the Security Context parameters and, eventually, any class I options from the Outer header. The resulting ciphertext becomes the new payload of the OSCORE message, as shown in Figure 6.

As defined in [RFC5116], this ciphertext is the encrypted Plaintext's concatenation of the Authentication Tag. Note that Inner Compression only affects the Plaintext before encryption. The Authentication Tag is fixed in length and uncompressed, so it counts as part of the cost of protection ๐Ÿง

     Outer Header
  +-+-+---+--------+---------------+
  |v|t|TKL|new code| Message ID    |
  +-+-+---+--------+---------------+....+
  | Token                               |
  +--------------------------------.....+
  | Options (IU)             |
  .                          .
  . OSCORE Option            .
  +------+-------------------+
  | 0xFF |
  +------+---------------------------+
  |                                  |
  | Ciphertext: Encrypted Inner      |
  |             Header and Payload   |
  |             + Authentication Tag |
  |                                  |
  +----------------------------------+

Figure 6: OSCORE Message

The SCHC compression scheme compresses both the Plaintext before encryption and the resulting OSCORE message after encryption ๐Ÿ’– See Figure 7.

The OSCORE message turns into a segmented process, where SCHC compression runs independently in two stages. Each stage has its own set of Rules: the Inner SCHC Rules and the Outer SCHC Rules. This way, compression is applied to all fields of the original CoAP message ๐ŸŒˆ

     Outer Message                             OSCORE Plaintext
  +-+-+---+--------+---------------+          +-------+
  |v|t|TKL|new code| Message ID    |          | code  |
  +-+-+---+--------+---------------+....+     +-------+-----......+
  | Token                               |     | Options (E)       |
  +--------------------------------.....+     +-------+------.....+
  | Options (IU)             |                | 0xFF  |
  .                          .                +-------+-----------+
  . OSCORE Option            .                |                   |
  +------+-------------------+                | Payload           |
  | 0xFF |                                    |                   |
  +------+------------+                       +-------------------+
  |  Ciphertext       |<---------\                      |
  |                   |          |                      v
  +-------------------+          |             +-----------------+
          |                      |             |   Inner SCHC    |
          v                      |             |   Compression   |
    +-----------------+          |             +-----------------+
    |   Outer SCHC    |          |                     |
    |   Compression   |          |                     v
    +-----------------+          |             +-------+
          |                      |             |RuleID |
          v                      |             +-------+-----------+
    +--------+             +------------+      |Compression Residue|
    |RuleID' |             | Encryption | <--  +----------+--------+
    +--------+-----------+ +------------+      |                   |
    |Compression Residue'|                     | Payload           |
    +-----------+--------+                     |                   |
    |  Ciphertext        |                     +-------------------+
    |                    |
    +--------------------+

Figure 7: OSCORE Compression Diagram

Note that since the corresponding endpoint can only decrypt the Inner part of the message, this endpoint will also have to implement Inner SCHC Compression/Decompression. No skipping that step, bestie ๐Ÿซถ

7.3. Example OSCORE Compression

okay this section is the fun part ๐ŸŽ€ It walks through a GET request and its Content response, going from a Device-based CoAP client to a cloud-based CoAP server. It also sketches a possible set of Rules for Inner SCHC Compression and Outer SCHC Compression. Then it dumps the results and compares SCHC + OSCORE performance with SCHC + CoAP performance. The whole thing gives us an approximation of the cost of security with SCHC-OSCORE ๐Ÿ”ฅ

Our first CoAP message is the GET request in Figure 8.

Original message:
=================
0x4101000182bb74656d7065726174757265

Header:
0x4101
01   Ver
  00   CON
    0001   TKL
        00000001   Request Code 1 "GET"

0x0001 = mid
0x82 = token

Options:
0xbb74656d7065726174757265
Option 11: URI_PATH
Value = temperature

Original message length:   17 bytes

Figure 8: CoAP GET Request

Its matching response is the Content response in Figure 9 โœจ

Original message:
=================
0x6145000182ff32332043

Header:
0x6145
01   Ver
  10   ACK
    0001   TKL
        01000101 Successful Response Code 69 "2.05 Content"

0x0001 = mid
0x82 = token

0xFF  Payload marker
Payload:
0x32332043

Original message length:   10 bytes

Figure 9: CoAP Content Response

The SCHC Rules for Inner Compression cover all the fields already present in a regular CoAP message. The methods described in Section 4 apply to these fields. Table 4 gives an example ๐Ÿ’…

+===================================================================+
|RuleID 0                                                           |
+========+==+==+==+===========+===============+==============+======+
| Field  |FL|FP|DI|     TV    |       MO      |     CDA      | Sent |
|        |  |  |  |           |               |              |[bits]|
+========+==+==+==+===========+===============+==============+======+
|CoAP    |8 |1 |Up|1          | equal         | not-sent     |      |
|Code    |  |  |  |           |               |              |      |
+--------+--+--+--+-----------+---------------+--------------+======+
|CoAP    |8 |1 |Dw|[69,132]   | match-mapping | mapping-sent |c     |
|Code    |  |  |  |           |               |              |      |
+--------+--+--+--+-----------+---------------+--------------+======+
|CoAP    |  |1 |Up|temperature| equal         | not-sent     |      |
|Uri-Path|  |  |  |           |               |              |      |
+--------+--+--+--+-----------+---------------+--------------+======+

Table 4: Inner SCHC Rule

Figure 10 shows the Plaintext we get for the example GET request ๐Ÿงš The packet goes through Inner Compression and encryption up to the payload, and the Outer OSCORE message then adds the result of that Inner process.

   ________________________________________________________
  |                                                        |
  | OSCORE Plaintext                                       |
  |                                                        |
  | 0x01bb74656d7065726174757265  (13 bytes)               |
  |                                                        |
  | 0x01 Request Code GET                                  |
  |                                                        |
  |      bb74656d7065726174757265 Option 11: URI_PATH      |
  |                               Value = temperature      |
  |________________________________________________________|

okay so the next bit is where the sauce really is โœจ we're still in the OSCORE example, and now the plaintext gets squeezed before it gets locked up ๐Ÿ”๐Ÿ’–

                                 |
                                 |
                                 | Inner SCHC Compression
                                 |
                                 v
                   _________________________________
                  |                                 |
                  | Compressed Plaintext            |
                  |                                 |
                  | 0x00                            |
                  |                                 |
                  | RuleID = 0x00 (1 byte)          |
                  | (No Compression Residue)        |
                  |_________________________________|

                                 |
                                 | AEAD Encryption
                                 |  (piv = 0x04)
                                 v
            _________________________________________________
           |                                                 |
           |  encrypted_plaintext = 0xa2 (1 byte)            |
           |  tag = 0xc54fe1b434297b62 (8 bytes)             |
           |                                                 |
           |  ciphertext = 0xa2c54fe1b434297b62 (9 bytes)    |
           |_________________________________________________|

      Figure 10: Plaintext Compression and Encryption for GET Request

so in this case the original message has no payload ๐Ÿ™ˆ, which means the plaintext shrinks all the way down to just 1 byte, the RuleID ๐ŸŽ€. The AEAD algorithm keeps that length in its first output and gives you a fixed-size tag ๐Ÿฆ‹. SCHC can't compress the tag, so the OSCORE message has to carry it uncompressed. Integrity protection adds overhead to the total message length, which limits how much compression you can get. That's the price of adding security to the exchange ๐Ÿ’…

Figure 11 shows the process for the example Content response. The Compression Residue here is 1 bit long ๐ŸŒธ Since SCHC adds padding after the payload, the misalignment makes the hex code of the payload look different from the original, even though SCHC still can't compress the tag. The tag bytes cost something and limit SCHC's performance, but they're what bring security to the transmission ๐Ÿซถ

     ________________________________________________________
     |                                                        |
     | OSCORE Plaintext                                       |
     |                                                        |
     | 0x45ff32332043  (6 bytes)                              |
     |                                                        |
     | 0x45 Successful Response Code 69 "2.05 Content"        |
     |                                                        |
     |     ff Payload marker                                  |
     |                                                        |
     |       32332043 Payload                                 |
     |________________________________________________________|

                                 |
                                 |
                                 | Inner SCHC Compression
                                 |
                                 v
         _________________________________________________
        |                                                 |
        | Compressed Plaintext                            |
        |                                                 |
        | 0x001919902180 (6 bytes)                        |
        |                                                 |
        |   00 RuleID                                     |
        |                                                 |
        |  0b0 (1 bit match-mapping Compression Residue)  |
        |       0x32332043 >> 1 (shifted payload)         |
        |                        0b0000000 Padding        |
        |_________________________________________________|

                                 |
                                 | AEAD Encryption
                                 |  (piv = 0x04)
                                 v
        _________________________________________________________
       |                                                         |
       |  encrypted_plaintext = 0x10c6d7c26cc1 (6 bytes)         |
       |  tag = 0xe9aef3f2461e0c29 (8 bytes)                     |
       |                                                         |
       |  ciphertext = 0x10c6d7c26cc1e9aef3f2461e0c29 (14 bytes) |
       |_________________________________________________________|

    Figure 11: Plaintext Compression and Encryption for Content Response

The Outer SCHC Rule (Table 5) must process the OSCORE options fields ๐Ÿงš Figures 12 and 13 show a dump of the OSCORE messages generated from the example messages. They include the Inner Compressed ciphertext in the payload, and these are the messages that have to be compressed via the Outer SCHC Compression scheme ๐Ÿ’œ

Table 5 shows a possible set of Outer Rule items to compress the Outer header ๐Ÿ“

   +===================================================================+
   |RuleID 0                                                           |
   +===============+===+==+==+================+=======+=========+======+
   |     Field     | FL|FP|DI|       TV       |   MO  |   CDA   | Sent |
   |               |   |  |  |                |       |         |[bits]|
   +===============+===+==+==+================+=======+=========+======+
   |CoAP version   |2  |1 |Bi| 01             |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP Type      |2  |1 |Up| 0              |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP Type      |2  |1 |Dw| 2              |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP TKL       |4  |1 |Bi| 1              |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP Code      |8  |1 |Up| 2              |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP Code      |8  |1 |Dw| 68             |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP MID       |16 |1 |Bi| 0000           |MSB(12)|LSB      |MMMM  |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP Token     |tkl|1 |Bi| 0x80           |MSB(5) |LSB      |TTT   |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP           |8  |1 |Up| 0x09           |equal  |not-sent |      |
   |OSCORE_flags   |   |  |  |                |       |         |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP OSCORE_piv|var|1 |Up| 0x00           |MSB(4) |LSB      |PPPP  |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP OSCORE_kid|var|1 |Up| 0x636c69656e70 |MSB(52)|LSB      |KKKK  |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP           |var|1 |Bi| b''            |equal  |not-sent |      |
   |OSCORE_kidctx  |   |  |  |                |       |         |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP           |8  |1 |Dw| b''            |equal  |not-sent |      |
   |OSCORE_flags   |   |  |  |                |       |         |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP OSCORE_piv|var|1 |Dw| b''            |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+
   |CoAP OSCORE_kid|var|1 |Dw| b''            |equal  |not-sent |      |
   +---------------+---+--+--+----------------+-------+---------+======+

                          Table 5: Outer SCHC Rule
   Protected message:
   ==================
   0x4102000182d8080904636c69656e74ffa2c54fe1b434297b62
   (25 bytes)

   Header:
   0x4102
   01   Ver
     00   CON
       0001   TKL
           00000010   Request Code 2 "POST"

   0x0001 = mid
   0x82 = token

   Options:
   0xd8080904636c69656e74 (10 bytes)
   Option 21: OBJECT_SECURITY
   Value = 0x0904636c69656e74
             09 = 000 0 1 001 flag byte
                      h k  n
               04 piv
                 636c69656e74 kid

   0xFF  Payload marker
   Payload:
   0xa2c54fe1b434297b62 (9 bytes)

         Figure 12: Protected and Inner SCHC Compressed GET Request
   Protected message:
   ==================
   0x6144000182d008ff10c6d7c26cc1e9aef3f2461e0c29
   (22 bytes)

   Header:
   0x6144
   01   Ver
     10   ACK
       0001   TKL
           01000100   Successful Response Code 68 "2.04 Changed"

   0x0001 = mid
   0x82 = token

   Options:
   0xd008 (2 bytes)
   Option 21: OBJECT_SECURITY
   Value = b''

   0xFF  Payload marker
   Payload:
   0x10c6d7c26cc1e9aef3f2461e0c29 (14 bytes)

      Figure 13: Protected and Inner SCHC Compressed Content Response

Now for the flag bits ๐Ÿšฉ A few SCHC compression methods are handy here, depending on the application. The simplest option is to fix the flags to one value, pairing an MO of "equal" with a CDA of "not-sent". That definition saves the most bits, but it can cost you flexibility. Otherwise, SCHC could use a "match-mapping" MO to pick from several configurations for the exchange. If neither works for you, the SCHC description may use an "MSB" MO to mask off the three hard-coded most significant bits ๐ŸŽ€

Heads up: fixing a flag bit limits which CoAP options you can use in the exchange, because those option choices depend on specific options. So choose wisely, bestie ๐Ÿ’…

The piv field is a great candidate for masking some bits off with an "MSB" MO and an "LSB" CDA โœจ This SCHC description could shine in applications where messages are infrequent, like LPWAN technologies. Just know that compressing the sequence numbers may reduce how many sequence numbers you can use in an exchange. Once the sequence number goes past that maximum value, the OSCORE keys need to be re-established ๐Ÿ”‘

The size, s, that is included in the kid context field MAY be masked off with an "LSB" CDA. The rest of the field could have more bits masked off, or the whole field could be fixed with a MO of "equal" and a CDA of "not-sent". The same goes for the kid field ๐Ÿฆ‹

The Outer Rule of Table 5 is applied to the example GET request and Content response. Figures 14 and 15 show the resulting messages ๐ŸŒˆ

   Compressed message:
   ==================
   0x001489458a9fc3686852f6c4 (12 bytes)
   0x00 RuleID
       1489 Compression Residue
           458a9fc3686852f6c4 Padded payload

   Compression Residue:
   0b 0001 010 0100 0100 (15 bits -> 2 bytes with padding)
       mid tkn piv  kid

   Payload
   0xa2c54fe1b434297b62 (9 bytes)

   Compressed message length: 12 bytes

               Figure 14: SCHC-OSCORE Compressed GET Request
   Compressed message:
   ==================
   0x0014218daf84d983d35de7e48c3c1852 (16 bytes)
   0x00 RuleID
       14 Compression Residue
         218daf84d983d35de7e48c3c1852 Padded payload
   Compression Residue:
   0b0001 010 (7 bits -> 1 byte with padding)
     mid  tkn

   Payload
   0x10c6d7c26cc1e9aef3f2461e0c29 (14 bytes)

   Compressed message length: 16 bytes

             Figure 15: SCHC-OSCORE Compressed Content Response

In contrast ๐Ÿ‘€ comparing these results with what you'd get by SCHC-compressing the original CoAP messages without OSCORE protection means compressing the CoAP messages according to the SCHC Rule in Table 6 ๐Ÿง

Okay so here's the wrap-up of the whole thing ๐Ÿ’… Table 6 is basically the cheat sheet for the no-OSCORE setup, and then we get the lil "about 10 bytes" flex when OSCORE shows up ๐Ÿฆ‹

+===================================================================+
|RuleID 1                                                           |
+========+===+==+==+===========+===============+=============+======+
| Field  | FL|FP|DI|     TV    |       MO      |     CDA     | Sent |
|        |   |  |  |           |               |             |[bits]|
+========+===+==+==+===========+===============+=============+======+
|CoAP    |2  |1 |Bi|01         | equal         |not-sent     |      |
|version |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |2  |1 |Up|0          | equal         |not-sent     |      |
|Type    |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |2  |1 |Dw|2          | equal         |not-sent     |      |
|Type    |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP TKL|4  |1 |Bi|1          | equal         |not-sent     |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |8  |1 |Up|2          | equal         |not-sent     |      |
|Code    |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |8  |1 |Dw|[69,132]   | match-mapping |mapping-sent |C     |
|Code    |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP MID|16 |1 |Bi|0000       | MSB(12)       |LSB          |MMMM  |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |tkl|1 |Bi|0x80       | MSB(5)        |LSB          |TTT   |
|Token   |   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+
|CoAP    |   |1 |Up|temperature| equal         |not-sent     |      |
|Uri-Path|   |  |  |           |               |             |      |
+--------+---+--+--+-----------+---------------+-------------+======+

Table 6: SCHC-CoAP Rule (No OSCORE)

The Rule in Table 6 gives us the SCHC compression results in Figure 16 for the request and Figure 17 for the response ๐ŸŽ€

Compressed message:
==================
0x0114
0x01 = RuleID

Compression Residue:
0b00010100 (1 byte)

Compressed message length: 2 bytes

Figure 16: CoAP GET Compressed without OSCORE

Compressed message:
==================
0x010a32332043
0x01 = RuleID

Compression Residue:
0b00001010 (1 byte)

Payload
0x32332043

Compressed message length: 6 bytes

Figure 17: CoAP Content Compressed without OSCORE

Look at that glow-up ๐ŸŒธ The gap between SCHC + OSCORE and regular SCHC + CoAP is about 10 bytes, so it's not a huge deal, just a little extra.


8. IANA Considerations โœจ

Good news bestie: this document has no IANA actions ๐Ÿ™Œ Nothing to register here, so you can chill.

9. Security Considerations ๐Ÿ”ฅ

Okay, this section is serious, so let's get into it ๐Ÿ’€ Using SCHC header compression on CoAP header fields only changes how the header info is represented. SCHC header compression by itself doesn't raise or lower the overall security level of the communication. When the connection doesn't use a security protocol (OSCORE, DTLS, etc.), you need a Layer 2 security mechanism to protect the SCHC messages, no excuses ๐Ÿ˜ค

If an LPWAN is your Layer 2 technology, the SCHC security considerations in [RFC8724] still apply. If you're using some other Layer 2 protocol, then a cryptographic integrity-protection mechanism to protect the SCHC headers is REQUIRED. That integrity protection is what keeps the properties that [RFC8724] relies upon working, so it's not optional ๐Ÿ”

When SCHC is used with OSCORE, the security considerations in [RFC8613] keep applying ๐Ÿฆ‹

When SCHC is used with the OSCORE Outer headers, you have to pick the Initialization Vector (IV) size in the Compression Residue very carefully ๐Ÿง There's a trade-off here: a longer "MSB" MO prefix gives you better compression efficiency, but the Device then has to renew its key material more often, otherwise the IV grows into something that can't be compressed anymore. Key renewal takes several message exchanges and a lot of energy-heavy computation, and the best balance depends on the specifics of the Device and how it's actually used ๐Ÿ’œ

If an attacker can slip a corrupted SCHC-compressed packet onto a link, they can launch DoS attacks by making the decompressor burn through resources. But honestly, an attacker who can inject packets at the link layer can do way more damaging stuff, so that's the bigger problem ๐Ÿ˜ญ

SCHC compression produces variable-length Compression Residues for some CoAP fields. In the compressed header, the length field that gets sent is not the length of the original header field, but the length of the Compression Residue actually being transmitted ๐ŸŒˆ If a corrupted packet reaches the decompressor with a longer or shorter length than the original compressed representation had, the SCHC decompression procedures will catch the error and drop the packet.

SCHC header compression Rules MUST remain tightly coupled between the compressor and the decompressor. If the compression Rules get out of sync, a Compression Residue might be decompressed differently at the receiver than the initial message that was submitted to compression procedures. So any time the context Rules get updated on an OSCORE endpoint, that endpoint MUST trigger OSCORE key re-establishment. Other message-protection mechanisms may need similar procedures to signal Rule updates. โš ๏ธ

10. Normative References ๐Ÿ“š

[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>.

[RFC5116]  McGrew, D., "An Interface and Algorithms for Authenticated
           Encryption", RFC 5116, DOI 10.17487/RFC5116, January 2008,
           <https://www.rfc-editor.org/info/rfc5116>.

[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>.

[RFC7641]  Hartke, K., "Observing Resources in the Constrained
           Application Protocol (CoAP)", RFC 7641,
           DOI 10.17487/RFC7641, September 2015,
           <https://www.rfc-editor.org/info/rfc7641>.

[RFC7959]  Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in
           the Constrained Application Protocol (CoAP)", RFC 7959,
           DOI 10.17487/RFC7959, August 2016,
           <https://www.rfc-editor.org/info/rfc7959>.

[RFC7967]  Bhattacharyya, A., Bandyopadhyay, S., Pal, A., and T.
           Bose, "Constrained Application Protocol (CoAP) Option for
           No Server Response", RFC 7967, DOI 10.17487/RFC7967,
           August 2016, <https://www.rfc-editor.org/info/rfc7967>.

[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>.

[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>.

[RFC8724]  Minaburo, A., Toutain, L., Gomez, C., Barthel, D., and JC.
           Zรบรฑiga, "SCHC: Generic Framework for Static Context Header
           Compression and Fragmentation", RFC 8724,
           DOI 10.17487/RFC8724, April 2020,
           <https://www.rfc-editor.org/info/rfc8724>.

Acknowledgements ๐Ÿ’–

The authors want to give a huge shoutout (in alphabetical order) to Christian Amsuss, Dominique Barthel, Carsten Bormann, Theresa Enghardt, Thomas Fossati, Klaus Hartke, Benjamin Kaduk, Francesca Palombini, Alexander Pelov, Gรถran Selander, and ร‰ric Vyncke ๐Ÿซถ

Authors' Addresses ๐ŸŒธ

Ana Minaburo
Acklio
1137A avenue des Champs Blancs
35510 Cesson-Sevigne Cedex
France

Email: ana@ackl.io


Laurent Toutain
Institut MINES TELECOM; IMT Atlantique
CS 17607
2 rue de la Chataigneraie
35576 Cesson-Sevigne Cedex
France

Email: Laurent.Toutain@imt-atlantique.fr


Ricardo Andreasen
Universidad de Buenos Aires
Av. Paseo Colon 850
C1063ACV Ciudad Autonoma de Buenos Aires
Argentina

Email: randreasen@fi.uba.ar
๐Ÿ“ฆ where this page comes from