RFC 7252

The Constrained Application Protocol (CoAP)

๐Ÿ“… published June 2014, from ietf

RFC 7252: The Constrained Application Protocol (CoAP) ๐Ÿ’–

Part 1 of 23 ๐ŸŽ€

  • RFC number: 7252
  • Title: The Constrained Application Protocol (CoAP)
  • Authors: Z. Shelby (ARM), K. Hartke, and C. Bormann (Universitaet Bremen TZI) โœจ
  • Category: Standards Track ๐Ÿ”ฅ
  • ISSN: 2070-1721
  • Date: June 2014 ๐ŸŒธ
  • Obsoletes / Updates: Nothing. The title block doesn't list any RFCs this one obsoletes or updates ๐Ÿงš

Abstract

okay bestie, so CoAP is a specialized web transfer protocol ๐Ÿ’… It's made for constrained nodes and constrained networks, meaning stuff that's low-power and kinda lossy. These nodes are often running on 8-bit microcontrollers with tiny amounts of ROM and RAM ๐Ÿฅบ Meanwhile the networks they live on, like IPv6 over Low-Power Wireless Personal Area Networks (6LoWPANs), often have high packet error rates and a typical throughput of 10s of kbit/s. Lowkey wild, right? ๐Ÿ’€ The whole thing is designed for machine-to-machine (M2M) applications, like smart energy and building automation ๐Ÿ โšก

CoAP gives you a request/response interaction model between application endpoints ๐Ÿฆ‹ It also has built-in discovery of services and resources, so things can find each other without extra fuss โœจ It keeps the key concepts of the Web, like URIs and Internet media types ๐ŸŒˆ It's built to interface easily with HTTP so it can plug into the Web, while still hitting the specialized requirements it needs: multicast support, very low overhead, and simplicity for constrained environments ๐Ÿ‘‘ It's giving efficient and iconic, periodt ๐Ÿ˜ญ๐Ÿซถ


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 got public review, and the Internet Engineering Steering Group (IESG) approved it for publication ๐ŸŽ€ If you want more info on Internet Standards, check out Section 2 of RFC 5741 ๐Ÿงš

You can find the current status of this document, any errata, and how to send feedback on it at http://www.rfc-editor.org/info/rfc7252 ๐Ÿฆ‹


Copyright (c) 2014 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 (http://trustee.ietf.org/license-info) as they're in effect on the date this document was published ๐Ÿ“œ Please actually read these, bestie, because they explain your rights and restrictions for this document ๐Ÿ™ˆ Code Components extracted from this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Simplified BSD License ๐Ÿ’–

More parts are coming, so stay tuned! ๐Ÿซถ

Table of Contents ๐Ÿ“š

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   5
     1.1.  Features  . . . . . . . . . . . . . . . . . . . . . . . .   5
     1.2.  Terminology . . . . . . . . . . . . . . . . . . . . . . .   6
   2.  Constrained Application Protocol  . . . . . . . . . . . . . .  10
     2.1.  Messaging Model . . . . . . . . . . . . . . . . . . . . .  11
     2.2.  Request/Response Model  . . . . . . . . . . . . . . . . .  12
     2.3.  Intermediaries and Caching  . . . . . . . . . . . . . . .  15
     2.4.  Resource Discovery  . . . . . . . . . . . . . . . . . . .  15
   3.  Message Format  . . . . . . . . . . . . . . . . . . . . . . .  15
     3.1.  Option Format . . . . . . . . . . . . . . . . . . . . . .  17
     3.2.  Option Value Formats  . . . . . . . . . . . . . . . . . .  19
   4.  Message Transmission  . . . . . . . . . . . . . . . . . . . .  20
     4.1.  Messages and Endpoints  . . . . . . . . . . . . . . . . .  20
     4.2.  Messages Transmitted Reliably . . . . . . . . . . . . . .  21
     4.3.  Messages Transmitted without Reliability  . . . . . . . .  23
     4.4.  Message Correlation . . . . . . . . . . . . . . . . . . .  24
     4.5.  Message Deduplication . . . . . . . . . . . . . . . . . .  24
     4.6.  Message Size  . . . . . . . . . . . . . . . . . . . . . .  25
     4.7.  Congestion Control  . . . . . . . . . . . . . . . . . . .  26
     4.8.  Transmission Parameters . . . . . . . . . . . . . . . . .  27
       4.8.1.  Changing the Parameters . . . . . . . . . . . . . . .  27
       4.8.2.  Time Values Derived from Transmission Parameters  . .  28
   5.  Request/Response Semantics  . . . . . . . . . . . . . . . . .  31
     5.1.  Requests  . . . . . . . . . . . . . . . . . . . . . . . .  31
     5.2.  Responses . . . . . . . . . . . . . . . . . . . . . . . .  31
       5.2.1.  Piggybacked . . . . . . . . . . . . . . . . . . . . .  33
       5.2.2.  Separate  . . . . . . . . . . . . . . . . . . . . . .  33
       5.2.3.  Non-confirmable . . . . . . . . . . . . . . . . . . .  34
     5.3.  Request/Response Matching . . . . . . . . . . . . . . . .  34
       5.3.1.  Token . . . . . . . . . . . . . . . . . . . . . . . .  34
       5.3.2.  Request/Response Matching Rules . . . . . . . . . . .  35

     5.4.  Options . . . . . . . . . . . . . . . . . . . . . . . . .  36
       5.4.1.  Critical/Elective . . . . . . . . . . . . . . . . . .  37
       5.4.2.  Proxy Unsafe or Safe-to-Forward and NoCacheKey  . . .  38
       5.4.3.  Length  . . . . . . . . . . . . . . . . . . . . . . .  38
       5.4.4.  Default Values  . . . . . . . . . . . . . . . . . . .  38
       5.4.5.  Repeatable Options  . . . . . . . . . . . . . . . . .  39
       5.4.6.  Option Numbers  . . . . . . . . . . . . . . . . . . .  39
     5.5.  Payloads and Representations  . . . . . . . . . . . . . .  40
       5.5.1.  Representation  . . . . . . . . . . . . . . . . . . .  40
       5.5.2.  Diagnostic Payload  . . . . . . . . . . . . . . . . .  41
       5.5.3.  Selected Representation . . . . . . . . . . . . . . .  41
       5.5.4.  Content Negotiation . . . . . . . . . . . . . . . . .  41
     5.6.  Caching . . . . . . . . . . . . . . . . . . . . . . . . .  42
       5.6.1.  Freshness Model . . . . . . . . . . . . . . . . . . .  43
       5.6.2.  Validation Model  . . . . . . . . . . . . . . . . . .  43
     5.7.  Proxying  . . . . . . . . . . . . . . . . . . . . . . . .  44
       5.7.1.  Proxy Operation . . . . . . . . . . . . . . . . . . .  44
       5.7.2.  Forward-Proxies . . . . . . . . . . . . . . . . . . .  46
       5.7.3.  Reverse-Proxies . . . . . . . . . . . . . . . . . . .  46
     5.8.  Method Definitions  . . . . . . . . . . . . . . . . . . .  47
       5.8.1.  GET . . . . . . . . . . . . . . . . . . . . . . . . .  47
       5.8.2.  POST  . . . . . . . . . . . . . . . . . . . . . . . .  47
       5.8.3.  PUT . . . . . . . . . . . . . . . . . . . . . . . . .  48
       5.8.4.  DELETE  . . . . . . . . . . . . . . . . . . . . . . .  48
     5.9.  Response Code Definitions . . . . . . . . . . . . . . . .  48
       5.9.1.  Success 2.xx  . . . . . . . . . . . . . . . . . . . .  48
       5.9.2.  Client Error 4.xx . . . . . . . . . . . . . . . . . .  50
       5.9.3.  Server Error 5.xx . . . . . . . . . . . . . . . . . .  51
     5.10. Option Definitions  . . . . . . . . . . . . . . . . . . .  52
       5.10.1.  Uri-Host, Uri-Port, Uri-Path, and Uri-Query  . . . .  53
       5.10.2.  Proxy-Uri and Proxy-Scheme . . . . . . . . . . . . .  54
       5.10.3.  Content-Format . . . . . . . . . . . . . . . . . . .  55
       5.10.4.  Accept . . . . . . . . . . . . . . . . . . . . . . .  55
       5.10.5.  Max-Age  . . . . . . . . . . . . . . . . . . . . . .  55
       5.10.6.  ETag . . . . . . . . . . . . . . . . . . . . . . . .  56
       5.10.7.  Location-Path and Location-Query . . . . . . . . . .  57
       5.10.8.  Conditional Request Options  . . . . . . . . . . . .  57
       5.10.9.  Size1 Option . . . . . . . . . . . . . . . . . . . .  59
   6.  CoAP URIs . . . . . . . . . . . . . . . . . . . . . . . . . .  59
     6.1.  coap URI Scheme . . . . . . . . . . . . . . . . . . . . .  59
     6.2.  coaps URI Scheme  . . . . . . . . . . . . . . . . . . . .  60
     6.3.  Normalization and Comparison Rules  . . . . . . . . . . .  61
     6.4.  Decomposing URIs into Options . . . . . . . . . . . . . .  61
     6.5.  Composing URIs from Options . . . . . . . . . . . . . . .  62
   7.  Discovery . . . . . . . . . . . . . . . . . . . . . . . . . .  64
     7.1.  Service Discovery . . . . . . . . . . . . . . . . . . . .  64
     7.2.  Resource Discovery  . . . . . . . . . . . . . . . . . . .  64
       7.2.1.  'ct' Attribute  . . . . . . . . . . . . . . . . . . .  64

   8.  Multicast CoAP  . . . . . . . . . . . . . . . . . . . . . . .  65
     8.1.  Messaging Layer . . . . . . . . . . . . . . . . . . . . .  65
     8.2.  Request/Response Layer  . . . . . . . . . . . . . . . . .  66
       8.2.1.  Caching . . . . . . . . . . . . . . . . . . . . . . .  67
       8.2.2.  Proxying  . . . . . . . . . . . . . . . . . . . . . .  67
   9.  Securing CoAP . . . . . . . . . . . . . . . . . . . . . . . .  68
     9.1.  DTLS-Secured CoAP . . . . . . . . . . . . . . . . . . . .  69
       9.1.1.  Messaging Layer . . . . . . . . . . . . . . . . . . .  70
       9.1.2.  Request/Response Layer  . . . . . . . . . . . . . . .  71
       9.1.3.  Endpoint Identity . . . . . . . . . . . . . . . . . .  71
   10. Cross-Protocol Proxying between CoAP and HTTP . . . . . . . .  74
     10.1.  CoAP-HTTP Proxying . . . . . . . . . . . . . . . . . . .  75
       10.1.1.  GET  . . . . . . . . . . . . . . . . . . . . . . . .  76
       10.1.2.  PUT  . . . . . . . . . . . . . . . . . . . . . . . .  77
       10.1.3.  DELETE . . . . . . . . . . . . . . . . . . . . . . .  77
       10.1.4.  POST . . . . . . . . . . . . . . . . . . . . . . . .  77
     10.2.  HTTP-CoAP Proxying . . . . . . . . . . . . . . . . . . .  77
       10.2.1.  OPTIONS and TRACE  . . . . . . . . . . . . . . . . .  78
       10.2.2.  GET  . . . . . . . . . . . . . . . . . . . . . . . .  78
       10.2.3.  HEAD . . . . . . . . . . . . . . . . . . . . . . . .  79
       10.2.4.  POST . . . . . . . . . . . . . . . . . . . . . . . .  79
       10.2.5.  PUT  . . . . . . . . . . . . . . . . . . . . . . . .  79
       10.2.6.  DELETE . . . . . . . . . . . . . . . . . . . . . . .  80
       10.2.7.  CONNECT  . . . . . . . . . . . . . . . . . . . . . .  80
   11. Security Considerations . . . . . . . . . . . . . . . . . . .  80
     11.1.  Parsing the Protocol and Processing URIs . . . . . . . .  80
     11.2.  Proxying and Caching . . . . . . . . . . . . . . . . . .  81
     11.3.  Risk of Amplification  . . . . . . . . . . . . . . . . .  81
     11.4.  IP Address Spoofing Attacks  . . . . . . . . . . . . . .  83
     11.5.  Cross-Protocol Attacks . . . . . . . . . . . . . . . . .  84
     11.6.  Constrained-Node Considerations  . . . . . . . . . . . .  86
   12. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  86
     12.1.  CoAP Code Registries . . . . . . . . . . . . . . . . . .  86
       12.1.1.  Method Codes . . . . . . . . . . . . . . . . . . . .  87
       12.1.2.  Response Codes . . . . . . . . . . . . . . . . . . .  88
     12.2.  CoAP Option Numbers Registry . . . . . . . . . . . . . .  89
     12.3.  CoAP Content-Formats Registry  . . . . . . . . . . . . .  91
     12.4.  URI Scheme Registration  . . . . . . . . . . . . . . . .  93
     12.5.  Secure URI Scheme Registration . . . . . . . . . . . . .  94
     12.6.  Service Name and Port Number Registration  . . . . . . .  95
     12.7.  Secure Service Name and Port Number Registration . . . .  96
     12.8.  Multicast Address Registration . . . . . . . . . . . . .  97
   13. Acknowledgements  . . . . . . . . . . . . . . . . . . . . . .  97
   14. References  . . . . . . . . . . . . . . . . . . . . . . . . .  98
     14.1.  Normative References . . . . . . . . . . . . . . . . . .  98
     14.2.  Informative References . . . . . . . . . . . . . . . . . 100
   Appendix A.  Examples . . . . . . . . . . . . . . . . . . . . . . 104
   Appendix B.  URI Examples . . . . . . . . . . . . . . . . . . . . 110

1. Introduction โœจ

okay so the whole internet runs on web services (web APIs) now, and that's only possible because of the fundamental Representational State Transfer [REST] architecture of the Web. it's giving foundation ๐Ÿ’…

the CoRE (Constrained RESTful Environments) work is about bringing REST to the most constrained nodes (think 8-bit microcontrollers with limited RAM and ROM ๐Ÿฅบ) and the most constrained networks (like 6LoWPAN, [RFC4944]). and here's the tea: 6LoWPAN supports fragmenting IPv6 packets into tiny link-layer frames, but that causes a big drop in packet delivery probability ๐Ÿ’€. so one of CoAP's design goals was to keep message overhead small, so there's way less need to fragment anything. smart, bestie ๐Ÿงš

the main goal of CoAP is to be a generic web protocol built for the special needs of this constrained world, especially energy, building automation, and other machine-to-machine (M2M) applications ๐Ÿ”‹๐Ÿ . and no, it's not trying to blindly squish HTTP [RFC2616] down. instead it realizes a subset of REST that's shared with HTTP but tuned for M2M. CoAP could be used to glow up simple HTTP interfaces into something more compact, but the real main character moves are the features it brings for M2M: built-in discovery, multicast support, and asynchronous message exchanges ๐Ÿฆ‹โœจ

so this document specifies the Constrained Application Protocol (CoAP). it translates to HTTP really easily, so it plugs right into the existing Web, while still hitting the specialized requirements: multicast support, very low overhead, and simplicity for constrained environments and M2M applications. iconic, honestly ๐Ÿ‘‘

1.1. Features ๐ŸŽ€

CoAP has the following main features, and the vibes are immaculate:

  • Web protocol fulfilling M2M requirements in constrained environments ๐ŸŒธ
  • UDP [RFC0768] binding with optional reliability, supporting unicast and multicast requests ๐Ÿ“ก
  • Asynchronous message exchanges ๐Ÿ’œ
  • Low header overhead and parsing complexity ๐Ÿ“
  • URI and Content-type support ๐ŸŒˆ
  • Simple proxy and caching capabilities ๐Ÿงš
  • A stateless HTTP mapping, allowing proxies to be built that provide access to CoAP resources via HTTP in a uniform way, or for HTTP simple interfaces to be realized alternatively over CoAP ๐Ÿฆ‹
  • Security binding to Datagram Transport Layer Security (DTLS) [RFC6347] ๐Ÿ”๐Ÿ’–

1.2. Terminology ๐Ÿ’…

okay so the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this doc get read the way [RFC2119] describes, but only when they show up in ALL CAPS ๐ŸŽ€ they can also appear in lowercase, and then they don't carry any of that normative meaning โœจ

this spec expects you to already know all the terms and concepts covered in [RFC2616], like "resource", "representation", "cache", and "fresh" ๐Ÿงš it got finished before the updated set of HTTP RFCs (RFC 7230 to RFC 7235) dropped, so it specifically points at the older version, RFC 2616 ๐ŸŒธ on top of that, it defines the following terms:

Endpoint ๐Ÿฆ‹ An entity taking part in the CoAP protocol. People casually say it lives on a "Node", though "Host" would match Internet standards usage better, and it's further identified by transport-layer multiplexing info, which can include a UDP port number and a security association (Section 4.1).

Sender ๐Ÿ’– The originating endpoint of a message. When you care about pinning down exactly which sender it is, it's also called "source endpoint".

Recipient ๐Ÿ’œ The destination endpoint of a message. When the focus is on identifying the specific recipient, it's also called "destination endpoint".

Client ๐Ÿ“ The originating endpoint of a request, and the destination endpoint of a response.

Server ๐Ÿ‘‘ The destination endpoint of a request, and the originating endpoint of a response.

Origin Server ๐Ÿ  The server on which a given resource resides or is to be created.

Intermediary ๐Ÿซถ A CoAP endpoint that acts both as a server and as a client towards an origin server (possibly via further intermediaries). A common form of intermediary is a proxy, and several classes of proxies get discussed in this specification.

Proxy ๐Ÿงš An intermediary that is mainly concerned with forwarding requests and relaying back responses, possibly doing caching, namespace translation, or protocol translation along the way. Unlike intermediaries in the general sense, proxies generally don't implement specific application semantics. Based on where they sit in the overall structure of request forwarding, there are two common forms: forward-proxy and reverse-proxy. In some cases, a single endpoint might act as an origin server, forward-proxy, or reverse-proxy, switching behavior based on the nature of each request โœจ

Forward-Proxy ๐ŸŒˆ An endpoint selected by a client, usually through local configuration rules, to perform requests on behalf of that client, doing any necessary translations. Some translations are minimal, like proxy requests for coap URIs, whereas other requests might need translation to and from entirely different application-layer protocols.

Reverse-Proxy ๐Ÿ›ก๏ธ An endpoint that stands in for one or more other servers and satisfies requests on their behalf, doing any necessary translations. Unlike a forward-proxy, the client may not be aware that it's talking to a reverse-proxy, since a reverse-proxy receives requests as if it were the origin server for the target resource ๐Ÿ‘€

CoAP-to-CoAP Proxy ๐Ÿ” A proxy that maps from a CoAP request to a CoAP request, i.e., it uses the CoAP protocol on both the server and the client side. Contrast this with cross-proxy.

Cross-Proxy ๐ŸŒ A cross-protocol proxy, or "cross-proxy" for short, is a proxy that translates between different protocols, like a CoAP-to-HTTP proxy or an HTTP-to-CoAP proxy. While this specification makes very specific demands of CoAP-to-CoAP proxies, there's more variation possible in cross-proxies.

Confirmable Message ๐Ÿ“ฌ Some messages require an acknowledgement, and these are called "Confirmable". When no packets are lost, each Confirmable message gets exactly one return message of type Acknowledgement or type Reset.

Non-confirmable Message ๐Ÿƒ Some other messages don't require an acknowledgement. This is especially true for messages that get repeated regularly for application requirements, like repeated readings from a sensor ๐ŸŒก๏ธ

Acknowledgement Message โœ… An Acknowledgement message says that a specific Confirmable message arrived. By itself, it doesn't indicate success or failure of any request encapsulated in the Confirmable message, but it may also carry a Piggybacked Response (see below).

Reset Message ๐Ÿ”„ A Reset message says that a specific message (Confirmable or Non-confirmable) was received, but some context is missing to properly process it. This usually happens when the receiving node has rebooted and forgotten some state it needs to interpret the message ๐Ÿฅฒ Provoking a Reset message (e.g., by sending an Empty Confirmable message) is also useful as a cheap check on whether an endpoint is alive, which is called a "CoAP ping" ๐Ÿ“

Piggybacked Response ๐ŸŽ A piggybacked Response rides right inside a CoAP Acknowledgement (ACK) message that's sent to acknowledge receipt of the Request for this Response (Section 5.2.1). so cute, one trip ๐Ÿซ 

Separate Response ๐Ÿ“ฆ When a Confirmable message carrying a request gets acknowledged with an Empty message (e.g., because the server doesn't have the answer right away), a Separate Response gets sent in its own separate message exchange (Section 5.2.2).

Empty Message ๐Ÿซฅ A message with a Code of 0.00, which is neither a request nor a response. An Empty message only contains the 4-byte header.

Critical Option โš ๏ธ An option that the endpoint ultimately receiving the message would need to understand in order to properly process the message (Section 5.4.1). Note that critical options are, as the name "Option" implies, generally optional: unsupported critical options lead to an error response or summary rejection of the message ๐Ÿ’€

Elective Option ๐ŸŒท An option that's intended to be ignored by an endpoint that doesn't understand it. Processing the message even without understanding the option is acceptable (Section 5.4.1).

Unsafe Option ๐Ÿšจ An option that a proxy receiving the message would need to understand in order to safely forward the message (Section 5.4.2). Not every critical option is an unsafe option.

Safe-to-Forward Option ๐Ÿš€ An option that's intended to be safe for forwarding by a proxy that doesn't understand it. Forwarding the message even without understanding the option is acceptable (Section 5.4.2).

Resource Discovery ๐Ÿ” The process where a CoAP client queries a server for its list of hosted resources (i.e., links as defined in Section 7).

Content-Format ๐Ÿงพ The combination of an Internet media type, potentially with specific parameters given, and a content-coding (which is often the identity content-coding). It's identified by a numeric identifier defined by the "CoAP Content-Formats" registry. When the focus is less on the numeric identifier and more on the combination of these characteristics of a resource representation, it's also called "representation format" ๐Ÿ’…

additional terminology for constrained nodes and constrained-node networks lives in [RFC7228] ๐ŸŒฟ

in this spec, "byte" is used in its now customary sense as a synonym for "octet" โœจ

all multi-byte integers in this protocol are interpreted in network byte order ๐Ÿ”ข

and where arithmetic shows up, this spec uses the notation you'd recognize from the programming language C, except that the operator ** stands for exponentiation ๐Ÿงฎ


2. Constrained Application Protocol ๐Ÿฆ‹

the interaction model of CoAP is similar to the client/server model of HTTP. BUT machine-to-machine interactions typically end up with a CoAP implementation acting in both the client and server roles ๐Ÿค– A CoAP request is equivalent to an HTTP one and gets sent by a client to request an action (using a Method Code) on a resource (identified by a URI) on a server. The server then sends back a response with a Response Code, and this response may include a resource representation ๐Ÿ’Œ

Hmm, "BUT" is not a keyword, but let me avoid all caps accidentally, so I'll correct: the interaction model of CoAP is similar to the client/server model of HTTP. However, machine-to-machine interactions typically end up with a CoAP implementation acting in both the client and server roles ๐Ÿค– A CoAP request is equivalent to an HTTP one and gets sent by a client to request an action (using a Method Code) on a resource (identified by a URI) on a server. The server then sends back a response with a Response Code, and this response may include a resource representation ๐Ÿ’Œ

unlike HTTP, CoAP handles these exchanges asynchronously over a datagram-oriented transport like UDP ๐Ÿ“ก It does this logically using a layer of messages that supports optional reliability (with exponential back-off) โณ CoAP defines four types of messages: Confirmable, Non-confirmable, Acknowledgement, and Reset. Method Codes and Response Codes included in some of these messages make them carry requests or responses. The basic exchanges of the four message types are somewhat orthogonal to the request/response interactions. Requests can be carried in Confirmable and Non-confirmable messages, and responses can be carried in these too, as well as piggybacked in Acknowledgement messages ๐Ÿงฉ

one could think of CoAP logically as a two-layer approach: a CoAP messaging layer that deals with UDP and the asynchronous nature of the interactions, plus the request/response interactions using Method and Response Codes (see Figure 1) ๐Ÿฐ CoAP is however a single protocol, with messaging and request/response as just features of the CoAP header ๐Ÿ’–

                    +----------------------+
                    |      Application     |
                    +----------------------+
                    +----------------------+  \
                    |  Requests/Responses  |  |
                    |----------------------|  | CoAP
                    |       Messages       |  |
                    +----------------------+  /
                    +----------------------+
                    |          UDP         |
                    +----------------------+

Figure 1: Abstract Layering of CoAP ๐Ÿ–ผ๏ธ

2.1. Messaging Model ๐Ÿ’Œ

okay so the CoAP messaging model is all about trading messages over UDP between endpoints ๐Ÿ“จโœจ

CoAP uses a short, fixed-length binary header (4 bytes) ๐ŸŽ€ that can be followed by compact binary options and a payload. The same message format is used for both requests and responses. The full message format is in Section 3. Every message carries a Message ID, which is used to detect duplicates and for optional reliability. (The Message ID is compact, and its 16-bit size lets one endpoint send up to about 250 messages per second to another with the default protocol parameters ๐Ÿงš)

Reliability comes from marking a message as Confirmable (CON) ๐Ÿซถ. A Confirmable message gets retransmitted using a default timeout and exponential back-off between retransmissions, until the recipient sends back an Acknowledgement message (ACK) with the same Message ID (in this example, 0x7d34) from the matching endpoint. Check out Figure 2 ๐Ÿ’…. When a recipient can't process a Confirmable message at all (meaning it can't even send a suitable error response), it replies with a Reset message (RST) instead of an Acknowledgement (ACK) ๐Ÿ’€.

                     Client              Server
                        |                  |
                        |   CON [0x7d34]   |
                        +----------------->|
                        |                  |
                        |   ACK [0x7d34]   |
                        |<-----------------+
                        |                  |

Figure 2: Reliable Message Transmission

A message that doesn't need reliable delivery (like one single reading out of a stream of sensor data) can be sent as a Non-confirmable message (NON) ๐ŸŒธ. These don't get acknowledged, but they still have a Message ID for duplicate detection (in this example, 0x01a0). See Figure 3 โœจ. When a recipient can't process a Non-confirmable message, it may reply with a Reset message (RST).

                     Client              Server
                        |                  |
                        |   NON [0x01a0]   |
                        +----------------->|
                        |                  |

Figure 3: Unreliable Message Transmission

For details on CoAP messages, see Section 4 ๐Ÿ“–.

Since CoAP runs over UDP, it can also use multicast IP destination addresses, which means multicast CoAP requests are a thing ๐Ÿฆ‹. Section 8 covers how to use CoAP messages with multicast addresses properly, plus precautions for avoiding response congestion.

Several security modes are defined for CoAP in Section 9, ranging from no security at all to certificate-based security ๐Ÿ”. This document specifies a binding to DTLS for securing the protocol. The use of IPsec with CoAP is discussed in [IPsec-CoAP].

2.2. Request/Response Model ๐ŸŽ€

CoAP request and response semantics ride along in CoAP messages. Those messages include either a Method Code or a Response Code, depending on which side is talking ๐Ÿ’ฌ. Optional (or default) request and response info, like the URI and payload media type, gets carried as CoAP options. A Token is used to match responses to requests, separately from the underlying messages (Section 5.3). (The Token is its own concept, totally separate from the Message ID, so don't mix them up ๐Ÿ™ˆ)

A request goes out in a Confirmable (CON) or Non-confirmable (NON) message. If the response to a request sent in a Confirmable message is immediately available, it comes back inside the resulting Acknowledgement (ACK) message. This is called a piggybacked response, and Section 5.2.1 has the details ๐Ÿฅฐ. (There's no need to separately acknowledge a piggybacked response, because the client will retransmit the request if the Acknowledgement carrying the piggybacked response gets lost.) Figure 4 shows two basic GET requests with piggybacked responses: one succeeds, and one comes back as a 4.04 (Not Found) ๐Ÿ™ˆ.

     Client              Server       Client              Server
        |                  |             |                  |
        |   CON [0xbc90]   |             |   CON [0xbc91]   |
        | GET /temperature |             | GET /temperature |
        |   (Token 0x71)   |             |   (Token 0x72)   |
        +----------------->|             +----------------->|
        |                  |             |                  |
        |   ACK [0xbc90]   |             |   ACK [0xbc91]   |
        |   2.05 Content   |             |  4.04 Not Found  |
        |   (Token 0x71)   |             |   (Token 0x72)   |
        |     "22.5 C"     |             |   "Not found"    |
        |<-----------------+             |<-----------------+
        |                  |             |                  |

Figure 4: Two GET Requests with Piggybacked Responses

If the server can't respond right away to a request in a Confirmable message, it just sends back an Empty Acknowledgement message so the client can stop retransmitting the request ๐Ÿ›‘. When the response is ready, the server sends it in a brand-new Confirmable message, which the client then needs to acknowledge in turn ๐Ÿ”. This is called a "separate response", and it's shown in Figure 5 and explained further in Section 5.2.2 โณ.

                     Client              Server
                        |                  |
                        |   CON [0x7a10]   |
                        | GET /temperature |
                        |   (Token 0x73)   |
                        +----------------->|
                        |                  |
                        |   ACK [0x7a10]   |
                        |<-----------------+
                        |                  |
                        ... Time Passes  ...
                        |                  |
                        |   CON [0x23bb]   |
                        |   2.05 Content   |
                        |   (Token 0x73)   |
                        |     "22.5 C"     |
                        |<-----------------+
                        |                  |
                        |   ACK [0x23bb]   |
                        +----------------->|
                        |                  |

Figure 5: A GET Request with a Separate Response

If a request is sent in a Non-confirmable message, the response goes back in a new Non-confirmable message. That said, the server may instead send a Confirmable message ๐Ÿคทโ€โ™€๏ธ. Figure 6 shows this kind of exchange.

                     Client              Server
                        |                  |
                        |   NON [0x7a11]   |
                        | GET /temperature |
                        |   (Token 0x74)   |
                        +----------------->|
                        |                  |
                        |   NON [0x23bc]   |
                        |   2.05 Content   |
                        |   (Token 0x74)   |
                        |     "22.5 C"     |
                        |<-----------------+
                        |                  |

Figure 6: A Request and a Response Carried in Non-confirmable Messages

CoAP uses GET, PUT, POST, and DELETE in a similar way to HTTP, and the semantics are in Section 5.8 ๐Ÿ’…. (Heads up, the detailed semantics of CoAP methods are "almost, but not entirely unlike" [HHGTTG] those of HTTP methods ๐ŸŒŒ. Intuition from HTTP experience generally does apply well, but there are enough differences that it's worth actually reading this spec.)

Methods beyond the basic four can be added to CoAP in separate specifications. New methods don't necessarily have to work in request/response pairs. Even for existing methods, a single request can produce multiple responses, for example with a multicast request (Section 8) or with the Observe option [OBSERVE] ๐Ÿ‘€.

URI support in a server is simplified, because the client already parses the URI and splits it into host, port, path, and query components, using default values for efficiency โšก. Response Codes relate to a small subset of HTTP status codes, plus a few CoAP-specific codes, as defined in Section 5.9 ๐Ÿ“.

2.3. Intermediaries and Caching ๐Ÿง

The protocol supports caching responses so requests can be fulfilled efficiently ๐Ÿ’œ. Simple caching is enabled through freshness and validity information carried with CoAP responses. A cache can live in an endpoint or in an intermediary. Caching functionality is specified in Section 5.6.

Proxying is useful in constrained networks for a bunch of reasons: limiting network traffic, improving performance, accessing resources on sleeping devices, and security ๐Ÿ”’. Proxying requests on behalf of another CoAP endpoint is supported by the protocol. When using a proxy, the URI of the resource to request is included in the request, while the destination IP address is set to the proxy's address. Section 5.7 has more on proxy functionality.

CoAP was designed according to the REST architecture [REST], so it has functionality similar to HTTP. That makes it pretty straightforward to map CoAP to HTTP and HTTP to CoAP ๐ŸŒˆ. Such a mapping can realize an HTTP REST interface using CoAP, or convert between HTTP and CoAP. The conversion can be done by a cross-protocol proxy ("cross-proxy"), which converts the Method or Response Code, media type, and options into the matching HTTP feature. Section 10 has more detail about HTTP mapping.

2.4. Resource Discovery ๐Ÿ”

Resource discovery matters a lot for machine-to-machine interactions, and it's supported using the CoRE Link Format [RFC6690], as discussed in Section 7 ๐Ÿซง.

3. Message Format ๐Ÿ“ฆโœจ

okay bestie, this is where the actual packets come in ๐Ÿซถ CoAP messages are super compact and by default they ride over UDP, so each CoAP message fills the data section of one UDP datagram ๐Ÿฆ‹ You can also run CoAP over Datagram Transport Layer Security (DTLS), which is covered in Section 9.1 ๐Ÿ’œ It could also work over other transports like SMS, TCP, or SCTP, but those are out of scope for this doc ๐Ÿ™ˆ Also, UDP-lite [RFC3828] and the UDP zero checksum [RFC6936] are NOT supported by CoAP ๐Ÿ’€

Every CoAP message is encoded in a simple binary format. It starts with a fixed-size 4-byte header, then a variable-length Token value that can be between 0 and 8 bytes long ๐ŸŽ€

After the Token comes zero or more CoAP Options, in Type-Length-Value (TLV) format. A payload can follow them, and it takes up the rest of the datagram ๐ŸŒธ

 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Ver| T |  TKL  |      Code     |          Message ID           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Token (if any, TKL bytes) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Options (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 1 1 1 1 1 1 1|    Payload (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                      Figure 7: Message Format

Here's the header breakdown, bestie ๐Ÿ‘‘

  • Version (Ver): 2-bit unsigned integer that shows the CoAP version number. Implementations of this spec MUST set this field to 1 (01 binary). Other values are reserved for future versions. Messages with unknown version numbers MUST be silently ignored ๐Ÿ™ˆ
  • Type (T): 2-bit unsigned integer that tells you if the message is Confirmable (0), Non-confirmable (1), Acknowledgement (2), or Reset (3). The semantics for these message types are in Section 4 ๐Ÿฆ‹
  • Token Length (TKL): 4-bit unsigned integer for the length of the Token field (0-8 bytes). Lengths 9-15 are reserved, MUST NOT be sent, and MUST be processed as a message format error. not me reading that and going "absolutely not" ๐Ÿ˜ญ
  • Code: 8-bit unsigned integer, split into a 3-bit class (the most significant bits) and a 5-bit detail (the least significant bits). It's written as "c.dd", where "c" is a digit from 0 to 7 and "dd" is two digits from 00 to 31. The class can mean a request (0), a success response (2), a client error response (4), or a server error response (5). All other class values are reserved. Code 0.00 is a special case that means an Empty message. For requests, the Code field is the Request Method. For responses, it's a Response Code. Possible values live in the CoAP Code Registries (Section 12.1), and the semantics of requests and responses are in Section 5 ๐ŸŒˆ
  • Message ID: 16-bit unsigned integer in network byte order. It's used to detect duplicate messages and to match Acknowledgement/Reset messages to Confirmable/Non-confirmable ones. The rules for generating a Message ID and matching messages are in Section 4 โœจ

The Token value follows the header, and its size comes from the Token Length field (0 to 8 bytes). The Token is how requests and responses get correlated, and the rules for generating a Token and correlating them are in Section 5.3.1 ๐Ÿ’…

Header and Token are followed by zero or more Options (Section 3.1). An Option can be followed by the end of the message, by another Option, or by the Payload Marker and the payload ๐ŸŽ€

After the header, token, and options (if there are any), there's the optional payload. If it's there and has non-zero length, it gets a fixed, one-byte Payload Marker (0xFF) in front. The marker is how you know the options are done and the payload starts ๐Ÿซถ The payload data runs from right after the marker to the end of the UDP datagram, so the Payload Length gets calculated from the datagram size ๐ŸŒธ No marker means a zero-length payload. A marker followed by a zero-length payload MUST be processed as a message format error ๐Ÿ’€

Implementation Note: the byte value 0xFF can also show up inside an option length or value, so you can't just scan bytes for 0xFF to find the payload marker. 0xFF only counts as a payload marker where the start of another option could happen ๐Ÿ™ˆ

3.1. Option Format

CoAP defines a bunch of options that can go in a message. Each option instance says which Option Number it is, how long its Option Value is, and what that Option Value is ๐Ÿงš

Here's the twist: the instances MUST appear in order of their Option Numbers, and they use delta encoding between them. Each instance's Option Number is its delta added to the Option Number of the instance before it in the message. For the first instance, the one before it is assumed to be Option Number zero. You can include multiple instances of the same option by using a delta of zero ๐ŸŒˆ

Option Numbers are kept in the "CoAP Option Numbers" registry (Section 12.2). For the semantics of the options defined in this document, check Section 5.4 ๐Ÿ’–

 0   1   2   3   4   5   6   7
+---------------+---------------+
|               |               |
|  Option Delta | Option Length |   1 byte
|               |               |
+---------------+---------------+
\                               \
/         Option Delta          /   0-2 bytes
\          (extended)           \
+-------------------------------+
\                               \
/         Option Length         /   0-2 bytes
\          (extended)           \
+-------------------------------+
\                               \
/                               /
\                               \
/         Option Value          /   0 or more bytes
\                               \
/                               /
\                               \
+-------------------------------+

                      Figure 8: Option Format

Here are the fields in an option ๐Ÿฆ‹

  • Option Delta: 4-bit unsigned integer. A value from 0 to 12 is the Option Delta itself. Three values are reserved for special constructs:
    • 13: an 8-bit unsigned integer follows the initial byte and holds the Option Delta minus 13.
    • 14: a 16-bit unsigned integer in network byte order follows the initial byte and holds the Option Delta minus 269.
    • 15: reserved for the Payload Marker. If the field is set to this value but the whole byte isn't the payload marker, it MUST be processed as a message format error.

The resulting Option Delta is the gap between this option's Option Number and the previous one's (or zero for the first option). Basically, the Option Number is just all the Option Deltas of this option and every option before it, summed up ๐Ÿงฎ

  • Option Length: 4-bit unsigned integer. A value from 0 to 12 is the length of the Option Value in bytes. Three values are reserved for special constructs:
    • 13: an 8-bit unsigned integer comes before the Option Value and holds the Option Length minus 13.
    • 14: a 16-bit unsigned integer in network byte order comes before the Option Value and holds the Option Length minus 269.
    • 15: reserved for future use. If the field is set to this value, it MUST be processed as a message format error.
  • Value: a sequence of exactly Option Length bytes. The length and format of the Option Value depend on the option, and it MAY define variable-length values. Section 3.2 has the formats used in this document. Options defined in other documents MAY use other option value formats ๐ŸŒธ

3.2. Option Value Formats

The options defined in this document use the following option value formats ๐Ÿ’…

  • empty: a zero-length sequence of bytes.
  • opaque: an opaque sequence of bytes.
  • uint: a non-negative integer, represented in network byte order using however many bytes the Option Length field says. An option definition can specify a range of allowed byte counts. If there's a choice, a sender SHOULD represent the integer with as few bytes as possible, meaning no leading zero bytes. For example, the number 0 is an empty option value (zero-length), and the number 1 is a single byte with the value 1 (bit combination 00000001, most significant bit first). A recipient MUST be prepared to process values with leading zero bytes ๐Ÿง 
Implementation Note: the exception allowed for senders is meant for highly constrained, templated implementations (like hardware ones) that use fixed-size options in their templates ๐Ÿค–
  • string: a Unicode string encoded in UTF-8 [RFC3629] in Net-Unicode form [RFC5198] ๐ŸŒˆ

Here's the vibe: wherever UTF-8 encoding shows up in CoAP, the encoded strings can be used and compared directly as opaque byte strings by CoAP implementations. There's no expectation or need to normalize inside a CoAP implementation, except when Unicode strings that aren't known to be normalized get imported from sources outside CoAP. Also, ASCII strings (without special control characters) are always valid UTF-8 Net-Unicode strings โœจ

4. Message Transmission ๐Ÿš€

CoAP messages get exchanged asynchronously between CoAP endpoints. They carry CoAP requests and responses, whose semantics are in Section 5 ๐Ÿ’–

Since CoAP sits on unreliable transports like UDP, CoAP messages may arrive out of order, show up duplicated, or just vanish without notice ๐Ÿ˜ญ So CoAP has a lightweight reliability mechanism, and it doesn't try to rebuild everything TCP does. It has these features:

  • Simple stop-and-wait retransmission reliability with exponential back-off for Confirmable messages.
  • Duplicate detection for both Confirmable and Non-confirmable messages.

4.1. Messages and Endpoints โœจ

okay so a CoAP endpoint is just whatever is the source or destination of a CoAP message ๐Ÿ’– what counts as an endpoint depends on the transport you're using. for the transports in this spec, it depends on the security mode (see Section 9) ๐Ÿ”. with no security, an endpoint is literally just an IP address plus a UDP port number ๐Ÿฆ‹. with other security modes, it's identified however that security mode defines it ๐Ÿ’…

there are different types of messages, and the Type field in the CoAP Header tells you which one you've got ๐ŸŽ€

separate from the type, a message can carry a request, carry a response, or be Empty ๐ŸŒธ that's signaled by the Request/Response Code field in the CoAP Header, and it's the bit that matters for the request/response model ๐Ÿซถ the possible values live in the CoAP Code Registries (Section 12.1) ๐Ÿ“š

an Empty message has the Code field set to 0.00 ๐Ÿงš the Token Length field MUST be set to 0, and bytes of data MUST NOT show up after the Message ID field ๐Ÿ™ˆ if there are any bytes there anyway, they MUST be processed as a message format error ๐Ÿ’€

4.2. Messages Transmitted Reliably ๐Ÿ”

so reliable transmission starts when you mark a message as Confirmable in the CoAP header ๐Ÿ’– a Confirmable message always carries either a request or a response, unless it's only there to get a Reset message back, in which case it's Empty ๐Ÿงš

here's the big rule: a recipient MUST either (a) acknowledge the Confirmable message with an Acknowledgement message, or (b) reject it if the recipient doesn't have the context to process it properly โœจ that includes when the message is Empty, uses a code from a reserved class (1, 6, or 7), or has a message format error ๐Ÿ˜ญ rejecting a Confirmable message means sending a matching Reset message and otherwise ignoring it ๐Ÿ™ˆ

the Acknowledgement message MUST echo the Message ID of the Confirmable message, and it MUST carry a response or be Empty (see Sections 5.2.1 and 5.2.2) ๐ŸŽ€ the Reset message MUST echo the Message ID of the Confirmable message, and it MUST be Empty ๐ŸŒˆ

rejecting an Acknowledgement or Reset message (including when the Acknowledgement carries a request or a code with a reserved class, or when the Reset message isn't Empty) just means silently ignoring it ๐Ÿคซ and more generally, recipients of Acknowledgement and Reset messages MUST NOT respond with either an Acknowledgement or a Reset message ๐Ÿ™…โ€โ™€๏ธ no ping-pong, bestie ๐Ÿ’…

the sender keeps retransmitting the Confirmable message at exponentially increasing intervals ๐Ÿ“ˆ until it gets an acknowledgement (or a Reset message), or it runs out of attempts ๐Ÿฅฒ

retransmission is controlled by two things that a CoAP endpoint MUST keep track of for each Confirmable message it sends while it's waiting for an acknowledgement (or reset) ๐Ÿ“‹ those are a timeout and a retransmission counter ๐Ÿ’œ for a brand new Confirmable message, the initial timeout is set to a random duration (often not a whole number of seconds) between ACK_TIMEOUT and (ACK_TIMEOUT * ACK_RANDOM_FACTOR) (see Section 4.8), and the retransmission counter starts at 0 ๐ŸŽฒ when the timeout triggers and the retransmission counter is less than MAX_RETRANSMIT, the message gets retransmitted, the counter goes up by one, and the timeout doubles โซ if the counter hits MAX_RETRANSMIT on a timeout, or the endpoint gets a Reset message, then the attempt is canceled and the application process is told it failed ๐Ÿ’” but if the endpoint gets an acknowledgement in time, the transmission counts as successful ๐ŸŽ‰

this spec doesn't make strong demands on how accurate the clocks are that run that binary exponential back-off algorithm โฐ an endpoint might be late for a specific retransmission because of its sleep schedule and then catch up on the next one ๐Ÿ˜ด still, the minimum gap before another retransmission is ACK_TIMEOUT, and the whole sequence of (re-)transmissions MUST stay inside the envelope of MAX_TRANSMIT_SPAN (see Section 4.8.2), even if that means the sender misses a chance to transmit โณ no cap, that's a hard boundary ๐Ÿšง

a CoAP endpoint that sent a Confirmable message MAY give up on getting an ACK even before the MAX_RETRANSMIT counter value is reached ๐Ÿณ๏ธ for example, the application canceled the request because it doesn't need a response anymore, or there's some other sign that the CON message did arrive ๐Ÿ“ฌ especially when a CoAP request got a separate response, the requester knows only the ACK got lost, so retransmitting the request wouldn't do anything ๐Ÿ™„ but a responder MUST NOT rely on this cross-layer behavior from a requester ๐Ÿšซ it MUST keep the state needed to create the ACK for the request, if needed, even when the requester already acknowledged a Confirmable response ๐Ÿง  main character responder energy ๐Ÿ‘‘

another reason to stop retransmitting MAY be receiving ICMP errors ๐Ÿ‘€ if you do want to take ICMP errors into account (to guard against potential spoofing attacks ๐Ÿ•ต๏ธ), implementations SHOULD carefully check the information about the original datagram inside the ICMP message, including port numbers and CoAP header info like message type and code, Message ID, and Token ๐Ÿ” if that's not possible because of limits in the UDP service API, ICMP errors SHOULD be ignored ๐Ÿ™ˆ

Packet Too Big errors [RFC4443] ("fragmentation needed and DF set" for IPv4 [RFC0792]) cannot properly occur, and they SHOULD be ignored if the implementation note in Section 4.6 is followed ๐Ÿซ  otherwise, they SHOULD feed into a path MTU discovery algorithm [RFC4821] ๐Ÿ›ค๏ธ Source Quench and Time Exceeded ICMP messages SHOULD be ignored too ๐Ÿ™…โ€โ™€๏ธ and host, network, port, or protocol unreachable errors or parameter problem errors MAY, after appropriate vetting, be used to tell the application that sending failed ๐Ÿ“ฃ

4.3. Messages Transmitted without Reliability ๐Ÿฆ‹

not every message needs an acknowledgement ๐Ÿ’… this is super true for messages that get repeated regularly for application needs, like repeated sensor readings where eventual success is totally fine ๐ŸŒก๏ธโœจ

as a more lightweight option, you can send a message less reliably by marking it Non-confirmable ๐Ÿชถ a Non-confirmable message always carries a request or response, and it MUST NOT be Empty ๐Ÿ™…โ€โ™€๏ธ a Non-confirmable message MUST NOT be acknowledged by the recipient ๐Ÿšซ a recipient MUST reject the message if it doesn't have the context to process it properly, including when the message is Empty, uses a code from a reserved class (1, 6, or 7), or has a message format error ๐Ÿ’€ rejecting a Non-confirmable message MAY involve sending a matching Reset message, but apart from that Reset message, the rejected message MUST be silently ignored ๐Ÿคซ

at the CoAP level, the sender has no way of knowing whether a Non-confirmable message was received ๐Ÿซฅ a sender MAY choose to send multiple copies of a Non-confirmable message within MAX_TRANSMIT_SPAN (limited by the rules in Section 4.7, especially PROBING_RATE if no response comes back) ๐Ÿ” or the network might duplicate the message in transit ๐Ÿ‘ฏ so that the receiver only acts on the message once, Non-confirmable messages also get a Message ID ๐ŸŽ€ (this Message ID comes from the same number space as the Message IDs for Confirmable messages ๐Ÿ”ข)

quick recap of Sections 4.2 and 4.3: the four message types can be used like in Table 1 ๐Ÿ“Š a "*" means the combo isn't used in normal operation and is only there to get a Reset message back (a "CoAP ping") ๐Ÿ“

                   +----------+-----+-----+-----+-----+
                   |          | CON | NON | ACK | RST |
                   +----------+-----+-----+-----+-----+
                   | Request  | X   | X   | -   | -   |
                   | Response | X   | X   | X   | -   |
                   | Empty    | *   | -   | X   | X   |
                   +----------+-----+-----+-----+-----+

                      Table 1: Usage of Message Types

4.4. Message Correlation ๐Ÿ”—

an Acknowledgement or Reset message gets matched up with a Confirmable or Non-confirmable message using the Message ID, plus the address info of the corresponding endpoint ๐Ÿ—บ๏ธ the Message ID is a 16-bit unsigned integer generated by the sender of a Confirmable or Non-confirmable message and included in the CoAP header ๐Ÿ”ข the Message ID MUST be echoed in the Acknowledgement or Reset message by the recipient ๐Ÿชž

the same Message ID MUST NOT be reused (when talking to the same endpoint) within the EXCHANGE_LIFETIME (Section 4.8.2) โณ no recycling IDs too early, periodt ๐Ÿ’…

Implementation Note: there are a few ways to generate Message IDs ๐Ÿง  in the simplest case, a CoAP endpoint keeps one Message ID variable and changes it every time it sends a new Confirmable or Non-confirmable message, no matter the destination address or port ๐ŸŽฏ endpoints handling tons of transactions could keep multiple Message ID variables, for example one per prefix or destination address ๐Ÿ“ฆ (heads up: some receiving endpoints might not be able to tell unicast and multicast packets addressed to them apart, so endpoints generating Message IDs need to make sure those don't overlap โš ๏ธ) it is strongly recommended that the initial value of the variable (e.g., on startup) be randomized, so successful off-path attacks on the protocol are less likely ๐ŸŽฒ๐Ÿ”

for an Acknowledgement or Reset message to match a Confirmable or Non-confirmable message, the Message ID and source endpoint of the Acknowledgement or Reset message MUST match the Message ID and destination endpoint of the Confirmable or Non-confirmable message ๐Ÿ’œ perfect match or no match, bestie โœจ

4.5. Message Deduplication ๐Ÿ’–

okay so bestie, a recipient can get the same Confirmable message (same Message ID and source endpoint) more than once inside the EXCHANGE_LIFETIME (Section 4.8.2) ๐Ÿ˜ญ This happens when the Acknowledgement went missing, or didn't reach the original sender before the first timeout. The recipient SHOULD acknowledge each duplicate copy using the same Acknowledgement or Reset message, but it SHOULD process any request or response in the message only once โœจ This rule MAY be relaxed if the Confirmable message carries a request that is idempotent (see Section 5.1) or can be handled in an idempotent fashion. Here are some examples of relaxed deduplication ๐Ÿฆ‹

  • A server might relax the requirement to answer all retransmissions of an idempotent request with the same response (Section 4.2), so that it doesn't have to keep state for Message IDs. For example, an implementation might want to process duplicate transmissions of a GET, PUT, or DELETE request as separate requests, if the effort of duplicate processing is less expensive than keeping track of previous responses would be. ๐Ÿงš
  • A constrained server might even want to relax this requirement for certain non-idempotent requests, if the application semantics make this trade-off favorable. For example, if the result of a POST request is just the creation of some short-lived state at the server, it may be less expensive to pay this effort multiple times than to keep track of whether a previous transmission of the same request was already processed ๐Ÿ’…

A recipient might receive the same Non-confirmable message (same Message ID and source endpoint) multiple times within NON_LIFETIME (Section 4.8.2). As a general rule that MAY be relaxed based on the specific semantics of a message, the recipient SHOULD silently ignore any duplicated Non-confirmable message, and SHOULD process any request or response in the message only once ๐ŸŒธ

4.6. Message Size ๐ŸŽ€

okay this one is giving "it depends on your link layer" ๐Ÿ™ˆ Specific link layers make it beneficial to keep CoAP messages small enough to fit into their link-layer packets (see Section 1), but honestly this is a matter of implementation quality. The CoAP specification itself only gives an upper bound to the message size. Messages bigger than an IP packet cause undesirable packet fragmentation ๐Ÿ’€ A CoAP message, appropriately encapsulated, SHOULD fit within a single IP packet (so, avoid IP fragmentation), and (by fitting into one UDP payload) obviously needs to fit within a single IP datagram. If the Path MTU isn't known for a destination, an IP MTU of 1280 bytes SHOULD be assumed. If nothing is known about the size of the headers, good upper bounds are 1152 bytes for the message size and 1024 bytes for the payload size โœจ

Implementation Note: CoAP's choice of message size parameters works really well with IPv6 and with most of today's IPv4 paths ๐Ÿ’– (However, with IPv4 it's harder to absolutely ensure there is no IP fragmentation. If IPv4 support on unusual networks is a consideration, implementations may want to limit themselves to more conservative IPv4 datagram sizes such as 576 bytes. Per [RFC0791], the absolute minimum value of the IP MTU for IPv4 is as low as 68 bytes, which would leave only 40 bytes minus security overhead for a UDP payload. Implementations extremely focused on this problem might also set the IPv4 DF bit and perform some form of path MTU discovery [RFC4821]; this should generally be unnecessary in realistic use cases for CoAP, however.) A more important kind of fragmentation in many constrained networks happens on the adaptation layer (e.g., 6LoWPAN L2 packets are limited to 127 bytes including various overheads). This may motivate implementations to be frugal in their packet sizes and to move to block-wise transfers [BLOCK] when approaching three-digit message sizes ๐Ÿงš

Message sizes matter a lot to implementations on constrained nodes too ๐Ÿฅบ Many implementations need to allocate a buffer for incoming messages. If an implementation is too constrained to allocate the upper bound above, it could apply the following strategy for messages not using DTLS security. Implementations that receive a datagram into a buffer that is too small are usually able to tell whether the trailing part of the datagram was discarded, and to retrieve the initial part. So at least the CoAP header and options, if not all of the payload, are likely to fit within the buffer. A server can therefore fully interpret a request and return a 4.13 (Request Entity Too Large; see Section 5.9.2.9) Response Code if the payload was truncated. A client sending an idempotent request, and receiving a response larger than would fit in the buffer, can repeat the request with a suitable value for the Block Option [BLOCK] ๐Ÿซถ

4.7. Congestion Control ๐ŸŒˆ

basic congestion control for CoAP comes from the exponential back-off mechanism in Section 4.2 ๐Ÿ”ฅ

So in order not to cause congestion, clients (including proxies) MUST strictly limit the number of simultaneous outstanding interactions they maintain to a given server (including proxies) to NSTART ๐Ÿ™…โ€โ™€๏ธ An outstanding interaction is either a CON for which an ACK has not yet been received but is still expected (message layer), or a request for which neither a response nor an Acknowledgment message has been received yet but is still expected. These two can both happen at the same time, and they count as one outstanding interaction. The default value of NSTART for this specification is 1 โญ

More congestion control optimizations and considerations are expected in the future. They may, for example, provide automatic initialization of the CoAP transmission parameters defined in Section 4.8, and thus may allow a value for NSTART greater than one ๐Ÿ‘‘

After EXCHANGE_LIFETIME, a client stops expecting a response to a Confirmable request for which no acknowledgment message was received ๐Ÿฆ‹

The specific algorithm by which a client stops "expecting" a response to a Confirmable request that was acknowledged, or to a Non-confirmable request, is not defined. Unless this is modified by additional congestion control optimizations, it MUST be chosen so that an endpoint does not exceed an average data rate of PROBING_RATE when sending to another endpoint that does not respond ๐Ÿ’œ

Note: CoAP puts the onus of congestion control mostly on the clients. But clients may malfunction or actually be attackers, e.g., to perform amplification attacks (Section 11.3). To limit the damage (to the network and to its own energy resources), a server SHOULD implement some rate limiting for its response transmission, based on reasonable assumptions about application requirements. This is most helpful if the rate limit can be made effective for the misbehaving endpoints only. ๐Ÿšจ

4.8. Transmission Parameters ๐Ÿ“

message transmission is controlled by the following parameters, and the defaults are:

                   +-------------------+---------------+
                   | name              | default value |
                   +-------------------+---------------+
                   | ACK_TIMEOUT       | 2 seconds     |
                   | ACK_RANDOM_FACTOR | 1.5           |
                   | MAX_RETRANSMIT    | 4             |
                   | NSTART            | 1             |
                   | DEFAULT_LEISURE   | 5 seconds     |
                   | PROBING_RATE      | 1 byte/second |
                   +-------------------+---------------+

                     Table 2: CoAP Protocol Parameters

4.8.1. Changing the Parameters ๐Ÿ”ง

the values for ACK_TIMEOUT, ACK_RANDOM_FACTOR, MAX_RETRANSMIT, NSTART, DEFAULT_LEISURE (Section 8.2), and PROBING_RATE may be configured to values specific to the application environment (including dynamically adjusted values). However, the configuration method is out of scope for this document ๐Ÿ™ƒ It is RECOMMENDED that an application environment use consistent values for these parameters. The specific effects of running with inconsistent values in an application environment are outside the scope of this specification.

The transmission parameters were chosen to achieve behavior under congestion that is safe on the Internet ๐ŸŒŠ If a configuration wants to use different values, the onus is on that configuration to make sure these congestion control properties are not violated. In particular, a decrease of ACK_TIMEOUT below 1 second would violate the guidelines of [RFC5405]. ([RTO-CONSIDER] provides some additional background.) CoAP was designed to enable implementations that do not maintain round-trip-time (RTT) measurements. However, where it is desired to decrease ACK_TIMEOUT significantly or increase NSTART, this can only be done safely when such measurements are maintained. Configurations MUST NOT decrease ACK_TIMEOUT or increase NSTART without using mechanisms that ensure congestion control safety, either defined in the configuration or in future standards documents. Not optional, bestie ๐Ÿšซ

ACK_RANDOM_FACTOR MUST NOT be decreased below 1.0, and it SHOULD have a value sufficiently different from 1.0 to provide some protection from synchronization effects โœจ

MAX_RETRANSMIT can be freely adjusted. A value that is too small will reduce the probability that a Confirmable message is actually received, while a larger value than given here will require further adjustments in the time values (see Section 4.8.2) ๐Ÿง

If the choice of transmission parameters leads to an increase of derived time values (see Section 4.8.2), the configuration mechanism MUST ensure the adjusted value is also available to all the endpoints with which these adjusted values are used to communicate. So everyone's on the same page, periodt ๐Ÿ’…๐Ÿซถ


4.8.2. Time Values Derived from Transmission Parameters ๐Ÿ’…

okay so ACK_TIMEOUT, ACK_RANDOM_FACTOR, and MAX_RETRANSMIT together decide the timing of retransmissions โฐ, and that timing decides how long an implementation has to hang onto certain information items ๐Ÿซถ. so we give these derived time values names, so we can reference them without any confusion โœจ

  • MAX_TRANSMIT_SPAN is the maximum time from the first transmission of a Confirmable message to its last retransmission. for the default transmission parameters it's (2+4+8+16)*1.5 = 45 seconds, or more generally:
ACK_TIMEOUT * ((2 ** MAX_RETRANSMIT) - 1) * ACK_RANDOM_FACTOR
  • MAX_TRANSMIT_WAIT is the maximum time from the first transmission of a Confirmable message to the moment the sender gives up on waiting for an acknowledgement or reset ๐Ÿฅบ. for the default transmission parameters it's (2+4+8+16+32)*1.5 = 93 seconds, or more generally:
ACK_TIMEOUT * ((2 ** (MAX_RETRANSMIT + 1)) - 1) *
ACK_RANDOM_FACTOR

in addition, we have to make some assumptions about the characteristics of the network and the nodes ๐ŸŒ

  • MAX_LATENCY is the maximum time a datagram is expected to take from the start of its transmission to the completion of its reception. this constant is related to the MSL (Maximum Segment Lifetime) of [RFC0793], which is "arbitrarily defined to be 2 minutes" ([RFC0793] glossary, page 81). now, this is not necessarily smaller than MAX_TRANSMIT_WAIT, because MAX_LATENCY isn't meant to describe a situation where the protocol works well ๐Ÿ™ˆ. it's the worst-case situation the protocol has to guard against. we also arbitrarily define MAX_LATENCY to be 100 seconds ๐Ÿ’ฏ. apart from being reasonably realistic for the bulk of configurations, and being close to the historic choice for TCP, this value also lets Message ID lifetime timers be represented in 8 bits (when measured in seconds) ๐Ÿงš. in these calculations, there is no assumption that the direction of the transmission is irrelevant (i.e., that the network is symmetric). there's just the assumption that the same value can reasonably be used as a maximum value for both directions. if that is not the case, the following calculations become only slightly more complex ๐Ÿค“
  • PROCESSING_DELAY is the time a node takes to turn around a Confirmable message into an acknowledgement. we assume the node will attempt to send an ACK before the sender times out, so as a conservative assumption we set it equal to ACK_TIMEOUT โšก
  • MAX_RTT is the maximum round-trip time, or:
(2 * MAX_LATENCY) + PROCESSING_DELAY

from these values, we can derive the following values relevant to protocol operation ๐Ÿฆ‹

  • EXCHANGE_LIFETIME is the time from starting to send a Confirmable message to the time when an acknowledgement is no longer expected. at that point, message-layer information about the message exchange can be purged ๐Ÿงน. EXCHANGE_LIFETIME includes a MAX_TRANSMIT_SPAN, a MAX_LATENCY forward, PROCESSING_DELAY, and a MAX_LATENCY for the way back. there's no need to consider MAX_TRANSMIT_WAIT if the configuration is chosen such that the last waiting period (ACK_TIMEOUT * (2 ** MAX_RETRANSMIT) or the difference between MAX_TRANSMIT_SPAN and MAX_TRANSMIT_WAIT) is less than MAX_LATENCY. and that's a likely choice, because MAX_LATENCY is a worst-case value that's unlikely to be met in the real world ๐ŸŒธ. in this case, EXCHANGE_LIFETIME simplifies to:
MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY

or 247 seconds with the default transmission parameters ๐ŸŽ€

  • NON_LIFETIME is the time from sending a Non-confirmable message to the time its Message ID can be safely reused. if multiple transmissions of a NON message aren't used, its value is MAX_LATENCY, or 100 seconds. however, a CoAP sender might send a NON message multiple times, especially for multicast applications ๐Ÿ“ก. while the period of reuse isn't bounded by the specification, the expectation of reliable duplicate detection at the receiver is on the timescales of MAX_TRANSMIT_SPAN. so for this purpose, it's safer to use the value:
MAX_TRANSMIT_SPAN + MAX_LATENCY

or 145 seconds with the default transmission parameters. however, an implementation that just wants a single timeout value for retiring Message IDs can safely use the larger value for EXCHANGE_LIFETIME ๐Ÿซถ

Table 3 lists the derived parameters introduced in this subsection, along with their default values ๐Ÿ“‹

                   +-------------------+---------------+
                   | name              | default value |
                   +-------------------+---------------+
                   | MAX_TRANSMIT_SPAN |          45 s |
                   | MAX_TRANSMIT_WAIT |          93 s |
                   | MAX_LATENCY       |         100 s |
                   | PROCESSING_DELAY  |           2 s |
                   | MAX_RTT           |         202 s |
                   | EXCHANGE_LIFETIME |         247 s |
                   | NON_LIFETIME      |         145 s |
                   +-------------------+---------------+

                   Table 3: Derived Protocol Parameters

5. Request/Response Semantics ๐ŸŽ€

CoAP runs a request/response model that's a lot like HTTP ๐Ÿ’•. a CoAP endpoint in the role of a "client" sends one or more CoAP requests to a "server", and the server services those requests by sending CoAP responses. the difference from HTTP is that requests and responses aren't sent over a previously established connection. instead, they're exchanged asynchronously over CoAP messages ๐Ÿฆ‹

5.1. Requests ๐Ÿ“ฎ

a CoAP request consists of the method to be applied to the resource, the identifier of the resource, a payload and Internet media type (if any), and optional metadata about the request โœจ

CoAP supports the basic methods of GET, POST, PUT, and DELETE, which map easily to HTTP ๐ŸŒˆ. they have the same properties as HTTP of being safe (only retrieval) and idempotent (you can invoke them multiple times with the same effects) (see Section 9.1 of [RFC2616]) ๐Ÿง . the GET method is safe, so it MUST NOT take any action on a resource other than retrieval. the GET, PUT, and DELETE methods MUST be performed in such a way that they are idempotent. POST is not idempotent, because its effect is determined by the origin server and depends on the target resource. it usually results in a new resource being created or the target resource being updated ๐Ÿ’…

a request is initiated by setting the Code field in the CoAP header of a Confirmable or a Non-confirmable message to a Method Code, and including request information ๐Ÿš€

the methods used in requests are described in detail in Section 5.8 ๐Ÿ”

5.2. Responses ๐Ÿ’Œ

after receiving and interpreting a request, a server responds with a CoAP response. that response is matched to the request by means of a client-generated token (Section 5.3). note that this is different from the Message ID, which matches a Confirmable message to its Acknowledgement ๐Ÿงฉ

a response is identified by the Code field in the CoAP header being set to a Response Code. similar to the HTTP Status Code, the CoAP Response Code indicates the result of the attempt to understand and satisfy the request. these codes are fully defined in Section 5.9 ๐Ÿ“–. the Response Code numbers to be set in the Code field of the CoAP header are maintained in the CoAP Response Code Registry (Section 12.1.2) ๐Ÿ—‚๏ธ

                              0
                              0 1 2 3 4 5 6 7
                             +-+-+-+-+-+-+-+-+
                             |class|  detail |
                             +-+-+-+-+-+-+-+-+

                  Figure 9: Structure of a Response Code

the upper three bits of the 8-bit Response Code number define the class of response. the lower five bits don't have any categorization role. they just give additional detail to the overall class (Figure 9) ๐Ÿ“

as a human-readable notation for specifications and protocol diagnostics, CoAP code numbers including the Response Code are documented in the format "c.dd". here "c" is the class in decimal, and "dd" is the detail as a two-digit decimal. for example, "Forbidden" is written as 4.03, which means an 8-bit code value of hexadecimal 0x83 (4*0x20+3) or decimal 131 (4*32+3) ๐Ÿ™ˆ

there are 3 classes of Response Codes:

  • 2 - Success: the request was successfully received, understood, and accepted ๐Ÿฅณ
  • 4 - Client Error: the request contains bad syntax or cannot be fulfilled ๐Ÿ˜ฌ
  • 5 - Server Error: the server failed to fulfill an apparently valid request ๐Ÿ’€

the Response Codes are designed to be extensible. Response Codes in the Client Error or Server Error class that an endpoint doesn't recognize are treated as equivalent to the generic Response Code of that class (4.00 and 5.00, respectively). however, there is no generic Response Code indicating success. so a Response Code in the Success class that an endpoint doesn't recognize can only be used to determine that the request was successful, without any further details ๐ŸŒŸ

the possible Response Codes are described in detail in Section 5.9 ๐Ÿ”ฎ

responses can be sent in multiple ways, which are defined in the following subsections ๐Ÿงš

5.2.1. Piggybacked ๐Ÿฃ

in the most basic case, the response is carried directly in the Acknowledgement message that acknowledges the request. this requires that the request was carried in a Confirmable message. this is called a "Piggybacked Response" ๐Ÿ’–

the response is returned in the Acknowledgement message, whether it indicates success or failure. in effect, the response is piggybacked on the Acknowledgement message, and no separate message is required to return the response ๐Ÿซถ

Implementation Note: the protocol leaves the decision of whether to piggyback a response (or send a separate response) up to the server. the client MUST be prepared to receive either. on the quality-of-implementation level, there is a strong expectation that servers will implement code to piggyback whenever possible, saving resources in the network and at both the client and the server ๐Ÿ”ฅ

5.2.2. Separate ๐Ÿฆ‹

Okay so, a piggybacked response isn't always possible ๐Ÿ™ˆ. A server might need longer to get the representation of the requested resource than it can wait before sending the Acknowledgement, and if it takes too long the client just keeps retransmitting the request ๐Ÿ’€ (see also the tea on PROCESSING_DELAY in Section 4.8.2). And a response to a request that came in a Non-confirmable message is always sent separately, because there's no Acknowledgement to hitch a ride on ๐Ÿ˜ญ.

One way a server can handle this is to start working on getting the representation and, while that's in progress, let an acknowledgement timer run out โฐ. A server can also send an acknowledgement right away if it already knows there won't be a piggybacked response ๐Ÿ’…. Either way, the acknowledgement basically works as a promise that the request will be handled later ๐Ÿซถ.

When the server finally has the representation, it sends the response ๐ŸŽ€. If it really can't afford to lose that message, it goes out as a Confirmable message from the server to the client, and the client answers with an Acknowledgement that echoes the new Message ID the server picked ๐Ÿ”ฅ. (It can also be a Non-confirmable message; see Section 5.2.3 ๐ŸŒธ.)

When the server goes the separate route, it sends the Acknowledgement to the Confirmable request as an Empty message ๐Ÿ’–. Once the server has sent back that Empty Acknowledgement, it MUST NOT send the response in another Acknowledgement, even if the client retransmits the same request again ๐Ÿ™…โ€โ™€๏ธ. If a retransmitted request shows up (maybe the original Acknowledgement got delayed), another Empty Acknowledgement goes out, and any response MUST be sent as a separate response ๐Ÿ’œ.

If the server then sends a Confirmable response, the client's Acknowledgement to that response MUST also be an Empty message, one that carries neither a request nor a response โœจ. The server MUST stop retransmitting its response on any matching Acknowledgement (silently ignoring any Response Code or payload) or Reset message ๐Ÿ‘‘.

Implementation Notes: Here's the tea. The underlying datagram transport might not preserve sequence, so the Confirmable message carrying the response could actually arrive before or after the Acknowledgement for the request. For the purposes of ending the retransmission sequence, that counts as an acknowledgement too ๐Ÿงš. Also, while the CoAP protocol itself doesn't make any specific demands here, there's an expectation that the response comes within a time frame that's reasonable from an application point of view โณ. And since there's no underlying transport protocol that could be told to run a keep-alive mechanism, the requester may want to set up a timeout that's unrelated to CoAP's retransmission timers, in case the server gets destroyed or otherwise can't send the response ๐Ÿฅบ.

5.2.3. Non-confirmable ๐ŸŒˆ

If the request message is Non-confirmable, the response SHOULD be returned in a Non-confirmable message as well ๐Ÿ’œ. However, an endpoint MUST be prepared to receive a Non-confirmable response (preceded or followed by an Empty Acknowledgement message) in reply to a Confirmable request, or a Confirmable response in reply to a Non-confirmable request ๐Ÿซถ. Be flexible, bestie ๐Ÿ’….

5.3. Request/Response Matching ๐Ÿงฉ

Regardless of how a response is sent, it gets matched to the request using a token that the client includes in the request, plus some extra address info about the matching endpoint ๐ŸŽ€.

5.3.1. Token ๐Ÿช™

The Token is what matches a response to a request ๐Ÿ’–. The token value is a sequence of 0 to 8 bytes. (Every message carries a token, even if it's zero length, so don't be surprised ๐Ÿ™ˆ.) Every request carries a client-generated token that the server MUST echo (without modification) in any resulting response ๐Ÿ”ฅ.

A token is meant to be a client-local identifier for telling apart concurrent requests (see Section 5.3 ๐ŸŒธ). Honestly, it could've just been called a "request ID" ๐Ÿ’….

The client SHOULD generate tokens so that the tokens currently in use for a given source/destination endpoint pair are unique ๐Ÿฆ‹. (A client implementation can actually reuse the same token for any request as long as it uses a different endpoint each time, e.g., a different source port number ๐Ÿงš.) An empty token value is fine when no other tokens are in use to a destination, or when requests are made serially per destination and get piggybacked responses ๐Ÿ“. There are multiple possible implementation strategies for this, though ๐Ÿ‘‘.

A client sending a request without using Transport Layer Security (Section 9) SHOULD use a nontrivial, randomized token to guard against spoofing of responses (Section 11.4) ๐Ÿ”. This protective use of tokens is exactly why they're allowed to be up to 8 bytes ๐ŸŽ€. How much random stuff goes into the Token depends on the client's security requirements and how much of a threat response spoofing poses ๐Ÿค”. A client connected to the general Internet SHOULD use at least 32 bits of randomness ๐Ÿ’ช, and keep in mind that not being directly connected to the Internet is not necessarily enough protection against spoofing ๐Ÿ™ˆ. (The Message ID adds little protection, since it's usually assigned sequentially, which makes it guessable, and it can be bypassed by spoofing a separate response ๐Ÿ˜ญ.) Clients that want to optimize the Token length may also want to detect the level of ongoing attacks (for example, by tallying recent Token mismatches in incoming messages) and bump the Token length up as needed ๐Ÿ“ˆ. [RFC4086] discusses randomness requirements for security ๐Ÿ“š.

An endpoint receiving a token it did not generate MUST treat the token as opaque and make no assumptions about its content or structure ๐Ÿซฃ.

5.3.2. Request/Response Matching Rules ๐Ÿ“‹

The exact rules for matching a response to a request go like this:

  1. The source endpoint of the response MUST be the same as the destination endpoint of the original request.
  2. In a piggybacked response, the Message ID of the Confirmable request and the Acknowledgement MUST match, and the tokens of the response and original request MUST match. In a separate response, just the tokens of the response and original request MUST match.

If a message carrying a response is unexpected (the client isn't waiting for a response from the identified endpoint, at the endpoint addressed, and/or with the given token), the response gets rejected (Sections 4.2 and 4.3) ๐Ÿšซ.

Implementation Note: A client that receives a response in a CON message might want to clean up its message state right after sending the ACK ๐Ÿงน. If that ACK gets lost and the server retransmits the CON, the client might not have any state left to match this response to. That makes the retransmission an unexpected message, so the client will likely send a Reset message so it doesn't get any more retransmissions ๐Ÿ™ƒ. This behavior is normal and not an indication of an error ๐Ÿ’–. (Clients that aren't aggressively optimized in their state memory usage will still have message state that identifies the second CON as a retransmission. Clients that actually expect more messages from the server [OBSERVE] will have to keep state in any case ๐Ÿซถ.)

5.4. Options ๐ŸŽ€

Both requests and responses can include a list of one or more options ๐Ÿ’…. For example, the URI in a request is carried in several options, and the metadata that would live in an HTTP header in HTTP gets supplied as options too ๐ŸŒธ.

CoAP defines a single set of options that get used in both requests and responses ๐Ÿง:

  • Content-Format
  • ETag
  • Location-Path
  • Location-Query
  • Max-Age
  • Proxy-Uri
  • Proxy-Scheme
  • Uri-Host
  • Uri-Path
  • Uri-Port
  • Uri-Query
  • Accept
  • If-Match
  • If-None-Match
  • Size1

The semantics of these options, along with their properties, are defined in detail in Section 5.10 ๐Ÿ“–.

Not every option is defined for use with every method and Response Code ๐Ÿ™ˆ. The possible options for methods and Response Codes are defined in Sections 5.8 and 5.9, respectively. If an option isn't defined for a Method or Response Code, it MUST NOT be included by a sender, and a recipient MUST treat it like an unrecognized option ๐Ÿšซ.

5.4.1. Critical/Elective โš–๏ธ

Options fall into one of two classes: "critical" or "elective" ๐Ÿ’ซ. The difference is how an endpoint handles an option it doesn't recognize:

  • Upon reception, unrecognized options of class "elective" MUST be silently ignored ๐Ÿคซ.
  • Unrecognized options of class "critical" that occur in a Confirmable request MUST cause the return of a 4.02 (Bad Option) response ๐Ÿ™…โ€โ™€๏ธ. This response SHOULD include a diagnostic payload describing the unrecognized option(s) (see Section 5.5.2) ๐Ÿฉบ.
  • Unrecognized options of class "critical" that occur in a Confirmable response, or piggybacked in an Acknowledgement, MUST cause the response to be rejected (Section 4.2) ๐Ÿšซ.
  • Unrecognized options of class "critical" that occur in a Non-confirmable message MUST cause the message to be rejected (Section 4.3) ๐Ÿ’€.

Note that, whether critical or elective, an option is never "mandatory" (it's always optional) ๐Ÿ’…. These rules exist so that implementations can stop processing options they don't understand or implement ๐Ÿงš.

Critical/elective rules apply to non-proxying endpoints ๐Ÿฆ‹. A proxy processes options based on the Unsafe/Safe-to-Forward classes defined in Section 5.7 ๐ŸŒท.

5.4.2. Proxy Unsafe or Safe-to-Forward and NoCacheKey ๐Ÿ”‘

On top of being marked critical or elective, options are also classified by how a proxy should deal with them if it doesn't recognize them ๐Ÿ‘€. For this purpose, an option is either considered Unsafe to forward (UnSafe is set) or Safe-to-Forward (UnSafe is clear) ๐Ÿ›ก๏ธ.

Also, for an option marked Safe-to-Forward, the option number tells you whether or not it's meant to be part of the Cache-Key (Section 5.6) in a request. If some of the NoCacheKey bits are 0, it is part of the Cache-Key; if all NoCacheKey bits are 1, it isn't (see Section 5.4.6) ๐Ÿ—๏ธ.

Note: The Cache-Key indication only matters for proxies that don't implement the given option as a request option and instead rely only on the Unsafe/Safe-to-Forward indication ๐Ÿค“. For example, for ETag, actually using the request option as part of the Cache-Key is grossly inefficient, but it's the best thing a proxy can do if it doesn't implement ETag, since the response is going to differ based on whether the request option is present ๐Ÿ˜ต. A more useful proxy that does implement the ETag request option doesn't use ETag as part of the Cache-Key ๐Ÿ™Œ. NoCacheKey is indicated in three bits, so only one out of eight codepoints is qualified as NoCacheKey, leaving seven out of eight codepoints for what appears to be the more likely case ๐Ÿ“Š.

Proxy behavior with regard to these classes is defined in Section 5.7 ๐ŸŽ€.

5.4.3. Length ๐Ÿ“

Option values are defined to have a specific length, often expressed as an upper and lower bound ๐Ÿง. If the length of an option value in a request is outside the defined range, that option MUST be treated like an unrecognized option (see Section 5.4.1) ๐Ÿ’….

5.4.4. Default Values ๐Ÿ’–

Okay so options can come with a default value ๐ŸŽ€. If an option's value is meant to be that default, the option SHOULD NOT be included in the message, bestie. And if the option isn't there at all, the default value MUST be assumed ๐Ÿ’….

Where a critical option has a default, it gets picked super carefully so that leaving the option out can be processed properly by implementations that have no clue the critical option exists, and by implementations that read "not there" as "the default is here" ๐Ÿซถ. Iconic planning, honestly.

5.4.5. Repeatable Options ๐Ÿฆ‹

Some options are defined as repeatable, which means they MAY show up one or more times in a message ๐ŸŒธ. Options that aren't repeatable MUST NOT appear more than once in a message. No exceptions, periodt ๐Ÿ’€.

If a message has more copies of an option than that option is allowed to have, every extra copy (the supernumerary ones) that shows up later in the message MUST be treated like an unrecognized option (see Section 5.4.1) ๐Ÿ™ˆ.

5.4.6. Option Numbers ๐Ÿงš

An Option is identified by its option number, and the number also tells you extra stuff. Odd numbers mean critical, even numbers mean elective ๐Ÿ‘‘. This isn't just a vibe or a convention either, it's a real feature of the protocol: whether an option is elective or critical is completely decided by whether its number is even or odd ๐Ÿ”ฅ.

More generally, an option number is built with a bit mask that says if an option is Critical or Elective, Unsafe or Safe-to-Forward, and, for Safe-to-Forward ones, gives a Cache-Key indication too, as the figure below shows ๐Ÿ’œ. In the text, the bit mask is written as a single byte that gets applied to the least significant byte of the option number (in unsigned integer representation) ๐Ÿ“. When bit 7 (the least significant bit) is 1, the option is Critical, and it's Elective when it's 0. When bit 6 is 1, the option is Unsafe, and it's Safe-to-Forward when it's 0. When bit 6 is 0 (so the option isn't Unsafe), it's NoCacheKey if and only if bits 3-5 are all set to 1. Every other bit combo means it is a Cache-Key ๐ŸŒˆ. These classes of options get explained in the next sections โœจ.

                       0   1   2   3   4   5   6   7
                     +---+---+---+---+---+---+---+---+
                     |           | NoCacheKey| U | C |
                     +---+---+---+---+---+---+---+---+

          Figure 10: Option Number Mask (Least Significant Byte)

An endpoint may use an equivalent of the C code in Figure 11 to derive the characteristics of an option number "onum" ๐Ÿง .

   Critical = (onum & 1);
   UnSafe = (onum & 2);
   NoCacheKey = ((onum & 0x1e) == 0x1c);

       Figure 11: Determining Characteristics from an Option Number

The option numbers for the options defined in this document are listed in the "CoAP Option Numbers" registry (Section 12.2) ๐Ÿ“‹.

5.5. Payloads and Representations ๐ŸŽ€

Both requests and responses can include a payload, depending on the Method or Response Code. If a Method or Response Code isn't defined to have a payload, a sender MUST NOT include one, and a recipient MUST ignore it ๐Ÿ’€. Ignore it, babe, it's not for you.

5.5.1. Representation ๐Ÿ“ธ

The payload of requests, or of responses indicating success, is usually a representation of a resource ("resource representation") or the result of the requested action ("action result") โœจ. Its format is specified by the Internet media type and content coding given by the Content-Format Option. If that option is missing, there's no default value, so the format has to be inferred by the application (e.g., from the application context). Payload "sniffing" SHOULD only be attempted if no content type is given ๐Ÿ™ˆ.

Implementation Note: Quality-of-implementation vibes here ๐Ÿ’…. People really expect a Content-Format indication with resource representations whenever it's possible. It's not a "SHOULD" level requirement, and that's only because it isn't a protocol requirement. Plus, it'd be super hard to spell out exactly when that expectation could get broken ๐Ÿ˜ญ.

For responses indicating a client or server error, the payload only counts as a representation of the result of the requested action if a Content-Format Option is given. Without that option, the payload is a Diagnostic Payload (Section 5.5.2) ๐ŸŒˆ.

5.5.2. Diagnostic Payload ๐Ÿ”ฅ

If no Content-Format option is given, the payload of a response indicating a client or server error is a brief, human-readable diagnostic message that explains the error situation. This diagnostic message MUST be encoded using UTF-8 [RFC3629], more specifically using Net-Unicode form [RFC5198] ๐Ÿงพ.

The message is kind of like the Reason-Phrase on an HTTP status line. It's not for end users, it's for software engineers who need to interpret it while debugging, in the context of this present English-language specification. So no mechanism for language tagging is needed or provided ๐Ÿค“. Unlike what's usual in HTTP, the payload SHOULD be empty if there's no additional information beyond the Response Code ๐Ÿ’….

5.5.3. Selected Representation ๐Ÿฆ‹

Not every response carries a payload that gives a representation of the resource addressed by the request. It's still sometimes useful to refer to such a representation in relation to a response, whether or not it actually got enclosed ๐Ÿ’–.

We use the term "selected representation" for the current representation of a target resource that would have been selected in a successful response if the corresponding request had used the method GET and excluded any conditional request options (Section 5.10.8) โœจ.

Certain response options give metadata about the selected representation, which might differ from the representation included in the message for responses to some state-changing methods. Of the response options defined in this specification, only the ETag response option (Section 5.10.6) is defined as metadata about the selected representation ๐Ÿงš.

5.5.4. Content Negotiation ๐ŸŒธ

A server may be able to supply a representation for a resource in one of multiple representation formats. Without further info from the client, it provides the representation in the format it prefers ๐Ÿ‘‘.

By using the Accept Option (Section 5.10.4) in a request, the client can indicate which content-format it prefers to receive ๐Ÿ’œ.

5.6. Caching ๐Ÿงบ

CoAP endpoints MAY cache responses in order to reduce response time and network bandwidth consumption on future, equivalent requests ๐Ÿ’พ.

The goal of caching in CoAP is to reuse a prior response message to satisfy a current request. Sometimes a stored response can be reused with no network request at all, which cuts latency and network round-trips. A "freshness" mechanism handles that (see Section 5.6.1). Even when a new request is needed, it's often possible to reuse the payload of a prior response to satisfy it, saving network bandwidth. A "validation" mechanism handles that one (see Section 5.6.2) ๐Ÿซถ.

Unlike HTTP, the cacheability of CoAP responses doesn't depend on the request method. It depends on the Response Code. The cacheability of each Response Code is defined along with the Response Code definitions in Section 5.9. Response Codes that indicate success and are unrecognized by an endpoint MUST NOT be cached ๐Ÿšซ.

For a presented request, a CoAP endpoint MUST NOT use a stored response, unless:

  • the presented request method and the one used to obtain the stored response match,
  • all options match between those in the presented request and those of the request used to obtain the stored response (which includes the request URI), except that there's no need for a match of any request options marked as NoCacheKey (Section 5.4) or recognized by the Cache and fully interpreted with respect to its specified cache behavior (such as the ETag request option described in Section 5.10.6; see also Section 5.4.2), and
  • the stored response is either fresh or successfully validated as defined below.

The set of request options used for matching the cache entry is also collectively referred to as the "Cache-Key" ๐Ÿ”‘. For URI schemes other than coap and coaps, matching of those options that constitute the request URI may be performed under rules specific to the URI scheme ๐ŸŒ.

5.6.1. Freshness Model โฐ

When a response is "fresh" in the cache, it can be used to satisfy subsequent requests without contacting the origin server, which makes things way more efficient โœจ.

The mechanism for figuring out freshness is for an origin server to provide an explicit expiration time in the future, using the Max-Age Option (see Section 5.10.5). The Max-Age Option says the response is to be considered not fresh once its age is greater than the specified number of seconds ๐Ÿ•ฐ๏ธ.

The Max-Age Option defaults to a value of 60. So if it's not present in a cacheable response, the response is considered not fresh after its age is greater than 60 seconds. If an origin server wants to prevent caching, it MUST explicitly include a Max-Age Option with a value of zero seconds. Hard no to caching ๐Ÿ™…โ€โ™€๏ธ.

If a client has a fresh stored response and makes a new request matching the request for that stored response, the new response invalidates the old response ๐Ÿ’….

5.6.2. Validation Model ๐Ÿ”

When an endpoint has one or more stored responses for a GET request, but can't use any of them (e.g., because they're not fresh), it can use the ETag Option (Section 5.10.6) in the GET request. That gives the origin server a chance both to select a stored response to be used and to update its freshness. This process is known as "validating" or "revalidating" the stored response ๐Ÿง.

When sending such a request, the endpoint SHOULD add an ETag Option specifying the entity-tag of each stored response that's applicable ๐Ÿซถ.

A 2.03 (Valid) response indicates the stored response identified by the entity-tag given in the response's ETag Option can be reused after updating it as described in Section 5.9.1.3 ๐ŸŽ‰.

Any other Response Code indicates that none of the stored responses nominated in the request is suitable. Instead, the response SHOULD be used to satisfy the request, and it MAY replace the stored response ๐Ÿ’€.

5.7. Proxying ๐Ÿฆ‹

okay so a proxy is a CoAP endpoint that clients can hand requests to, and then the proxy makes them on their behalf ๐Ÿ’…. This is super useful when the request couldn't otherwise be made, or when the proxy can answer from a cache so the response comes back faster and uses less network bandwidth or energy ๐Ÿ”‹โœจ (energy matters a LOT for tiny devices).

In an overall Constrained RESTful Environment, proxies can have really different jobs ๐Ÿ‘‘. Clients can explicitly pick one, which we call a "forward-proxy" ๐Ÿงš. A proxy can also be slotted in to stand in for origin servers, and that's a "reverse-proxy" ๐Ÿชž. Separately, a proxy can map a CoAP request to a CoAP request (a "CoAP-to-CoAP proxy") or translate from or to a different protocol (a "cross-proxy") ๐ŸŒˆ. The full definitions are in Section 1.2 ๐Ÿ’–.

Notes: the terminology here was picked to feel culturally familiar to the wider web app world ๐ŸŒธ, without matching it in every single detail (which might not even matter in Constrained RESTful Environments). Don't read too much into the pieces of the words, like "forward", "reverse", or "cross" ๐Ÿ™ˆ. HTTP proxies often do more than proxy HTTP. They also offer a transport-protocol proxying function (CONNECT) so end-to-end transport layer security can go through the proxy ๐Ÿ”. No such function is defined for CoAP-to-CoAP proxies in this spec, because forwarding UDP packets is unlikely to be of much value in Constrained RESTful Environments ๐Ÿคทโ€โ™€๏ธ. See also Section 10.2.7 for the cross-proxy case โœจ.

When a client uses a proxy to make a request that uses a secure URI scheme (e.g., coaps or https), the request towards the proxy SHOULD be sent using DTLS, except where equivalent lower-layer security is used for the leg between the client and the proxy ๐Ÿ”’๐Ÿ’œ.

5.7.1. Proxy Operation ๐Ÿ› ๏ธ

A proxy generally needs a way to figure out the potential request parameters for a request it sends to a destination, based on the request it got from its client ๐Ÿค”. This is fully specified for a forward-proxy, but for a reverse-proxy it may depend on the specific configuration ๐ŸŽ›๏ธ. Honestly, the client of a reverse-proxy usually doesn't indicate a locator for the destination, so the reverse-proxy needs some form of namespace translation ๐Ÿ—บ๏ธ. Still, some parts of proxy operation are shared by all forms ๐Ÿซถ.

If a proxy doesn't use a cache, it just forwards the translated request to the determined destination ๐Ÿ“ฌ. Otherwise, if it does use a cache but doesn't have a stored response that matches the translated request and is still considered fresh, it needs to refresh its cache according to Section 5.6 ๐Ÿ”„. For options in the request that the proxy recognizes, it knows whether that option is meant to be part of the key used to look up the cached value or not ๐Ÿ”‘. For example, requests for different Uri-Path values address different resources, so Uri-Path values are always part of the Cache-Key, while, e.g., Token values are never part of the Cache-Key ๐Ÿ™…โ€โ™€๏ธ. For options the proxy doesn't recognize but that are marked Safe-to-Forward in the option number, the option also tells the proxy whether to include it in the Cache-Key (NoCacheKey is not all set) or not (NoCacheKey is all set) ๐Ÿงฉ. (Options that are unrecognized and marked Unsafe lead to 4.02 Bad Option ๐Ÿ’€.)

If the request to the destination times out, a 5.04 (Gateway Timeout) response MUST be returned โฐ. If the request to the destination gets a response the proxy can't process (e.g., due to unrecognized critical options or message format errors), a 5.02 (Bad Gateway) response MUST be returned ๐Ÿ˜ญ. Otherwise, the proxy returns the response to the client ๐ŸŽ€.

If a response is generated out of a cache, the generated (or implied) Max-Age Option MUST NOT extend the max-age originally set by the server, considering the time the resource representation spent in the cache โณ. For example, the Max-Age Option could be adjusted by the proxy for each response using this formula:

proxy-max-age = original-max-age - cache-age

Like, if a request is made to a proxied resource that was refreshed 20 seconds ago and had an original Max-Age of 60 seconds, then that resource's proxied max-age is now 40 seconds ๐Ÿงฎโœจ. Considering potential network delays on the way from the origin server, a proxy should be conservative in the max-age values it offers ๐Ÿซง.

All options present in a proxy request MUST be processed at the proxy ๐Ÿ‘€. Unsafe options in a request that the proxy doesn't recognize MUST lead to a 4.02 (Bad Option) response being returned by the proxy ๐Ÿšซ. A CoAP-to-CoAP proxy MUST forward to the origin server all Safe-to-Forward options that it doesn't recognize ๐Ÿ“ฆ. Similarly, Unsafe options in a response that are not recognized by the CoAP-to-CoAP proxy server MUST lead to a 5.02 (Bad Gateway) response ๐Ÿ’…. Again, Safe-to-Forward options that are not recognized MUST be forwarded ๐Ÿ’–.

Additional considerations for cross-protocol proxying between CoAP and HTTP are discussed in Section 10 ๐ŸŒ.

5.7.2. Forward-Proxies ๐Ÿงญ

CoAP makes a clear difference between requests made (as if) to an origin server and requests made through a forward-proxy ๐Ÿ‘ฏ. CoAP requests to a forward-proxy are sent as normal Confirmable or Non-confirmable requests to the forward-proxy endpoint, but they specify the request URI in a different way ๐Ÿ”€. In a proxy request, the request URI is a string in the Proxy-Uri Option (see Section 5.10.2) ๐Ÿงต. In a request to an origin server, the request URI is split into the Uri-Host, Uri-Port, Uri-Path, and Uri-Query Options (see Section 5.10.1) ๐Ÿช“. Alternatively, the URI in a proxy request can be put together from a Proxy-Scheme option plus those split options ๐Ÿงฉ.

When a proxy request is made to an endpoint and that endpoint is unwilling or unable to act as proxy for the request URI, it MUST return a 5.05 (Proxying Not Supported) response ๐Ÿ™…โ€โ™€๏ธ. If the authority (host and port) is recognized as identifying the proxy endpoint itself (see Section 5.10.2), then the request MUST be treated as a local (non-proxied) request ๐Ÿ .

Unless a proxy is configured to forward the proxy request to another proxy, it MUST translate the request like this: the scheme of the request URI defines the outgoing protocol and its details (e.g., CoAP is used over UDP for the "coap" scheme and over DTLS for the "coaps" scheme) ๐Ÿ”. For a CoAP-to-CoAP proxy, the origin server's IP address and port are determined by the authority component of the request URI, and the request URI is decoded and split into the Uri-Host, Uri-Port, Uri-Path and Uri-Query Options ๐Ÿงฉ. This consumes the Proxy-Uri or Proxy-Scheme option, which is therefore not forwarded to the origin server ๐Ÿซก.

5.7.3. Reverse-Proxies ๐Ÿชž

Reverse-proxies don't use the Proxy-Uri or Proxy-Scheme options at all ๐Ÿ™ˆ. Instead, they need to figure out the destination (next hop) of a request from information in the request plus information in their configuration ๐Ÿง . For example, a reverse-proxy might offer various resources as if they were its own, after learning about them through resource discovery ๐Ÿ”. The reverse-proxy is free to build a namespace for the URIs that identify these resources ๐ŸŽจ. It can also build a namespace that gives the client more control over where the request goes, e.g., by embedding host identifiers and port numbers into the URI path of the resources it offers ๐Ÿงšโ€โ™€๏ธ.

When processing the response, a reverse-proxy has to be careful that ETag option values from different sources don't get mixed up on one resource offered to its clients ๐Ÿ˜ฌ. In many cases, the ETag can be forwarded unchanged ๐Ÿ’…. If the mapping from a resource offered by the reverse-proxy to resources offered by its various origin servers isn't unique, the reverse-proxy may need to generate a new ETag, making sure the semantics of this option are properly preserved ๐Ÿซถ.

5.8. Method Definitions ๐ŸŽ€

In this section, each method is defined along with its behavior ๐Ÿ“–. A request with an unrecognized or unsupported Method Code MUST generate a 4.05 (Method Not Allowed) piggybacked response ๐Ÿšซ.

5.8.1. GET ๐Ÿ“ฅ

The GET method retrieves a representation for the information that currently corresponds to the resource identified by the request URI ๐Ÿ’–. If the request includes an Accept Option, that indicates the preferred content-format of a response ๐ŸŽฏ. If the request includes an ETag Option, the GET method requests that ETag be validated, and that the representation be transferred only if validation failed ๐Ÿ”Ž. Upon success, a 2.05 (Content) or 2.03 (Valid) Response Code SHOULD be present in the response โœจ.

The GET method is safe and idempotent ๐Ÿซง.

5.8.2. POST ๐Ÿ“ค

The POST method requests that the representation enclosed in the request be processed ๐Ÿณ. The actual function performed by POST is determined by the origin server and depends on the target resource ๐ŸŽ›๏ธ. It usually results in a new resource being created or the target resource being updated ๐Ÿ†•.

If a resource has been created on the server, the response returned by the server SHOULD have a 2.01 (Created) Response Code, and SHOULD include the URI of the new resource in a sequence of one or more Location-Path and/or Location-Query Options (Section 5.10.7) ๐ŸŽ‰. If the POST succeeds but doesn't result in a new resource being created on the server, the response SHOULD have a 2.04 (Changed) Response Code ๐Ÿ”. If the POST succeeds and results in the target resource being deleted, the response SHOULD have a 2.02 (Deleted) Response Code ๐Ÿ—‘๏ธ.

POST is neither safe nor idempotent ๐Ÿ˜….

5.8.3. PUT ๐Ÿงฑ

The PUT method requests that the resource identified by the request URI be updated or created with the enclosed representation ๐Ÿ–Œ๏ธ. The representation format is specified by the media type and content coding given in the Content-Format Option, if provided ๐Ÿท๏ธ.

If a resource exists at the request URI, the enclosed representation SHOULD be considered a modified version of that resource, and a 2.04 (Changed) Response Code SHOULD be returned ๐Ÿ”„. If no resource exists, the server MAY create a new resource with that URI, resulting in a 2.01 (Created) Response Code ๐ŸŒฑ. If the resource could not be created or modified, an appropriate error Response Code SHOULD be sent ๐Ÿ™ˆ.

Further restrictions to a PUT can be made by including the If-Match (see Section 5.10.8.1) or If-None-Match (see Section 5.10.8.2) options in the request ๐Ÿšง.

PUT is not safe but is idempotent ๐Ÿซถ.

5.8.4. DELETE ๐Ÿ—‘๏ธ

The DELETE method requests that the resource identified by the request URI be deleted ๐Ÿ‘‹. A 2.02 (Deleted) Response Code SHOULD be used on success, or in case the resource did not exist before the request โœ….

DELETE is not safe but is idempotent ๐Ÿ’œ.

5.9. Response Code Definitions ๐ŸŒธ

Each Response Code is described below, including any options required in the response ๐Ÿ“‹. Where appropriate, some of the codes will be specified in regards to related Response Codes in HTTP [RFC2616]. This does not mean that any such relationship modifies the HTTP mapping specified in Section 10 ๐Ÿงšโ€โ™€๏ธ.

5.9.1. Success 2.xx ๐Ÿฅณ

This class of Response Code indicates that the client's request was successfully received, understood, and accepted ๐ŸŽŠโœจ.

5.9.1.1. 2.01 Created ๐ŸŽ€

Okay so this is basically HTTP 201 "Created" ๐ŸŒธ but it only shows up when someone's sending a POST or PUT. Any payload that comes back is a representation of what the action actually did โœจ

If the response has one or more Location-Path and/or Location-Query Options, those values tell you where the resource got created ๐Ÿ—บ๏ธ If there aren't any, the resource was created right at the request URI. A cache that gets this response MUST mark any stored response for the created resource as not fresh ๐Ÿ™…โ€โ™€๏ธ

And this response is not cacheable, bestie ๐Ÿ’…

5.9.1.2. 2.02 Deleted ๐Ÿ—‘๏ธ

This one is giving HTTP 204 "No Content" vibes, but it's only for requests that make the resource stop being available, like DELETE and, in certain situations, POST ๐Ÿ’€ Again, any payload that comes back is a representation of the action result โœจ

This response is not cacheable. HOWEVER, a cache MUST mark any stored response for the deleted resource as not fresh ๐Ÿซถ

5.9.1.3. 2.03 Valid ๐Ÿ’œ

This Response Code is related to HTTP 304 "Not Modified", but it only exists to say the response identified by the entity-tag in the included ETag Option is still valid ๐Ÿฆ‹ So the response MUST include an ETag Option and MUST NOT include a payload. No payload, just vibes ๐Ÿ™ˆ

When a cache that recognizes and processes the ETag response option gets a 2.03 (Valid) response, it MUST update the stored response with the value of the Max-Age Option in the response (explicitly, or implicitly as a default value; see also Section 5.6.2) โฐ For each type of Safe-to-Forward option in the response, the set of options of that type in the stored response (which might be empty) MUST be swapped out for the set of options of that type in the response you just got ๐Ÿ”„ (Unsafe options might trigger similar option-specific processing, as defined by the option itself ๐Ÿ‘€)

5.9.1.4. 2.04 Changed โœจ

This is like HTTP 204 "No Content", but again only for POST and PUT requests ๐Ÿ’– The payload returned with the response, if any, is a representation of the action result.

This response is not cacheable. However, a cache MUST mark any stored response for the changed resource as not fresh ๐ŸŒˆ

5.9.1.5. 2.05 Content ๐Ÿ“

This Response Code is like HTTP 200 "OK", but it's only for GET requests ๐Ÿงš

The payload returned with the response is a representation of the target resource ๐Ÿ’…

This response is cacheable, and caches can use the Max-Age Option to figure out freshness (see Section 5.6.1). If the ETag Option is there, it can also be used for validation (see Section 5.6.2) ๐Ÿ”ฅ

5.9.2. Client Error 4.xx ๐Ÿ™ˆ

This class of Response Code is for when the client seems to have messed up ๐Ÿฅบ These Response Codes can show up for any request method.

The server SHOULD include a diagnostic payload under the conditions detailed in Section 5.5.2 ๐Ÿฉบ

Responses in this class are cacheable, and caches can use the Max-Age Option to determine freshness (see Section 5.6.1). They cannot be validated, though ๐Ÿ™…โ€โ™€๏ธ

5.9.2.1. 4.00 Bad Request ๐Ÿ’€

This Response Code is Like HTTP 400 "Bad Request" ๐Ÿซ 

5.9.2.2. 4.01 Unauthorized ๐Ÿ”

The client isn't authorized to do the requested action ๐Ÿšซ The client SHOULD NOT repeat the request without first improving its authentication status with the server. Which specific mechanism you use for that is outside this document's scope, but see Section 9 if you want more info ๐Ÿ‘‘

5.9.2.3. 4.02 Bad Option โš ๏ธ

The server couldn't understand the request because of one or more unrecognized or malformed options ๐Ÿ˜ญ The client SHOULD NOT repeat the request without modification.

5.9.2.4. 4.03 Forbidden ๐Ÿšท

This Response Code is like HTTP 403 "Forbidden" ๐Ÿ’œ

5.9.2.5. 4.04 Not Found ๐Ÿ”

This Response Code is like HTTP 404 "Not Found" โœจ

5.9.2.6. 4.05 Method Not Allowed ๐Ÿ™…โ€โ™€๏ธ

This is like HTTP 405 "Method Not Allowed", but there's no parallel to the "Allow" header field here ๐Ÿฅ€

5.9.2.7. 4.06 Not Acceptable ๐Ÿ™ƒ

This is like HTTP 406 "Not Acceptable", except there's no response entity ๐Ÿซฅ

5.9.2.8. 4.12 Precondition Failed ๐Ÿšง

This Response Code is like HTTP 412 "Precondition Failed" ๐Ÿฆ‹

5.9.2.9. 4.13 Request Entity Too Large ๐Ÿ˜

This Response Code is like HTTP 413 "Request Entity Too Large" ๐ŸŒŠ

The response SHOULD include a Size1 Option (Section 5.10.9) to show the maximum size of request entity the server can handle and is willing to handle, unless the server isn't in a position to make that info available ๐Ÿ“

5.9.2.10. 4.15 Unsupported Content-Format ๐ŸŒ

This is like HTTP 415 "Unsupported Media Type" ๐Ÿ™…โ€โ™€๏ธ

5.9.3. Server Error 5.xx ๐Ÿšจ

This class of Response Code is for when the server knows it messed up or just can't do the request ๐Ÿฅฒ These Response Codes can show up for any request method.

The server SHOULD include a diagnostic payload under the conditions detailed in Section 5.5.2 ๐Ÿฉน

Responses in this class are cacheable: caches can use the Max-Age Option to determine freshness (see Section 5.6.1). They cannot be validated ๐Ÿซถ

5.9.3.1. 5.00 Internal Server Error ๐Ÿ’ฅ

This Response Code is like HTTP 500 "Internal Server Error" ๐Ÿ˜ตโ€๐Ÿ’ซ

5.9.3.2. 5.01 Not Implemented ๐Ÿ› ๏ธ

This is like HTTP 501 "Not Implemented" ๐Ÿšง

5.9.3.3. 5.02 Bad Gateway ๐ŸŒ‰

This Response Code is like HTTP 502 "Bad Gateway" ๐Ÿซ 

5.9.3.4. 5.03 Service Unavailable ๐Ÿ˜ด

This is like HTTP 503 "Service Unavailable", but instead of the "Retry-After" header field, it uses the Max-Age Option to say how many seconds to wait before retrying โณ

5.9.3.5. 5.04 Gateway Timeout โฐ

This Response Code is like HTTP 504 "Gateway Timeout" ๐Ÿ’€

5.9.3.6. 5.05 Proxying Not Supported ๐Ÿšซ

The server is unable or unwilling to act as a forward-proxy for the URI given in the Proxy-Uri Option, or using Proxy-Scheme (see Section 5.10.2) ๐Ÿ™…โ€โ™€๏ธ

5.10. Option Definitions ๐ŸŽ€

The individual CoAP options are summarized in Table 4 and explained in the subsections of this section โœจ

In this table, the C, U, and N columns show the properties Critical, UnSafe, and NoCacheKey. Since NoCacheKey only means something for options that are Safe-to-Forward (not marked Unsafe), that column gets a dash for UnSafe options ๐Ÿง

+-----+---+---+---+---+----------------+--------+--------+----------+
| No. | C | U | N | R | Name           | Format | Length | Default  |
+-----+---+---+---+---+----------------+--------+--------+----------+
|   1 | x |   |   | x | If-Match       | opaque | 0-8    | (none)   |
|   3 | x | x | - |   | Uri-Host       | string | 1-255  | (see     |
|     |   |   |   |   |                |        |        | below)   |
|   4 |   |   |   | x | ETag           | opaque | 1-8    | (none)   |
|   5 | x |   |   |   | If-None-Match  | empty  | 0      | (none)   |
|   7 | x | x | - |   | Uri-Port       | uint   | 0-2    | (see     |
|     |   |   |   |   |                |        |        | below)   |
|   8 |   |   |   | x | Location-Path  | string | 0-255  | (none)   |
|  11 | x | x | - | x | Uri-Path       | string | 0-255  | (none)   |
|  12 |   |   |   |   | Content-Format | uint   | 0-2    | (none)   |
|  14 |   | x | - |   | Max-Age        | uint   | 0-4    | 60       |
|  15 | x | x | - | x | Uri-Query      | string | 0-255  | (none)   |
|  17 | x |   |   |   | Accept         | uint   | 0-2    | (none)   |
|  20 |   |   |   | x | Location-Query | string | 0-255  | (none)   |
|  35 | x | x | - |   | Proxy-Uri      | string | 1-1034 | (none)   |
|  39 | x | x | - |   | Proxy-Scheme   | string | 1-255  | (none)   |
|  60 |   |   | x |   | Size1          | uint   | 0-4    | (none)   |
+-----+---+---+---+---+----------------+--------+--------+----------+

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

                             Table 4: Options

5.10.1. Uri-Host, Uri-Port, Uri-Path, and Uri-Query ๐Ÿ—บ๏ธ

The Uri-Host, Uri-Port, Uri-Path, and Uri-Query Options are how you specify the target resource of a request to a CoAP origin server ๐ŸŽฏ They encode the different parts of the request URI so that no percent-encoding shows up in the option values, and the full URI can still be rebuilt at any endpoint involved ๐Ÿงฉ The syntax of CoAP URIs is defined in Section 6.

The steps for parsing URIs into options are defined in Section 6.4. Those steps result in zero or more Uri-Host, Uri-Port, Uri-Path, and Uri-Query Options being included in a request, where each option holds the following values:

  • the Uri-Host Option specifies the Internet host of the resource being requested,
  • the Uri-Port Option specifies the transport-layer port number of the resource,
  • each Uri-Path Option specifies one segment of the absolute path to the resource, and
  • each Uri-Query Option specifies one argument parameterizing the resource.

Note: Fragments ([RFC3986], Section 3.5) are not part of the request URI, so they won't be sent in a CoAP request ๐Ÿ™ˆ

The default value of the Uri-Host Option is the IP literal representing the destination IP address of the request message. Likewise, the default value of the Uri-Port Option is the destination UDP port ๐Ÿ”Œ These defaults are enough for requests to most servers. Explicit Uri-Host and Uri-Port Options are typically used when an endpoint hosts multiple virtual servers ๐Ÿ 

The Uri-Path and Uri-Query Options can contain any character sequence, and no percent-encoding is performed ๐ŸŒธ The value of a Uri-Path Option MUST NOT be "." or ".." (because the request URI has to be resolved before it's parsed into options) ๐Ÿ™…โ€โ™€๏ธ

The steps for building the request URI from the options are defined in Section 6.5. An implementation doesn't have to construct the URI, though. It can just look up the target resource by checking the individual options ๐Ÿง 

Examples can be found in Appendix B ๐Ÿ“š

5.10.2. Proxy-Uri and Proxy-Scheme ๐Ÿฆ‹

The Proxy-Uri Option is used to make a request to a forward-proxy (see Section 5.7). The forward-proxy is asked to forward the request, or to serve it from a valid cache, and return the response ๐Ÿ”

The option value is an absolute-URI ([RFC3986], Section 4.3).

Note that the forward-proxy MAY forward the request on to another proxy, or directly to the server specified by the absolute-URI ๐ŸŒ To avoid request loops, a proxy MUST be able to recognize all of its server names, including any aliases, local variations, and the numeric IP addresses ๐Ÿ”„

An endpoint that gets a request with a Proxy-Uri Option and is unable or unwilling to act as a forward-proxy for that request MUST cause the return of a 5.05 (Proxying Not Supported) response ๐Ÿ™…โ€โ™€๏ธ

The Proxy-Uri Option MUST take precedence over any of the Uri-Host, Uri-Port, Uri-Path, or Uri-Query options (and each of those MUST NOT be included in a request that contains the Proxy-Uri Option) ๐Ÿ‘‘

As a special case that makes life easier for lots of proxy clients, the absolute-URI can be built from the Uri-* options. When a Proxy-Scheme Option is present, the absolute-URI is constructed like this: a CoAP URI is built from the Uri-* options as defined in Section 6.5 โœจ In the resulting URI, the initial scheme (everything up to, but not including, the following colon) is then replaced by the content of the Proxy-Scheme Option ๐ŸŽ€ Heads up: this only works if the parts of the desired URI other than the scheme can actually be expressed with Uri-* options. For example, to represent a URI with a userinfo component in the authority, only Proxy-Uri can be used ๐Ÿ™ˆ

5.10.3. Content-Format ๐ŸŽ€

okay so Content-Format tells you what kind of representation the message payload is in ๐Ÿงš. It's a numeric Content-Format identifier, and those live in the "CoAP Content-Formats" registry (Section 12.3) ๐Ÿ’…. If the option isn't there, no default gets assumed at all, so the representation format of any payload is just indeterminate (Section 5.5) ๐Ÿ™ˆ no guessing, bestie!

5.10.4. Accept ๐Ÿ’Œ

The CoAP Accept option is how a client says which Content-Format it's cool with ๐Ÿซถ. Same deal as before: it's a numeric identifier from the "CoAP Content-Formats" registry (Section 12.3). If there's no Accept option, the client isn't expressing a preference, so no default value is assumed ๐Ÿคทโ€โ™€๏ธ. When the client does have a preference, it wants the server to send back the representation in that format โœจ. The server returns the preferred Content-Format if it's available. If it can't, then a 4.06 "Not Acceptable" MUST be sent as the response, unless some other error code takes precedence for that response ๐Ÿ’€.

5.10.5. Max-Age โณ

Max-Age says the maximum time a response can be cached before it's considered not fresh (see Section 5.6.1) ๐Ÿฆ‹.

The option value is an integer number of seconds between 0 and 2**32-1 inclusive, which is about 136.1 years ๐Ÿ˜ญ. If the option isn't in a response, a default of 60 seconds gets assumed ๐ŸŒธ.

The value is meant to be current at the time it's sent ๐Ÿ’œ. Servers that provide resources with strict tolerances on the value of Max-Age SHOULD update the value before each retransmission. (See also Section 5.7.1.)

5.10.6. ETag ๐Ÿท๏ธ

An entity-tag is meant to be a resource-local identifier, so you can tell apart the representations of the same resource that vary over time ๐Ÿ”ฅ. The server providing the resource generates it, and it can do that in any number of ways, including a version, checksum, hash, or time โฐ. An endpoint receiving an entity-tag MUST treat it as opaque and make no assumptions about its content or structure ๐Ÿ™ˆ. (Endpoints that generate an entity-tag are encouraged to use the most compact representation possible, in particular in regards to clients and intermediaries that may want to store multiple ETag values.)

5.10.6.1. ETag as a Response Option ๐Ÿ’–

The ETag Option in a response gives the current value (i.e., after the request was processed) of the entity-tag for the "tagged representation" ๐ŸŽ€. If no Location-* options are present, the tagged representation is the selected representation (Section 5.5.3) of the target resource. If one or more Location-* options are present, and thus a location URI is indicated (Section 5.10.7), the tagged representation is the representation that would be retrieved by a GET request to the location URI.

An ETag response option can be included with any response for which there is a tagged representation (e.g., it would not be meaningful in a 4.04 or 4.00 response). The ETag Option MUST NOT occur more than once in a response.

There is no default value for the ETag Option. If it isn't in a response, the server makes no statement about the entity-tag for the tagged representation ๐Ÿค.

5.10.6.2. ETag as a Request Option ๐Ÿ”

In a GET request, an endpoint that has one or more representations previously obtained from the resource, and has obtained ETag response options with these, can specify an instance of the ETag Option for one or more of these stored responses ๐Ÿ“ฆ.

A server can issue a 2.03 Valid response (Section 5.9.1.3) in place of a 2.05 Content response if one of the ETags given is the entity-tag for the current representation, i.e., is valid. The 2.03 Valid response then echoes this specific ETag in a response option โœ….

Basically, a client can figure out whether any of its stored representations is still current (see Section 5.6.2) without having to transfer them again. Iconic efficiency ๐Ÿ‘‘.

The ETag Option MAY occur zero, one, or multiple times in a request.

5.10.7. Location-Path and Location-Query ๐Ÿ“

The Location-Path and Location-Query Options work together to indicate a relative URI that consists of an absolute path, a query string, or both. A combination of these options is included in a 2.01 (Created) response to show where the resource created by a POST request lives (see Section 5.8.2) ๐Ÿงš. The location gets resolved relative to the request URI.

If a response with one or more Location-Path and/or Location-Query Options passes through a cache that interprets these options, and the implied URI identifies one or more currently stored responses, those entries MUST be marked as not fresh ๐Ÿ™…โ€โ™€๏ธ.

Each Location-Path Option specifies one segment of the absolute path to the resource, and each Location-Query Option specifies one argument parameterizing the resource. The Location-Path and Location-Query Option can contain any character sequence. No percent-encoding is performed. The value of a Location-Path Option MUST NOT be "." or "..". (No dot-dot drama allowed ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’….)

The steps for constructing the location URI from the options are analogous to Section 6.5, except that the first five steps are skipped and the result is a relative URI-reference, which is then interpreted relative to the request URI. Note that the relative URI-reference constructed this way always includes an absolute path (e.g., leaving out Location-Path but supplying Location-Query means the path component in the URI is "/") ๐ŸŒธ.

The options that are used to compute the relative URI-reference are collectively called Location-* options. Beyond Location-Path and Location-Query, more Location-* options may be defined in the future and have been reserved option numbers 128, 132, 136, and 140. If any of these reserved option numbers occurs in addition to Location-Path and/or Location-Query and are not supported, then a 4.02 (Bad Option) error MUST be returned ๐Ÿšซ.

5.10.8. Conditional Request Options ๐Ÿšฆ

Conditional request options let a client ask the server to perform the request only if certain conditions specified by the option are fulfilled. It's giving "only if you're ready" energy ๐Ÿฅน.

For each of these options, if the condition given is not fulfilled, then the server MUST NOT perform the requested method. Instead, the server MUST respond with the 4.12 (Precondition Failed) Response Code ๐Ÿ™….

If the condition is fulfilled, the server performs the request method as if the conditional request options were not present โœจ.

If the request would, without the conditional request options, result in anything other than a 2.xx or 4.12 Response Code, then any conditional request options MAY be ignored ๐Ÿคทโ€โ™€๏ธ.

5.10.8.1. If-Match ๐Ÿชž

The If-Match Option MAY be used to make a request conditional on the current existence or value of an ETag for one or more representations of the target resource. If-Match is generally useful for resource update requests, such as PUT requests, as a means for protecting against accidental overwrites when multiple clients are acting in parallel on the same resource (i.e., the "lost update" problem). Nobody wants their update quietly erased ๐Ÿ˜ญ๐Ÿซถ.

The value of an If-Match option is either an ETag or the empty string. An If-Match option with an ETag matches a representation with that exact ETag. An If-Match option with an empty value matches any existing representation (i.e., it places the precondition on the existence of any current representation for the target resource) ๐ŸŽฏ.

The If-Match Option can occur multiple times. If any of the options match, then the condition is fulfilled ๐Ÿฅณ.

If there is one or more If-Match Options, but none of the options match, then the condition is not fulfilled ๐Ÿ’€.

5.10.8.2. If-None-Match ๐Ÿ™ˆ

The If-None-Match Option MAY be used to make a request conditional on the nonexistence of the target resource. If-None-Match is useful for resource creation requests, such as PUT requests, as a means for protecting against accidental overwrites when multiple clients are acting in parallel on the same resource. The If-None-Match Option carries no value ๐ŸŒท.

If the target resource does exist, then the condition is not fulfilled โŒ.

(It is not very useful to combine If-Match and If-None-Match options in one request, because the condition will then never be fulfilled. Don't do the messy combo, bestie ๐Ÿ™…โ€โ™€๏ธ.)

5.10.9. Size1 Option ๐Ÿ“

The Size1 option provides size information about the resource representation in a request. The option value is an integer number of bytes ๐Ÿง. Its main use is with block-wise transfers [BLOCK]. In the present specification, it is used in 4.13 responses (Section 5.9.2.9) to indicate the maximum size of request entity that the server is able and willing to handle ๐Ÿ’œ.


6. CoAP URIs ๐ŸŒ

CoAP uses the "coap" and "coaps" URI schemes for identifying CoAP resources and providing a means of locating the resource ๐Ÿฆ‹. Resources are organized hierarchically and governed by a potential CoAP origin server listening for CoAP requests ("coap") or DTLS-secured CoAP requests ("coaps") on a given UDP port. The CoAP server is identified via the generic syntax's authority component, which includes a host component and optional UDP port number. The remainder of the URI is considered to be identifying a resource that can be operated on by the methods defined by the CoAP protocol. The "coap" and "coaps" URI schemes can thus be compared to the "http" and "https" URI schemes, respectively ๐Ÿซถ.

The syntax of the "coap" and "coaps" URI schemes is specified in this section in Augmented Backus-Naur Form (ABNF) [RFC5234]. The definitions of "host", "port", "path-abempty", "query", "segment", "IP-literal", "IPv4address", and "reg-name" are adopted from [RFC3986] ๐Ÿ“–.

Implementation Note: Unfortunately, over time, the URI format has acquired significant complexity. Implementers are encouraged to examine [RFC3986] closely. For example, the ABNF for IPv6 addresses is more complicated than maybe expected. Also, implementers should take care to perform the processing of percent-decoding or percent-encoding exactly once on the way from a URI to its decoded components or back. Percent-encoding is crucial for data transparency but may lead to unusual results such as a slash character in a path component. URIs are lowkey chaos, so read [RFC3986] closely ๐Ÿ’€๐Ÿซ .

6.1. coap URI Scheme ๐Ÿฆ‹

coap-URI = "coap:" "//" host [ ":" port ] path-abempty [ "?" query ]

okay so the host part is basically where the server lives ๐Ÿ . If the host is written as an IP-literal or an IPv4address, the CoAP server can be reached at that exact IP address, no detours needed โœจ. If the host is a registered name instead, that name is treated as an indirect identifier, so the endpoint might use a name lookup service like DNS to figure out the address behind it ๐Ÿ”. The host MUST NOT be empty ๐Ÿšซ. If a URI shows up with a missing authority or an empty host, it MUST be considered invalid, no exceptions bestie ๐Ÿ’€.

The port subcomponent tells you which UDP port the CoAP server is listening on ๐ŸŽง. If it's empty or not given at all, the default port 5683 is assumed ๐Ÿ’–.

The path picks out a resource inside the host and port scope ๐Ÿ—บ๏ธ. It's a bunch of path segments separated by a slash, which is U+002F SOLIDUS "/" for the nerds in the back ๐Ÿค“.

The query is how you add extra flavour to the resource ๐ŸŒธ. It's a list of arguments separated by an ampersand, U+0026 AMPERSAND "&" ๐Ÿ’…. Each argument is usually a "key=value" pair, so very on brand for URIs โœจ.

The "coap" scheme also supports the "/.well-known/" path prefix from [RFC5785] ๐Ÿงš. That's the official "well-known locations" zone in a host's namespace, and it's how you discover policy or other info about a host (the so-called "site-wide metadata") ๐Ÿ”‘. Think hosted resources and stuff, see Section 7 for the deets ๐Ÿ‘‘.

Application designers are encouraged to make their URIs short but descriptive ๐Ÿ“. Like, CoAP lives in environments that are super tight on bandwidth and energy, so you want to lean toward shortness here, without ditching the descriptive part entirely ๐Ÿ”‹. Balance is everything, periodt ๐Ÿ’œ.

6.2. coaps URI Scheme ๐Ÿ”

coaps-URI = "coaps:" "//" host [ ":" port ] path-abempty
            [ "?" query ]

so "coaps" is basically the secure sibling of "coap" ๐Ÿ”’. Every single requirement listed above for "coap" also applies to "coaps" ๐Ÿ’ฏ, with two little differences. First, the default UDP port is 5684 when the port subcomponent is empty or missing ๐ŸŽ€. Second, the UDP datagrams MUST be secured with DTLS, as described in Section 9.1 ๐Ÿ›ก๏ธ. No DTLS, no "coaps" ๐Ÿ™…โ€โ™€๏ธ.

Caching of responses to "coaps" identified requests is covered in Section 11.2 ๐ŸงŠ.

Resources available through "coaps" have no shared identity with the "coap" scheme ๐Ÿซฃ. Even if both URIs point to the same authority, meaning the same host listening on the same UDP port, they're totally separate namespaces ๐Ÿ‘ฏโ€โ™€๏ธ. They're treated as distinct origin servers, so no mixing them up!! ๐Ÿ˜ญ

6.3. Normalization and Comparison Rules ๐Ÿงฎ

Since "coap" and "coaps" follow the URI generic syntax, these URIs get normalized and compared using the algorithm in Section 6 of [RFC3986] โœจ. You just use the defaults described above for each scheme ๐ŸŒˆ.

If the port matches the default port for the scheme, the normal form is to drop the port subcomponent entirely ๐Ÿ—‘๏ธ. An empty path counts as an absolute path of "/", so the normal form gives you "/" instead ๐Ÿ™Œ. The scheme and host are case insensitive and usually written in lowercase ๐Ÿ”ก. IP-literals should be in the recommended form from [RFC5952] ๐ŸŒŸ. Everything else gets compared case-sensitively, so be careful, bestie ๐Ÿง. Characters outside the "reserved" set are equivalent to their percent-encoded bytes (see Section 2.1 of [RFC3986]), and the normal form is to not encode them ๐Ÿซถ.

Here's a cute example where these three URIs are all equivalent and end up producing the same options and option values in the CoAP messages ๐ŸŽ€:

coap://example.com:5683/~sensors/temp.xml
coap://EXAMPLE.com/%7Esensors/temp.xml
coap://EXAMPLE.com:/%7esensors/temp.xml

6.4. Decomposing URIs into Options ๐Ÿฐ

This is the recipe for parsing a request's options out of a string called |url| ๐Ÿฅฃ. The steps either give you zero or more of the Uri-Host, Uri-Port, Uri-Path, and Uri-Query Options in the request, or they fail ๐Ÿ’€.

  1. If the |url| string isn't an absolute URI ([RFC3986]), then fail this algorithm ๐Ÿ™…โ€โ™€๏ธ.
  2. Resolve the |url| string using the reference resolution process defined by [RFC3986] ๐Ÿ”. At this point the URL is in ASCII encoding ([RFC0020]), even though the decoded components get interpreted in UTF-8 ([RFC3629]) after steps 5, 8, and 9 ๐ŸŒ.

NOTE: It doesn't matter what it's resolved relative to, since we already know it's an absolute URL at this stage ๐Ÿคทโ€โ™€๏ธ.

  1. If |url| doesn't have a <scheme> component whose value, when converted to ASCII lowercase, is "coap" or "coaps", then fail this algorithm ๐Ÿšซ.
  2. If |url| has a <fragment> component, then fail this algorithm ๐Ÿ’….
  3. If the <host> component of |url| doesn't represent the request's destination IP address as an IP-literal or IPv4address, include a Uri-Host Option โœจ. Its value is the <host> component of |url|, converted to ASCII lowercase, with all percent-encodings ("%" followed by two hexadecimal digits) converted to the matching characters ๐Ÿ”ค.

NOTE: In the usual case where the destination IP address comes from the host part, this makes sure a Uri-Host Option only ever shows up for a <host> component of the form reg-name ๐Ÿง .

  1. If |url| has a <port> component, then let |port| be that component's value read as a decimal integer ๐Ÿ”ข. Otherwise, let |port| be the default port for the scheme ๐ŸŽฏ.
  2. If |port| doesn't equal the request's destination UDP port, include a Uri-Port Option, and its value is |port| ๐Ÿ”Œ.
  3. If the value of the <path> component of |url| is empty or is just a single slash character (U+002F SOLIDUS "/"), then move on to the next step ๐Ÿ‘‰.

Otherwise, for each segment in the <path> component, include a Uri-Path Option. Its value is the segment (without the delimiting slashes), with each percent-encoding ("%" followed by two hexadecimal digits) converted to the matching byte ๐Ÿงฉ.

  1. If |url| has a <query> component, then, for each argument in it, include a Uri-Query Option. Its value is the argument (without the question mark and the delimiting ampersands), with each percent-encoding converted to the matching byte ๐ŸŽ.

Note that these rules completely resolve any percent-encoding ๐Ÿ’–.

6.5. Composing URIs from Options ๐Ÿ—๏ธ

Now the reverse ๐Ÿชž. These are the steps for building a URI from a request's options, and they either give you a URI or they fail ๐Ÿ™ƒ. Here, percent-encoding a character means swapping each of its (UTF-8-encoded) bytes for a "%" followed by two hexadecimal digits representing that byte ๐Ÿ” . The A-F digits are uppercase (as in Section 2.1 of [RFC3986]), and to cut down on variability, the hexadecimal notation for percent-encoding in CoAP URIs MUST use uppercase letters ๐Ÿ” โœจ. The definitions of "unreserved" and "sub-delims" come straight from [RFC3986] ๐Ÿ“–.

  1. If the request is secured using DTLS, let |url| be the string "coaps://". Otherwise, let |url| be the string "coap://" ๐Ÿ”.
  2. If the request includes a Uri-Host Option, let |host| be that option's value, with any non-ASCII characters replaced by their percent-encoding ๐ŸŒ. If |host| isn't a valid reg-name, IP-literal, or IPv4address, fail the algorithm ๐Ÿšซ. If the request doesn't include a Uri-Host Option, let |host| be the IP-literal (following the conventions of [RFC5952]) or IPv4address representing the request's destination IP address ๐Ÿ“.
  3. Append |host| to |url| โž•.
  4. If the request includes a Uri-Port Option, let |port| be that option's value ๐Ÿ”Œ. Otherwise, let |port| be the request's destination UDP port ๐ŸŽฏ.
  5. If |port| isn't the default port for the scheme, append a single U+003A COLON character (:) followed by the decimal representation of |port| to |url| ๐Ÿ’.
  6. Let |resource name| be the empty string ๐Ÿซ™. For each Uri-Path Option in the request, append a single U+002F SOLIDUS character (/) followed by the option's value to |resource name|, converting any character that isn't in the "unreserved" set, the "sub-delims" set, a U+003A COLON (:), or a U+0040 COMMERCIAL AT (@) into its percent-encoded form ๐Ÿง.
  7. If |resource name| is the empty string, set it to a single U+002F SOLIDUS character (/) ๐ŸŒท.
  8. For each Uri-Query Option in the request, append a single U+003F QUESTION MARK (?) for the first option, or U+0026 AMPERSAND (&) for subsequent options, followed by the option's value to |resource name| ๐ŸŽ€. Any character that isn't in the "unreserved" set, the "sub-delims" set (except U+0026 AMPERSAND (&)), a U+003A COLON (:), a U+0040 COMMERCIAL AT (@), a U+002F SOLIDUS (/), or a U+003F QUESTION MARK (?) gets converted to its percent-encoded form ๐Ÿ’….
  9. Append |resource name| to |url| ๐Ÿงท.
  10. Return |url| ๐ŸŽ‰.

Note that these steps are designed to lead to a URI in normal form (see Section 6.3), so everything lines up neatly ๐Ÿ’œ.


7. Discovery ๐Ÿ”

7.1. Service Discovery ๐Ÿ›Ž๏ธ

As part of discovering the services a CoAP server offers, a client has to learn about the endpoint the server uses ๐Ÿ‘€.

A client discovers a server by knowing or learning a URI that references a resource in that server's namespace ๐Ÿ—๏ธ. Alternatively, clients can use multicast CoAP (see Section 8) and the "All CoAP Nodes" multicast address to hunt down CoAP servers ๐Ÿ“ก.

Unless the port subcomponent in a "coap" or "coaps" URI tells you the UDP port the CoAP server is on, the server is assumed to be reachable at the default port ๐Ÿก.

The CoAP default port number 5683 MUST be supported by a server that offers resources for resource discovery (see Section 7.2 below), and it SHOULD be supported for providing access to other resources ๐Ÿ’–. The default port number 5684 for DTLS-secured CoAP MAY be supported by a server for resource discovery and for providing access to other resources ๐Ÿ”. Beyond that, other endpoints can be hosted at other ports, e.g., in the dynamic port space ๐Ÿงš.

Implementation Note: When a CoAP server is hosted by a 6LoWPAN node, header compression efficiency improves when it also supports a port number in the 61616-61631 compressed UDP port space defined in [RFC4944] and [RFC6282] ๐Ÿ—œ๏ธ. (Note that, since its UDP port differs from the default port, it's a different endpoint from the server at the default port ๐Ÿ‘ฏ.)

7.2. Resource Discovery ๐Ÿ—‚๏ธ

Discovering the resources a CoAP endpoint offers is extremely important in machine-to-machine applications, where there are no humans in the loop and static interfaces lead to fragility ๐Ÿค–๐Ÿ’”. To maximize interoperability in a CoRE environment, a CoAP endpoint SHOULD support the CoRE Link Format of discoverable resources as described in [RFC6690], except where fully manual configuration is wanted โœจ. It's up to the server which resources get made discoverable (if any) ๐ŸŒธ.

7.2.1. 'ct' Attribute ๐ŸŽ€

Okay bestie, this part introduces a brand new Web Linking [RFC5988] attribute built to work with [RFC6690] โœจ. It's called "ct", and it's giving "here's a little hint about which Content-Formats this resource hands back" ๐Ÿ’…. It's only a hint though! It does not override the Content-Format Option of a CoAP response you get by actually requesting the representation ๐Ÿ™ˆ. The value is a CoAP identifier code written as a decimal ASCII integer, and it MUST be in the range 0-65535 (a 16-bit unsigned integer) ๐Ÿ”ข. For example, "application/xml" gets written as ct=41 ๐Ÿงš. If there's no Content-Format code attribute, then you can't assume anything about the type, so don't guess ๐Ÿ’€. The attribute MAY include a space-separated sequence of Content-Format codes, which means multiple formats are available ๐ŸŒˆ. The syntax lives in the production "ct-value" in Figure 12, where "cardinal", "SP", and "DQUOTE" are defined exactly as in [RFC6690] ๐Ÿซถ.

ct-value =  cardinal
         /  DQUOTE cardinal *( 1*SP cardinal ) DQUOTE

Figure 12


8. Multicast CoAP ๐ŸŒธ

Okay so CoAP can totally make requests to an IP multicast group, and this is defined as a series of deltas on top of regular unicast CoAP ๐Ÿฆ‹. If you want the bigger picture on group communication, check out [GROUPCOMM] ๐Ÿ‘‘.

CoAP endpoints that offer services they want other endpoints to find through multicast service discovery join one or more of the appropriate all-CoAP-node multicast addresses (Section 12.8) and listen on the default CoAP port ๐Ÿ“ก. Here's the tea: an endpoint might also receive multicast requests on other multicast addresses, including the all-nodes IPv6 address (or via broadcast on IPv4) ๐Ÿ˜ญ. So an endpoint MUST therefore be prepared to receive those messages, but it MAY ignore them if multicast service discovery isn't wanted ๐Ÿ™ˆโœจ.

8.1. Messaging Layer ๐Ÿ’Œ

A multicast request is characterized by being carried in a CoAP message that is addressed to an IP multicast address instead of a CoAP endpoint ๐Ÿ’ซ. Such multicast requests MUST be Non-confirmable ๐Ÿ™…โ€โ™€๏ธ.

A server SHOULD be aware that a request arrived via multicast, e.g., by using modern APIs such as IPV6_RECVPKTINFO [RFC3542], if available ๐Ÿง .

To avoid an implosion of error responses ๐Ÿ’ฅ, when a server is aware that a request arrived via multicast, it MUST NOT return a Reset message in reply to a Non-confirmable message. If it isn't aware, it MAY return a Reset message in reply to a Non-confirmable message as usual. A Reset like that looks exactly like one for a unicast message from the sender, so the sender MUST avoid using a Message ID that is also still active from this endpoint with any unicast endpoint that might receive the multicast message ๐ŸŽฏ.

At the time of writing, multicast messages can only be carried in UDP, not in DTLS. This means the security modes defined for CoAP in this document are not applicable to multicast. โš ๏ธ

8.2. Request/Response Layer ๐ŸŽ€

When a server is aware that a request arrived via multicast, the server MAY always ignore the request, especially if it has nothing useful to respond with (e.g., if it only has an empty payload or an error response) ๐Ÿซ . That call can depend on the application. (For example, in query filtering as described in [RFC6690], a server should not respond to a multicast request if the filter doesn't match. More examples are in [GROUPCOMM].) ๐Ÿ’…

If a server does decide to respond to a multicast request, it should not respond immediately. Instead, it should pick a duration for the period of time during which it intends to respond โณ. For this exposition, we call the length of that period the Leisure ๐Ÿฆ‹. The specific value of this Leisure may depend on the application or MAY be derived as described below. The server SHOULD then pick a random point of time within the chosen leisure period to send back the unicast response to the multicast request ๐ŸŽฒ. If further responses need to be sent based on the same multicast address membership, a new leisure period starts at the earliest after the previous one finishes ๐Ÿ”.

To compute a value for Leisure, the server should have a group size estimate G, a target data transfer rate R (both should be chosen conservatively), and an estimated response size S. A rough lower bound for Leisure can then be computed as:

lb_Leisure = S * G / R

For example, for a multicast request with link-local scope on a 2.4 GHz IEEE 802.15.4 (6LoWPAN) network, G could be (relatively conservatively) set to 100, S to 100 bytes, and the target rate to 8 kbit/s = 1 kB/s. The resulting lower bound for the Leisure is 10 seconds โฑ๏ธโœจ.

If a CoAP endpoint doesn't have suitable data to compute a value for Leisure, it MAY resort to DEFAULT_LEISURE ๐Ÿซถ.

When matching a response to a multicast request, only the token MUST match. The source endpoint of the response doesn't need to be (and won't be) the same as the destination endpoint of the original request ๐Ÿงš.

For the purposes of interpreting the Location-* options and any links embedded in the representation, the request URI (i.e., the base URI relative to which the response is interpreted) is formed by replacing the multicast address in the Host component of the original request URI with the literal IP address of the endpoint that actually responded ๐Ÿ“.

8.2.1. Caching ๐Ÿ—ƒ๏ธ

When a client makes a multicast request, it always makes a new request to the multicast group. That's because there may be new group members that joined in the meantime, or ones that didn't get the previous request ๐Ÿ‘€. It MAY update a cache with the received responses. Then it uses both cached-still-fresh and new responses as the result of the request ๐Ÿ’–.

A response received in reply to a GET request to a multicast group MAY be used to satisfy a subsequent request on the related unicast request URI. The unicast request URI is obtained by replacing the authority part of the request URI with the transport-layer source address of the response message ๐Ÿฆ‹.

A cache MAY revalidate a response by making a GET request on the related unicast request URI ๐Ÿ”.

A GET request to a multicast group MUST NOT contain an ETag option. A mechanism to suppress responses the client already has is left for further study ๐Ÿง.

8.2.2. Proxying ๐Ÿ”€

When a forward-proxy receives a request with a Proxy-Uri, or a URI constructed from Proxy-Scheme, that indicates a multicast address, the proxy obtains a set of responses as described above. It then sends all responses (both cached-still-fresh and new) back to the original client ๐Ÿš€.

This specification doesn't provide a way to indicate the unicast-modified request URI (base URI) in responses forwarded this way. Proxying multicast requests is discussed in more detail in [GROUPCOMM], and one proposal to address the base URI issue can be found in Section 3 of [CoAP-MISC] ๐Ÿ™Œ.


9. Securing CoAP ๐Ÿ”

This section defines the DTLS binding for CoAP ๐ŸŽ€.

During the provisioning phase, a CoAP device gets the security information it needs, including keying materials and access control lists ๐Ÿ—๏ธ. This specification defines provisioning for the RawPublicKey mode in Section 9.1.3.2.1. At the end of the provisioning phase, the device will be in one of four security modes, each with the following information for that mode. The NoSec and RawPublicKey modes are mandatory to implement for this specification ๐Ÿ‘‘.

  • NoSec: There is no protocol-level security, because DTLS is disabled. Alternative techniques to provide lower-layer security SHOULD be used when appropriate. The use of IPsec is discussed in [IPsec-CoAP]. Certain link layers used with constrained nodes also provide link-layer security, which may be appropriate with proper key management ๐Ÿงฑ.
  • PreSharedKey: DTLS is enabled, there is a list of pre-shared keys [RFC4279], and each key includes a list of which nodes it can be used to communicate with, as described in Section 9.1.3.1. At the extreme, there may be one key for each node this CoAP node needs to communicate with (a 1:1 node/key ratio). Conversely, if more than two entities share a specific pre-shared key, this key only enables the entities to authenticate as a member of that group and not as a specific peer ๐Ÿ”‘.
  • RawPublicKey: DTLS is enabled, and the device has an asymmetric key pair without a certificate (a raw public key) that is validated using an out-of-band mechanism [RFC7250], as described in Section 9.1.3.2. The device also has an identity calculated from the public key and a list of identities of the nodes it can communicate with ๐Ÿฆ„.
  • Certificate: DTLS is enabled, and the device has an asymmetric key pair with an X.509 certificate [RFC5280] that binds it to its subject and is signed by some common trust root, as described in Section 9.1.3.3. The device also has a list of root trust anchors that can be used for validating a certificate ๐Ÿ“œ.

In the "NoSec" mode, the system simply sends the packets over normal UDP over IP, and it is indicated by the "coap" scheme and the CoAP default port ๐Ÿ“ฆ. The system is secured only by keeping attackers from being able to send or receive packets from the network with the CoAP nodes. See Section 11.5 for an additional complication with this approach ๐Ÿ˜ฌ.

The other three security modes are achieved using DTLS and are indicated by the "coaps" scheme and the DTLS-secured CoAP default port ๐Ÿ”’. The result is a security association that can be used to authenticate (within the limits of the security model) and, based on this authentication, authorize the communication partner ๐Ÿซถ. CoAP itself doesn't provide protocol primitives for authentication or authorization. Where this is required, it can be provided either by communication security (i.e., IPsec or DTLS) or by object security (within the payload). Devices that require authorization for certain operations are expected to require one of these two forms of security ๐Ÿ›ก๏ธ. Necessarily, where an intermediary is involved, communication security only works when that intermediary is part of the trust relationships. CoAP doesn't provide a way to forward different levels of authorization that clients may have with an intermediary to further intermediaries or origin servers -- so it therefore may be required to perform all authorization at the first intermediary ๐Ÿฅบโœจ.

9.1. DTLS-Secured CoAP โœจ

okay so just like HTTP gets its security glow-up from TLS over TCP ๐Ÿ”, CoAP gets its own with Datagram TLS (DTLS) [RFC6347] over UDP (check Figure 13 ๐Ÿ‘€). This section defines the CoAP binding to DTLS, along with the minimal mandatory-to-implement configurations appropriate for constrained environments. The binding is defined as a series of deltas to unicast CoAP. In practice, DTLS is basically TLS with extra features to handle the unreliable nature of UDP transport ๐Ÿฆ‹

                         +----------------------+
                         |      Application     |
                         +----------------------+
                         +----------------------+
                         |  Requests/Responses  |
                         |----------------------|  CoAP
                         |       Messages       |
                         +----------------------+
                         +----------------------+
                         |         DTLS         |
                         +----------------------+
                         +----------------------+
                         |          UDP         |
                         +----------------------+

             Figure 13: Abstract Layering of DTLS-Secured CoAP

In some constrained nodes (limited flash and/or RAM) and networks (limited bandwidth or high scalability requirements), and depending on the specific cipher suites in use, all modes of DTLS may not be applicable ๐Ÿฅบ Some DTLS cipher suites can add serious implementation complexity, plus some initial handshake overhead needed when setting up the security association. Once the initial handshake is completed, DTLS adds a limited per-datagram overhead of approximately 13 bytes, not including any initialization vectors/ nonces (e.g., 8 bytes with TLS_PSK_WITH_AES_128_CCM_8 [RFC6655]), integrity check values (e.g., 8 bytes with TLS_PSK_WITH_AES_128_CCM_8 [RFC6655]), and padding required by the cipher suite. Whether a given mode of DTLS is applicable for a CoAP-based application should be carefully weighed ๐Ÿง considering the specific cipher suites that may be applicable, whether session maintenance makes it compatible with application flows, and whether sufficient resources are available on the constrained nodes and for the added network overhead.

(For some modes of using DTLS, this specification identifies a mandatory-to-implement cipher suite. This is an implementation requirement to maximize interoperability in those cases where these cipher suites are indeed appropriate. The specific security policies of an application may determine the actual set of cipher suites that can be used.) DTLS is not applicable to group keying (multicast communication); however, it may be a component in a future group key management protocol ๐ŸŒธ


9.1.1. Messaging Layer

The endpoint acting as the CoAP client should also act as the DTLS client ๐Ÿ’… It should initiate a session to the server on the appropriate port. When the DTLS handshake has finished, the client may initiate the first CoAP request. All CoAP messages MUST be sent as DTLS "application data" ๐Ÿ”ฅ

The following rules are added for matching an Acknowledgement message or Reset message to a Confirmable message, or a Reset message to a Non-confirmable message: The DTLS session MUST be the same, and the epoch MUST be the same.

A message is the same when it is sent within the same DTLS session and same epoch and has the same Message ID ๐ŸŽ€

Note: When a Confirmable message is retransmitted, a new DTLS sequence_number is used for each attempt, even though the CoAP Message ID stays the same. So a recipient still has to perform deduplication as described in Section 4.5. Retransmissions MUST NOT be performed across epochs ๐Ÿ™ˆ

DTLS connections in RawPublicKey and Certificate mode are set up using mutual authentication, so they can stay up and be reused for future message exchanges in either direction โœจ Devices can close a DTLS connection when they need to recover resources, but in general they should keep the connection up for as long as possible. Closing the DTLS connection after every CoAP message exchange is very inefficient ๐Ÿ’€


9.1.2. Request/Response Layer

The following rules are added for matching a response to a request: The DTLS session MUST be the same, and the epoch MUST be the same. ๐Ÿซถ

This means the response to a DTLS secured request MUST always be DTLS secured using the same security session and epoch. Any attempt to supply a NoSec response to a DTLS request simply does not match the request and therefore MUST be rejected (unless it does match an unrelated NoSec request) ๐Ÿ˜ญ


9.1.3. Endpoint Identity

Devices SHOULD support the Server Name Indication (SNI) to indicate their authority in the SNI HostName field, as defined in Section 3 of [RFC6066] ๐Ÿ‘‘ This is needed so that when a host acting as a virtual server for multiple Authorities receives a new DTLS connection, it knows which keys to use for the DTLS session.


9.1.3.1. Pre-Shared Keys

When forming a connection to a new node, the system selects an appropriate key based on which nodes it is trying to reach, and then forms a DTLS session using a PSK (Pre-Shared Key) mode of DTLS ๐Ÿ”‘ Implementations in these modes MUST support the mandatory-to-implement cipher suite TLS_PSK_WITH_AES_128_CCM_8 as specified in [RFC6655].

Depending on the commissioning model, applications may need to define an application profile for identity hints (as required and detailed in Section 5.2 of [RFC4279]) so they can use PSK identity hints ๐Ÿ“

The security considerations of Section 7 of [RFC4279] apply. In particular, applications should carefully weigh whether or not they need Perfect Forward Secrecy (PFS), and select an appropriate cipher suite (Section 7.1 of [RFC4279]). The entropy of the PSK must be sufficient to mitigate against brute-force and (where the PSK is not chosen randomly but by a human) dictionary attacks (Section 7.2 of [RFC4279]) ๐Ÿ˜ฑ The cleartext communication of client identities may leak data or compromise privacy (Section 7.3 of [RFC4279]). Seriously, this part matters, bestie ๐Ÿšจ


9.1.3.2. Raw Public Key Certificates

In this mode, the device has an asymmetric key pair but without an X.509 certificate (called a raw public key). For example, the asymmetric key pair is generated by the manufacturer and installed on the device (see also Section 11.6) ๐Ÿงš A device MAY be configured with multiple raw public keys. The type and length of the raw public key depends on the cipher suite used.

Implementations in RawPublicKey mode MUST support the mandatory-to-implement cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 as specified in [RFC7251], [RFC5246], and [RFC4492]. The key used MUST be ECDSA capable. The curve secp256r1 MUST be supported [RFC4492]; this curve is equivalent to the NIST P-256 curve. The hash algorithm is SHA-256. Implementations MUST use the Supported Elliptic Curves and Supported Point Formats Extensions [RFC4492]; the uncompressed point format MUST be supported, and [RFC6090] can be used as an implementation method. Some guidance relevant to the implementation of this cipher suite can be found in [W3CXMLSEC]. The mechanism for using raw public keys with TLS is specified in [RFC7250] ๐ŸŒˆ

Implementation Note: Specifically, this means the extensions listed in Figure 14 with at least the values listed will be present in the DTLS handshake ๐Ÿง 

   Extension: elliptic_curves
    Type: elliptic_curves (0x000a)
    Length: 4
    Elliptic Curves Length: 2
    Elliptic curves (1 curve)
      Elliptic curve: secp256r1 (0x0017)

   Extension: ec_point_formats
    Type: ec_point_formats (0x000b)
    Length: 2
    EC point formats Length: 1
    Elliptic curves point formats (1)
      EC point format: uncompressed (0)

   Extension: signature_algorithms
    Type: signature_algorithms (0x000d)
    Length: 4
    Data (4 bytes): 00 02 04 03
      HashAlgorithm: sha256 (4)
      SignatureAlgorithm: ecdsa (3)
                  Figure 14: DTLS Extensions Present for
                    TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8

9.1.3.2.1. Provisioning

The RawPublicKey mode was designed to be easily provisioned in M2M deployments ๐Ÿค– It is assumed that each device has an appropriate asymmetric public key pair installed. An identifier is calculated by the endpoint from the public key, as described in Section 2 of [RFC6920]. All implementations that support checking RawPublicKey identities MUST support at least the sha-256-120 mode (SHA-256 truncated to 120 bits). Implementations SHOULD also support longer length identifiers and MAY support shorter lengths. Note that shorter lengths provide less security against attacks, and their use is NOT RECOMMENDED ๐Ÿ™…โ€โ™€๏ธ

Depending on how identifiers are given to the system that verifies them, support for URI, binary, and/or human-speakable format [RFC6920] needs to be implemented. All implementations SHOULD support the binary mode, and implementations that have a user interface SHOULD also support the human-speakable format ๐Ÿ’–

During provisioning, the identifier of each node is collected, for example, by reading a barcode on the outside of the device or by obtaining a pre-compiled list of the identifiers. These identifiers are then installed in the corresponding endpoint, for example, an M2M data collection server. The identifier is used for two purposes: to associate the endpoint with further device information, and to perform access control. During (initial and ongoing) provisioning, an access control list of identifiers with which the device may start DTLS sessions SHOULD also be installed and maintained ๐Ÿ”’

9.1.3.3. X.509 Certificates โœจ

okay so if you're in Certificate Mode, you MUST support the mandatory-to-implement cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ๐Ÿ” as specified in [RFC7251], [RFC5246], and [RFC4492]. The certificate has to include a SubjectPublicKeyInfo saying the algorithm is id-ecPublicKey with namedCurves secp256r1 [RFC5480], and the public key format is uncompressed [RFC5480]. The hash algorithm is SHA-256, and if the key usage extension is included, it indicates digitalSignature. Certificates MUST be signed with ECDSA using secp256r1, and the signature MUST use SHA-256. The key MUST be ECDSA capable. The curve secp256r1 MUST be supported [RFC4492], and it's the same thing as the NIST P-256 curve ๐Ÿ’…. Implementations MUST use the Supported Elliptic Curves and Supported Point Formats Extensions [RFC4492], the uncompressed point format MUST be supported, and [RFC6090] can be used as an implementation method ๐Ÿซถ.

The subject in the certificate would be built from a long-term unique identifier for the device, like the EUI-64 [EUI64] ๐ŸŽ€. The subject could also be based on the Fully Qualified Domain Name (FQDN) that was used as the Host part of the CoAP URI. Not me though, the device's IP address should not typically be used as the subject ๐Ÿ™ˆ, because it would change over time. The discovery process in the system would build the mapping between the IP addresses of each device and its subject. Some devices could have more than one subject and would need more than a single certificate. Main character energy for sure ๐Ÿ‘‘.

When a new connection is formed, the certificate from the remote device needs to be verified ๐Ÿ”. If the CoAP node has a source of absolute time, then the node SHOULD check that the validity dates of the certificate are within range. The certificate MUST be validated as appropriate for the security requirements, using functionality equivalent to the algorithm in Section 6 of [RFC5280]. If the certificate contains a SubjectAltName, then the authority of the request URI MUST match at least one of the authorities of any CoAP URI found in a field of URI type in the SubjectAltName set. If there is no SubjectAltName in the certificate, then the authority of the request URI MUST match the Common Name (CN) found in the certificate, using the matching rules defined in [RFC3280], with the exception that certificates with wildcards are not allowed ๐Ÿšซ.

CoRE support for certificate status checking requires further study ๐Ÿ“š. A mapping of the Online Certificate Status Protocol (OCSP) [RFC6960] onto CoAP isn't defined right now, and OCSP may also not be easily applicable in all environments. So an alternative approach may be using the TLS Certificate Status Request extension (Section 8 of [RFC6066]; also known as "OCSP stapling") or, preferably, the Multiple Certificate Status Extension ([RFC6961]), if available ๐ŸŒˆ.

If the system has a shared key in addition to the certificate, then a cipher suite that includes the shared key, such as TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA [RFC5489], SHOULD be used ๐Ÿ“.


10. Cross-Protocol Proxying between CoAP and HTTP ๐Ÿฆ‹

okay so CoAP only supports a limited subset of HTTP functionality, which means proxying between the two is honestly pretty straightforward ๐Ÿ˜Œ. There are a few reasons you might want to proxy between CoAP and HTTP, like designing a web interface that works over either protocol or building an actual CoAP-HTTP proxy ๐Ÿงš. CoAP could also be proxied to other protocols like XMPP [RFC6120] or SIP [RFC3264], but defining those mechanisms is out of scope for this spec, so we're skipping them ๐Ÿ™…โ€โ™€๏ธ.

There are two possible directions for accessing a resource through a forward-proxy:

  • CoAP-HTTP Proxying: lets CoAP clients access resources on HTTP servers through an intermediary. It's kicked off by including the Proxy-Uri or Proxy-Scheme Option with an "http" or "https" URI in a CoAP request to a CoAP-HTTP proxy ๐ŸŽ€.
  • HTTP-CoAP Proxying: lets HTTP clients access resources on CoAP servers through an intermediary. It's kicked off by specifying a "coap" or "coaps" URI in the Request-Line of an HTTP request to an HTTP-CoAP proxy ๐Ÿ’œ.

Either way, only the request/response model of CoAP gets mapped to HTTP. The underlying model of Confirmable or Non-confirmable messages, etc., is invisible and MUST have no effect on a proxy function ๐Ÿ‘€. The following sections describe how requests to a forward-proxy are handled. Reverse-proxies aren't specified, since the proxy function is transparent to the client, with the proxy acting as if it were the origin server. Still, similar considerations apply to reverse-proxies as to forward-proxies, and there generally will be an expectation that reverse-proxies operate in a similar way to forward-proxies ๐Ÿ”. As an implementation note, HTTP client libraries may make it hard to operate an HTTP-CoAP forward-proxy by not giving you a way to put a CoAP URI on the HTTP Request-Line, so reverse-proxying may therefore lead to wider applicability of a proxy ๐ŸŒธ. A separate specification may define a convention for URIs operating such an HTTP-CoAP reverse-proxy [MAPPING].

10.1. CoAP-HTTP Proxying

If a request contains a Proxy-Uri or Proxy-Scheme Option with an 'http' or 'https' URI [RFC2616], then the receiving CoAP endpoint (called "the proxy" from here on) is requested to perform the operation specified by the request method on the indicated HTTP resource and return the result to the client. (See also Section 5.7 for how the request to the proxy is formulated, including security requirements ๐Ÿ”’.)

This section specifies, for any CoAP request, the CoAP response that the proxy should return to the client. How the proxy actually satisfies the request is an implementation detail ๐Ÿ› ๏ธ, although the typical case is expected to be that the proxy translates and forwards the request to an HTTP origin server.

Since HTTP and CoAP share the basic set of request methods, performing a CoAP request on an HTTP resource isn't that different from performing it on a CoAP resource ๐Ÿค. The meanings of the individual CoAP methods when performed on HTTP resources are explained in the subsections below.

If the proxy is unable or unwilling to service a request with an HTTP URI, a 5.05 (Proxying Not Supported) response is returned to the client ๐Ÿ™…โ€โ™€๏ธ. If the proxy services the request by interacting with a third party (such as the HTTP origin server) and can't get a result within a reasonable time frame, a 5.04 (Gateway Timeout) response is returned. If a result can be obtained but isn't understood, a 5.02 (Bad Gateway) response is returned ๐Ÿ’€.

10.1.1. GET

The GET method asks the proxy to return a representation of the HTTP resource identified by the request URI ๐Ÿ“–.

On success, a 2.05 (Content) Response Code SHOULD be returned ๐ŸŽ‰. The payload of the response MUST be a representation of the target HTTP resource, and the Content-Format Option MUST be set accordingly. The response MUST indicate a Max-Age value that is no greater than the remaining time the representation can be considered fresh โฐ. If the HTTP entity has an entity-tag, the proxy SHOULD include an ETag Option in the response and process ETag Options in requests as described below ๐Ÿท๏ธ.

A client can influence how a GET request is processed by including the following options:

  • Accept: The request MAY include an Accept Option, identifying the preferred response content-format ๐Ÿ’–.
  • ETag: The request MAY include one or more ETag Options, identifying responses that the client has stored. This asks the proxy to send a 2.03 (Valid) response whenever it would otherwise send a 2.05 (Content) response with an entity-tag in the requested set ๐Ÿฅฐ. Note that CoAP ETags are always strong ETags in the HTTP sense. CoAP doesn't have the equivalent of HTTP weak ETags, and there's no good way to make use of them in a cross-proxy ๐Ÿ™ƒ.

10.1.2. PUT

The PUT method asks the proxy to update or create the HTTP resource identified by the request URI, using the enclosed representation โœ๏ธ.

If a new resource gets created at the request URI, a 2.01 (Created) response MUST be returned to the client. If an existing resource gets modified, a 2.04 (Changed) response MUST be returned to show the request finished successfully โœ….

10.1.3. DELETE

The DELETE method asks the proxy to delete the HTTP resource identified by the request URI at the HTTP origin server ๐Ÿ—‘๏ธ.

A 2.02 (Deleted) response MUST be returned to the client on success, or if the resource doesn't exist at the time of the request ๐Ÿซก.

10.1.4. POST

The POST method asks the proxy to have the representation enclosed in the request processed by the HTTP origin server. What the POST method actually does is decided by the origin server and depends on the resource identified by the request URI ๐Ÿง.

If the action performed by the POST method doesn't result in a resource that can be identified by a URI, a 2.04 (Changed) response MUST be returned to the client. If a resource has been created on the origin server, a 2.01 (Created) response MUST be returned ๐ŸŒŸ.

10.2. HTTP-CoAP Proxying

If an HTTP request contains a Request-URI with a "coap" or "coaps" URI, then the receiving HTTP endpoint (called "the proxy" from here on) is requested to perform the operation specified by the request method on the indicated CoAP resource and return the result to the client ๐Ÿช„.

This section specifies, for any HTTP request, the HTTP response that the proxy should return to the client. Unless otherwise specified, all the statements made are RECOMMENDED behavior ๐Ÿ’ซ. Some highly constrained implementations may need to resort to shortcuts ๐Ÿค. How the proxy actually satisfies the request is an implementation detail, although the typical case is expected to be that the proxy translates and forwards the request to a CoAP origin server. The meanings of the individual HTTP methods when performed on CoAP resources are explained in the subsections below.

If the proxy is unable or unwilling to service a request with a CoAP URI, a 501 (Not Implemented) response is returned to the client. If the proxy services the request by interacting with a third party (such as the CoAP origin server) and can't get a result within a reasonable time frame, a 504 (Gateway Timeout) response is returned. If a result can be obtained but isn't understood, a 502 (Bad Gateway) response is returned ๐Ÿซ .

10.2.1. OPTIONS and TRACE

Since the OPTIONS and TRACE methods aren't supported in CoAP, a 501 (Not Implemented) error MUST be returned to the client ๐Ÿ™Š.

10.2.2. GET

okay so GET is the "hey proxy, can you grab me the CoAP resource at this Request-URI and send it back" method ๐Ÿ’– and when it works you get a 200 (OK) back โœจ The payload MUST be a representation of the target CoAP resource, and the Content-Type and Content-Encoding header fields MUST be set to match it ๐ŸŽ€ The response MUST also have a max-age directive, and that value can't be bigger than however long the representation is still fresh ๐Ÿ•’ If the CoAP response has an ETag option, the proxy should include an ETag header field too ๐Ÿซถ

Clients can also tweak how a GET gets handled by adding these options ๐Ÿ’…

  • Accept: the most-preferred media type from the HTTP Accept header becomes a CoAP Accept option ๐ŸŒธ HTTP's media-type ranges, parameters, and extensions aren't supported by the CoAP Accept option, so those don't come along for the ride ๐Ÿ˜ญ If the proxy can't send back something that fits the combined Accept field value, it sends a 406 (Not Acceptable) response ๐Ÿ’€ The proxy MAY then retry the request with the next media types from the HTTP Accept header field ๐Ÿ”
  • Conditional GETs: conditional HTTP GET requests that include an If-Match or If-None-Match request-header field can be mapped onto a matching CoAP request ๐Ÿงš The If-Modified-Since and If-Unmodified-Since request-header fields aren't directly supported by CoAP, but a caching proxy handles them locally instead โœจ

10.2.3. HEAD

HEAD is basically GET's twin, except the server MUST NOT return a message-body in the response ๐Ÿ™ˆ Same headers, no body, no drama ๐Ÿฆ‹

CoAP doesn't have a direct version of HTTP's HEAD method, but an HTTP-CoAP proxy still responds to HEAD requests for CoAP resources ๐ŸŒˆ The HTTP headers come back with no message-body attached ๐Ÿ“

Implementation Note: an HTTP-CoAP proxy might want to use a block-wise transfer option [BLOCK] to cut down how much data actually gets transferred ๐Ÿ’œ It does need to be ready for the case where the origin server doesn't support block-wise transfers at all ๐Ÿ˜…


10.2.4. POST

POST is the "please process this representation I'm sending you" method ๐Ÿ”ฅ The proxy asks the CoAP origin server to handle the enclosed representation, and what actually happens is up to the origin server and depends on the resource at the request URI ๐Ÿ‘‘

If the POST doesn't result in a resource that has its own URI, a 200 (OK) or 204 (No Content) response MUST be returned to the client ๐ŸŒธ If a resource was created on the origin server, a 201 (Created) response MUST be returned ๐ŸŽ‰

If any of the Location-* Options show up in the CoAP response, the proxy builds a Location header field out of their values and returns it ๐Ÿ“


10.2.5. PUT

PUT means "update this resource, or make it if it doesn't exist yet" ๐Ÿงธ The proxy asks the CoAP origin server to do that with the enclosed representation at the Request-URI ๐Ÿ’–

If a brand new resource gets created at the Request-URI, the client gets a 201 (Created) response โœจ If an existing resource gets modified instead, the client gets either a 200 (OK) or a 204 (No Content) Response Code to say it went through โœ…


10.2.6. DELETE

DELETE asks the proxy to delete the CoAP resource at the Request-URI on the CoAP origin server ๐Ÿ—‘๏ธ Bye bye ๐Ÿ‘‹

A successful response is 200 (OK) if the response includes an entity describing the status ๐Ÿ“ It's 204 (No Content) if the action was enacted but the response doesn't include an entity ๐Ÿซง


10.2.7. CONNECT

Not gonna lie, this one isn't happening yet ๐Ÿ˜” An HTTP-CoAP proxy can't currently satisfy CONNECT, because TLS to DTLS tunneling hasn't been specified yet ๐Ÿšง For now the client gets a 501 (Not Implemented) error ๐Ÿ™ƒ


11. Security Considerations ๐Ÿ”

Okay bestie, this part is serious, so let's get into it ๐Ÿซถ This section looks at the possible threats to the protocol ๐Ÿ‘€ It's here to inform protocol and application developers about the security limitations of CoAP as described in this document ๐Ÿ’… CoAP realizes a subset of the features in HTTP/1.1, so the security considerations in Section 15 of [RFC2616] also apply to CoAP ๐ŸŒธ This section focuses on the limitations that are specific to CoAP โœจ


11.1. Parsing the Protocol and Processing URIs

A network-facing application can have vulnerabilities in the logic it uses to process incoming packets ๐Ÿ˜ฑ Complex parsers are well known as a likely source of these bugs, like being able to remotely crash a node or even remotely execute arbitrary code on it ๐Ÿ’€ CoAP tries to shrink those opportunities by keeping parser complexity down ๐Ÿงฉ It gives the whole range of encodable values a meaning where it can, and it aggressively cuts the complexity that usually comes from having unnecessary choices between multiple representations that mean the same thing ๐ŸŒˆ A lot of the URI processing has been moved to the clients, which means fewer chances for bugs to sneak into the servers ๐Ÿ™Œ Even so, the URI processing code in CoAP implementations is likely to be a big source of the remaining vulnerabilities, so it should be implemented with special care ๐Ÿ” CoAP access control implementations need to make sure they don't add vulnerabilities through mismatches between the code that makes access control decisions from a URI and the code that finally serves up the resource at that URI ๐Ÿšจ The most complex parser left might be the one for the CoRE Link Format, although that was also designed with reduced implementation complexity as a goal [RFC6690] ๐Ÿฆ‹ (See also Section 15.2 of [RFC2616].) ๐Ÿ’œ


11.2. Proxying and Caching

As Section 15.7 of [RFC2616] mentions, proxies are men-in-the-middle by their very nature ๐Ÿ˜ณ That means they break any IPsec or DTLS protection a direct CoAP message exchange might have ๐Ÿ™ˆ So they're interesting targets for breaking the confidentiality or integrity of CoAP message exchanges ๐ŸŽฏ As [RFC2616] notes, they're also interesting targets for breaking availability ๐Ÿ’”

The threat to confidentiality and integrity of request/response data gets amplified when proxies also cache ๐Ÿ“ฆ CoAP doesn't define any of the cache-suppressing Cache-Control options that HTTP/1.1 provides to better protect sensitive data, so keep that in mind ๐Ÿซฃ

For a caching implementation, any access control considerations that would apply to making the request that generated the cache entry also need to be applied to the value in the cache ๐Ÿ” This matters for clients that implement multiple security domains, and for proxies that might serve multiple clients ๐Ÿ‘ฏ Also, a caching proxy MUST NOT make cached values available to requests that have lesser transport-security properties than the ones the proxy would need to forward the request in the first place ๐Ÿšซ

Unlike the "coap" scheme, responses to "coaps" identified requests are never "public" ๐Ÿ”’ So they MUST NOT be reused for shared caching, unless the cache can make equivalent access control decisions to the ones that led to the cached entry ๐Ÿ›‘ They can, however, be reused in a private cache if the message is cacheable by default in CoAP ๐Ÿซง

Finally, a proxy that fans out Separate Responses (as opposed to piggybacked Responses) to multiple original requesters may add extra amplification ๐Ÿ“ข (See Section 11.3.) ๐ŸŒธ


11.3. Risk of Amplification

CoAP servers generally reply to a request packet with a response packet ๐Ÿ“จ That response packet can be a lot bigger than the request packet ๐Ÿ˜ฌ An attacker could use CoAP nodes to turn a small attack packet into a bigger one, which is known as amplification ๐Ÿ’ฅ So there's a real danger that CoAP nodes get dragged into denial-of-service (DoS) attacks by using the amplifying properties of the protocol ๐Ÿšจ An attacker trying to overload a victim, but limited in how much traffic it can generate, can use amplification to generate a lot more traffic ๐Ÿ“ˆ

This is especially a problem for nodes that enable NoSec access, can be reached by an attacker, and can reach potential victims (for example, on the general Internet) ๐ŸŒ That's because UDP provides no way to verify the source address in the request packet ๐Ÿซ  An attacker just needs to put the victim's IP address in the source address of a suitable request packet, and boom, a bigger packet gets aimed at the victim ๐ŸŽฏ

There is one mitigating factor: many constrained networks can only generate a small amount of traffic, which may make CoAP nodes less attractive for this attack ๐Ÿงธ But the limited capacity of a constrained network makes the network itself a likely victim of an amplification attack ๐Ÿ˜ข

So large amplification factors SHOULD NOT be provided in the response if the request isn't authenticated ๐Ÿšซ A CoAP server can cut down how much amplification it gives an attacker by using the slicing/blocking modes of CoAP [BLOCK] and offering large resource representations only in fairly small slices ๐Ÿฐ For example, for a 1000-byte resource, a 10-byte request might result in an 80-byte response (with a 64-byte block) instead of a 1016-byte response, which makes a huge difference in the amplification ๐Ÿ“‰

CoAP also supports using multicast IP addresses in requests, which is an important requirement for M2M ๐Ÿค– Multicast CoAP requests can be the source of accidental or deliberate DoS attacks, especially over constrained networks โš ๏ธ This specification tries to reduce the amplification effects of multicast requests by limiting when a response is returned ๐Ÿ›ก๏ธ To limit the chance of malicious use, CoAP servers SHOULD NOT accept multicast requests that can't be authenticated in some way, either cryptographically or by some multicast boundary that limits the potential sources ๐Ÿ”‘ If possible, a CoAP server SHOULD limit support for multicast requests to the specific resources where the feature is actually required ๐ŸŽ€

On some general-purpose operating systems with a POSIX-style API [IEEE1003.1], it isn't straightforward to find out whether a received packet was addressed to a multicast address ๐Ÿคฏ Plenty of implementations know whether they've joined a multicast group, but packets addressed to multicast addresses of the form FF0x::1 are received by every IPv6 node, and that creates a problem ๐Ÿ˜ต Implementations SHOULD make use of modern APIs such as IPV6_RECVPKTINFO [RFC3542], if they're available, to figure this out ๐Ÿง โœจ

11.4. IP Address Spoofing Attacks ๐ŸŽญ

okay so UDP has no handshake, which is lowkey a big problem ๐Ÿ™ˆ That means a rogue endpoint that can read AND write messages on the constrained network (aka NoSec or PreSharedKey setups where the nodes/key ratio is > 1:1) can totally mess with a single endpoint, a whole group of endpoints, or the entire network. For example, it could:

  1. spoof a Reset message in response to a Confirmable message or Non-confirmable message, thus making an endpoint "deaf"; or
  2. spoof an ACK in response to a CON message, thus potentially stopping the sender of the CON message from retransmitting, and drowning out the actual response; or
  3. spoof the entire response with forged payload/options (this has different levels of impact: from single-response disruption, to much bolder attacks on the supporting infrastructure, e.g., poisoning proxy caches, or tricking validation/lookup interfaces in resource directories and, more generally, any component that stores global network state and uses CoAP as the messaging facility to handle setting or updating state is a potential target.); or
  4. spoof a multicast request for a target node; this may result in network congestion/collapse, a DoS attack on the victim, or forced wake-up from sleeping; or
  5. spoof observe messages, etc.

Response spoofing by off-path attackers can be detected and mitigated even without transport layer security ๐Ÿ›ก๏ธ by choosing a nontrivial, randomized token in the request (Section 5.3.1). [RFC4086] discusses randomness requirements for security.

In principle, other kinds of spoofing can only be detected by CoAP if Confirmable message semantics is used, because you'd see unexpected Acknowledgement or Reset messages coming from the deceived endpoint. But that means keeping track of the used Message IDs, which isn't always possible, and honestly the detection usually shows up after the damage is already done ๐Ÿ˜ญ This kind of attack can be prevented using security modes other than NoSec.

With or without source address spoofing, a client can try to overload a server by sending requests, preferably complex ones, to it ๐Ÿ’€ Address spoofing makes tracing back and blocking this attack harder. Since the cost of a CON request is small, this attack can easily be executed. Under this attack, a constrained node with limited total energy may burn through that energy much faster than planned (battery depletion attack) ๐Ÿ”‹ Also, if the client uses a Confirmable message and the server responds with a Confirmable separate response to a (possibly spoofed) address that doesn't respond, the server will have to allocate buffer and retransmission logic for each response until it hits the exhaustion of MAX_TRANSMIT_SPAN, which makes it more likely to run out of resources for processing legitimate traffic. The latter problem can be eased somewhat by limiting the rate of responses, as discussed in Section 4.7. An attacker could also spoof the address of a legitimate client, which might cause the server, if it uses separate responses, to block legitimate responses to that client because of NSTART=1. All of these attacks can be prevented using a security mode other than NoSec, leaving only attacks on the security protocol ๐Ÿซถ

11.5. Cross-Protocol Attacks ๐ŸŽ€

The ability to get a CoAP endpoint to send packets to a fake source address isn't only useful for amplification, it can also be used for cross-protocol attacks against a victim listening to UDP packets at a given address (IP address and port) ๐Ÿ‘€ Here's how it goes down:

  • The attacker sends a message to a CoAP endpoint with the given address as the fake source address.
  • The CoAP endpoint replies with a message to the given source address.
  • The victim at the given address receives a UDP packet that it interprets according to the rules of a different protocol.

This may be used to get around firewall rules that block direct communication from the attacker to the victim, but happen to allow communication from the CoAP endpoint (which may also play a valid role in the other protocol) to the victim.

Also, CoAP endpoints may be the victim of a cross-protocol attack generated through an endpoint of another UDP-based protocol, such as DNS. In both cases, attacks are possible if the security properties of the endpoints rely on checking IP addresses (and on firewalling off direct attacks sent from outside using fake IP addresses). In general, because of their lack of context, UDP-based protocols are relatively easy targets for cross-protocol attacks ๐Ÿ˜ค

Finally, CoAP URIs transported by other means could be used to incite clients to send messages to endpoints of other protocols.

One mitigation against cross-protocol attacks is strict checking of the syntax of received packets, combined with a sufficient difference in syntax. For example, it might help if it were difficult to incite a DNS server to send a DNS response that would pass the checks of a CoAP endpoint. Unfortunately, the first two bytes of a DNS reply are an ID that can be chosen by the attacker, and that ID maps into the interesting part of the CoAP header. The next two bytes are then interpreted as CoAP's Message ID (i.e., any value is acceptable) ๐Ÿ™ƒ The DNS count words may be interpreted as multiple instances of a (nonexistent but elective) CoAP option 0, or possibly as a Token. The echoed query, finally, may be manufactured by the attacker to achieve a desired effect on the CoAP endpoint; the response added by the server (if any) might then just be interpreted as added payload.

                                1  1  1  1  1  1
  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                      ID                       | T, TKL, code
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   | Message ID
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    QDCOUNT                    | (options 0)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ANCOUNT                    | (options 0)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    NSCOUNT                    | (options 0)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|                    ARCOUNT                    | (options 0)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  Figure 15: DNS Header ([RFC1035], Section 4.1.1) vs. CoAP Message

In general, for any pair of protocols, one of them can very well have been designed in a way that lets an attacker cause the generation of replies that look like messages of the other protocol ๐Ÿ•ต๏ธโ€โ™€๏ธ It's often way harder to ensure or prove the absence of viable attacks than to come up with examples that don't yet fully enable an attack but might be developed further by more creative minds. Cross-protocol attacks can therefore only be completely mitigated if endpoints don't authorize actions the attacker wants just based on trusting the source IP address of a packet. Conversely, a NoSec environment that completely relies on a firewall for CoAP security not only needs to firewall off the CoAP endpoints, but also all other endpoints that might be incited to send UDP messages to CoAP endpoints using some other UDP-based protocol.

In addition to the considerations above, the security considerations for DTLS with respect to cross-protocol attacks apply. For example, if the same DTLS security association ("connection") is used to carry data of multiple protocols, DTLS no longer provides protection against cross-protocol attacks between those protocols ๐Ÿ”

11.6. Constrained-Node Considerations ๐Ÿงธ

Implementers on constrained nodes often find themselves without a good source of entropy [RFC4086]. If that's the case, the node MUST NOT be used for processes that require good entropy, such as key generation. Instead, keys should be generated externally and added to the device during manufacturing or commissioning ๐Ÿ”‘

Because of their low processing power, constrained nodes are particularly susceptible to timing attacks. Special care must be taken in the implementation of cryptographic primitives โฑ๏ธ

Large numbers of constrained nodes will be installed in exposed environments and will have little resistance to tampering, including recovery of keying materials. This needs to be considered when defining the scope of credentials assigned to them. In particular, assigning a shared key to a group of nodes may make any single constrained node a target for subverting the entire group ๐Ÿฅบ

12. IANA Considerations ๐ŸŒธ

12.1. CoAP Code Registries ๐Ÿ“

This document defines two sub-registries for the values of the Code field in the CoAP header within the "Constrained RESTful Environments (CoRE) Parameters" registry, hereafter referred to as the "CoRE Parameters" registry.

Values in the two sub-registries are eight-bit values notated as three decimal digits c.dd, separated by a period between the first and the second digit. The first digit c is between 0 and 7 and denotes the code class. The second and third digits dd denote a decimal number between 00 and 31 for the detail.

All Code values are assigned by sub-registries according to the following ranges:

0.00      Indicates an Empty message (see Section 4.1).

0.01-0.31 Indicates a request.  Values in this range are assigned by
          the "CoAP Method Codes" sub-registry (see Section 12.1.1).

1.00-1.31 Reserved

2.00-5.31 Indicates a response.  Values in this range are assigned by
          the "CoAP Response Codes" sub-registry (see
          Section 12.1.2).

6.00-7.31 Reserved

12.1.1. Method Codes ๐Ÿงš

The name of the sub-registry is "CoAP Method Codes".

Each entry in the sub-registry must include the Method Code in the range 0.01-0.31, the name of the method, and a reference to the method's documentation.

Initial entries in this sub-registry are as follows:

                    +------+--------+-----------+
                    | Code | Name   | Reference |
                    +------+--------+-----------+
                    | 0.01 | GET    | [RFC7252] |
                    | 0.02 | POST   | [RFC7252] |
                    | 0.03 | PUT    | [RFC7252] |
                    | 0.04 | DELETE | [RFC7252] |
                    +------+--------+-----------+

                     Table 5: CoAP Method Codes

All other Method Codes are Unassigned.

The IANA policy for future additions to this sub-registry is "IETF Review or IESG Approval" as described in [RFC5226].

The documentation of a Method Code should specify the semantics of a request with that code, including the following properties:

  • The Response Codes the method returns in the success case.
  • Whether the method is idempotent, safe, or both.

12.1.2. Response Codes โœจ

okay so this is the sub-registry for response codes, and it's called "CoAP Response Codes" ๐Ÿ’… every entry needs three things: the Response Code (which has to be somewhere in the 2.00-5.31 range), a description, and a reference to where that code is documented.

Here are the starter entries, bestie ๐ŸŽ€

+------+------------------------------+-----------+
| Code | Description                  | Reference |
+------+------------------------------+-----------+
| 2.01 | Created                      | [RFC7252] |
| 2.02 | Deleted                      | [RFC7252] |
| 2.03 | Valid                        | [RFC7252] |
| 2.04 | Changed                      | [RFC7252] |
| 2.05 | Content                      | [RFC7252] |
| 4.00 | Bad Request                  | [RFC7252] |
| 4.01 | Unauthorized                 | [RFC7252] |
| 4.02 | Bad Option                   | [RFC7252] |
| 4.03 | Forbidden                    | [RFC7252] |
| 4.04 | Not Found                    | [RFC7252] |
| 4.05 | Method Not Allowed           | [RFC7252] |
| 4.06 | Not Acceptable               | [RFC7252] |
| 4.12 | Precondition Failed          | [RFC7252] |
| 4.13 | Request Entity Too Large     | [RFC7252] |
| 4.15 | Unsupported Content-Format   | [RFC7252] |
| 5.00 | Internal Server Error        | [RFC7252] |
| 5.01 | Not Implemented              | [RFC7252] |
| 5.02 | Bad Gateway                  | [RFC7252] |
| 5.03 | Service Unavailable          | [RFC7252] |
| 5.04 | Gateway Timeout              | [RFC7252] |
| 5.05 | Proxying Not Supported       | [RFC7252] |
+------+------------------------------+-----------+

                   Table 6: CoAP Response Codes

The Response Codes 3.00-3.31 are Reserved for future use ๐Ÿฆ‹ Every other Response Code is Unassigned.

For future additions to this sub-registry, the IANA policy is "IETF Review or IESG Approval", as described in [RFC5226] ๐ŸŒธ

Now, the documentation for a Response Code should spell out what a response with that code actually means, including these properties:

  • The methods the Response Code applies to.
  • Whether payload is required, optional, or not allowed.
  • The semantics of the payload. For example, the payload of a 2.05 (Content) response is a representation of the target resource, and the payload in an error response is a human-readable diagnostic payload ๐Ÿซถ
  • The format of the payload. For example, the format in a 2.05 (Content) response is indicated by the Content-Format Option, and the format of the payload in an error response is always Net-Unicode text โœจ
  • Whether the response is cacheable according to the freshness model.
  • Whether the response is validatable according to the validation model.
  • Whether the response causes a cache to mark responses stored for the request URI as not fresh.

12.2. CoAP Option Numbers Registry ๐Ÿงš

okay this one is so good ๐Ÿ˜ญ This document sets up a sub-registry for the Option Numbers used in CoAP options, and it lives inside the "CoRE Parameters" registry. The sub-registry is called "CoAP Option Numbers".

Every entry needs the Option Number, the name of the option, and a reference to the option's documentation.

The starter entries look like this ๐Ÿ’œ

+--------+------------------+-----------+
| Number | Name             | Reference |
+--------+------------------+-----------+
|      0 | (Reserved)       | [RFC7252] |
|      1 | If-Match         | [RFC7252] |
|      3 | Uri-Host         | [RFC7252] |
|      4 | ETag             | [RFC7252] |
|      5 | If-None-Match    | [RFC7252] |
|      7 | Uri-Port         | [RFC7252] |
|      8 | Location-Path    | [RFC7252] |
|     11 | Uri-Path         | [RFC7252] |
|     12 | Content-Format   | [RFC7252] |
|     14 | Max-Age          | [RFC7252] |
|     15 | Uri-Query        | [RFC7252] |
|     17 | Accept           | [RFC7252] |
|     20 | Location-Query   | [RFC7252] |
|     35 | Proxy-Uri        | [RFC7252] |
|     39 | Proxy-Scheme     | [RFC7252] |
|     60 | Size1            | [RFC7252] |
|    128 | (Reserved)       | [RFC7252] |
|    132 | (Reserved)       | [RFC7252] |
|    136 | (Reserved)       | [RFC7252] |
|    140 | (Reserved)       | [RFC7252] |
+--------+------------------+-----------+

               Table 7: CoAP Option Numbers

The IANA policy here is split into three tiers ๐Ÿ“ The range 0..255 is reserved for options defined by the IETF (IETF Review or IESG Approval). The range 256..2047 is reserved for commonly used options with public specifications (Specification Required). The range 2048..64999 is for all other options, including private or vendor-specific ones, which go through a Designated Expert review so the option semantics get defined correctly.

Option numbers 65000 through 65535 inclusive are reserved for experiments. They are not meant for vendor-specific use of any kind, and they MUST NOT be used in operational deployments. > Hard rule, no exceptions, bestie ๐Ÿ™ˆ

Here's the summary table ๐ŸŒˆ

+-------------+---------------------------------------+
|       Range | Registration Procedures               |
+-------------+---------------------------------------+
|       0-255 | IETF Review or IESG Approval          |
|    256-2047 | Specification Required                |
|  2048-64999 | Expert Review                         |
| 65000-65535 | Experimental use (no operational use) |
+-------------+---------------------------------------+

 Table 8: CoAP Option Numbers: Registration Procedures

The documentation for an Option Number should explain the semantics of an option with that number, including these properties:

  • The meaning of the option in a request.
  • The meaning of the option in a response.
  • Whether the option is critical or elective, as determined by the Option Number.
  • Whether the option is Safe-to-Forward, and, if yes, whether it is part of the Cache-Key, as determined by the Option Number (see Section 5.4.2).
  • The format and length of the option's value.
  • Whether the option must occur at most once or whether it can occur multiple times.
  • The default value, if any. For a critical option with a default value, there should be a discussion on how the default value enables processing by implementations that do not support the critical option (Section 5.4.4) ๐Ÿ”ฅ

12.3. CoAP Content-Formats Registry ๐Ÿ’–

okay so Internet media types are identified by a string, like "application/xml" [RFC2046] ๐Ÿฆ‹ To keep the overhead small when using these media types to indicate the format of payloads, this document sets up a sub-registry for a subset of Internet media types. Each one gets a numeric identifier, combined with a content-coding. The sub-registry is named "CoAP Content-Formats", and it lives inside the "CoRE Parameters" registry.

Each entry needs to include the media type registered with IANA, the numeric identifier in the range 0-65535 to be used for that media type in CoAP, the content-coding associated with this identifier, and a reference to a document describing what a payload with that media type means semantically.

CoAP doesn't have its own way to convey content-encoding information with a request or response, so the content-encoding is specified for each identifier instead (if there is any). If multiple content-encodings are going to be used with a media type, a separate Content-Format identifier needs to be registered for each one ๐Ÿงš Similarly, other parameters related to an Internet media type, such as level, can be defined for a CoAP Content-Format entry.

Here are the starter entries ๐ŸŽ€

+--------------------------+----------+----+------------------------+
| Media type               | Encoding | ID | Reference              |
+--------------------------+----------+----+------------------------+
| text/plain;              | -        |  0 | [RFC2046] [RFC3676]    |
| charset=utf-8            |          |    | [RFC5147]              |
| application/link-format  | -        | 40 | [RFC6690]              |
| application/xml          | -        | 41 | [RFC3023]              |
| application/octet-stream | -        | 42 | [RFC2045] [RFC2046]    |
| application/exi          | -        | 47 | [REC-exi-20140211]     |
| application/json         | -        | 50 | [RFC7159]              |
+--------------------------+----------+----+------------------------+

                   Table 9: CoAP Content-Formats

The identifiers between 65000 and 65535 inclusive are reserved for experiments. They are not meant for vendor-specific use of any kind, and they MUST NOT be used in operational deployments. The identifiers between 256 and 9999 are reserved for future use in IETF specifications (IETF Review or IESG Approval). All other identifiers are Unassigned.

Because the namespace of single-byte identifiers is so small ๐Ÿฅบ, the IANA policy for future additions in the range 0-255 inclusive is "Expert Review", as described in [RFC5226]. The IANA policy for additions in the range 10000-64999 inclusive is "First Come First Served", as described in [RFC5226]. Here's the summary ๐ŸŒธ

+-------------+---------------------------------------+
|       Range | Registration Procedures               |
+-------------+---------------------------------------+
|       0-255 | Expert Review                         |
|    256-9999 | IETF Review or IESG Approval          |
| 10000-64999 | First Come First Served               |
| 65000-65535 | Experimental use (no operational use) |
+-------------+---------------------------------------+

 Table 10: CoAP Content-Formats: Registration Procedures

In machine-to-machine applications, generic Internet media types like text/plain, application/xml or application/octet-stream aren't expected to be useful for real applications in the long term ๐Ÿ’€ It is recommended that M2M applications making use of CoAP request new Internet media types from IANA that indicate semantic information about how to create or parse a payload. For example, a Smart Energy application payload carried as XML might request a more specific type like application/se+xml or application/se-exi ๐Ÿ‘‘

12.4. URI Scheme Registration ๐Ÿฆ‹

Okay bestie, this part is the official paperwork for the coap URI scheme ๐Ÿ“โœจ The request is for IANA to register it, and it follows [RFC4395]. Let's go through every field ๐Ÿ’…

URI scheme name. coap

Status. Permanent.

URI scheme syntax. Defined in Section 6.1 of [RFC7252].

URI scheme semantics. The coap scheme is how you name resources that can be reached over the Constrained Application Protocol (CoAP) ๐ŸŒธ You find the resource by contacting the governing CoAP server, then you operate on it by sending CoAP requests to that server. Honestly it's giving the same energy as the "http" URI scheme [RFC2616]. See Section 6 of [RFC7252] for the details of how it works.

Encoding considerations. The scheme follows the encoding rules for URIs in [RFC3986]. That means internationalized and reserved characters are written with UTF-8-based percent-encoding ๐Ÿซถ

Applications/protocols that use this URI scheme name. CoAP endpoints use this scheme to access CoAP resources โœจ

Interoperability considerations. None.

Security considerations. See Section 11.1 of [RFC7252]. Go read that one, it's important ๐Ÿ™ˆ

Contact. IETF Chair <chair@ietf.org>

Author/Change controller. IESG <iesg@ietf.org>

References. [RFC7252]


12.5. Secure URI Scheme Registration ๐Ÿ”

Same vibe, but now it's the secure sibling. This is the registration request for the URI scheme coaps, and it also complies with [RFC4395] ๐Ÿ’œ

URI scheme name. coaps

Status. Permanent.

URI scheme syntax. Defined in Section 6.2 of [RFC7252].

URI scheme semantics. The coaps scheme names resources that can be reached over CoAP using Datagram Transport Layer Security (DTLS) for transport security ๐Ÿ›ก๏ธ You locate them by contacting the governing CoAP server and operating on them by sending CoAP requests to that server. It's basically the "https" URI scheme [RFC2616] in CoAP form. See Section 6 of [RFC7252] for the details of operation.

Encoding considerations. Same deal as coap: the encoding follows the URI rules in [RFC3986], so internationalized and reserved characters are expressed using UTF-8-based percent-encoding ๐Ÿฆ‹

Applications/protocols that use this URI scheme name. CoAP endpoints use this scheme to access CoAP resources using DTLS ๐Ÿ”ฅ

Interoperability considerations. None.

Security considerations. See Section 11.1 of [RFC7252].

Contact. IETF Chair <chair@ietf.org>

Author/Change controller. IESG <iesg@ietf.org>

References. [RFC7252]


12.6. Service Name and Port Number Registration ๐Ÿšช

Okay this one is about how you find CoAP in the first place ๐Ÿงš One of CoAP's jobs is resource discovery, where a CoAP client asks a CoAP server what resources it offers (see Section 7). For that to work from just an IP address, the CoAP discovery port has to be standardized. Iconic behaviour from the spec, no notes ๐Ÿ’…

IANA has assigned the port number 5683 and the service name coap, in accordance with [RFC6335].

Besides unicast, CoAP can also be used with both multicast and anycast ๐ŸŒˆ

Service Name. coap

Transport Protocol. udp

Assignee. IESG <iesg@ietf.org>

Contact. IETF Chair <chair@ietf.org>

Description. Constrained Application Protocol (CoAP)

Reference. [RFC7252]

Port Number. 5683


12.7. Secure Service Name and Port Number Registration ๐Ÿ”’

Now the secure version of that discovery story ๐Ÿ’– CoAP resource discovery can also happen through the DTLS-secured CoAP coaps scheme. So the port for secure discovery needs to be standardized too.

IANA has assigned the port number 5684 and the service name coaps, in accordance with [RFC6335].

Besides unicast, DTLS-secured CoAP can be used with anycast โœจ

Service Name. coaps

Transport Protocol. udp

Assignee. IESG <iesg@ietf.org>

Contact. IETF Chair <chair@ietf.org>

Description. DTLS-secured CoAP

Reference. [RFC7252]

Port Number. 5684


12.8. Multicast Address Registration ๐Ÿ“ก

Section 8, "Multicast CoAP", is where multicast gets defined ๐Ÿฆ‹ IANA assigned these multicast addresses for CoAP nodes to use:

  • IPv4 -- "All CoAP Nodes" address 224.0.1.187, from the "IPv4 Multicast Address Space Registry". As the address is used for discovery that may span beyond a single network, it has come from the Internetwork Control Block (224.0.1.x, RFC 5771).
  • IPv6 -- "All CoAP Nodes" address FF0X::FD, from the "IPv6 Multicast Address Space Registry", in the "Variable Scope Multicast Addresses" space (RFC 3307). Note that there is a distinct multicast address for each scope that interested CoAP nodes should listen to; CoAP needs the Link-Local and Site-Local scopes only.

Ngl the IPv6 one is a little more involved, because the scope gets swapped in for the X in FF0X::FD ๐Ÿ™ˆ


13. Acknowledgements ๐Ÿซถ

Brian Frank was a contributor to, and coauthor of, early versions of this specification ๐ŸŒธ

Special thanks to Peter Bigot, Esko Dijk, and Cullen Jennings for substantial contributions to the ideas and text in the document, along with countless detailed reviews and discussions ๐Ÿ‘‘

Thanks to Floris Van den Abeele, Anthony Baire, Ed Beroset, Berta Carballido, Angelo P. Castellani, Gilbert Clark, Robert Cragie, Pierre David, Esko Dijk, Lisa Dusseault, Mehmet Ersue, Thomas Fossati, Tobias Gondrom, Bert Greevenbosch, Tom Herbst, Jeroen Hoebeke, Richard Kelsey, Sye Loong Keoh, Ari Keranen, Matthias Kovatsch, Avi Lior, Stephan Lohse, Salvatore Loreto, Kerry Lynn, Andrew McGregor, Alexey Melnikov, Guido Moritz, Petri Mutka, Colin O'Flynn, Charles Palmer, Adriano Pezzuto, Thomas Poetsch, Robert Quattlebaum, Akbar Rahman, Eric Rescorla, Dan Romascanu, David Ryan, Peter Saint-Andre, Szymon Sasin, Michael Scharf, Dale Seed, Robby Simpson, Peter van der Stok, Michael Stuber, Linyi Tian, Gilman Tolle, Matthieu Vial, Maciej Wasilak, Fan Xianyou, and Alper Yegin for helpful comments and discussions that have shaped the document ๐Ÿ’œ Special thanks also to the responsible IETF area director at the time of completion, Barry Leiba, and the IESG reviewers, Adrian Farrel, Martin Stiemerling, Pete Resnick, Richard Barnes, Sean Turner, Spencer Dawkins, Stephen Farrell, and Ted Lemon, who contributed in-depth reviews ๐ŸŒˆ

Some of the text has been borrowed from the working documents of the IETF HTTPBIS working group ๐Ÿ“


14. References โœจ

14.1. Normative References ๐Ÿ“š

  • [RFC0768] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980.
  • [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996.
  • [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, November 1996.
  • [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
  • [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
  • [RFC3023] Murata, M., St. Laurent, S., and D. Kohn, "XML Media Types", RFC 3023, January 2001.
  • [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.
  • [RFC3676] Gellens, R., "The Text/Plain Format and DelSp Parameters", RFC 3676, February 2004.
  • [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, January 2005.
  • [RFC4279] Eronen, P. and H. Tschofenig, "Pre-Shared Key Ciphersuites for Transport Layer Security (TLS)", RFC 4279, December 2005.
  • [RFC4395] Hansen, T., Hardie, T., and L. Masinter, "Guidelines and Registration Procedures for New URI Schemes", BCP 35, RFC 4395, February 2006.
  • [RFC5147] Wilde, E. and M. Duerst, "URI Fragment Identifiers for the text/plain Media Type", RFC 5147, April 2008.
  • [RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network Interchange", RFC 5198, March 2008.
  • [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 5226, May 2008.
  • [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, January 2008.
  • [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, August 2008.
  • [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, May 2008.
  • [RFC5480] Turner, S., Brown, D., Yiu, K., Housley, R., and T. Polk, "Elliptic Curve Cryptography Subject Public Key Information", RFC 5480, March 2009.
  • [RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known Uniform Resource Identifiers (URIs)", RFC 5785, April 2010.
  • [RFC5952] Kawamura, S. and M. Kawashima, "A Recommendation for IPv6 Address Text Representation", RFC 5952, August 2010.
  • [RFC5988] Nottingham, M., "Web Linking", RFC 5988, October 2010.
  • [RFC6066] Eastlake, D., "Transport Layer Security (TLS) Extensions: Extension Definitions", RFC 6066, January 2011.
  • [RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer Security Version 1.2", RFC 6347, January 2012.
  • [RFC6690] Shelby, Z., "Constrained RESTful Environments (CoRE) Link Format", RFC 6690, August 2012.
  • [RFC6920] Farrell, S., Kutscher, D., Dannewitz, C., Ohlman, B., Keranen, A., and P. Hallam-Baker, "Naming Things with Hashes", RFC 6920, April 2013.
  • [RFC7250] Wouters, P., Tschofenig, H., Gilmore, J., Weiler, S., and T. Kivinen, "Using Raw Public Keys in Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", RFC 7250, June 2014.
  • [RFC7251] McGrew, D., Bailey, D., Campagna, M., and R. Dugal, "AES-CCM Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)", RFC 7251, June 2014.

14.2. Informative References ๐Ÿ“šโœจ

okay bestie, this is the big reading list ๐Ÿงš every entry is a source the spec points to for background, and I've kept each one word for word so nothing gets lost ๐Ÿ’…

  • [BLOCK] Bormann, C. and Z. Shelby, "Blockwise transfers in CoAP", Work in Progress, October 2013.
  • [CoAP-MISC] Bormann, C. and K. Hartke, "Miscellaneous additions to CoAP", Work in Progress, December 2013.
  • [EUI64] IEEE Standards Association, "Guidelines for 64-bit Global Identifier (EUI-64 (TM))", Registration Authority Tutorials, April 2010, <http://standards.ieee.org/regauth/oui/tutorials/EUI64.html>.
  • [GROUPCOMM] Rahman, A. and E. Dijk, "Group Communication for CoAP", Work in Progress, December 2013.
  • [HHGTTG] Adams, D., "The Hitchhiker's Guide to the Galaxy", Pan Books ISBN 3320258648, 1979. ๐ŸŒˆ
  • [IEEE1003.1] IEEE and The Open Group, "Portable Operating System Interface (POSIX)", The Open Group Base Specifications Issue 7, IEEE 1003.1, 2013 Edition, <http://pubs.opengroup.org/onlinepubs/9699919799/>.
  • [IPsec-CoAP] Bormann, C., "Using CoAP with IPsec", Work in Progress, December 2012.
  • [MAPPING] Castellani, A., Loreto, S., Rahman, A., Fossati, T., and E. Dijk, "Guidelines for HTTP-CoAP Mapping Implementations", Work in Progress, February 2014.
  • [OBSERVE] Hartke, K., "Observing Resources in CoAP", Work in Progress, April 2014. ๐Ÿ‘€
  • [REC-exi-20140211] Schneider, J., Kamiya, T., Peintner, D., and R. Kyusakov, "Efficient XML Interchange (EXI) Format 1.0 (Second Edition)", W3C Recommendation REC-exi-20140211, February 2014, <http://www.w3.org/TR/2014/REC-exi-20140211/>.
  • [REST] Fielding, R., "Architectural Styles and the Design of Network-based Software Architectures", Ph.D. Dissertation, University of California, Irvine, 2000, <http://www.ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation.pdf>. ๐ŸŽ€
  • [RFC0020] Cerf, V., "ASCII format for network interchange", RFC 20, October 1969.
  • [RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.
  • [RFC0792] Postel, J., "Internet Control Message Protocol", STD 5, RFC 792, September 1981.
  • [RFC0793] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.
  • [RFC1035] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987.
  • [RFC3264] Rosenberg, J. and H. Schulzrinne, "An Offer/Answer Model with Session Description Protocol (SDP)", RFC 3264, June 2002.
  • [RFC3280] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.
  • [RFC3542] Stevens, W., Thomas, M., Nordmark, E., and T. Jinmei, "Advanced Sockets Application Program Interface (API) for IPv6", RFC 3542, May 2003.
  • [RFC3828] Larzon, L-A., Degermark, M., Pink, S., Jonsson, L-E., and G. Fairhurst, "The Lightweight User Datagram Protocol (UDP-Lite)", RFC 3828, July 2004.
  • [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, June 2005.
  • [RFC4443] Conta, A., Deering, S., and M. Gupta, "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification", RFC 4443, March 2006.
  • [RFC4492] Blake-Wilson, S., Bolyard, N., Gupta, V., Hawk, C., and B. Moeller, "Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS)", RFC 4492, May 2006.
  • [RFC4821] Mathis, M. and J. Heffner, "Packetization Layer Path MTU Discovery", RFC 4821, March 2007.
  • [RFC4944] Montenegro, G., Kushalnagar, N., Hui, J., and D. Culler, "Transmission of IPv6 Packets over IEEE 802.15.4 Networks", RFC 4944, September 2007.
  • [RFC5405] Eggert, L. and G. Fairhurst, "Unicast UDP Usage Guidelines for Application Designers", BCP 145, RFC 5405, November 2008.
  • [RFC5489] Badra, M. and I. Hajjeh, "ECDHE_PSK Cipher Suites for Transport Layer Security (TLS)", RFC 5489, March 2009.
  • [RFC6090] McGrew, D., Igoe, K., and M. Salter, "Fundamental Elliptic Curve Cryptography Algorithms", RFC 6090, February 2011.
  • [RFC6120] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Core", RFC 6120, March 2011.
  • [RFC6282] Hui, J. and P. Thubert, "Compression Format for IPv6 Datagrams over IEEE 802.15.4-Based Networks", RFC 6282, September 2011.
  • [RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S. Cheshire, "Internet Assigned Numbers Authority (IANA) Procedures for the Management of the Service Name and Transport Protocol Port Number Registry", BCP 165, RFC 6335, August 2011.
  • [RFC6655] McGrew, D. and D. Bailey, "AES-CCM Cipher Suites for Transport Layer Security (TLS)", RFC 6655, July 2012.
  • [RFC6936] Fairhurst, G. and M. Westerlund, "Applicability Statement for the Use of IPv6 UDP Datagrams with Zero Checksums", RFC 6936, April 2013.
  • [RFC6960] Santesson, S., Myers, M., Ankney, R., Malpani, A., Galperin, S., and C. Adams, "X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP", RFC 6960, June 2013.
  • [RFC6961] Pettersen, Y., "The Transport Layer Security (TLS) Multiple Certificate Status Request Extension", RFC 6961, June 2013.
  • [RFC7159] Bray, T., "The JavaScript Object Notation (JSON) Data Interchange Format", RFC 7159, March 2014.
  • [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for Constrained-Node Networks", RFC 7228, May 2014.
  • [RTO-CONSIDER] Allman, M., "Retransmission Timeout Considerations", Work in Progress, May 2012.
  • [W3CXMLSEC] Wenning, R., "Report of the XML Security PAG", W3C XML Security PAG, October 2012, <http://www.w3.org/2011/xmlsec-pag/pagreport.html>. ๐Ÿ’–

Appendix A. Examples โœจ

okay so this section is literally a bunch of short GET request flows ๐Ÿฆ‹ they show the basic vibe, what happens when stuff gets retransmitted, and multicast. the diagrams are the main event, so read them like little group chat screenshots ๐Ÿ’…

Figure 16 is the basic one ๐ŸŽ€ the client sends a Confirmable GET for coap://server/temperature with Message ID 0x7d34. the request has one Uri-Path Option (Delta 0 + 11 = 11, Length 11, Value "temperature") and the Token is left empty. the whole request is 16 bytes โœจ the server answers with a 2.05 (Content) inside the Acknowledgement for that Confirmable request, echoing both the Message ID 0x7d34 and the empty Token. the Payload is "22.3 C" and the response is 11 bytes. it's a piggybacked response, bestie, iconic ๐ŸŒธ

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d34)
      | GET  |   Uri-Path: "temperature"
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=ACK, Code=2.05, MID=0x7d34)
      | 2.05 |    Payload: "22.3 C"
      |      |


    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | 1 | 0 |   0   |     GET=1     |          MID=0x7d34           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  11   |  11   |      "temperature" (11 B) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | 1 | 2 |   0   |    2.05=69    |          MID=0x7d34           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1 1 1 1 1 1 1 1|      "22.3 C" (6 B) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 16: Confirmable Request; Piggybacked Response

Figure 17 is the same vibe but with a non-empty Token (Value 0x20) in both the request and the response ๐Ÿงš that bumps the sizes up to 17 bytes for the request and 12 bytes for the response.

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d35)
      | GET  |      Token: 0x20
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=ACK, Code=2.05, MID=0x7d35)
      | 2.05 |      Token: 0x20
      |      |    Payload: "22.3 C"
      |      |


    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | 1 | 0 |   1   |     GET=1     |          MID=0x7d35           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     0x20      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  11   |  11   |      "temperature" (11 B) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


    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
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | 1 | 2 |   1   |    2.05=69    |          MID=0x7d35           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     0x20      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |1 1 1 1 1 1 1 1| "22.3 C" (6 B) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 17: Confirmable Request; Piggybacked Response

Figure 18 is where the Confirmable GET gets lost ๐Ÿ’€ after ACK_TIMEOUT seconds the client retransmits, and then it gets a piggybacked response just like in the last example. same Message ID, same Token, big comeback energy ๐Ÿ”ฅ

   Client  Server
      |      |
      |      |
      +----X |     Header: GET (T=CON, Code=0.01, MID=0x7d36)
      | GET  |      Token: 0x31
      |      |   Uri-Path: "temperature"
   TIMEOUT   |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d36)
      | GET  |      Token: 0x31
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=ACK, Code=2.05, MID=0x7d36)
      | 2.05 |      Token: 0x31
      |      |    Payload: "22.3 C"
      |      |

Figure 18: Confirmable Request (Retransmitted); Piggybacked Response

Figure 19 is a plot twist ๐Ÿซฃ this time the first Acknowledgement from the server gets lost. after ACK_TIMEOUT seconds the client retransmits the request, and the server sends the piggybacked response again.

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d37)
      | GET  |      Token: 0x42
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      | X----+     Header: 2.05 Content (T=ACK, Code=2.05, MID=0x7d37)
      | 2.05 |      Token: 0x42
      |      |    Payload: "22.3 C"
   TIMEOUT   |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d37)
      | GET  |      Token: 0x42
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=ACK, Code=2.05, MID=0x7d37)
      | 2.05 |      Token: 0x42
      |      |    Payload: "22.3 C"
      |      |

Figure 19: Confirmable Request; Piggybacked Response (Retransmitted)

Figure 20 is the separate response era ๐ŸŒˆ the server ACKs the Confirmable request first, then sends the 2.05 (Content) in its own Confirmable message. the ACK and the Confirmable response don't have to show up in the order they were sent, so no drama if they swap places. the client then acknowledges the Confirmable response, and we're done โœจ

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d38)
      | GET  |      Token: 0x53
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      |<- - -+     Header: (T=ACK, Code=0.00, MID=0x7d38)
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=CON, Code=2.05, MID=0xad7b)
      | 2.05 |      Token: 0x53
      |      |    Payload: "22.3 C"
      |      |
      |      |
      +- - ->|     Header: (T=ACK, Code=0.00, MID=0xad7b)
      |      |

Figure 20: Confirmable Request; Separate Response

Figure 21 is a little tragedy ๐Ÿ˜ญ the client loses its state (like it crashes and reboots) right after sending the Confirmable request, so the separate response shows up later and the client has no clue what it is. so the client rejects that Confirmable response with a Reset message. the unexpected ACK just gets silently ignored, no biggie ๐Ÿ™ˆ

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=CON, Code=0.01, MID=0x7d39)
      | GET  |      Token: 0x64
      |      |   Uri-Path: "temperature"
    CRASH    |
      |      |
      |<- - -+     Header: (T=ACK, Code=0.00, MID=0x7d39)
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=CON, Code=2.05, MID=0xad7c)
      | 2.05 |      Token: 0x64
      |      |    Payload: "22.3 C"
      |      |
      |      |
      +- - ->|     Header: (T=RST, Code=0.00, MID=0xad7c)
      |      |

Figure 21: Confirmable Request; Separate Response (Unexpected)

Figure 22 is the Non-confirmable main character ๐ŸŽ€ both the request and the response are Non-confirmable, which means either one can get lost and nobody will ever tell you lmao.

   Client  Server
      |      |
      |      |
      +----->|     Header: GET (T=NON, Code=0.01, MID=0x7d40)
      | GET  |      Token: 0x75
      |      |   Uri-Path: "temperature"
      |      |
      |      |
      |<-----+     Header: 2.05 Content (T=NON, Code=2.05, MID=0xad7d)
      | 2.05 |      Token: 0x75
      |      |    Payload: "22.3 C"
      |      |

Figure 22: Non-confirmable Request; Non-confirmable Response

Figure 23 is multicast, and it's giving group project ๐Ÿ“ the client sends a Non-confirmable GET to a multicast address, all nodes in link-local scope (ff02::1). there are 3 servers on the link: A, B and C. A and B both have a matching resource, so they send back Non-confirmable 2.05 (Content) responses. B's response gets lost. C doesn't have a matching resource, so it sends a Non-confirmable 4.04 (Not Found) response instead ๐Ÿซถ

   Client  ff02::1  A  B  C
      |       |     |  |  |
      |       |     |  |  |
      +------>|     |  |  |  Header: GET (T=NON, Code=0.01, MID=0x7d41)
      |  GET  |     |  |  |   Token: 0x86
      |             |  |  |   Uri-Path: "temperature"
      |             |  |  |
      |             |  |  |
      |<------------+  |  |  Header: 2.05 (T=NON, Code=2.05, MID=0x60b1)
      |      2.05   |  |  |   Token: 0x86
      |             |  |  |   Payload: "22.3 C"
      |             |  |  |
      |             |  |  |
      |   X------------+  |  Header: 2.05 (T=NON, Code=2.05, MID=0x01a0)
      |      2.05   |  |  |   Token: 0x86
      |             |  |  |   Payload: "20.9 C"
      |             |  |  |
      |             |  |  |
      |<------------------+  Header: 4.04 (T=NON, Code=4.04, MID=0x952a)
      |      4.04   |  |  |   Token: 0x86
      |             |  |  |

Figure 23: Non-confirmable Request (Multicast); Non-confirmable Response


Appendix B. URI Examples ๐ŸŒท

okay this one is all about building URIs from Uri options ๐Ÿ”— each example takes a set of options and shows the URI you end up with after constructing it. section 6.5 talks about the destination IP address and port too, but not every path through the algorithm actually puts the destination IP address and port into the URI, so keep that in mind ๐Ÿง

  • Input:
Destination IP Address = [2001:db8::2:1]
Destination UDP Port = 5683

Output:

coap://[2001:db8::2:1]/
  • Input:
Destination IP Address = [2001:db8::2:1]
Destination UDP Port = 5683
Uri-Host = "example.net"

Output:

coap://example.net/
  • Input:
Destination IP Address = [2001:db8::2:1]
Destination UDP Port = 5683
Uri-Host = "example.net"
Uri-Path = ".well-known"
Uri-Path = "core"

Output:

coap://example.net/.well-known/core
  • Input:
Destination IP Address = [2001:db8::2:1]
Destination UDP Port = 5683
Uri-Host = "xn--18j4d.example"
Uri-Path = the string composed of the Unicode characters U+3053
U+3093 U+306b U+3061 U+306f, usually represented in UTF-8 as
E38193E38293E381ABE381A1E381AF hexadecimal

Output:

coap://xn--18j4d.example/
%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF

(The line break has been inserted for readability; it is not part of the URI.)

  • Input:
Destination IP Address = 198.51.100.1
Destination UDP Port = 61616
Uri-Path = ""
Uri-Path = "/"
Uri-Path = ""
Uri-Path = ""
Uri-Query = "//"
Uri-Query = "?&"

Output:

coap://198.51.100.1:61616//%2F//?%2F%2F&?%26

Authors' Addresses ๐Ÿซถ

Here are the people who wrote this, bestie. The addresses and contact details are kept exactly as they appear in the original.

Zach Shelby
ARM
150 Rose Orchard
San Jose, CA  95134
USA

Phone: +1-408-203-9434
EMail: zach.shelby@arm.com


Klaus Hartke
Universitaet Bremen TZI
Postfach 330440
Bremen  D-28359
Germany

Phone: +49-421-218-63905
EMail: hartke@tzi.org


Carsten Bormann
Universitaet Bremen TZI
Postfach 330440
Bremen  D-28359
Germany

Phone: +49-421-218-63921
EMail: cabo@tzi.org
๐Ÿ“ฆ where this page comes from