Initial commit
[yaffs-website] / node_modules / http-signature / http_signing.md
1 # Abstract
2
3 This document describes a way to add origin authentication, message integrity,
4 and replay resistance to HTTP REST requests.  It is intended to be used over
5 the HTTPS protocol.
6
7 # Copyright Notice
8
9 Copyright (c) 2011 Joyent, Inc. and the persons identified as document authors.
10 All rights reserved.
11
12 Code Components extracted from this document must include MIT License text.
13
14 # Introduction
15
16 This protocol is intended to provide a standard way for clients to sign HTTP
17 requests.  RFC2617 (HTTP Authentication) defines Basic and Digest authentication
18 mechanisms, and RFC5246 (TLS 1.2) defines client-auth, both of which are widely
19 employed on the Internet today.  However, it is common place that the burdens of
20 PKI prevent web service operators from deploying that methodology, and so many
21 fall back to Basic authentication, which has poor security characteristics.
22
23 Additionally, OAuth provides a fully-specified alternative for authorization
24 of web service requests, but is not (always) ideal for machine to machine
25 communication, as the key acquisition steps (generally) imply a fixed
26 infrastructure that may not make sense to a service provider (e.g., symmetric
27 keys).
28
29 Several web service providers have invented their own schemes for signing
30 HTTP requests, but to date, none have been placed in the public domain as a
31 standard.  This document serves that purpose.  There are no techniques in this
32 proposal that are novel beyond previous art, however, this aims to be a simple
33 mechanism for signing these requests.
34
35 # Signature Authentication Scheme
36
37 The "signature" authentication scheme is based on the model that the client must
38 authenticate itself with a digital signature produced by either a private
39 asymmetric key (e.g., RSA) or a shared symmetric key (e.g., HMAC).  The scheme
40 is parameterized enough such that it is not bound to any particular key type or
41 signing algorithm.  However, it does explicitly assume that clients can send an
42 HTTP `Date` header.
43
44 ## Authorization Header
45
46 The client is expected to send an Authorization header (as defined in RFC 2617)
47 with the following parameterization:
48
49     credentials := "Signature" params
50     params := 1#(keyId | algorithm | [headers] | [ext] | signature)
51     digitalSignature := plain-string
52
53     keyId := "keyId" "=" <"> plain-string <">
54     algorithm := "algorithm" "=" <"> plain-string <">
55     headers := "headers" "=" <"> 1#headers-value <">
56     ext := "ext" "=" <"> plain-string <">
57     signature := "signature" "=" <"> plain-string <">
58
59     headers-value := plain-string
60     plain-string   = 1*( %x20-21 / %x23-5B / %x5D-7E )
61
62 ### Signature Parameters
63
64 #### keyId
65
66 REQUIRED.  The `keyId` field is an opaque string that the server can use to look
67 up the component they need to validate the signature.  It could be an SSH key
68 fingerprint, an LDAP DN, etc.  Management of keys and assignment of `keyId` is
69 out of scope for this document.
70
71 #### algorithm
72
73 REQUIRED. The `algorithm` parameter is used if the client and server agree on a
74 non-standard digital signature algorithm.  The full list of supported signature
75 mechanisms is listed below.
76
77 #### headers
78
79 OPTIONAL.  The `headers` parameter is used to specify the list of HTTP headers
80 used to sign the request.  If specified, it should be a quoted list of HTTP
81 header names, separated by a single space character.  By default, only one
82 HTTP header is signed, which is the `Date` header.  Note that the list MUST be
83 specified in the order the values are concatenated together during signing. To
84 include the HTTP request line in the signature calculation, use the special
85 `request-line` value.  While this is overloading the definition of `headers` in
86 HTTP linguism, the request-line is defined in RFC 2616, and as the outlier from
87 headers in useful signature calculation, it is deemed simpler to simply use
88 `request-line` than to add a separate parameter for it.
89
90 #### extensions
91
92 OPTIONAL.  The `extensions` parameter is used to include additional information
93 which is covered by the request.  The content and format of the string is out of
94 scope for this document, and expected to be specified by implementors.
95
96 #### signature
97
98 REQUIRED.  The `signature` parameter is a `Base64` encoded digital signature
99 generated by the client. The client uses the `algorithm` and `headers` request
100 parameters to form a canonicalized `signing string`.  This `signing string` is
101 then signed with the key associated with `keyId` and the algorithm
102 corresponding to `algorithm`.  The `signature` parameter is then set to the
103 `Base64` encoding of the signature.
104
105 ### Signing String Composition
106
107 In order to generate the string that is signed with a key, the client MUST take
108 the values of each HTTP header specified by `headers` in the order they appear.
109
110 1. If the header name is not `request-line` then append the lowercased header
111    name followed with an ASCII colon `:` and an ASCII space ` `.
112 2. If the header name is `request-line` then append the HTTP request line,
113    otherwise append the header value.
114 3. If value is not the last value then append an ASCII newline `\n`. The string
115    MUST NOT include a trailing ASCII newline.
116
117 # Example Requests
118
119 All requests refer to the following request (body omitted):
120
121     POST /foo HTTP/1.1
122     Host: example.org
123     Date: Tue, 07 Jun 2014 20:51:35 GMT
124     Content-Type: application/json
125     Digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
126     Content-Length: 18
127
128 The "rsa-key-1" keyId refers to a private key known to the client and a public
129 key known to the server. The "hmac-key-1" keyId refers to key known to the
130 client and server.
131
132 ## Default parameterization
133
134 The authorization header and signature would be generated as:
135
136     Authorization: Signature keyId="rsa-key-1",algorithm="rsa-sha256",signature="Base64(RSA-SHA256(signing string))"
137
138 The client would compose the signing string as:
139
140     date: Tue, 07 Jun 2014 20:51:35 GMT
141
142 ## Header List
143
144 The authorization header and signature would be generated as:
145
146     Authorization: Signature keyId="rsa-key-1",algorithm="rsa-sha256",headers="(request-target) date content-type digest",signature="Base64(RSA-SHA256(signing string))"
147
148 The client would compose the signing string as (`+ "\n"` inserted for
149 readability):
150
151     (request-target) post /foo + "\n"
152     date: Tue, 07 Jun 2011 20:51:35 GMT + "\n"
153     content-type: application/json + "\n"
154     digest: SHA-256=Base64(SHA256(Body))
155
156 ## Algorithm
157
158 The authorization header and signature would be generated as:
159
160     Authorization: Signature keyId="hmac-key-1",algorithm="hmac-sha1",signature="Base64(HMAC-SHA1(signing string))"
161
162 The client would compose the signing string as:
163
164     date: Tue, 07 Jun 2011 20:51:35 GMT
165
166 # Signing Algorithms
167
168 Currently supported algorithm names are:
169
170 * rsa-sha1
171 * rsa-sha256
172 * rsa-sha512
173 * dsa-sha1
174 * hmac-sha1
175 * hmac-sha256
176 * hmac-sha512
177
178 # Security Considerations
179
180 ## Default Parameters
181
182 Note the default parameterization of the `Signature` scheme is only safe if all
183 requests are carried over a secure transport (i.e., TLS).  Sending the default
184 scheme over a non-secure transport will leave the request vulnerable to
185 spoofing, tampering, replay/repudiation, and integrity violations (if using the
186 STRIDE threat-modeling methodology).
187
188 ## Insecure Transports
189
190 If sending the request over plain HTTP, service providers SHOULD require clients
191 to sign ALL HTTP headers, and the `request-line`.  Additionally, service
192 providers SHOULD require `Content-MD5` calculations to be performed to ensure
193 against any tampering from clients.
194
195 ## Nonces
196
197 Nonces are out of scope for this document simply because many service providers
198 fail to implement them correctly, or do not adopt security specifications
199 because of the infrastructure complexity.  Given the `header` parameterization,
200 a service provider is fully enabled to add nonce semantics into this scheme by
201 using something like an `x-request-nonce` header, and ensuring it is signed
202 with the `Date` header.
203
204 ## Clock Skew
205
206 As the default scheme is to sign the `Date` header, service providers SHOULD
207 protect against logged replay attacks by enforcing a clock skew.  The server
208 SHOULD be synchronized with NTP, and the recommendation in this specification
209 is to allow 300s of clock skew (in either direction).
210
211 ## Required Headers to Sign
212
213 It is out of scope for this document to dictate what headers a service provider
214 will want to enforce, but service providers SHOULD at minimum include the
215 `Date` header.
216
217 # References
218
219 ## Normative References
220
221 * [RFC2616] Hypertext Transfer Protocol -- HTTP/1.1
222 * [RFC2617] HTTP Authentication: Basic and Digest Access Authentication
223 * [RFC5246] The Transport Layer Security (TLS) Protocol Version 1.2
224
225 ## Informative References
226
227     Name: Mark Cavage (editor)
228     Company: Joyent, Inc.
229     Email: mark.cavage@joyent.com
230     URI: http://www.joyent.com
231
232 # Appendix A - Test Values
233
234 The following test data uses the RSA (1024b) keys, which we will refer
235 to as `keyId=Test` in the following samples:
236
237     -----BEGIN PUBLIC KEY-----
238     MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCFENGw33yGihy92pDjZQhl0C3
239     6rPJj+CvfSC8+q28hxA161QFNUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6
240     Z4UMR7EOcpfdUE9Hf3m/hs+FUR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJw
241     oYi+1hqp1fIekaxsyQIDAQAB
242     -----END PUBLIC KEY-----
243
244     -----BEGIN RSA PRIVATE KEY-----
245     MIICXgIBAAKBgQDCFENGw33yGihy92pDjZQhl0C36rPJj+CvfSC8+q28hxA161QF
246     NUd13wuCTUcq0Qd2qsBe/2hFyc2DCJJg0h1L78+6Z4UMR7EOcpfdUE9Hf3m/hs+F
247     UR45uBJeDK1HSFHD8bHKD6kv8FPGfJTotc+2xjJwoYi+1hqp1fIekaxsyQIDAQAB
248     AoGBAJR8ZkCUvx5kzv+utdl7T5MnordT1TvoXXJGXK7ZZ+UuvMNUCdN2QPc4sBiA
249     QWvLw1cSKt5DsKZ8UETpYPy8pPYnnDEz2dDYiaew9+xEpubyeW2oH4Zx71wqBtOK
250     kqwrXa/pzdpiucRRjk6vE6YY7EBBs/g7uanVpGibOVAEsqH1AkEA7DkjVH28WDUg
251     f1nqvfn2Kj6CT7nIcE3jGJsZZ7zlZmBmHFDONMLUrXR/Zm3pR5m0tCmBqa5RK95u
252     412jt1dPIwJBANJT3v8pnkth48bQo/fKel6uEYyboRtA5/uHuHkZ6FQF7OUkGogc
253     mSJluOdc5t6hI1VsLn0QZEjQZMEOWr+wKSMCQQCC4kXJEsHAve77oP6HtG/IiEn7
254     kpyUXRNvFsDE0czpJJBvL/aRFUJxuRK91jhjC68sA7NsKMGg5OXb5I5Jj36xAkEA
255     gIT7aFOYBFwGgQAQkWNKLvySgKbAZRTeLBacpHMuQdl1DfdntvAyqpAZ0lY0RKmW
256     G6aFKaqQfOXKCyWoUiVknQJAXrlgySFci/2ueKlIE1QqIiLSZ8V8OlpFLRnb1pzI
257     7U1yQXnTAEFYM560yJlzUpOb1V4cScGd365tiSMvxLOvTA==
258     -----END RSA PRIVATE KEY-----
259
260 And all examples use this request:
261
262 <!-- httpreq -->
263
264     POST /foo?param=value&pet=dog HTTP/1.1
265     Host: example.com
266     Date: Thu, 05 Jan 2014 21:31:40 GMT
267     Content-Type: application/json
268     Digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
269     Content-Length: 18
270
271     {"hello": "world"}
272
273 <!-- /httpreq -->
274
275 ### Default
276
277 The string to sign would be:
278
279 <!-- sign {"name": "Default", "options": {"keyId":"Test", "algorithm": "rsa-sha256"}} -->
280 <!-- signstring -->
281
282     date: Thu, 05 Jan 2014 21:31:40 GMT
283
284 <!-- /signstring -->
285
286 The Authorization header would be:
287
288 <!-- authz -->
289
290     Authorization: Signature keyId="Test",algorithm="rsa-sha256",headers="date",signature="jKyvPcxB4JbmYY4mByyBY7cZfNl4OW9HpFQlG7N4YcJPteKTu4MWCLyk+gIr0wDgqtLWf9NLpMAMimdfsH7FSWGfbMFSrsVTHNTk0rK3usrfFnti1dxsM4jl0kYJCKTGI/UWkqiaxwNiKqGcdlEDrTcUhhsFsOIo8VhddmZTZ8w="
291
292 <!-- /authz -->
293
294 ### All Headers
295
296 Parameterized to include all headers, the string to sign would be (`+ "\n"`
297 inserted for readability):
298
299 <!-- sign {"name": "All Headers", "options": {"keyId":"Test", "algorithm": "rsa-sha256", "headers": ["(request-target)", "host", "date", "content-type", "digest", "content-length"]}} -->
300 <!-- signstring -->
301
302     (request-target): post /foo?param=value&pet=dog
303     host: example.com
304     date: Thu, 05 Jan 2014 21:31:40 GMT
305     content-type: application/json
306     digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
307     content-length: 18
308
309 <!-- /signstring -->
310
311 The Authorization header would be:
312
313 <!-- authz -->
314
315     Authorization: Signature keyId="Test",algorithm="rsa-sha256",headers="(request-target) host date content-type digest content-length",signature="Ef7MlxLXoBovhil3AlyjtBwAL9g4TN3tibLj7uuNB3CROat/9KaeQ4hW2NiJ+pZ6HQEOx9vYZAyi+7cmIkmJszJCut5kQLAwuX+Ms/mUFvpKlSo9StS2bMXDBNjOh4Auj774GFj4gwjS+3NhFeoqyr/MuN6HsEnkvn6zdgfE2i0="
316
317 <!-- /authz -->
318
319 ## Generating and verifying signatures using `openssl`
320
321 The `openssl` commandline tool can be used to generate or verify the signatures listed above.
322
323 Compose the signing string as usual, and pipe it into the the `openssl dgst` command, then into `openssl enc -base64`, as follows:
324
325     $ printf 'date: Thu, 05 Jan 2014 21:31:40 GMT' | \
326       openssl dgst -binary -sign /path/to/private.pem -sha256 | \
327       openssl enc -base64
328     jKyvPcxB4JbmYY4mByyBY7cZfNl4OW9Hp...
329     $
330
331 The `-sha256` option is necessary to produce an `rsa-sha256` signature. You can select other hash algorithms such as `sha1` by changing this argument.
332
333 To verify a signature, first save the signature data, Base64-decoded, into a file, then use `openssl dgst` again with the `-verify` option:
334
335     $ echo 'jKyvPcxB4JbmYY4mByy...' | openssl enc -A -d -base64 > signature
336     $ printf 'date: Thu, 05 Jan 2014 21:31:40 GMT' | \
337       openssl dgst -sha256 -verify /path/to/public.pem -signature ./signature
338     Verified OK
339     $
340
341 ## Generating and verifying signatures using `sshpk-sign`
342
343 You can also generate and check signatures using the `sshpk-sign` tool which is
344 included with the `sshpk` package in `npm`.
345
346 Compose the signing string as above, and pipe it into `sshpk-sign` as follows:
347
348     $ printf 'date: Thu, 05 Jan 2014 21:31:40 GMT' | \
349       sshpk-sign -i /path/to/private.pem
350     jKyvPcxB4JbmYY4mByyBY7cZfNl4OW9Hp...
351     $
352
353 This will produce an `rsa-sha256` signature by default, as you can see using
354 the `-v` option:
355
356     sshpk-sign: using rsa-sha256 with a 1024 bit key
357
358 You can also use `sshpk-verify` in a similar manner:
359
360     $ printf 'date: Thu, 05 Jan 2014 21:31:40 GMT' | \
361       sshpk-verify -i ./public.pem -s 'jKyvPcxB4JbmYY...'
362     OK
363     $