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"
27 // All functions in this file are called from the webcrypto worker pool except
30 // * SerializeKeyForClone()
31 // * DeserializeKeyForClone()
32 // * ImportKey() // TODO(eroman): Change this.
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
);
62 const blink::WebCryptoAesCbcParams
* params
= algorithm
.aesCbcParams();
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
);
83 const blink::WebCryptoAesGcmParams
* params
= algorithm
.aesGcmParams();
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(
100 CryptoData(params
->iv()),
101 CryptoData(params
->optionalAdditionalData()),
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())
115 const blink::WebCryptoRsaOaepParams
* params
= algorithm
.rsaOaepParams();
117 return Status::ErrorUnexpected();
119 return platform::EncryptRsaOaep(public_key
,
120 key
.algorithm().rsaHashedParams()->hash(),
121 CryptoData(params
->optionalLabel()),
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())
135 const blink::WebCryptoRsaOaepParams
* params
= algorithm
.rsaOaepParams();
137 return Status::ErrorUnexpected();
139 return platform::DecryptRsaOaep(private_key
,
140 key
.algorithm().rsaHashedParams()->hash(),
141 CryptoData(params
->optionalLabel()),
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())
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())
169 // Do not allow verification of truncated MACs.
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())
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())
201 return platform::VerifyRsaSsaPkcs1v1_5(
203 key
.algorithm().rsaHashedParams()->hash(),
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
,
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
);
227 return Status::ErrorUnsupported();
231 // Returns the key format to use for structured cloning.
232 blink::WebCryptoKeyFormat
GetCloneFormatForKeyType(
233 blink::WebCryptoKeyType 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
;
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
:
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
273 bool ValidateDeserializedKey(const blink::WebCryptoKey
& key
,
274 const blink::WebCryptoKeyAlgorithm
& algorithm
,
275 blink::WebCryptoKeyType type
) {
276 if (algorithm
.id() != key
.algorithm().id())
279 if (key
.type() != type
)
282 switch (algorithm
.paramsType()) {
283 case blink::WebCryptoKeyAlgorithmParamsTypeAes
:
284 if (algorithm
.aesParams()->lengthBits() !=
285 key
.algorithm().aesParams()->lengthBits())
288 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed
:
289 if (algorithm
.rsaHashedParams()->modulusLengthBits() !=
290 key
.algorithm().rsaHashedParams()->modulusLengthBits())
292 if (algorithm
.rsaHashedParams()->publicExponent().size() !=
293 key
.algorithm().rsaHashedParams()->publicExponent().size())
295 if (memcmp(algorithm
.rsaHashedParams()->publicExponent().data(),
296 key
.algorithm().rsaHashedParams()->publicExponent().data(),
297 key
.algorithm().rsaHashedParams()->publicExponent().size()) !=
301 case blink::WebCryptoKeyAlgorithmParamsTypeNone
:
302 case blink::WebCryptoKeyAlgorithmParamsTypeHmac
:
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
,
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())
335 status
= CheckAesKwInputSize(wrapped_key_data
);
336 if (status
.IsError())
338 return platform::UnwrapSymKeyAesKw(wrapped_key_data
,
339 platform_wrapping_key
,
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())
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())
367 return platform::WrapSymKeyAesKw(
368 platform_key
, platform_wrapping_key
, buffer
);
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())
383 status
= CheckAesKwInputSize(data
);
384 if (status
.IsError())
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
);
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
);
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
,
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())
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
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())
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
) {
467 case blink::WebCryptoAlgorithmIdSha1
:
468 case blink::WebCryptoAlgorithmIdSha256
:
470 case blink::WebCryptoAlgorithmIdSha384
:
471 case blink::WebCryptoAlgorithmIdSha512
:
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
))
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
:
503 case blink::WebCryptoKeyTypePublic
:
504 return blink::WebCryptoKeyUsageVerify
;
505 case blink::WebCryptoKeyTypePrivate
:
506 return blink::WebCryptoKeyUsageSign
;
510 case blink::WebCryptoAlgorithmIdRsaOaep
:
512 case blink::WebCryptoKeyTypePublic
:
513 return blink::WebCryptoKeyUsageEncrypt
|
514 blink::WebCryptoKeyUsageWrapKey
;
515 case blink::WebCryptoKeyTypePrivate
:
516 return blink::WebCryptoKeyUsageDecrypt
|
517 blink::WebCryptoKeyUsageUnwrapKey
;
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;
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
544 return Status::ErrorUnexpected();
545 case blink::WebCryptoKeyFormatSpki
:
546 key_type
= blink::WebCryptoKeyTypePublic
;
547 key_type_known
= true;
549 case blink::WebCryptoKeyFormatPkcs8
:
550 key_type
= blink::WebCryptoKeyTypePrivate
;
551 key_type_known
= true;
553 case blink::WebCryptoKeyFormatJwk
:
554 key_type_known
= false;
557 return Status::ErrorUnexpected();
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
)
570 CheckKeyUsages(algorithm
, blink::WebCryptoKeyTypePrivate
, usages
)
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();
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
);
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
,
647 blink::WebCryptoKeyUsageMask usage_mask
,
648 blink::WebCryptoKey
* key
) {
650 CheckKeyUsages(algorithm
.id(), blink::WebCryptoKeyTypeSecret
, usage_mask
);
651 if (status
.IsError())
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;
667 case blink::WebCryptoAlgorithmIdHmac
: {
668 const blink::WebCryptoHmacKeyGenParams
* params
=
669 algorithm
.hmacKeyGenParams();
671 if (params
->hasLengthBits()) {
672 if (params
->optionalLengthBits() % 8)
673 return Status::ErrorGenerateKeyLength();
674 keylen_bytes
= params
->optionalLengthBits() / 8;
676 keylen_bytes
= ShaBlockSizeBytes(params
->hash().id());
677 if (keylen_bytes
== 0)
678 return Status::ErrorUnsupported();
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
,
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(),
706 &public_key_usage_mask
,
707 &private_key_usage_mask
);
708 if (status
.IsError())
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
,
726 public_key_usage_mask
,
727 private_key_usage_mask
,
728 params
->modulusLengthBits(),
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
,
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.
749 BestEffortCheckKeyUsagesForImport(algorithm
.id(), format
, usage_mask
);
750 if (status
.IsError())
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
);
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
) {
774 case blink::WebCryptoKeyFormatRaw
: {
775 platform::SymKey
* sym_key
;
776 Status status
= ToPlatformSymKey(key
, &sym_key
);
777 if (status
.IsError())
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())
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())
793 return platform::ExportKeyPkcs8(private_key
, key
.algorithm(), buffer
);
795 case blink::WebCryptoKeyFormatJwk
:
796 return ExportKeyJwk(key
, buffer
);
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
);
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
);
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
,
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.
896 BestEffortCheckKeyUsagesForImport(algorithm
.id(), format
, usage_mask
);
897 if (status
.IsError())
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
,
913 return UnwrapKeyDecryptAndImport(format
,
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
,
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
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
),
947 KeyAlgorithmToImportAlgorithm(algorithm
),
951 if (status
.IsError())
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();
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();
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();
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
),
987 return Status::ErrorCreateKeyBadUsages();
989 return Status::Success();
992 } // namespace webcrypto
994 } // namespace content