CoRE Working Group | C. Amsüss |
Internet-Draft | Energy Harvesting Solutions |
Intended status: Standards Track | March 27, 2017 |
Expires: September 28, 2017 |
Request-Tag option
draft-amsuess-core-request-tag-00
This memo describes an optional extension to the Constrained Application Protocol (CoAP, [RFC7252] and [RFC7959]) that allows matching of request blocks. This primarily serves to transfer the security properties that Object Security of CoAP (OSCOAP, [I-D.ietf-core-object-security]) provides for single requests to blockwise transfers. The security of blockwise transfer in OSCOAP is reflected on in a dedicated section.
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
This Internet-Draft will expire on September 28, 2017.
Copyright (c) 2017 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
The OSCOAP protocol provides a security layer for CoAP that, given a security context shared with a peer, provides
It does not (and should not) provide sequential delivery. In particular, it does not protect against requests being delayed; the corresponding attack and mitigation is described in [I-D.mattsson-core-coap-actuators].
The goal of this memo is to provide protection to the bodies of a blockwise fragmented request/response pair that is equivalent to the protection that would be provided if the complete request and response bodies fit into single messae each. (Packing long payloads into single OSCOAP messages is actually possible using the outer blockwise mechanism, but does not go well with the constraints of devices CoAP is designed for). [Author’s note: The results of this might move back into OSCOAP – for now, the matter is explored here.]
The proposed method of matching blocks to each other is the introduction of a Request-Tag option, which is similar to the ETag sent along with responses, but ephemeral and set by the client. It is phrased in a way that it can not only be used in OSCOAP, but also by other security mechanisms (eg. CoAP over DTLS), or for other purposes (see Appendix A).
In order to minimize the impact on message sizes, the Request-Tag option is designed to be only used when required[, and its interaction with OSCOAP should mandate actively setting it only in rare cases. If this is still insufficient, compressing it into the AAD can still be considered].
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119].
The terms “payload” and “body” are used as in [RFC7959]. The complete interchange of a request and a response body is called a REST “operation”, while a request and response message (as matched by their tokens) is called an “exchange”.
A new option is defined for all request methods:
+-----+---+---+---+---+-----------------------+--------+--------+---------+ | No. | C | U | N | R | Name | Format | Length | Default | +-----+---+---+---+---+-----------------------+--------+--------+---------+ | TBD | x | x | - | | Request-Tag | opaque | 0-8 | (none) | +-----+---+---+---+---+-----------------------+--------+--------+---------+ C=Critical, U=Unsafe, N=NoCacheKey, R=Repeatable
Figure 1: Option summary
It is critical (because a client that wants to secure its request body can’t have a server ignore it), unsafe (because it needs to understood by any proxy that does blockwise (dis)assembly), and not repeatable. ([Does “unsafe” make nocachekey irrelevant? I think so.])
A client MAY set the Request-Tag option to indicate that the receiving server MUST NOT act on any block in the same blockwise operation that has a different Request-Tag set. A server MUST NOT use blocks with and blocks without Request-Tag option either.
[Note on future development: If it turns out we need to compress the option into the AAD, this might hook in here and specify that when OSCOAP and blockwise is in use, the client MUST set a Request-Tag if and only if it sets a Block1 option in descriptive usage, and is value MUST be the partial IV of that message. That value MUST then be included somewhere in the AAD of every block message after the first, where this compression proposal so far fails because the verifying server would have to know at AAD-building time whether or not this is an inner blockwise request.]
If the Request-Tag option is set, the client MAY perform simultaneous operations that utilize Block1 fragmentation from the same endpoint towards the same resource, lifting the limitation of [RFC7959] section 2.5. The server is still under no obligation to keep state of more than one transaction. When an operation is in progress and a second one can not be served at the same time, the server MUST either respond to the second request with a 5.03 response code (in which it SHOULD indicate the time it is willing to wait for additional blocks in the first open operation in the Max-Age option), or cancel the first operation by responding 4.08 in subsequent exchanges in the first operations. Clients that see the latter behavior SHOULD [or MUST?] fall back to serializing requests as it would without the Request-Tag option.
[Author’s note: The above paragraph sounds problematic to me. For further exploration of those error cases, I’d need to know how simultaneous operations (even on different resources) from different endpoints are handled in constrained clients; I only did stateless operations in constrained devices so far.]
The option is not used in responses.
If a request that uses Request-Tag is rejected with 4.02 Bad Option, the client MAY retry the operation without it, but it then needs to serialize all operations that affect the same resource. Security requirements can forbid dropping the Request-Tag option.
[Author’s note: If this stays a document of its own, OSCOAP should make a normative reference to it and state something like:
With this text, clients could even work around ever needing to send the option by bumping their sequence number – looks like bad behavior in the first place, but then again, it is just a variant of the “forbid out-of-order sequence numbers in blockwise” alternative option.
AFAICT this would be the first actual use of the window size; so far client and server can well interact with different replay window sizes. Probably it’s OK to be the first user of the parameter.
For the options list:
The Request-Discriminator option is added to the “E=*” category in the options list, and is listed together with Block1/2 in all other places they are mentioned.
For somewhere else (?):
A server responding an inner Block2 option SHOULD use an ETag on it, even if the result is not cachable (eg. the response to a POST request), and take reasonable measures against identical ETags on distinct states, otherwise OSCOAP does not provide integrity protection of the response body.
]
Blockwise transfer, specified in [RFC7959], fragments REST operations into exchanges of individual blocks. It provides, at the discretion of the server, direct access to parts of a resource representation (where the client can fetch or send any block in any sequence, also called “random access”) or sequential access (where the operation is started by exchanging the first block, and terminates in the exchange of the last block).
The individual blocks are correlated only by the client endpoint (or security context if applicable), the requested URI, and time (and thereby server state, where the operation is available at most until another request with the same endpoint/URI combination arrives).
The specification does include security considerations, which do advise against allowing random write access, but does not contain a mechanism that allows protecting the integrity of the operation’s body. Consequently, the attacks described below are possible even when blockwise transfer is used over DTLS to the author’s knowledge.
There are several shapes a blockwise exchange can take, named here for further reference. Requests or responses bodies are called “small” or “large” here if they do or do not, respectively, fit in a single message. Empty bodies are small. Naming consists of case discrimination letters for No blockwise, Sequential transfer and Random access in the Block1 and Block2 phases, respectively.
[Author’s note: I’d appreciate real examples to replace the more contrived ones; the worst are marked with (?).]
[Note that the NS picture frame example is by far the worst and farest-fetched. I’d like to have an example of a non-safe request resulting in fragmented responses, but that behavior is usually discouraged (PUT responses typically being empty, POST responses bearing a Location), but not outright forbidden, and catered for in blockwise where it comes to combined use of Block1 and Block2.]
This section outlines some attacks that should be mitigated by the Request-Tag option. They are written with a malicious proxy between client and server in mind; whether that is a forward, reverse, transparent proxy, or any other entity on the data path that can intercept and inject packages into the communication is irrelevant to the attacks.
The illustrations draw terminology (especially the “@” and “X” symbols) from [I-D.mattsson-core-coap-actuators].
The scenarios typically require the attacker to have a good idea of the content of the packages that are transferred. Note that the attacker can see the codes of the messages.
In this scenario, blocks from two operations on a POST-accepting resource are combined to make the server execute an action that was not intended by the authorized client. This works only if the client attempts a second operation after first operation failed (due what the attacker made appear like a network outage) within the replay window. The client does not receive a confirmation on the second operation either, but by the time, the server has already executed the unauthorized action.
Client Foe Server | | | +-------------> POST "incarcerate" (Block1: 0, more to come) | | | <-------------+ 2.31 Continue (Block1: 0 received, send more) | | | +----->@ | POST "valjean" (Block1: 1, last block) | | | +----->X | All retransmissions dropped | | | (Client: Odd, but let's go on and promote Javert) | | | +-------------> POST "promote" (Block1: 0, more to come) | | | | X<-----+ 2.31 Continue (Block1: 0 received, send more) | | | | @------> POST "valjean" (Block1: 1, last block) | | | | X<-----+ 2.04 Valjean Promoted
Figure 2: Attack example
With Request-Tag in place, the client would have assigned a different Request-Tag to the “promote” line, and the server would have either reacted to the “valjean” POST by incarcerating valjean (if it could keep both operation states at the same time), or responded 5.03 to the “promote” request until a timeout, or responded 4.08 to the injected “valjean” request.
The client would only have been free to use the same Request-Tag on the “promote” POST as on the “incarcerate” POST if, in the meantime, it had exchanged enough messages that the latest message of the first use (“valjean”) is dropped from the server’s window, and thus the sever would not accept its replay.
In this example, mismatched Block1 packages against a resource that passes judgement are mixed up to create a response matched to the wrong operation.
Again, a first operation is aborted by the proxy (“Homeless stole apples. What shall we do with him?” – “Set him free.”), and a part of that operation is later used in a different operation to prime the server for responding leniently to another operation that would originally have been “Hitman killed someone. What shall we do with him?” – “Hang him.”.
Client Foe Server | | | +----->@ | POST "Homeless stole apples. Wh" | | | (Block1: 0, more to come) (Client: We'll try that one later again; for now, we have something more urgent:) | | | +-------------> POST "Hitman killed someone. Wh" | | | (Block1: 0, more to come) | | | | @<-----+ 2.31 Continue (Block1: 0 received, send more) | | | | @------> POST "Homeless stole apples. Wh" | | | (Block1: 0, more to come) | | | | X<-----+ 2.31 Continue (Block1: 0 received, send more) | | | <------@ | 2.31 Continue (Block1: 0 received, send more) | | | +-------------> POST "at shall we do with him?" | | | (Block1: 1, last block) | | | <-------------+ 2.05 "Set him free." (Block1: 1 received, and this is the result)
Figure 3: Attack example
The example works equivalently with longer responses, placing it in the SS category instead of the SN.
[More examples would help, especially for the other blockwise cases. Is it relevant to distinguish non-piggybacked responses?]
This part is informative and serves to illustrate why this option is necessary, and how it is different from similar concepts.
Why not…
When used in combination with OSCOAP or other security layers to prevent block mixing between REST operations, it is crucial to only reuse request tags as specified, and not to use any affected sequence numbers (which means the latest sequence number plus the window size) should information about used request tags get lost.
While the Request-Tag is not echoed back by the server unlike the Token, the client should still refrain from setting it to internal values (like memory address of state data) to avoid exposing internal data to a server that it could use in unrelated attacks.
[Missing: have a number assigned and the option published]
[RFC2119] | Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997. |
[RFC7252] | Shelby, Z., Hartke, K. and C. Bormann, "The Constrained Application Protocol (CoAP)", RFC 7252, DOI 10.17487/RFC7252, June 2014. |
[RFC7959] | Bormann, C. and Z. Shelby, "Block-Wise Transfers in the Constrained Application Protocol (CoAP)", RFC 7959, DOI 10.17487/RFC7959, August 2016. |
[I-D.ietf-core-object-security] | Selander, G., Mattsson, J., Palombini, F. and L. Seitz, "Object Security of CoAP (OSCOAP)", Internet-Draft draft-ietf-core-object-security-01, December 2016. |
[I-D.mattsson-core-coap-actuators] | Mattsson, J., Fornehed, J., Selander, G. and F. Palombini, "Controlling Actuators with CoAP", Internet-Draft draft-mattsson-core-coap-actuators-02, November 2016. |
In pre-OSCOAP practice, proxies rarely face situations where simultaneous Block1 operations from different affect a single resource and can not be executed in parallel due to the constraints of only one Block1 operation being possible per endpoint pair and resource. (If that happens, the proxy can either serialize the requests, or 5.03 the second requester until the first request has completed).
With OSCOAP, all clients access the resource / as far as a proxy is concerned, which would lead to more frequent situations in which it would need to serialize requests. Clients that employ OSCOAP’s outer-blockwise mechanism find themselves in a similar situation.
Those proxies and clients can utilize the Request-Tag option work off those requests in parallel by assigning them different Request-Tag values. To a proxy, this will only mean an increase in state of up to eight bytes per operation (if it could handle unencrypted simultaneous requests, it would tell them apart by their URIs; here, it tells them apart by their request tags). The state a server needs to keep per operation increases by the same eight bytes compared to serving the same simultaneous requests directly to different endopoints.
All messages exchanged in the following diagrams transferred as OSCOAP protected messages. The field data shown indicates code, payload and options of the unprotected (ie. inner) messages. Payloads are symbolic and do not necessarily line up in any block size when taken literally. Sequence numbers used are indicated at the sender side, and the window size used is 32.
Figure 4 shows how under usual circumstances, the Request-Tag option does not need to be set:
Client Server | | [1]-----------> POST "incarcerate" (Block1: 0, more to come) | | <----------[11] 2.31 Continue (Block1: 0 received, send more) | | [2]-----------> POST "valjean" (Block1: 1, last block) | | <----------[12] 2.04 Valjean incarcerated (Block1: 1 received) | | [3]-----------> POST "promote" (Block1: 0, more to come) | | <----------[13] 2.31 Continue (Block1: 0 received, send more) | | [4]-----------> POST "javert" (Block1: 1, last block) | | <----------[14] 2.04 Javert promoted (Block1: 1 received)
Figure 4: Back to back block transfer
If there is any doubt about whether all sent sequence numbers of a Request-Tag value are either acknowledged or off the window, the client uses a different value as in Figure 5. The client here uses the shortest possible value, the empty string:
Client Server | | [1]-----------> POST "incarcerate" (Block1: 0, more to come) | | <----------[11] 2.31 Continue (Block1: 0 received, send more) | | [2]---X | POST "valjean" (Block1: 1, last block) | | (extended network outage; when it's over, the client attempts a different operation:) [3]-----------> POST "promote" (Block1: 0, more to come; | | Request-Tag: "") | | <----------[12] 2.31 Continue (Block1: 0 received, send more) | | [4]-----------> POST "javert" (Block1: 1, last block; | | Request-Tag: "") | | <----------[14] 2.04 Javert promoted (Block1: 1 received)
Figure 5: Behavior after extended package loss
A proxy can use the Request-Tag option to work off operations from different clients (indicated by the two origin lines under “Clients”) towards a single resource:
Clients Proxy Server | | | +-----> | POST "Homeless stole apples. Wh" | | | (Block1: 0, more to come) | | | | +------> POST "Homeless stole apples. Wh" | | | (Block1: 0, more to come) | | | | <------+ 2.31 Continue (Block1: 0 received, send more) | | | <-----+ | 2.31 Continue (Block1: 0 received, send more) | | | +-------> | POST "Hitman killed someone. Wh" | | | (Block1: 0, more to come) | | | | +------> POST "Hitman killed someone. Wh" | | | (Block1: 0, more to come; Request-Tag: "") | | | | <------+ 2.31 Continue (Block1: 0 received, send more) | | | <-------+ | 2.31 Continue (Block1: 0 received, send more) | | | | | | | |-----> | POST "at shall we do with him?" | | | (Block1: 1, last block) | | | | +------> POST "at shall we do with him?" | | | (Block1: 1, last block) | | | | <------+ 2.05 "Set him free." | | | (Block1: 1 received, and this is the result) | | | <-----+ | 2.05 "Set him free." | | | | (Block1: 1 received, and this is the result) | |-------> | POST "at shall we do with him?" | | | (Block1: 1, last block) | | | | +------> POST "at shall we do with him?" | | | (Block1: 1, last block, Request-Tag: "") | | | | <------+ 2.05 "Hang him." | | | (Block1: 1 received, and this is the result) | | | <-------+ | 2.05 "Hang him." | | | (Block1: 1 received, and this is the result)
Figure 6: Proxy example