OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <algorithm> | |
8 #include <map> | |
9 #include "base/base64.h" | |
10 #include "base/json/json_reader.h" | |
11 #include "base/logging.h" | |
7 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
13 #include "base/strings/string_piece.h" | |
14 #include "base/values.h" | |
8 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 15 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
10 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | 18 #include "third_party/WebKit/public/platform/WebCryptoKey.h" |
11 | 19 |
12 namespace content { | 20 namespace content { |
13 | 21 |
22 namespace { | |
23 | |
24 // FIXME! Need WebKit::WebCryptoAlgorithmIdNone | |
eroman
2013/10/22 21:49:38
There are other ways of accomplishing this that I
Ryan Sleevi
2013/10/24 01:45:58
There are other formats that may have embedded alg
eroman
2013/10/24 02:35:04
I will make the necessary changes to Blink side.
padolph
2013/10/28 20:35:07
This is addressed by your recent Blink checkin. Th
| |
25 const WebKit::WebCryptoAlgorithmId WebCryptoAlgorithmIdNone = | |
26 (WebKit::WebCryptoAlgorithmId)99; | |
27 | |
28 // TODO(padolph) Similar Create*Algorithm() methods are in | |
eroman
2013/10/22 21:49:38
What do you think about a renderer/webcrypto/webcr
padolph
2013/10/28 20:35:07
Done.
Should the stuff in webcrypto_util.[h|cc] b
| |
29 // webcrypto_impl_unittest.cc. Find a common place to put these. | |
30 | |
31 WebKit::WebCryptoAlgorithm CreateAlgorithm(WebKit::WebCryptoAlgorithmId id) { | |
32 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | |
33 } | |
34 | |
35 WebKit::WebCryptoAlgorithm CreateAlgorithmWithInnerHash( | |
36 WebKit::WebCryptoAlgorithmId algorithm_id, | |
37 unsigned short hash_key_length) { | |
38 WebKit::WebCryptoAlgorithmId hashId; | |
eroman
2013/10/22 21:49:38
use hacker_style_variable_naming for chromium code
padolph
2013/10/28 20:35:07
Done.
| |
39 switch (hash_key_length) { | |
40 case 160: | |
41 hashId = WebKit::WebCryptoAlgorithmIdSha1; | |
42 break; | |
43 case 224: | |
44 hashId = WebKit::WebCryptoAlgorithmIdSha224; | |
45 break; | |
46 case 256: | |
47 hashId = WebKit::WebCryptoAlgorithmIdSha256; | |
48 break; | |
49 case 384: | |
50 hashId = WebKit::WebCryptoAlgorithmIdSha384; | |
51 break; | |
52 case 512: | |
53 hashId = WebKit::WebCryptoAlgorithmIdSha384; | |
54 break; | |
55 } | |
56 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
eroman
2013/10/22 21:49:38
Please add a default case to the switch above (per
padolph
2013/10/28 20:35:07
Done.
| |
57 algorithm_id, | |
58 new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId))); | |
59 } | |
60 | |
61 WebKit::WebCryptoAlgorithm CreateHmacAlgorithm(unsigned short hash_key_length) { | |
62 return CreateAlgorithmWithInnerHash( | |
63 WebKit::WebCryptoAlgorithmIdHmac, | |
64 hash_key_length); | |
65 } | |
66 | |
67 WebKit::WebCryptoAlgorithm CreateRsaSsaAlgorithm( | |
68 unsigned short hash_key_length) { | |
69 return CreateAlgorithmWithInnerHash( | |
70 WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
71 hash_key_length); | |
72 } | |
73 | |
74 WebKit::WebCryptoAlgorithm CreateRsaOaepAlgorithm( | |
75 unsigned short hash_key_length) { | |
76 return CreateAlgorithmWithInnerHash( | |
77 WebKit::WebCryptoAlgorithmIdRsaOaep, | |
78 hash_key_length); | |
79 } | |
80 | |
81 WebKit::WebCryptoAlgorithm CreateAesAlgorithm( | |
82 WebKit::WebCryptoAlgorithmId aes_alg_id, | |
83 unsigned short length) { | |
84 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
85 aes_alg_id, | |
86 new WebKit::WebCryptoAesKeyGenParams(length)); | |
87 } | |
88 | |
89 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm(unsigned short length) { | |
90 return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc, length); | |
91 } | |
92 | |
93 WebKit::WebCryptoAlgorithm CreateAesGcmAlgorithm(unsigned short length) { | |
94 return CreateAesAlgorithm(WebKit::WebCryptoAlgorithmIdAesGcm, length); | |
95 } | |
96 | |
97 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
eroman
2013/10/22 21:49:38
Please provide a comment pointing to the definitio
padolph
2013/10/28 20:35:07
Will do. 'base64url' encoding is relatively common
| |
98 std::string base64EncodedText(input); | |
99 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); | |
eroman
2013/10/22 21:49:38
Are these transformations enumerated int he JOSE s
padolph
2013/10/28 20:35:07
Yes, in RFC4648 Section 5.
| |
100 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); | |
101 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); | |
102 return base::Base64Decode(base64EncodedText, output); | |
103 } | |
104 | |
105 // Identifiers for all JWK "alg" (algorithm) values handled by this code. The | |
eroman
2013/10/22 21:49:38
There is enough JWK stuff, that I suggest moving t
padolph
2013/10/28 20:35:07
Most of this code went away with the function tabl
| |
106 // "enum trick" is used to force int type, so a user type is not required in | |
eroman
2013/10/22 21:49:38
Not sure I know what the "enum trick" refers to. Y
padolph
2013/10/28 20:35:07
This code went away with the function table refact
| |
107 // web_crypto_impl.h | |
108 enum { | |
109 kJwkAlgorithmHs256, | |
110 kJwkAlgorithmHs384, | |
111 kJwkAlgorithmHs512, | |
112 kJwkAlgorithmRs256, | |
113 kJwkAlgorithmRs384, | |
114 kJwkAlgorithmRs512, | |
115 kJwkAlgorithmRsa1_5, | |
116 kJwkAlgorithmRsaOaep, | |
117 kJwkAlgorithmA128Kw, | |
118 kJwkAlgorithmA256Kw, | |
119 kJwkAlgorithmA128Gcm, | |
120 kJwkAlgorithmA256Gcm, | |
121 kJwkAlgorithmA128Cbc, | |
122 kJwkAlgorithmA256Cbc, | |
123 kJwkAlgorithmA384Cbc, | |
124 kJwkAlgorithmA512Cbc | |
125 }; | |
126 | |
127 WebKit::WebCryptoAlgorithmId JwkAlgIdToWebCryptoAlgId(int jwk_algorithm_id) { | |
eroman
2013/10/22 21:49:38
This function appears to be unused
padolph
2013/10/28 20:35:07
Done.
| |
128 switch (jwk_algorithm_id) { | |
129 case kJwkAlgorithmHs256: | |
130 case kJwkAlgorithmHs384: | |
131 case kJwkAlgorithmHs512: | |
132 return WebKit::WebCryptoAlgorithmIdHmac; | |
133 case kJwkAlgorithmRs256: | |
134 case kJwkAlgorithmRs384: | |
135 case kJwkAlgorithmRs512: | |
136 return WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | |
137 case kJwkAlgorithmRsa1_5: | |
138 return WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5; | |
139 case kJwkAlgorithmRsaOaep: | |
140 return WebKit::WebCryptoAlgorithmIdRsaOaep; | |
141 case kJwkAlgorithmA128Kw: | |
142 case kJwkAlgorithmA256Kw: | |
143 // TODO(padolph) Support AES keywrap algorithm, required for JWK but not | |
144 // present in the Web Crypto spec. | |
145 return WebCryptoAlgorithmIdNone; | |
146 case kJwkAlgorithmA128Gcm: | |
147 case kJwkAlgorithmA256Gcm: | |
148 return WebKit::WebCryptoAlgorithmIdAesGcm; | |
149 case kJwkAlgorithmA128Cbc: | |
150 case kJwkAlgorithmA256Cbc: | |
151 case kJwkAlgorithmA384Cbc: | |
152 case kJwkAlgorithmA512Cbc: | |
153 return WebKit::WebCryptoAlgorithmIdAesCbc; | |
154 default: | |
155 DCHECK(false); | |
156 return WebCryptoAlgorithmIdNone; | |
157 } | |
158 } | |
159 | |
160 unsigned short JwkAlgIdToKeyLengthBits(int jwk_algorithm_id) { | |
161 switch (jwk_algorithm_id) { | |
162 case kJwkAlgorithmA128Kw: | |
163 case kJwkAlgorithmA128Gcm: | |
164 case kJwkAlgorithmA128Cbc: | |
165 return 128; | |
166 case kJwkAlgorithmHs256: | |
167 case kJwkAlgorithmA256Kw: | |
168 case kJwkAlgorithmRs256: | |
169 case kJwkAlgorithmA256Gcm: | |
170 case kJwkAlgorithmA256Cbc: | |
171 return 256; | |
172 case kJwkAlgorithmHs384: | |
173 case kJwkAlgorithmRs384: | |
174 case kJwkAlgorithmA384Cbc: | |
175 return 384; | |
176 case kJwkAlgorithmHs512: | |
177 case kJwkAlgorithmRs512: | |
178 case kJwkAlgorithmA512Cbc: | |
179 return 512; | |
180 default: | |
181 return 0; | |
182 } | |
183 } | |
184 | |
185 WebKit::WebCryptoAlgorithm CreateWebCryptoAlgorithmFromJwkAlgorithmId( | |
eroman
2013/10/22 21:49:38
I think things would be more readable to have a si
padolph
2013/10/28 20:35:07
Done. But since the creation functions have differ
| |
186 int jwk_algorithm_id) { | |
187 const unsigned short key_length_bits = | |
188 JwkAlgIdToKeyLengthBits(jwk_algorithm_id); | |
189 DCHECK(key_length_bits); | |
190 switch(jwk_algorithm_id) { | |
191 case kJwkAlgorithmHs256: | |
192 case kJwkAlgorithmHs384: | |
193 case kJwkAlgorithmHs512: | |
194 return CreateHmacAlgorithm(key_length_bits); | |
195 case kJwkAlgorithmRs256: | |
196 case kJwkAlgorithmRs384: | |
197 case kJwkAlgorithmRs512: | |
198 return CreateRsaSsaAlgorithm(key_length_bits); | |
199 case kJwkAlgorithmRsa1_5: | |
200 return CreateAlgorithm(WebKit::WebCryptoAlgorithmIdRsaEsPkcs1v1_5); | |
201 case kJwkAlgorithmRsaOaep: | |
202 return CreateRsaOaepAlgorithm(key_length_bits); | |
203 case kJwkAlgorithmA128Kw: | |
204 case kJwkAlgorithmA256Kw: | |
205 // TODO(padolph) Support AES keywrap algorithm, required for JWK but not | |
206 // present in the Web Crypto spec. | |
207 return CreateAlgorithm(WebCryptoAlgorithmIdNone); | |
208 case kJwkAlgorithmA128Gcm: | |
209 case kJwkAlgorithmA256Gcm: | |
210 return CreateAesGcmAlgorithm(key_length_bits); | |
211 case kJwkAlgorithmA128Cbc: | |
212 case kJwkAlgorithmA256Cbc: | |
213 case kJwkAlgorithmA384Cbc: | |
214 case kJwkAlgorithmA512Cbc: | |
215 return CreateAesCbcAlgorithm(key_length_bits); | |
216 default: | |
217 DCHECK(false); | |
eroman
2013/10/22 21:49:38
NOTREACHED()
padolph
2013/10/28 20:35:07
This code is now gone.
| |
218 return CreateAlgorithm(WebCryptoAlgorithmIdNone); | |
219 } | |
220 } | |
221 | |
222 typedef std::map<std::string, int> StringIntMap; | |
223 | |
224 void InitJwkAlgorithmMap(StringIntMap& jwk_algorithm_map) | |
eroman
2013/10/22 21:49:38
Chromium style (unlike Blink style) does not like
padolph
2013/10/28 20:35:07
This code is now gone.
| |
225 { | |
226 // Note: A*CBC are not yet present in the JOSE JWA spec | |
227 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
228 jwk_algorithm_map["HS256" ] = kJwkAlgorithmHs256; | |
eroman
2013/10/22 21:49:38
style nit: remove the space padding (i personally
padolph
2013/10/28 20:35:07
Done.
| |
229 jwk_algorithm_map["HS384" ] = kJwkAlgorithmHs384; | |
230 jwk_algorithm_map["HS512" ] = kJwkAlgorithmHs512; | |
231 jwk_algorithm_map["RS256" ] = kJwkAlgorithmRs256; | |
232 jwk_algorithm_map["RS384" ] = kJwkAlgorithmRs384; | |
233 jwk_algorithm_map["RS512" ] = kJwkAlgorithmRs512; | |
234 jwk_algorithm_map["RSA1_5" ] = kJwkAlgorithmRsa1_5; | |
235 jwk_algorithm_map["RSA-OAEP"] = kJwkAlgorithmRsaOaep; | |
236 jwk_algorithm_map["A128KW" ] = kJwkAlgorithmA128Kw; | |
237 jwk_algorithm_map["A256KW" ] = kJwkAlgorithmA256Kw; | |
238 jwk_algorithm_map["A128GCM" ] = kJwkAlgorithmA128Gcm; | |
239 jwk_algorithm_map["A256GCM" ] = kJwkAlgorithmA256Gcm; | |
240 jwk_algorithm_map["A128CBC" ] = kJwkAlgorithmA128Cbc; | |
241 jwk_algorithm_map["A256CBC" ] = kJwkAlgorithmA256Cbc; | |
242 jwk_algorithm_map["A384CBC" ] = kJwkAlgorithmA384Cbc; | |
243 jwk_algorithm_map["A512CBC" ] = kJwkAlgorithmA512Cbc; | |
244 } | |
245 | |
246 // forward | |
247 bool operator!=(const WebKit::WebCryptoAlgorithm& lhs, | |
248 const WebKit::WebCryptoAlgorithm& rhs); | |
249 | |
250 // TODO(padolph) Verify this logic is sufficient to judge algorithm | |
251 // "consistency" for JWK import, and for all supported algorithms. | |
252 bool operator==(const WebKit::WebCryptoAlgorithm& lhs, | |
eroman
2013/10/22 21:49:38
Chromium style guide doesn't like operator overloa
Ryan Sleevi
2013/10/24 01:45:58
Should WebKit::WebCryptoAlgorithm have an Equals()
eroman
2013/10/24 02:35:04
It isn't obvious what equality means, so I think t
padolph
2013/10/28 20:35:07
Function name changed. But I am also very confused
| |
253 const WebKit::WebCryptoAlgorithm& rhs) { | |
254 if (lhs.id() != rhs.id()) | |
255 return false; | |
256 if (lhs.id() == WebKit::WebCryptoAlgorithmIdHmac || | |
257 lhs.id() == WebKit::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | |
258 lhs.id() == WebKit::WebCryptoAlgorithmIdRsaOaep) { | |
259 if (lhs.hmacParams()->hash() != rhs.hmacParams()->hash()) | |
260 return false; | |
261 } | |
262 return true; | |
eroman
2013/10/22 21:49:38
For the sake of future proofing, I would rather ha
padolph
2013/10/28 20:35:07
Done.
| |
263 } | |
264 | |
265 bool operator!=(const WebKit::WebCryptoAlgorithm& lhs, | |
266 const WebKit::WebCryptoAlgorithm& rhs) { | |
267 return !(lhs == rhs); | |
268 } | |
269 | |
270 } // namespace | |
271 | |
14 WebCryptoImpl::WebCryptoImpl() { | 272 WebCryptoImpl::WebCryptoImpl() { |
15 Init(); | 273 Init(); |
274 InitJwkAlgorithmMap(jwk_algorithm_map_); | |
eroman
2013/10/22 21:49:38
I would prefer lazy initialization, since JWK may
Ryan Sleevi
2013/10/24 01:45:58
Don't use a function-level static. They're forbidd
eroman
2013/10/24 02:35:04
My mistake! I got muddled with Blink style vs Chro
padolph
2013/10/28 20:35:07
LazyInstance used.
| |
16 } | 275 } |
17 | 276 |
18 void WebCryptoImpl::encrypt( | 277 void WebCryptoImpl::encrypt( |
19 const WebKit::WebCryptoAlgorithm& algorithm, | 278 const WebKit::WebCryptoAlgorithm& algorithm, |
20 const WebKit::WebCryptoKey& key, | 279 const WebKit::WebCryptoKey& key, |
21 const unsigned char* data, | 280 const unsigned char* data, |
22 unsigned data_size, | 281 unsigned data_size, |
23 WebKit::WebCryptoResult result) { | 282 WebKit::WebCryptoResult result) { |
24 WebKit::WebArrayBuffer buffer; | 283 WebKit::WebArrayBuffer buffer; |
25 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { | 284 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 WebKit::WebCryptoKeyFormat format, | 336 WebKit::WebCryptoKeyFormat format, |
78 const unsigned char* key_data, | 337 const unsigned char* key_data, |
79 unsigned key_data_size, | 338 unsigned key_data_size, |
80 const WebKit::WebCryptoAlgorithm& algorithm, | 339 const WebKit::WebCryptoAlgorithm& algorithm, |
81 bool extractable, | 340 bool extractable, |
82 WebKit::WebCryptoKeyUsageMask usage_mask, | 341 WebKit::WebCryptoKeyUsageMask usage_mask, |
83 WebKit::WebCryptoResult result) { | 342 WebKit::WebCryptoResult result) { |
84 WebKit::WebCryptoKeyType type; | 343 WebKit::WebCryptoKeyType type; |
85 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; | 344 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
86 | 345 |
87 if (!ImportKeyInternal(format, | 346 if (format == WebKit::WebCryptoKeyFormatJwk) { |
88 key_data, | 347 if (!ImportKeyJwk(key_data, |
89 key_data_size, | 348 key_data_size, |
90 algorithm, | 349 extractable, |
91 usage_mask, | 350 algorithm, |
92 &handle, | 351 usage_mask, |
93 &type)) { | 352 &handle, |
94 result.completeWithError(); | 353 &type)) { |
95 return; | 354 result.completeWithError(); |
355 } | |
356 } else { | |
357 if (!ImportKeyInternal(format, | |
358 key_data, | |
359 key_data_size, | |
360 algorithm, | |
361 usage_mask, | |
362 &handle, | |
363 &type)) { | |
364 result.completeWithError(); | |
365 } | |
96 } | 366 } |
97 | 367 |
98 WebKit::WebCryptoKey key( | 368 WebKit::WebCryptoKey key(WebKit::WebCryptoKey::create( |
99 WebKit::WebCryptoKey::create( | 369 handle.release(), type, extractable, algorithm, usage_mask)); |
100 handle.release(), type, extractable, algorithm, usage_mask)); | |
101 | 370 |
102 result.completeWithKey(key); | 371 result.completeWithKey(key); |
103 } | 372 } |
104 | 373 |
105 void WebCryptoImpl::sign( | 374 void WebCryptoImpl::sign( |
106 const WebKit::WebCryptoAlgorithm& algorithm, | 375 const WebKit::WebCryptoAlgorithm& algorithm, |
107 const WebKit::WebCryptoKey& key, | 376 const WebKit::WebCryptoKey& key, |
108 const unsigned char* data, | 377 const unsigned char* data, |
109 unsigned data_size, | 378 unsigned data_size, |
110 WebKit::WebCryptoResult result) { | 379 WebKit::WebCryptoResult result) { |
(...skipping 20 matching lines...) Expand all Loading... | |
131 signature_size, | 400 signature_size, |
132 data, | 401 data, |
133 data_size, | 402 data_size, |
134 &signature_match)) { | 403 &signature_match)) { |
135 result.completeWithError(); | 404 result.completeWithError(); |
136 } else { | 405 } else { |
137 result.completeWithBoolean(signature_match); | 406 result.completeWithBoolean(signature_match); |
138 } | 407 } |
139 } | 408 } |
140 | 409 |
410 bool WebCryptoImpl::ImportKeyJwk( | |
411 const unsigned char* key_data, | |
412 unsigned key_data_size, | |
413 bool extractable, | |
414 const WebKit::WebCryptoAlgorithm& algorithm, | |
415 WebKit::WebCryptoKeyUsageMask usage_mask, | |
416 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | |
417 WebKit::WebCryptoKeyType* type) { | |
418 | |
419 // JSON Web Key Format (JWK) | |
eroman
2013/10/22 21:49:38
This is a good comment block, thanks!
| |
420 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16 | |
421 // TODO(padolph) Not all possible values are handled by this code right now | |
422 // | |
423 // A JWK is a simple JSON dictionary with the following entries | |
424 // - "kty" (Key Type) Parameter, REQUIRED | |
425 // - <kty-specific parameters, see below>, REQUIRED | |
426 // - "use" (Key Use) Parameter, OPTIONAL | |
427 // - "alg" (Algorithm) Parameter, OPTIONAL | |
428 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE] | |
429 // (all other entries are ignored) | |
430 // | |
431 // Input key_data contains the JWK. To build a Web Crypto Key, the JWK values | |
432 // are parsed out and used as follows: | |
433 // Web Crypto Key type <-- (deduced) | |
434 // Web Crypto Key extractable <-- extractable | |
435 // Web Crypto Key algorithm <-- alg | |
436 // Web Crypto Key keyUsage <-- usage | |
437 // Web Crypto Key keying material <-- kty-specific parameters | |
438 // | |
439 // Values for each entry are case-sensitive and defined in | |
440 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. | |
441 // Note that not all values specified by JOSE are handled by this code. Only | |
442 // handled values are listed. | |
443 // - kty (Key Type) | |
444 // +-------+--------------------------------------------------------------+ | |
445 // | "RSA" | RSA [RFC3447] | | |
446 // | "oct" | Octet sequence (used to represent symmetric keys) | | |
447 // +-------+--------------------------------------------------------------+ | |
448 // - use (Key Use) | |
449 // +-------+--------------------------------------------------------------+ | |
450 // | "enc" | encrypt and decrypt operations | | |
451 // | "sig" | sign and verify (MAC) operations | | |
452 // | "wrap"| key wrap and unwrap [not yet part of JOSE] | | |
453 // +-------+--------------------------------------------------------------+ | |
454 // - extractable (Key Exportability) | |
455 // +-------+--------------------------------------------------------------+ | |
456 // | true | Key may be exported from the trusted environment | | |
457 // | false | Key cannot exit the trusted environment | | |
458 // +-------+--------------------------------------------------------------+ | |
459 // - alg (Algorithm) | |
460 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
461 // +--------------+-------------------------------------------------------+ | |
462 // | Digital Signature or MAC Algorithm | | |
463 // +--------------+-------------------------------------------------------+ | |
464 // | "HS256" | HMAC using SHA-256 hash algorithm | | |
465 // | "HS384" | HMAC using SHA-384 hash algorithm | | |
466 // | "HS512" | HMAC using SHA-512 hash algorithm | | |
467 // | "RS256" | RSASSA using SHA-256 hash algorithm | | |
468 // | "RS384" | RSASSA using SHA-384 hash algorithm | | |
469 // | "RS512" | RSASSA using SHA-512 hash algorithm | | |
470 // +--------------+-------------------------------------------------------| | |
471 // | Key Management Algorithm | | |
472 // +--------------+-------------------------------------------------------+ | |
473 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | | |
474 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | | |
475 // | | (OAEP) [RFC3447], with the default parameters | | |
476 // | | specified by RFC3447 in Section A.2.1 | | |
477 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | | |
478 // | | [RFC3394] using 128 bit keys | | |
479 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | | |
480 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | | |
481 // | | 128 bit keys | | |
482 // | "A256GCM" | AES GCM using 256 bit keys | | |
483 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | | |
484 // | | padding [NIST.800-38A] [not yet part of JOSE] | | |
485 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | | |
486 // | "A384CBC" | AES CBC using 384 bit keys [not yet part of JOSE] | | |
487 // | "A512CBC" | AES CBC using 512 bit keys [not yet part of JOSE] | | |
488 // +--------------+-------------------------------------------------------+ | |
489 // | |
490 // kty-specific parameters | |
491 // The value of kty determines the type and content of the keying material | |
492 // carried in the JWK to be imported. Currently only two possibilities are | |
493 // supported: a raw key or an RSA public key. RSA private keys are not | |
494 // supported because typical applications seldom need to import a private key, | |
495 // and the large number of JWK parameters required to describe one. | |
496 // - kty == "oct" (symmetric or other raw key) | |
497 // +-------+--------------------------------------------------------------+ | |
498 // | "k" | Contains the value of the symmetric (or other single-valued) | | |
499 // | | key. It is represented as the base64url encoding of the | | |
500 // | | octet sequence containing the key value. | | |
501 // +-------+--------------------------------------------------------------+ | |
502 // - kty == "RSA" (RSA public key) | |
503 // +-------+--------------------------------------------------------------+ | |
504 // | "n" | Contains the modulus value for the RSA public key. It is | | |
505 // | | represented as the base64url encoding of the value's | | |
506 // | | unsigned big endian representation as an octet sequence. | | |
507 // +-------+--------------------------------------------------------------+ | |
508 // | "e" | Contains the exponent value for the RSA public key. It is | | |
509 // | | represented as the base64url encoding of the value's | | |
510 // | | unsigned big endian representation as an octet sequence. | | |
511 // +-------+--------------------------------------------------------------+ | |
512 // | |
513 // Conflict resolution | |
514 // The type, algorithm, extractable, and usage_mask input parameters may be | |
515 // different from similar values inside the JWK. The Web Crypto spec says that | |
516 // if a JWK value is present, but is inconsistent with the input value, it is | |
517 // an error and the operation must fail. | |
518 | |
519 const char* const foo = reinterpret_cast<const char *>(key_data); | |
eroman
2013/10/22 21:49:38
Please use a variable name other than "foo".
padolph
2013/10/28 20:35:07
Done.
| |
520 base::StringPiece json_string(foo, key_data_size); | |
521 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
522 // Note, bare pointer dict_value is ok since it points into scoped value. | |
523 base::DictionaryValue* dict_value = NULL; | |
524 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
525 return false; | |
526 | |
527 // JWK "kty". Exit early if this required JWK parameter is missing. | |
528 std::string jwk_kty_value; | |
529 if (!dict_value->GetString("kty", &jwk_kty_value)) | |
530 return false; | |
531 | |
532 // JWK "extractable" --> extractable parameter | |
533 bool jwk_extractable_value; | |
534 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { | |
535 // collision check | |
536 if (jwk_extractable_value != extractable) | |
537 return false; | |
538 } | |
539 | |
540 // JWK "alg" --> algorithm parameter | |
541 std::string jwk_alg_value; | |
542 if (dict_value->GetString("alg", &jwk_alg_value)) { | |
543 const StringIntMap::iterator pos = jwk_algorithm_map_.find(jwk_alg_value); | |
eroman
2013/10/22 21:49:38
const_iterator?
padolph
2013/10/28 20:35:07
Done.
| |
544 if (pos == jwk_algorithm_map_.end()) | |
545 return false; | |
546 const int jwk_algorithm_id = pos->second; | |
547 WebKit::WebCryptoAlgorithm webcrypto_algorithm_from_jwk = | |
548 CreateWebCryptoAlgorithmFromJwkAlgorithmId(jwk_algorithm_id); | |
549 // collision check | |
550 if (webcrypto_algorithm_from_jwk != algorithm) | |
551 return false; | |
552 } | |
553 | |
554 // JWK "use" --> usage_mask parameter | |
555 std::string jwk_use_value; | |
556 if (dict_value->GetString("use", &jwk_use_value)) { | |
557 unsigned jwk_usage_mask; | |
558 if (jwk_use_value == "enc") { | |
559 jwk_usage_mask = | |
560 WebKit::WebCryptoKeyUsageEncrypt | WebKit::WebCryptoKeyUsageDecrypt; | |
561 } else if (jwk_use_value == "sig") { | |
562 jwk_usage_mask = | |
563 WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; | |
564 } else if (jwk_use_value == "wrap") { | |
565 jwk_usage_mask = | |
566 WebKit::WebCryptoKeyUsageWrapKey | WebKit::WebCryptoKeyUsageUnwrapKey; | |
567 } else { | |
568 return false; | |
569 } | |
570 // collision check | |
571 if (!(jwk_usage_mask & usage_mask)) | |
eroman
2013/10/22 21:49:38
Do they need to match exactly?
Ryan Sleevi
2013/10/24 01:45:58
No.
The spec merely says that if they conflict in
eroman
2013/10/24 02:35:04
Thanks Ryan!
My understanding then is that we wan
padolph
2013/10/28 20:35:07
Yea, after thinking about it more, subset makes mo
| |
572 return false; | |
573 } | |
574 | |
575 // JWK keying material --> ImportKeyInternal() | |
576 if (jwk_kty_value == "oct") { | |
577 // collision check | |
578 if (*type != WebKit::WebCryptoKeyTypeSecret) | |
579 return false; | |
580 std::string jwk_k_value_url64; | |
581 if (!dict_value->GetString("k", &jwk_k_value_url64)) | |
582 return false; | |
583 std::string jwk_k_value; | |
584 if (!Base64DecodeUrlSafe(jwk_k_value_url64, &jwk_k_value)) | |
585 return false; | |
586 const std::vector<uint8> data(jwk_k_value.begin(), jwk_k_value.end()); | |
eroman
2013/10/22 21:49:38
Rather than copying into a std::vector<>, I believ
padolph
2013/10/28 20:35:07
Done.
| |
587 if (!ImportKeyInternal(WebKit::WebCryptoKeyFormatRaw, | |
588 &data[0], | |
eroman
2013/10/22 21:49:38
Is data guaranteed to have at least 1 element?
padolph
2013/10/28 20:35:07
No. I added a check for that plus a unit test. Tha
| |
589 data.size(), | |
590 algorithm, | |
591 usage_mask, | |
592 handle, | |
593 type)) { | |
594 return false; | |
595 } | |
596 } else if (jwk_kty_value == "RSA") { | |
597 // Only an RSA public key is currently handled. | |
598 // collision check | |
599 if (*type != WebKit::WebCryptoKeyTypePublic) | |
600 return false; | |
601 // TODO(padolph): JWK import RSA public key | |
602 return false; | |
603 } else { | |
604 return false; | |
605 } | |
606 | |
607 return true; | |
608 } | |
609 | |
141 } // namespace content | 610 } // namespace content |
OLD | NEW |