RFC 9175

Constrained Application Protocol (CoAP): Echo, Request-Tag, and Token Processing

๐Ÿ“… published February 2022, from ietf

RFC 9175: Constrained Application Protocol (CoAP): Echo, Request-Tag, and Token Processing ๐ŸŽ€

okay bestie, this one is a Standards Track doc from the IETF, published February 2022 ๐Ÿ“…. It was written by C. Amsรผss, J. PreuรŸ Mattsson, and G. Selander, all from Ericsson AB โœจ. It's the ISSN 2070-1721 one, and the header says it updates RFC 7252 ๐Ÿฆ‹. It doesn't list anything it obsoletes, so the only change to an older spec is that update.

Abstract โœจ

This doc is all about making CoAP safer in specific situations ๐Ÿ”. It adds the Echo option, which lets a CoAP server check that a request is fresh, or make a client prove it can actually be reached at the address it claims ๐Ÿ“ฌ. It also adds the Request-Tag option, which helps the server match up block-wise fragments that belong to the same request ๐Ÿงฉ.

It updates RFC 7252 in three ways ๐Ÿ’…. First, it sets processing requirements for client Tokens. Second, it forbids non-secure reuse of Tokens, so responses stay tied to the right requests when CoAP runs with a security protocol ๐Ÿ”’. Third, it adds amplification mitigation, where the Echo option is now recommended ๐Ÿ“ฃ.

Status of This Memo ๐ŸŒธ

This is an Internet Standards Track document ๐Ÿ†.

It's a product of the Internet Engineering Task Force (IETF), so it reflects consensus from the IETF community ๐Ÿซถ. It went through public review and was approved for publication by the Internet Engineering Steering Group (IESG) ๐Ÿ‘‘. If you want more on Internet Standards, check Section 2 of RFC 7841 ๐Ÿ“š.

Info about the current status, any errata, and how to send feedback lives at https://www.rfc-editor.org/info/rfc9175 ๐Ÿ’Œ.

Copyright (c) 2022 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) as they were in effect on the date of publication ๐Ÿ“œ. Please read these carefully, since they spell out your rights and restrictions for this document ๐Ÿง. Code Components pulled out of this document must include the Revised BSD License text described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as the Revised BSD License describes ๐ŸŽ€.

Table of Contents ๐Ÿ—บ๏ธ

1.  Introduction
  1.1.  Terminology
2.  Request Freshness and the Echo Option
  2.1.  Request Freshness
  2.2.  The Echo Option
    2.2.1.  Echo Option Format
  2.3.  Echo Processing
  2.4.  Applications of the Echo Option
  2.5.  Characterization of Echo Applications
    2.5.1.  Time-Based versus Event-Based Freshness
    2.5.2.  Authority over Used Information
    2.5.3.  Protection by a Security Protocol
  2.6.  Updated Amplification Mitigation Requirements for Servers
3.  Protecting Message Bodies Using Request Tags
  3.1.  Fragmented Message Body Integrity
  3.2.  The Request-Tag Option
    3.2.1.  Request-Tag Option Format
  3.3.  Request-Tag Processing by Servers
  3.4.  Setting the Request-Tag
  3.5.  Applications of the Request-Tag Option
    3.5.1.  Body Integrity Based on Payload Integrity
    3.5.2.  Multiple Concurrent Block-Wise Operations
    3.5.3.  Simplified Block-Wise Handling for Constrained Proxies
  3.6.  Rationale for the Option Properties
  3.7.  Rationale for Introducing the Option
  3.8.  Block2 and ETag Processing
4.  Token Processing for Secure Request-Response Binding
  4.1.  Request-Response Binding
  4.2.  Updated Token Processing Requirements for Clients
5.  Security Considerations
  5.1.  Token Reuse
6.  Privacy Considerations
7.  IANA Considerations
8.  References
  8.1.  Normative References
  8.2.  Informative References
Appendix A.  Methods for Generating Echo Option Values
Appendix B.  Request-Tag Message Size Impact
Acknowledgements
Authors' Addresses

1. Introduction ๐ŸŒท

okay so the original CoAP specs (RFC 7252, RFC 7641, and RFC 7959) were built on the idea that security would live on a separate layer, usually DTLS [RFC6347] ๐Ÿ”. That works for a lot of stuff, but some use cases need extra features or processing to make CoAP secure, so this doc adds those security upgrades โœจ.

This doc adds two options: Echo and Request-Tag ๐ŸŽ€. Echo lets a CoAP server check that a request is fresh, which can help sync state or force a client to prove it's reachable at its claimed address ๐Ÿ“ก. Request-Tag helps the server match up message fragments from the same request when they were split with CoAP block-wise transfer, which blocks some attacks and makes concurrent block-wise operations possible ๐Ÿงฉ. These options don't replace a security protocol on their own ๐Ÿ™…โ€โ™€๏ธ. They define the format and processing for data that gives extra security when it's integrity protected with something like DTLS [RFC6347], TLS [RFC8446], or Object Security for Constrained RESTful Environments (OSCORE) [RFC8613] ๐Ÿฆ‹.

This doc updates [RFC7252] with a recommendation that servers use the Echo option to mitigate amplification attacks ๐Ÿ“ฃ.

It also updates the Token processing requirements for clients in [RFC7252] ๐Ÿ’…. The new rules forbid non-secure reuse of Tokens, so responses stay bound to the right requests when CoAP runs with security. That heads off error cases and attacks where a client might link the wrong response to a request ๐Ÿ™ˆ.

Each of the following sections opens with a more detailed intro to its topic in its first subsection ๐Ÿ’–.

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 read as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they show up in all capitals, just like they do here ๐Ÿง.

Like [RFC7252], this doc is built on the Representational State Transfer [REST] architecture of the Web ๐ŸŒ.

Unless otherwise stated, "client" and "server" mean "CoAP client" and "CoAP server", as defined in [RFC7252] ๐Ÿ’œ.

A message's "freshness" tells you when it was sent, measured on the recipient's timescale โฐ. A server that gets a request can either verify that it's fresh, or determine that freshness can't be verified. What counts as fresh depends on the application. Examples include "no more than 42 seconds ago" or "after this server's last reboot" ๐Ÿ“.

The words "payload" and "body" of a message are used as in [RFC7959] ๐ŸŽ. The full exchange of a request and response body is called a (REST) "operation" ๐Ÿ”. An operation that gets fragmented using [RFC7959] is a "block-wise operation" ๐Ÿงฉ. A block-wise operation that fragments the request body is a "block-wise request operation". A block-wise operation that fragments the response body is a "block-wise response operation" ๐ŸŒˆ.

Two request messages are "matchable" if they happen between the same endpoint pair, have the same code, and have the same set of options. The exception: elective NoCacheKey options and options used in block-wise transfer (Block1, Block2, and Request-Tag) don't need to match ๐Ÿง . Two block-wise request operations are matchable if their request messages are matchable ๐Ÿซง.

Two matchable block-wise request operations are "concurrent" if a block from the second request gets exchanged even though the client still plans to exchange more blocks in the first operation ๐ŸŒ€. (Concurrent block-wise request operations from a single endpoint aren't possible with the options from [RFC7959]. See the last paragraphs of Sections 2.4 and 2.5 for why, since the second operation's block overwrites any state from the first exchange ๐Ÿ™ƒ.)

The Echo and Request-Tag options are defined in this document ๐ŸŽ€.

2. Request Freshness and the Echo Option โณ

2.1. Request Freshness ๐Ÿ•ฐ๏ธ

In general, a CoAP server that receives a request can't verify when the CoAP client sent it ๐Ÿ˜ฌ. That stays true even when the request is protected by a security protocol like DTLS. That's why CoAP requests are open to certain delay attacks, which are especially dangerous with actuators [COAP-ATTACKS] ๐Ÿšจ. Some attacks can be blocked by setting up fresh session keys, like doing a DTLS handshake for every request. But in general that isn't a good fit for constrained environments, because it adds message overhead and latency ๐Ÿข. Also, if there are proxies, fresh DTLS session keys between the server and the proxy say nothing about when the client made the request ๐Ÿซ . In a general hop-by-hop setup, freshness may need to be verified at each hop ๐Ÿ”.

A simple way to handle possibly delayed requests is for the CoAP server to reject a request the first time it shows up, and ask the CoAP client to prove it meant to make that request right now ๐Ÿ’โ€โ™€๏ธ.

2.2. The Echo Option ๐Ÿฆ‹

This doc defines the Echo option, a lightweight challenge-response mechanism for CoAP that lets a CoAP server verify a request is fresh ๐Ÿ”. A fresh request is one whose age hasn't gone past the freshness requirements the server set ๐Ÿ’ซ. Those requirements are application specific, and they may vary based on the resource, the method, and parameters outside of CoAP, like policies ๐Ÿ“‹. The Echo option value is a challenge from the server to the client. It's included in a CoAP response and echoed back to the server in one or more CoAP requests ๐Ÿ”„.

This mechanism matters a lot for actuators and other use cases where CoAP operations need fresh requests ๐Ÿค–. It's also useful in general for syncing state between a CoAP client and server, cryptographically verifying that the client is alive, or forcing a client to show it's reachable at its claimed network address ๐ŸŒธ. You could do the same thing by echoing freshness indicators in CoAP payloads, but that only works for methods and response codes that are defined to have a payload ๐Ÿ™„. The Echo option gives you a standard way to carry freshness indicators that works for all methods and response codes, which is honestly iconic ๐Ÿ‘‘โœจ.

2.2.1. Echo Option Format ๐ŸŽ€

okay so the Echo option is elective ๐ŸŒธ, safe to forward ๐Ÿฆ‹, not part of the cache-key, and not repeatable (see Table 1, which extends Table 4 of [RFC7252]). here's the cute little summary card:

+=====+===+===+===+===+======+========+========+=========+
| No. | C | U | N | R | Name | Format | Length | Default |
+=====+===+===+===+===+======+========+========+=========+
| 252 |   |   | x |   | Echo | opaque | 1-40   | (none)  |
+-----+---+---+---+---+------+--------+--------+---------+

                  Table 1: Echo Option Summary

C=Critical, U=Unsafe, N=NoCacheKey, R=Repeatable

the server is the one who makes Echo option values ๐Ÿง. what's inside them and how they're shaped is totally implementation specific, so every server gets to be its own little designer ๐Ÿ’…. Appendix A has a bunch of ways to make them if you're curious. clients and intermediaries MUST treat an Echo option value as opaque and make no assumptions about its content or structure. hands off the contents, bestie ๐Ÿ™ˆ

when a server gets an Echo option in a request, it MUST be able to verify that the value (a) was generated by the server or by some other party the server trusts, and (b) meets the freshness requirements of the application. depending on those requirements, the server may check exactly when the value was generated (time-based freshness โฐ) or check that the Echo option was generated after a specific event (event-based freshness ๐ŸŽ‰). since the request is bound to the Echo option value, the server can tell that the request is not older than that value. this is so clever ngl โœจ

when the Echo option is used with OSCORE [RFC8613], it MAY be an Inner or Outer option, and the Inner and Outer values are independent. OSCORE servers MUST only produce Inner Echo options unless they are merely testing for reachability of the client (the same as proxies may do). the Inner option is encrypted and integrity protected between the endpoints ๐Ÿ”, whereas the Outer option is not protected by OSCORE. as always with OSCORE, Outer options are visible to (and may be acted on by) all proxies and are visible on all links where no additional encryption (like TLS between client and proxy) is used. so be careful with Outer options, they're basically out in the open ๐Ÿ‘€


2.3. Echo Processing ๐ŸŒˆ

the Echo option MAY be included in any request or response (see Section 2.4 for different applications).

the application decides under what conditions a CoAP request to a resource has to be fresh ๐Ÿ‘‘. these conditions can include things like which resource is requested, the request method and other data in the request, and conditions in the environment, such as the state of the server or the time of the day.

if a certain request has to be fresh, the request does not contain a fresh Echo option value, and the server can't verify the freshness some other way, then the server MUST NOT process the request further and SHOULD send a 4.01 (Unauthorized) response with an Echo option. the server MAY include the same Echo option value in several different response messages and to different clients. examples of this could be time-based freshness (when several responses are sent closely after each other) or event-based freshness (with no event taking place between the responses). very efficient, very cute ๐Ÿ“

the server may use request freshness provided by the Echo option to verify the aliveness of a client or to synchronize state. the server may also include the Echo option in a response to force a client to demonstrate reachability at its claimed network address. note that the Echo option does not bind a request to any particular previous response. it just indicates that the client had access to the previous response at the time when it created the request ๐Ÿง 

when a client gets a 4.01 (Unauthorized) response with the Echo option, it SHOULD resend the original request with an Echo option added, carrying the received Echo option value. the client MAY send a different request compared to the original request. when a client gets any other response with the Echo option, it SHOULD echo the Echo option value in the next request to the server. the client MAY include the same Echo option value in several different requests to the server, or discard it at any time (especially to avoid tracking; see Section 6) ๐Ÿซถ

a client MUST only send Echo option values to the endpoints it received them from (where, as defined in Section 1.2 of [RFC7252], the security association is part of the endpoint). in OSCORE processing, that means sending Echo option values from Outer options (or from non-OSCORE responses) back in Outer options, and sending values from Inner options back in Inner options in the same security context. keep your Inner and Outer stuff sorted, babe ๐Ÿ—‚๏ธ

when a server gets a request with the Echo option, it figures out whether the request has to be fresh. if not, the Echo option MAY be ignored ๐Ÿคทโ€โ™€๏ธ. if the request has to be fresh and the server can't verify the freshness some other way, the server MUST use the Echo option to verify that the request is fresh. if the server can't verify that the request is fresh, the request is not processed further, and an error message MAY be sent. the error message SHOULD include a new Echo option ๐Ÿ’Œ

one way for the server to verify freshness is to bind the Echo option value to a specific point in time and verify that the request is not older than a certain threshold T. the server can check this by confirming that (t1 - t0) < T, where t1 is the request receive time and t0 is the time when the Echo option value was generated. an example message flow over DTLS is shown Figure 1. it's giving time travel but make it secure ๐Ÿ•ฐ๏ธ

    Client   Server
       |       |
       +------>|        Code: 0.03 (PUT)
       |  PUT  |       Token: 0x41
       |       |    Uri-Path: lock
       |       |     Payload: 0 (Unlock)
       |       |
       |<------+        Code: 4.01 (Unauthorized)
       |  4.01 |       Token: 0x41
       |       |        Echo: 0x00000009437468756c687521 (t0 = 9, +MAC)
       |       |
       | ...   | The round trips take 1 second, time is now t1 = 10.
       |       |
       +------>|        Code: 0.03 (PUT)
       |  PUT  |       Token: 0x42
       |       |    Uri-Path: lock
       |       |        Echo: 0x00000009437468756c687521 (t0 = 9, +MAC)
       |       |     Payload: 0 (Unlock)
       |       |
       |       | Verify MAC, compare t1 - t0 = 1 < T => permitted.
       |       |
       |<------+        Code: 2.04 (Changed)
       |  2.04 |       Token: 0x42
       |       |

     Figure 1: Example Message Flow for Time-Based Freshness Using the
         'Integrity-Protected Timestamp' Construction of Appendix A

another way for the server to verify freshness is to keep a cache of values tied to events ๐Ÿ—ƒ๏ธ. the application decides how big the cache is. from here on we assume the cache size is 1, in which case freshness means "no new event has taken place". every event writes a new value into the cache. the cache values MUST be different, or chosen in a way so the probability for collisions is negligible ๐ŸŽฒ. the server verifies freshness by checking that e0 equals e1, where e0 is the cached value when the Echo option value was generated, and e1 is the cached value when the request arrives. an example message flow over DTLS is shown in Figure 2.

     Client   Server
        |       |
        +------>|        Code: 0.03 (PUT)
        |  PUT  |       Token: 0x41
        |       |    Uri-Path: lock
        |       |     Payload: 0 (Unlock)
        |       |
        |<------+        Code: 4.01 (Unauthorized)
        |  4.01 |       Token: 0x41
        |       |        Echo: 0x05 (e0 = 5, number of total lock
        |       |                            operations performed)
        |       |
        | ...   | No alterations happen to the lock state, e1 has the
        |       | same value e1 = 5.
        |       |
        +------>|        Code: 0.03 (PUT)
        |  PUT  |       Token: 0x42
        |       |    Uri-Path: lock
        |       |        Echo: 0x05
        |       |     Payload: 0 (Unlock)
        |       |
        |       | Compare e1 = e0 => permitted.
        |       |
        |<------+        Code: 2.04 (Changed)
        |  2.04 |       Token: 0x42
        |       |        Echo: 0x06 (e2 = 6, to allow later locking
        |       |                            without more round trips)
        |       |

       Figure 2: Example Message Flow for Event-Based Freshness Using
            the 'Persistent Counter' Construction of Appendix A

when the Echo option serves freshness requirements (including client aliveness and state synchronizing), the Echo option value MUST be integrity protected between the intended endpoints, e.g., using DTLS, TLS, or an OSCORE Inner option [RFC8613]. when it's used to demonstrate reachability at a claimed network address, the Echo option SHOULD be a Message Authentication Code (MAC) of the claimed address, but MAY be unprotected. mixing different Echo applications can call for different choices, so see Appendix A, item 2 for an example ๐Ÿงฉ

an Echo option MAY be sent with a successful response, even though the request already met any freshness requirements on the operation. this is called a "preemptive" Echo option value, and it's super useful when the server expects the client to need to prove freshness relative to the current response in the near future ๐Ÿš€

a CoAP-to-CoAP proxy MAY set an Echo option on responses, both on forwarded ones that had no Echo option and on ones the proxy generates itself (from cache or as an error) ๐Ÿชž. if it does so, it MUST remove the Echo option it recognizes as its own from follow-up requests. when it gets an Echo option in a response, it MAY forward it to the client (and, since it doesn't recognize it as its own in future requests, relay it in the other direction as well), or process it on its own. if it does the latter, it MUST ensure that the client's request was generated (or is regenerated) after the Echo option value used to send to the server was first seen. (in most cases, this means the proxy needs to ask the client to repeat the request with a new Echo option value ๐Ÿ”„)

the CoAP server side of CoAP-to-HTTP proxies MAY request freshness, especially if they have reason to think access may need it (e.g., because it's a PUT or POST) ๐Ÿ“ฎ. how that gets determined is out of scope for this document. the CoAP client side of HTTP-to-CoAP proxies MUST respond to Echo challenges itself if the proxy knows from the recent establishing of the connection that the HTTP request is fresh. otherwise, it MUST NOT repeat an unsafe request, and it SHOULD respond with a 503 (Service Unavailable) with a Retry-After value of 0 seconds and terminate any underlying Keep-Alive connection ๐Ÿ›‘. if the HTTP request arrived in early data, the proxy SHOULD use a 425 (Too Early) response instead (see [RFC8470]). the proxy MAY also use other mechanisms to establish freshness of the HTTP request that are not specified here โœจ

2.4. Applications of the Echo Option

okay bestie, unless we say otherwise, every one of these apps needs a security protocol ๐Ÿ”’ and the Echo option has to be protected by it ๐Ÿ’– no skipping this part!!

  1. Actuation requests lowkey need freshness guarantees so an actuator doesn't do a delayed action by accident or because some attacker replayed it ๐Ÿ˜ญ In general, all unsafe methods (e.g., POST, PUT, and DELETE) may require freshness guarantees for secure operation.
    • The same Echo option value can be reused for multiple actuation requests to the same server, as long as the total time since it was generated is still below the freshness threshold โœจ
    • For actuator apps with low delay tolerance, the server may send preemptive Echo option values in successful requests, regardless of whether or not the request had an Echo option ๐Ÿƒโ€โ™€๏ธ This saves extra round trips for requests that come in rapid sequence. The client then uses the Echo option with the new value in the next actuation request, and the server compares the receive time accordingly.
  2. A server may use the Echo option to synchronize properties (like state or time) with a requesting client ๐Ÿ•ฐ๏ธ A server MUST NOT synchronize a property with a client that is not the authority of the property being synchronized. For example, if access to a server resource depends on time, then the server MUST NOT synchronize time with a client requesting access unless the client is a time authority for the server. not me being strict, but this is a hard rule ๐Ÿ™…โ€โ™€๏ธ

Note that the state to be synchronized is not carried inside the Echo option. Any explicit state information needs to be carried along in the messages the Echo option value is sent in. The Echo mechanism only provides a partial order on the messages' processing, so don't expect more from it ๐Ÿ’…

  • If a server reboots during operation, it may need to synchronize state or time before continuing the interaction. For example, with OSCORE, it is possible to reuse a partly persistently stored security context by synchronizing the Partial IV (sequence number) using the Echo option, as specified in Section 7.5 of [RFC8613]. โœจ
  • A device joining a CoAP group communication [GROUP-COAP] protected with OSCORE [GROUP-OSCORE] may be required to initially synchronize its replay window state with a client by using the Echo option in a unicast response to a multicast request. The client receiving the response with the Echo option includes the Echo option value in a subsequent unicast request to the responding server. big group energy ๐ŸŒˆ
  1. An attacker can do a denial-of-service attack by putting a victim's address in the source address of a CoAP request and sending that request to a resource with a large amplification factor ๐Ÿ˜ฑ The amplification factor is the ratio between the size of the request and the total size of the response(s) to that request. A server that gives a large amplification factor to an unauthenticated peer SHOULD mitigate amplification attacks, as described in Section 11.3 of [RFC7252]. One way to do that is for the server to respond to the alleged source address of the request with an Echo option in a short response message (e.g., 4.01 (Unauthorized)), which asks the client to verify its source address ๐Ÿ›ก๏ธ This only needs to happen once per endpoint, and it limits the range of potential victims from the general Internet to endpoints that have previously been in contact with the server. For this application, the Echo option can be used in messages that are not integrity protected, for example, during discovery. (This is formally recommended in Section 2.6.) ๐Ÿฆ‹
    • In the presence of a proxy, a server can't tell the different origin client endpoints apart, i.e., the client a request originates from. Following from the recommendation above, a proxy that gives a large amplification factor to unauthenticated peers SHOULD mitigate amplification attacks. The proxy SHOULD use the Echo option to verify origin reachability, as described in Section 2.3. The proxy MAY forward safe requests immediately so a cached result is ready when the client's repeated request arrives ๐Ÿงš
    • Amplification mitigation is a trade-off between giving leverage to an attacker and causing overhead. An amplification factor of 3 (i.e., don't send more than three times the number of bytes received until the peer's address is confirmed) is considered acceptable for unconstrained applications in [RFC9000], Section 8.

When that limit is applied and no further context is available, a safe default is sending initial responses no larger than 136 bytes in CoAP serialization. (The number assumes Ethernet, IP, and UDP headers of 14, 40, and 8 bytes, respectively, with 4 bytes added for the CoAP header. Triple that minus the non-CoAP headers gives the 136 bytes.) Given the token also takes up space in the request, responding with 132 bytes after the token is safe as well. ๐Ÿงฎ

  • When an Echo response is sent to mitigate amplification, it MUST be sent as a piggybacked or Non-confirmable response, never as a separate one (which would cause amplification due to retransmission). this one is non-negotiable ๐Ÿšซ
  1. A server may want to use the request freshness provided by the Echo option to verify the aliveness of a client ๐Ÿ‘€ Note that, in a deployment with hop-by-hop security and proxies, the server can only verify aliveness of the closest proxy.

2.5. Characterization of Echo Applications

okay so use cases for the Echo option can be sorted by a few criteria that tell you what properties the Echo option value needs ๐Ÿง These criteria apply both to the ones listed in Section 2.4 and to any brand-new applications. They explain the statements in Section 2.4 and give guidance for the new stuff ๐Ÿ’œ

2.5.1. Time-Based versus Event-Based Freshness

The property a client shows by sending an Echo option value is that the request was sent after a certain point in time, or after some event happened on the server โฐ

When events are counted, they form something that can be used as a monotonic but very non-uniform time line. With highly regular events and low-resolution time, time-based and event-based freshness kind of blur together: "no longer than a month ago" is basically the same vibe as "since the last full moon" ๐ŸŒ•

In an extreme form of event-based freshness, the server can place an event whenever an Echo option value is used. This makes the Echo option value effectively single use โ˜๏ธ

Event-based and time-based freshness can be combined in a single Echo option value, e.g., by encrypting a timestamp with a key that changes with every event. That gets you semantics in the style of "usable once but only for 5 minutes" ๐Ÿ”

2.5.2. Authority over Used Information

Information sent to the server in the request Echo option value has different authority depending on the application. Knowing who or what is the authoritative source of that information helps the server implementor decide how much protection the Echo option value needs ๐Ÿง 

If all that is conveyed to the server is information the client is authorized to provide arbitrarily (which is another way of saying the server has to trust the client on whatever the Echo option is being used for), then the server can issue Echo option values that don't need protection on their own. They still need to be covered by the security protocol that covers the rest of the message, but the Echo option value can be just short enough to be unique between this server and client ๐Ÿซถ

For example, the client's OSCORE Sender Sequence Number (as used in [RFC8613], Appendix B.1.2) is such information.

In most other cases, there is information conveyed for which the server is the authority ("the request must not be older than five minutes" is counted on the server's clock, not the client's), or which even involves the network (as when performing amplification mitigation). In these cases, the Echo option value itself needs to be protected against forgery by the client, e.g., by using a sufficiently large, random value or a MAC, as described in Appendix A, items 1 and 2. ๐Ÿšจ

For some applications, the server may be able to trust the client to also act as the authority (e.g., when using time-based freshness purely to mitigate request delay attacks). These need careful case-by-case evaluation ๐Ÿ”

To issue Echo option values without integrity protection of its own, the server needs to trust the client to never produce requests with attacker-controlled Echo option values. The provisions of Section 2.3 (saying that an Echo option value may only be sent as received from the same server) allow that. The requirement stated there for the client to treat the Echo option value as opaque holds for these applications, just like for all others ๐Ÿ™Œ

When the client is the sole authority over the synchronized property, the server can still use time or events to issue new Echo option values. In that case, the request's Echo option value doesn't so much prove the indicated freshness to the server. Instead, it reflects the client's intention to indicate reception of responses containing that value when sending the later ones ๐Ÿ’Œ

Note that a single Echo option value can be used for multiple purposes (e.g., to both get the sequence number information and perform amplification mitigation). In this case, the stricter protection requirements apply. the strictest rule wins, always ๐Ÿ†

2.5.3. Protection by a Security Protocol

For meaningful results, the Echo option needs to be used in combination with a security protocol in almost all applications ๐Ÿ”’

When the information extracted by the server is only about a part of the system outside of any security protocol, the Echo option can also be used without a security protocol (in the case of OSCORE, as an Outer option) ๐ŸŒธ

The only known application satisfying this requirement is network address reachability. Here, unprotected Echo option values are used both by servers (e.g., during setup of a security context) and by proxies (which don't necessarily have a security association with their clients) for amplification mitigation ๐Ÿซง

2.6. Updated Amplification Mitigation Requirements for Servers

This section updates the amplification mitigation requirements for servers in [RFC7252] to recommend the use of the Echo option to mitigate amplification attacks. The requirements for clients are not updated. Section 11.3 of [RFC7252] is updated by adding the following text:

A CoAP server SHOULD mitigate potential amplification attacks by responding to unauthenticated clients with 4.01 (Unauthorized) including an Echo option, as described in item 3 in Section 2.4 of RFC 9175.

3. Protecting Message Bodies Using Request Tags โœจ

3.1. Fragmented Message Body Integrity ๐Ÿงฉ

Okay so CoAP was built for unreliable transports like UDP ๐Ÿฆ‹, and it comes with a lightweight reliability feature for messages that get lost or show up out of order. For a security protocol to support CoAP over those transports, it must allow out-of-order delivery of messages. ๐Ÿ’…

The block-wise transfer mechanism [RFC7959] extends CoAP so a big resource representation (the CoAP message body) can be sent as a sequence of blocks (CoAP message payloads). It uses a pair of CoAP options, Block1 and Block2, for the request and response payload respectively. ๐ŸŒธ

Here's the tea ๐Ÿซข: block-wise functionality can't detect when blocks from different message bodies to the same resource, with the same block number, get swapped. That's still true even when CoAP is paired with a security protocol like DTLS or OSCORE, within the replay window [COAP-ATTACKS]. This is a vulnerability of the block-wise functionality of CoAP [RFC7959]. ๐Ÿ˜ญ

A straightforward fix for mixing up blocks from different messages is to give each message body its own unique identifier. That would offer the same protection you get when the whole body fits in a single payload. The ETag option [RFC7252], set by the CoAP server, already identifies a response body that's fragmented using the Block2 option. ๐Ÿ”ฅ


3.2. The Request-Tag Option ๐Ÿท๏ธ

This document defines the Request-Tag option for identifying request bodies. It's similar to ETag, except it's ephemeral and set by the CoAP client. โœจ Request-Tag is meant to be a short-lived identifier that keeps apart distinct block-wise request operations on one resource from one client, which fixes the issue from Section 3.1. It lets the receiving server reliably put request payloads (blocks) back together into their message bodies. If the server chooses to support it, it can also reliably process simultaneous block-wise request operations on a single resource. ๐Ÿ‘‘

If the requests should protect against blocks being swapped between different message bodies, they must be integrity protected. Request-Tag is mainly used in requests that carry the Block1 option, plus the Block2 requests that follow them. ๐Ÿงš

Honestly, it's an implementation of the "proxy-safe elective option" that's used just to "vary the cache key", as suggested in [RFC7959], Section 2.4. ๐ŸŽ€

3.2.1. Request-Tag Option Format ๐Ÿ“‹

The Request-Tag option is elective, safe to forward, repeatable, and part of the cache key (see Table 2, which extends Table 4 of [RFC7252]). ๐Ÿ’œ

+=====+===+===+===+===+=============+========+========+=========+
| No. | C | U | N | R | Name        | Format | Length | Default |
+=====+===+===+===+===+=============+========+========+=========+
| 292 |   |   |   | x | Request-Tag | opaque | 0-8    | (none)  |
+-----+---+---+---+---+-------------+--------+--------+---------+

                  Table 2: Request-Tag Option Summary

C=Critical, U=Unsafe, N=NoCacheKey, R=Repeatable

Request-Tag, just like the Block options, counts as both a class E and a class U option for OSCORE processing (see Section 4.1 of [RFC8613]). ๐Ÿ” The Request-Tag MAY be an Inner or Outer option, and it affects the Inner or Outer block operations respectively. That means the Inner and Outer values are independent of each other. The Inner option is encrypted and integrity protected between client and server, and it gives message body identification when requests are fragmented end to end. The Outer option is visible to proxies, and it labels message bodies when requests are fragmented hop by hop. ๐Ÿ‘€

The Request-Tag option only shows up in request messages of block-wise operations. ๐Ÿ™ˆ

The Request-Tag mechanism can be applied independently on the server and client sides of CoAP-to-CoAP proxies, same as the Block options. But since it's safe to forward, a proxy is free to just forward it while processing an operation. CoAP-to-HTTP proxies and HTTP-to-CoAP proxies can use Request-Tag on their CoAP sides. It doesn't apply to HTTP requests. ๐Ÿฆ‹


3.3. Request-Tag Processing by Servers ๐Ÿ–ฅ๏ธ

Request-Tag doesn't need any special processing on the server side. It only needs the processing that's already required for any unknown elective proxy-safe cache-key option. ๐Ÿ’… The option changes the properties that tell block-wise operations apart. That covers all options except Block1 and Block2, plus all operations that are elective NoCacheKey. So the server can't treat messages with a different list of Request-Tag options as belonging to the same operation. ๐Ÿšซ

To keep using the cache, a server (proxies included) MAY discard the Request-Tag option from an assembled block-wise request when it's checking its cache. The reason is that the option relates to the operation on the wire, not its semantics. For example, a FETCH request with the same body as an older one can be served from the cache if the older one's Max-Age hasn't expired yet. That's true even if the second operation uses a Request-Tag and the first one didn't. (This is similar to the situation with ETag: it's formally part of the cache key, but implementations that know what it means can cache more efficiently, see [RFC7252], Section 5.4.2.) ๐Ÿง 

A server receiving a Request-Tag MUST treat it as opaque and make no assumptions about its content or structure. ๐Ÿซถ

Two messages carrying the same Request-Tag is a necessary but not sufficient condition for being part of the same operation. โญ For one thing, a server may still treat them as independent messages when it sends 2.01 (Created) and 2.04 (Changed) responses for every block. Also, a client that lost interest in an old operation but still wants to start over can overwrite the server's old state. It does this with a new initial (num=0) Block1 request and the same Request-Tag, under some circumstances. In that case the new message isn't part of the old operation, either. ๐ŸŒˆ

As it has always been, a server that can only serve a limited number of block-wise operations at the same time has options. It can delay the start of the operation by replying with 5.03 (Service Unavailable) and a Max-Age that indicates how long it expects the existing operation to keep going. Or it can forget the state established with the older operation and respond with 4.08 (Request Entity Incomplete) to later blocks on the first operation. ๐Ÿ“


3.4. Setting the Request-Tag ๐ŸŽ€

For each separate block-wise request operation, the client can choose a Request-Tag value or choose not to set one. ๐Ÿ’– It needs to be set to the same value (or left unset) in all messages that belong to the same operation. Otherwise, the server treats them as separate operations. ๐Ÿ˜ค

Starting a request operation that's matchable to a previous operation, even while using the same Request-Tag value, is called "request tag recycling". โ™ป๏ธ The absence of a Request-Tag option counts as a value that's distinct from all values when a single Request-Tag option is set. So starting a request operation that's matchable to a previous operation where neither one has a Request-Tag option also counts as request tag recycling. This is also called "recycling the absent option". ๐Ÿ™ƒ

Clients that use Request-Tag for a particular purpose (like in Section 3.5) MUST NOT recycle a request tag unless the first operation has concluded. What counts as a concluded operation depends on the purpose, and it's defined accordingly. See the examples in Section 3.5. ๐Ÿ“š

When Block1 and Block2 are combined in an operation, the Request-Tag of the Block1 phase is also set in the Block2 phase. If it wasn't, the request would have a different set of options and wouldn't be recognized anymore. ๐Ÿ”

Clients are encouraged to generate compact messages. In practice that means sending messages without Request-Tag options whenever possible, and using short values when the absent option can't be recycled. ๐Ÿงƒ

Note that Request-Tag options can be present in request messages that carry no Block options. For example, that happens when a proxy that doesn't know about Request-Tag reassembled the messages. ๐Ÿงฉ

The Request-Tag option MUST NOT be present in response messages. ๐Ÿšซโœจ


3.5. Applications of the Request-Tag Option ๐ŸŒˆ

3.5.1. Body Integrity Based on Payload Integrity ๐Ÿ’–

When a client fragments a request body into multiple message payloads, the individual messages can still be integrity protected, and it's still possible for an attacker to maliciously replace a later operation's blocks with an earlier operation's blocks (see Section 2.5 of [COAP-ATTACKS]). ๐Ÿ˜ฑ So the integrity protection of each block doesn't extend to the operation's request body. That's the whole problem. ๐Ÿ’€

To get that protection, use the Request-Tag mechanism like this:

  • The individual exchanges MUST be integrity protected end to end between the client and server.
  • The client MUST NOT recycle a request tag in a new operation unless the previous operation matchable to the new one has concluded.

If any future security mechanisms allow a block-wise transfer to continue after an endpoint's details (like the IP address) have changed, then the client MUST consider messages matchable if they were sent to any endpoint address using the new operation's security context. ๐ŸŒ

  • The client MUST NOT regard a block-wise request operation as concluded unless all of the messages the client has sent in the operation would be regarded as invalid by the server if they were replayed. ๐Ÿ”’

When security services are provided by OSCORE, these confirmations typically come from either the client receiving an OSCORE response message that matches the request (an empty Acknowledgement (ACK) is insufficient), or because the message's sequence number is old enough to be outside the server's receive window. โณ

When security services are provided by DTLS, this can only be confirmed if there was no CoAP retransmission of the request, the request was responded to, and the server uses replay protection. ๐Ÿ›ก๏ธ

Authors of other documents (for example, applications of [RFC8613]) are invited to mandate this subsection's behavior for clients that run block-wise interactions over secured transports. That way, the server can rely on a conforming client to set the Request-Tag option when required, and can have confidence in the integrity of the assembled body. ๐Ÿซถ

Note that this mechanism is implicitly implemented when the security layer guarantees ordered delivery (for example, CoAP over TLS [RFC8323]). With each message, any earlier message can't be replayed anymore. So the client never needs to set the Request-Tag option unless it wants to perform concurrent operations. ๐ŸŒŸ

Body integrity only makes sense in applications that have stateful block-wise transfers. In applications where all the state lives in the application itself, clients don't need to worry about body integrity or the Request-Tag. For example, rather than POSTing a large representation to a collection in a stateful block-wise transfer, a collection item is created first. Then it's written to once, and it's available once it's been written completely. ๐Ÿง

Body integrity is largely independent from replay protection. When no replay protection is available (it's optional in DTLS), a full block-wise operation may be replayed. But by following the above, no operations will get mixed up. The only link between body integrity and replay protection is that, without replay protection, recycling isn't possible. ๐Ÿฆ„

3.5.2. Multiple Concurrent Block-Wise Operations

okay bestie, so picture this ๐Ÿ’… a CoAP client (especially a CoAP proxy ๐Ÿซถ) starts a block-wise request to a resource while there's already another block-wise operation running on that same resource. the new one should NOT cancel the old one, lowkey because a proxy would be in exactly this spot when it forwards operations with the same cache-key options but maybe different payloads ๐Ÿ™ˆ

so for that, Request-Tag is the proxy-safe elective option that Section 2.4 of [RFC7959] suggests in its last paragraph โœจ

when a client is setting up a new block-wise operation, it has to check the other active operations first ๐Ÿ‘€

- If any of them is matchable to the new one, and the client neither wants to cancel the old one nor postpone the new one, it can pick a Request-Tag value (including the absent option) that is not in use by the other matchable operations for the new operation. - Otherwise, it can start the new operation without setting the Request-Tag option on it.

๐ŸŽ€ the first bullet is a whole vibe: if there's a matchable one and you don't want to cancel or delay anything, pick a Request-Tag value (absent option counts too!) that nobody else matchable is using. and if that's not the situation, just start the new operation without setting Request-Tag at all. main character energy, no drama ๐Ÿ’–


3.5.3. Simplified Block-Wise Handling for Constrained Proxies

so the Block options were defined to be unsafe to forward ๐Ÿ˜ญ because a proxy that forwards blocks as plain messages would risk mixing up clients' requests. the chaos is real ๐Ÿ’€

BUT here's the plot twist ๐Ÿฆ‹ in some cases, like when forwarding block-wise request operations, appending a Request-Tag value unique to the client can satisfy the requirements on the proxy that come from having a Block option. literally a glow-up ๐ŸŒธ

this is especially useful for proxies that strive for stateless operations, as described in Section 4 of [RFC8974] ๐Ÿงš

ngl, the precise classification of which cases a Request-Tag option is sufficient for is not trivial, especially when both request and response body are fragmented. it's out of scope for this document, so that's a problem for future us ๐Ÿ™ˆ


3.6. Rationale for the Option Properties

the Request-Tag option can be elective because servers that don't know about Request-Tag just see operations with differing request tags as unmatchable. no confusion, no drama โœจ

the Request-Tag option can be safe to forward but still part of the cache key, because proxies unaware of Request-Tag will consider operations with differing request tags unmatchable but can still forward them. iconic ๐Ÿ‘‘

the Request-Tag option is repeatable ๐Ÿ“ because that easily lets several cascaded stateless proxies each put in an origin address. they can do the steps of Section 3.5.3 without making a concatenation of the received option and their own value, and can just add a new Request-Tag option unconditionally. no extra work, periodt ๐Ÿ’…

in draft versions of this document, the Request-Tag option used to be critical and unsafe to forward. that design was based on an erroneous understanding of which blocks could be composed according to [RFC7959]. oops, glow-up achieved ๐ŸŒˆ


3.7. Rationale for Introducing the Option

there was an alternative considered for the Request-Tag option to cope with the problem of fragmented message body integrity (Section 3.5.1). it was to update [RFC7959] to say that blocks could only be assembled if their fragments' order corresponded to the sequence numbers. ๐Ÿค”

but that approach would have been difficult to roll out reliably on DTLS ๐Ÿ˜ญ, where many implementations do not expose sequence numbers, and it still would not prevent attacks like the ones in Section 2.5.2 of [COAP-ATTACKS]. not it ๐Ÿ™…โ€โ™€๏ธ


3.8. Block2 and ETag Processing

the same security properties as in Section 3.5.1 can be obtained for block-wise response operations ๐Ÿฆ‹ the threat model here doesn't depend on an attacker. a client can build a wrong representation just by assembling it from blocks from different resource states. that can happen when a resource gets modified during a transfer, or when some blocks are still valid in the client's cache. wild ๐Ÿ˜ณ

rules saying that response body reassembly is conditional on matching ETag values are already in place from Section 2.4 of [RFC7959] โœจ

to get protection equivalent to Section 3.5.1, a server MUST use the Block2 option together with the ETag option ([RFC7252], Section 5.10.6), and MUST NOT use the same ETag value for different representations of a resource. these are non-negotiable, bestie ๐Ÿซถ


  1. Token Processing for Secure Request-Response Binding โœจ

4.1. Request-Response Binding

okay this one is SO important ๐Ÿ”ฅ a fundamental requirement of secure REST operations is that the client can bind a response to a particular request. if that isn't ensured, a client may wrongly associate a response to a request. the wrong response could be an old response for the same resource, or a response for a totally different resource (see Section 2.3 of [COAP-ATTACKS]). example: a request for the alarm status "GET /status" gets matched to a prior response "on" instead of the correct "off". yikes ๐Ÿ˜ฑ

in HTTP/1.1, this binding is always assured by ordered and reliable delivery, plus the rule that the server sends responses in the same order the requests were received. CoAP is not like that ๐Ÿ’€ the server (or an attacker) can return responses in any order, and there can be any number of responses to a request (see [RFC7641]). in CoAP, concurrent requests are told apart by their Token. the CoAP Message ID can't do this job, since those are typically different for the REST request and corresponding response in the case of "separate response" (see Section 2.2 of [RFC7252]). ๐Ÿ™…โ€โ™€๏ธ

CoAP [RFC7252] doesn't treat the Token as a cryptographically important value, and doesn't give stricter guidelines than that Tokens currently "in use" SHOULD (not SHALL) be unique. if it's used with a security protocol that doesn't provide bindings between requests and responses (like DTLS and TLS), Token reuse may result in a client matching a response to the wrong request. mismatches can also happen for reasons other than a malicious attacker, like delayed delivery or a server sending notifications to an uninterested client ๐Ÿซ 

a straightforward mitigation is to mandate that clients don't reuse Tokens until the traffic keys have been replaced. the next section formalizes that ๐ŸŽ€


4.2. Updated Token Processing Requirements for Clients

as we said in Section 4.1, the client must be able to verify that a response corresponds to a particular request. this section updates the Token processing requirements for clients in [RFC7252] so that secure REST operations like "coaps" always assure a cryptographically secure binding of responses to requests. the Token processing for servers is not updated. Token processing in Section 5.3.1 of [RFC7252] is updated by adding the following text:

When CoAP is used with a security protocol not providing bindings between requests and responses, the Tokens have cryptographic importance. The client MUST make sure that Tokens are not used in a way so that responses risk being associated with the wrong request. One easy way to accomplish this is to implement the Token (or part of the Token) as a sequence number, starting at zero for each new or rekeyed secure connection. This approach SHOULD be followed.

  1. Security Considerations ๐Ÿšจ

okay bestie, this section is serious business, so listen up ๐Ÿ‘‘

the freshness assertion of the Echo option comes from the client reproducing the same Echo option value in a request as it received in a previous response. if the Echo option value is a large random number, there's a high probability that the request was generated after seeing the response. but if the Echo option value of the response can be guessed (for example, if it's based on a small random number or a counter, see Appendix A), then it's possible to compose a request with the right Echo option value ahead of time ๐Ÿ˜ฑ using guessable Echo option values is only permissible in a narrow set of cases described in Section 2.5.2. Echo option values MUST be set by the CoAP server such that the risk associated with unintended reuse can be managed. ๐Ÿซถ

if uniqueness of the Echo option value is based on randomness, then a secure pseudorandom number generator and truly random seeds are essential for the security of the Echo option ๐Ÿ”. if no true random number generator is available, a truly random seed must be provided from an external source. since each pseudorandom number must only be used once, an implementation needs to get a new truly random seed after reboot, or continuously store the state in nonvolatile memory. see [RFC8613], Appendix B.1.1 for issues and approaches for writing to nonvolatile memory ๐Ÿ’พ

a single active Echo option value with 64 (pseudo)random bits gives the same theoretical security level as a 64-bit MAC (as used in, e.g., AES_128_CCM_8). if a random unique Echo option value is intended, the Echo option value SHOULD contain 64 (pseudo)random bits that are not predictable for any party other than the server. a server MAY use different security levels for different use cases (client aliveness, request freshness, state synchronization, network address reachability, etc.) ๐ŸŒธ

the security provided by the Echo and Request-Tag options depends on the security protocol used. CoAP and HTTP proxies require (D)TLS to be terminated at the proxies. so the proxies are able to manipulate, inject, delete, or reorder options or packets. the security claims in such architectures only hold under the assumption that all intermediaries are fully trusted and have not been compromised ๐Ÿ˜ฌ

Echo option values without the protection of randomness or a MAC are limited to cases when the client is the trusted source of all derived properties (as per Section 2.5.2). using them needs per-application consideration of both the impact of a malicious client and of implementation errors in clients. these Echo option values are the only legitimate case for Echo option values shorter than four bytes, which are not necessarily secret. they MUST NOT be used unless the Echo option values in the request are integrity protected, as per Section 2.3 ๐Ÿšซ

servers SHOULD use a monotonic clock to generate timestamps and compute round-trip times. non-monotonic clocks are not secure, because the server will accept expired Echo option values if the clock is moved backward. the server will also reject fresh Echo option values if the clock is moved forward ๐Ÿ˜ต. non-monotonic clocks MAY be used as long as their deviations are acceptable given the freshness requirements. if the deviations from a monotonic clock are known, it may be possible to adjust the threshold accordingly โฐ

an attacker may be able to affect the server's system time in various ways, such as setting up a fake NTP server or broadcasting false time signals to radio-controlled clocks ๐Ÿ“ก

for the purpose of generating timestamps for the Echo option, a server MAY set a timer at reboot and use the time since reboot, choosing the granularity so that different requests arrive at different times. servers MAY intermittently reset the timer and MAY generate a random offset applied to all timestamps. when resetting the timer, the server MUST reject all Echo option values that were created before the reset โณ

servers that use the "List of Cached Random Values and Timestamps" method described in Appendix A may be vulnerable to resource exhaustion attacks. one way to minimize the state is to use the "Integrity-Protected Timestamp" method described in Appendix A ๐Ÿง 

5.1. Token Reuse

Okay, bestie, reusing Tokens and still making sure a response never gets matched to the wrong request is NOT trivial ๐Ÿ˜ญ. The server can process requests in any order and send several responses to the same request. An attacker can block, delay, and reorder messages too. So when CoAP runs over a security protocol that doesn't bind requests to responses, like DTLS or TLS, a sequence number is recommended. Main character energy, but make it safe ๐Ÿ›ก๏ธ.

For a generic response to a Confirmable request over DTLS, you can only claim the binding without out-of-band knowledge if:

  • the original request was never retransmitted and
  • the response was piggybacked in an Acknowledgement message (as a Confirmable or Non-confirmable response may have been transmitted multiple times).

If observation was used, the same holds for the registration, all reregistrations, and the cancellation. ๐Ÿฆ‹

Also, for observations, any responses that use that Token and have a DTLS sequence number earlier than the cancellation Acknowledgement message need to be discarded. Ngl, this is typically not supported in DTLS implementations ๐Ÿ’€.

Some setups let you reuse Tokens without those constraints, because a different component in the setup provides the associations โœจ:

  • In CoAP over TLS, retransmissions are not handled by the CoAP layer and behave like a replay window size of 1. When a client sends TLS-protected requests without Observe to a single server, it can reuse a Token as soon as the previous response with that Token has been received. ๐ŸŒธ
  • Requests whose responses are cryptographically bound to the requests (like in OSCORE) can reuse Tokens indefinitely. ๐Ÿ‘‘

In all other cases, a sequence number approach is RECOMMENDED, as per Section 4. ๐Ÿ’œ

Tokens that can't be reused still need to be handled properly. You could increase the Token as soon as the current one can't be reused, or keep a list of all Tokens that are unsuitable for reuse. Either way, you've got options ๐Ÿซถ.

When the Token (or part of the Token) contains a sequence number, the encoding has to be chosen so that collisions are avoided. This matters even more when the Token holds more than just the sequence number, like serialized state, as in [RFC8974]. Careful, careful, careful ๐Ÿ™ˆ.


6. Privacy Considerations ๐ŸŽ€

Implementations SHOULD NOT put any privacy-sensitive information in the Echo or Request-Tag option values. Unencrypted timestamps could reveal things about the server, like its location, its time since reboot, or that it will accept expired certificates. ๐Ÿ˜ฌ Timestamps MAY be used if the Echo option is encrypted between the client and the server, for example with DTLS and no proxies, or with OSCORE and an Inner Echo option. ๐Ÿ”

Like HTTP cookies, the Echo option could be abused as a tracking mechanism that identifies a client across requests. This is especially true for preemptive Echo option values. Servers MUST NOT use the Echo option to correlate requests for any purpose other than freshness and reachability. Clients only send Echo option values to the same server they got them from. Compared to HTTP, CoAP clients are often authenticated and non-mobile, so servers can often correlate requests based on the security context, the client credentials, or the network address. Especially when the Echo option makes it easier for a server to correlate requests, clients MAY discard all preemptive Echo option values. Protect your vibes ๐Ÿงš.

Publicly visible generated identifiers can leak information, even when they're opaque (as all the ones defined in this document are). See [NUMERIC-IDS] for the details. To avoid those effects, the absent Request-Tag option should be recycled as much as possible. That's generally doable as long as a security mechanism is in place, even for OSCORE outer block-wise transfers, because the OSCORE option's variation makes sure no matchable requests are created by different clients. When an unprotected Echo option is used to demonstrate reachability, the recommended mechanism of Section 2.3 keeps the effects to a minimum. ๐ŸŒˆ


7. IANA Considerations ๐Ÿ“‹

IANA has added the following option numbers to the "CoAP Option Numbers" registry defined by [RFC7252]:

+========+=============+===========+
| Number | Name        | Reference |
+========+=============+===========+
| 252    | Echo        | RFC 9175  |
+--------+-------------+-----------+
| 292    | Request-Tag | RFC 9175  |
+--------+-------------+-----------+

Table 3: Additions to CoAP Option Numbers Registry


8. References ๐Ÿ“š

8.1. Normative References

8.2. Informative References

Appendix A. Methods for Generating Echo Option Values โœจ

okay bestie, the content and structure of the Echo option value are totally up to the implementation and get decided by the server ๐Ÿ’… This appendix walks through two simple mechanisms for time-based freshness and one for event-based freshness. The "List of Cached Random Values and Timestamps" mechanism is RECOMMENDED in general ๐ŸŽ€ and the "Integrity-Protected Timestamp" mechanism is RECOMMENDED in case the Echo option is encrypted between the client and the server ๐Ÿ”

Every mechanism has its own trade-offs between the size of the Echo option value, the amount of server state, the amount of computation, and the security properties it offers. It's giving "pick your fighter" ๐ŸฅŠ A server MAY use different methods and security levels for different use cases (client aliveness, request freshness, state synchronization, network address reachability, etc.) ๐Ÿฆ‹

1. List of Cached Random Values and Timestamps ๐ŸŒธ

The Echo option value is a (pseudo)random byte string called r. The server caches a list containing the random byte strings and their initial transmission times. Assuming 72-bit random values and 32-bit timestamps, the size of the Echo option value is 9 bytes and the amount of server state is 13n bytes, where n is the number of active Echo option values. The security against an attacker guessing Echo option values is given by s = bit length of r - log2(n). The length of r and the maximum allowed n should be set so that the security level is harmonized with other parts of the deployment, e.g., s >= 64. If the server loses time continuity, e.g., due to reboot, the entries in the old list MUST be deleted. ๐Ÿซถ

Echo option value:

random value r

Server State:

random value r, timestamp t0

This method is suitable for both time-based and event-based freshness (e.g., by clearing the cache when an event occurs) and is independent of the client authority. โœจ

2. Integrity-Protected Timestamp ๐Ÿ”

The Echo option value is an integrity-protected timestamp. The timestamp can have a different resolution and range. A 32-bit timestamp can, e.g., give a resolution of 1 second with a range of 136 years. The (pseudo)random secret key is generated by the server and not shared with any other party. The use of truncated HMAC-SHA-256 is RECOMMENDED. With a 32-bit timestamp and a 64-bit MAC, the size of the Echo option value is 12 bytes, and the server state is small and constant. The security against an attacker guessing Echo option values is given by the MAC length. If the server loses time continuity, e.g., due to reboot, the old key MUST be deleted and replaced by a new random secret key. ๐Ÿ”‘

Heads up: the privacy considerations in Section 6 may apply to the timestamp. Therefore, it might be important to encrypt it. Depending on the choice of encryption algorithms, this may require an initialization vector to be included in the Echo option value (see below). ๐Ÿ™ˆ

Echo option value:

timestamp t0, MAC(k, t0)

Server State:

secret key k

This method is suitable for both time-based and event-based freshness (by the server remembering the time at which the event took place) and independent of the client authority. ๐Ÿ’œ

If this method is used to additionally obtain network reachability of the client, the server MUST use the client's network address too, e.g., as in:

MAC(k, t0, claimed network address)

3. Persistent Counter ๐Ÿงš

This can be used in OSCORE for sequence number recovery, per Appendix B.1.2 of [RFC8613]. The Echo option value is a simple counter without integrity protection of its own, serialized in uint format. The counter is incremented in a persistent way every time the state that needs to be synchronized is changed (in the case described in Appendix B.1.2 of [RFC8613], when a reboot indicates that volatile state may have been lost). An example of how such a persistent counter can be implemented efficiently is the OSCORE server Sender Sequence Number mechanism described in Appendix B.1.1 of [RFC8613]. ๐Ÿ“

Echo option value:

counter

Server State:

counter

This method is suitable only if the client is the authority over the synchronized property. Consequently, it cannot be used to show client aliveness. It provides statements from the client similar to event-based freshness (but without a proof of freshness). ๐Ÿ™ƒ

Other mechanisms complying with the security and privacy considerations may be used. The use of encrypted timestamps in the Echo option provides additional protection but typically requires an initialization vector (a.k.a. nonce) as input to the encryption algorithm, which adds a slight complication to the procedure as well as overhead. ๐ŸŒˆ


Appendix B. Request-Tag Message Size Impact ๐ŸŽ€

so in the absence of concurrent operations, the Request-Tag mechanism for body integrity (Section 3.5.1) incurs no overhead if no messages are lost. To be more precise: in OSCORE, that means no operations are aborted due to repeated transmission failure, and in DTLS, it means no packets are lost and replay protection is active. It also costs nothing when block-wise request operations happen rarely (in OSCORE, if there is always only one request block-wise operation in the replay window). ๐Ÿฆ‹

In those situations, no message has any Request-Tag option set, and the Request-Tag value can be recycled indefinitely. โ™ป๏ธโœจ

When the absence of a Request-Tag option cannot be recycled any more within a security context, the messages with a present but empty Request-Tag option can be used (1 byte overhead). When that is used up, 256 values from 1-byte options (2 bytes overhead) are available. ๐Ÿ’…

In situations where that overhead is unacceptable (e.g., because the payloads are known to be at a fragmentation threshold), the absent Request-Tag value can be made usable again:

  • In DTLS, a new session can be established. ๐Ÿซถ
  • In OSCORE, the sequence number can be artificially increased so that all lost messages are outside of the replay window by the time the first request of the new operation gets processed, and all earlier operations can therefore be regarded as concluded. ๐Ÿ‘‘

Acknowledgements ๐Ÿ’–

The authors want to thank Carsten Bormann, Roman Danyliw, Benjamin Kaduk, Murray Kucherawy, Francesca Palombini, and Jim Schaad for providing valuable input to the document. ๐ŸŒธ

Authors' Addresses โœจ

Christian Amsรผss
Email: christian@amsuess.com


John PreuรŸ Mattsson
Ericsson AB
Email: john.mattsson@ericsson.com


Gรถran Selander
Ericsson AB
Email: goran.selander@ericsson.com
๐Ÿ“ฆ where this page comes from