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

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

Issue 379383002: Refactor WebCrypto code (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase onto master Created 6 years, 5 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 | Annotate | Revision Log
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 "content/child/webcrypto/shared_crypto.h" 5 #include "content/child/webcrypto/algorithm_dispatch.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "content/child/webcrypto/algorithm.h"
9 #include "content/child/webcrypto/algorithm_registry.h"
8 #include "content/child/webcrypto/crypto_data.h" 10 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/jwk.h"
10 #include "content/child/webcrypto/platform_crypto.h" 11 #include "content/child/webcrypto/platform_crypto.h"
11 #include "content/child/webcrypto/status.h" 12 #include "content/child/webcrypto/status.h"
12 #include "content/child/webcrypto/webcrypto_util.h" 13 #include "content/child/webcrypto/webcrypto_util.h"
13 #include "crypto/secure_util.h"
14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
16 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
17 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
18 15
19 namespace content { 16 namespace content {
20 17
21 namespace webcrypto { 18 namespace webcrypto {
22 19
23 // ------------
24 // Threading:
25 // ------------
26 //
27 // All functions in this file are called from the webcrypto worker pool except
28 // for:
29 //
30 // * SerializeKeyForClone()
31 // * DeserializeKeyForClone()
32 // * ImportKey() // TODO(eroman): Change this.
33
34 namespace { 20 namespace {
35 21
36 // TODO(eroman): Move this helper to WebCryptoKey.
37 bool KeyUsageAllows(const blink::WebCryptoKey& key,
38 const blink::WebCryptoKeyUsage usage) {
39 return ((key.usages() & usage) != 0);
40 }
41
42 bool IsValidAesKeyLengthBits(unsigned int length_bits) {
43 // 192-bit AES is disallowed.
44 return length_bits == 128 || length_bits == 256;
45 }
46
47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
48 // 192-bit AES is disallowed.
49 return length_bytes == 16 || length_bytes == 32;
50 }
51
52 const size_t kAesBlockSizeBytes = 16;
53
54 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
55 const blink::WebCryptoAlgorithm& algorithm,
56 const blink::WebCryptoKey& key,
57 const CryptoData& data,
58 std::vector<uint8>* buffer) {
59 platform::SymKey* sym_key;
60 Status status = ToPlatformSymKey(key, &sym_key);
61 if (status.IsError())
62 return status;
63
64 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
65 if (!params)
66 return Status::ErrorUnexpected();
67
68 CryptoData iv(params->iv().data(), params->iv().size());
69 if (iv.byte_length() != kAesBlockSizeBytes)
70 return Status::ErrorIncorrectSizeAesCbcIv();
71
72 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer);
73 }
74
75 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
76 const blink::WebCryptoAlgorithm& algorithm,
77 const blink::WebCryptoKey& key,
78 const CryptoData& data,
79 std::vector<uint8>* buffer) {
80 platform::SymKey* sym_key;
81 Status status = ToPlatformSymKey(key, &sym_key);
82 if (status.IsError())
83 return status;
84
85 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
86 if (!params)
87 return Status::ErrorUnexpected();
88
89 unsigned int tag_length_bits = 128;
90 if (params->hasTagLengthBits())
91 tag_length_bits = params->optionalTagLengthBits();
92
93 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 &&
94 tag_length_bits != 104 && tag_length_bits != 112 &&
95 tag_length_bits != 120 && tag_length_bits != 128)
96 return Status::ErrorInvalidAesGcmTagLength();
97
98 return platform::EncryptDecryptAesGcm(
99 mode,
100 sym_key,
101 data,
102 CryptoData(params->iv()),
103 CryptoData(params->optionalAdditionalData()),
104 tag_length_bits,
105 buffer);
106 }
107
108 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
109 const blink::WebCryptoKey& key,
110 const CryptoData& data,
111 std::vector<uint8>* buffer) {
112 platform::PublicKey* public_key;
113 Status status = ToPlatformPublicKey(key, &public_key);
114 if (status.IsError())
115 return status;
116
117 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
118 if (!params)
119 return Status::ErrorUnexpected();
120
121 return platform::EncryptRsaOaep(public_key,
122 key.algorithm().rsaHashedParams()->hash(),
123 CryptoData(params->optionalLabel()),
124 data,
125 buffer);
126 }
127
128 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
129 const blink::WebCryptoKey& key,
130 const CryptoData& data,
131 std::vector<uint8>* buffer) {
132 platform::PrivateKey* private_key;
133 Status status = ToPlatformPrivateKey(key, &private_key);
134 if (status.IsError())
135 return status;
136
137 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
138 if (!params)
139 return Status::ErrorUnexpected();
140
141 return platform::DecryptRsaOaep(private_key,
142 key.algorithm().rsaHashedParams()->hash(),
143 CryptoData(params->optionalLabel()),
144 data,
145 buffer);
146 }
147
148 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm,
149 const blink::WebCryptoKey& key,
150 const CryptoData& data,
151 std::vector<uint8>* buffer) {
152 platform::SymKey* sym_key;
153 Status status = ToPlatformSymKey(key, &sym_key);
154 if (status.IsError())
155 return status;
156
157 return platform::SignHmac(
158 sym_key, key.algorithm().hmacParams()->hash(), data, buffer);
159 }
160
161 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm,
162 const blink::WebCryptoKey& key,
163 const CryptoData& signature,
164 const CryptoData& data,
165 bool* signature_match) {
166 std::vector<uint8> result;
167 Status status = SignHmac(algorithm, key, data, &result);
168 if (status.IsError())
169 return status;
170
171 // Do not allow verification of truncated MACs.
172 *signature_match =
173 result.size() == signature.byte_length() &&
174 crypto::SecureMemEqual(
175 Uint8VectorStart(result), signature.bytes(), signature.byte_length());
176
177 return Status::Success();
178 }
179
180 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
181 const blink::WebCryptoKey& key,
182 const CryptoData& data,
183 std::vector<uint8>* buffer) {
184 platform::PrivateKey* private_key;
185 Status status = ToPlatformPrivateKey(key, &private_key);
186 if (status.IsError())
187 return status;
188
189 return platform::SignRsaSsaPkcs1v1_5(
190 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer);
191 }
192
193 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
194 const blink::WebCryptoKey& key,
195 const CryptoData& signature,
196 const CryptoData& data,
197 bool* signature_match) {
198 platform::PublicKey* public_key;
199 Status status = ToPlatformPublicKey(key, &public_key);
200 if (status.IsError())
201 return status;
202
203 return platform::VerifyRsaSsaPkcs1v1_5(
204 public_key,
205 key.algorithm().rsaHashedParams()->hash(),
206 signature,
207 data,
208 signature_match);
209 }
210
211 // Note that this function may be called from the target Blink thread.
212 Status ImportKeyRaw(const CryptoData& key_data,
213 const blink::WebCryptoAlgorithm& algorithm,
214 bool extractable,
215 blink::WebCryptoKeyUsageMask usage_mask,
216 blink::WebCryptoKey* key) {
217 switch (algorithm.id()) {
218 case blink::WebCryptoAlgorithmIdAesCtr:
219 case blink::WebCryptoAlgorithmIdAesCbc:
220 case blink::WebCryptoAlgorithmIdAesGcm:
221 case blink::WebCryptoAlgorithmIdAesKw:
222 if (!IsValidAesKeyLengthBytes(key_data.byte_length())) {
223 return key_data.byte_length() == 24
224 ? Status::ErrorAes192BitUnsupported()
225 : Status::ErrorImportAesKeyLength();
226 }
227 // Fallthrough intentional!
228 case blink::WebCryptoAlgorithmIdHmac:
229 return platform::ImportKeyRaw(
230 algorithm, key_data, extractable, usage_mask, key);
231 default:
232 return Status::ErrorUnsupported();
233 }
234 }
235
236 // Returns the key format to use for structured cloning.
237 blink::WebCryptoKeyFormat GetCloneFormatForKeyType(
238 blink::WebCryptoKeyType type) {
239 switch (type) {
240 case blink::WebCryptoKeyTypeSecret:
241 return blink::WebCryptoKeyFormatRaw;
242 case blink::WebCryptoKeyTypePublic:
243 return blink::WebCryptoKeyFormatSpki;
244 case blink::WebCryptoKeyTypePrivate:
245 return blink::WebCryptoKeyFormatPkcs8;
246 }
247
248 NOTREACHED();
249 return blink::WebCryptoKeyFormatRaw;
250 }
251
252 // Converts a KeyAlgorithm into an equivalent Algorithm for import.
253 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm(
254 const blink::WebCryptoKeyAlgorithm& algorithm) {
255 switch (algorithm.paramsType()) {
256 case blink::WebCryptoKeyAlgorithmParamsTypeAes:
257 return CreateAlgorithm(algorithm.id());
258 case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
259 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id());
260 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
261 return CreateRsaHashedImportAlgorithm(
262 algorithm.id(), algorithm.rsaHashedParams()->hash().id());
263 case blink::WebCryptoKeyAlgorithmParamsTypeNone:
264 break;
265 default:
266 break;
267 }
268 return blink::WebCryptoAlgorithm::createNull();
269 }
270
271 // There is some duplicated information in the serialized format used by
272 // structured clone (since the KeyAlgorithm is serialized separately from the
273 // key data). Use this extra information to further validate what was
274 // deserialized from the key data.
275 //
276 // A failure here implies either a bug in the code, or that the serialized data
277 // was corrupted.
278 bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
279 const blink::WebCryptoKeyAlgorithm& algorithm,
280 blink::WebCryptoKeyType type) {
281 if (algorithm.id() != key.algorithm().id())
282 return false;
283
284 if (key.type() != type)
285 return false;
286
287 switch (algorithm.paramsType()) {
288 case blink::WebCryptoKeyAlgorithmParamsTypeAes:
289 if (algorithm.aesParams()->lengthBits() !=
290 key.algorithm().aesParams()->lengthBits())
291 return false;
292 break;
293 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
294 if (algorithm.rsaHashedParams()->modulusLengthBits() !=
295 key.algorithm().rsaHashedParams()->modulusLengthBits())
296 return false;
297 if (algorithm.rsaHashedParams()->publicExponent().size() !=
298 key.algorithm().rsaHashedParams()->publicExponent().size())
299 return false;
300 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
301 key.algorithm().rsaHashedParams()->publicExponent().data(),
302 key.algorithm().rsaHashedParams()->publicExponent().size()) !=
303 0)
304 return false;
305 break;
306 case blink::WebCryptoKeyAlgorithmParamsTypeNone:
307 case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
308 break;
309 default:
310 return false;
311 }
312
313 return true;
314 }
315
316 Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
317 const blink::WebCryptoAlgorithm& algorithm,
318 const blink::WebCryptoKey& key,
319 const CryptoData& data,
320 std::vector<uint8>* buffer) {
321 platform::SymKey* sym_key;
322 Status status = ToPlatformSymKey(key, &sym_key);
323 if (status.IsError())
324 return status;
325
326 unsigned int min_length = mode == ENCRYPT ? 16 : 24;
327
328 if (data.byte_length() < min_length)
329 return Status::ErrorDataTooSmall();
330 if (data.byte_length() % 8)
331 return Status::ErrorInvalidAesKwDataLength();
332
333 if (status.IsError())
334 return status;
335 return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer);
336 }
337
338 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, 22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
339 const blink::WebCryptoKey& key, 23 const blink::WebCryptoKey& key,
340 const CryptoData& data, 24 const CryptoData& data,
341 std::vector<uint8>* buffer) { 25 std::vector<uint8>* buffer) {
342 if (algorithm.id() != key.algorithm().id()) 26 if (algorithm.id() != key.algorithm().id())
343 return Status::ErrorUnexpected(); 27 return Status::ErrorUnexpected();
344 switch (algorithm.id()) { 28
345 case blink::WebCryptoAlgorithmIdAesCbc: 29 const AlgorithmImplementation* impl = NULL;
346 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); 30 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
347 case blink::WebCryptoAlgorithmIdAesGcm: 31 if (status.IsError())
348 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); 32 return status;
349 case blink::WebCryptoAlgorithmIdRsaOaep: 33
350 return DecryptRsaOaep(algorithm, key, data, buffer); 34 return impl->Decrypt(algorithm, key, data, buffer);
351 case blink::WebCryptoAlgorithmIdAesKw:
352 return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer);
353 default:
354 return Status::ErrorUnsupported();
355 }
356 } 35 }
357 36
358 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, 37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
359 const blink::WebCryptoKey& key, 38 const blink::WebCryptoKey& key,
360 const CryptoData& data, 39 const CryptoData& data,
361 std::vector<uint8>* buffer) { 40 std::vector<uint8>* buffer) {
362 if (algorithm.id() != key.algorithm().id()) 41 if (algorithm.id() != key.algorithm().id())
363 return Status::ErrorUnexpected(); 42 return Status::ErrorUnexpected();
364 switch (algorithm.id()) { 43
365 case blink::WebCryptoAlgorithmIdAesCbc: 44 const AlgorithmImplementation* impl = NULL;
366 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); 45 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
367 case blink::WebCryptoAlgorithmIdAesGcm: 46 if (status.IsError())
368 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); 47 return status;
369 case blink::WebCryptoAlgorithmIdAesKw: 48
370 return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer); 49 return impl->Encrypt(algorithm, key, data, buffer);
371 case blink::WebCryptoAlgorithmIdRsaOaep: 50 }
372 return EncryptRsaOaep(algorithm, key, data, buffer); 51
52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
53 const blink::WebCryptoKey& key,
54 std::vector<uint8>* buffer) {
55 const AlgorithmImplementation* impl = NULL;
56 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
57 if (status.IsError())
58 return status;
59
60 switch (format) {
61 case blink::WebCryptoKeyFormatRaw:
62 return impl->ExportKeyRaw(key, buffer);
63 case blink::WebCryptoKeyFormatSpki:
64 return impl->ExportKeySpki(key, buffer);
65 case blink::WebCryptoKeyFormatPkcs8:
66 return impl->ExportKeyPkcs8(key, buffer);
67 case blink::WebCryptoKeyFormatJwk:
68 return impl->ExportKeyJwk(key, buffer);
373 default: 69 default:
374 return Status::ErrorUnsupported(); 70 return Status::ErrorUnsupported();
375 } 71 }
376 } 72 }
377 73
378 Status UnwrapKeyDecryptAndImport(
379 blink::WebCryptoKeyFormat format,
380 const CryptoData& wrapped_key_data,
381 const blink::WebCryptoKey& wrapping_key,
382 const blink::WebCryptoAlgorithm& wrapping_algorithm,
383 const blink::WebCryptoAlgorithm& algorithm,
384 bool extractable,
385 blink::WebCryptoKeyUsageMask usage_mask,
386 blink::WebCryptoKey* key) {
387 std::vector<uint8> buffer;
388 Status status = DecryptDontCheckKeyUsage(
389 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
390 if (status.IsError())
391 return status;
392 // NOTE that returning the details of ImportKey() failures may leak
393 // information about the plaintext of the encrypted key (for instance the JWK
394 // key_ops). As long as the ImportKey error messages don't describe actual
395 // key bytes however this should be OK. For more discussion see
396 // http://crubg.com/372040
397 return ImportKey(
398 format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
399 }
400
401 Status WrapKeyExportAndEncrypt(
402 blink::WebCryptoKeyFormat format,
403 const blink::WebCryptoKey& key_to_wrap,
404 const blink::WebCryptoKey& wrapping_key,
405 const blink::WebCryptoAlgorithm& wrapping_algorithm,
406 std::vector<uint8>* buffer) {
407 std::vector<uint8> exported_data;
408 Status status = ExportKey(format, key_to_wrap, &exported_data);
409 if (status.IsError())
410 return status;
411 return EncryptDontCheckUsage(
412 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
413 }
414
415 // Returns the internal block size for SHA-*
416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) {
417 switch (hash_id) {
418 case blink::WebCryptoAlgorithmIdSha1:
419 case blink::WebCryptoAlgorithmIdSha256:
420 return 64;
421 case blink::WebCryptoAlgorithmIdSha384:
422 case blink::WebCryptoAlgorithmIdSha512:
423 return 128;
424 default:
425 NOTREACHED();
426 return 0;
427 }
428 }
429
430 // Returns the mask of all key usages that are possible for |algorithm| and
431 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make
432 // sense, then returns 0 (no usages).
433 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType(
434 blink::WebCryptoAlgorithmId algorithm,
435 blink::WebCryptoKeyType key_type) {
436 if (IsAlgorithmAsymmetric(algorithm) ==
437 (key_type == blink::WebCryptoKeyTypeSecret))
438 return 0;
439
440 switch (algorithm) {
441 case blink::WebCryptoAlgorithmIdAesCbc:
442 case blink::WebCryptoAlgorithmIdAesGcm:
443 case blink::WebCryptoAlgorithmIdAesCtr:
444 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
445 blink::WebCryptoKeyUsageWrapKey |
446 blink::WebCryptoKeyUsageUnwrapKey;
447 case blink::WebCryptoAlgorithmIdAesKw:
448 return blink::WebCryptoKeyUsageWrapKey |
449 blink::WebCryptoKeyUsageUnwrapKey;
450 case blink::WebCryptoAlgorithmIdHmac:
451 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
452 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
453 switch (key_type) {
454 case blink::WebCryptoKeyTypePublic:
455 return blink::WebCryptoKeyUsageVerify;
456 case blink::WebCryptoKeyTypePrivate:
457 return blink::WebCryptoKeyUsageSign;
458 default:
459 return 0;
460 }
461 case blink::WebCryptoAlgorithmIdRsaOaep:
462 switch (key_type) {
463 case blink::WebCryptoKeyTypePublic:
464 return blink::WebCryptoKeyUsageEncrypt |
465 blink::WebCryptoKeyUsageWrapKey;
466 case blink::WebCryptoKeyTypePrivate:
467 return blink::WebCryptoKeyUsageDecrypt |
468 blink::WebCryptoKeyUsageUnwrapKey;
469 default:
470 return 0;
471 }
472 default:
473 return 0;
474 }
475 }
476
477 // Returns Status::Success() if |usages| is a valid set of key usages for
478 // |algorithm| and |key_type|. Otherwise returns an error.
479 // In the case of JWK format the check is incomplete for asymmetric algorithms.
480 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm,
481 blink::WebCryptoKeyFormat format,
482 blink::WebCryptoKeyUsageMask usages) {
483 if (!IsAlgorithmAsymmetric(algorithm))
484 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages);
485
486 // Try to infer the key type given the import format.
487 blink::WebCryptoKeyType key_type;
488 bool key_type_known = false;
489
490 switch (format) {
491 case blink::WebCryptoKeyFormatRaw:
492 // TODO(eroman): The spec defines Diffie-Hellman raw import for public
493 // keys, so this will need to be updated in the future when DH is
494 // implemented.
495 return Status::ErrorUnexpected();
496 case blink::WebCryptoKeyFormatSpki:
497 key_type = blink::WebCryptoKeyTypePublic;
498 key_type_known = true;
499 break;
500 case blink::WebCryptoKeyFormatPkcs8:
501 key_type = blink::WebCryptoKeyTypePrivate;
502 key_type_known = true;
503 break;
504 case blink::WebCryptoKeyFormatJwk:
505 key_type_known = false;
506 break;
507 default:
508 return Status::ErrorUnexpected();
509 }
510
511 if (key_type_known)
512 return CheckKeyUsages(algorithm, key_type, usages);
513
514 // If the key type is not known, then the algorithm is asymmetric. Whether the
515 // key data describes a public or private key isn't known yet. But it must at
516 // least be ONE of those two.
517 DCHECK(IsAlgorithmAsymmetric(algorithm));
518
519 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages)
520 .IsError() &&
521 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages)
522 .IsError()) {
523 return Status::ErrorCreateKeyBadUsages();
524 }
525
526 return Status::Success();
527 }
528
529 // Returns an error if |combined_usage_mask| is invalid for generating a key
530 // pair for |algorithm|. Otherwise returns Status::Success(), and fills
531 // |public_key_usages| with the usages for the public key, and
532 // |private_key_usages| with those for the private key.
533 Status CheckKeyUsagesForGenerateKeyPair(
534 blink::WebCryptoAlgorithmId algorithm,
535 blink::WebCryptoKeyUsageMask combined_usage_mask,
536 blink::WebCryptoKeyUsageMask* public_key_usages,
537 blink::WebCryptoKeyUsageMask* private_key_usages) {
538 DCHECK(IsAlgorithmAsymmetric(algorithm));
539
540 blink::WebCryptoKeyUsageMask all_public_key_usages =
541 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic);
542 blink::WebCryptoKeyUsageMask all_private_key_usages =
543 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate);
544
545 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages,
546 combined_usage_mask))
547 return Status::ErrorCreateKeyBadUsages();
548
549 *public_key_usages = combined_usage_mask & all_public_key_usages;
550 *private_key_usages = combined_usage_mask & all_private_key_usages;
551
552 return Status::Success();
553 }
554
555 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
556 // to unsigned long.
557 bool BigIntegerToLong(const uint8* data,
558 unsigned int data_size,
559 unsigned long* result) {
560 // TODO(padolph): Is it correct to say that empty data is an error, or does it
561 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
562 if (data_size == 0)
563 return false;
564
565 *result = 0;
566 for (size_t i = 0; i < data_size; ++i) {
567 size_t reverse_i = data_size - i - 1;
568
569 if (reverse_i >= sizeof(unsigned long) && data[i])
570 return false; // Too large for a long.
571
572 *result |= data[i] << 8 * reverse_i;
573 }
574 return true;
575 }
576
577
578 } // namespace 74 } // namespace
579 75
580 void Init() { platform::Init(); }
581
582 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
583 const blink::WebCryptoKey& key, 77 const blink::WebCryptoKey& key,
584 const CryptoData& data, 78 const CryptoData& data,
585 std::vector<uint8>* buffer) { 79 std::vector<uint8>* buffer) {
586 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 80 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
587 return Status::ErrorUnexpected(); 81 return Status::ErrorUnexpected();
588 return EncryptDontCheckUsage(algorithm, key, data, buffer); 82 return EncryptDontCheckUsage(algorithm, key, data, buffer);
589 } 83 }
590 84
591 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
592 const blink::WebCryptoKey& key, 86 const blink::WebCryptoKey& key,
593 const CryptoData& data, 87 const CryptoData& data,
594 std::vector<uint8>* buffer) { 88 std::vector<uint8>* buffer) {
595 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) 89 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
596 return Status::ErrorUnexpected(); 90 return Status::ErrorUnexpected();
597 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); 91 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
598 } 92 }
599 93
600 Status Digest(const blink::WebCryptoAlgorithm& algorithm, 94 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
601 const CryptoData& data, 95 const CryptoData& data,
602 std::vector<uint8>* buffer) { 96 std::vector<uint8>* buffer) {
603 switch (algorithm.id()) { 97 const AlgorithmImplementation* impl = NULL;
604 case blink::WebCryptoAlgorithmIdSha1: 98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
605 case blink::WebCryptoAlgorithmIdSha256: 99 if (status.IsError())
606 case blink::WebCryptoAlgorithmIdSha384: 100 return status;
607 case blink::WebCryptoAlgorithmIdSha512:
608 return platform::DigestSha(algorithm.id(), data, buffer);
609 default:
610 return Status::ErrorUnsupported();
611 }
612 }
613 101
614 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( 102 return impl->Digest(algorithm, data, buffer);
615 blink::WebCryptoAlgorithmId algorithm) {
616 return platform::CreateDigestor(algorithm);
617 } 103 }
618 104
619 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, 105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
620 bool extractable, 106 bool extractable,
621 blink::WebCryptoKeyUsageMask usage_mask, 107 blink::WebCryptoKeyUsageMask usage_mask,
622 blink::WebCryptoKey* key) { 108 blink::WebCryptoKey* key) {
623 Status status = 109 const AlgorithmImplementation* impl = NULL;
624 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask); 110 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
625 if (status.IsError()) 111 if (status.IsError())
626 return status; 112 return status;
627 113
628 unsigned int keylen_bytes = 0; 114 status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask);
115 if (status.IsError())
116 return status;
629 117
630 // Get the secret key length in bytes from generation parameters. 118 return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key);
631 // This resolves any defaults.
632 switch (algorithm.id()) {
633 case blink::WebCryptoAlgorithmIdAesCbc:
634 case blink::WebCryptoAlgorithmIdAesGcm:
635 case blink::WebCryptoAlgorithmIdAesKw: {
636 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) {
637 return algorithm.aesKeyGenParams()->lengthBits() == 192
638 ? Status::ErrorAes192BitUnsupported()
639 : Status::ErrorGenerateKeyLength();
640 }
641 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8;
642 break;
643 }
644 case blink::WebCryptoAlgorithmIdHmac: {
645 const blink::WebCryptoHmacKeyGenParams* params =
646 algorithm.hmacKeyGenParams();
647 DCHECK(params);
648 if (params->hasLengthBits()) {
649 if (params->optionalLengthBits() % 8)
650 return Status::ErrorGenerateKeyLength();
651 keylen_bytes = params->optionalLengthBits() / 8;
652 } else {
653 keylen_bytes = ShaBlockSizeBytes(params->hash().id());
654 if (keylen_bytes == 0)
655 return Status::ErrorUnsupported();
656 }
657 break;
658 }
659
660 default:
661 return Status::ErrorUnsupported();
662 }
663
664 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
665 // probably be able to allowed to generate them too.
666 if (keylen_bytes == 0)
667 return Status::ErrorGenerateKeyLength();
668
669 return platform::GenerateSecretKey(
670 algorithm, extractable, usage_mask, keylen_bytes, key);
671 } 119 }
672 120
673 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, 121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
674 bool extractable, 122 bool extractable,
675 blink::WebCryptoKeyUsageMask combined_usage_mask, 123 blink::WebCryptoKeyUsageMask combined_usage_mask,
676 blink::WebCryptoKey* public_key, 124 blink::WebCryptoKey* public_key,
677 blink::WebCryptoKey* private_key) { 125 blink::WebCryptoKey* private_key) {
678 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0; 126 const AlgorithmImplementation* impl = NULL;
679 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0; 127 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
680
681 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(),
682 combined_usage_mask,
683 &public_key_usage_mask,
684 &private_key_usage_mask);
685 if (status.IsError()) 128 if (status.IsError())
686 return status; 129 return status;
687 130
688 // TODO(padolph): Handle other asymmetric algorithm key generation. 131 blink::WebCryptoKeyUsageMask public_usage_mask;
689 switch (algorithm.paramsType()) { 132 blink::WebCryptoKeyUsageMask private_usage_mask;
690 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: { 133 status = impl->VerifyKeyUsagesBeforeGenerateKeyPair(
691 const blink::WebCryptoRsaHashedKeyGenParams* params = 134 combined_usage_mask, &public_usage_mask, &private_usage_mask);
692 algorithm.rsaHashedKeyGenParams(); 135 if (status.IsError())
136 return status;
693 137
694 if (!params->modulusLengthBits()) 138 return impl->GenerateKeyPair(algorithm,
695 return Status::ErrorGenerateRsaZeroModulus(); 139 extractable,
696 140 public_usage_mask,
697 unsigned long public_exponent = 0; 141 private_usage_mask,
698 if (!BigIntegerToLong(params->publicExponent().data(), 142 public_key,
699 params->publicExponent().size(), 143 private_key);
700 &public_exponent) ||
701 (public_exponent != 3 && public_exponent != 65537)) {
702 return Status::ErrorGenerateKeyPublicExponent();
703 }
704
705 return platform::GenerateRsaKeyPair(algorithm,
706 extractable,
707 public_key_usage_mask,
708 private_key_usage_mask,
709 params->modulusLengthBits(),
710 public_exponent,
711 public_key,
712 private_key);
713 }
714 default:
715 return Status::ErrorUnsupported();
716 }
717 } 144 }
718 145
719 // Note that this function may be called from the target Blink thread. 146 // Note that this function may be called from the target Blink thread.
720 Status ImportKey(blink::WebCryptoKeyFormat format, 147 Status ImportKey(blink::WebCryptoKeyFormat format,
721 const CryptoData& key_data, 148 const CryptoData& key_data,
722 const blink::WebCryptoAlgorithm& algorithm, 149 const blink::WebCryptoAlgorithm& algorithm,
723 bool extractable, 150 bool extractable,
724 blink::WebCryptoKeyUsageMask usage_mask, 151 blink::WebCryptoKeyUsageMask usage_mask,
725 blink::WebCryptoKey* key) { 152 blink::WebCryptoKey* key) {
726 // This is "best effort" because it is incomplete for JWK (for which the key 153 const AlgorithmImplementation* impl = NULL;
727 // type is not yet known). ImportKeyJwk() does extra checks on key usage once 154 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
728 // the key type has been determined. 155 if (status.IsError())
729 Status status = 156 return status;
730 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); 157
158 status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
731 if (status.IsError()) 159 if (status.IsError())
732 return status; 160 return status;
733 161
734 switch (format) { 162 switch (format) {
735 case blink::WebCryptoKeyFormatRaw: 163 case blink::WebCryptoKeyFormatRaw:
736 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key); 164 return impl->ImportKeyRaw(
165 key_data, algorithm, extractable, usage_mask, key);
737 case blink::WebCryptoKeyFormatSpki: 166 case blink::WebCryptoKeyFormatSpki:
738 return platform::ImportKeySpki( 167 return impl->ImportKeySpki(
739 algorithm, key_data, extractable, usage_mask, key); 168 key_data, algorithm, extractable, usage_mask, key);
740 case blink::WebCryptoKeyFormatPkcs8: 169 case blink::WebCryptoKeyFormatPkcs8:
741 return platform::ImportKeyPkcs8( 170 return impl->ImportKeyPkcs8(
742 algorithm, key_data, extractable, usage_mask, key); 171 key_data, algorithm, extractable, usage_mask, key);
743 case blink::WebCryptoKeyFormatJwk: 172 case blink::WebCryptoKeyFormatJwk:
744 return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key); 173 return impl->ImportKeyJwk(
174 key_data, algorithm, extractable, usage_mask, key);
745 default: 175 default:
746 return Status::ErrorUnsupported(); 176 return Status::ErrorUnsupported();
747 } 177 }
748 }
749
750 // TODO(eroman): Move this to anonymous namespace.
751 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
752 const blink::WebCryptoKey& key,
753 std::vector<uint8>* buffer) {
754 switch (format) {
755 case blink::WebCryptoKeyFormatRaw: {
756 platform::SymKey* sym_key;
757 Status status = ToPlatformSymKey(key, &sym_key);
758 if (status.IsError())
759 return status;
760 return platform::ExportKeyRaw(sym_key, buffer);
761 }
762 case blink::WebCryptoKeyFormatSpki: {
763 platform::PublicKey* public_key;
764 Status status = ToPlatformPublicKey(key, &public_key);
765 if (status.IsError())
766 return status;
767 return platform::ExportKeySpki(public_key, buffer);
768 }
769 case blink::WebCryptoKeyFormatPkcs8: {
770 platform::PrivateKey* private_key;
771 Status status = ToPlatformPrivateKey(key, &private_key);
772 if (status.IsError())
773 return status;
774 return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer);
775 }
776 case blink::WebCryptoKeyFormatJwk:
777 return ExportKeyJwk(key, buffer);
778 default:
779 return Status::ErrorUnsupported();
780 }
781 } 178 }
782 179
783 Status ExportKey(blink::WebCryptoKeyFormat format, 180 Status ExportKey(blink::WebCryptoKeyFormat format,
784 const blink::WebCryptoKey& key, 181 const blink::WebCryptoKey& key,
785 std::vector<uint8>* buffer) { 182 std::vector<uint8>* buffer) {
786 if (!key.extractable()) 183 if (!key.extractable())
787 return Status::ErrorKeyNotExtractable(); 184 return Status::ErrorKeyNotExtractable();
788 return ExportKeyDontCheckExtractability(format, key, buffer); 185 return ExportKeyDontCheckExtractability(format, key, buffer);
789 } 186 }
790 187
791 Status Sign(const blink::WebCryptoAlgorithm& algorithm, 188 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
792 const blink::WebCryptoKey& key, 189 const blink::WebCryptoKey& key,
793 const CryptoData& data, 190 const CryptoData& data,
794 std::vector<uint8>* buffer) { 191 std::vector<uint8>* buffer) {
795 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) 192 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
796 return Status::ErrorUnexpected(); 193 return Status::ErrorUnexpected();
797 if (algorithm.id() != key.algorithm().id()) 194 if (algorithm.id() != key.algorithm().id())
798 return Status::ErrorUnexpected(); 195 return Status::ErrorUnexpected();
799 196
800 switch (algorithm.id()) { 197 const AlgorithmImplementation* impl = NULL;
801 case blink::WebCryptoAlgorithmIdHmac: 198 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
802 return SignHmac(algorithm, key, data, buffer); 199 if (status.IsError())
803 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 200 return status;
804 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer); 201
805 default: 202 return impl->Sign(algorithm, key, data, buffer);
806 return Status::ErrorUnsupported();
807 }
808 } 203 }
809 204
810 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm, 205 Status Verify(const blink::WebCryptoAlgorithm& algorithm,
811 const blink::WebCryptoKey& key, 206 const blink::WebCryptoKey& key,
812 const CryptoData& signature, 207 const CryptoData& signature,
813 const CryptoData& data, 208 const CryptoData& data,
814 bool* signature_match) { 209 bool* signature_match) {
815 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) 210 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
816 return Status::ErrorUnexpected(); 211 return Status::ErrorUnexpected();
817 if (algorithm.id() != key.algorithm().id()) 212 if (algorithm.id() != key.algorithm().id())
818 return Status::ErrorUnexpected(); 213 return Status::ErrorUnexpected();
819 214
215 // TODO(eroman): Move this into implementation which need it instead.
820 if (!signature.byte_length()) { 216 if (!signature.byte_length()) {
821 // None of the algorithms generate valid zero-length signatures so this 217 // None of the algorithms generate valid zero-length signatures so this
822 // will necessarily fail verification. Early return to protect 218 // will necessarily fail verification. Early return to protect
823 // implementations from dealing with a NULL signature pointer. 219 // implementations from dealing with a NULL signature pointer.
824 *signature_match = false; 220 *signature_match = false;
825 return Status::Success(); 221 return Status::Success();
826 } 222 }
827 223
828 switch (algorithm.id()) { 224 const AlgorithmImplementation* impl = NULL;
829 case blink::WebCryptoAlgorithmIdHmac: 225 Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
830 return VerifyHmac(algorithm, key, signature, data, signature_match); 226 if (status.IsError())
831 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 227 return status;
832 return VerifyRsaSsaPkcs1v1_5( 228
833 algorithm, key, signature, data, signature_match); 229 return impl->Verify(algorithm, key, signature, data, signature_match);
834 default:
835 return Status::ErrorUnsupported();
836 }
837 } 230 }
838 231
839 Status WrapKey(blink::WebCryptoKeyFormat format, 232 Status WrapKey(blink::WebCryptoKeyFormat format,
840 const blink::WebCryptoKey& key_to_wrap, 233 const blink::WebCryptoKey& key_to_wrap,
841 const blink::WebCryptoKey& wrapping_key, 234 const blink::WebCryptoKey& wrapping_key,
842 const blink::WebCryptoAlgorithm& wrapping_algorithm, 235 const blink::WebCryptoAlgorithm& wrapping_algorithm,
843 std::vector<uint8>* buffer) { 236 std::vector<uint8>* buffer) {
844 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) 237 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
845 return Status::ErrorUnexpected(); 238 return Status::ErrorUnexpected();
846 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
847 return Status::ErrorUnexpected();
848 239
849 return WrapKeyExportAndEncrypt( 240 std::vector<uint8> exported_data;
850 format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer); 241 Status status = ExportKey(format, key_to_wrap, &exported_data);
242 if (status.IsError())
243 return status;
244 return EncryptDontCheckUsage(
245 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
851 } 246 }
852 247
853 Status UnwrapKey(blink::WebCryptoKeyFormat format, 248 Status UnwrapKey(blink::WebCryptoKeyFormat format,
854 const CryptoData& wrapped_key_data, 249 const CryptoData& wrapped_key_data,
855 const blink::WebCryptoKey& wrapping_key, 250 const blink::WebCryptoKey& wrapping_key,
856 const blink::WebCryptoAlgorithm& wrapping_algorithm, 251 const blink::WebCryptoAlgorithm& wrapping_algorithm,
857 const blink::WebCryptoAlgorithm& algorithm, 252 const blink::WebCryptoAlgorithm& algorithm,
858 bool extractable, 253 bool extractable,
859 blink::WebCryptoKeyUsageMask usage_mask, 254 blink::WebCryptoKeyUsageMask usage_mask,
860 blink::WebCryptoKey* key) { 255 blink::WebCryptoKey* key) {
861 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 256 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
862 return Status::ErrorUnexpected(); 257 return Status::ErrorUnexpected();
863 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 258 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
864 return Status::ErrorUnexpected(); 259 return Status::ErrorUnexpected();
865 260
866 // Fail-fast if the key usages don't make sense. This avoids decrypting the 261 // Fail fast if the import is doomed to fail.
867 // key only to then have import fail. It is "best effort" because when 262 const AlgorithmImplementation* import_impl = NULL;
868 // unwrapping JWK for asymmetric algorithms the key type isn't known yet. 263 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl);
869 Status status =
870 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
871 if (status.IsError()) 264 if (status.IsError())
872 return status; 265 return status;
873 266
874 return UnwrapKeyDecryptAndImport(format, 267 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
875 wrapped_key_data, 268 if (status.IsError())
876 wrapping_key, 269 return status;
877 wrapping_algorithm, 270
878 algorithm, 271 std::vector<uint8> buffer;
879 extractable, 272 status = DecryptDontCheckKeyUsage(
880 usage_mask, 273 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
881 key); 274 if (status.IsError())
275 return status;
276
277 // NOTE that returning the details of ImportKey() failures may leak
278 // information about the plaintext of the encrypted key (for instance the JWK
279 // key_ops). As long as the ImportKey error messages don't describe actual
280 // key bytes however this should be OK. For more discussion see
281 // http://crubg.com/372040
282 return ImportKey(
283 format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
882 } 284 }
883 285
884 // Note that this function is called from the target Blink thread. 286 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
885 bool SerializeKeyForClone(const blink::WebCryptoKey& key, 287 blink::WebCryptoAlgorithmId algorithm) {
886 blink::WebVector<uint8>* key_data) { 288 return CreatePlatformDigestor(algorithm);
887 return static_cast<webcrypto::platform::Key*>(key.handle())
888 ->ThreadSafeSerializeForClone(key_data);
889 }
890
891 // Note that this function is called from the target Blink thread.
892 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
893 blink::WebCryptoKeyType type,
894 bool extractable,
895 blink::WebCryptoKeyUsageMask usage_mask,
896 const CryptoData& key_data,
897 blink::WebCryptoKey* key) {
898 // TODO(eroman): This should not call into the platform crypto layer.
899 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks
900 // are held.
901 //
902 // An alternate approach is to defer the key import until the key is used.
903 // However this means that any deserialization errors would have to be
904 // surfaced as WebCrypto errors, leading to slightly different behaviors. For
905 // instance you could clone a key which fails to be deserialized.
906 Status status = ImportKey(GetCloneFormatForKeyType(type),
907 key_data,
908 KeyAlgorithmToImportAlgorithm(algorithm),
909 extractable,
910 usage_mask,
911 key);
912 if (status.IsError())
913 return false;
914 return ValidateDeserializedKey(*key, algorithm, type);
915 }
916
917 Status ToPlatformSymKey(const blink::WebCryptoKey& key,
918 platform::SymKey** out) {
919 *out = static_cast<platform::Key*>(key.handle())->AsSymKey();
920 if (!*out)
921 return Status::ErrorUnexpectedKeyType();
922 return Status::Success();
923 }
924
925 Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
926 platform::PublicKey** out) {
927 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
928 if (!*out)
929 return Status::ErrorUnexpectedKeyType();
930 return Status::Success();
931 }
932
933 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
934 platform::PrivateKey** out) {
935 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
936 if (!*out)
937 return Status::ErrorUnexpectedKeyType();
938 return Status::Success();
939 }
940
941 // Returns Status::Success() if |usages| is a valid set of key usages for
942 // |algorithm| and |key_type|. Otherwise returns an error.
943 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm,
944 blink::WebCryptoKeyType key_type,
945 blink::WebCryptoKeyUsageMask usages) {
946 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type),
947 usages))
948 return Status::ErrorCreateKeyBadUsages();
949
950 return Status::Success();
951 } 289 }
952 290
953 } // namespace webcrypto 291 } // namespace webcrypto
954 292
955 } // namespace content 293 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698