RFC 8613

Object Security for Constrained RESTful Environments (OSCORE)

๐Ÿ“… published July 2019, from ietf

Object Security for Constrained RESTful Environments (OSCORE) ๐Ÿ’–

okay bestie, this is RFC 8613 ๐Ÿ’… It's an IETF document, which means it's a Request for Comments, and it's on the Standards Track ๐Ÿ‘‘ It was published in July 2019 and has ISSN 2070-1721 โœจ

The authors are G. Selander, J. Mattsson, and F. Palombini, all from Ericsson AB ๐Ÿฆ‹, plus L. Seitz from RISE ๐ŸŒธ

It updates RFC 7252 ๐Ÿ”ฅ That's the CoAP spec. ngl the title block already tells the whole plot: OSCORE adds extra security to CoAP and changes some of how CoAP works, so the older spec needs an update.


Abstract ๐Ÿซถ

This doc defines Object Security for Constrained RESTful Environments (OSCORE), a way to protect the application layer of the Constrained Application Protocol (CoAP) using CBOR Object Signing and Encryption (COSE). OSCORE gives end-to-end protection between endpoints that talk over CoAP or CoAP-mappable HTTP ๐Ÿฆ‹ It's built for constrained nodes and networks that do a lot of proxy stuff, including translating between different transport protocols ๐ŸŒˆ

Even though it's an optional feature of CoAP, OSCORE changes how CoAP options get processed and how IANA registration works ๐Ÿ™ˆ That's why this document updates RFC 7252 ๐Ÿ’œ


Status of This Memo ๐Ÿ“œ

This is an Internet Standards Track document โญ

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 7841 ๐Ÿ“

Info about the current status of this document, any errata, and how to send feedback is at https://www.rfc-editor.org/info/rfc8613 ๐Ÿงš


Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License ๐ŸŽ€


Table of Contents ๐Ÿ—บ๏ธ

Here's the whole map of the spec, so you can see everything that's coming ๐Ÿ‘€

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   5
     1.1.  Terminology . . . . . . . . . . . . . . . . . . . . . . .   7
   2.  The OSCORE Option . . . . . . . . . . . . . . . . . . . . . .   8
   3.  The Security Context  . . . . . . . . . . . . . . . . . . . .   8
     3.1.  Security Context Definition . . . . . . . . . . . . . . .   9
     3.2.  Establishment of Security Context Parameters  . . . . . .  11
     3.3.  Requirements on the Security Context Parameters . . . . .  14
   4.  Protected Message Fields  . . . . . . . . . . . . . . . . . .  15
     4.1.  CoAP Options  . . . . . . . . . . . . . . . . . . . . . .  16
     4.2.  CoAP Header Fields and Payload  . . . . . . . . . . . . .  24
     4.3.  Signaling Messages  . . . . . . . . . . . . . . . . . . .  25
   5.  The COSE Object . . . . . . . . . . . . . . . . . . . . . . .  26
     5.1.  ID Context and 'kid context'  . . . . . . . . . . . . . .  27
     5.2.  AEAD Nonce  . . . . . . . . . . . . . . . . . . . . . . .  28
     5.3.  Plaintext . . . . . . . . . . . . . . . . . . . . . . . .  29
     5.4.  Additional Authenticated Data . . . . . . . . . . . . . .  30
   6.  OSCORE Header Compression . . . . . . . . . . . . . . . . . .  31
     6.1.  Encoding of the OSCORE Option Value . . . . . . . . . . .  32
     6.2.  Encoding of the OSCORE Payload  . . . . . . . . . . . . .  33
     6.3.  Examples of Compressed COSE Objects . . . . . . . . . . .  33
   7.  Message Binding, Sequence Numbers, Freshness, and Replay
       Protection  . . . . . . . . . . . . . . . . . . . . . . . . .  36
     7.1.  Message Binding . . . . . . . . . . . . . . . . . . . . .  36
     7.2.  Sequence Numbers  . . . . . . . . . . . . . . . . . . . .  36
     7.3.  Freshness . . . . . . . . . . . . . . . . . . . . . . . .  36
     7.4.  Replay Protection . . . . . . . . . . . . . . . . . . . .  37
     7.5.  Losing Part of the Context State  . . . . . . . . . . . .  38
   8.  Processing  . . . . . . . . . . . . . . . . . . . . . . . . .  39
     8.1.  Protecting the Request  . . . . . . . . . . . . . . . . .  39
     8.2.  Verifying the Request . . . . . . . . . . . . . . . . . .  40
     8.3.  Protecting the Response . . . . . . . . . . . . . . . . .  41
     8.4.  Verifying the Response  . . . . . . . . . . . . . . . . .  43
   9.  Web Linking . . . . . . . . . . . . . . . . . . . . . . . . .  44
   10. CoAP-to-CoAP Forwarding Proxy . . . . . . . . . . . . . . . .  45
   11. HTTP Operations . . . . . . . . . . . . . . . . . . . . . . .  46
     11.1.  The HTTP OSCORE Header Field . . . . . . . . . . . . . .  46
     11.2.  CoAP-to-HTTP Mapping . . . . . . . . . . . . . . . . . .  47
     11.3.  HTTP-to-CoAP Mapping . . . . . . . . . . . . . . . . . .  48
     11.4.  HTTP Endpoints . . . . . . . . . . . . . . . . . . . . .  48
     11.5.  Example: HTTP Client and CoAP Server . . . . . . . . . .  48
     11.6.  Example: CoAP Client and HTTP Server . . . . . . . . . .  50
   12. Security Considerations . . . . . . . . . . . . . . . . . . .  51
     12.1.  End-to-end Protection  . . . . . . . . . . . . . . . . .  51
     12.2.  Security Context Establishment . . . . . . . . . . . . .  52
     12.3.  Master Secret  . . . . . . . . . . . . . . . . . . . . .  52
     12.4.  Replay Protection  . . . . . . . . . . . . . . . . . . .  53
     12.5.  Client Aliveness . . . . . . . . . . . . . . . . . . . .  53
     12.6.  Cryptographic Considerations . . . . . . . . . . . . . .  53
     12.7.  Message Segmentation . . . . . . . . . . . . . . . . . .  54
     12.8.  Privacy Considerations . . . . . . . . . . . . . . . . .  54
   13. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  55
     13.1.  COSE Header Parameters Registry  . . . . . . . . . . . .  55
     13.2.  CoAP Option Numbers Registry . . . . . . . . . . . . . .  55
     13.3.  CoAP Signaling Option Numbers Registry . . . . . . . . .  56
     13.4.  Header Field Registrations . . . . . . . . . . . . . . .  57
     13.5.  Media Type Registration  . . . . . . . . . . . . . . . .  57
     13.6.  CoAP Content-Formats Registry  . . . . . . . . . . . . .  58
     13.7.  OSCORE Flag Bits Registry  . . . . . . . . . . . . . . .  58
     13.8.  Expert Review Instructions . . . . . . . . . . . . . . .  59
   14. References  . . . . . . . . . . . . . . . . . . . . . . . . .  60
     14.1.  Normative References . . . . . . . . . . . . . . . . . .  60
     14.2.  Informative References . . . . . . . . . . . . . . . . .  62
   Appendix A.  Scenario Examples  . . . . . . . . . . . . . . . . .  65
     A.1.  Secure Access to Sensor . . . . . . . . . . . . . . . . .  65
     A.2.  Secure Subscribe to Sensor  . . . . . . . . . . . . . . .  66
   Appendix B.  Deployment Examples  . . . . . . . . . . . . . . . .  68
     B.1.  Security Context Derived Once . . . . . . . . . . . . . .  68
     B.2.  Security Context Derived Multiple Times . . . . . . . . .  70
   Appendix C.  Test Vectors . . . . . . . . . . . . . . . . . . . .  75
     C.1.  Test Vector 1: Key Derivation with Master Salt  . . . . .  75
     C.2.  Test Vector 2: Key Derivation without Master Salt . . . .  77
     C.3.  Test Vector 3: Key Derivation with ID Context . . . . . .  78
     C.4.  Test Vector 4: OSCORE Request, Client . . . . . . . . . .  80
     C.5.  Test Vector 5: OSCORE Request, Client . . . . . . . . . .  81
     C.6.  Test Vector 6: OSCORE Request, Client . . . . . . . . . .  82
     C.7.  Test Vector 7: OSCORE Response, Server  . . . . . . . . .  84
     C.8.  Test Vector 8: OSCORE Response with Partial IV, Server  .  85
   Appendix D.  Overview of Security Properties  . . . . . . . . . .  86
     D.1.  Threat Model  . . . . . . . . . . . . . . . . . . . . . .  86
     D.2.  Supporting Proxy Operations . . . . . . . . . . . . . . .  87
     D.3.  Protected Message Fields  . . . . . . . . . . . . . . . .  87
     D.4.  Uniqueness of (key, nonce)  . . . . . . . . . . . . . . .  88
     D.5.  Unprotected Message Fields  . . . . . . . . . . . . . . .  89
   Appendix E.  CDDL Summary . . . . . . . . . . . . . . . . . . . .  93
   Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  94
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  94

That's the front door, bestie ๐Ÿฆ‹ Section 1 (the Introduction) is next, so keep your eyes peeled โœจ

1. Introduction โœจ

Okay bestie, let's get into it ๐Ÿ’– So CoAP [RFC7252] is this super cute web transfer protocol built for constrained nodes and networks [RFC7228] ๐Ÿฆ‹, and CoAP can also get mapped from HTTP [RFC8075]. CoAP uses proxies for scalability and efficiency, and it leans on DTLS [RFC6347] for security ๐Ÿ”. But here's the tea: CoAP-to-CoAP, HTTP-to-CoAP, and CoAP-to-HTTP proxies need DTLS or TLS [RFC8446] terminated at the proxy. ๐Ÿ˜ญ So the proxy can see everything it needs to do its job, but it can also eavesdrop on or manipulate any part of the message payload and metadata in transit between the endpoints. Not me being dramatic... the proxy can even inject, delete, or reorder packets, since they're no longer protected by (D)TLS. ๐Ÿ’€

This document defines the Object Security for Constrained RESTful Environments (OSCORE) security protocol ๐Ÿ‘‘, which protects CoAP and CoAP-mappable HTTP requests and responses end-to-end, even across intermediary nodes like CoAP forward proxies and cross-protocol translators such as HTTP-to-CoAP proxies [RFC8075]. On top of the core CoAP features from [RFC7252], OSCORE supports the Observe [RFC7641], Block-wise [RFC7959], and No-Response [RFC7967] options, plus the PATCH and FETCH methods [RFC8132]. An analysis of end-to-end security for CoAP messages through some types of intermediary nodes is in [CoAP-E2E-Sec] ๐Ÿ”. Basically, OSCORE protects the RESTful interactions: the request method, the requested resource, the message payload, etc. (see Section 4). Here, "RESTful" refers to the Representational State Transfer (REST) Architecture [REST] ๐ŸŒธ. OSCORE does not protect the CoAP messaging layer or the CoAP Token, which may change between the endpoints, so those get processed as defined in [RFC7252]. Also, the message formats for CoAP over unreliable transport [RFC7252] and CoAP over reliable transport [RFC8323] differ only in the CoAP messaging layer, so OSCORE can be applied to both unreliable and reliable transports (see Figure 1) โœจ.

           +-----------------------------------+
           |            Application            |
           +-----------------------------------+
           +-----------------------------------+  \
           |  Requests / Responses / Signaling |  |
           |-----------------------------------|  |
           |               OSCORE              |  | CoAP
           |-----------------------------------|  |
           | Messaging Layer / Message Framing |  |
           +-----------------------------------+  /
           +-----------------------------------+
           |          UDP / TCP / ...          |
           +-----------------------------------+

          Figure 1: Abstract Layering of CoAP with OSCORE

OSCORE works in very constrained nodes and networks ๐Ÿงš, thanks to its small message size and its restricted code and memory requirements on top of what CoAP already needs. Examples of OSCORE in use are in Appendix A. OSCORE may be used over any underlying layer, like UDP or TCP, and with non-IP transports (e.g., [CoAP-802.15.4]) ๐Ÿ’œ. OSCORE may also be used in different ways with HTTP: OSCORE messages may be transported in HTTP, and OSCORE may also protect CoAP-mappable HTTP messages, as described below.

OSCORE is designed to protect as much information as possible while still allowing CoAP proxy operations (Section 10) ๐ŸŽ€. It works with existing CoAP-to-CoAP forward proxies [RFC7252], but an OSCORE-aware proxy will be more efficient. HTTP-to-CoAP proxies [RFC8075] and CoAP-to-HTTP proxies can also be used with OSCORE, as specified in Section 11 ๐Ÿฆ‹. OSCORE may be used together with TLS or DTLS over one or more hops in the end-to-end path, e.g., transported with HTTPS in one hop and with plain CoAP in another hop. The use of OSCORE does not affect the URI scheme, so OSCORE can be used with any URI scheme defined for CoAP or HTTP. The application decides the conditions for which OSCORE is required ๐Ÿซถ.

OSCORE uses pre-shared keys that may have been established out-of-band or with a key establishment protocol (see Section 3.2) ๐Ÿ”‘. The technical solution builds on CBOR Object Signing and Encryption (COSE) [RFC8152], giving you end-to-end encryption, integrity, replay protection, and binding of the response to the request ๐Ÿ”ฅ. A compressed version of COSE is used, as specified in Section 6. OSCORE is signaled in CoAP with a new option (Section 2), and in HTTP with a new header field (Section 11.1) and content type (Section 13.5). The solution transforms a CoAP/HTTP message into an "OSCORE message" before sending, and back again after receiving. The OSCORE message is a CoAP/HTTP message related to the original message in the following way: the original CoAP/HTTP message is translated to CoAP (if it isn't already CoAP) and protected in a COSE object. The encrypted message fields of this COSE object are carried in the CoAP payload or HTTP body of the OSCORE message, and the OSCORE option or header field is included in the message ๐ŸŒˆ. Here's a sketch of an exchange of OSCORE messages, when the original message is CoAP, in Figure 2. The use of OSCORE with HTTP is detailed in Section 11.

       Client                                          Server
          |      OSCORE request - POST example.com:      |
          |        Header, Token,                        |
          |        Options: OSCORE, ...,                 |
          |        Payload: COSE ciphertext              |
          +--------------------------------------------->|
          |                                              |
          |<---------------------------------------------+
          |      OSCORE response - 2.04 (Changed):       |
          |        Header, Token,                        |
          |        Options: OSCORE, ...,                 |
          |        Payload: COSE ciphertext              |
          |                                              |

                Figure 2: Sketch of CoAP with OSCORE

An implementation supporting this specification MAY implement only the client part, MAY implement only the server part, or MAY implement only one of the proxy parts ๐Ÿง.

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. Translation: these capital words are the official vibe-check words, and they only count when they're written in ALL CAPS ๐Ÿ’….

Readers are expected to be familiar with the terms and concepts described in CoAP [RFC7252], COSE [RFC8152], Concise Binary Object Representation (CBOR) [RFC7049], Concise Data Definition Language (CDDL) [RFC8610] (summarized in Appendix E), and constrained environments [RFC7228]. Additional optional features include Observe [RFC7641], Block-wise [RFC7959], No-Response [RFC7967], and CoAP over reliable transport [RFC8323] ๐ŸŒธ.

The term "hop" is used to denote a particular leg in the end-to-end path ๐Ÿ›ค๏ธ. The concept "hop-by-hop" (as in "hop-by-hop encryption" or "hop-by-hop fragmentation") is the opposite of "end-to-end". In this document, it's used to indicate that the messages are processed accordingly in the intermediaries, rather than just forwarded to the next node ๐Ÿ™ˆ.

The term "stop processing" is used throughout the document to mean that the message is not passed up to the CoAP request/response layer (see Figure 1) ๐Ÿ›‘.

The terms Common Context, Sender Context, Recipient Context, Master Secret, Master Salt, Sender ID, Sender Key, Recipient ID, Recipient Key, ID Context, and Common IV are defined in Section 3.1 ๐Ÿ“.


2. The OSCORE Option ๐ŸŽ€

The OSCORE option defined in this section (see Figure 3, which extends "Table 4: Options" of [RFC7252]) tells you that the CoAP message is an OSCORE message and that it contains a compressed COSE object (see Sections 5 and 6) ๐Ÿ’–. The OSCORE option is critical, safe to forward, part of the cache key, and not repeatable ๐Ÿ”.

+------+---+---+---+---+----------------+--------+--------+---------+
| No.  | C | U | N | R | Name           | Format | Length | Default |
+------+---+---+---+---+----------------+--------+--------+---------+
|   9  | x |   |   |   | OSCORE         |  (*)   | 0-255  | (none)  |
+------+---+---+---+---+----------------+--------+--------+---------+

    C = Critical,   U = Unsafe,   N = NoCacheKey,   R = Repeatable
    (*) See below.

                     Figure 3: The OSCORE Option

The OSCORE option includes the OSCORE flag bits (Section 6), the Sender Sequence Number, the Sender ID, and the ID Context when these fields are present (Section 3) ๐Ÿงš. The detailed format and length are specified in Section 6. If the OSCORE flag bits are all zero (0x00), the option value SHALL be empty (Option Length = 0). An endpoint receiving a CoAP message without payload that also contains an OSCORE option SHALL treat it as malformed and reject it ๐Ÿšซ.

A successful response to a request with the OSCORE option SHALL contain the OSCORE option โœจ. Whether error responses contain the OSCORE option depends on the error type (see Section 8) ๐Ÿ’€.

For CoAP proxy operations, see Section 10 ๐Ÿฆ‹.


3. The Security Context ๐Ÿ”

OSCORE requires that client and server establish a shared security context used to process the COSE objects ๐Ÿค. OSCORE uses COSE with an Authenticated Encryption with Associated Data (AEAD, [RFC5116]) algorithm to protect message data between a client and a server ๐Ÿ’œ. In this section, we define the security context and how it gets derived on the client and server, based on a shared secret and a key derivation function ๐ŸŒˆ.

3.1. Security Context Definition โœจ

okay so the security context is basically the bag of info you need to do all the OSCORE crypto ๐ŸŽ€ each endpoint has three pieces: a "Common Context", a "Sender Context", and a "Recipient Context" ๐Ÿ’…

the endpoints protect the messages they send using the Sender Context, and check incoming messages using the Recipient Context. both of those get derived from the Common Context plus some other stuff ๐Ÿฆ‹ and clients and servers need to be able to grab the right security context to use, obviously ๐Ÿ’œ

so an endpoint uses its Sender ID (SID) to build its Sender Context, and the other endpoint takes that same ID, now called the Recipient ID (RID), and uses it to build its Recipient Context ๐ŸŒธ basically the two contexts are mirror images of each other. the Sender Context on one side matches the Recipient Context on the other side, and the other way around too. so the two security contexts that share the same IDs aren't identical, but they're partly mirrored, which is kind of iconic honestly โœจ here's how retrieving and using it looks (Figure 4):

         .---------------------.   .---------------------.
         |    Common Context   | = |    Common Context   |
         +---------------------+   +---------------------+
         |    Sender Context   | = |  Recipient Context  |
         +---------------------+   +---------------------+
         |  Recipient Context  | = |    Sender Context   |
         '---------------------'   '---------------------'
                  Client                   Server
                     |                       |
Retrieve context for  | OSCORE request:       |
 target resource      |   Token = Token1,     |
Protect request with  |   kid = SID, ...      |
  Sender Context      +---------------------->| Retrieve context with
                     |                       |  RID = kid
                     |                       | Verify request with
                     |                       |  Recipient Context
                     | OSCORE response:      | Protect response with
                     |   Token = Token1, ... |  Sender Context
Retrieve context with |<----------------------+
 Token = Token1      |                       |
Verify request with   |                       |
 Recipient Context    |                       |

Figure 4: Retrieval and Use of the Security Context

the Common Context holds these parameters ๐Ÿงš

  • AEAD Algorithm. The COSE AEAD algorithm to use for encryption.
  • HKDF Algorithm. An HMAC-based key derivation function (HKDF, [RFC5869]) used to derive the Sender Key, Recipient Key, and Common IV.
  • Master Secret. Variable length, random byte string (see Section 12.3) used to derive AEAD keys and Common IV.
  • Master Salt. Optional variable-length byte string containing the salt used to derive AEAD keys and Common IV.
  • ID Context. Optional variable-length byte string providing additional information to identify the Common Context and to derive AEAD keys and Common IV. The use of ID Context is described in Section 5.1.
  • Common IV. Byte string derived from the Master Secret, Master Salt, and ID Context. Used to generate the AEAD nonce (see Section 5.2). Same length as the nonce of the AEAD Algorithm.

the Sender Context holds these ๐ŸŒท

  • Sender ID. Byte string used to identify the Sender Context, to derive AEAD keys and Common IV, and to contribute to the uniqueness of AEAD nonces. Maximum length is determined by the AEAD Algorithm.
  • Sender Key. Byte string containing the symmetric AEAD key to protect messages to send. Derived from Common Context and Sender ID. Length is determined by the AEAD Algorithm.
  • Sender Sequence Number. Non-negative integer used by the sender to enumerate requests and certain responses, e.g., Observe notifications. Used as "Partial IV" [RFC8152] to generate unique AEAD nonces. Maximum value is determined by the AEAD Algorithm. Initialization is described in Section 3.2.2.

the Recipient Context holds these ๐Ÿฆ‹

  • Recipient ID. Byte string used to identify the Recipient Context, to derive AEAD keys and Common IV, and to contribute to the uniqueness of AEAD nonces. Maximum length is determined by the AEAD Algorithm.
  • Recipient Key. Byte string containing the symmetric AEAD key to verify messages received. Derived from Common Context and Recipient ID. Length is determined by the AEAD Algorithm.
  • Replay Window (Server only). The replay window used to verify requests received. Replay protection is described in Section 7.4 and Section 3.2.2.

so basically, everything here is locked in once the security context is set up, EXCEPT the Sender Sequence Number and the Replay Window ๐Ÿ”’ (they're allowed to change, bestie). also an endpoint can save memory by not storing the Common IV, Sender Key, and Recipient Key and just deriving them when it needs them ๐Ÿ’– or it can drop the Master Secret and Master Salt once it's already derived the other stuff. galaxy brain moves ๐Ÿง 

endpoints MAY act as both client and server and use the same security context for both roles ๐Ÿ‘‘ no matter which role it's in, it protects outgoing messages with its Sender Context and checks incoming ones with its Recipient Context. and the endpoints MUST NOT change the Sender/Recipient ID when they switch roles. in other words, switching roles doesn't change the set of AEAD keys being used ๐Ÿซถ

3.2. Establishment of Security Context Parameters

each endpoint derives the security context parameters from a small set of input parameters ๐ŸŒˆ the following input parameters SHALL be preestablished:

  • Master Secret
  • Sender ID
  • Recipient ID

the following input parameters MAY be preestablished. if any of these isn't preestablished, the default value below gets used ๐Ÿ’…

  • AEAD Algorithm
    • Default is AES-CCM-16-64-128 (COSE algorithm encoding: 10)
  • Master Salt
    • Default is the empty byte string
  • HKDF Algorithm
    • Default is HKDF SHA-256
  • Replay Window
    • The default mechanism is an anti-replay sliding window (see Section 4.1.2.6 of [RFC6347] with a window size of 32

all the input parameters need to be known and agreed on by both endpoints, but the Replay Window may be different on the two endpoints ๐ŸŽ€ how the input parameters get preestablished is application specific. security context establishment considerations are in Section 12.2, and examples of deploying OSCORE are in Appendix B ๐Ÿ“š

3.2.1. Derivation of Sender Key, Recipient Key, and Common IV

okay the HKDF MUST be one of the HMAC-based HKDF [RFC5869] algorithms defined for COSE [RFC8152]. HKDF SHA-256 is mandatory to implement ๐Ÿ’– the security context parameters Sender Key, Recipient Key, and Common IV SHALL be derived from the input parameters using the HKDF, which is the composition of the HKDF-Extract and HKDF-Expand steps [RFC5869]:

output parameter = HKDF(salt, IKM, info, L)

where:

  • salt is the Master Salt as defined above
  • IKM is the Master Secret as defined above
  • info is the serialization of a CBOR array consisting of (the notation follows [RFC8610] as summarized in Appendix E):
info = [
  id : bstr,
  id_context : bstr / nil,
  alg_aead : int / tstr,
  type : tstr,
  L : uint,
]

where:

  • id is the Sender ID or Recipient ID when deriving Sender Key and Recipient Key, respectively, and the empty byte string when deriving the Common IV.
  • id_context is the ID Context, or nil if ID Context is not provided.
  • alg_aead is the AEAD Algorithm, encoded as defined in [RFC8152].
  • type is "Key" or "IV". The label is an ASCII string and does not include a trailing NUL byte.
  • L is the size of the key/nonce for the AEAD Algorithm used, in bytes.

for example, if the algorithm AES-CCM-16-64-128 (see Section 10.2 in [RFC8152]) is used, the integer value for alg_aead is 10, and the value for L is 16 for keys and 13 for the Common IV ๐Ÿง assuming the default algorithms HKDF SHA-256 and AES-CCM-16-64-128, the extract phase of HKDF produces a pseudorandom key (PRK) like this:

PRK = HMAC-SHA-256(Master Salt, Master Secret)

and since L is smaller than the hash function output size, the expand phase of HKDF consists of a single HMAC invocation. so the Sender Key, Recipient Key, and Common IV are the first 16 or 13 bytes of:

output parameter = HMAC-SHA-256(PRK, info || 0x01)

different values of info get used for each derived parameter, and || means byte string concatenation ๐Ÿฆ‹

note that [RFC5869] says that if the salt isn't provided, it gets set to a string of zeros. for implementation purposes, not providing the salt is the same as setting the salt to the empty byte string. OSCORE sets the salt default value to the empty byte string, which is converted to a string of zeroes (see Section 2.2 of [RFC5869]) ๐ŸŒธ

3.2.2. Initial Sequence Numbers and Replay Window

the Sender Sequence Number is initialized to 0 ๐Ÿ“

the supported types of replay protection and the replay window size are application specific, and they depend on how OSCORE is transported (see Section 7.4). the default mechanism is the anti-replay window of received messages used by IPsec AH/ESP and DTLS (see Section 4.1.2.6 of [RFC6347]) with a window size of 32 ๐Ÿ›ก๏ธ

3.3. Requirements on the Security Context Parameters

okay this part is so important bestie ๐Ÿ˜ญ to make sure Sender Keys are unique, the quartet (Master Secret, Master Salt, ID Context, Sender ID) MUST be unique. i.e., the pair (ID Context, Sender ID) SHALL be unique in the set of all security contexts using the same Master Secret and Master Salt. this means Sender ID SHALL be unique in the set of all security contexts using the same Master Secret, Master Salt, and ID Context. that requirement is what guarantees unique (key, nonce) pairs for the AEAD ๐Ÿ”ฅ

there are different ways to assign Sender IDs: a protocol that lets the parties negotiate locally unique identifiers, a trusted third party (e.g., [ACE-OAuth]), or the identifiers can be assigned out-of-band ๐Ÿงš Sender IDs can be super short (the empty string is a legit value, iykyk ๐Ÿ™ˆ). the maximum length of Sender ID in bytes equals the length of the AEAD nonce minus 6, see Section 5.2. for AES-CCM-16-64-128, the maximum length of Sender ID is 7 bytes.

to make it easier to grab the right Recipient Context, the Recipient ID SHOULD be unique in the sets of all Recipient Contexts used by an endpoint. if an endpoint has the same Recipient ID with different Recipient Contexts (meaning the Recipient Contexts are derived from different Common Contexts), then the endpoint may need to try multiple times before it verifies the right security context associated with the Recipient ID ๐Ÿ˜ตโ€๐Ÿ’ซ

the ID Context is used to tell security contexts apart. the methods used to assign Sender IDs can also be used to assign the ID Context. on top of that, the ID Context can be used to add randomness to new Sender and Recipient Contexts (see Appendix B.2). ID Context can be arbitrarily long ๐ŸŒˆ

4. Protected Message Fields โœจ

Okay so, OSCORE takes a CoAP message (which might have started life as an HTTP message) and turns it into an OSCORE message, and then back again ๐Ÿ”„. It protects as much of the original message as it can, but it still leaves room for certain proxy operations (see Sections 10 and 11). This section explains how OSCORE protects each message field and carries it end-to-end between client and server, in either direction ๐Ÿ’–

The rest of this section and the later ones talk about things in terms of CoAP messages. If HTTP is used for a particular hop in the end-to-end path, this section applies to the conceptual CoAP message that maps to and from the original HTTP message (see Section 11). So an HTTP message gets conceptually turned into a CoAP message, then into an OSCORE message, and the reverse direction works the same way ๐Ÿฆ‹ An actual implementation might go straight from HTTP to OSCORE and skip the CoAP step in the middle.

Protection of signaling messages (Section 5 of [RFC8323]) is covered in Section 4.3. Everything else in this section is about request/response messages ๐ŸŽ€

Message fields of a CoAP message can be protected end-to-end between the CoAP client and the CoAP server in three different ways:

  • Class E: encrypted and integrity protected, ๐Ÿ”
  • Class I: integrity protected only, or ๐Ÿงท
  • Class U: unprotected. ๐ŸŒธ

The sending endpoint SHALL transfer Class E message fields in the ciphertext of the COSE object in the OSCORE message. ๐Ÿซถ The sending endpoint SHALL include Class I message fields in the AAD of the AEAD algorithm, so the receiving endpoint can tell if the value changed in transit. Class U message fields SHALL NOT be protected in transfer. Class I and Class U field values travel in the header or options part of the OSCORE message, which means proxies can see them ๐Ÿ‘€

Fields that proxies can't see (the ones hidden inside the ciphertext of the COSE object) are called "Inner" (Class E). Fields that ride in the header or options part of the OSCORE message, where proxies can see them, are called "Outer" (Class I or Class U). There are currently no Class I options defined.

An OSCORE message can carry both an Inner and an Outer copy of the same CoAP message field ๐Ÿ’… Inner fields are meant for the receiving endpoint, while Outer fields exist so proxies can do their thing โœจ

4.1. CoAP Options

Here's a quick summary of how options get protected, shown in Figure 5 ๐Ÿ“ Some options can have both Inner and Outer fields, and each one is protected accordingly. Certain options need special processing, as described in Section 4.1.3.

Options that are unknown, or that OSCORE processing isn't defined for, SHALL be processed as Class E (and get no special processing). Specs for new CoAP options SHOULD define how they're processed with OSCORE. A new COAP option SHOULD be Class E unless it needs proxy processing. If a new CoAP option is Class U, the potential issues with leaving it unprotected SHOULD be documented (see Appendix D.5). ๐Ÿงš

4.1.1. Inner Options

Inner option message fields (Class E) are for talking directly to the other endpoint ๐Ÿ’œ

The sending endpoint SHALL write the Inner option message fields from the original CoAP message into the plaintext of the COSE object (Section 5.3), and then remove those Inner option fields from the OSCORE message โœ‚๏ธ

How the receiving endpoint processes Inner option fields is specified in Sections 8.2 and 8.4.

                   +------+-----------------+---+---+
                   | No.  | Name            | E | U |
                   +------+-----------------+---+---+
                   |   1  | If-Match        | x |   |
                   |   3  | Uri-Host        |   | x |
                   |   4  | ETag            | x |   |
                   |   5  | If-None-Match   | x |   |
                   |   6  | Observe         | x | x |
                   |   7  | Uri-Port        |   | x |
                   |   8  | Location-Path   | x |   |
                   |   9  | OSCORE          |   | x |
                   |  11  | Uri-Path        | x |   |
                   |  12  | Content-Format  | x |   |
                   |  14  | Max-Age         | x | x |
                   |  15  | Uri-Query       | x |   |
                   |  17  | Accept          | x |   |
                   |  20  | Location-Query  | x |   |
                   |  23  | Block2          | x | x |
                   |  27  | Block1          | x | x |
                   |  28  | Size2           | x | x |
                   |  35  | Proxy-Uri       |   | x |
                   |  39  | Proxy-Scheme    |   | x |
                   |  60  | Size1           | x | x |
                   | 258  | No-Response     | x | x |
                   +------+-----------------+---+---+

                 E = Encrypt and Integrity Protect (Inner)
                 U = Unprotected (Outer)

                   Figure 5: Protection of CoAP Options

4.1.2. Outer Options

Outer option message fields (Class U or I) are there to support proxy operations, see Appendix D.2 ๐ŸŒˆ

The sending endpoint SHALL include the Outer option message field from the original message in the options part of the OSCORE message. All Outer option message fields, including the OSCORE option, SHALL be encoded as described in Section 3.1 of [RFC7252], where the delta is the difference from the previously included instance of an Outer option message field. ๐Ÿ”ข

How the receiving endpoint processes Outer options is specified in Sections 8.2 and 8.4.

A procedure for integrity-protection-only of Class I option message fields is specified in Section 5.4. Specifications that introduce repeatable Class I options MUST specify that proxies MUST NOT change the order of the instances of such an option in the CoAP message. ๐Ÿ™ˆ

Note: There are currently no Class I option message fields defined.

4.1.3. Special Options

Some options need special processing, as specified in this section โญ

4.1.3.1. Max-Age

An Inner Max-Age message field tells the client the maximum time a response may be cached (as defined in [RFC7252]). It travels end-to-end from the server to the client, and proxies can't see it ๐Ÿ™ˆ The Inner Max-Age SHALL be processed by OSCORE as a normal Inner option, as specified in Section 4.1.1.

An Outer Max-Age message field exists to stop unnecessary caching of error responses that OSCORE processing causes at intermediary nodes that don't know about OSCORE ๐ŸงŠ A server MAY set a Class U Max-Age message field with the value zero on those error responses, which are described in Sections 7.4, 8.2, and 8.4. Why? Those error responses are cacheable, but later OSCORE requests would never hit the cached copy in the intermediary, so setting the Outer Max-Age to zero keeps the intermediary from pointlessly caching them ๐Ÿซ  Successful OSCORE responses don't need an Outer Max-Age option. Except when the Observe option (see Section 4.1.3.5) is used, responses look to an OSCORE-unaware intermediary like 2.04 (Changed) responses, which are non-cacheable (see Section 4.2). For Observe responses, which are cacheable, an Outer Max-Age option with the value 0 may be used to avoid unnecessary proxy caching. ๐Ÿ’พ

The Outer Max-Age message field is processed according to Section 4.1.2.

4.1.3.2. Uri-Host and Uri-Port

When Uri-Host and Uri-Port are set to their default values (see Section 5.10.1 [RFC7252]), they get left out of the message (Section 5.4.4 of [RFC7252]). That's great for both overhead and privacy ๐Ÿคซ

To support forward proxy operations, Proxy-Scheme, Uri-Host, and Uri-Port need to be Class U. For how to use Proxy-Uri, see Section 4.1.3.3.

Messing with unprotected message fields (including Uri-Host, Uri-Port, the destination IP/port, or the request scheme) MUST NOT lead to an OSCORE message being verified by an unintended server. ๐Ÿšซ Different servers SHALL have different security contexts. ๐Ÿ”‘

4.1.3.3. Proxy-Uri

When Proxy-Uri is present, the client SHALL first break down the Proxy-Uri value of the original CoAP message into the Proxy-Scheme, Uri-Host, Uri-Port, Uri-Path, and Uri-Query options, following Section 6.4 of [RFC7252] ๐Ÿงฉ

Uri-Path and Uri-Query are Class E options. They SHALL be protected and processed as Inner options (Section 4.1.1) ๐Ÿ”

The Proxy-Uri option of the OSCORE message SHALL be set to the composition of the Proxy-Scheme, Uri-Host, and Uri-Port options, as specified in Section 6.5 of [RFC7252], and it's processed as an Outer option of Class U (Section 4.1.2).

Replacing the Proxy-Uri value with the Proxy-Scheme and Uri-* options works by design for all CoAP URIs (see Section 6 of [RFC7252]). OSCORE-aware HTTP servers should not use the userinfo component of the HTTP URI (as defined in Section 3.2.1 of [RFC3986]), so this kind of replacement stays possible when there are CoAP-to-HTTP proxies (see Section 11.2) ๐Ÿง In future specs for cross-protocol proxying with different URI structures, the authors are expected to create Uri-* options that let you decompose the Proxy-Uri and specify the OSCORE processing โœจ

Here's an example of how Proxy-Uri gets processed. Say the original CoAP message contains:

  • Proxy-Uri = "coap://example.com/resource?q=1" ๐ŸŒท

During OSCORE processing, the Proxy-Uri gets split into:

  • Proxy-Scheme = "coap" ๐ŸŒผ
  • Uri-Host = "example.com" ๐ŸŒผ
  • Uri-Port = "5683" (default) ๐ŸŒผ
  • Uri-Path = "resource" ๐ŸŒผ
  • Uri-Query = "q=1" ๐ŸŒผ

Uri-Path and Uri-Query follow the processing defined in Section 4.1.1, so they're encrypted and carried inside the COSE object:

  • Uri-Path = "resource" ๐Ÿ”’
  • Uri-Query = "q=1" ๐Ÿ”’

The leftover options get composed into the Proxy-Uri that sits in the options part of the OSCORE message, which has this value:

  • Proxy-Uri = "coap://example.com" ๐Ÿซง

For more details, see Sections 6.1 and 12.6 of [RFC7252] ๐Ÿ“š

4.1.3.4. The Block Options

Block-wise [RFC7959] is an optional feature. An implementation MAY support CoAP [RFC7252] and the OSCORE option without supporting block-wise transfers. ๐Ÿงฉ The Block options (Block1, Block2, Size1, Size2) do two different jobs depending on where they live. As Inner message fields, they give secure message segmentation, so each segment can be verified. As Outer message fields, they enable hop-by-hop fragmentation of the OSCORE message. Inner and Outer block processing can behave differently performance-wise, depending on the underlying transport ๐Ÿš€ End-to-end integrity can be verified for both Inner and Outer block-wise transfers, as long as all the blocks get received. ๐Ÿ’–

4.1.3.4.1. Inner Block Options

The sending CoAP endpoint MAY fragment a CoAP message as defined in [RFC7959] before the message is processed by OSCORE. In that case, the Block options SHALL be processed by OSCORE as normal Inner options (Section 4.1.1). The receiving CoAP endpoint SHALL process the OSCORE message before processing block-wise as defined in [RFC7959]. ๐ŸŽ€

4.1.3.4.2. Outer Block Options ๐Ÿงฑ

Okay so, proxies are allowed (MAY) to chop an OSCORE message into pieces using [RFC7959], by adding Block option fields that are Outer (Section 4.1.2). ๐Ÿงฉ Here's the catch: Outer Block options are neither encrypted nor integrity protected, so ๐Ÿ˜ฌ a sneaky proxy could keep injecting block fragments forever. The receiving endpoint has to get the last block (see [RFC7959]) before it can put the OSCORE message back together and verify its integrity. So applications that support both OSCORE and [RFC7959] MUST specify a security policy that defines a maximum unfragmented message size (MAX_UNFRAGMENTED_SIZE), taking into account the biggest message the endpoints can handle. Anything bigger SHOULD get fragmented by the sending endpoint using Inner Block options (Section 4.1.3.4.1). Main character energy, fr ๐Ÿ’…

An endpoint that gets an OSCORE message with an Outer Block option SHALL process that option according to [RFC7959] first. It keeps going until all the blocks of the OSCORE message have arrived, or until the total size of the blocks goes over MAX_UNFRAGMENTED_SIZE. If all the blocks arrive, the OSCORE message is processed the way this document describes. If the size goes over the limit instead, the message SHALL be discarded. No cap, that's a hard stop ๐Ÿ›‘

Also, since Uri-Path and Uri-Query are encrypted, messages to the same server can look like they're all headed for the same resource when you're a proxy ๐Ÿ™ˆ So a proxy SHOULD mitigate the chance of mixing up blocks from concurrent requests to the same server. One way to do that is the Request-Tag processing from Section 3.3.2 of [CoAP-ECHO-REQ-TAG]. ๐ŸŽ€


4.1.3.5. Observe ๐Ÿ‘€

Observe [RFC7641] is an optional feature ๐ŸŒธ An implementation MAY support CoAP [RFC7252] and the OSCORE option without supporting [RFC7641]. If it doesn't, the Observe-related processing can just be left out.

Observe with OSCORE is aimed at the forwarding requirements in Section 2.2.1 of [CoAP-E2E-Sec]. Basically, observations need to be able to go through intermediary nodes, like in Figure 8 of [RFC7641]. โœจ

Inner Observe SHALL be used to protect the value of the Observe option between the endpoints. Outer Observe SHALL be used to support forwarding by intermediary nodes. Iconic teamwork ๐Ÿซถ

The server SHALL include a new Partial IV (see Section 5) in responses to Observe registrations, whether or not they have the Observe option. The only exception is the first response, where the Partial IV MAY be omitted.

For cancellations, Section 3.6 of [RFC7641] says that all options MUST be identical to the ones in the registration request, except for the Observe option and the set of ETag options. With OSCORE, this matching happens against the options in the decrypted message. ๐Ÿ”

[RFC7252] doesn't say how a server should react when it gets the same Token in different requests. With OSCORE, the server SHOULD NOT remove an active observation just because it sees a request with the same Token. Don't be that server ๐Ÿ™…โ€โ™€๏ธ

Since POST with the Observe option isn't defined, messages with the Observe option need the Outer Code MUST be set to 0.05 (FETCH) for requests and 2.05 (Content) for responses (see Section 4.2). Okay, that's the rule, periodt ๐Ÿ’–


4.1.3.5.1. Registrations and Cancellations ๐Ÿ”

The Inner and Outer Observe options in the request MUST contain the Observe value of the original CoAP request. That's 0 for registration or 1 for cancellation.

Every time a client sends a new request with the Observe option, a new Partial IV MUST be used (see Section 5), so the payload and the OSCORE option both change. The server uses the Partial IV of the new request as the request_piv for all the notifications tied to it (see Section 5.4). ๐Ÿฆ‹

Intermediaries don't get to see the OSCORE security context the endpoints use. So they can't make requests, or change responses, with the OSCORE option in a way that passes verification at the receiving endpoint as coming from the other endpoint. That leads to a few limits for Observe operations, ngl a bit sad but very real ๐Ÿ˜ญ

  • An intermediary node that removes the Outer Observe 0 option doesn't turn the registration request into one without the Observe option (see Section 2 of [RFC7641]). Other cancellation methods can be used instead, as described in Section 3.6 of [RFC7641].
  • An intermediary node can't turn a normal response into an OSCORE-protected Observe notification (see Figure 7 of [RFC7641]) that verifies as coming from the server.
  • An intermediary node can't start an OSCORE-protected Observe registration (Observe option with value 0) that verifies as coming from the client. An OSCORE-aware intermediary SHALL NOT initiate registrations of observations (see Section 10). If an OSCORE-unaware proxy resends an old registration message from a client, the replay protection mechanism in the server gets triggered. To keep that from making the OSCORE-unaware proxy cancel the registration, a server MAY respond to a replayed registration request by replaying a cached notification. Or, the server MAY send a new notification instead. ๐Ÿ”„
  • An intermediary node can't start an OSCORE-protected Observe cancellation (Observe option with value 1) that verifies as coming from the client. An application MAY decide to let intermediaries cancel Observe registrations, for example by sending the Observe option with value 1 (see Section 3.6 of [RFC7641]). That can also be done with other methods, like sending an RST message. This is out of scope for this specification. ๐Ÿ™ˆ

4.1.3.5.2. Notifications ๐Ÿ””

If the server accepts an Observe registration, a Partial IV MUST be included in all notifications, both successful and error ones. The only exception is the first notification, where the Partial IV MAY be omitted. To protect against replay, the client SHALL maintain a Notification Number for each Observation it registers. The Notification Number is a non-negative integer holding the largest Partial IV of the notifications received for that Observe registration. More details on replay protection for notifications are in Section 7.4.1. ๐Ÿ›ก๏ธ

For notifications, the Inner Observe option value MUST be empty (see Section 3.2 of [RFC7252]). The Outer Observe option in a notification is there so intermediary nodes can allow multiple responses to one request. It MAY be set to the value of the Observe option in the original CoAP message. The client orders notifications and does replay protection by comparing their Partial IVs, and it SHALL ignore the Outer Observe option value. Partial IVs are the MVP here โญ

If the client gets a response to an Observe request without an Inner Observe option, it verifies that response as a non-Observe response, as specified in Section 8.4. If the client gets a response to a non-Observe request that has an Inner Observe option, it stops processing the message, as specified in Section 8.4. Nope, not today ๐Ÿšซ

A client MUST consider the notification with the highest Partial IV as the freshest, no matter what order they arrive in. To support existing Observe implementations, the OSCORE client implementation MAY set the Observe option value to the three least significant bytes of the Partial IV. Implementations need to make sure that the notification without a Partial IV is treated as the oldest. ๐Ÿ•ฐ๏ธ


4.1.3.6. No-Response ๐Ÿ™…โ€โ™€๏ธ

No-Response [RFC7967] is an optional feature. The client uses it to say it isn't interested in certain classes of responses to a particular request. An implementation MAY support [RFC7252] and the OSCORE option without supporting [RFC7967]. ๐Ÿ’…

If No-Response is used, it MUST be Inner. The Inner No-Response SHALL be processed by OSCORE as specified in Section 4.1.1. The Outer option SHOULD NOT be present. The server SHALL ignore the Outer No-Response option. The client MAY set the Outer No-Response value to 26 (suppress all known codes) if the Inner value is set to 26. ๐Ÿคซ

The client MUST be prepared to receive and discard 5.04 (Gateway Timeout) error messages from intermediaries. Those can happen because the destination timed out with no response. Expect the drama and just toss it ๐Ÿ—‘๏ธ


4.1.3.7. OSCORE ๐Ÿง

The OSCORE option is only defined to show up in OSCORE messages, as a sign that OSCORE processing has happened. The content of the OSCORE option is neither encrypted nor integrity protected as a whole. But some part of it is protected (see Section 5.4). โœจ

Nested OSCORE isn't supported. If OSCORE processing finds an OSCORE option in the original CoAP message, then processing SHALL be stopped. No double-wrapping allowed, bestie ๐Ÿ›‘


4.2. CoAP Header Fields and Payload ๐Ÿ’Œ

Here's a quick look at how the CoAP header fields and payload get protected, with CoAP-over-UDP and CoAP-over-TCP fields marked in the table so you know which is which ๐Ÿฆ‹

                   +------------------+---+---+
                   | Field            | E | U |
                   +------------------+---+---+
                   | Version (UDP)    |   | x |
                   | Type (UDP)       |   | x |
                   | Length (TCP)     |   | x |
                   | Token Length     |   | x |
                   | Code             | x |   |
                   | Message ID (UDP) |   | x |
                   | Token            |   | x |
                   | Payload          | x |   |
                   +------------------+---+---+
             E = Encrypt and Integrity Protect (Inner)
             U = Unprotected (Outer)

      Figure 6: Protection of CoAP Header Fields and Payload

Most CoAP header fields (the message fields in the fixed 4-byte header) have to be read and/or changed by CoAP proxies ๐Ÿ”„ So they generally can't be protected end-to-end from one endpoint to the other. Like I mentioned in Section 1, OSCORE only protects the CoAP request/response layer, not the CoAP messaging layer (Section 2 of [RFC7252]). That's why fields like Type and Message ID aren't protected with OSCORE. Not everything can be a main character ๐Ÿ˜…

The CoAP header field Code is protected by OSCORE. Code SHALL be encrypted and integrity protected (Class E), so an intermediary can't eavesdrop on it or mess with it, like swapping GET for DELETE ๐Ÿ™€

The sending endpoint SHALL write the Code of the original CoAP message into the plaintext of the COSE object (see Section 5.3). After that, the sending endpoint writes an Outer Code into the OSCORE message. With one exception (see Section 4.1.3.5), the Outer Code SHALL be set to 0.02 (POST) for requests and 2.04 (Changed) for responses. The receiving endpoint SHALL discard the Outer Code in the OSCORE message and write the Code from the COSE object plaintext (Section 5.3) into the decrypted CoAP message. Code swap complete โœจ

The other currently defined CoAP header fields are Unprotected (Class U). The sending endpoint SHALL write all other header fields of the original message into the header of the OSCORE message. The receiving endpoint SHALL write the header fields from the received OSCORE message into the header of the decrypted CoAP message. Simple, clean, iconic ๐ŸŽ€

The CoAP Payload, if there is one in the original CoAP message, SHALL be encrypted and integrity protected, so it's an Inner message field. ๐Ÿ” The sending endpoint writes the payload of the original CoAP message into the plaintext (Section 5.3) input to the COSE object. The receiving endpoint verifies and decrypts the COSE object, and then it recreates the payload of the original CoAP message. Payload glow-up complete ๐Ÿ’œ

4.3. Signaling Messages โœจ

Okay bestie, signaling messages (CoAP Code 7.00-7.31) exist to swap info about an underlying transport connection, specifically for CoAP over reliable transports [RFC8323]. ๐Ÿงš

OSCORE MAY be used to protect signaling if the endpoints for OSCORE coincide with the endpoints for the signaling message. If OSCORE is used to protect signaling then:

  • To comply with [RFC8323], an initial empty Capabilities and Settings Message (CSM) SHALL be sent. The subsequent signaling message SHALL be protected. ๐Ÿ’…
  • Signaling messages SHALL be protected as CoAP request messages, except in the case in which the signaling message is a response to a previous signaling message; then it SHALL be protected as a CoAP response message. For example, 7.02 (Ping) is protected as a CoAP request and 7.03 (Pong) as a CoAP response. ๐Ÿ“
  • The Outer Code for signaling messages SHALL be set to 0.02 (POST), unless it is a response to a previous signaling message, in which case it SHALL be set to 2.04 (Changed). ๐ŸŒธ
  • All signaling options, except the OSCORE option, SHALL be Inner (Class E). ๐Ÿ”’

NOTE: Option numbers for signaling messages are specific to the CoAP Code (see Section 5.2 of [RFC8323]).

If OSCORE is not used to protect signaling, Signaling messages SHALL be unaltered by OSCORE. ๐Ÿฆ‹


5. The COSE Object ๐ŸŽ€

This section defines how to use COSE [RFC8152] to wrap and protect data in the original message. OSCORE uses the untagged COSE_Encrypt0 structure (see Section 5.2 of [RFC8152]) with an AEAD algorithm. The AEAD key lengths, AEAD nonce length, and maximum Sender Sequence Number are algorithm dependent. ๐Ÿง

The AEAD algorithm AES-CCM-16-64-128 defined in Section 10.2 of [RFC8152] is mandatory to implement. For AES-CCM-16-64-128, the length of Sender Key and Recipient Key is 128 bits; the length of AEAD nonce and Common IV is 13 bytes. The maximum Sender Sequence Number is specified in Section 12. ๐Ÿ”‘

As specified in [RFC5116], plaintext denotes the data that is to be encrypted and integrity protected, and Additional Authenticated Data (AAD) denotes the data that is to be integrity protected only. โœจ

The COSE object SHALL be a COSE_Encrypt0 object with fields defined as follows: ๐Ÿ‘‘

  • The 'protected' field is empty.
  • The 'unprotected' field includes:
    • The 'Partial IV' parameter. The value is set to the Sender Sequence Number. All leading bytes of value zero SHALL be removed when encoding the Partial IV, except in the case of Partial IV value 0, which is encoded to the byte string 0x00.

This parameter SHALL be present in requests and will not typically be present in responses (for two exceptions, see Observe notifications (Section 4.1.3.5.2) and Replay Window synchronization (Appendix B.1.2)). ๐Ÿ“

  • The 'kid' parameter. The value is set to the Sender ID. This parameter SHALL be present in requests and will not typically be present in responses. An example where the Sender ID is included in a response is the extension of OSCORE to group communication [Group-OSCORE]. ๐Ÿงš
  • Optionally, a 'kid context' parameter (see Section 5.1). This parameter MAY be present in requests and, if so, MUST contain an ID Context (see Section 3.1). This parameter SHOULD NOT be present in responses: an example of how 'kid context' can be used in responses is given in Appendix B.2. If 'kid context' is present in the request, then the server SHALL use a security context with that ID Context when verifying the request. ๐Ÿซถ
  • The 'ciphertext' field is computed from the secret key (Sender Key or Recipient Key), AEAD nonce (see Section 5.2), plaintext (see Section 5.3), and the AAD (see Section 5.4) following Section 5.2 of [RFC8152]. ๐Ÿ’œ

The encryption process is described in Section 5.3 of [RFC8152]. ๐ŸŒˆ

5.1. ID Context and 'kid context' ๐Ÿฆ‹

For certain use cases, e.g., deployments where the same Sender ID is used with multiple contexts, it is possible (and sometimes necessary, see Section 3.3) for the client to use an ID Context to distinguish the security contexts (see Section 3.1). For example:

  • If the client has a unique identifier in some namespace, then that identifier can be used as ID Context. ๐ŸŒธ
  • The ID Context may be used to add randomness into new Sender and Recipient Contexts, see Appendix B.2. ๐ŸŽ€
  • In the case of group communication [Group-OSCORE], a group identifier is used as ID Context to enable different security contexts for a server belonging to multiple groups. ๐Ÿ‘‘

The Sender ID and ID Context are used to establish the necessary input parameters and in the derivation of the security context (see Section 3.2).

While the 'kid' parameter is used to transport the Sender ID, the new COSE header parameter 'kid context' is used to transport the ID Context in requests, see Figure 7.

+----------+--------+------------+----------------+-----------------+
|   Name   |  Label | Value Type | Value Registry |   Description   |
+----------+--------+------------+----------------+-----------------+
|   kid    |    10  | bstr       |                | Identifies the  |
| context  |        |            |                | context for the |
|          |        |            |                | key identifier  |
+----------+--------+------------+----------------+-----------------+

Figure 7: Common Header Parameter 'kid context' for the COSE Object

If ID Context is non-empty and the client sends a request without 'kid context' resulting in an error indicating that the server could not find the security context, then the client could include the ID Context in the 'kid context' when making another request. Note that since the error is unprotected, it may have been spoofed and the real response blocked by an on-path attacker. ๐Ÿ™ˆ

5.2. AEAD Nonce ๐Ÿ’…

The high-level design of the AEAD nonce follows Section 4.4 of [IV-GEN]. The detailed construction of the AEAD nonce is presented here (see Figure 8):

  1. left-pad the Partial IV (PIV) with zeroes to exactly 5 bytes,
  2. left-pad the Sender ID of the endpoint that generated the Partial IV (ID_PIV) with zeroes to exactly nonce length minus 6 bytes,
  3. concatenate the size of the ID_PIV (a single byte S) with the padded ID_PIV and the padded PIV,
  4. and then XOR with the Common IV.

Note that in this specification, only AEAD algorithms that use nonces equal or greater than 7 bytes are supported. The nonce construction with S, ID_PIV, and PIV together with endpoint-unique IDs and encryption keys makes it easy to verify that the nonces used with a specific key will be unique, see Appendix D.4. ๐Ÿ”ฅ

If the Partial IV is not present in a response, the nonce from the request is used. For responses that are not notifications (i.e., when there is a single response to a request), the request and the response should typically use the same nonce to reduce message overhead. Both alternatives provide all the required security properties, see Section 7.4 and Appendix D.4. Another non-Observe scenario where a Partial IV is included in a response is when the server is unable to perform replay protection, see Appendix B.1.2. For processing instructions see Section 8. โœจ

           <- nonce length minus 6 B -> <-- 5 bytes -->
      +---+-------------------+--------+---------+-----+
      | S |      padding      | ID_PIV | padding | PIV |----+
      +---+-------------------+--------+---------+-----+    |
                                                            |
       <---------------- nonce length ---------------->     |
      +------------------------------------------------+    |
      |                   Common IV                    |->(XOR)
      +------------------------------------------------+    |
                                                            |
       <---------------- nonce length ---------------->     |
      +------------------------------------------------+    |
      |                     Nonce                      |<---+
      +------------------------------------------------+

Figure 8: AEAD Nonce Formation

5.3. Plaintext ๐ŸŒธ

The plaintext is formatted as a CoAP message with a subset of the header (see Figure 9) consisting of:

  • the Code of the original CoAP message as defined in Section 3 of [RFC7252]; and
  • all Inner option message fields (see Section 4.1.1) present in the original CoAP message (see Section 4.1). The options are encoded as described in Section 3.1 of [RFC7252], where the delta is the difference from the previously included instance of Class E option; and
  • the Payload of original CoAP message, if present, and in that case prefixed by the one-byte Payload Marker (0xff).

NOTE: The plaintext contains all CoAP data that needs to be encrypted end-to-end between the endpoints. ๐Ÿ”

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     Code      |    Class E options (if any) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1 1 1 1 1 1 1 1|    Payload (if any) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    (only if there is payload)

                         Figure 9: Plaintext

5.4. Additional Authenticated Data

okay so the external_aad SHALL be a CBOR array wrapped in a bstr object ๐Ÿ’… as defined below, following the notation of [RFC8610] as summarized in Appendix E:

external_aad = bstr .cbor aad_array

aad_array = [
  oscore_version : uint,
  algorithms : [ alg_aead : int / tstr ],
  request_kid : bstr,
  request_piv : bstr,
  options : bstr,
]

where:

  • oscore_version: contains the OSCORE version number. Implementations of this specification MUST set this field to 1. Other values are reserved for future versions. ๐Ÿ”ข
  • algorithms: contains (for extensibility) an array of algorithms, according to this specification only containing alg_aead. ๐Ÿ“ฆ
  • alg_aead: contains the AEAD Algorithm from the security context used for the exchange (see Section 3.1). ๐Ÿ”
  • request_kid: contains the value of the 'kid' in the COSE object of the request (see Section 5). ๐Ÿ—๏ธ
  • request_piv: contains the value of the 'Partial IV' in the COSE object of the request (see Section 5). ๐Ÿงฉ
  • options: contains the Class I options (see Section 4.1.2) present in the original CoAP message encoded as described in Section 3.1 of [RFC7252], where the delta is the difference from the previously included instance of class I option. ๐ŸŽ€

The oscore_version and algorithms parameters are established out-of-band, so they aren't transported in OSCORE. But the external_aad lets you verify that they're the same on both endpoints. โœจ

NOTE: The format of the external_aad is, for simplicity, the same for requests and responses, although some parameters, e.g., request_kid, need not be integrity protected in all requests. ๐Ÿ™ˆ

The AAD is composed from the external_aad as described in Section 5.3 of [RFC8152] (the notation follows [RFC8610] as summarized in Appendix E):

AAD = Enc_structure = [ "Encrypt0", h'', external_aad ]

The following is an example of AAD constructed using AEAD Algorithm = AES-CCM-16-64-128 (10), request_kid = 0x00, request_piv = 0x25 and no Class I options:

oscore_version: 0x01 (1 byte)
algorithms: 0x810a (2 bytes)
request_kid: 0x00 (1 byte)
request_piv: 0x25 (1 byte)
options: 0x (0 bytes)
aad_array: 0x8501810a4100412540 (9 bytes)
external_aad: 0x498501810a4100412540 (10 bytes)
AAD: 0x8368456e63727970743040498501810a4100412540 (21 bytes)

Note that the AAD consists of a fixed string of 11 bytes concatenated with the external_aad. ๐Ÿง


6. OSCORE Header Compression ๐ŸŒธ

The Concise Binary Object Representation (CBOR) [RFC7049] combines very small message sizes with extensibility. The CBOR Object Signing and Encryption (COSE) [RFC8152] uses CBOR to create compact encoding of signed and encrypted data. However, COSE is built to support a large number of different stateless use cases and isn't fully optimized for use as a stateful security protocol, which leads to a larger than necessary message expansion. ๐Ÿ˜ฉ

So in this section, we define a stateless header compression mechanism. It simply removes redundant information from the COSE objects, which significantly reduces the per-packet overhead. โœ‚๏ธ The result of applying this mechanism to a COSE object is called the "compressed COSE object".

The COSE_Encrypt0 object used in OSCORE is transported in the OSCORE option and in the Payload. The Payload contains the ciphertext of the COSE object. The headers of the COSE object are compactly encoded as described in the next section. ๐ŸŽ

6.1. Encoding of the OSCORE Option Value

The value of the OSCORE option SHALL contain the OSCORE flag bits, the 'Partial IV' parameter, the 'kid context' parameter (length and value), and the 'kid' parameter as follows: ๐Ÿงฉ

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

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

                    Figure 10: The OSCORE Option Value
  • The first byte, containing the OSCORE flag bits, encodes the following set of bits and the length of the 'Partial IV' parameter:
    • The three least significant bits encode the Partial IV length n. If n = 0, then the Partial IV is not present in the compressed COSE object. The values n = 6 and n = 7 are reserved. ๐Ÿ”ข
    • The fourth least significant bit is the 'kid' flag, k. It is set to 1 if 'kid' is present in the compressed COSE object. ๐Ÿท๏ธ
    • The fifth least significant bit is the 'kid context' flag, h. It is set to 1 if the compressed COSE object contains a 'kid context' (see Section 5.1). ๐Ÿ’œ
    • The sixth-to-eighth least significant bits are reserved for future use. These bits SHALL be set to zero when not in use. According to this specification, if any of these bits are set to 1, the message is considered to be malformed and decompression fails as specified in item 2 of Section 8.2. ๐Ÿšซ

The flag bits are registered in the "OSCORE Flag Bits" registry specified in Section 13.7. ๐Ÿ“‹

  • The following n bytes encode the value of the Partial IV, if the Partial IV is present (n > 0).
  • The following 1 byte encodes the length s of the 'kid context' (Section 5.1), if the 'kid context' flag is set (h = 1).
  • The following s bytes encode the 'kid context', if the 'kid context' flag is set (h = 1).
  • The remaining bytes encode the value of the 'kid', if the 'kid' is present (k = 1).

Note that the 'kid' MUST be the last field of the OSCORE option value, even in the case in which reserved bits are used and additional fields are added to it. ๐Ÿ‘‘

The length of the OSCORE option thus depends on the presence and length of Partial IV, 'kid context', 'kid', as specified in this section, and on the presence and length of additional parameters, as defined in the future documents registering those parameters. ๐Ÿฆ‹

6.2. Encoding of the OSCORE Payload

The payload of the OSCORE message SHALL encode the ciphertext of the COSE object. ๐Ÿซถ

6.3. Examples of Compressed COSE Objects

This section covers a list of OSCORE Header Compression examples for requests and responses. โœจ The examples assume the COSE_Encrypt0 object is set (which means the CoAP message and cryptographic material is known). Note that the full CoAP unprotected message, as well as the full security context, is not reported in the examples, but only the input necessary to the compression mechanism, i.e., the COSE_Encrypt0 object. The output is the compressed COSE object as defined in Section 6, divided into two parts, since the object is transported in two CoAP fields: the OSCORE option and payload. ๐Ÿ“

  1. Request with ciphertext = 0xaea0155667924dff8a24e4cb35b9, kid = 0x25, and Partial IV = 0x05

Before compression (24 bytes):

[
  h'',
  { 4:h'25', 6:h'05' },
  h'aea0155667924dff8a24e4cb35b9',
]

After compression (17 bytes):

Flag byte: 0b00001001 = 0x09 (1 byte)

Option Value: 0x090525 (3 bytes)

Payload: 0xaea0155667924dff8a24e4cb35b9 (14 bytes)
  1. Request with ciphertext = 0xaea0155667924dff8a24e4cb35b9, kid = empty string, and Partial IV = 0x00

Before compression (23 bytes):

[
  h'',
  { 4:h'', 6:h'00' },
  h'aea0155667924dff8a24e4cb35b9',
]

After compression (16 bytes):

Flag byte: 0b00001001 = 0x09 (1 byte)

Option Value: 0x0900 (2 bytes)

Payload: 0xaea0155667924dff8a24e4cb35b9 (14 bytes)
  1. Request with ciphertext = 0xaea0155667924dff8a24e4cb35b9, kid = empty string, Partial IV = 0x05, and kid context = 0x44616c656b

Before compression (30 bytes):

[
  h'',
  { 4:h'', 6:h'05', 10:h'44616c656b' },
  h'aea0155667924dff8a24e4cb35b9',
]

After compression (22 bytes):

Flag byte: 0b00011001 = 0x19 (1 byte)

Option Value: 0x19050544616c656b (8 bytes)

Payload: 0xae a0155667924dff8a24e4cb35b9 (14 bytes)
  1. Response with ciphertext = 0xaea0155667924dff8a24e4cb35b9 and no Partial IV

Before compression (18 bytes):

[
  h'',
  {},
  h'aea0155667924dff8a24e4cb35b9',
]

After compression (14 bytes):

Flag byte: 0b00000000 = 0x00 (1 byte)

Option Value: 0x (0 bytes)

Payload: 0xaea0155667924dff8a24e4cb35b9 (14 bytes)
  1. Response with ciphertext = 0xaea0155667924dff8a24e4cb35b9 and Partial IV = 0x07

Before compression (21 bytes):

[
  h'',
  { 6:h'07' },
  h'aea0155667924dff8a24e4cb35b9',
]

After compression (16 bytes):

Flag byte: 0b00000001 = 0x01 (1 byte)

Option Value: 0x0107 (2 bytes)

Payload: 0xaea0155667924dff8a24e4cb35b9 (14 bytes)

7. Message Binding, Sequence Numbers, Freshness, and Replay Protection ๐Ÿฆ‹

7.1. Message Binding

To help prevent response delay and mismatch attacks [CoAP-Actuators] from on-path attackers and compromised intermediaries, OSCORE binds responses to the requests by including the 'kid' and Partial IV of the request in the AAD of the response. ๐Ÿ”— So the server needs to store the 'kid' and Partial IV of the request until all responses have been sent. ๐Ÿง 

7.2. Sequence Numbers

An AEAD nonce MUST NOT be used more than once per AEAD key. The uniqueness of (key, nonce) pairs is shown in Appendix D.4, and in particular depends on a correct usage of Partial IVs (which encode the Sender Sequence Numbers, see Section 5). If messages are processed concurrently, the operation of reading and increasing the Sender Sequence Number MUST be atomic. โšก

7.2.1. Maximum Sequence Number

The maximum Sender Sequence Number is algorithm dependent (see Section 12) and SHALL be less than 2^40. If the Sender Sequence Number exceeds the maximum, the endpoint MUST NOT process any more messages with the given Sender Context. If necessary, the endpoint SHOULD acquire a new security context before this happens. The latter is out of scope of this document. ๐Ÿ”„

7.3. Freshness

For requests, OSCORE provides only the guarantee that the request is not older than the security context. โณ For applications having stronger demands on request freshness (e.g., control of actuators), OSCORE needs to be augmented with mechanisms providing freshness (for example, as specified in [CoAP-ECHO-REQ-TAG]). ๐Ÿค–

Assuming an honest server (see Appendix D), the message binding guarantees that a response is not older than its request. For responses that are not notifications (i.e., when there is a single response to a request), this gives absolute freshness. โœ… For notifications, the absolute freshness gets weaker with time, and it is RECOMMENDED that the client regularly re-register the observation. ๐Ÿ“† Note that the message binding does not guarantee that a misbehaving server created the response before receiving the request, i.e., it does not verify server aliveness. ๐Ÿ‘€

For requests and notifications, OSCORE also provides relative freshness in the sense that the received Partial IV allows a recipient to determine the relative order of requests or responses. ๐Ÿงš

7.4. Replay Protection โœจ

okay so, to stop replayed requests from sneaking through, the server's Recipient Context has a Replay Window ๐Ÿ›ก๏ธ. A server SHALL verify that the Sender Sequence Number it gets in the 'Partial IV' parameter of the COSE object (see Section 6.1) hasn't been received before. If that check fails, the server SHALL stop processing the message, and it MAY optionally respond with a 4.01 (Unauthorized) error message. The server MAY also set an Outer Max-Age option with a value of zero, which tells any intermediary not to cache the response ๐Ÿ™…โ€โ™€๏ธ. The diagnostic payload MAY contain the string Replay detected. The size and type of the Replay Window depends on the use case and on the protocol the OSCORE message travels over ๐Ÿš‚. With reliable, ordered transport from endpoint to endpoint (e.g., TCP), the server MAY just store the last received Partial IV and require that newly received Partial IVs equal the last received Partial IV + 1. But with a mix of reliable and unreliable transports, where messages can get lost, that approach may be too restrictive, and the default replay window may be more suitable (see Section 3.2.2) ๐Ÿคทโ€โ™€๏ธ.

Responses (with or without a Partial IV) are protected against replay because they're bound to the request, and only a single response is accepted ๐Ÿ”’. So in this case the Partial IV isn't used for replay protection of responses.

The operation of validating the Partial IV and updating the replay protection MUST be atomic. No splitting it up, bestie ๐Ÿ’….

7.4.1. Replay Protection of Notifications ๐Ÿ””

This part applies additionally when the Observe option is supported.

The Notification Number (see Section 4.1.3.5.2) is initialized to the Partial IV of the first successfully verified notification in response to the registration request. A client MUST only accept at most one Observe notification without a Partial IV, and treats it as the oldest notification received. A client receiving a notification that contains a Partial IV SHALL compare that Partial IV with the Notification Number associated with that Observe registration. The client MUST stop processing notifications with a Partial IV that has been previously received. Applications MAY decide that a client only processes notifications with a greater Partial IV than the Notification Number ๐ŸŒธ.

If verification of the response succeeds and the received Partial IV was greater than the Notification Number, then the client SHALL overwrite the corresponding Notification Number with the received Partial IV โœจ.

7.5. Losing Part of the Context State ๐Ÿ’”

To prevent reuse of an AEAD nonce with the same AEAD key, or the acceptance of replayed messages, an endpoint has to handle losing the rapidly changing parts of the context, like the Sender Sequence Number and Replay Window. These usually live in RAM, so they get wiped during something like an unplanned reboot ๐Ÿ˜ญ. There are a few ways to recover:

  1. The endpoints can reuse an existing Security Context after updating its mutable parts (Sender Sequence Number and Replay Window). This requires that the mutable parts are available for the device's whole lifetime, or that the device can set up a fresh security context after losing its mutable data. Examples are based on careful use of nonvolatile memory (see Appendix B.1.1) and on the Echo option (see Appendix B.1.2). If an endpoint uses a partial security context stored in nonvolatile memory, it MUST NOT reuse a previous Sender Sequence Number and MUST NOT accept previously received messages ๐Ÿšซ.
  2. The endpoints can reuse an existing shared Master Secret and derive new Sender and Recipient Contexts (see Appendix B.2 for an example). This typically needs a good source of randomness ๐ŸŽฒ.
  3. The endpoints can use a trusted third-party-assisted key establishment protocol, such as [OSCORE-PROFILE]. This means running a three-party protocol and may need a good source of randomness ๐Ÿงš.
  4. The endpoints can run a key exchange protocol that provides forward secrecy, which results in a fresh Master Secret, and an entirely new Security Context is derived from it. This needs a good source of randomness. On top of that, running the protocol may have a non-negligible cost, e.g., in power consumption ๐Ÿ”‹.

The endpoints need to be configured with info about which method is used. The choice of method may depend on the capabilities of the deployed devices and the solution architecture. Using a key exchange protocol is necessary for deployments that require forward secrecy ๐Ÿ‘‘.

8. Processing โš™๏ธ

This section describes the OSCORE message processing. Extra processing for Observe or Block-wise is described in subsections.

Note that, just like [RFC7252], where the Token and source/destination pair are used to match a response with a request, both endpoints MUST keep the association (Token, {Security Context, Partial IV of the request}). That's how they find the Security Context and compute the AAD to protect or verify the response ๐Ÿ”. The association MAY be forgotten after it has been used to successfully protect or verify the response, except for Observe processing, where the association MUST be kept for as long as the Observation is active ๐Ÿ‘€.

The processing of the Sender Sequence Number follows the procedure described in Section 3 of [IV-GEN] ๐Ÿ”ข.

8.1. Protecting the Request ๐ŸŽ€

Given a CoAP request, the client SHALL perform the following steps to create an OSCORE request:

  1. Retrieve the Sender Context associated with the target resource.
  2. Compose the AAD and the plaintext, as described in Sections 5.3 and 5.4.
  3. Encode the Partial IV (Sender Sequence Number in network byte order) and increment the Sender Sequence Number by one. Compute the AEAD nonce from the Sender ID, Common IV, and Partial IV as described in Section 5.2.
  4. Encrypt the COSE object using the Sender Key. Compress the COSE object as specified in Section 6.
  5. Format the OSCORE message according to Section 4. The OSCORE option is added (see Section 4.1.2) ๐Ÿซถ.

8.2. Verifying the Request ๐Ÿ•ต๏ธโ€โ™€๏ธ

A server receiving a request containing the OSCORE option SHALL perform the following steps:

  1. Discard Code and all Class E options (marked in Figure 5 with 'x' in column E) present in the received message. For example, an If-Match Outer option is discarded, but an Uri-Host Outer option is not discarded ๐Ÿ—‘๏ธ.
  2. Decompress the COSE object (Section 6) and retrieve the Recipient Context associated with the Recipient ID in the 'kid' parameter, additionally using the 'kid context', if present. Note that the Recipient Context MAY be retrieved by deriving a new security context, e.g., as described in Appendix B.2. If either the decompression or the COSE message fails to decode, or the server fails to retrieve a Recipient Context with a Recipient ID matching the 'kid' parameter received, then the server SHALL stop processing the request ๐Ÿ›‘.
    • If either the decompression or the COSE message fails to decode, the server MAY respond with a 4.02 (Bad Option) error message. The server MAY set an Outer Max-Age option with a value of zero. The diagnostic payload MAY contain the string Failed to decode COSE.
    • If the server fails to retrieve a Recipient Context with a Recipient ID matching the 'kid' parameter received, the server MAY respond with a 4.01 (Unauthorized) error message. The server MAY set an Outer Max-Age option with a value of zero. The diagnostic payload MAY contain the string Security context not found.
  3. Verify that the Partial IV hasn't been received before, using the Replay Window as described in Section 7.4 ๐Ÿ”.
  4. Compose the AAD, as described in Section 5.4.
  5. Compute the AEAD nonce from the Recipient ID, Common IV, and the Partial IV received in the COSE object.
  6. Decrypt the COSE object using the Recipient Key, as per Section 5.3 of [RFC8152]. (The decrypt operation includes the verification of the integrity ๐Ÿ”.)
    • If decryption fails, the server MUST stop processing the request and MAY respond with a 4.00 (Bad Request) error message. The server MAY set an Outer Max-Age option with a value of zero. The diagnostic payload MAY contain the string Decryption failed.
    • If decryption succeeds, update the Replay Window, as described in Section 7 โœ….
  7. Add the decrypted Code, options, and payload to the decrypted request. The OSCORE option is removed ๐Ÿงน.
  8. The decrypted CoAP request is processed according to [RFC7252] ๐Ÿ’–.

8.2.1. Supporting Block-wise ๐Ÿงฉ

If Block-wise is supported, insert the following step before any other:

A. If Block-wise is present in the request, then process the Outer Block options according to [RFC7959], until all blocks of the request have been received (see Section 4.1.3.4) ๐Ÿ“ฆ.

8.3. Protecting the Response ๐Ÿ’Œ

If a CoAP response is generated in response to an OSCORE request, the server SHALL perform the following steps to create an OSCORE response. Note that CoAP error responses derived from CoAP processing (step 8 in Section 8.2) are protected, just like successful CoAP responses. The OSCORE errors (steps 2, 3, and 6 in Section 8.2) don't follow the processing below. They're sent as simple CoAP responses, without OSCORE processing ๐Ÿ™ˆ.

  1. Retrieve the Sender Context in the Security Context associated with the Token.
  2. Compose the AAD and the plaintext, as described in Sections 5.3 and 5.4.
  3. Compute the AEAD nonce as described in Section 5.2:
    • Either use the AEAD nonce from the request, or
    • Encode the Partial IV (Sender Sequence Number in network byte order) and increment the Sender Sequence Number by one. Compute the AEAD nonce from the Sender ID, Common IV, and Partial IV.
  4. Encrypt the COSE object using the Sender Key. Compress the COSE object as specified in Section 6. If the AEAD nonce was constructed from a new Partial IV, this Partial IV MUST be included in the message. If the AEAD nonce from the request was used, the Partial IV MUST NOT be included in the message ๐Ÿ“.
  5. Format the OSCORE message according to Section 4. The OSCORE option is added (see Section 4.1.2) ๐Ÿฆ‹.

8.3.1. Supporting Observe ๐Ÿ‘€โœจ

okay so if you're supporting Observe, you slot this extra step in between steps 2 and 3 of Section 8.3 ๐ŸŽ€

A. If the response is an Observe notification:

  • If the response is the first notification:
    • compute the AEAD nonce as described in Section 5.2 ๐Ÿ’…:
      • Either use the AEAD nonce from the request, or
      • Encode the Partial IV (Sender Sequence Number in network byte order) and increment the Sender Sequence Number by one. Compute the AEAD nonce from the Sender ID, Common IV, and Partial IV.

Then, go to 4. ๐Ÿซถ

  • If the response is not the first notification:
    • encode the Partial IV (Sender Sequence Number in network byte order) and increment the Sender Sequence Number by one. Compute the AEAD nonce from the Sender ID, Common IV, and Partial IV, then go to 4. ๐Ÿ’œ

8.4. Verifying the Response ๐Ÿ”

a client receiving a response containing the OSCORE option SHALL perform the following steps, no cap ๐Ÿ’–

  1. Discard Code and all Class E options (marked in Figure 5 with 'x' in column E) present in the received message. For example, ETag Outer option is discarded, as well as Max-Age Outer option. ๐Ÿงน
  2. Retrieve the Recipient Context in the Security Context associated with the Token. Decompress the COSE object (Section 6). If either the decompression or the COSE message fails to decode, then go to 8. ๐Ÿ™ˆ
  3. Compose the AAD, as described in Section 5.4.
  4. Compute the AEAD nonce:
    • If the Partial IV is not present in the response, the AEAD nonce from the request is used.
    • If the Partial IV is present in the response, compute the AEAD nonce from the Recipient ID, Common IV, and the Partial IV, received in the COSE object. โœจ
  5. Decrypt the COSE object using the Recipient Key, as per Section 5.3 of [RFC8152]. (The decrypt operation includes the verification of the integrity.) If decryption fails, then go to 8. ๐Ÿ”
  6. Add decrypted Code, options and payload to the decrypted request. The OSCORE option is removed. ๐ŸŽ€
  7. The decrypted CoAP response is processed according to [RFC7252]. ๐ŸŒธ
  8. In case any of the previous erroneous conditions apply: the client SHALL stop processing the response. ๐Ÿ›‘

8.4.1. Supporting Block-wise ๐Ÿงฉ

If Block-wise is supported, insert the following step before any other:

A. If Block-wise is present in the response, then process the Outer Block options according to [RFC7959], until all blocks of the response have been received (see Section 4.1.3.4). ๐Ÿ“ฆ


8.4.2. Supporting Observe ๐Ÿ‘€๐Ÿ’…

If Observe is supported:

Insert the following step between step 5 and step 6:

A. If the request was an Observe registration, then:

  • If the Partial IV is not present in the response, and the Inner Observe option is present, and the AEAD nonce from the request was already used once, then go to 8. ๐Ÿ™…โ€โ™€๏ธ
  • If the Partial IV is present in the response and the Inner Observe option is present, then follow the processing described in Section 4.1.3.5.2 and Section 7.4.1, then:
    • initialize the Notification Number (if first successfully verified notification), or
    • overwrite the Notification Number (if the received Partial IV was greater than the Notification Number). ๐Ÿ”ฅ

Replace step 8 of Section 8.4 with:

B. In case any of the previous erroneous conditions apply: the client SHALL stop processing the response. An error condition occurring while processing a response to an observation request does not cancel the observation. A client MUST NOT react to failure by re-registering the observation immediately. ๐Ÿ™ƒ bestie, the observation is still alive even if one response goes sideways ๐Ÿฆ‹


9. Web Linking ๐Ÿ”—๐ŸŒˆ

The use of OSCORE MAY be indicated by a target "osc" attribute in a web link [RFC8288] to a resource, e.g., using a link-format document [RFC6690] if the resource is accessible over CoAP. โœจ

The "osc" attribute is a hint indicating that the destination of that link is only accessible using OSCORE, and unprotected access to it is not supported. Note that this is simply a hint, it does not include any security context material or any other information required to run OSCORE. ๐Ÿซฃ

A value MUST NOT be given for the "osc" attribute; any present value MUST be ignored by parsers. The "osc" attribute MUST NOT appear more than once in a given link-value; occurrences after the first MUST be ignored by parsers. ๐Ÿ’…

The example in Figure 11 shows a use of the "osc" attribute: the client does resource discovery on a server and gets back a list of resources, one of which includes the "osc" attribute indicating that the resource is protected with OSCORE. The link-format notation (see Section 5 of [RFC6690]) is used. ๐Ÿงš

                  REQ: GET /.well-known/core

                  RES: 2.05 Content
                     </sensors/temp>;osc,
                     </sensors/light>;if="sensor"

                      Figure 11: The Web Link

10. CoAP-to-CoAP Forwarding Proxy ๐Ÿšš

CoAP is designed for proxy operations (see Section 5.7 of [RFC7252]). ๐Ÿ“

OSCORE is designed to work with OSCORE-unaware CoAP proxies. Security requirements for forwarding are listed in Section 2.2.1 of [CoAP-E2E-Sec]. Proxy processing of the (Outer) Proxy-Uri option works as defined in [RFC7252]. Proxy processing of the (Outer) Block options works as defined in [RFC7959]. ๐Ÿซถ

However, not all CoAP proxy operations are useful:

  • Since a CoAP response is only applicable to the original CoAP request, caching is in general not useful. In support of existing proxies, OSCORE uses the Outer Max-Age option, see Section 4.1.3.1. ๐Ÿ™„
  • Proxy processing of the (Outer) Observe option as defined in [RFC7641] is specified in Section 4.1.3.5.

Optionally, a CoAP proxy MAY detect OSCORE and act accordingly. An OSCORE-aware CoAP proxy:

  • SHALL bypass caching for the request if the OSCORE option is present.
  • SHOULD avoid caching responses to requests with an OSCORE option. ๐Ÿ™ˆ

In the case of Observe (see Section 4.1.3.5), the OSCORE-aware CoAP proxy:

  • SHALL NOT initiate an Observe registration.
  • MAY verify the order of notifications using Partial IV rather than the Observe option. ๐Ÿ‘‘

11. HTTP Operations ๐ŸŒ๐Ÿ’–

The CoAP request/response model may be mapped to HTTP and vice versa as described in Section 10 of [RFC7252]. The HTTP-CoAP mapping is further detailed in [RFC8075]. This section defines the components needed to map and transport OSCORE messages over HTTP hops. By mapping between HTTP and CoAP and by using cross-protocol proxies, OSCORE may be used end-to-end between, e.g., an HTTP client and a CoAP server. Examples are provided in Sections 11.5 and 11.6. ๐Ÿฆ‹


11.1. The HTTP OSCORE Header Field ๐Ÿท๏ธ

The HTTP OSCORE header field (see Section 13.4) is used for carrying the content of the CoAP OSCORE option when transporting OSCORE messages over HTTP hops. ๐ŸŽ€

The HTTP OSCORE header field is only used in POST requests and responses with HTTP Status Code 200 (OK). When used, the HTTP header field Content-Type is set to 'application/oscore' (see Section 13.5) indicating that the HTTP body of this message contains the OSCORE payload (see Section 6.2). No additional semantics are provided by other message fields. ๐Ÿ’…

Using the Augmented Backus-Naur Form (ABNF) notation of [RFC5234], including the following core ABNF syntax rules defined by that specification: ALPHA (letters) and DIGIT (decimal digits), the HTTP OSCORE header field value is as follows.

base64url-char = ALPHA / DIGIT / "-" / "_"

OSCORE = 2*base64url-char

The HTTP OSCORE header field is not appropriate to list in the Connection header field (see Section 6.1 of [RFC7230]) since it is not hop-by-hop. OSCORE messages are generally not useful when served from cache (i.e., they will generally be marked Cache-Control: no-cache) and so interaction with Vary is not relevant (Section 7.1.4 of [RFC7231]). Since the HTTP OSCORE header field is critical for message processing, moving it from headers to trailers renders the message unusable in case trailers are ignored (see Section 4.1 of [RFC7230]). ๐Ÿšซ

In general, intermediaries are not allowed to insert, delete, or modify the OSCORE header. In general, changes to the HTTP OSCORE header field will violate the integrity of the OSCORE message resulting in an error. For the same reason the HTTP OSCORE header field is generally not preserved across redirects. ๐Ÿ”’

Since redirects are not defined in the mappings between HTTP and CoAP ([RFC8075] [RFC7252]), a number of conditions need to be fulfilled for redirects to work. For CoAP-client-to-HTTP-server redirects, such conditions include:

  • the CoAP-to-HTTP proxy follows the redirect, instead of the CoAP client as in the HTTP case.
  • the CoAP-to-HTTP proxy copies the HTTP OSCORE header field and body to the new request.
  • the target of the redirect has the necessary OSCORE security context required to decrypt and verify the message.

Since OSCORE requires the HTTP body to be preserved across redirects, the HTTP server is RECOMMENDED to reply with 307 (Temporary Redirect) or 308 (Permanent Redirect) instead of 301 (Moved Permanently) or 302 (Found). ๐ŸŒธ

For the case of HTTP-client-to-CoAP-server redirects, although redirect is not defined for CoAP servers [RFC7252], an HTTP client receiving a redirect should generate a new OSCORE request for the server it was redirected to. ๐Ÿงญ


11.2. CoAP-to-HTTP Mapping ๐Ÿ”

Section 10.1 of [RFC7252] describes the fundamentals of the CoAP-to-HTTP cross-protocol mapping process. The additional rules for OSCORE messages are as follows:

  • The HTTP OSCORE header field value is set to:
    • AA if the CoAP OSCORE option is empty; otherwise,
    • the value of the CoAP OSCORE option (Section 6.1) in base64url (Section 5 of [RFC4648]) encoding without padding. Implementation notes for this encoding are given in Appendix C of [RFC7515]. โœจ
  • The HTTP Content-Type is set to 'application/oscore' (see Section 13.5), independent of CoAP Content-Format. ๐Ÿ’œ

11.3. HTTP-to-CoAP Mapping ๐Ÿ”„

Section 10.2 of [RFC7252] and [RFC8075] specify the behavior of an HTTP-to-CoAP proxy. The additional rules for HTTP messages with the OSCORE header field are as follows.

  • The CoAP OSCORE option is set as follows:
    • empty if the value of the HTTP OSCORE header field is a single zero byte (0x00) represented by AA; otherwise,
    • the value of the HTTP OSCORE header field decoded from base64url (Section 5 of [RFC4648]) without padding. Implementation notes for this encoding are given in Appendix C of [RFC7515].
  • The CoAP Content-Format option is omitted, the content format for OSCORE (Section 13.6) MUST NOT be used. ๐Ÿ™…โ€โ™€๏ธ

11.4. HTTP Endpoints ๐Ÿ

Restricted to subsets of HTTP and CoAP supporting a bijective mapping, OSCORE can be originated or terminated in HTTP endpoints. ๐ŸŽฏ

The sending HTTP endpoint uses [RFC8075] to translate the HTTP message into a CoAP message. The CoAP message is then processed with OSCORE as defined in this document. The OSCORE message is then mapped to HTTP as described in Section 11.2 and sent in compliance with the rules in Section 11.1. ๐Ÿ“ค

The receiving HTTP endpoint maps the HTTP message to a CoAP message using [RFC8075] and Section 11.3. The resulting OSCORE message is processed as defined in this document. If successful, the plaintext CoAP message is translated to HTTP for normal processing in the endpoint. ๐Ÿ“ฅ๐Ÿ’–

11.5. Example: HTTP Client and CoAP Server ๐ŸŽ€

okay so this bit shows what a request and response between an HTTP client and a CoAP server could look like ๐Ÿ’– It's not a test vector, just an illustration of how the message fields get translated at each step โœจ

Mapping and notation here is based on "Simple Form" (Section 5.4.1 of [RFC8075]) ๐ŸŒธ

[HTTP request -- Before client object security processing]

  GET http://proxy.url/hc/?target_uri=coap://server.url/orders
   HTTP/1.1

[HTTP request -- HTTP Client to Proxy]

  POST http://proxy.url/hc/?target_uri=coap://server.url/ HTTP/1.1
  Content-Type: application/oscore
  OSCORE: CSU
  Body: 09 07 01 13 61 f7 0f d2 97 b1 [binary]

[CoAP request -- Proxy to CoAP Server]

  POST coap://server.url/
  OSCORE: 09 25
  Payload: 09 07 01 13 61 f7 0f d2 97 b1 [binary]

[CoAP request -- After server object security processing]

  GET coap://server.url/orders

[CoAP response -- Before server object security processing]

  2.05 Content
  Content-Format: 0
  Payload: Exterminate! Exterminate!

[CoAP response -- CoAP Server to Proxy]

  2.04 Changed
  OSCORE: [empty]
  Payload: 00 31 d1 fc f6 70 fb 0c 1d d5 ... [binary]

[HTTP response -- Proxy to HTTP Client]

  HTTP/1.1 200 OK
  Content-Type: application/oscore
  OSCORE: AA
  Body: 00 31 d1 fc f6 70 fb 0c 1d d5 ... [binary]

[HTTP response -- After client object security processing]

  HTTP/1.1 200 OK
  Content-Type: text/plain
  Body: Exterminate! Exterminate!

Note that the HTTP Status Code 200 (OK) in the next-to-last message is the mapping of CoAP Code 2.04 (Changed) ๐Ÿ”„ whereas the HTTP Status Code 200 (OK) in the last message is the mapping of the CoAP Code 2.05 (Content). That one was encrypted within the compressed COSE object carried in the Body of the HTTP response ๐Ÿคฏ main character energy for that COSE object, honestly ๐Ÿงš

11.6. Example: CoAP Client and HTTP Server ๐Ÿฆ‹

this one flips it around and shows what a request and response between a CoAP client and an HTTP server could look like ๐Ÿ’… Same deal: not a test vector, just an illustration of how the fields get translated in each step ๐ŸŒˆ

[CoAP request -- Before client object security processing]

  GET coap://proxy.url/
  Proxy-Uri=http://server.url/orders

[CoAP request -- CoAP Client to Proxy]

  POST coap://proxy.url/
  Proxy-Uri=http://server.url/
  OSCORE: 09 25
  Payload: 09 07 01 13 61 f7 0f d2 97 b1 [binary]

[HTTP request -- Proxy to HTTP Server]

  POST http://server.url/ HTTP/1.1
  Content-Type: application/oscore
  OSCORE: CSU
  Body: 09 07 01 13 61 f7 0f d2 97 b1 [binary]

[HTTP request -- After server object security processing]

  GET http://server.url/orders HTTP/1.1

[HTTP response -- Before server object security processing]

  HTTP/1.1 200 OK
  Content-Type: text/plain
  Body: Exterminate! Exterminate!

[HTTP response -- HTTP Server to Proxy]

  HTTP/1.1 200 OK
  Content-Type: application/oscore
  OSCORE: AA
  Body: 00 31 d1 fc f6 70 fb 0c 1d d5 ... [binary]

[CoAP response -- Proxy to CoAP Client]

  2.04 Changed
  OSCORE: [empty]
  Payload: 00 31 d1 fc f6 70 fb 0c 1d d5 ... [binary]

[CoAP response -- After client object security processing]

  2.05 Content
  Content-Format: 0
  Payload: Exterminate! Exterminate!

Note that the HTTP Code 2.04 (Changed) in the next-to-last message is the mapping of HTTP Status Code 200 (OK) ๐ŸŒท whereas the CoAP Code 2.05 (Content) in the last message is the value that was encrypted within the compressed COSE object carried in the Body of the HTTP response ๐Ÿ’œ


12. Security Considerations โœจ

okay this section is where things get serious, so buckle up ๐Ÿซถ An overview of the security properties is given in Appendix D.

12.1. End-to-end Protection ๐Ÿ”

so in setups with intermediary nodes like proxies or gateways, transport layer security such as (D)TLS only protects data hop-by-hop ๐Ÿ˜ฌ That means the intermediary nodes can read and modify any information. Trusting every intermediary is problematic, not just for privacy but for security too, because they're free to delete resources on sensors and falsify commands to actuators (like "unlock door", "start fire alarm", "raise bridge") ๐Ÿ’€ Even in the rare case where every owner of an intermediary node is fully trusted, attacks and data breaches make that kind of architecture brittle ๐Ÿฅ€

(D)TLS protects hop-by-hop the entire message. OSCORE protects end-to-end all information that is not required for proxy operations (see Section 4).

(D)TLS and OSCORE can be combined ๐Ÿฆ‹ which gives you end-to-end security of the message payload, plus hop-by-hop protection of the entire message during transport between endpoint and intermediary node. In particular, when OSCORE is used with HTTP, the additional TLS protection of HTTP hops is RECOMMENDED, e.g., between an HTTP endpoint and a proxy translating between HTTP and CoAP ๐Ÿ”’

Applications need to consider that certain message fields and message types are not protected end-to-end and may be spoofed or manipulated. The consequences of unprotected message fields are analyzed in Appendix D.5 โš ๏ธ

12.2. Security Context Establishment ๐Ÿ—๏ธ

using COSE_Encrypt0 and AEAD to protect messages the way this document specifies requires an established security context, bestie ๐Ÿ’… The method to establish one, described in Section 3.2, is based on a common Master Secret and unique Sender IDs. The necessary input parameters may be preestablished or obtained using a key establishment protocol augmented with establishment of Sender/Recipient ID, such as a key exchange protocol or the OSCORE profile of the Authentication and Authorization for Constrained Environments (ACE) framework [OSCORE-PROFILE]. Such a procedure must ensure that the requirements of the security context parameters for the intended use are complied with (see Section 3.3) even in error situations.

While recipient IDs are allowed to coincide between different security contexts (see Section 3.3), this may cause a server to process multiple verifications before finding the right security context or rejecting a message ๐Ÿ™ˆ Considerations for deploying OSCORE with a fixed Master Secret are given in Appendix B.

12.3. Master Secret ๐Ÿ”‘

OSCORE uses HKDF [RFC5869] and the established input parameters to derive the security context. The required properties of the security context parameters are discussed in Section 3.3, and here we focus on the Master Secret ๐ŸŽ€ In this specification, HKDF denotes the composition of the expand and extract functions as defined in [RFC5869], and the Master Secret is used as Input Keying Material (IKM).

Informally, HKDF takes as source an IKM containing some good amount of randomness, but not necessarily distributed uniformly (or for which an attacker has some partial knowledge), and derives from it one or more cryptographically strong secret keys [RFC5869] โœจ

So the main requirement for the OSCORE Master Secret is that it be secret and have a good amount of randomness ๐Ÿง‚ The selected key establishment schemes must ensure that the necessary properties for the Master Secret are fulfilled. For pre-shared key deployments and key transport solutions such as [OSCORE-PROFILE], the Master Secret can be generated offline using a good random number generator. Randomness requirements for security are described in [RFC4086] ๐ŸŽฒ

12.4. Replay Protection ๐Ÿ”

replay attacks need to be considered in different parts of the implementation, so keep your eyes open ๐Ÿ‘€ Most AEAD algorithms require a unique nonce for each message, and the Sender Sequence Numbers in the COSE message field 'Partial IV' are used for that. If the recipient accepts any sequence number larger than the one previously received, then the problem of sequence number synchronization is avoided. With reliable transport, it may be defined that only messages with sequence numbers equal to the previous sequence number + 1 are accepted. An adversary may try to induce a device reboot for the purpose of replaying a message (see Section 7.5) ๐Ÿ˜ค

Note that sharing a security context between servers may open up for replay attacks, for example, if the Replay Windows are not synchronized โณ

12.5. Client Aliveness ๐Ÿซง

a verified OSCORE request lets the server verify the identity of the entity who generated the message. However, it does not verify that the client is currently involved in the communication, since the message may be a delayed delivery of a previously generated request that now reaches the server ๐Ÿ•ฐ๏ธ To verify the aliveness of the client, the server may use the Echo option in the response to a request from the client (see [CoAP-ECHO-REQ-TAG]) ๐Ÿ’–

12.6. Cryptographic Considerations ๐Ÿงฎ

the maximum Sender Sequence Number depends on the AEAD algorithm. It is 2^40 - 1, or any algorithm-specific lower limit, and after that a new security context must be generated ๐Ÿ”„ The mechanism to build the AEAD nonce (Section 5.2) assumes that the nonce is at least 56 bits and the Partial IV is at most 40 bits. The mandatory-to-implement AEAD algorithm AES-CCM-16-64-128 is selected for compatibility with CCM*. AEAD algorithms that require unpredictable nonces are not supported ๐Ÿ™…

To prevent cryptanalysis when the same plaintext is repeatedly encrypted by many different users with distinct AEAD keys, the AEAD nonce is formed by mixing the sequence number with a secret per-context initialization vector (Common IV). That IV is derived along with the keys (see Section 3.1 of [RFC8152]), and a Master Salt is used in the key derivation (see [MF00] for an overview) ๐Ÿง The Master Secret, Sender Key, Recipient Key, and Common IV must be secret, and the rest of the parameters may be public. The Master Secret must have a good amount of randomness (see Section 12.3) ๐ŸŒŸ

The ID Context, Sender ID, and Partial IV are always at least implicitly integrity protected, because manipulating them leads to the wrong nonce or key being used, which results in decryption failure ๐Ÿ›ก๏ธ

12.7. Message Segmentation ๐Ÿงฉ

the Inner Block options let the sender split large messages into OSCORE-protected blocks, so the receiving endpoint can verify blocks before it has received the complete message ๐Ÿฅฐ The Outer Block options allow for arbitrary proxy fragmentation operations that cannot be verified by the endpoints, but by policy they can be restricted in size, since the Inner Block options already allow for secure fragmentation of very large messages. A maximum message size (above which the sending endpoint fragments the message and the receiving endpoint discards the message, if complying with the policy) may be obtained as part of normal resource discovery ๐Ÿ“

12.8. Privacy Considerations ๐Ÿฆ‹

okay so privacy threats that happen through intermediary nodes get WAY smaller with OSCORE ๐Ÿ”’โœจ End-to-end integrity protection plus encryption of the message payload and of every option that isn't used for proxy operations means attacks on sensor and actuator communication are much harder to pull off. That matters a lot because those devices can have a direct impact on someone's personal sphere ๐Ÿซถ

The unprotected options (Figure 5) can still leak privacy-sensitive info, see Appendix D.5 ๐Ÿ’€ CoAP headers that get sent in plaintext let someone do things like match a CON with its ACK (that's the CoAP Message Identifier), match requests with responses (that's the Token), and do traffic analysis ๐Ÿ™ˆ OSCORE doesn't protect HTTP header fields that are not both CoAP-mappable and Class E. The HTTP message fields that on-path entities can see are only there to carry the OSCORE message around. The actual application-layer message is encoded in CoAP and encrypted, so it's hidden ๐Ÿ”

The COSE message fields, aka the OSCORE option, can reveal stuff about the communicating endpoints ๐Ÿ‘€ For example, 'kid' and 'kid context' are meant to help the server find the right context, but they can end up revealing info about the client. And tracking 'kid' and 'kid context' to one server can be used to correlate requests from one client ๐Ÿ•ต๏ธโ€โ™€๏ธ

Unprotected error messages reveal info about the security state of the communication between the endpoints ๐Ÿ˜ญ Unprotected signaling messages reveal info about the reliable transport used on a leg of the path. Using the mechanisms described in Section 7.5 may reveal when a device goes through a reboot. This can be mitigated if the device stores the precise state of the Sender Sequence Number and Replay Window on a clean shutdown ๐Ÿ’œ

The length of message fields can reveal info about the message too ๐Ÿ“ Applications may use a padding scheme to protect against traffic analysis ๐ŸŽ€


13. IANA Considerations ๐ŸŒธ

13.1. COSE Header Parameters Registry

The 'kid context' parameter has been added to the "COSE Header Parameters" registry ๐Ÿ“

  • Name: kid context
  • Label: 10
  • Value Type: bstr
  • Value Registry: (empty)
  • Description: Identifies the context for the key identifier
  • Reference: Section 5.1 of this document

13.2. CoAP Option Numbers Registry

The OSCORE option has been added to the "CoAP Option Numbers" registry ๐Ÿงš

+--------+-----------------+-------------------+
| Number | Name            | Reference         |
+--------+-----------------+-------------------+
|     9  | OSCORE          | [RFC8613]         |
+--------+-----------------+-------------------+

Furthermore, the following existing entries in the "CoAP Option Numbers" registry have been updated with a reference to the document specifying OSCORE processing of that option ๐Ÿ’…

+--------+-----------------+-------------------------------+
| Number | Name            |          Reference            |
+--------+-----------------+-------------------------------+
|   1    | If-Match        | [RFC7252] [RFC8613]           |
|   3    | Uri-Host        | [RFC7252] [RFC8613]           |
|   4    | ETag            | [RFC7252] [RFC8613]           |
|   5    | If-None-Match   | [RFC7252] [RFC8613]           |
|   6    | Observe         | [RFC7641] [RFC8613]           |
|   7    | Uri-Port        | [RFC7252] [RFC8613]           |
|   8    | Location-Path   | [RFC7252] [RFC8613]           |
|  11    | Uri-Path        | [RFC7252] [RFC8613]           |
|  12    | Content-Format  | [RFC7252] [RFC8613]           |
|  14    | Max-Age         | [RFC7252] [RFC8613]           |
|  15    | Uri-Query       | [RFC7252] [RFC8613]           |
|  17    | Accept          | [RFC7252] [RFC8613]           |
|  20    | Location-Query  | [RFC7252] [RFC8613]           |
|  23    | Block2          | [RFC7959] [RFC8323] [RFC8613] |
|  27    | Block1          | [RFC7959] [RFC8323] [RFC8613] |
|  28    | Size2           | [RFC7959] [RFC8613]           |
|  35    | Proxy-Uri       | [RFC7252] [RFC8613]           |
|  39    | Proxy-Scheme    | [RFC7252] [RFC8613]           |
|  60    | Size1           | [RFC7252] [RFC8613]           |
| 258    | No-Response     | [RFC7967] [RFC8613]           |
+--------+-----------------+-------------------------------+

Future additions to the "CoAP Option Numbers" registry need to provide a reference to the document where the OSCORE processing of that CoAP Option is defined ๐Ÿ“

13.3. CoAP Signaling Option Numbers Registry

The OSCORE option has been added to the "CoAP Signaling Option Numbers" registry ๐ŸŒˆ

+------------+--------+---------------------+-------------------+
| Applies to | Number | Name                | Reference         |
+------------+--------+---------------------+-------------------+
| 7.xx (all) |     9  | OSCORE              | [RFC8613]         |
+------------+--------+---------------------+-------------------+

13.4. Header Field Registrations

The HTTP OSCORE header field has been added to the "Message Headers" registry โœจ

+-------------------+----------+----------+---------------------+
| Header Field Name | Protocol | Status   | Reference           |
+-------------------+----------+----------+---------------------+
| OSCORE            | http     | standard | [RFC8613],          |
|                   |          |          | Section 11.1        |
+-------------------+----------+----------+---------------------+

13.5. Media Type Registration

This section registers the 'application/oscore' media type in the "Media Types" registry ๐ŸŽ€ This media type is used to indicate that the content is an OSCORE message. The OSCORE body cannot be understood without the OSCORE header field value and the security context ๐Ÿ”‘

Type name: application

Subtype name: oscore

Required parameters: N/A

Optional parameters: N/A

Encoding considerations: binary

Security considerations: See the Security Considerations section
   of [RFC8613].

Interoperability considerations: N/A

Published specification: [RFC8613]

Applications that use this media type: IoT applications sending
   security content over HTTP(S) transports.

Fragment identifier considerations: N/A

Additional information:

*  Deprecated alias names for this type: N/A
*  Magic number(s): N/A
*  File extension(s): N/A
*  Macintosh file type code(s): N/A
Person & email address to contact for further information:
   IESG <iesg@ietf.org>

Intended usage: COMMON

Restrictions on usage: N/A

Author: Goeran Selander <goran.selander@ericsson.com>

Change Controller: IESG

Provisional registration?  No

13.6. CoAP Content-Formats Registry

This section registers the media type 'application/oscore' media type in the "CoAP Content-Formats" registry ๐Ÿง This Content-Format for the OSCORE payload is defined for potential future use cases and SHALL NOT be used in the OSCORE message. The OSCORE payload cannot be understood without the OSCORE option value and the security context ๐Ÿšซ

+----------------------+----------+----------+-------------------+
| Media Type           | Encoding |   ID     |     Reference     |
+----------------------+----------+----------+-------------------+
| application/oscore   |          |  10001   | [RFC8613]         |
+----------------------+----------+----------+-------------------+

13.7. OSCORE Flag Bits Registry

This document defines a subregistry for the OSCORE flag bits within the "CoRE Parameters" registry ๐ŸŒธ The name of the subregistry is "OSCORE Flag Bits". The registry has been created with the Expert Review policy [RFC8126]. Guidelines for the experts are provided in Section 13.8 ๐Ÿ’œ

The columns of the registry are as follows:

  • Bit Position: This indicates the position of the bit in the set of OSCORE flag bits, starting at 0 for the most significant bit. The bit position must be an integer or a range of integers, in the range 0 to 63.
  • Name: The name is present to make it easier to refer to and discuss the registration entry. The value is not used in the protocol. Names are to be unique in the table.
  • Description: This contains a brief description of the use of the bit.
  • Reference: This contains a pointer to the specification defining the entry.

The initial contents of the registry are in the table below. The reference column for all rows is this document. The entries with Bit Position of 0 and 1 are marked as 'Reserved'. The entry with Bit Position of 1 will be specified in a future document and will be used to expand the space for the OSCORE flag bits in Section 6.1, so that entries 8-63 of the registry are defined ๐Ÿ”ฅ

+--------------+-------------+-----------------------------+-----------+
| Bit Position | Name        | Description                 | Reference |
+--------------+-------------+-----------------------------+-----------+
|       0      | Reserved    |                             |           |
+--------------+-------------+-----------------------------+-----------+
|       1      | Reserved    |                             |           |
+--------------+-------------+-----------------------------+-----------+
|       2      | Unassigned  |                             |           |
+--------------+-------------+-----------------------------+-----------+
|       3      | Kid Context | Set to 1 if kid context     | [RFC8613] |
|              | Flag        | is present in the           |           |
|              |             | compressed COSE object      |           |
+--------------+-------------+-----------------------------+-----------+
|       4      | Kid Flag    | Set to 1 if kid is present  | [RFC8613] |
|              |             | in the compressed COSE      |           |
|              |             | object                      |           |
+--------------+-------------+-----------------------------+-----------+
|     5-7      | Partial IV  | Encodes the Partial IV      | [RFC8613] |
|              | Length      | length; can have value      |           |
|              |             | 0 to 5                      |           |
+--------------+-------------+-----------------------------+-----------+
|    8-63      | Unassigned  |                             |           |
+--------------+-------------+-----------------------------+-----------+

13.8. Expert Review Instructions

The expert reviewers for the registry defined in this document are expected to ensure that the usage solves a valid use case that could not be solved better in a different way, that it is not going to duplicate one that is already registered, and that the registered point is likely to be used in deployments ๐Ÿ•ต๏ธโ€โ™€๏ธ They are furthermore expected to check the clarity of purpose and use of the requested code points. Experts should take into account the expected usage of entries when approving point assignment, and the length of the encoded value should be weighed against the number of code points left that encode to that size and the size of device it will be used on. Experts should block registration for entries 8-63 until these points are defined (i.e., until the mechanism for the OSCORE flag bits expansion via bit 1 is specified) ๐Ÿšฆ

14. References โœจ

14.1. Normative References ๐Ÿ“š

okay so these are the docs you literally can't skip if you want to implement this stuff ๐Ÿ’… they're the foundation everything else is built on, so bookmark them bestie ๐Ÿ”–

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

   [RFC4086]  Eastlake 3rd, D., Schiller, J., and S. Crocker,
              "Randomness Requirements for Security", BCP 106, RFC 4086,
              DOI 10.17487/RFC4086, June 2005,
              <https://www.rfc-editor.org/info/rfc4086>.

   [RFC4648]  Josefsson, S., "The Base16, Base32, and Base64 Data
              Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
              <https://www.rfc-editor.org/info/rfc4648>.

   [RFC5234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
              Specifications: ABNF", STD 68, RFC 5234,
              DOI 10.17487/RFC5234, January 2008,
              <https://www.rfc-editor.org/info/rfc5234>.

   [RFC6347]  Rescorla, E. and N. Modadugu, "Datagram Transport Layer
              Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347,
              January 2012, <https://www.rfc-editor.org/info/rfc6347>.

   [RFC7049]  Bormann, C. and P. Hoffman, "Concise Binary Object
              Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049,
              October 2013, <https://www.rfc-editor.org/info/rfc7049>.

   [RFC7230]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
              Protocol (HTTP/1.1): Message Syntax and Routing",
              RFC 7230, DOI 10.17487/RFC7230, June 2014,
              <https://www.rfc-editor.org/info/rfc7230>.

   [RFC7231]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
              Protocol (HTTP/1.1): Semantics and Content", RFC 7231,
              DOI 10.17487/RFC7231, June 2014,
              <https://www.rfc-editor.org/info/rfc7231>.

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

   [RFC8075]  Castellani, A., Loreto, S., Rahman, A., Fossati, T., and
              E. Dijk, "Guidelines for Mapping Implementations: HTTP to
              the Constrained Application Protocol (CoAP)", RFC 8075,
              DOI 10.17487/RFC8075, February 2017,
              <https://www.rfc-editor.org/info/rfc8075>.

   [RFC8132]  van der Stok, P., Bormann, C., and A. Sehgal, "PATCH and
              FETCH Methods for the Constrained Application Protocol
              (CoAP)", RFC 8132, DOI 10.17487/RFC8132, April 2017,
              <https://www.rfc-editor.org/info/rfc8132>.

   [RFC8152]  Schaad, J., "CBOR Object Signing and Encryption (COSE)",
              RFC 8152, DOI 10.17487/RFC8152, July 2017,
              <https://www.rfc-editor.org/info/rfc8152>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

   [RFC8288]  Nottingham, M., "Web Linking", RFC 8288,
              DOI 10.17487/RFC8288, October 2017,
              <https://www.rfc-editor.org/info/rfc8288>.

   [RFC8323]  Bormann, C., Lemay, S., Tschofenig, H., Hartke, K.,
              Silverajan, B., and B. Raymor, Ed., "CoAP (Constrained
              Application Protocol) over TCP, TLS, and WebSockets",
              RFC 8323, DOI 10.17487/RFC8323, February 2018,
              <https://www.rfc-editor.org/info/rfc8323>.

   [RFC8446]  Rescorla, E., "The Transport Layer Security (TLS) Protocol
              Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
              <https://www.rfc-editor.org/info/rfc8446>.

   [RFC8610]  Birkholz, H., Vigano, C., and C. Bormann, "Concise Data
              Definition Language (CDDL): A Notational Convention to
              Express Concise Binary Object Representation (CBOR) and
              JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610,
              June 2019, <https://www.rfc-editor.org/info/rfc8610>.

14.2. Informative References ๐Ÿฆ‹

these are the extra-credit reads ๐ŸŒธ background info, drafts that are still cooking, and other fun stuff that's not required but absolutely iconic to know about ๐Ÿงš some of these are still "Work in Progress" drafts, so they might change, ngl ๐Ÿ™ˆ

   [ACE-OAuth]
              Seitz, L., Selander, G., Wahlstroem, E., Erdtman, S., and
              H. Tschofenig, "Authentication and Authorization for
              Constrained Environments (ACE) using the OAuth 2.0
              Framework (ACE-OAuth)", Work in Progress, draft-ietf-ace-
              oauth-authz-24, March 2019.

   [CoAP-802.15.4]
              Bormann, C., "Constrained Application Protocol (CoAP) over
              IEEE 802.15.4 Information Element for IETF", Work in
              Progress, draft-bormann-6lo-coap-802-15-ie-00, April 2016.

   [CoAP-Actuators]
              Mattsson, J., Fornehed, J., Selander, G., Palombini, F.,
              and C. Amsuess, "Controlling Actuators with CoAP", Work in
              Progress, draft-mattsson-core-coap-actuators-06, September
              2018.

   [CoAP-E2E-Sec]
              Selander, G., Palombini, F., and K. Hartke, "Requirements
              for CoAP End-To-End Security", Work in Progress, draft-
              hartke-core-e2e-security-reqs-03, July 2017.

   [CoAP-ECHO-REQ-TAG]
              Amsuess, C., Mattsson, J., and G. Selander, "CoAP: Echo,
              Request-Tag, and Token Processing", Work in Progress,
              draft-ietf-core-echo-request-tag-04, March 2019.

   [Group-OSCORE]
              Tiloca, M., Selander, G., Palombini, F., and J. Park,
              "Group OSCORE - Secure Group Communication for CoAP", Work
              in Progress, draft-ietf-core-oscore-groupcomm-04, March
              2019.

   [IV-GEN]   McGrew, D., "Generation of Deterministic Initialization
              Vectors (IVs) and Nonces", Work in Progress, draft-mcgrew-
              iv-gen-03, October 2013.

   [MF00]     McGrew, D. and S. Fluhrer, "Attacks on Additive Encryption
              of Redundant Plaintext and Implications on Internet
              Security", Proceedings of the Seventh Annual Workshop on
              Selected Areas in Cryptography (SAC 2000) Springer-
              Verlag., pp. 14-28, 2000.

   [OSCORE-PROFILE]
              Palombini, F., Seitz, L., Selander, G., and M. Gunnarsson,
              "OSCORE profile of the Authentication and Authorization
              for Constrained Environments Framework", Work in
              Progress, draft-ietf-ace-oscore-profile-07, February 2019.

   [REST]     Fielding, R., "Architectural Styles and the Design of
              Network-based Software Architectures", Ph.D.
              Dissertation, University of California, Irvine, 2010.

   [RFC3552]  Rescorla, E. and B. Korver, "Guidelines for Writing RFC
              Text on Security Considerations", BCP 72, RFC 3552,
              DOI 10.17487/RFC3552, July 2003,
              <https://www.rfc-editor.org/info/rfc3552>.

   [RFC3986]  Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
              Resource Identifier (URI): Generic Syntax", STD 66,
              RFC 3986, DOI 10.17487/RFC3986, January 2005,
              <https://www.rfc-editor.org/info/rfc3986>.

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

   [RFC5869]  Krawczyk, H. and P. Eronen, "HMAC-based Extract-and-Expand
              Key Derivation Function (HKDF)", RFC 5869,
              DOI 10.17487/RFC5869, May 2010,
              <https://www.rfc-editor.org/info/rfc5869>.

   [RFC6690]  Shelby, Z., "Constrained RESTful Environments (CoRE) Link
              Format", RFC 6690, DOI 10.17487/RFC6690, August 2012,
              <https://www.rfc-editor.org/info/rfc6690>.

   [RFC7228]  Bormann, C., Ersue, M., and A. Keranen, "Terminology for
              Constrained-Node Networks", RFC 7228,
              DOI 10.17487/RFC7228, May 2014,
              <https://www.rfc-editor.org/info/rfc7228>.

   [RFC7515]  Jones, M., Bradley, J., and N. Sakimura, "JSON Web
              Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May
              2015, <https://www.rfc-editor.org/info/rfc7515>.

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

   [RFC8126]  Cotton, M., Leiba, B., and T. Narten, "Guidelines for
              Writing an IANA Considerations Section in RFCs", BCP 26,
              RFC 8126, DOI 10.17487/RFC8126, June 2017,
              <https://www.rfc-editor.org/info/rfc8126>.

Appendix A. Scenario Examples โœจ

okay appendix A is the fun part!! ๐ŸŽ€ this shows OSCORE in action for the scenarios from Section 2.2.1.1 of [CoAP-E2E-Sec] ๐Ÿงš we're assuming a security context is already set up between client and server, so pretend the handshake already happened ๐Ÿ’– and to keep things simple, the examples only show what's in the messages and skip the nitty gritty of the compressed COSE message format ๐Ÿซถ

A.1. Secure Access to Sensor ๐Ÿšจ

this one shows a client asking a server for the alarm status ๐Ÿ’…

      Client  Proxy  Server
        |       |       |
        +------>|       |            Code: 0.02 (POST)
        | POST  |       |           Token: 0x8c
        |       |       |          OSCORE: [kid:5f, Partial IV:42]
        |       |       |         Payload: {Code:0.01,
        |       |       |                   Uri-Path:"alarm_status"}
        |       |       |
        |       +------>|            Code: 0.02 (POST)
        |       | POST  |           Token: 0x7b
        |       |       |          OSCORE: [kid:5f, Partial IV:42]
        |       |       |         Payload: {Code:0.01,
        |       |       |                   Uri-Path:"alarm_status"}
        |       |       |
        |       |<------+            Code: 2.04 (Changed)
        |       |  2.04 |           Token: 0x7b
        |       |       |          OSCORE: -
        |       |       |         Payload: {Code:2.05, "0"}
        |       |       |
        |<------+       |            Code: 2.04 (Changed)
        |  2.04 |       |           Token: 0x8c
        |       |       |          OSCORE: -
        |       |       |         Payload: {Code:2.05, "0"}
        |       |       |

quick decoder ring ๐Ÿ“ square brackets [ ... ] mean the content of a compressed COSE object, and curly brackets { ... } mean encrypted data ๐Ÿ”

Figure 12: Secure Access to Sensor

okay the big secret here is that OSCORE encrypts the CoAP request and response codes ๐Ÿ™ˆ so the only codes visible on the outside are dummy ones (POST and Changed). the Uri-Path option ("alarm_status") and the payload ("0") are hidden too, periodt ๐Ÿ”’

the COSE header of the request has an identifier (5f) that tells you which security context protected the message, plus a Partial IV (42) ๐ŸŽ€

and for verification: the server checks the request the way Section 8.2 describes, and the client checks the response the way Section 8.4 describes ๐Ÿ‘‘

A.2. Secure Subscribe to Sensor ๐Ÿฉธ๐Ÿ“ˆ

okay so this example is such a vibe ๐Ÿ’… a client wants to subscribe to a blood sugar measurement resource (GET /glucose) ๐Ÿ“ and it first gets the value 220 mg/dl, then a second value 180 mg/dl. bestie, it's giving live updates, no cap ๐Ÿงš

Look at the diagram below, it's literally so iconic ๐Ÿ˜ญโœจ

   Client  Proxy  Server
     |       |       |
     +------>|       |            Code: 0.05 (FETCH)
     | FETCH |       |           Token: 0x83
     |       |       |         Observe: 0
     |       |       |          OSCORE: [kid:ca, Partial IV:15]
     |       |       |         Payload: {Code:0.01,
     |       |       |                   Observe:0,
     |       |       |                   Uri-Path:"glucose"}
     |       |       |
     |       +------>|            Code: 0.05 (FETCH)
     |       | FETCH |           Token: 0xbe
     |       |       |         Observe: 0
     |       |       |          OSCORE: [kid:ca, Partial IV:15]
     |       |       |         Payload: {Code:0.01,
     |       |       |                   Observe:0,
     |       |       |                   Uri-Path:"glucose"}
     |       |       |
     |       |<------+            Code: 2.05 (Content)
     |       |  2.05 |           Token: 0xbe
     |       |       |         Observe: 7
     |       |       |          OSCORE: -
     |       |       |         Payload: {Code:2.05,
     |       |       |                   Observe:-,
     |       |       |                   Content-Format:0, "220"}
     |       |       |
     |<------+       |            Code: 2.05 (Content)
     |  2.05 |       |           Token: 0x83
     |       |       |         Observe: 7
     |       |       |          OSCORE: -
     |       |       |         Payload: {Code:2.05,
     |       |       |                   Observe:-,
     |       |       |                   Content-Format:0, "220"}
    ...     ...     ...
     |       |       |
     |       |<------+            Code: 2.05 (Content)
     |       |  2.05 |           Token: 0xbe
     |       |       |         Observe: 8
     |       |       |          OSCORE: [Partial IV:36]
     |       |       |         Payload: {Code:2.05,
     |       |       |                   Observe:-,
     |       |       |                   Content-Format:0, "180"}
     |       |       |
     |<------+       |            Code: 2.05 (Content)
     |  2.05 |       |           Token: 0x83
     |       |       |         Observe: 8
     |       |       |          OSCORE: [Partial IV:36]
     |       |       |         Payload: {Code:2.05,
     |       |       |                   Observe:-,
     |       |       |                   Content-Format:0, "180"}
     |       |       |

Square brackets [ ... ] mean the compressed COSE object header ๐Ÿ“ฆ, and curly brackets { ... } mean encrypted data ๐Ÿ”. Super simple, right? ๐Ÿฅฐ

Figure 13: Secure Subscribe to Sensor ๐ŸŽ€

okay so the dummy Codes (FETCH/Content) are used to allow forwarding of Observe messages ๐Ÿฆ‹. The options Content-Format (0) and the payload ("220" and "180") are encrypted ๐Ÿ”’, so nobody snooping gets to see them ๐Ÿ‘€๐Ÿ’€.

The COSE header of the request has an identifier (ca), which tells you the security context used to protect the message ๐Ÿ—๏ธ, plus a Partial IV (15). The COSE header of the second response has the Partial IV (36). The first response uses the Partial IV of the request ๐Ÿง โœจ. Very organized, very slay.

The server verifies that the Partial IV has not been received before ๐Ÿ™…โ€โ™€๏ธ. That's the big no-repeats rule, bestie ๐Ÿ’–.

The client verifies that the responses are bound to the request, and that the Partial IVs are greater than any Partial IV previously received in a response bound to the request ๐Ÿ“ˆ. The one exception is the notification without a Partial IV, which is considered the oldest ๐Ÿ‘ต๐ŸŒธ. Iykyk ๐Ÿ’….


Appendix B. Deployment Examples ๐Ÿงšโ€โ™€๏ธ๐ŸŽ€

For many Internet of Things (IoT) deployments, a 128-bit uniformly random Master Key is sufficient for encrypting all data exchanged with the IoT device throughout its lifetime ๐Ÿ”‘๐ŸŒˆ. Lowkey a huge win. Two examples are given in this section ๐Ÿซถ. In the first example, the security context is only derived once from the Master Secret. In the second example, security contexts are derived multiple times using random inputs ๐ŸŽฒโœจ.

B.1. Security Context Derived Once ๐ŸŒธ

An application that only derives the security context once needs to handle the loss of mutable security context parameters, e.g., due to reboot ๐Ÿ”„๐Ÿ’€. Major "oh no" energy, but we have a plan, periodt ๐Ÿ’….

B.1.1. Sender Sequence Number ๐Ÿ”ข

In order to handle loss of Sender Sequence Numbers, the device MAY implement procedures for writing to nonvolatile memory during normal operations and updating the security context after reboot ๐Ÿ’พ. Wait, I need to be careful here, bestie: the original text says the device may do this, so it's optional, not required ๐Ÿ™ˆ. Provided that the procedures comply with the requirements on the security context parameters (Section 3.3), this example gives one such procedure โœจ.

There are known issues related to writing to nonvolatile memory ๐Ÿ˜ฌ. For example, flash drives may have a limited number of erase operations during their lifetime ๐Ÿชซ. Also, the time for a write operation to nonvolatile memory to be completed may be unpredictable, e.g., due to caching, which could result in important security context data not being stored at the time when the device reboots ๐Ÿ˜ฑ. Not ideal, not me, not today ๐Ÿ˜ญ.

However, many devices have predictable limits for writing to nonvolatile memory ๐Ÿ“, are physically limited to only sending a small number of messages per minute ๐Ÿข, and may have no good source of randomness ๐ŸŽฒ๐Ÿ’€.

To prevent reuse of Sender Sequence Number, an endpoint may perform the following procedure during normal operations ๐Ÿ›ก๏ธ:

  • Before using a Sender Sequence Number that is evenly divisible by K, where K is a positive integer, store the Sender Sequence Number (SSN1) in nonvolatile memory. After booting, the endpoint initiates the new Sender Sequence Number (SSN2) to the value stored in persistent memory plus K plus F: SSN2 = SSN1 + K + F, where F is a positive integer ๐Ÿงฎ.
    • Writing to nonvolatile memory can be costly, so the value K gives a trade-off between how often you store things and efficient use of Sender Sequence Numbers ๐Ÿ’ธโš–๏ธ.
    • Writing to nonvolatile memory may be subject to delays, or failure, so F MUST be set so that the last Sender Sequence Number used before reboot is never larger than SSN2 ๐Ÿšจ. That's a hard rule, bestie ๐Ÿ’–.

If F cannot be set so SSN2 is always larger than the last Sender Sequence Number used before reboot, the method described in this section MUST NOT be used ๐Ÿ™…โ€โ™€๏ธ. No exceptions, no drama ๐Ÿ‘‘.

B.1.2. Replay Window ๐ŸชŸ

In case of loss of security context on the server, the server may perform the following procedure after booting, to prevent accepting replays of previously received requests ๐Ÿ›‘:

  • The server updates its Sender Sequence Number as specified in Appendix B.1.1 to be used as Partial IV in the response containing the Echo option (next bullet) ๐Ÿ”.
  • For each stored security context, the first time after booting the server receives an OSCORE request, the server responds with an OSCORE protected 4.01 (Unauthorized), containing only the Echo option [CoAP-ECHO-REQ-TAG] and no diagnostic payload ๐Ÿ™‹โ€โ™€๏ธ. The server MUST use its Partial IV when generating the AEAD nonce and MUST include the Partial IV in the response (see Section 5) ๐Ÿซก. If the server, with use of the Echo option, can verify a second OSCORE request as fresh, then the Partial IV of the second request is set as the lower limit of the Replay Window of that security context ๐Ÿช„โœจ. Main character energy.

B.1.3. Notifications ๐Ÿ””

To prevent the acceptance of replays of previously received notifications, the client may perform the following procedure after booting ๐Ÿงƒ:

  • The client forgets about earlier registrations and removes all Notification Numbers ๐Ÿ—‘๏ธ. The client then registers again using the Observe option ๐Ÿ”๐Ÿ’œ.

B.2. Security Context Derived Multiple Times

okay so an application that doesn't need forward secrecy ๐Ÿฆ‹ is allowed to make multiple security contexts out of one Master Secret โœจ The requirements on the security context parameters MUST be fulfilled (Section 3.3) even if the client or server gets rebooted, recommissioned, or runs into error cases ๐Ÿ’€

This section shows a protocol that adds some randomness to the ID Context parameter and mixes it with stuff the two sides already agreed on, like Master Secret, Master Salt, and Sender/Recipient ID (see Section 3.2), to derive brand new security contexts ๐ŸŒธ The random input rides between client and server in the kid context parameter. This protocol MUST NOT be used unless both endpoints have good sources of randomness ๐ŸŽฒ

During normal requests, the ID Context of an established security context may be sent in the kid context, which, together with kid, helps the server find the right security context ๐Ÿ” Or the kid context can be left out, since both client and server are expected to already know the ID Context (see Section 5.1) ๐Ÿซถ

This protocol may only be needed when the mutable part of the security context gets lost on the client or server, e.g., when the endpoint has rebooted ๐Ÿ˜ญ It may also be used whenever the client and server need to derive a new security context. For example, if a device is provisioned with one fixed set of input parameters (including Master Secret, Sender and Recipient Identifiers), then a randomized ID Context makes sure the security context is different for each deployment ๐Ÿงš

Heads up bestie: the server needs to be configured to run this protocol when it can't retrieve an existing security context, instead of stopping processing the message like step 2 of Section 8.2 says ๐Ÿ‘€

Here's the vibe, described with reference to Figure 14 ๐Ÿ’– The client or the server may start the protocol. If the server starts it, step 1 gets skipped ๐Ÿฆ‹

                  Client                Server
                    |                      |
1. Protect with     |      request #1      |
   ID Context = ID1 |--------------------->| 2. Verify with
                    |  kid_context = ID1   |    ID Context = ID1
                    |                      |
                    |      response #1     |    Protect with
3. Verify with      |<---------------------|    ID Context = R2||ID1
   ID Context = R2||ID1 |   kid_context = R2   |
                    |                      |
   Protect with     |      request #2      |
   ID Context = R2||R3 |--------------------->| 4. Verify with
                    | kid_context = R2||R3 |    ID Context = R2||R3
                    |                      |
                    |      response #2     |    Protect with
5. Verify with      |<---------------------|    ID Context = R2||R3
   ID Context = R2||R3 |                      |

        Figure 14: Protocol for Establishing a New Security Context

Here's the step-by-step, no cap ๐Ÿ’…

  1. (Optional) If the client doesn't have a valid security context with the server, e.g., because of a reboot or because this is the first time it's contacting the server, then it generates a random string R1 and uses it as ID Context, together with the input parameters shared with the server, to derive a first security context ๐ŸŒฑ The client sends an OSCORE request to the server protected with that first security context, containing R1 wrapped in a CBOR bstr as kid context. The request may target a special resource used for updating security contexts โœจ
  2. The server gets an OSCORE request it has no valid security context for, either because the client generated a new security context ID1 = R1 or because the server lost part of its security context, e.g., ID Context, Sender Sequence Number or Replay Window ๐Ÿ˜ฑ If the server can verify the request (see Section 8.2) with the new first security context, using the received ID1 (sent in kid context) as ID Context and the input parameters tied to the received kid, then the server generates a random string R2 and derives a second security context with ID Context = ID2 = R2 || ID1 ๐Ÿ”ฅ It sends a 4.01 (Unauthorized) response protected with that second security context, containing R2 wrapped in a CBOR bstr as kid context, and caches R2. R2 MUST NOT be reused, because that may lead to reuse of key and nonce in response #1 ๐Ÿ™…โ€โ™€๏ธ Also, the server may receive several requests #1 tied to one security context, which means multiple parallel protocol runs. Multiple instances of R2 may need to be cached until one of those runs is completed, see Appendix B.2.1 ๐ŸŒˆ
  3. The client gets a response with a kid context holding a CBOR bstr that wraps R2, answering an OSCORE request it made with ID Context = ID1 ๐ŸŽ€ The client derives a second security context using ID Context = ID2 = R2 || ID1. If the client can verify the response (see Section 8.4) using that second security context, then the client makes a request protected with a third security context, derived from ID Context = ID3 = R2 || R3, where R3 is a random byte string the client generated ๐Ÿฆ‹ The request includes R2 || R3 wrapped in a CBOR bstr as kid context.
  4. If the server gets a request with a kid context holding a CBOR bstr that wraps ID3, where the first part of ID3 is identical to an R2 sent in an earlier response #1 that it hasn't received before, then the server derives a third security context with ID Context = ID3 ๐Ÿง The server MUST NOT accept replayed request #2 messages ๐Ÿšซ If the server can verify the request (see Section 8.2) with the third security context, then it marks that third security context to be used with this client and removes all instances of R2 tied to this security context from the cache ๐Ÿงน This security context replaces the previous one with the client, and the first and second security contexts get deleted. The server responds using the same security context as in the request ๐Ÿ’œ
  5. If the client gets a response to the request with the third security context and the response verifies (see Section 8.4), then the client marks the third security context to be used with this server ๐Ÿฅน This security context replaces the previous one with the server, and the first and second security contexts get deleted โœจ

If verification fails at any step, the endpoint stops processing that message ๐Ÿ›‘

The length of the nonces R1, R2, and R3 is application specific. The application needs to set the length of each nonce so that the probability of its value being repeated is negligible; typically, that means at least 8 bytes long ๐Ÿ“ Since R2 may be generated as the result of a replayed request #1, the chance of R2 collisions is affected by the birthday paradox ๐Ÿ™ˆ For example, setting the length of R2 to 8 bytes results in an average collision after 2^32 response #1 messages, which should not be an issue for a constrained server handling on the order of one request per second โฑ๏ธ

Request #2 can be an ordinary request. The server performs the action of the request and sends response #2 after successfully completing the operations related to the security context in step 4 ๐Ÿ‘‘ The client acts on response #2 after successfully completing step 5 โœ…

When sending request #2, the client is assured that the Sender Key (derived with the random value R3) has never been used before ๐Ÿ” When receiving response #2, the client is assured that the response (protected with a key derived from the random value R3 and the Master Secret) was created by the server in response to request #2 ๐Ÿ’…

Similarly, when receiving request #2, the server is assured that the request (protected with a key derived from the random value R2 and the Master Secret) was created by the client in response to response #1 ๐Ÿค When sending response #2, the server is assured that the Sender Key (derived with the random value R2) has never been used before ๐ŸŒŸ

Implementation and denial-of-service considerations are covered in Appendix B.2.1 and Appendix B.2.2 ๐Ÿ’–

B.2.1. Implementation Considerations ๐Ÿ’–

Okay bestie, this section adds some implementation considerations to the protocol we just went through in the previous section โœจ

The server might only have room for a few security contexts, or it might only be able to handle a few protocol runs in parallel ๐Ÿฅบ. The server may legitimately receive multiple request #1 messages using the same immutable security context, e.g., because of packet loss. Replays of old request #1 messages could be difficult for the server to tell apart from legitimate ones ๐Ÿ™ˆ. The server needs to handle the case when the maximum number of cached R2s is reached. If the server receives a request #1 and isn't capable of executing it, then it may respond with an unprotected 5.03 (Service Unavailable) error message ๐Ÿ’€. The server may clear up state from protocol runs that never complete, e.g., by setting a timer when caching R2 and removing R2 and the associated security contexts from the cache at timeout. Also, state information can be flushed at reboot ๐Ÿงน.

As an alternative to caching R2, the server could generate R2 in a way that lets it be sent (in response #1) and verified (at reception of request #2) as the value of R2 it had generated. Such a procedure MUST NOT lead to the server accepting replayed request #2 messages ๐Ÿšซ. One construction described below is based on using a secret random HMAC key K_HMAC per set of immutable security context parameters associated with a client. This construction lets the server handle verification of R2 in response #2, at the cost of storing the K_HMAC keys and a slightly larger message overhead in response #1. The steps below refer to modifications to Appendix B.2:

  • In step 2, R2 is generated in the following way. First, the server generates a random K_HMAC (unless it already has one associated with the security context). Then it sets R2 = S2 || HMAC(K_HMAC, S2), where S2 is a random byte string, and the HMAC is truncated to 8 bytes. K_HMAC may have an expiration time, after which it is erased. Note that neither R2, S2, nor the derived first and second security contexts need to be cached ๐ŸŒธ.
  • In step 4, instead of verifying that R2 coincides with a cached value, the server looks up the associated K_HMAC and verifies the truncated HMAC, and the processing continues accordingly depending on verification success or failure. K_HMAC is used until a run of the protocol is completed (after verification of request #2), or until it expires, whichever comes first. After that, K_HMAC is erased. (The latter corresponds to removing the cached values of R2 in step 4 of Appendix B.2, and it makes the server reject replays of request #2 ๐Ÿ™…โ€โ™€๏ธ.)

The length of S2 is application specific, and the probability of collision of S2s is impacted by the birthday paradox ๐ŸŽ‚. For example, setting the length of S2 to 8 bytes results in an average collision after 2^32 response #1 messages, which should not be an issue for a constrained server handling on the order of one request per second ๐Ÿงฎ.

Two endpoints sharing a security context might accidentally start two instances of the protocol at the same time, each in the role of client, e.g., after a power outage affecting both endpoints โšก. Such a race condition could potentially lead to both protocols failing, and both endpoints repeatedly reinitiating the protocol without converging ๐Ÿ˜ฉ. Both endpoints can detect this situation, and it can be handled in different ways. The requests could potentially be spread out more in time, for example by only initiating this protocol when the endpoint actually needs to make a request, and potentially adding a random delay before requests immediately after reboot or if such parallel protocol runs are detected โณ.

B.2.2. Attack Considerations ๐Ÿ•ต๏ธโ€โ™€๏ธ

An on-path attacker may inject a message causing the endpoint to process verification of the message. A message crafted without access to the Master Secret will fail to verify ๐Ÿ”.

Replaying an old request with a value of 'kid_context' that the server does not recognize could trigger the protocol. This causes the server to generate the first and second security context and send a response. But if the client did not expect a response, it will be discarded. This may still result in a denial-of-service attack against the server, e.g., because of not being able to manage the state associated with many parallel protocol runs, and it may prevent legitimate client requests ๐Ÿ˜ฌ. Implementation alternatives with less data caching per request #1 message are favorable in this respect; see Appendix B.2.1 ๐Ÿ’….

Replaying response #1 in response to some request other than request #1 will fail to verify, since response #1 is associated to request #1 through the dependencies of ID Contexts and the Partial IV of request #1 included in the external_aad of response #1. Not a vibe ๐Ÿ™…โ€โ™€๏ธ.

If request #2 has already been well received, then the server has a valid security context, so a replay of request #2 is handled by the normal replay protection mechanism ๐Ÿ›ก๏ธ. Similarly, if response #2 has already been received, a replay of response #2 to some other request from the client will fail by the normal verification of binding of response to request ๐Ÿ”’.


Appendix C. Test Vectors ๐ŸŽ€

This appendix includes the test vectors for different examples of CoAP messages using OSCORE. Given a set of inputs, OSCORE defines how to set up the Security Context in both the client and the server ๐Ÿงš.

Note that in Appendix C.4 and all following test vectors, the Token and the Message ID of the OSCORE-protected CoAP messages are set to the same value as the unprotected CoAP message, to help the reader with comparisons ๐Ÿ‘€.

C.1. Test Vector 1: Key Derivation with Master Salt ๐Ÿ“

In this test vector, a Master Salt of 8 bytes is used. The default values are used for AEAD Algorithm and HKDF.

C.1.1. Client

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Master Salt: 0x9e7ca92223786340 (8 bytes)
  • Sender ID: 0x (0 byte)
  • Recipient ID: 0x01 (1 byte)

From the previous parameters:

  • info (for Sender Key): 0x8540f60a634b657910 (9 bytes)
  • info (for Recipient Key): 0x854101f60a634b657910 (10 bytes)
  • info (for Common IV): 0x8540f60a6249560d (8 bytes)

Outputs:

  • Sender Key: 0xf0910ed7295e6ad4b54fc793154302ff (16 bytes)
  • Recipient Key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • Common IV: 0x4622d4dd6d944168eefb54987c (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0x4622d4dd6d944168eefb54987c (13 bytes)
  • recipient nonce: 0x4722d4dd6d944169eefb54987c (13 bytes)

C.1.2. Server

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Master Salt: 0x9e7ca92223786340 (8 bytes)
  • Sender ID: 0x01 (1 byte)
  • Recipient ID: 0x (0 byte)

From the previous parameters:

  • info (for Sender Key): 0x854101f60a634b657910 (10 bytes)
  • info (for Recipient Key): 0x8540f60a634b657910 (9 bytes)
  • info (for Common IV): 0x8540f60a6249560d (8 bytes)

Outputs:

  • Sender Key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • Recipient Key: 0xf0910ed7295e6ad4b54fc793154302ff (16 bytes)
  • Common IV: 0x4622d4dd6d944168eefb54987c (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0x4722d4dd6d944169eefb54987c (13 bytes)
  • recipient nonce: 0x4622d4dd6d944168eefb54987c (13 bytes)

C.2. Test Vector 2: Key Derivation without Master Salt ๐ŸŒˆ

In this test vector, the default values are used for AEAD Algorithm, HKDF, and Master Salt.

C.2.1. Client

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Sender ID: 0x00 (1 byte)
  • Recipient ID: 0x01 (1 byte)

From the previous parameters:

  • info (for Sender Key): 0x854100f60a634b657910 (10 bytes)
  • info (for Recipient Key): 0x854101f60a634b657910 (10 bytes)
  • info (for Common IV): 0x8540f60a6249560d (8 bytes)

Outputs:

  • Sender Key: 0x321b26943253c7ffb6003b0b64d74041 (16 bytes)
  • Recipient Key: 0xe57b5635815177cd679ab4bcec9d7dda (16 bytes)
  • Common IV: 0xbe35ae297d2dace910c52e99f9 (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0xbf35ae297d2dace910c52e99f9 (13 bytes)
  • recipient nonce: 0xbf35ae297d2dace810c52e99f9 (13 bytes)

C.2.2. Server

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Sender ID: 0x01 (1 byte)
  • Recipient ID: 0x00 (1 byte)

From the previous parameters:

  • info (for Sender Key): 0x854101f60a634b657910 (10 bytes)
  • info (for Recipient Key): 0x854100f60a634b657910 (10 bytes)
  • info (for Common IV): 0x8540f60a6249560d (8 bytes)

Outputs:

  • Sender Key: 0xe57b5635815177cd679ab4bcec9d7dda (16 bytes)
  • Recipient Key: 0x321b26943253c7ffb6003b0b64d74041 (16 bytes)
  • Common IV: 0xbe35ae297d2dace910c52e99f9 (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0xbf35ae297d2dace810c52e99f9 (13 bytes)
  • recipient nonce: 0xbf35ae297d2dace910c52e99f9 (13 bytes)

C.3. Test Vector 3: Key Derivation with ID Context ๐Ÿงธ

In this test vector, a Master Salt of 8 bytes and an ID Context of 8 bytes are used. The default values are used for AEAD Algorithm and HKDF.

C.3.1. Client

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Master Salt: 0x9e7ca92223786340 (8 bytes)
  • Sender ID: 0x (0 byte)
  • Recipient ID: 0x01 (1 byte)
  • ID Context: 0x37cbf3210017a2d3 (8 bytes)

From the previous parameters:

  • info (for Sender Key): 0x85404837cbf3210017a2d30a634b657910 (17 bytes)
  • info (for Recipient Key): 0x8541014837cbf3210017a2d30a634b657910 (18 bytes)
  • info (for Common IV): 0x85404837cbf3210017a2d30a6249560d (16 bytes)

Outputs:

  • Sender Key: 0xaf2a1300a5e95788b356336eeecd2b92 (16 bytes)
  • Recipient Key: 0xe39a0c7c77b43f03b4b39ab9a268699f (16 bytes)
  • Common IV: 0x2ca58fb85ff1b81c0b7181b85e (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0x2ca58fb85ff1b81c0b7181b85e (13 bytes)
  • recipient nonce: 0x2da58fb85ff1b81d0b7181b85e (13 bytes)

C.3.2. Server

Inputs:

  • Master Secret: 0x0102030405060708090a0b0c0d0e0f10 (16 bytes)
  • Master Salt: 0x9e7ca92223786340 (8 bytes)
  • Sender ID: 0x01 (1 byte)
  • Recipient ID: 0x (0 byte)
  • ID Context: 0x37cbf3210017a2d3 (8 bytes)

From the previous parameters:

  • info (for Sender Key): 0x8541014837cbf3210017a2d30a634b657910 (18 bytes)
  • info (for Recipient Key): 0x85404837cbf3210017a2d30a634b657910 (17 bytes)
  • info (for Common IV): 0x85404837cbf3210017a2d30a6249560d (16 bytes)

Outputs:

  • Sender Key: 0xe39a0c7c77b43f03b4b39ab9a268699f (16 bytes)
  • Recipient Key: 0xaf2a1300a5e95788b356336eeecd2b92 (16 bytes)
  • Common IV: 0x2ca58fb85ff1b81c0b7181b85e (13 bytes)

From the previous parameters and a Partial IV equal to 0 (both for sender and recipient):

  • sender nonce: 0x2da58fb85ff1b81d0b7181b85e (13 bytes)
  • recipient nonce: 0x2ca58fb85ff1b81c0b7181b85e (13 bytes)

C.4. Test Vector 4: OSCORE Request, Client ๐ŸŽ€

okay so this one is an OSCORE-protected CoAP GET request ๐Ÿงš it uses the security context we derived in Appendix C.1. the unprotected request only has the Uri-Path and Uri-Host options, nothing extra ๐Ÿ’…

Unprotected CoAP request:

0x44015d1f00003974396c6f63616c686f737483747631 (22 bytes)

Common Context:

  • AEAD Algorithm: 10 (AES-CCM-16-64-128)
  • Key Derivation Function: HKDF SHA-256
  • Common IV: 0x4622d4dd6d944168eefb54987c (13 bytes)

Sender Context:

  • Sender ID: 0x (0 byte)
  • Sender Key: 0xf0910ed7295e6ad4b54fc793154302ff (16 bytes)
  • Sender Sequence Number: 20

The following COSE and cryptographic parameters are derived ๐ŸŒธ

  • Partial IV: 0x14 (1 byte)
  • kid: 0x (0 byte)
  • aad_array: 0x8501810a40411440 (8 bytes)
  • AAD: 0x8368456e63727970743040488501810a40411440 (20 bytes)
  • plaintext: 0x01b3747631 (5 bytes)
  • encryption key: 0xf0910ed7295e6ad4b54fc793154302ff (16 bytes)
  • nonce: 0x4622d4dd6d944168eefb549868 (13 bytes)

From the previous parameter, the following is derived ๐Ÿฆ‹

  • OSCORE option value: 0x0914 (2 bytes)
  • ciphertext: 0x612f1092f1776f1c1668b3825e (13 bytes)

And from there, we get the protected message ๐Ÿ˜ญ

  • Protected CoAP request (OSCORE message):
0x44025d1f00003974396c6f6
3616c686f7374620914ff612f1092f1776f1c1668b3825e (35 bytes)

C.5. Test Vector 5: OSCORE Request, Client ๐Ÿ“

this one is another OSCORE-protected CoAP GET request, this time using the security context from Appendix C.2 ๐Ÿซถ again the unprotected request only has the Uri-Path and Uri-Host options

Unprotected CoAP request:

0x440171c30000b932396c6f63616c686f737483747631 (22 bytes)

Common Context:

  • AEAD Algorithm: 10 (AES-CCM-16-64-128)
  • Key Derivation Function: HKDF SHA-256
  • Common IV: 0xbe35ae297d2dace910c52e99f9 (13 bytes)

Sender Context:

  • Sender ID: 0x00 (1 bytes)
  • Sender Key: 0x321b26943253c7ffb6003b0b64d74041 (16 bytes)
  • Sender Sequence Number: 20

The following COSE and cryptographic parameters are derived โœจ

  • Partial IV: 0x14 (1 byte)
  • kid: 0x00 (1 byte)
  • aad_array: 0x8501810a4100411440 (9 bytes)
  • AAD: 0x8368456e63727970743040498501810a4100411440 (21 bytes)
  • plaintext: 0x01b3747631 (5 bytes)
  • encryption key: 0x321b26943253c7ffb6003b0b64d74041 (16 bytes)
  • nonce: 0xbf35ae297d2dace910c52e99ed (13 bytes)

From the previous parameter, the following is derived ๐ŸŒˆ

  • OSCORE option value: 0x091400 (3 bytes)
  • ciphertext: 0x4ed339a5a379b0b8bc731fffb0 (13 bytes)

From there, the protected message looks like this ๐Ÿ’–

  • Protected CoAP request (OSCORE message):
0x440271c30000b932396c6f6
3616c686f737463091400ff4ed339a5a379b0b8bc731fffb0 (36 bytes)

C.6. Test Vector 6: OSCORE Request, Client ๐Ÿ‘‘

ok this one is for an application that sets the ID Context and needs it sent along in the request, so 'kid context' shows up in the protected message ๐Ÿ”ฅ it uses the security context from Appendix C.3, and the unprotected request again only has the Uri-Path and Uri-Host options

Unprotected CoAP request:

0x44012f8eef9bbf7a396c6f63616c686f737483747631 (22 bytes)

Common Context:

  • AEAD Algorithm: 10 (AES-CCM-16-64-128)
  • Key Derivation Function: HKDF SHA-256
  • Common IV: 0x2ca58fb85ff1b81c0b7181b85e (13 bytes)
  • ID Context: 0x37cbf3210017a2d3 (8 bytes)

Sender Context:

  • Sender ID: 0x (0 bytes)
  • Sender Key: 0xaf2a1300a5e95788b356336eeecd2b92 (16 bytes)
  • Sender Sequence Number: 20

The following COSE and cryptographic parameters are derived ๐Ÿฆ‹

  • Partial IV: 0x14 (1 byte)
  • kid: 0x (0 byte)
  • kid context: 0x37cbf3210017a2d3 (8 bytes)
  • aad_array: 0x8501810a40411440 (8 bytes)
  • AAD: 0x8368456e63727970743040488501810a40411440 (20 bytes)
  • plaintext: 0x01b3747631 (5 bytes)
  • encryption key: 0xaf2a1300a5e95788b356336eeecd2b92 (16 bytes)
  • nonce: 0x2ca58fb85ff1b81c0b7181b84a (13 bytes)

From the previous parameter, the following is derived ๐Ÿงš

  • OSCORE option value: 0x19140837cbf3210017a2d3 (11 bytes)
  • ciphertext: 0x72cd7273fd331ac45cffbe55c3 (13 bytes)

And from there, the protected message ๐Ÿซถ

  • Protected CoAP request (OSCORE message):
0x44022f8eef9bbf7a396c6f63616c686f73746b19140837cbf3210017a2d3ff
72cd7273fd331ac45cffbe55c3 (44 bytes)

C.7. Test Vector 7: OSCORE Response, Server ๐ŸŒธ

this is an OSCORE-protected 2.05 (Content) response to the request from Appendix C.4 ๐Ÿ’… the unprotected response has the payload "Hello World!" and no options. the protected response doesn't contain a 'kid' or a Partial IV. heads up, some parameters are derived from the request, so that's where they come from ๐Ÿ™ˆ

Unprotected CoAP response:

0x64455d1f00003974ff48656c6c6f20576f726c6421 (21 bytes)

Common Context:

  • AEAD Algorithm: 10 (AES-CCM-16-64-128)
  • Key Derivation Function: HKDF SHA-256
  • Common IV: 0x4622d4dd6d944168eefb54987c (13 bytes)

Sender Context:

  • Sender ID: 0x01 (1 byte)
  • Sender Key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • Sender Sequence Number: 0

The following COSE and cryptographic parameters are derived โœจ

  • aad_array: 0x8501810a40411440 (8 bytes)
  • AAD: 0x8368456e63727970743040488501810a40411440 (20 bytes)
  • plaintext: 0x45ff48656c6c6f20576f726c6421 (14 bytes)
  • encryption key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • nonce: 0x4622d4dd6d944168eefb549868 (13 bytes)

From the previous parameter, the following is derived ๐Ÿฆ‹

  • OSCORE option value: 0x (0 bytes)
  • ciphertext: 0xdbaad1e9a7e7b2a813d3c31524378303cdafae119106 (22 bytes)

And from there, the protected response ๐Ÿ’–

  • Protected CoAP response (OSCORE message):
0x64445d1f0000397490ffdbaad1e9a7e7b2a813d3c31524378303cdafae119106
(32 bytes)

C.8. Test Vector 8: OSCORE Response with Partial IV, Server ๐Ÿงš

ok so this is also an OSCORE-protected 2.05 (Content) response to the request in Appendix C.4 ๐ŸŒˆ the unprotected response has the payload "Hello World!" and no options. this time the protected response doesn't have a 'kid', but it does have a Partial IV. again, some parameters are derived from the request ๐Ÿ“

Unprotected CoAP response:

0x64455d1f00003974ff48656c6c6f20576f726c6421 (21 bytes)

Common Context:

  • AEAD Algorithm: 10 (AES-CCM-16-64-128)
  • Key Derivation Function: HKDF SHA-256
  • Common IV: 0x4622d4dd6d944168eefb54987c (13 bytes)

Sender Context:

  • Sender ID: 0x01 (1 byte)
  • Sender Key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • Sender Sequence Number: 0

The following COSE and cryptographic parameters are derived ๐Ÿ’œ

  • Partial IV: 0x00 (1 byte)
  • aad_array: 0x8501810a40411440 (8 bytes)
  • AAD: 0x8368456e63727970743040488501810a40411440 (20 bytes)
  • plaintext: 0x45ff48656c6c6f20576f726c6421 (14 bytes)
  • encryption key: 0xffb14e093c94c9cac9471648b4f98710 (16 bytes)
  • nonce: 0x4722d4dd6d944169eefb54987c (13 bytes)

From the previous parameter, the following is derived โœจ

  • OSCORE option value: 0x0100 (2 bytes)
  • ciphertext: 0x4d4c13669384b67354b2b6175ff4b8658c666a6cf88e (22 bytes)

And from there, the protected message ๐Ÿ”ฅ

  • Protected CoAP response (OSCORE message):
0x64445d1f00003974920100
ff4d4c13669384b67354b2b6175ff4b8658c666a6cf88e (34 bytes)

Appendix D. Overview of Security Properties ๐Ÿ”’

D.1. Threat Model ๐Ÿ’€

this section lays out the threat model, using the terms from [RFC3552] ๐Ÿซถ

we assume the endpoints running OSCORE haven't themselves been compromised. the attacker is assumed to have control of the CoAP channel the endpoints talk over, intermediary nodes included. the attacker can launch any passive or active on-path or off-path attacks, and that includes eavesdropping, traffic analysis, spoofing, insertion, modification, deletion, delay, replay, man-in-the-middle, and denial-of-service attacks. basically, the attacker can read any CoAP message on the network and undetectably remove, change, or inject forged messages onto the wire ๐Ÿ˜ญ

OSCORE targets the protection of the CoAP request/response layer (Section 2 of [RFC7252]) between the endpoints. that covers the CoAP Payload, Code, Uri-Path/Uri-Query, and the other Class E option instances (Section 4.1) โœจ

OSCORE does not protect the CoAP messaging layer (Section 2 of [RFC7252]) or other lower layers involved in routing and transporting the CoAP requests and responses ๐Ÿ™ˆ

also, OSCORE does not protect Class U option instances (Section 4.1). these are used to support CoAP forward proxy operations (see Section 5.7.2 of [RFC7252]). the supported proxies (forwarding, and cross-protocol ones, e.g., CoAP to CoAP-mappable protocols such as HTTP) must be able to change certain Class U options (by instruction from the Client), and that can get the CoAP request redirected to the server. changes caused by the proxy may result in the request not reaching the server or reaching the wrong server. for cross-protocol proxies, mappings are done on the Outer part of the message, so these protocols are essentially used as transport. manipulating these options may thus impact whether the protected message reaches the destination endpoint or doesn't ๐Ÿฆ‹

attacks on unprotected CoAP message fields generally cause denial-of-service attacks. those are out of scope for this document, but more details are in Appendix D.5 ๐Ÿ’…

attacks against the CoAP request-response layer, though, are in scope. OSCORE is intended to protect against eavesdropping, spoofing, insertion, modification, deletion, replay, and man-in-the middle attacks ๐Ÿ‘‘

and yes, OSCORE is susceptible to traffic analysis, as discussed later in Appendix D ๐ŸŒธ

D.2. Supporting Proxy Operations ๐Ÿงš

CoAP is designed to work with intermediaries that read and/or change CoAP message fields so they can do supporting jobs in constrained environments, like forwarding and cross-protocol translations ๐Ÿ“

if you secure CoAP on the transport layer, the entire message is protected between the endpoints, and that means CoAP proxy operations aren't possible. to enable proxy operations, the security on the transport layer has to be terminated at the proxy. in that case, the whole CoAP message is unprotected at the proxy ๐Ÿซถ

requirements for CoAP end-to-end security are specified in [CoAP-E2E-Sec], and forwarding is detailed in Section 2.2.1 of that document. the client and server are assumed to be honest, while proxies and gateways are only trusted to perform their intended operations ๐Ÿ’–

by working at the CoAP layer, OSCORE lets different CoAP message fields be protected differently. that way, the fields needed for proxy operations stay available to the proxy, while the message fields meant for the other endpoint stay protected โœจ in the rest of this section, we look at how OSCORE protects the protected message fields, and what happens when the fields meant for proxy operation are left unprotected ๐ŸŒˆ

D.3. Protected Message Fields ๐Ÿ”’

okay so the protected message fields get tucked into the plaintext (Section 5.3) AND the AAD (Section 5.4) of the COSE_Encrypt0 object, and then the whole thing gets locked up with an AEAD algorithm ๐Ÿ’–

OSCORE leans on two things: a random Master Secret that's already set up before anything starts (Section 12.3) to derive encryption keys, and a way of making sure every (key, nonce) pair is unique (Appendix D.4) ๐ŸŒธ. If both of those hold, and the keys only get used for as much data as Section 7.2.1 allows, then OSCORE should give you these guarantees:

  • Confidentiality: an attacker should not be able to figure out the plaintext of a given OSCORE message, or work out that different plaintexts are related (Section 5.3). ๐Ÿ™ˆ
  • Integrity: an attacker should not be able to craft a new OSCORE message with different protected message fields from an existing one and have the receiver accept it. ๐Ÿ›ก๏ธ
  • Request-response binding: an attacker should not be able to trick a client into matching a response to the wrong request. ๐ŸŽ€
  • Non-replayability: an attacker should not be able to get the receiver to accept a message it already received and accepted. ๐Ÿ”

When we say "attacker," we mean anyone who isn't one of the endpoints, like a compromised intermediary ๐Ÿ‘€. The vibe is that OSCORE gets these properties by AEAD-protecting the plaintext with a strong key, plus making sure every (key, nonce) pair is unique ๐Ÿ’ช. AEAD encryption [RFC5116] handles confidentiality and integrity for the data โœจ. Response-request binding comes from putting the kid and the Partial IV of the request into the AAD of the response ๐Ÿฆ‹. And non-replayability for requests and notifications comes from unique (key, nonce) pairs plus a replay protection mechanism, which is application dependent (see Section 7.4) ๐Ÿงš.

Real talk though, OSCORE is vulnerable to a bunch of traffic analysis attacks that look at the length and timing of encrypted packets ๐Ÿ˜ญ. OSCORE doesn't have any specific defenses against this, but the application can use a padding mechanism so an attacker can't directly figure out the length of the padding ๐Ÿซถ. Just know that info about the padding can still leak through side-channel attacks that watch for differences in timing ๐Ÿ’€.


D.4. Uniqueness of (key, nonce) ๐Ÿ”‘

in this section we're showing that (key, nonce) pairs stay unique as long as the requirements in Sections 3.3 and 7.2.1 are followed โœจ

So, fix a Common Context (Section 3.1) and an endpoint, which we'll call the encrypting endpoint ๐ŸŽฏ. An endpoint can switch between the client and server roles, but each endpoint always encrypts with the Sender Key of its Sender Context ๐Ÿ”„. Sender Keys are (stochastically) unique because they're derived with HKDF from unique Sender IDs, so messages encrypted by different endpoints use different keys ๐ŸŒˆ. The only thing left to prove is that the nonces used by that one fixed endpoint are unique ๐Ÿง.

Since the Common IV is fixed, the nonces get determined by two things: PIV, which is the Partial IV of the request or of the response, and the Sender ID of whichever endpoint generated that Partial IV (ID_PIV) ๐Ÿ’…. The nonce construction (Section 5.2), using the size of the ID_PIV (S), makes unique nonces for different (ID_PIV, PIV) pairs โœจ. There are two cases:

A. For requests, and for responses with a Partial IV (like Observe notifications) ๐Ÿ“ฃ:

  • ID_PIV = Sender ID of the encrypting endpoint
  • PIV = current Partial IV of the encrypting endpoint

Because the encrypting endpoint steps the Partial IV for every use, the nonces in case A are all unique, as long as the number of encrypted messages stays within the required range (Section 7.2.1) ๐Ÿ™Œ.

B. For responses without a Partial IV (like a single response to a request) ๐Ÿ“:

  • ID_PIV = Sender ID of the endpoint that generated the request
  • PIV = Partial IV of the request

Since Sender IDs are unique, ID_PIV is different from the Sender ID of the encrypting endpoint ๐Ÿซง. That means the nonces in case B are different from the nonces in case A, where the encrypting endpoint generated the Partial IV ๐Ÿ’œ. And since the Partial IV of the request gets checked for replay (Section 7.4) against this Recipient Context, PIV is unique for that ID_PIV, which makes all the nonces in case B distinct ๐Ÿ‘‘.


D.5. Unprotected Message Fields ๐Ÿ•ต๏ธโ€โ™€๏ธ

this section looks at attacks on the message fields that OSCORE does not protect, going by the threat model in Appendix D.1 ๐Ÿฆ‹

D.5.1. CoAP Header Fields ๐ŸŒธ

  • Version. The CoAP version [RFC7252] isn't expected to be sensitive to disclosure. Right now there's only one CoAP version defined ๐Ÿผ. Changing this parameter could be a denial-of-service attack ๐Ÿ˜ฌ. Future versions of CoAP need to analyze attacks on OSCORE-protected messages where an adversary changes the CoAP version ๐Ÿ”.
  • Token/Token Length. The Token field is a client-local identifier used to tell apart concurrent requests [RFC7252] ๐ŸŽŸ๏ธ. CoAP proxies are allowed to read and change Token and Token Length between hops ๐Ÿšช. An eavesdropper who reads the Token can match requests to responses, and that can be used for traffic analysis ๐Ÿ‘€. This is especially true for notifications, where lots of responses match one request ๐Ÿ“ฌ. Changing Token and Token Length as an on-path attacker could turn into a denial-of-service attack, because the client might not be able to tell which request a response belongs to, or find the info it needs to verify the response's integrity ๐Ÿ’€.
  • Code. The Outer CoAP Code of an OSCORE message is POST or FETCH for requests, with the matching response codes ๐Ÿ“ฎ. The receiving endpoint throws away the Outer CoAP Code and uses the Inner CoAP Code instead (see Section 4.2) ๐Ÿ—‘๏ธ. So if an attacker changes the Outer Code, the receiving endpoint isn't affected ๐Ÿ™Œ. However, switching the Outer Code from FETCH to a value for a method that doesn't work with Observe (like POST) could, depending on the proxy implementation (since Observe is undefined for several Codes), make the proxy stop forwarding notifications, which is a denial-of-service attack ๐Ÿšซ. Using FETCH instead of POST reveals no more than the presence of the Outer Observe option already does ๐Ÿซถ.
  • Type/Message ID. The Type and Message ID fields [RFC7252] reveal info about the UDP transport binding ๐ŸŒ. For example, an eavesdropper reading the Type or Message ID can learn how UDP messages relate to each other ๐Ÿงฉ. CoAP proxies are allowed to change Type and Message ID ๐Ÿ”€. These fields aren't present in CoAP over TCP [RFC8323], and they don't affect the request/response message there ๐Ÿ™…โ€โ™€๏ธ. Changing these fields on a UDP hop is a denial-of-service attack โš ๏ธ. An attacker who sends an ACK can make the endpoint think it doesn't need to retransmit the previous message ๐Ÿ”. An attacker who sends a RST might be able to cancel an observation ๐Ÿ›‘. And by changing a NON to a CON, the attacker can make the receiving endpoint ACK messages that never asked for an ACK ๐Ÿคฏ.
  • Length. This field holds the length of the message [RFC8323], which can be used for traffic analysis ๐Ÿ“. It isn't present in CoAP over UDP, and it doesn't affect the request/response message ๐Ÿ™ˆ. Changing Length is a denial-of-service attack, kind of like changing TCP header fields ๐Ÿฅ€.

D.5.2. CoAP Options ๐ŸŽ€

  • Max-Age. The Outer Max-Age is set to zero to avoid unnecessary caching of OSCORE error responses ๐ŸงŠ. Changing this value could therefore cause unnecessary caching ๐Ÿ™ƒ. No extra info is carried with this option ๐Ÿซง.
  • Proxy-Uri/Proxy-Scheme. These options are used in CoAP forward proxy deployments โžก๏ธ. With OSCORE, the Proxy-Uri option doesn't contain the Uri-Path/Uri-Query parts of the URI ๐Ÿ—บ๏ธ. The other parts of Proxy-Uri can't be protected, because forward proxies need to change them to do their job ๐Ÿ”ง. The server can check what scheme was used in the last hop, but it can't check what the client requested or what was used in previous hops ๐Ÿคทโ€โ™€๏ธ.
  • Uri-Host/Uri-Port. In forward proxy deployments, an adversary may change the Uri-Host/Uri-Port, and the application needs to deal with the fallout (see Section 4.1.3.2) ๐Ÿงฏ. The Uri-Host may be omitted, reveal info equivalent to the IP address, or reveal more privacy-sensitive info, and that last one is discouraged ๐Ÿšซ๐Ÿ•ต๏ธ.
  • Observe. The Outer Observe option is meant for a proxy to support forwarding Observe messages ๐Ÿ“ก. But the endpoints ignore it, because the Inner Observe option decides how the endpoints process things ๐Ÿง . Since the Partial IV gives absolute ordering of notifications, an intermediary can't fake reordering (see Section 4.1.3.5) ๐Ÿ”’. The Partial IV is only allowed to be absent on the first notification, and its absence doesn't stop correct ordering of notifications โœ…. The size and distribution of notifications over time might reveal info about the content or nature of the notifications ๐Ÿ“Š. Cancellations (Section 4.1.3.5.1) aren't tied to their registrations the same way responses are tied to requests in OSCORE (see Appendix D.3) ๐Ÿงต. But that doesn't make mismatched-cancellation attacks possible, because for a cancellation to be accepted, all options in the decrypted message except for ETag options MUST be the same (see Section 4.1.3.5) ๐Ÿ›ก๏ธโœจ.
  • Block1/Block2/Size1/Size2. The Outer Block options allow fragmentation of OSCORE messages on top of the segmentation done by the Inner Block options ๐Ÿงฉ. Having these options present means a big message is on its way, so the message size can be estimated and used for traffic analysis ๐Ÿ“ฆ. Messing with these options is a potential denial-of-service attack, like injecting fake Block fragments ๐Ÿ’ฅ. One measure against this kind of attack is the maximum message size, MAX_UNFRAGMENTED_SIZE (Section 4.1.3.4.2), above which messages get dropped ๐Ÿšง.
  • No-Response. The Outer No-Response option supports proxy functionality, specifically to avoid error transmissions from proxies to clients, and to keep proxies applying congestion control from reducing bandwidth to servers when they aren't getting responses ๐Ÿ“ญ. Modifying or adding this option is a potential denial-of-service attack against proxy operations ๐Ÿ˜ค. But since the option has an Inner value, its use can be securely agreed upon between the endpoints ๐Ÿค. The presence of this option isn't expected to reveal any sensitive info about the message exchange ๐ŸŒท.
  • OSCORE. The OSCORE option carries info about the compressed COSE header ๐Ÿ—‚๏ธ. Changing this field may cause OSCORE verification to fail โŒ.

D.5.3. Error and Signaling Messages ๐Ÿ’Œ

okay bestie, errors that happen during CoAP processing are protected end-to-end ๐Ÿ”’, which is giving security ๐Ÿ’…. Errors during OSCORE processing can't always be protected, though ๐Ÿ™ˆ. For example, the receiving endpoint might not be able to find the right security context. So for this setting, unprotected error messages are allowed, as specified, to prevent extensive retransmissions. The catch is that those error messages can be spoofed or manipulated, and that's a potential denial-of-service attack ๐Ÿ’€.

This document specifies OPTIONAL error codes and specific diagnostic payloads for OSCORE processing error messages. Be careful with these, though, because they might reveal how many and which security contexts exist on the server ๐Ÿ‘€. Servers MAY want to omit the diagnostic payload of error messages, use the same error code for every error, or avoid responding altogether to OSCORE processing errors if that's a security concern for the application ๐Ÿ›ก๏ธ. And here's the important part: clients MUST NOT rely on the error code or the diagnostic payload to trigger specific actions ๐Ÿšซ, because these errors are unprotected and can be spoofed or manipulated.

Signaling messages used in CoAP over TCP [RFC8323] are intended to be hop-by-hop ๐Ÿ”. Spoofing signaling messages can be used as a denial-of-service attack on a TCP connection, so keep an eye on them ๐Ÿฆ‹.

D.5.4. HTTP Message Fields ๐ŸŒ

Okay, so this one is a fun contrast ๐Ÿซถ. With CoAP, OSCORE doesn't protect header fields, which is what lets CoAP-CoAP proxy operations work. With HTTP, though, OSCORE use is restricted to transporting a protected CoAP message over an HTTP hop. Any unprotected HTTP message fields may reveal information about the transport of the OSCORE message and enable various denial-of-service attacks ๐Ÿ˜ญ. It is RECOMMENDED to additionally use TLS [RFC8446] for HTTP hops. TLS encrypts and integrity-protects the headers, but it still leaves some information for traffic analysis ๐Ÿ•ต๏ธโ€โ™€๏ธ.

Appendix E. CDDL Summary โœจ

Data structure definitions in this specification use the CDDL language for conciseness and precision [RFC8610]. This appendix is a quick summary of the small subset of CDDL that the specification uses ๐Ÿ“.

Within that subset, a CDDL rule looks like name = type, where name is the name given to the type. A type can be one of the following:

  • a reference to another named type, by giving its name. The predefined named types used in this specification are: uint, an unsigned integer (as represented in CBOR by major type 0); int, an unsigned or negative integer (as represented in CBOR by major type 0 or 1); bstr, a byte string (as represented in CBOR by major type 2); tstr, a text string (as represented in CBOR by major type 3);
  • a choice between two types, by giving both types separated by a /;
  • an array type (as represented in CBOR by major type 4), where the sequence of elements of the array is described by giving a sequence of entries separated by commas ,, and this sequence is enclosed by square brackets [ and ]. Arrays described by an array description contain elements that correspond one-to-one to the sequence of entries given. Each entry of an array description is of the form name : type, where name is the name given to the entry and type is the type of the array element corresponding to this entry.

Acknowledgments ๐Ÿซถ

The following individuals provided input to this document: Christian Amsuess, Tobias Andersson, Carsten Bormann, Joakim Brorsson, Ben Campbell, Esko Dijk, Jaro Fietz, Thomas Fossati, Martin Gunnarsson, Klaus Hartke, Rikard Hoeglund, Mirja Kuehlewind, Kathleen Moriarty, Eric Rescorla, Michael Richardson, Adam Roach, Jim Schaad, Peter van der Stok, Dave Thaler, Martin Thomson, Marco Tiloca, William Vignat, and Malisa Vucinic. Literally so many legends ๐Ÿ‘‘.

Ludwig Seitz and Goeran Selander worked on this document as part of the CelticPlus project CyberWI, with funding from Vinnova. Ludwig Seitz had additional funding from the SSF project SEC4Factory under the grant RIT17-0032. ๐ŸŒˆ

Authors' Addresses ๐Ÿ’œ

Goeran Selander
Ericsson AB

Email: goran.selander@ericsson.com


John Mattsson
Ericsson AB

Email: john.mattsson@ericsson.com


Francesca Palombini
Ericsson AB

Email: francesca.palombini@ericsson.com


Ludwig Seitz
RISE

Email: ludwig.seitz@ri.se
๐Ÿ“ฆ where this page comes from