Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: content/child/webcrypto/jwk.cc

Issue 200263002: Revert of [webcrypto] JWK: Updated import(ext, key_ops) and added export of symmetric keys (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@wcAesKw_nss1
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 <algorithm> 5 #include <algorithm>
6 #include <functional> 6 #include <functional>
7 #include <map> 7 #include <map>
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
11 #include "base/strings/stringprintf.h" 10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_piece.h"
13 #include "base/values.h"
12 #include "content/child/webcrypto/crypto_data.h" 14 #include "content/child/webcrypto/crypto_data.h"
13 #include "content/child/webcrypto/platform_crypto.h" 15 #include "content/child/webcrypto/platform_crypto.h"
14 #include "content/child/webcrypto/shared_crypto.h" 16 #include "content/child/webcrypto/shared_crypto.h"
15 #include "content/child/webcrypto/webcrypto_util.h" 17 #include "content/child/webcrypto/webcrypto_util.h"
16 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
17 18
18 namespace content { 19 namespace content {
19 20
20 namespace webcrypto { 21 namespace webcrypto {
21 22
22 namespace { 23 namespace {
23 24
24 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
25 // TODO(padolph): Add 'deriveBits' once supported by Blink.
26 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
27 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
28 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
29 blink::WebCryptoKeyUsageDeriveKey;
30 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
31 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
32 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
33
34 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); 25 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)();
35 26
36 class JwkAlgorithmInfo { 27 class JwkAlgorithmInfo {
37 public: 28 public:
38 JwkAlgorithmInfo() 29 JwkAlgorithmInfo()
39 : creation_func_(NULL), 30 : creation_func_(NULL),
40 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} 31 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {}
41 32
42 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) 33 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func)
43 : creation_func_(algorithm_creation_func), 34 : creation_func_(algorithm_creation_func),
44 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} 35 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {}
45 36
46 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func, 37 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func,
47 unsigned int required_key_length_bits) 38 unsigned int required_key_length_bits)
48 : creation_func_(algorithm_creation_func), 39 : creation_func_(algorithm_creation_func),
49 required_key_length_bytes_(required_key_length_bits / 8) { 40 required_key_length_bytes_(required_key_length_bits / 8) {
50 DCHECK_EQ(0u, required_key_length_bits % 8); 41 DCHECK((required_key_length_bits % 8) == 0);
51 } 42 }
52 43
53 bool CreateImportAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { 44 bool CreateImportAlgorithm(blink::WebCryptoAlgorithm* algorithm) const {
54 *algorithm = creation_func_(); 45 *algorithm = creation_func_();
55 return !algorithm->isNull(); 46 return !algorithm->isNull();
56 } 47 }
57 48
58 bool IsInvalidKeyByteLength(size_t byte_length) const { 49 bool IsInvalidKeyByteLength(size_t byte_length) const {
59 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) 50 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT)
60 return false; 51 return false;
(...skipping 11 matching lines...) Expand all
72 63
73 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap; 64 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap;
74 65
75 class JwkAlgorithmRegistry { 66 class JwkAlgorithmRegistry {
76 public: 67 public:
77 JwkAlgorithmRegistry() { 68 JwkAlgorithmRegistry() {
78 // TODO(eroman): 69 // TODO(eroman):
79 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20 70 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20
80 // says HMAC with SHA-2 should have a key size at least as large as the 71 // says HMAC with SHA-2 should have a key size at least as large as the
81 // hash output. 72 // hash output.
82 alg_to_info_["HS1"] =
83 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
84 blink::WebCryptoAlgorithmIdSha1>);
85 alg_to_info_["HS256"] = 73 alg_to_info_["HS256"] =
86 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, 74 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
87 blink::WebCryptoAlgorithmIdSha256>); 75 blink::WebCryptoAlgorithmIdSha256>);
88 alg_to_info_["HS384"] = 76 alg_to_info_["HS384"] =
89 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, 77 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
90 blink::WebCryptoAlgorithmIdSha384>); 78 blink::WebCryptoAlgorithmIdSha384>);
91 alg_to_info_["HS512"] = 79 alg_to_info_["HS512"] =
92 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, 80 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm,
93 blink::WebCryptoAlgorithmIdSha512>); 81 blink::WebCryptoAlgorithmIdSha512>);
94 alg_to_info_["RS256"] = 82 alg_to_info_["RS256"] =
95 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, 83 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
96 blink::WebCryptoAlgorithmIdSha256>); 84 blink::WebCryptoAlgorithmIdSha256>);
97 alg_to_info_["RS384"] = 85 alg_to_info_["RS384"] =
98 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, 86 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
99 blink::WebCryptoAlgorithmIdSha384>); 87 blink::WebCryptoAlgorithmIdSha384>);
100 alg_to_info_["RS512"] = 88 alg_to_info_["RS512"] =
101 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, 89 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm,
102 blink::WebCryptoAlgorithmIdSha512>); 90 blink::WebCryptoAlgorithmIdSha512>);
103 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo( 91 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo(
104 &BindAlgorithmId<CreateAlgorithm, 92 &BindAlgorithmId<CreateAlgorithm,
105 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>); 93 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>);
106 alg_to_info_["RSA-OAEP"] = 94 alg_to_info_["RSA-OAEP"] =
107 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm, 95 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm,
108 blink::WebCryptoAlgorithmIdSha1>); 96 blink::WebCryptoAlgorithmIdSha1>);
109 alg_to_info_["A128KW"] = JwkAlgorithmInfo( 97 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
110 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>, 98 alg_to_info_["A128KW"] =
111 128); 99 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128);
112 alg_to_info_["A192KW"] = JwkAlgorithmInfo( 100 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
113 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>, 101 alg_to_info_["A256KW"] =
114 192); 102 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256);
115 alg_to_info_["A256KW"] = JwkAlgorithmInfo(
116 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesKw>,
117 256);
118 alg_to_info_["A128GCM"] = JwkAlgorithmInfo( 103 alg_to_info_["A128GCM"] = JwkAlgorithmInfo(
119 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, 104 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
120 128); 105 128);
121 alg_to_info_["A192GCM"] = JwkAlgorithmInfo(
122 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
123 192);
124 alg_to_info_["A256GCM"] = JwkAlgorithmInfo( 106 alg_to_info_["A256GCM"] = JwkAlgorithmInfo(
125 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, 107 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>,
126 256); 108 256);
127 alg_to_info_["A128CBC"] = JwkAlgorithmInfo( 109 alg_to_info_["A128CBC"] = JwkAlgorithmInfo(
128 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, 110 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>,
129 128); 111 128);
130 alg_to_info_["A192CBC"] = JwkAlgorithmInfo( 112 alg_to_info_["A192CBC"] = JwkAlgorithmInfo(
131 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, 113 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>,
132 192); 114 192);
133 alg_to_info_["A256CBC"] = JwkAlgorithmInfo( 115 alg_to_info_["A256CBC"] = JwkAlgorithmInfo(
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 if (!dict->Get(path, &value)) 190 if (!dict->Get(path, &value))
209 return Status::Success(); 191 return Status::Success();
210 192
211 if (!value->GetAsString(result)) 193 if (!value->GetAsString(result))
212 return Status::ErrorJwkPropertyWrongType(path, "string"); 194 return Status::ErrorJwkPropertyWrongType(path, "string");
213 195
214 *property_exists = true; 196 *property_exists = true;
215 return Status::Success(); 197 return Status::Success();
216 } 198 }
217 199
218 // Extracts the optional array property with key |path| from |dict| and saves
219 // the result to |*result| if it was found. If the property exists and is not an
220 // array, returns an error. Otherwise returns success, and sets
221 // |*property_exists| if it was found. Note that |*result| is owned by |dict|.
222 Status GetOptionalJwkList(base::DictionaryValue* dict,
223 const std::string& path,
224 base::ListValue** result,
225 bool* property_exists) {
226 *property_exists = false;
227 base::Value* value = NULL;
228 if (!dict->Get(path, &value))
229 return Status::Success();
230
231 if (!value->GetAsList(result))
232 return Status::ErrorJwkPropertyWrongType(path, "list");
233
234 *property_exists = true;
235 return Status::Success();
236 }
237
238 // Extracts the required string property with key |path| from |dict| and saves 200 // Extracts the required string property with key |path| from |dict| and saves
239 // the base64url-decoded bytes to |*result|. If the property does not exist or 201 // the base64-decoded bytes to |*result|. If the property does not exist or is
240 // is not a string, or could not be base64url-decoded, returns an error. 202 // not a string, or could not be base64-decoded, returns an error.
241 Status GetJwkBytes(base::DictionaryValue* dict, 203 Status GetJwkBytes(base::DictionaryValue* dict,
242 const std::string& path, 204 const std::string& path,
243 std::string* result) { 205 std::string* result) {
244 std::string base64_string; 206 std::string base64_string;
245 Status status = GetJwkString(dict, path, &base64_string); 207 Status status = GetJwkString(dict, path, &base64_string);
246 if (status.IsError()) 208 if (status.IsError())
247 return status; 209 return status;
248 210
249 if (!Base64DecodeUrlSafe(base64_string, result)) 211 if (!Base64DecodeUrlSafe(base64_string, result))
250 return Status::ErrorJwkBase64Decode(path); 212 return Status::ErrorJwkBase64Decode(path);
(...skipping 14 matching lines...) Expand all
265 if (!dict->Get(path, &value)) 227 if (!dict->Get(path, &value))
266 return Status::Success(); 228 return Status::Success();
267 229
268 if (!value->GetAsBoolean(result)) 230 if (!value->GetAsBoolean(result))
269 return Status::ErrorJwkPropertyWrongType(path, "boolean"); 231 return Status::ErrorJwkPropertyWrongType(path, "boolean");
270 232
271 *property_exists = true; 233 *property_exists = true;
272 return Status::Success(); 234 return Status::Success();
273 } 235 }
274 236
275 // Returns true if the set bits in b make up a subset of the set bits in a.
276 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
277 blink::WebCryptoKeyUsageMask b) {
278 return (a & b) == b;
279 }
280
281 // Writes a secret/symmetric key to a JWK dictionary.
282 void WriteSecretKey(const blink::WebArrayBuffer& raw_key,
283 base::DictionaryValue* jwk_dict) {
284 DCHECK(jwk_dict);
285 jwk_dict->SetString("kty", "oct");
286 // For a secret/symmetric key, the only extra JWK field is 'k', containing the
287 // base64url encoding of the raw key.
288 DCHECK(!raw_key.isNull());
289 DCHECK(raw_key.data());
290 DCHECK(raw_key.byteLength());
291 unsigned int key_length_bytes = raw_key.byteLength();
292 const base::StringPiece key_str(static_cast<const char*>(raw_key.data()),
293 key_length_bytes);
294 jwk_dict->SetString("k", Base64EncodeUrlSafe(key_str));
295 }
296
297 // Writes a Web Crypto usage mask to a JWK dictionary.
298 void WriteKeyOps(blink::WebCryptoKeyUsageMask key_usages,
299 base::DictionaryValue* jwk_dict) {
300 jwk_dict->Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(key_usages));
301 }
302
303 // Writes a Web Crypto extractable value to a JWK dictionary.
304 void WriteExt(bool extractable, base::DictionaryValue* jwk_dict) {
305 jwk_dict->SetBoolean("ext", extractable);
306 }
307
308 // Writes a Web Crypto algorithm to a JWK dictionary.
309 Status WriteAlg(const blink::WebCryptoKeyAlgorithm& algorithm,
310 unsigned int raw_key_length_bytes,
311 base::DictionaryValue* jwk_dict) {
312 switch (algorithm.paramsType()) {
313 case blink::WebCryptoKeyAlgorithmParamsTypeAes: {
314 const char* aes_prefix = "";
315 switch (raw_key_length_bytes) {
316 case 16:
317 aes_prefix = "A128";
318 break;
319 case 24:
320 aes_prefix = "A192";
321 break;
322 case 32:
323 aes_prefix = "A256";
324 break;
325 default:
326 NOTREACHED(); // bad key length means algorithm was built improperly
327 return Status::ErrorUnexpected();
328 }
329 const char* aes_suffix = "";
330 switch (algorithm.id()) {
331 case blink::WebCryptoAlgorithmIdAesCbc:
332 aes_suffix = "CBC";
333 break;
334 case blink::WebCryptoAlgorithmIdAesCtr:
335 aes_suffix = "CTR";
336 break;
337 case blink::WebCryptoAlgorithmIdAesGcm:
338 aes_suffix = "GCM";
339 break;
340 case blink::WebCryptoAlgorithmIdAesKw:
341 aes_suffix = "KW";
342 break;
343 default:
344 return Status::ErrorUnsupported();
345 }
346 jwk_dict->SetString("alg",
347 base::StringPrintf("%s%s", aes_prefix, aes_suffix));
348 break;
349 }
350 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: {
351 DCHECK(algorithm.hmacParams());
352 switch (algorithm.hmacParams()->hash().id()) {
353 case blink::WebCryptoAlgorithmIdSha1:
354 jwk_dict->SetString("alg", "HS1");
355 break;
356 case blink::WebCryptoAlgorithmIdSha224:
357 jwk_dict->SetString("alg", "HS224");
358 break;
359 case blink::WebCryptoAlgorithmIdSha256:
360 jwk_dict->SetString("alg", "HS256");
361 break;
362 case blink::WebCryptoAlgorithmIdSha384:
363 jwk_dict->SetString("alg", "HS384");
364 break;
365 case blink::WebCryptoAlgorithmIdSha512:
366 jwk_dict->SetString("alg", "HS512");
367 break;
368 default:
369 NOTREACHED();
370 return Status::ErrorUnexpected();
371 }
372 break;
373 }
374 case blink::WebCryptoKeyAlgorithmParamsTypeRsa:
375 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
376 // TODO(padolph): Handle RSA key
377 return Status::ErrorUnsupported();
378 default:
379 return Status::ErrorUnsupported();
380 }
381 return Status::Success();
382 }
383
384 } // namespace 237 } // namespace
385 238
386 Status ImportKeyJwk(const CryptoData& key_data, 239 Status ImportKeyJwk(const CryptoData& key_data,
387 const blink::WebCryptoAlgorithm& algorithm_or_null, 240 const blink::WebCryptoAlgorithm& algorithm_or_null,
388 bool extractable, 241 bool extractable,
389 blink::WebCryptoKeyUsageMask usage_mask, 242 blink::WebCryptoKeyUsageMask usage_mask,
390 blink::WebCryptoKey* key) { 243 blink::WebCryptoKey* key) {
391 // TODO(padolph): Generalize this comment to include export, and move to top
392 // of file.
393 244
394 // The goal of this method is to extract key material and meta data from the 245 // The goal of this method is to extract key material and meta data from the
395 // incoming JWK, combine them with the input parameters, and ultimately import 246 // incoming JWK, combine them with the input parameters, and ultimately import
396 // a Web Crypto Key. 247 // a Web Crypto Key.
397 // 248 //
398 // JSON Web Key Format (JWK) 249 // JSON Web Key Format (JWK)
399 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21 250 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
251 // TODO(padolph): Not all possible values are handled by this code right now
400 // 252 //
401 // A JWK is a simple JSON dictionary with the following entries 253 // A JWK is a simple JSON dictionary with the following entries
402 // - "kty" (Key Type) Parameter, REQUIRED 254 // - "kty" (Key Type) Parameter, REQUIRED
403 // - <kty-specific parameters, see below>, REQUIRED 255 // - <kty-specific parameters, see below>, REQUIRED
404 // - "use" (Key Use) Parameter, OPTIONAL 256 // - "use" (Key Use) Parameter, OPTIONAL
405 // - "key_ops" (Key Operations) Parameter, OPTIONAL
406 // - "alg" (Algorithm) Parameter, OPTIONAL 257 // - "alg" (Algorithm) Parameter, OPTIONAL
407 // - "ext" (Key Exportability), OPTIONAL 258 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
259 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
408 // (all other entries are ignored) 260 // (all other entries are ignored)
409 // 261 //
410 // OPTIONAL here means that this code does not require the entry to be present 262 // OPTIONAL here means that this code does not require the entry to be present
411 // in the incoming JWK, because the method input parameters contain similar 263 // in the incoming JWK, because the method input parameters contain similar
412 // information. If the optional JWK entry is present, it will be validated 264 // information. If the optional JWK entry is present, it will be validated
413 // against the corresponding input parameter for consistency and combined with 265 // against the corresponding input parameter for consistency and combined with
414 // it according to rules defined below. A special case is that the method 266 // it according to rules defined below. A special case is that the method
415 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg' 267 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
416 // value (if present) is used as a fallback. 268 // value (if present) is used as a fallback.
417 // 269 //
418 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK 270 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
419 // values are parsed out and combined with the method input parameters to 271 // values are parsed out and combined with the method input parameters to
420 // build a Web Crypto Key: 272 // build a Web Crypto Key:
421 // Web Crypto Key type <-- (deduced) 273 // Web Crypto Key type <-- (deduced)
422 // Web Crypto Key extractable <-- JWK ext + input extractable 274 // Web Crypto Key extractable <-- JWK extractable + input extractable
423 // Web Crypto Key algorithm <-- JWK alg + input algorithm 275 // Web Crypto Key algorithm <-- JWK alg + input algorithm
424 // Web Crypto Key keyUsage <-- JWK use, key_ops + input usage_mask 276 // Web Crypto Key keyUsage <-- JWK use + input usage_mask
425 // Web Crypto Key keying material <-- kty-specific parameters 277 // Web Crypto Key keying material <-- kty-specific parameters
426 // 278 //
427 // Values for each JWK entry are case-sensitive and defined in 279 // Values for each JWK entry are case-sensitive and defined in
428 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18. 280 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
429 // Note that not all values specified by JOSE are handled by this code. Only 281 // Note that not all values specified by JOSE are handled by this code. Only
430 // handled values are listed. 282 // handled values are listed.
431 // - kty (Key Type) 283 // - kty (Key Type)
432 // +-------+--------------------------------------------------------------+ 284 // +-------+--------------------------------------------------------------+
433 // | "RSA" | RSA [RFC3447] | 285 // | "RSA" | RSA [RFC3447] |
434 // | "oct" | Octet sequence (used to represent symmetric keys) | 286 // | "oct" | Octet sequence (used to represent symmetric keys) |
435 // +-------+--------------------------------------------------------------+ 287 // +-------+--------------------------------------------------------------+
436 // 288 // - use (Key Use)
437 // - key_ops (Key Use Details)
438 // The key_ops field is an array that contains one or more strings from
439 // the table below, and describes the operations for which this key may be
440 // used.
441 // +-------+--------------------------------------------------------------+ 289 // +-------+--------------------------------------------------------------+
442 // | "encrypt" | encrypt operations | 290 // | "enc" | encrypt and decrypt operations |
443 // | "decrypt" | decrypt operations | 291 // | "sig" | sign and verify (MAC) operations |
444 // | "sign" | sign (MAC) operations | 292 // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
445 // | "verify" | verify (MAC) operations |
446 // | "wrapKey" | key wrap |
447 // | "unwrapKey" | key unwrap |
448 // | "deriveKey" | key derivation |
449 // | "deriveBits" | key derivation TODO(padolph): not currently supported |
450 // +-------+--------------------------------------------------------------+ 293 // +-------+--------------------------------------------------------------+
451 // 294 // - extractable (Key Exportability)
452 // - use (Key Use)
453 // The use field contains a single entry from the table below.
454 // +-------+--------------------------------------------------------------+
455 // | "sig" | equivalent to key_ops of [sign, verify] |
456 // | "enc" | equivalent to key_ops of [encrypt, decrypt, wrapKey, |
457 // | | unwrapKey, deriveKey, deriveBits] |
458 // +-------+--------------------------------------------------------------+
459 //
460 // NOTE: If both "use" and "key_ops" JWK members are present, the usages
461 // specified by them MUST be consistent. In particular, the "use" value
462 // "sig" corresponds to "sign" and/or "verify". The "use" value "enc"
463 // corresponds to all other values defined above. If "key_ops" values
464 // corresponding to both "sig" and "enc" "use" values are present, the "use"
465 // member SHOULD NOT be present, and if present, its value MUST NOT be
466 // either "sig" or "enc".
467 //
468 // - ext (Key Exportability)
469 // +-------+--------------------------------------------------------------+ 295 // +-------+--------------------------------------------------------------+
470 // | true | Key may be exported from the trusted environment | 296 // | true | Key may be exported from the trusted environment |
471 // | false | Key cannot exit the trusted environment | 297 // | false | Key cannot exit the trusted environment |
472 // +-------+--------------------------------------------------------------+ 298 // +-------+--------------------------------------------------------------+
473 //
474 // - alg (Algorithm) 299 // - alg (Algorithm)
475 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18 300 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
476 // +--------------+-------------------------------------------------------+ 301 // +--------------+-------------------------------------------------------+
477 // | Digital Signature or MAC Algorithm | 302 // | Digital Signature or MAC Algorithm |
478 // +--------------+-------------------------------------------------------+ 303 // +--------------+-------------------------------------------------------+
479 // | "HS1" | HMAC using SHA-1 hash algorithm |
480 // | "HS256" | HMAC using SHA-256 hash algorithm | 304 // | "HS256" | HMAC using SHA-256 hash algorithm |
481 // | "HS384" | HMAC using SHA-384 hash algorithm | 305 // | "HS384" | HMAC using SHA-384 hash algorithm |
482 // | "HS512" | HMAC using SHA-512 hash algorithm | 306 // | "HS512" | HMAC using SHA-512 hash algorithm |
483 // | "RS256" | RSASSA using SHA-256 hash algorithm | 307 // | "RS256" | RSASSA using SHA-256 hash algorithm |
484 // | "RS384" | RSASSA using SHA-384 hash algorithm | 308 // | "RS384" | RSASSA using SHA-384 hash algorithm |
485 // | "RS512" | RSASSA using SHA-512 hash algorithm | 309 // | "RS512" | RSASSA using SHA-512 hash algorithm |
486 // +--------------+-------------------------------------------------------| 310 // +--------------+-------------------------------------------------------|
487 // | Key Management Algorithm | 311 // | Key Management Algorithm |
488 // +--------------+-------------------------------------------------------+ 312 // +--------------+-------------------------------------------------------+
489 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | 313 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
490 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | 314 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
491 // | | (OAEP) [RFC3447], with the default parameters | 315 // | | (OAEP) [RFC3447], with the default parameters |
492 // | | specified by RFC3447 in Section A.2.1 | 316 // | | specified by RFC3447 in Section A.2.1 |
493 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | 317 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
494 // | | [RFC3394] using 128 bit keys | 318 // | | [RFC3394] using 128 bit keys |
495 // | "A192KW" | AES Key Wrap Algorithm using 192 bit keys |
496 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | 319 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
497 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | 320 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
498 // | | 128 bit keys | 321 // | | 128 bit keys |
499 // | "A192GCM" | AES GCM using 192 bit keys |
500 // | "A256GCM" | AES GCM using 256 bit keys | 322 // | "A256GCM" | AES GCM using 256 bit keys |
501 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | 323 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
502 // | | padding [NIST.800-38A] | 324 // | | padding [NIST.800-38A] [not yet part of JOSE, see |
503 // | "A192CBC" | AES CBC using 192 bit keys | 325 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
504 // | "A256CBC" | AES CBC using 256 bit keys | 326 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
327 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
505 // +--------------+-------------------------------------------------------+ 328 // +--------------+-------------------------------------------------------+
506 // 329 //
507 // kty-specific parameters 330 // kty-specific parameters
508 // The value of kty determines the type and content of the keying material 331 // The value of kty determines the type and content of the keying material
509 // carried in the JWK to be imported. Currently only two possibilities are 332 // carried in the JWK to be imported. Currently only two possibilities are
510 // supported: a raw key or an RSA public key. RSA private keys are not 333 // supported: a raw key or an RSA public key. RSA private keys are not
511 // supported because typical applications seldom need to import a private key, 334 // supported because typical applications seldom need to import a private key,
512 // and the large number of JWK parameters required to describe one. 335 // and the large number of JWK parameters required to describe one.
513 // - kty == "oct" (symmetric or other raw key) 336 // - kty == "oct" (symmetric or other raw key)
514 // +-------+--------------------------------------------------------------+ 337 // +-------+--------------------------------------------------------------+
(...skipping 21 matching lines...) Expand all
536 // 359 //
537 // algorithm 360 // algorithm
538 // If an algorithm is provided by both the input parameter and the JWK, 361 // If an algorithm is provided by both the input parameter and the JWK,
539 // consistency between the two is based only on algorithm ID's (including an 362 // consistency between the two is based only on algorithm ID's (including an
540 // inner hash algorithm if present). In this case if the consistency 363 // inner hash algorithm if present). In this case if the consistency
541 // check is passed, the input algorithm is used. If only one of either the 364 // check is passed, the input algorithm is used. If only one of either the
542 // input algorithm and JWK alg is provided, it is used as the final 365 // input algorithm and JWK alg is provided, it is used as the final
543 // algorithm. 366 // algorithm.
544 // 367 //
545 // extractable 368 // extractable
546 // If the JWK ext field is true but the input parameter is false, make the 369 // If the JWK extractable is true but the input parameter is false, make the
547 // Web Crypto Key non-extractable. Conversely, if the JWK ext field is 370 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
548 // false but the input parameter is true, it is an inconsistency. If both 371 // false but the input parameter is true, it is an inconsistency. If both
549 // are true or both are false, use that value. 372 // are true or both are false, use that value.
550 // 373 //
551 // usage_mask 374 // usage_mask
552 // The input usage_mask must be a strict subset of the interpreted JWK use 375 // The input usage_mask must be a strict subset of the interpreted JWK use
553 // value, else it is judged inconsistent. In all cases the input usage_mask 376 // value, else it is judged inconsistent. In all cases the input usage_mask
554 // is used as the final usage_mask. 377 // is used as the final usage_mask.
555 // 378 //
556 379
557 if (!key_data.byte_length()) 380 if (!key_data.byte_length())
558 return Status::ErrorImportEmptyKeyData(); 381 return Status::ErrorImportEmptyKeyData();
559 DCHECK(key); 382 DCHECK(key);
560 383
561 // Parse the incoming JWK JSON. 384 // Parse the incoming JWK JSON.
562 base::StringPiece json_string(reinterpret_cast<const char*>(key_data.bytes()), 385 base::StringPiece json_string(reinterpret_cast<const char*>(key_data.bytes()),
563 key_data.byte_length()); 386 key_data.byte_length());
564 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); 387 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
565 // Note, bare pointer dict_value is ok since it points into scoped value. 388 // Note, bare pointer dict_value is ok since it points into scoped value.
566 base::DictionaryValue* dict_value = NULL; 389 base::DictionaryValue* dict_value = NULL;
567 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) 390 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
568 return Status::ErrorJwkNotDictionary(); 391 return Status::ErrorJwkNotDictionary();
569 392
570 // JWK "kty". Exit early if this required JWK parameter is missing. 393 // JWK "kty". Exit early if this required JWK parameter is missing.
571 std::string jwk_kty_value; 394 std::string jwk_kty_value;
572 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value); 395 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value);
573 if (status.IsError()) 396 if (status.IsError())
574 return status; 397 return status;
575 398
576 // JWK "ext" (optional) --> extractable parameter 399 // JWK "extractable" (optional) --> extractable parameter
577 { 400 {
578 bool jwk_ext_value = false; 401 bool jwk_extractable_value = false;
579 bool has_jwk_ext; 402 bool has_jwk_extractable;
580 status = 403 status = GetOptionalJwkBool(dict_value,
581 GetOptionalJwkBool(dict_value, "ext", &jwk_ext_value, &has_jwk_ext); 404 "extractable",
405 &jwk_extractable_value,
406 &has_jwk_extractable);
582 if (status.IsError()) 407 if (status.IsError())
583 return status; 408 return status;
584 if (has_jwk_ext && !jwk_ext_value && extractable) 409 if (has_jwk_extractable && !jwk_extractable_value && extractable)
585 return Status::ErrorJwkExtInconsistent(); 410 return Status::ErrorJwkExtractableInconsistent();
586 } 411 }
587 412
588 // JWK "alg" (optional) --> algorithm parameter 413 // JWK "alg" (optional) --> algorithm parameter
589 // Note: input algorithm is also optional, so we have six cases to handle. 414 // Note: input algorithm is also optional, so we have six cases to handle.
590 // 1. JWK alg present but unrecognized: error 415 // 1. JWK alg present but unrecognized: error
591 // 2. JWK alg valid AND input algorithm isNull: use JWK value 416 // 2. JWK alg valid AND input algorithm isNull: use JWK value
592 // 3. JWK alg valid AND input algorithm specified, but JWK value 417 // 3. JWK alg valid AND input algorithm specified, but JWK value
593 // inconsistent with input: error 418 // inconsistent with input: error
594 // 4. JWK alg valid AND input algorithm specified, both consistent: use 419 // 4. JWK alg valid AND input algorithm specified, both consistent: use
595 // input value (because it has potentially more details) 420 // input value (because it has potentially more details)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
628 algorithm = algorithm_or_null; // case 4 453 algorithm = algorithm_or_null; // case 4
629 } 454 }
630 } else { 455 } else {
631 // JWK alg missing 456 // JWK alg missing
632 if (algorithm_or_null.isNull()) 457 if (algorithm_or_null.isNull())
633 return Status::ErrorJwkAlgorithmMissing(); // case 5 458 return Status::ErrorJwkAlgorithmMissing(); // case 5
634 algorithm = algorithm_or_null; // case 6 459 algorithm = algorithm_or_null; // case 6
635 } 460 }
636 DCHECK(!algorithm.isNull()); 461 DCHECK(!algorithm.isNull());
637 462
638 // JWK "key_ops" (optional) --> usage_mask parameter
639 base::ListValue* jwk_key_ops_value = NULL;
640 bool has_jwk_key_ops;
641 status = GetOptionalJwkList(
642 dict_value, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
643 if (status.IsError())
644 return status;
645 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
646 if (has_jwk_key_ops) {
647 status =
648 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
649 if (status.IsError())
650 return status;
651 // The input usage_mask must be a subset of jwk_key_ops_mask.
652 if (!ContainsKeyUsages(jwk_key_ops_mask, usage_mask))
653 return Status::ErrorJwkKeyopsInconsistent();
654 }
655
656 // JWK "use" (optional) --> usage_mask parameter 463 // JWK "use" (optional) --> usage_mask parameter
657 std::string jwk_use_value; 464 std::string jwk_use_value;
658 bool has_jwk_use; 465 bool has_jwk_use;
659 status = 466 status =
660 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use); 467 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use);
661 if (status.IsError()) 468 if (status.IsError())
662 return status; 469 return status;
663 blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
664 if (has_jwk_use) { 470 if (has_jwk_use) {
665 if (jwk_use_value == "enc") 471 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
666 jwk_use_mask = kJwkEncUsage; 472 if (jwk_use_value == "enc") {
667 else if (jwk_use_value == "sig") 473 jwk_usage_mask =
668 jwk_use_mask = kJwkSigUsage; 474 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
669 else 475 } else if (jwk_use_value == "sig") {
670 return Status::ErrorJwkUnrecognizedUse(); 476 jwk_usage_mask =
671 // The input usage_mask must be a subset of jwk_use_mask. 477 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
672 if (!ContainsKeyUsages(jwk_use_mask, usage_mask)) 478 } else if (jwk_use_value == "wrap") {
673 return Status::ErrorJwkUseInconsistent(); 479 jwk_usage_mask =
480 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
481 } else {
482 return Status::ErrorJwkUnrecognizedUsage();
483 }
484 if ((jwk_usage_mask & usage_mask) != usage_mask) {
485 // A usage_mask must be a subset of jwk_usage_mask.
486 return Status::ErrorJwkUsageInconsistent();
487 }
674 } 488 }
675 489
676 // If both 'key_ops' and 'use' are present, ensure they are consistent.
677 if (has_jwk_key_ops && has_jwk_use &&
678 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
679 return Status::ErrorJwkUseAndKeyopsInconsistent();
680
681 // JWK keying material --> ImportKeyInternal() 490 // JWK keying material --> ImportKeyInternal()
682 if (jwk_kty_value == "oct") { 491 if (jwk_kty_value == "oct") {
492
683 std::string jwk_k_value; 493 std::string jwk_k_value;
684 status = GetJwkBytes(dict_value, "k", &jwk_k_value); 494 status = GetJwkBytes(dict_value, "k", &jwk_k_value);
685 if (status.IsError()) 495 if (status.IsError())
686 return status; 496 return status;
687 497
688 // Some JWK alg ID's embed information about the key length in the alg ID 498 // Some JWK alg ID's embed information about the key length in the alg ID
689 // string. For example "A128CBC" implies the JWK carries 128 bits 499 // string. For example "A128CBC" implies the JWK carries 128 bits
690 // of key material. For such keys validate that enough bytes were provided. 500 // of key material. For such keys validate that enough bytes were provided.
691 // If this validation is not done, then it would be possible to select a 501 // If this validation is not done, then it would be possible to select a
692 // different algorithm by passing a different lengthed key, since that is 502 // different algorithm by passing a different lengthed key, since that is
693 // how WebCrypto interprets things. 503 // how WebCrypto interprets things.
694 if (algorithm_info && 504 if (algorithm_info &&
695 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { 505 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) {
696 return Status::ErrorJwkIncorrectKeyLength(); 506 return Status::ErrorJwkIncorrectKeyLength();
697 } 507 }
698 508
699 return ImportKey(blink::WebCryptoKeyFormatRaw, 509 return ImportKey(blink::WebCryptoKeyFormatRaw,
700 CryptoData(jwk_k_value), 510 CryptoData(jwk_k_value),
701 algorithm, 511 algorithm,
702 extractable, 512 extractable,
703 usage_mask, 513 usage_mask,
704 key); 514 key);
705 } else if (jwk_kty_value == "RSA") { 515 } else if (jwk_kty_value == "RSA") {
516
706 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry 517 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
707 // in the JWK, while an RSA private key must have those, plus at least a "d" 518 // in the JWK, while an RSA private key must have those, plus at least a "d"
708 // (private exponent) entry. 519 // (private exponent) entry.
709 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, 520 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
710 // section 6.3. 521 // section 6.3.
711 522
712 // RSA private key import is not currently supported, so fail here if a "d" 523 // RSA private key import is not currently supported, so fail here if a "d"
713 // entry is found. 524 // entry is found.
714 // TODO(padolph): Support RSA private key import. 525 // TODO(padolph): Support RSA private key import.
715 if (dict_value->HasKey("d")) 526 if (dict_value->HasKey("d"))
(...skipping 15 matching lines...) Expand all
731 CryptoData(jwk_e_value), 542 CryptoData(jwk_e_value),
732 key); 543 key);
733 544
734 } else { 545 } else {
735 return Status::ErrorJwkUnrecognizedKty(); 546 return Status::ErrorJwkUnrecognizedKty();
736 } 547 }
737 548
738 return Status::Success(); 549 return Status::Success();
739 } 550 }
740 551
741 Status ExportKeyJwk(const blink::WebCryptoKey& key,
742 blink::WebArrayBuffer* buffer) {
743 base::DictionaryValue jwk_dict;
744 Status status = Status::Error();
745 blink::WebArrayBuffer exported_key;
746
747 if (key.type() == blink::WebCryptoKeyTypeSecret) {
748 status = ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key);
749 if (status.IsError())
750 return status;
751 WriteSecretKey(exported_key, &jwk_dict);
752 } else {
753 // TODO(padolph): Handle asymmetric keys, at least the public key.
754 return Status::ErrorUnsupported();
755 }
756
757 WriteKeyOps(key.usages(), &jwk_dict);
758 WriteExt(key.extractable(), &jwk_dict);
759 status = WriteAlg(key.algorithm(), exported_key.byteLength(), &jwk_dict);
760 if (status.IsError())
761 return status;
762
763 std::string json;
764 base::JSONWriter::Write(&jwk_dict, &json);
765 *buffer = CreateArrayBuffer(reinterpret_cast<const uint8*>(json.data()),
766 json.size());
767 return Status::Success();
768 }
769
770 } // namespace webcrypto 552 } // namespace webcrypto
771 553
772 } // namespace content 554 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/child/webcrypto/shared_crypto.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698