Added unit test for DevTools' ephemeral port support.
[chromium-blink-merge.git] / content / child / webcrypto / shared_crypto.cc
blobb4d5931327a31de64f6ec3a9dd5ab5fa2d96823b
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
3 // found in the LICENSE file.
5 #include "content/child/webcrypto/shared_crypto.h"
7 #include "base/logging.h"
8 #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/status.h"
12 #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"
19 namespace content {
21 namespace webcrypto {
23 // ------------
24 // Threading:
25 // ------------
27 // All functions in this file are called from the webcrypto worker pool except
28 // for:
30 // * SerializeKeyForClone()
31 // * DeserializeKeyForClone()
32 // * ImportKey() // TODO(eroman): Change this.
34 namespace {
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);
42 bool IsValidAesKeyLengthBits(unsigned int length_bits) {
43 return length_bits == 128 || length_bits == 192 || length_bits == 256;
46 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
47 return length_bytes == 16 || length_bytes == 24 || length_bytes == 32;
50 const size_t kAesBlockSizeBytes = 16;
52 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
53 const blink::WebCryptoAlgorithm& algorithm,
54 const blink::WebCryptoKey& key,
55 const CryptoData& data,
56 std::vector<uint8>* buffer) {
57 platform::SymKey* sym_key;
58 Status status = ToPlatformSymKey(key, &sym_key);
59 if (status.IsError())
60 return status;
62 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
63 if (!params)
64 return Status::ErrorUnexpected();
66 CryptoData iv(params->iv().data(), params->iv().size());
67 if (iv.byte_length() != kAesBlockSizeBytes)
68 return Status::ErrorIncorrectSizeAesCbcIv();
70 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer);
73 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
74 const blink::WebCryptoAlgorithm& algorithm,
75 const blink::WebCryptoKey& key,
76 const CryptoData& data,
77 std::vector<uint8>* buffer) {
78 platform::SymKey* sym_key;
79 Status status = ToPlatformSymKey(key, &sym_key);
80 if (status.IsError())
81 return status;
83 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
84 if (!params)
85 return Status::ErrorUnexpected();
87 unsigned int tag_length_bits = 128;
88 if (params->hasTagLengthBits())
89 tag_length_bits = params->optionalTagLengthBits();
91 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 &&
92 tag_length_bits != 104 && tag_length_bits != 112 &&
93 tag_length_bits != 120 && tag_length_bits != 128)
94 return Status::ErrorInvalidAesGcmTagLength();
96 return platform::EncryptDecryptAesGcm(
97 mode,
98 sym_key,
99 data,
100 CryptoData(params->iv()),
101 CryptoData(params->optionalAdditionalData()),
102 tag_length_bits,
103 buffer);
106 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
107 const blink::WebCryptoKey& key,
108 const CryptoData& data,
109 std::vector<uint8>* buffer) {
110 platform::PublicKey* public_key;
111 Status status = ToPlatformPublicKey(key, &public_key);
112 if (status.IsError())
113 return status;
115 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
116 if (!params)
117 return Status::ErrorUnexpected();
119 return platform::EncryptRsaOaep(public_key,
120 key.algorithm().rsaHashedParams()->hash(),
121 CryptoData(params->optionalLabel()),
122 data,
123 buffer);
126 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
127 const blink::WebCryptoKey& key,
128 const CryptoData& data,
129 std::vector<uint8>* buffer) {
130 platform::PrivateKey* private_key;
131 Status status = ToPlatformPrivateKey(key, &private_key);
132 if (status.IsError())
133 return status;
135 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
136 if (!params)
137 return Status::ErrorUnexpected();
139 return platform::DecryptRsaOaep(private_key,
140 key.algorithm().rsaHashedParams()->hash(),
141 CryptoData(params->optionalLabel()),
142 data,
143 buffer);
146 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm,
147 const blink::WebCryptoKey& key,
148 const CryptoData& data,
149 std::vector<uint8>* buffer) {
150 platform::SymKey* sym_key;
151 Status status = ToPlatformSymKey(key, &sym_key);
152 if (status.IsError())
153 return status;
155 return platform::SignHmac(
156 sym_key, key.algorithm().hmacParams()->hash(), data, buffer);
159 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm,
160 const blink::WebCryptoKey& key,
161 const CryptoData& signature,
162 const CryptoData& data,
163 bool* signature_match) {
164 std::vector<uint8> result;
165 Status status = SignHmac(algorithm, key, data, &result);
166 if (status.IsError())
167 return status;
169 // Do not allow verification of truncated MACs.
170 *signature_match =
171 result.size() == signature.byte_length() &&
172 crypto::SecureMemEqual(
173 Uint8VectorStart(result), signature.bytes(), signature.byte_length());
175 return Status::Success();
178 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
179 const blink::WebCryptoKey& key,
180 const CryptoData& data,
181 std::vector<uint8>* buffer) {
182 platform::PrivateKey* private_key;
183 Status status = ToPlatformPrivateKey(key, &private_key);
184 if (status.IsError())
185 return status;
187 return platform::SignRsaSsaPkcs1v1_5(
188 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer);
191 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
192 const blink::WebCryptoKey& key,
193 const CryptoData& signature,
194 const CryptoData& data,
195 bool* signature_match) {
196 platform::PublicKey* public_key;
197 Status status = ToPlatformPublicKey(key, &public_key);
198 if (status.IsError())
199 return status;
201 return platform::VerifyRsaSsaPkcs1v1_5(
202 public_key,
203 key.algorithm().rsaHashedParams()->hash(),
204 signature,
205 data,
206 signature_match);
209 // Note that this function may be called from the target Blink thread.
210 Status ImportKeyRaw(const CryptoData& key_data,
211 const blink::WebCryptoAlgorithm& algorithm,
212 bool extractable,
213 blink::WebCryptoKeyUsageMask usage_mask,
214 blink::WebCryptoKey* key) {
215 switch (algorithm.id()) {
216 case blink::WebCryptoAlgorithmIdAesCtr:
217 case blink::WebCryptoAlgorithmIdAesCbc:
218 case blink::WebCryptoAlgorithmIdAesGcm:
219 case blink::WebCryptoAlgorithmIdAesKw:
220 if (!IsValidAesKeyLengthBytes(key_data.byte_length()))
221 return Status::ErrorImportAesKeyLength();
222 // Fallthrough intentional!
223 case blink::WebCryptoAlgorithmIdHmac:
224 return platform::ImportKeyRaw(
225 algorithm, key_data, extractable, usage_mask, key);
226 default:
227 return Status::ErrorUnsupported();
231 // Returns the key format to use for structured cloning.
232 blink::WebCryptoKeyFormat GetCloneFormatForKeyType(
233 blink::WebCryptoKeyType type) {
234 switch (type) {
235 case blink::WebCryptoKeyTypeSecret:
236 return blink::WebCryptoKeyFormatRaw;
237 case blink::WebCryptoKeyTypePublic:
238 return blink::WebCryptoKeyFormatSpki;
239 case blink::WebCryptoKeyTypePrivate:
240 return blink::WebCryptoKeyFormatPkcs8;
243 NOTREACHED();
244 return blink::WebCryptoKeyFormatRaw;
247 // Converts a KeyAlgorithm into an equivalent Algorithm for import.
248 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm(
249 const blink::WebCryptoKeyAlgorithm& algorithm) {
250 switch (algorithm.paramsType()) {
251 case blink::WebCryptoKeyAlgorithmParamsTypeAes:
252 return CreateAlgorithm(algorithm.id());
253 case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
254 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id());
255 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
256 return CreateRsaHashedImportAlgorithm(
257 algorithm.id(), algorithm.rsaHashedParams()->hash().id());
258 case blink::WebCryptoKeyAlgorithmParamsTypeNone:
259 break;
260 default:
261 break;
263 return blink::WebCryptoAlgorithm::createNull();
266 // There is some duplicated information in the serialized format used by
267 // structured clone (since the KeyAlgorithm is serialized separately from the
268 // key data). Use this extra information to further validate what was
269 // deserialized from the key data.
271 // A failure here implies either a bug in the code, or that the serialized data
272 // was corrupted.
273 bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
274 const blink::WebCryptoKeyAlgorithm& algorithm,
275 blink::WebCryptoKeyType type) {
276 if (algorithm.id() != key.algorithm().id())
277 return false;
279 if (key.type() != type)
280 return false;
282 switch (algorithm.paramsType()) {
283 case blink::WebCryptoKeyAlgorithmParamsTypeAes:
284 if (algorithm.aesParams()->lengthBits() !=
285 key.algorithm().aesParams()->lengthBits())
286 return false;
287 break;
288 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
289 if (algorithm.rsaHashedParams()->modulusLengthBits() !=
290 key.algorithm().rsaHashedParams()->modulusLengthBits())
291 return false;
292 if (algorithm.rsaHashedParams()->publicExponent().size() !=
293 key.algorithm().rsaHashedParams()->publicExponent().size())
294 return false;
295 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
296 key.algorithm().rsaHashedParams()->publicExponent().data(),
297 key.algorithm().rsaHashedParams()->publicExponent().size()) !=
299 return false;
300 break;
301 case blink::WebCryptoKeyAlgorithmParamsTypeNone:
302 case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
303 break;
304 default:
305 return false;
308 return true;
311 // Validates the size of data input to AES-KW. AES-KW requires the input data
312 // size to be at least 24 bytes and a multiple of 8 bytes.
313 Status CheckAesKwInputSize(const CryptoData& aeskw_input_data) {
314 if (aeskw_input_data.byte_length() < 24)
315 return Status::ErrorDataTooSmall();
316 if (aeskw_input_data.byte_length() % 8)
317 return Status::ErrorInvalidAesKwDataLength();
318 return Status::Success();
321 Status UnwrapKeyRaw(const CryptoData& wrapped_key_data,
322 const blink::WebCryptoKey& wrapping_key,
323 const blink::WebCryptoAlgorithm& wrapping_algorithm,
324 const blink::WebCryptoAlgorithm& algorithm,
325 bool extractable,
326 blink::WebCryptoKeyUsageMask usage_mask,
327 blink::WebCryptoKey* key) {
328 // TODO(padolph): Handle other wrapping algorithms
329 switch (wrapping_algorithm.id()) {
330 case blink::WebCryptoAlgorithmIdAesKw: {
331 platform::SymKey* platform_wrapping_key;
332 Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key);
333 if (status.IsError())
334 return status;
335 status = CheckAesKwInputSize(wrapped_key_data);
336 if (status.IsError())
337 return status;
338 return platform::UnwrapSymKeyAesKw(wrapped_key_data,
339 platform_wrapping_key,
340 algorithm,
341 extractable,
342 usage_mask,
343 key);
345 default:
346 return Status::ErrorUnsupported();
350 Status WrapKeyRaw(const blink::WebCryptoKey& key_to_wrap,
351 const blink::WebCryptoKey& wrapping_key,
352 const blink::WebCryptoAlgorithm& wrapping_algorithm,
353 std::vector<uint8>* buffer) {
354 // A raw key is always a symmetric key.
355 platform::SymKey* platform_key;
356 Status status = ToPlatformSymKey(key_to_wrap, &platform_key);
357 if (status.IsError())
358 return status;
360 // TODO(padolph): Handle other wrapping algorithms
361 switch (wrapping_algorithm.id()) {
362 case blink::WebCryptoAlgorithmIdAesKw: {
363 platform::SymKey* platform_wrapping_key;
364 status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key);
365 if (status.IsError())
366 return status;
367 return platform::WrapSymKeyAesKw(
368 platform_key, platform_wrapping_key, buffer);
370 default:
371 return Status::ErrorUnsupported();
375 Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm,
376 const blink::WebCryptoKey& key,
377 const CryptoData& data,
378 std::vector<uint8>* buffer) {
379 platform::SymKey* sym_key;
380 Status status = ToPlatformSymKey(key, &sym_key);
381 if (status.IsError())
382 return status;
383 status = CheckAesKwInputSize(data);
384 if (status.IsError())
385 return status;
386 return platform::DecryptAesKw(sym_key, data, buffer);
389 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
390 const blink::WebCryptoKey& key,
391 const CryptoData& data,
392 std::vector<uint8>* buffer) {
393 if (algorithm.id() != key.algorithm().id())
394 return Status::ErrorUnexpected();
395 switch (algorithm.id()) {
396 case blink::WebCryptoAlgorithmIdAesCbc:
397 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
398 case blink::WebCryptoAlgorithmIdAesGcm:
399 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
400 case blink::WebCryptoAlgorithmIdRsaOaep:
401 return DecryptRsaOaep(algorithm, key, data, buffer);
402 case blink::WebCryptoAlgorithmIdAesKw:
403 return DecryptAesKw(algorithm, key, data, buffer);
404 default:
405 return Status::ErrorUnsupported();
409 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
410 const blink::WebCryptoKey& key,
411 const CryptoData& data,
412 std::vector<uint8>* buffer) {
413 if (algorithm.id() != key.algorithm().id())
414 return Status::ErrorUnexpected();
415 switch (algorithm.id()) {
416 case blink::WebCryptoAlgorithmIdAesCbc:
417 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
418 case blink::WebCryptoAlgorithmIdAesGcm:
419 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
420 case blink::WebCryptoAlgorithmIdRsaOaep:
421 return EncryptRsaOaep(algorithm, key, data, buffer);
422 default:
423 return Status::ErrorUnsupported();
427 Status UnwrapKeyDecryptAndImport(
428 blink::WebCryptoKeyFormat format,
429 const CryptoData& wrapped_key_data,
430 const blink::WebCryptoKey& wrapping_key,
431 const blink::WebCryptoAlgorithm& wrapping_algorithm,
432 const blink::WebCryptoAlgorithm& algorithm,
433 bool extractable,
434 blink::WebCryptoKeyUsageMask usage_mask,
435 blink::WebCryptoKey* key) {
436 std::vector<uint8> buffer;
437 Status status = DecryptDontCheckKeyUsage(
438 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
439 if (status.IsError())
440 return status;
441 // NOTE that returning the details of ImportKey() failures may leak
442 // information about the plaintext of the encrypted key (for instance the JWK
443 // key_ops). As long as the ImportKey error messages don't describe actual
444 // key bytes however this should be OK. For more discussion see
445 // http://crubg.com/372040
446 return ImportKey(
447 format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
450 Status WrapKeyExportAndEncrypt(
451 blink::WebCryptoKeyFormat format,
452 const blink::WebCryptoKey& key_to_wrap,
453 const blink::WebCryptoKey& wrapping_key,
454 const blink::WebCryptoAlgorithm& wrapping_algorithm,
455 std::vector<uint8>* buffer) {
456 std::vector<uint8> exported_data;
457 Status status = ExportKey(format, key_to_wrap, &exported_data);
458 if (status.IsError())
459 return status;
460 return EncryptDontCheckUsage(
461 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
464 // Returns the internal block size for SHA-*
465 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) {
466 switch (hash_id) {
467 case blink::WebCryptoAlgorithmIdSha1:
468 case blink::WebCryptoAlgorithmIdSha256:
469 return 64;
470 case blink::WebCryptoAlgorithmIdSha384:
471 case blink::WebCryptoAlgorithmIdSha512:
472 return 128;
473 default:
474 NOTREACHED();
475 return 0;
479 // Returns the mask of all key usages that are possible for |algorithm| and
480 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make
481 // sense, then returns 0 (no usages).
482 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType(
483 blink::WebCryptoAlgorithmId algorithm,
484 blink::WebCryptoKeyType key_type) {
485 if (IsAlgorithmAsymmetric(algorithm) ==
486 (key_type == blink::WebCryptoKeyTypeSecret))
487 return 0;
489 switch (algorithm) {
490 case blink::WebCryptoAlgorithmIdAesCbc:
491 case blink::WebCryptoAlgorithmIdAesGcm:
492 case blink::WebCryptoAlgorithmIdAesCtr:
493 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
494 blink::WebCryptoKeyUsageWrapKey |
495 blink::WebCryptoKeyUsageUnwrapKey;
496 case blink::WebCryptoAlgorithmIdAesKw:
497 return blink::WebCryptoKeyUsageWrapKey |
498 blink::WebCryptoKeyUsageUnwrapKey;
499 case blink::WebCryptoAlgorithmIdHmac:
500 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
501 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
502 switch (key_type) {
503 case blink::WebCryptoKeyTypePublic:
504 return blink::WebCryptoKeyUsageVerify;
505 case blink::WebCryptoKeyTypePrivate:
506 return blink::WebCryptoKeyUsageSign;
507 default:
508 return 0;
510 case blink::WebCryptoAlgorithmIdRsaOaep:
511 switch (key_type) {
512 case blink::WebCryptoKeyTypePublic:
513 return blink::WebCryptoKeyUsageEncrypt |
514 blink::WebCryptoKeyUsageWrapKey;
515 case blink::WebCryptoKeyTypePrivate:
516 return blink::WebCryptoKeyUsageDecrypt |
517 blink::WebCryptoKeyUsageUnwrapKey;
518 default:
519 return 0;
521 default:
522 return 0;
526 // Returns Status::Success() if |usages| is a valid set of key usages for
527 // |algorithm| and |key_type|. Otherwise returns an error.
528 // In the case of JWK format the check is incomplete for asymmetric algorithms.
529 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm,
530 blink::WebCryptoKeyFormat format,
531 blink::WebCryptoKeyUsageMask usages) {
532 if (!IsAlgorithmAsymmetric(algorithm))
533 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages);
535 // Try to infer the key type given the import format.
536 blink::WebCryptoKeyType key_type;
537 bool key_type_known = false;
539 switch (format) {
540 case blink::WebCryptoKeyFormatRaw:
541 // TODO(eroman): The spec defines Diffie-Hellman raw import for public
542 // keys, so this will need to be updated in the future when DH is
543 // implemented.
544 return Status::ErrorUnexpected();
545 case blink::WebCryptoKeyFormatSpki:
546 key_type = blink::WebCryptoKeyTypePublic;
547 key_type_known = true;
548 break;
549 case blink::WebCryptoKeyFormatPkcs8:
550 key_type = blink::WebCryptoKeyTypePrivate;
551 key_type_known = true;
552 break;
553 case blink::WebCryptoKeyFormatJwk:
554 key_type_known = false;
555 break;
556 default:
557 return Status::ErrorUnexpected();
560 if (key_type_known)
561 return CheckKeyUsages(algorithm, key_type, usages);
563 // If the key type is not known, then the algorithm is asymmetric. Whether the
564 // key data describes a public or private key isn't known yet. But it must at
565 // least be ONE of those two.
566 DCHECK(IsAlgorithmAsymmetric(algorithm));
568 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages)
569 .IsError() &&
570 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages)
571 .IsError()) {
572 return Status::ErrorCreateKeyBadUsages();
575 return Status::Success();
578 // Returns an error if |combined_usage_mask| is invalid for generating a key
579 // pair for |algorithm|. Otherwise returns Status::Success(), and fills
580 // |public_key_usages| with the usages for the public key, and
581 // |private_key_usages| with those for the private key.
582 Status CheckKeyUsagesForGenerateKeyPair(
583 blink::WebCryptoAlgorithmId algorithm,
584 blink::WebCryptoKeyUsageMask combined_usage_mask,
585 blink::WebCryptoKeyUsageMask* public_key_usages,
586 blink::WebCryptoKeyUsageMask* private_key_usages) {
587 DCHECK(IsAlgorithmAsymmetric(algorithm));
589 blink::WebCryptoKeyUsageMask all_public_key_usages =
590 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic);
591 blink::WebCryptoKeyUsageMask all_private_key_usages =
592 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate);
594 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages,
595 combined_usage_mask))
596 return Status::ErrorCreateKeyBadUsages();
598 *public_key_usages = combined_usage_mask & all_public_key_usages;
599 *private_key_usages = combined_usage_mask & all_private_key_usages;
601 return Status::Success();
604 } // namespace
606 void Init() { platform::Init(); }
608 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
609 const blink::WebCryptoKey& key,
610 const CryptoData& data,
611 std::vector<uint8>* buffer) {
612 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
613 return Status::ErrorUnexpected();
614 return EncryptDontCheckUsage(algorithm, key, data, buffer);
617 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
618 const blink::WebCryptoKey& key,
619 const CryptoData& data,
620 std::vector<uint8>* buffer) {
621 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
622 return Status::ErrorUnexpected();
623 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
626 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
627 const CryptoData& data,
628 std::vector<uint8>* buffer) {
629 switch (algorithm.id()) {
630 case blink::WebCryptoAlgorithmIdSha1:
631 case blink::WebCryptoAlgorithmIdSha256:
632 case blink::WebCryptoAlgorithmIdSha384:
633 case blink::WebCryptoAlgorithmIdSha512:
634 return platform::DigestSha(algorithm.id(), data, buffer);
635 default:
636 return Status::ErrorUnsupported();
640 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
641 blink::WebCryptoAlgorithmId algorithm) {
642 return platform::CreateDigestor(algorithm);
645 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
646 bool extractable,
647 blink::WebCryptoKeyUsageMask usage_mask,
648 blink::WebCryptoKey* key) {
649 Status status =
650 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask);
651 if (status.IsError())
652 return status;
654 unsigned int keylen_bytes = 0;
656 // Get the secret key length in bytes from generation parameters.
657 // This resolves any defaults.
658 switch (algorithm.id()) {
659 case blink::WebCryptoAlgorithmIdAesCbc:
660 case blink::WebCryptoAlgorithmIdAesGcm:
661 case blink::WebCryptoAlgorithmIdAesKw: {
662 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits()))
663 return Status::ErrorGenerateKeyLength();
664 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8;
665 break;
667 case blink::WebCryptoAlgorithmIdHmac: {
668 const blink::WebCryptoHmacKeyGenParams* params =
669 algorithm.hmacKeyGenParams();
670 DCHECK(params);
671 if (params->hasLengthBits()) {
672 if (params->optionalLengthBits() % 8)
673 return Status::ErrorGenerateKeyLength();
674 keylen_bytes = params->optionalLengthBits() / 8;
675 } else {
676 keylen_bytes = ShaBlockSizeBytes(params->hash().id());
677 if (keylen_bytes == 0)
678 return Status::ErrorUnsupported();
680 break;
683 default:
684 return Status::ErrorUnsupported();
687 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
688 // probably be able to allowed to generate them too.
689 if (keylen_bytes == 0)
690 return Status::ErrorGenerateKeyLength();
692 return platform::GenerateSecretKey(
693 algorithm, extractable, usage_mask, keylen_bytes, key);
696 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
697 bool extractable,
698 blink::WebCryptoKeyUsageMask combined_usage_mask,
699 blink::WebCryptoKey* public_key,
700 blink::WebCryptoKey* private_key) {
701 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0;
702 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0;
704 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(),
705 combined_usage_mask,
706 &public_key_usage_mask,
707 &private_key_usage_mask);
708 if (status.IsError())
709 return status;
711 // TODO(padolph): Handle other asymmetric algorithm key generation.
712 switch (algorithm.paramsType()) {
713 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: {
714 const blink::WebCryptoRsaHashedKeyGenParams* params =
715 algorithm.rsaHashedKeyGenParams();
717 if (!params->modulusLengthBits())
718 return Status::ErrorGenerateRsaZeroModulus();
720 CryptoData publicExponent(params->publicExponent());
721 if (!publicExponent.byte_length())
722 return Status::ErrorGenerateKeyPublicExponent();
724 return platform::GenerateRsaKeyPair(algorithm,
725 extractable,
726 public_key_usage_mask,
727 private_key_usage_mask,
728 params->modulusLengthBits(),
729 publicExponent,
730 public_key,
731 private_key);
733 default:
734 return Status::ErrorUnsupported();
738 // Note that this function may be called from the target Blink thread.
739 Status ImportKey(blink::WebCryptoKeyFormat format,
740 const CryptoData& key_data,
741 const blink::WebCryptoAlgorithm& algorithm,
742 bool extractable,
743 blink::WebCryptoKeyUsageMask usage_mask,
744 blink::WebCryptoKey* key) {
745 // This is "best effort" because it is incomplete for JWK (for which the key
746 // type is not yet known). ImportKeyJwk() does extra checks on key usage once
747 // the key type has been determined.
748 Status status =
749 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
750 if (status.IsError())
751 return status;
753 switch (format) {
754 case blink::WebCryptoKeyFormatRaw:
755 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key);
756 case blink::WebCryptoKeyFormatSpki:
757 return platform::ImportKeySpki(
758 algorithm, key_data, extractable, usage_mask, key);
759 case blink::WebCryptoKeyFormatPkcs8:
760 return platform::ImportKeyPkcs8(
761 algorithm, key_data, extractable, usage_mask, key);
762 case blink::WebCryptoKeyFormatJwk:
763 return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key);
764 default:
765 return Status::ErrorUnsupported();
769 // TODO(eroman): Move this to anonymous namespace.
770 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
771 const blink::WebCryptoKey& key,
772 std::vector<uint8>* buffer) {
773 switch (format) {
774 case blink::WebCryptoKeyFormatRaw: {
775 platform::SymKey* sym_key;
776 Status status = ToPlatformSymKey(key, &sym_key);
777 if (status.IsError())
778 return status;
779 return platform::ExportKeyRaw(sym_key, buffer);
781 case blink::WebCryptoKeyFormatSpki: {
782 platform::PublicKey* public_key;
783 Status status = ToPlatformPublicKey(key, &public_key);
784 if (status.IsError())
785 return status;
786 return platform::ExportKeySpki(public_key, buffer);
788 case blink::WebCryptoKeyFormatPkcs8: {
789 platform::PrivateKey* private_key;
790 Status status = ToPlatformPrivateKey(key, &private_key);
791 if (status.IsError())
792 return status;
793 return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer);
795 case blink::WebCryptoKeyFormatJwk:
796 return ExportKeyJwk(key, buffer);
797 default:
798 return Status::ErrorUnsupported();
802 Status ExportKey(blink::WebCryptoKeyFormat format,
803 const blink::WebCryptoKey& key,
804 std::vector<uint8>* buffer) {
805 if (!key.extractable())
806 return Status::ErrorKeyNotExtractable();
807 return ExportKeyDontCheckExtractability(format, key, buffer);
810 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
811 const blink::WebCryptoKey& key,
812 const CryptoData& data,
813 std::vector<uint8>* buffer) {
814 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
815 return Status::ErrorUnexpected();
816 if (algorithm.id() != key.algorithm().id())
817 return Status::ErrorUnexpected();
819 switch (algorithm.id()) {
820 case blink::WebCryptoAlgorithmIdHmac:
821 return SignHmac(algorithm, key, data, buffer);
822 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
823 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer);
824 default:
825 return Status::ErrorUnsupported();
829 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
830 const blink::WebCryptoKey& key,
831 const CryptoData& signature,
832 const CryptoData& data,
833 bool* signature_match) {
834 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
835 return Status::ErrorUnexpected();
836 if (algorithm.id() != key.algorithm().id())
837 return Status::ErrorUnexpected();
839 if (!signature.byte_length()) {
840 // None of the algorithms generate valid zero-length signatures so this
841 // will necessarily fail verification. Early return to protect
842 // implementations from dealing with a NULL signature pointer.
843 *signature_match = false;
844 return Status::Success();
847 switch (algorithm.id()) {
848 case blink::WebCryptoAlgorithmIdHmac:
849 return VerifyHmac(algorithm, key, signature, data, signature_match);
850 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
851 return VerifyRsaSsaPkcs1v1_5(
852 algorithm, key, signature, data, signature_match);
853 default:
854 return Status::ErrorUnsupported();
858 Status WrapKey(blink::WebCryptoKeyFormat format,
859 const blink::WebCryptoKey& key_to_wrap,
860 const blink::WebCryptoKey& wrapping_key,
861 const blink::WebCryptoAlgorithm& wrapping_algorithm,
862 std::vector<uint8>* buffer) {
863 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
864 return Status::ErrorUnexpected();
865 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
866 return Status::ErrorUnexpected();
868 if (format == blink::WebCryptoKeyFormatRaw &&
869 wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
870 // AES-KW is a special case, due to NSS's implementation only
871 // supporting C_Wrap/C_Unwrap with AES-KW
872 return WrapKeyRaw(key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
875 return WrapKeyExportAndEncrypt(
876 format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
879 Status UnwrapKey(blink::WebCryptoKeyFormat format,
880 const CryptoData& wrapped_key_data,
881 const blink::WebCryptoKey& wrapping_key,
882 const blink::WebCryptoAlgorithm& wrapping_algorithm,
883 const blink::WebCryptoAlgorithm& algorithm,
884 bool extractable,
885 blink::WebCryptoKeyUsageMask usage_mask,
886 blink::WebCryptoKey* key) {
887 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
888 return Status::ErrorUnexpected();
889 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
890 return Status::ErrorUnexpected();
892 // Fail-fast if the key usages don't make sense. This avoids decrypting the
893 // key only to then have import fail. It is "best effort" because when
894 // unwrapping JWK for asymmetric algorithms the key type isn't known yet.
895 Status status =
896 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
897 if (status.IsError())
898 return status;
900 if (format == blink::WebCryptoKeyFormatRaw &&
901 wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
902 // AES-KW is a special case, due to NSS's implementation only
903 // supporting C_Wrap/C_Unwrap with AES-KW
904 return UnwrapKeyRaw(wrapped_key_data,
905 wrapping_key,
906 wrapping_algorithm,
907 algorithm,
908 extractable,
909 usage_mask,
910 key);
913 return UnwrapKeyDecryptAndImport(format,
914 wrapped_key_data,
915 wrapping_key,
916 wrapping_algorithm,
917 algorithm,
918 extractable,
919 usage_mask,
920 key);
923 // Note that this function is called from the target Blink thread.
924 bool SerializeKeyForClone(const blink::WebCryptoKey& key,
925 blink::WebVector<uint8>* key_data) {
926 return static_cast<webcrypto::platform::Key*>(key.handle())
927 ->ThreadSafeSerializeForClone(key_data);
930 // Note that this function is called from the target Blink thread.
931 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
932 blink::WebCryptoKeyType type,
933 bool extractable,
934 blink::WebCryptoKeyUsageMask usage_mask,
935 const CryptoData& key_data,
936 blink::WebCryptoKey* key) {
937 // TODO(eroman): This should not call into the platform crypto layer.
938 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks
939 // are held.
941 // An alternate approach is to defer the key import until the key is used.
942 // However this means that any deserialization errors would have to be
943 // surfaced as WebCrypto errors, leading to slightly different behaviors. For
944 // instance you could clone a key which fails to be deserialized.
945 Status status = ImportKey(GetCloneFormatForKeyType(type),
946 key_data,
947 KeyAlgorithmToImportAlgorithm(algorithm),
948 extractable,
949 usage_mask,
950 key);
951 if (status.IsError())
952 return false;
953 return ValidateDeserializedKey(*key, algorithm, type);
956 Status ToPlatformSymKey(const blink::WebCryptoKey& key,
957 platform::SymKey** out) {
958 *out = static_cast<platform::Key*>(key.handle())->AsSymKey();
959 if (!*out)
960 return Status::ErrorUnexpectedKeyType();
961 return Status::Success();
964 Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
965 platform::PublicKey** out) {
966 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
967 if (!*out)
968 return Status::ErrorUnexpectedKeyType();
969 return Status::Success();
972 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
973 platform::PrivateKey** out) {
974 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
975 if (!*out)
976 return Status::ErrorUnexpectedKeyType();
977 return Status::Success();
980 // Returns Status::Success() if |usages| is a valid set of key usages for
981 // |algorithm| and |key_type|. Otherwise returns an error.
982 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm,
983 blink::WebCryptoKeyType key_type,
984 blink::WebCryptoKeyUsageMask usages) {
985 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type),
986 usages))
987 return Status::ErrorCreateKeyBadUsages();
989 return Status::Success();
992 } // namespace webcrypto
994 } // namespace content