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