idnits 2.17.1 draft-rundgren-signed-http-requests-00.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- == There are 1 instance of lines with non-RFC2606-compliant FQDNs in the document. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (March 11, 2019) is 1872 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) == Missing Reference: 'REST' is mentioned on line 1113, but not defined == Missing Reference: 'HTTPSIG' is mentioned on line 1274, but not defined == Missing Reference: 'AWS' is mentioned on line 1266, but not defined == Missing Reference: 'FAPI' is mentioned on line 1304, but not defined == Missing Reference: 'OBIE' is mentioned on line 1279, but not defined == Missing Reference: 'STET' is mentioned on line 1274, but not defined -- Looks like a reference, but probably isn't: '1' on line 1323 == Outdated reference: A later version (-17) exists of draft-rundgren-json-canonicalization-scheme-05 ** Downref: Normative reference to an Informational draft: draft-rundgren-json-canonicalization-scheme (ref. 'JCS') -- Possible downref: Non-RFC (?) normative reference: ref. 'JWSJCS' ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7231 (Obsoleted by RFC 9110) -- Possible downref: Non-RFC (?) normative reference: ref. 'SHS' -- Possible downref: Non-RFC (?) normative reference: ref. 'UNICODE' Summary: 3 errors (**), 0 flaws (~~), 9 warnings (==), 5 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Network Working Group A. Rundgren 3 Internet-Draft Independent 4 Intended status: Standards Track March 11, 2019 5 Expires: September 12, 2019 7 Signed HTTP Requests (SHREQ) 8 draft-rundgren-signed-http-requests-00 10 Abstract 12 The SHREQ specification describes how the JSON Web Signature (JWS) 13 specification combined with the JSON Canonicalization Scheme (JCS), 14 can be utilized to support HTTP based applications needing digitally 15 signed requests. SHREQ is specifically tailored for Web applications 16 using JSON as data interchange format. However, there is also a 17 SHREQ scheme for HTTP requests that do not have a body ("payload") 18 like GET. SHREQ was designed to be agnostic with respect to REST 19 concepts versus traditional GET/POST schemes. 21 The intended audiences of this document are Web tool vendors, as well 22 as designers of secure Web applications. 24 Status of This Memo 26 This Internet-Draft is submitted in full conformance with the 27 provisions of BCP 78 and BCP 79. 29 Internet-Drafts are working documents of the Internet Engineering 30 Task Force (IETF). Note that other groups may also distribute 31 working documents as Internet-Drafts. The list of current Internet- 32 Drafts is at https://datatracker.ietf.org/drafts/current/. 34 Internet-Drafts are draft documents valid for a maximum of six months 35 and may be updated, replaced, or obsoleted by other documents at any 36 time. It is inappropriate to use Internet-Drafts as reference 37 material or to cite them other than as "work in progress." 39 This Internet-Draft will expire on September 12, 2019. 41 Copyright Notice 43 Copyright (c) 2019 IETF Trust and the persons identified as the 44 document authors. All rights reserved. 46 This document is subject to BCP 78 and the IETF Trust's Legal 47 Provisions Relating to IETF Documents 48 (https://trustee.ietf.org/license-info) in effect on the date of 49 publication of this document. Please review these documents 50 carefully, as they describe your rights and restrictions with respect 51 to this document. Code Components extracted from this document must 52 include Simplified BSD License text as described in Section 4.e of 53 the Trust Legal Provisions and are provided without warranty as 54 described in the Simplified BSD License. 56 Table of Contents 58 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 59 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 4 60 3. HTTP Processing . . . . . . . . . . . . . . . . . . . . . . . 4 61 3.1. Determining Request Type . . . . . . . . . . . . . . . . 4 62 3.2. Return Codes . . . . . . . . . . . . . . . . . . . . . . 5 63 4. Processing of JSON Based Requests . . . . . . . . . . . . . . 5 64 4.1. Request Creation . . . . . . . . . . . . . . . . . . . . 6 65 4.2. Request Validation . . . . . . . . . . . . . . . . . . . 8 66 5. Processing of URI Based Requests . . . . . . . . . . . . . . 9 67 5.1. Request Creation . . . . . . . . . . . . . . . . . . . . 10 68 5.2. Request Validation . . . . . . . . . . . . . . . . . . . 11 69 6. Common Operations . . . . . . . . . . . . . . . . . . . . . . 13 70 6.1. Create Signable JSON Data . . . . . . . . . . . . . . . . 13 71 6.2. Create Signable URI Data . . . . . . . . . . . . . . . . 13 72 6.3. Create HTTP Header Object . . . . . . . . . . . . . . . . 14 73 6.4. Create JWS Protected Header . . . . . . . . . . . . . . . 15 74 6.5. Create JWS String . . . . . . . . . . . . . . . . . . . . 15 75 6.6. Decode JWS String . . . . . . . . . . . . . . . . . . . . 16 76 6.7. Normalize Target URI . . . . . . . . . . . . . . . . . . 16 77 6.8. Normalize Header Data . . . . . . . . . . . . . . . . . . 17 78 6.9. Validate HTTP Header Object . . . . . . . . . . . . . . . 18 79 6.10. Validate JWS Signature . . . . . . . . . . . . . . . . . 19 80 6.11. Time Stamps . . . . . . . . . . . . . . . . . . . . . . . 20 81 6.12. Hash Algorithms . . . . . . . . . . . . . . . . . . . . . 20 82 7. Local Naming Conventions . . . . . . . . . . . . . . . . . . 21 83 8. MIME Multipart Requests . . . . . . . . . . . . . . . . . . . 21 84 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 21 85 10. Security Considerations . . . . . . . . . . . . . . . . . . . 21 86 11. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . 22 87 12. References . . . . . . . . . . . . . . . . . . . . . . . . . 22 88 12.1. Normative References . . . . . . . . . . . . . . . . . . 22 89 12.2. Informal References . . . . . . . . . . . . . . . . . . 23 90 Appendix A. Test Vectors . . . . . . . . . . . . . . . . . . . . 24 91 A.1. Type=URI, Method=GET, Algorithm=HS256 . . . . . . . . . . 24 92 A.2. Type=JSON, Method=POST, Algorithm=ES256 . . . . . . . . . 25 93 A.3. Type=JSON, Method=PUT, Algorithm=ES256 . . . . . . . . . 25 94 A.4. Type=URI, Method=DELETE, Algorithm=RS256 . . . . . . . . 26 95 Appendix B. Other Signed HTTP Request Solutions . . . . . . . . 27 96 B.1. Amazon Web Services . . . . . . . . . . . . . . . . . . . 27 97 B.2. HTTP Signatures . . . . . . . . . . . . . . . . . . . . . 27 98 B.3. Open Banking (UK) . . . . . . . . . . . . . . . . . . . . 27 99 B.4. Financial API . . . . . . . . . . . . . . . . . . . . . . 28 100 Appendix C. Development Portal . . . . . . . . . . . . . . . . . 28 101 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 28 103 1. Introduction 105 Currently there is no standard for digitally signing HTTP [RFC7230] 106 [RFC7231] requests. This has led to the development of a multitude 107 of more or less proprietary solutions (see Appendix B), typically 108 building on using HTTP header data for holding security constructs, 109 while JSON request data is provided in clear in the HTTP body. 111 SHREQ is intended to provide a standardized alternative, including 112 supporting the REST [REST] concept. 114 SHREQ builds on a common security model where all elements of an HTTP 115 request are signed: 117 o HTTP URI. 119 o HTTP method. 121 o HTTP body (if applicable). 123 o Optional: Additional HTTP headers as defined by applications 124 implementing this specification. 126 In addition there is a mandatory time stamp. 128 One of the design goals was turning signed requests into self- 129 contained objects. To achieve this for HTTP requests having a JSON 130 [RFC8259] body (see Section 4), the request data also carries the 131 signature. This arrangement has certain implications: 133 o Signed requests may be stored in databases or be embedded in other 134 JSON objects. The latter includes supporting counter signatures. 135 The canonicalization offered by JCS [JCS] enables validating the 136 integrity of request data at any time. 138 o For general interoperability concerns as well as due to the 139 reliance on JCS, JSON request data is limited to the I-JSON 140 [RFC7493] subset. 142 For HTTP requests that do not have a JSON body (see Section 5), the 143 signature and additional request data is added to the original URI 144 [RFC3986], making signed URI-only requests self-contained and 145 serializable as well. For simplicity such requests are (in this 146 specification NB), referred to as URI based requests. 148 Both variants utilize JWS [RFC7515] for holding the signature data. 150 For supporting signed HTTP responses any solution may be used. For 151 maximum "symmetry" and code reuse, the [JWSJCS] scheme should be a 152 suitable candidate since it builds on the same building blocks as 153 SHREQ. 155 2. Terminology 157 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 158 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 159 "OPTIONAL" in this document are to be interpreted as described in BCP 160 14 [RFC2119] [RFC8174] when, and only when, they appear in all 161 capitals, as shown here. 163 3. HTTP Processing 165 The following subsections describe HTTP specifics associated with 166 this specification. 168 3.1. Determining Request Type 170 In this specification the distinction between HTTP requests having a 171 JSON body or not is based on the presence of a "Content-Length" 172 header. Requests without a body object are in this specification 173 referred to as URI based requests. 175 This also implies that not all header combinations permitted by HTTP 176 can be used with this specification: 178 "Content-Length" 179 MUST NOT be used with URI based requests. MUST be present for 180 requests having a body and have an argument holding the length of 181 the body in bytes. 183 "Content-Type" 184 MUST NOT be used with URI based requests. MUST be present for 185 requests having a body and have the argument "application/json". 187 "Content-Encoding" 188 MUST NOT be used with any requests targeting this specification. 190 "Transfer-Encoding" 191 MUST NOT be used with any requests targeting this specification. 193 3.2. Return Codes 195 This specification utilizes a single HTTP return code 400 (Bad 196 request) for indicating syntax or security errors. Since the number 197 of possible error conditions is significant, it is RECOMMENDED to 198 accompany the error code with a short explanation in "text/plain" 199 format in the HTTP Body like: 201 - Missing ".secinf" element 202 - Invalid "alg": es256 203 - Unknown "kid": example.com:rsa:2018.1 204 - com.example.jose.Core.validate(2653): Signature validation error 205 - Missing header variable "x-testing" 207 Communities using this specification MAY customize error codes if 208 needed. However, in practice, it usually turns out to be of little 209 value compared to a text message and a generic "hard error" code 210 since neither users nor machines can do very much on their own to fix 211 errors that are outside of normal processing. 213 Application level errors are dealt with in an application specific 214 manner. As an example a bank application which finds out that the 215 customer do not have enough funds to perform a transaction would 216 presumably not return an HTTP error code but rather a specifically 217 crafted error message to be displayed to the user. 219 Return codes for successful operation is application specific but are 220 typically 200 (OK) or 201 (Created). 222 4. Processing of JSON Based Requests 224 Assume there is an unsigned HTTP request like the following: 226 POST /foo HTTP/1.1 227 Host: example.com 228 Content-Type: application/json 229 Content-Length: 1234 231 { 232 "something": "data", 234 Additional application specific properties 236 } 238 Adding a signature to the request above would require the following 239 enhancements to the JSON payload: 241 { 242 "something": "data", 244 Additional application specific properties 246 ".secinf": { 247 "uri": "https://example.com/foo", 248 "mtd": "POST", 249 "iat": 1551709923, 250 "jws": "eyJhbGciOiJIUzI1NiJ9..VHVItCBCb849imarDtjw4" 251 } 252 } 254 Notes: 256 o This specification presumes that request data featured in an HTTP 257 body is expressed as a JSON Object. 259 o The "uri" property holds a normalized target URI. 261 o The "mtd" property holds the expected HTTP method. In the example 262 it is actually redundant since the absence of a "mtd" property 263 defaults to "POST" for JSON based requests in this specification. 265 o The "iat" property holds a time stamp in UNIX "epoch" format. 267 o The argument to "jws" (a detached compact JWS) was truncated for 268 brevity. 270 The following subsections detail the operation for requests having an 271 HTTP body. 273 4.1. Request Creation 275 Precondition: the application data to be submitted with the request 276 already exists in a format serializable as a JSON Object, from now on 277 referred to as "message". 279 In order to create a valid signed JSON request, the following steps 280 (and ordering) MUST be adhered to: 282 1. Store the target HTTP method in a variable "targetMethod". 284 2. Store the target URI in a variable "targetURI" after having 285 normalized it as described in Section 6.7. 287 3. Add a JSON Object called ".secinf" to "message". 289 4. Add a property "uri" to ".secinf" where the argument is a JSON 290 String holding a copy of "targetURI". 292 5. Add a property "mtd" to ".secinf" where the argument is a JSON 293 String holding a copy of "targetMethod". 295 Note: for the HTTP method "POST", this step is optional because 296 "POST" is the default for JSON based requests. 298 6. If there is a need to include additional HTTP headers in the 299 signed request data, perform the following steps: 301 * Derive (or define) the hash algorithm to use as described in 302 Section 6.12. Save the algorithm in a variable 303 "hashAlgorithm". 305 * Create a header object as described in Section 6.3. 307 7. Add a time stamp property (see Section 6.11) to ".secinf". 309 Note: if the application data already contains a suitable time 310 stamp property, this step MAY be excluded. 312 8. Create a "JWS Payload" [RFC7515] as described in Section 6.1. 314 9. Create a "JWS Protected Header" [RFC7515] as described in 315 Section 6.4. 317 10. Create a JWS string object as described in Section 6.5. 319 11. Add a property "jws" to ".secinf" where the argument is a JSON 320 String holding the result of the preceding step. 322 12. Serialize "message" into an UTF-8 [UNICODE] encoded byte array 323 called "requestData". 325 13. Submit an HTTP compliant request to the "targetURI" including 326 the following information: 328 * HTTP method set to "targetMethod". 330 * HTTP Header "Content-Length" with the argument set to the 331 length of "requestData". 333 * HTTP Header "Content-Type" with the argument set to 334 "application/json". 336 * All HTTP headers (if any) specified in step 6. 338 * Other HTTP headers (if any) needed by the application. 340 * An HTTP Body containing a copy of "requestData". 342 4.2. Request Validation 344 In order to validate a request the following steps MUST be performed: 346 1. Store the HTTP method of the request in a variable 347 "targetMethod". 349 2. Store the from the request recreated target URI in a variable 350 "targetURI" after having normalized it as described in 351 Section 6.7. 353 3. If the HTTP header "Content-Type" is missing or differs from 354 "application/json" the service MUST reject the request (see 355 Section 3.2). 357 4. If the HTTP header "Content-Length" is missing or malformed the 358 service MUST reject the request (see Section 3.2). Save the 359 length data. 361 5. Read HTTP body data into a byte array with the length retrieved 362 in the preceding step. 364 6. Parse the byte array created in the preceding step with a JSON 365 parser and return the result in an object from now on referred 366 to as "message". If there are parsing errors or if "message" is 367 not a JSON Object the service MUST reject the request (see 368 Section 3.2). 370 7. Using "message", retrieve a JSON Object called ".secinf". If 371 ".secinf" is missing or is not a JSON Object the service MUST 372 reject the request (see Section 3.2). 374 8. Using ".secinf", the property "jws" is read. If "jws" is 375 missing or is not a JSON String the service MUST reject the 376 request (see Section 3.2). Decode the read string as described 377 in Section 6.6. 379 9. Using ".secinf", the property "uri" is read. If "uri" is 380 missing or does not match "targetURI" or is not a JSON String 381 the service MUST reject the request (see Section 3.2). 383 Note: in some proxy arrangements it may be difficult retrieving 384 the proper value of "targetURI". In such cases the comparison 385 with "uri" MAY be disabled. 387 10. Using ".secinf", the property "mtd" is read. if "mtd" is 388 missing the HTTP method is assumed to be "POST" else it is 389 assumed to be the read value. If the derived method does not 390 match "targetMethod" or is not a JSON String the service MUST 391 reject the request (see Section 3.2). 393 11. If the optional "hdr" property is present in ".secinf" perform 394 the following steps: 396 * Derive the hash algorithm to use as described in 397 Section 6.12. Save the algorithm in a variable 398 "hashAlgorithm". 400 * Process the argument of "hdr" as described in Section 6.9. 402 12. Using ".secinf", the property "iat" (see Section 6.11) is read. 403 if "iat" is missing or is not a JSON Number the service MUST 404 reject the request (see Section 3.2). 406 Note: if the application data already contains a suitable time 407 stamp property, this step MAY be excluded. 409 13. Remove the "jws" property from ".secinf". 411 14. Create a "JWS Payload" [RFC7515] as described in Section 6.1. 413 15. Perform signature validation as described in Section 6.10. 415 Note: validation of application specific data can be performed 416 anytime after step 6. The action(s) to perform after a possible 417 failure is out of scope for this specification (see Section 3.2). 419 5. Processing of URI Based Requests 421 Assume there is an unsigned HTTP request like the following: 423 GET /users?id=435 HTTP/1.1 424 Host: example.com 426 The full URI would be as follows: 428 https://example.com/users?id=435 430 Adding a signature to this request according to this specification 431 would return the following URI: 433 https://example.com/users?id=435&.jws=eyJhhiJ.eyJ7fgw.VHVIt 435 Notes: 437 o The revised URI represents a complete serializable signed request 438 object. 440 o The argument to ".jws" (a standard compact JWS) was truncated for 441 brevity. 443 The middle component of the JWS string ("JWS Payload"), contains 444 Base64Url encoded signed data related to the request. It should 445 (after Base64Url decoding) yield a JSON Object like the following: 447 { 448 "htu": "WUjqfXPztLzzXRCs6EcWCw-GC9hSL7hwCR1nG2FSvQ8", 449 "mtd": "GET", 450 "iat": 1551863696 451 } 453 Notes: 455 o The property "htu" holds a Base64Url encoded value of the 456 normalized target URI after it has been hashed by the hash 457 algorithm associated with the JWS signature. 459 o The "mtd" property holds the expected HTTP method. In the example 460 it is actually redundant since the absence of a "mtd" property 461 defaults to "GET" for URI based requests in this specification. 463 o The "iat" property holds a time stamp in UNIX "epoch" format. 465 The following subsections detail the operation for requests using an 466 HTTP query string component for holding a signature. 468 5.1. Request Creation 470 In order to create a valid signed URI request, the following steps 471 (and ordering) MUST be adhered to: 473 1. Store the target HTTP method in a variable "targetMethod". 475 2. Store the target URI in a variable "targetURI" after having 476 normalized it as described in Section 6.7. 478 3. Create an empty JSON Object from now on referred to as 479 ".secinf". 481 4. Derive (or define) the hash algorithm to use as described in 482 Section 6.12. Save the algorithm in a variable "hashAlgorithm". 484 5. Add a property "htu" (Hashed Target URI) to ".secinf" where the 485 argument is a JSON String holding the outcome of the process 486 described in Section 6.2. 488 6. Add a property "mtd" to ".secinf" where the argument is a JSON 489 String holding a copy of "targetMethod". 491 Note: for the HTTP method "GET", this step is optional because 492 "GET" is the default for URI based requests. 494 7. If there is a need to include additional HTTP headers in the 495 signed request data, create a header object as described in 496 Section 6.3. 498 8. Add a time stamp property (see Section 6.11) to ".secinf". 500 9. Serialize the ".secinf" JSON Object into a UTF-8 [UNICODE] byte 501 array representing a "JWS Payload" [RFC7515]. 503 10. Create a "JWS Protected Header" [RFC7515] as described in 504 Section 6.4. 506 11. Create a JWS string object as described in Section 6.5. 508 12. Create a query string component by concatenating ".jws=" with 509 the JWS string created in the preceding step. This component is 510 appended to the original unsigned request URI prepended by & or 511 ? depending on if it is the only query component or not. 513 13. Submit an HTTP compliant request to the target URI including the 514 following information: 516 * HTTP method set to "targetMethod". 518 * All HTTP headers (if any) specified in step 7. 520 * Other HTTP headers (if any) needed by the application. 522 5.2. Request Validation 524 In addition to normal validation of received data (which may be 525 carried out before or after the steps outlined here), the following 526 steps MUST be performed in order to validate a URI based HTTP 527 request: 529 1. Store the HTTP method of the request in a variable 530 "targetMethod". 532 2. Store the from the request recreated target URI in a variable 533 "targetURI" after having normalized it as described in 534 Section 6.7. 536 3. Extract the JWS string from the ".jws" element which MUST reside 537 in the query string of "targetURI". If the JWS string is 538 missing the service MUST reject the request (see Section 3.2). 540 4. Decode the argument of the preceding step as described in 541 Section 6.6. 543 5. Remove the ".jws" query string component from "targetURI". Note 544 that if the ".jws" query component is the last part of 545 "targetURI", the delimiter immediately preceding the ".jws" 546 component is removed, else the succeeding delimiter is removed. 548 6. Parse "JWS Payload" (created in step 4) with a JSON parser and 549 from now on refer to the result as ".secinf". If ".secinf" is 550 not a JSON Object the service MUST reject the request (see 551 Section 3.2). 553 7. Derive the hash algorithm to use as described in Section 6.12. 554 Save the algorithm in a variable "hashAlgorithm". 556 8. Using ".secinf" the property "htu" is read. If "htu" is missing 557 or is not a JSON String the service MUST reject the request (see 558 Section 3.2). 560 9. Perform the operation described in Section 6.2 and compare the 561 outcome with the argument to "htu". If these value do not match 562 the service MUST reject the request (see Section 3.2). 564 Note: in some proxy arrangements it may be difficult retrieving 565 the proper value of "targetURI". In such cases the comparison 566 with "htu" MAY be disabled. 568 10. Using ".secinf", the property "mtd" is read. if "mtd" is 569 missing the HTTP method is assumed to be "GET" else it is 570 assumed to be the read value. If the derived method does not 571 match "targetMethod" or is not a JSON String the service MUST 572 reject the request (see Section 3.2). 574 11. If the optional "hdr" property is present in ".secinf", process 575 the argument of "hdr" as described in Section 6.9. 577 12. Using ".secinf", the property "iat" (see Section 6.11) is read. 578 if "iat" is missing or is not a JSON Number the service MUST 579 reject the request (see Section 3.2). 581 13. Perform signature validation as described in Section 6.10. 583 Note: validation of application specific data can be performed 584 anytime. The action(s) to perform after a possible failure is out of 585 scope for this specification (see Section 3.2). 587 6. Common Operations 589 This specification builds on a modular scheme using common procedures 590 described in the following subsections. 592 6.1. Create Signable JSON Data 594 Unsigned request data is now supposed to reside in "message". To 595 facilitate resilience against (legitimate) variances in JSON 596 processing between different platforms and systems, "message" needs 597 to be canonicalized and serialized into a UTF-8 [UNICODE] encoded 598 byte array. If the used JSON tools offer intrinsic support for JCS 599 [JCS], this is typically a single operation, else the followings 600 steps are performed: 602 1. Serialize "message" using standard JSON tools for the platform. 604 2. Create a canonical and UTF-8 encoded form of the data created in 605 the preceding step, through an external software solution 606 supporting JCS. 608 The output from JCS represents a "JWS Payload" [RFC7515]. 610 6.2. Create Signable URI Data 612 For URI based requests, the steps to create signable URI data are as 613 follows: 615 1. Convert "targetURI" into a UTF-8 [UNICODE] encoded byte array. 617 2. Create a digest of the result of the preceding step using the 618 previously defined "hashAlgorithm". The result is a byte array. 620 3. The result of the preceding step is subsequently Base64Url 621 encoded. 623 The test vectors in Appendix A provide a few examples showing 624 authentic values of the "htu" (Hashed Target URI) property. 626 6.3. Create HTTP Header Object 628 To create a digest of headers to be included in a signed request, 629 perform the following operations: 631 1. Create an empty string "headerBlob". 633 2. Create an empty string "headerList". 635 3. Create a collection of headers to be sent as described in 636 Section 6.8. 638 4. Enumerate the "headerCollection" and perform the following steps 639 for each entry: 641 * Append header field name to "headerList". 643 * Append header field name to "headerBlob". 645 * Append a semicolon (':') to to "headerBlob". 647 * Append header field value to "headerBlob". 649 * For all but the last entry, append a newline (U+000A) to 650 "headerBlob". 652 * For all but the last entry, append a comma (',') to 653 "headerList". 655 5. Create a two element JSON Array object "headerData". 657 6. Run the previously defined "hashAlgorithm" (see Section 6.12) 658 over the UTF-8 [UNICODE] representation of "headerBlob". 660 7. Base64Url-encode the result of the preceding operation and assign 661 the result to the first entry in "headerData" in the form of a 662 JSON String. 664 8. Assign a copy of "headerList" to the second entry in "headerData" 665 in the form of a JSON String. 667 9. Add a property "hdr" to ".secinf" using a copy of "headerData" as 668 argument. 670 Below is an example of header input data: 672 x-debug: full 673 Cache-Control: max-age=60, must-revalidate 675 Applying the process described in this subsection and using the 676 SHA-256 [SHS] hash algorithm should generate the following ".secinf" 677 data: 679 "hdr": ["Ljzuq8C9PScbvLpBxG8GNOs-WQUd7gl7R64izahhe-0", 680 "x-debug,cache-control"] 682 6.4. Create JWS Protected Header 684 Create a "JWS Protected Header" [RFC7515] JSON Object with algorithm 685 and key data adapted for the application. Below is a minimal 686 example: 688 { 689 "alg": "ES256" 690 } 692 6.5. Create JWS String 694 To create a compact JWS object (a string), perform the following 695 steps: 697 1. Serialize the previously defined "JWS Protected Header" object 698 into a UTF-8 [UNICODE] encoded byte array. 700 2. Base64Url-encode the output from the preceding step into a local 701 variable "jwsProtectedHeaderB64U". 703 3. Base64Url-encode the previously defined variable "JWS Payload" 704 into a local variable "jwsPayloadB64U". 706 4. Set a local variable "signedData" to the UTF-8 encoded 707 representation of the concatenation of: 709 * The previously defined variable "jwsProtectedHeaderB64U". 711 * A point character ("."). 713 * The previously defined variable "jwsPayloadB64U". 715 5. Use the designated signature key, signature algorithm and 716 "signedData" to create a "JWS Signature" object (byte array). 718 6. Return the string consisting of the concatenation of: 720 * The previously defined variable "jwsProtectedHeaderB64U". 722 * A period character ('.'). 724 * For URI based requests only: "jwsPayloadB64U". That is, JSON 725 based requests use the detached JWS format described in 726 Appendix F of [RFC7515]. 728 * A period character ('.'). 730 * The previously defined variable "JWS Signature", here encoded 731 in Base64Url [RFC4648]. 733 6.6. Decode JWS String 735 The following processing steps presume that there is an input string 736 holding a JWS compact object, here called "jwsString": 738 1. Verify that "jwsString" has the syntax 740 "header.payload.signature" 742 where the length of the "payload" element is zero for JSON based 743 requests and non-zero for URI based requests. That is, JSON 744 based requests use the detached JWS format described in 745 Appendix F of [RFC7515]. 747 2. Assign the "header" portion of "jwsString" to a variable 748 "jwsProtectedHeaderB64U". 750 3. Base64Url-decode "jwsProtectedHeaderB64U" into a byte array. 752 4. Parse the output from the preceding step with a JSON parser and 753 assume that the result (which MUST be a JSON Object) represents a 754 "JWS Protected Header" [RFC7515]. 756 5. For URI based requests only: 757 base64Url-decode the "payload" portion of "jwsString" into a byte 758 array representing a "JWS Payload" [RFC7515]. 760 6. Base64Url-decode the "signature" portion of "jwsString" into a 761 byte array representing a "JWS Signature" [RFC7515]. 763 If any of the steps above fail, the service MUST reject the request 764 (see Section 3.2). 766 6.7. Normalize Target URI 768 To facilitate comparison between actual (received) URIs and signed 769 URIs, URIs MUST be normalized according to the following: 771 The schema default ports 443 and 80 MUST be removed from HTTPS and 772 HTTP URIs respectively. 774 URI characters that have been escaped that are in the non-reserved 775 set [ALPHA DIGIT '-' '.' '_' '~'] MUST be restored in their 776 natural form. 778 Escape sequences MUST transformed into uppercase. 780 Non-ASCII characters MUST be escaped to their UTF-8 [UNICODE] 781 counterpart. 783 Host names MUST be lowercased. 785 The following URI shows a non-normalized URI: 787 https://EXAMPLE.COM:443/%63EURO%2f 789 Note: EURO denotes a single Euro character (Unicode: U+20AC), 790 which not being ASCII, is currently not displayable in RFCs. 792 The same URI after normalization: 794 https://example.com/c%E2%82%AC%2F 796 [[ This section is still incomplete ]] 798 6.8. Normalize Header Data 800 Headers to be included in signed requests MUST be normalized. This 801 subsection shows a common procedure for senders and receivers based 802 on Section 3.2.4 of [RFC7230]. 804 Collect received headers or headers to be submitted in a list of 805 header field name and header field value pairs according to the 806 following: 808 o Header field names MUST be lowercased. 810 o Leading and trailing optional whitespace (OWS) in the header field 811 value MUST be omitted. If there are multiple instances of the 812 same header field name, all header field values associated with 813 the header field name MUST be concatenated, separated by a ASCII 814 comma and an ASCII space (', '), and used in the order in which 815 they are intended to appear in an HTTP message. Any other 816 modification to the header field value MUST NOT be made. 818 This list is referred to as "headerCollection" in other places in 819 this specification. 821 Below is an example of header input data: 823 x-debug: full 824 Cache-control: max-age=60 825 Cache-Control: must-revalidate 827 Applying the process described in this subsection should generate the 828 following collection: 830 |======================================================| 831 | Header Field Name | Header Field Value | 832 |======================================================| 833 | x-debug | full | 834 |------------------------------------------------------| 835 | cache-control | max-age=60, must-revalidate | 836 |------------------------------------------------------| 838 For interoperability reasons it is RECOMMENDED to not use duplicate 839 header names for headers that are to be signed. 841 6.9. Validate HTTP Header Object 843 To validate a digest of headers in a signed request, perform the 844 following operations: 846 1. Create a collection of received headers as described in 847 Section 6.8. 849 2. Create an empty string "headerBlob". 851 3. Read the "hdr" property of ".secinf". This MUST be a JSON Array 852 holding exactly two JSON String elements. 854 4. Perform the following actions on the data obtained in the 855 preceding step: 857 * Base64Url-decode the first string into a byte array "digest". 859 * Split the second string into ordered array of strings called 860 "headerList". Note that the format MUST be a list of header 861 field names in lowercase, separated by comma (',') characters. 862 There MUST NOT be any whitespace or terminating comma in this 863 string. 865 * Verify that the received "headerList" contains the header 866 field names as defined by an application specific policy. 868 5. Enumerate the "headerList" and perform the following steps for 869 each entry: 871 * Append header field name to "headerBlob". 873 * Append a semicolon (':') to to "headerBlob". 875 * Retrieve the matching header field value from 876 "headerCollection". 878 * Append the result of the preceding step to "headerBlob". 880 * For all but the last entry, append a newline (U+000A) to 881 "headerBlob". 883 6. Run the previously defined "hashAlgorithm" (see Section 6.12) 884 over the UTF-8 [UNICODE] representation of "headerBlob". 886 7. Verify that the result of the preceding step is identical to 887 "digest". 889 If any of the steps above fail, the service MUST reject the request 890 (see Section 3.2). 892 Note that this specification does not enforce any particular ordering 893 of signed header elements. 895 6.10. Validate JWS Signature 897 Validation of the JWS [RFC7515] object, using the previously 898 extracted and decoded objects requires the following steps: 900 1. Verify that the received "JWS Protected Header" contains a JWS 901 algorithm ("alg") and key identifiers that matches the needs of 902 the application. 904 2. Retrieve the signature validation key. This part is application 905 specific since the key may be implicit, specified by a key ID 906 ("kid") or be supplied in a certificate path ("x5c"). 908 3. Set a local variable "signedData" to the UTF-8 [UNICODE] encoded 909 representation of the string created by concatenating the 910 following elements: 912 * The previously collected variable "jwsProtectedHeaderB64U". 914 * A period character ('.'). 916 * The previously collected variable "JWS Payload", but here 917 encoded in Base64Url [RFC4648]. 919 4. Validate the signature using the algorithm retrieved in step 1, 920 the signature validation key from step 2, "signedData" from step 921 3 and the previously collected "JWS Signature" object (byte 922 array). 924 If any of the steps above fail, the service MUST reject the request 925 (see Section 3.2). 927 6.11. Time Stamps 929 Time stamps have the same name ("iat"), format and function as 930 described in JWT [RFC7519], Section 4.1.6. However, in this 931 specification time stamps are REQUIRED, and stored in the ".secinf" 932 JSON Object. 934 Although JWT permits non-integer values, implementers of this 935 specification SHOULD limit generated time stamp granularity to 936 seconds and use integer representation. 938 The policy with respect to the difference between the current time 939 and received time stamps is out of scope for this specification. 940 However, for security reasons it is generally a good idea limiting 941 deviations to a few minutes as well as using network based clock 942 synchronization in both ends. 944 6.12. Hash Algorithms 946 Inclusion of HTTP header elements as well as the "htu" property of 947 URI based requests depends on digests produced by a hash algorithm. 948 The default is using the hash algorithm associated with the JWS 949 signature algorithm ("alg") featured in the "JWS Protected Header". 950 That is, the JWA [RFC7518] algorithms "ES256" and "HS384" imply the 951 hash algorithms SHA-256 and SHA-384 respectively. 953 In case this is not desired, this specification permits overriding 954 the default by including a "hao" (Hash Algorithm Override) property 955 in the ".secinf" JSON Object. The currently recognized arguments to 956 "hao" are: 958 "S256" for SHA-256 [SHS] 960 "S384" for SHA-384 [SHS] 961 "S512" for SHA-512 [SHS] 963 7. Local Naming Conventions 965 Although using the ".secinf" JSON property name and ".jws" query 966 component name is RECOMMENDED, this specification permits (=being 967 considered as compatible), the use of local naming conventions as 968 long as the specified procedures and formats are adhered to. 970 Local naming conventions MUST be properly communicated in the 971 community using them. 973 8. MIME Multipart Requests 975 [[ 977 It should be possible to extending the JSON based request to also 978 support attachments. This is currently out of scope for this 979 specification. 981 ]] 983 9. IANA Considerations 985 This document currently has no IANA actions but the reserved names 986 below could be candidates for IANA registration: 988 .secinf 989 JSON Object holding the security related data of this 990 specification. 992 .jws 993 HTTP query component holding the security related data of this 994 specification. 996 The hash algorithms defined in Section 6.12 could also benefit from 997 IANA registration. 999 10. Security Considerations 1001 The purpose of this specification is adding an integrity and 1002 authorization layer to HTTP requests. This part is subject to the 1003 same security considerations as the underpinning JCS and JWS schemes. 1005 For most applications HTTPS [RFC7231] would be the logical choice, 1006 not only for protecting application data from snooping, but also to 1007 not unnecessary reveal data about signature keys. 1009 In a cloud scenario with Web servers open for access by any party new 1010 security challenges are introduced. Cryptographic solutions protect 1011 data but may also add vulnerabilities to denial-of-service attacks 1012 since they often need substantial processing. 1014 Protecting against replay attacks is important because replay may 1015 actually be a legitimate facility for systems repeating a request due 1016 to a communication failure. This cannot be entirely solved by time 1017 stamps and cryptography; you usually need unique transactions IDs and 1018 data base support as well. For reliable operation there must be 1019 common rules within a community using such features. The REST [REST] 1020 paradigm also requires such measures due to the idempotent operation 1021 specified for "PUT", "GET" and "DELETE. 1023 11. Acknowledgements 1025 Parts of this specification were derived from the HTTP signature 1026 [HTTPSIG] draft. 1028 12. References 1030 12.1. Normative References 1032 [JCS] A. Rundgren, B. Jordan, S. Erdtman, "JSON Canonicalization 1033 Scheme - Work in progress", . 1036 [JWSJCS] A. Rundgren, "Combined JWS and JCS Signature Scheme - Work 1037 in progress", . 1039 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1040 Requirement Levels", BCP 14, RFC 2119, 1041 DOI 10.17487/RFC2119, March 1997, 1042 . 1044 [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform 1045 Resource Identifier (URI): Generic Syntax", STD 66, 1046 RFC 3986, DOI 10.17487/RFC3986, January 2005, 1047 . 1049 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 1050 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 1051 . 1053 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 1054 Protocol (HTTP/1.1): Message Syntax and Routing", 1055 RFC 7230, DOI 10.17487/RFC7230, June 2014, 1056 . 1058 [RFC7231] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 1059 Protocol (HTTP/1.1): Semantics and Content", RFC 7231, 1060 DOI 10.17487/RFC7231, June 2014, 1061 . 1063 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 1064 DOI 10.17487/RFC7493, March 2015, 1065 . 1067 [RFC7515] Jones, M., Bradley, J., and N. Sakimura, "JSON Web 1068 Signature (JWS)", RFC 7515, DOI 10.17487/RFC7515, May 1069 2015, . 1071 [RFC7518] Jones, M., "JSON Web Algorithms (JWA)", RFC 7518, 1072 DOI 10.17487/RFC7518, May 2015, 1073 . 1075 [RFC7519] Jones, M., Bradley, J., and N. Sakimura, "JSON Web Token 1076 (JWT)", RFC 7519, DOI 10.17487/RFC7519, May 2015, 1077 . 1079 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 1080 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 1081 May 2017, . 1083 [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 1084 Interchange Format", STD 90, RFC 8259, 1085 DOI 10.17487/RFC8259, December 2017, 1086 . 1088 [SHS] National Institute of Standards and Technology, "Secure 1089 Hash Standard (SHS)", FIPS PUB 180-4, August 2015, 1090 . 1093 [UNICODE] The Unicode Consortium, "The Unicode Standard, Version 1094 10.0.0", 1095 . 1097 12.2. Informal References 1099 [AWS] Amazon.com, "Signing AWS API Requests", 1100 . 1103 [FAPI] Open ID, "Financial-grade API", 1104 . 1106 [HTTPSIG] M. Cavage, M. Sporny, "Signing HTTP Messages", 1107 . 1110 [OBIE] Open Banking UK, "Open Banking API", 1111 . 1113 [REST] Roy Fielding, "Architectural Styles and the Design of 1114 Network-based Software Architectures", 1115 . 1117 [STET] STET, "PSD2 API V1.4.1", . 1119 12.3. URIs 1121 [1] https://github.com/cyberphone/ietf-signed-http-requests 1123 Appendix A. Test Vectors 1125 The following test vectors "activate" all parts of the specification. 1126 After removing the line breaks needed for publishing, the test 1127 vectors are supposed to be fully validatable. 1129 A.1. Type=URI, Method=GET, Algorithm=HS256 1131 Target URI: 1133 https://example.com/users/456 1135 Signed URI: 1137 https://example.com/users/456?.jws=eyJhbGciOiJIUzI1NiJ9.eyJodHUi 1138 OiJmaVZpNGpZaER0N1ZDdVFJS1VJZFdJTkVXZm9oX05YSGZMVFpORWVTYXZZIiwi 1139 aWF0IjoxNTUxOTUxOTAwfQ.Wll5cFEE9sidHs01sADus8kbHNHAC5DCzyytYoAtT 1140 2g 1142 Decoded JWS Payload: 1144 { 1145 "htu": "fiVi4jYhDt7VCuQIKUIdWINEWfoh_NXHfLTZNEeSavY", 1146 "iat": 1551951900 1147 } 1149 Symmetric signature validation key, here in hexadecimal notation: 1151 7fdd851a3b9d2dafc5f0d00030e22b9343900cd42ede4948568a4a2ee655291a 1153 A.2. Type=JSON, Method=POST, Algorithm=ES256 1155 Target URI: 1157 https://example.com/users 1159 JSON Body: 1161 { 1162 "name": "John Doe", 1163 "profession": "Unknown", 1164 ".secinf": { 1165 "uri": "https://example.com/users", 1166 "iat": 1551951900, 1167 "jws": "eyJhbGciOiJFUzI1NiJ9..-N7yuF1TEASo5Ub5q2T1_EkLWrWHs2 1168 nyHjDupkinoRcQbSo8h2ygL9pmGzd_YU4jn_bcMQF8BrTIlSioNel5GQ" 1169 } 1170 } 1172 Public signature validation key, here in PEM format: 1174 -----BEGIN PUBLIC KEY----- 1175 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcensDzcMEkgiePz6DXB7cDuwFems 1176 hAFR90UNVQFCg8TGryvN7p7AbT55VxIXvYnvuAqIPQgefOnAdpTu3qdV5g== 1177 -----END PUBLIC KEY----- 1179 A.3. Type=JSON, Method=PUT, Algorithm=ES256 1181 Target URI: 1183 https://example.com/users/456 1185 JSON Body: 1187 { 1188 "name": "Jane Smith", 1189 "profession": "Hacker", 1190 ".secinf": { 1191 "uri": "https://example.com/users/456", 1192 "mtd": "PUT", 1193 "iat": 1551951900, 1194 "jws": "eyJhbGciOiJFUzI1NiJ9.._VWTXYcgr6OTCcJg6XZzPkHsLU-jUT 1195 T1HoQ92bihMIDlXR7xNfmxlHWSUc9cyFCxzsBy9yq33eFn3fApIH42SA" 1196 } 1197 } 1199 Public signature validation key, here in PEM format: 1201 -----BEGIN PUBLIC KEY----- 1202 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcensDzcMEkgiePz6DXB7cDuwFems 1203 hAFR90UNVQFCg8TGryvN7p7AbT55VxIXvYnvuAqIPQgefOnAdpTu3qdV5g== 1204 -----END PUBLIC KEY----- 1206 A.4. Type=URI, Method=DELETE, Algorithm=RS256 1208 Target URI: 1210 https://example.com/users/456 1212 Signed URI: 1214 https://example.com/users/456?.jws=eyJhbGciOiJSUzI1NiJ9.eyJodHUi 1215 OiI5R3FtRDBSRWRqSDFZNklvSXR3UjdKRURuU0pjVzNuSnhoM085eHQ3Zk1RQ1cy 1216 N3FtOEQyWUNtN1h4RzRwU1hwOGJFM3lTT3RzWlhIR0VJSWw1M05jQSIsIm10ZCI6 1217 IkRFTEVURSIsImlhdCI6MTU1MTk1MTkwMCwiaGFvIjoiUzUxMiIsImhkciI6WyIz 1218 ZXBrQno4RUJwMUxYX01EdFd1WnFWZjFLYjJyalFNZzE5RjVvT2Fhbk91SVFpS1Z1 1219 SHBrSG5WdWFLMlZZbVZ2bEpOSGxEY2NEeHFxVGQxNFU5VXg5USIsIngtZGVidWci 1220 XX0.YRTEbCrOy11c10HcPSDX_DCtl56S5qmcYWFcuG6wqsgg7vnCr22vCDhE1xJL 1221 xeM2hp_-gSmdxykJ-Q060xetax-nMmXUhrDtcRoeCfO12-xDTymZTJXtb11SX6Pn 1222 mt9CnM4ZOVrJVro7eLW8hCc4p5As7zDS2arNM_-IsWiNJ1T25EDb8ZS7kLLSA6Im 1223 lo31o8815kC0oHNI0q-lZeaOX3DhnL1tMJKZQzrItXvmZ0oqJ3kL8bxF6aglOFC0 1224 zOYUU2kciIf55jVcfBgwupecFw-rN56QEg8PzA8YA-nGPWHBpxJUWWseY4qXZudR 1225 cQQZtms7Yc1yK7z3fNhht6Oh1A 1227 Decoded JWS Payload: 1229 { 1230 "htu": "9GqmD0REdjH1Y6IoItwR7JEDnSJcW3nJxh3O9xt7fMQCW27qm8D2YC 1231 m7XxG4pSXp8bE3ySOtsZXHGEIIl53NcA", 1232 "mtd": "DELETE", 1233 "iat": 1551951900, 1234 "hao": "S512", 1235 "hdr": ["3epkBz8EBp1LX_MDtWuZqVf1Kb2rjQMg19F5oOaanOuIQiKVuHpkH 1236 nVuaK2VYmVvlJNHlDccDxqqTd14U9Ux9Q", "x-debug"] 1237 } 1239 Note the overridden hash algorithm. 1241 Required HTTP Headers: 1243 x-debug: full 1245 Public signature validation key, here in PEM format: 1247 -----BEGIN PUBLIC KEY----- 1248 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhFWEXArvaZEpSP5qNX7x 1249 4C4Hl28GJQTNvnDwkfqiWs63kXbdyPeS06bz6GnY3tfQ/093nGauWsimqKBmGAGM 1250 PtsV83Qxw1OIeO4ujbIIb9pema0qtVqs0MWlHxklZGFkYfAmbuEUFxYDeLDHe0bk 1251 kXbSlB7/t8pCSvc8HLgHjEQjYOlFRwjR0D+uLo+xgsCbpmCtYkB5lcT/zFgpRgY4 1252 zJNLSv7GZiz2S4Fc5ArGjd34lL47+L8bozuYjqNOv9sqX0Zgll5XaJ1ndvr7UqZu 1253 1xQFgm38reoM3IarBP/SkEFbt/v9iak602VO3k28fQhMaocP7JWR2YLT3kZM0+WT 1254 FwIDAQAB 1255 -----END PUBLIC KEY----- 1257 Appendix B. Other Signed HTTP Request Solutions 1259 This appendix briefly outlines a few other solutions addressing 1260 Signed HTTP Requests. 1262 B.1. Amazon Web Services 1264 AWS provides a system for their clients using HTTP headers holding 1265 security constructs while the digested HTTP body may hold any valid 1266 media type. For more information see the [AWS]. Signatures may also 1267 be added to query strings in a similar fashion to Section 5. 1269 B.2. HTTP Signatures 1271 HTTP Signatures is a system using HTTP headers holding security 1272 constructs while the (optional) digested HTTP body may hold any valid 1273 media type. This scheme has been adopted by the French Open Banking 1274 API [STET]. For more information see the Internet draft [HTTPSIG]. 1275 HTTP Signatures also supports signed response data. 1277 B.3. Open Banking (UK) 1279 The current (3.1) version of the Open Banking API [OBIE] use a scheme 1280 where a dedicated HTTP header holds a detached JWS signature covering 1281 a clear text JSON message in the HTTP body: 1283 POST /foo HTTP/1.1 1284 Host: example.com 1285 Content-Type: application/json 1286 x-jws-signature: eyJhbGciOiJSUzI1N..SD7xMbpL-2QgwUsAlMGzw 1287 Content-Length: 2765 1289 { 1290 "something": "data", 1292 Additional application specific properties 1294 } 1296 Notes: 1298 o The HTTP URI, method and headers are unsigned. 1300 o The signature argument (a JWS) was truncated for brevity. 1302 B.4. Financial API 1304 The current version (Draft 06) of the financial API [FAPI] use a 1305 scheme where the payload is signed using JWS in Base64Url mode: 1307 POST /foo HTTP/1.1 1308 Host: example.com 1309 Content-Type: application/jws 1310 Content-Length: 1288 1312 eyJhbGcRjIn0.ew0KICJfds56gty5ypc3MiOiA.2QgwUsA565656lMGzw 1314 Notes: 1316 o The HTTP URI, method and headers are unsigned. 1318 o The JWS signature was truncated for brevity. 1320 Appendix C. Development Portal 1322 The SHREQ specification is currently developed at: 1323 https://github.com/cyberphone/ietf-signed-http-requests [1]. 1325 Author's Address 1327 Anders Rundgren 1328 Independent 1329 Montpellier 1330 France 1332 Email: anders.rundgren.net@gmail.com 1333 URI: https://www.linkedin.com/in/andersrundgren/