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 // 192-bit AES is disallowed.
44 return length_bits
== 128 || length_bits
== 256;
47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes
) {
48 // 192-bit AES is disallowed.
49 return length_bytes
== 16 || length_bytes
== 32;
52 const size_t kAesBlockSizeBytes
= 16;
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
);
64 const blink::WebCryptoAesCbcParams
* params
= algorithm
.aesCbcParams();
66 return Status::ErrorUnexpected();
68 CryptoData
iv(params
->iv().data(), params
->iv().size());
69 if (iv
.byte_length() != kAesBlockSizeBytes
)
70 return Status::ErrorIncorrectSizeAesCbcIv();
72 return platform::EncryptDecryptAesCbc(mode
, sym_key
, data
, iv
, buffer
);
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
);
85 const blink::WebCryptoAesGcmParams
* params
= algorithm
.aesGcmParams();
87 return Status::ErrorUnexpected();
89 unsigned int tag_length_bits
= 128;
90 if (params
->hasTagLengthBits())
91 tag_length_bits
= params
->optionalTagLengthBits();
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();
98 return platform::EncryptDecryptAesGcm(
102 CryptoData(params
->iv()),
103 CryptoData(params
->optionalAdditionalData()),
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())
117 const blink::WebCryptoRsaOaepParams
* params
= algorithm
.rsaOaepParams();
119 return Status::ErrorUnexpected();
121 return platform::EncryptRsaOaep(public_key
,
122 key
.algorithm().rsaHashedParams()->hash(),
123 CryptoData(params
->optionalLabel()),
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())
137 const blink::WebCryptoRsaOaepParams
* params
= algorithm
.rsaOaepParams();
139 return Status::ErrorUnexpected();
141 return platform::DecryptRsaOaep(private_key
,
142 key
.algorithm().rsaHashedParams()->hash(),
143 CryptoData(params
->optionalLabel()),
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())
157 return platform::SignHmac(
158 sym_key
, key
.algorithm().hmacParams()->hash(), data
, buffer
);
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())
171 // Do not allow verification of truncated MACs.
173 result
.size() == signature
.byte_length() &&
174 crypto::SecureMemEqual(
175 Uint8VectorStart(result
), signature
.bytes(), signature
.byte_length());
177 return Status::Success();
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())
189 return platform::SignRsaSsaPkcs1v1_5(
190 private_key
, key
.algorithm().rsaHashedParams()->hash(), data
, buffer
);
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())
203 return platform::VerifyRsaSsaPkcs1v1_5(
205 key
.algorithm().rsaHashedParams()->hash(),
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
,
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();
227 // Fallthrough intentional!
228 case blink::WebCryptoAlgorithmIdHmac
:
229 return platform::ImportKeyRaw(
230 algorithm
, key_data
, extractable
, usage_mask
, key
);
232 return Status::ErrorUnsupported();
236 // Returns the key format to use for structured cloning.
237 blink::WebCryptoKeyFormat
GetCloneFormatForKeyType(
238 blink::WebCryptoKeyType 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
;
249 return blink::WebCryptoKeyFormatRaw
;
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
:
268 return blink::WebCryptoAlgorithm::createNull();
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.
276 // A failure here implies either a bug in the code, or that the serialized data
278 bool ValidateDeserializedKey(const blink::WebCryptoKey
& key
,
279 const blink::WebCryptoKeyAlgorithm
& algorithm
,
280 blink::WebCryptoKeyType type
) {
281 if (algorithm
.id() != key
.algorithm().id())
284 if (key
.type() != type
)
287 switch (algorithm
.paramsType()) {
288 case blink::WebCryptoKeyAlgorithmParamsTypeAes
:
289 if (algorithm
.aesParams()->lengthBits() !=
290 key
.algorithm().aesParams()->lengthBits())
293 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed
:
294 if (algorithm
.rsaHashedParams()->modulusLengthBits() !=
295 key
.algorithm().rsaHashedParams()->modulusLengthBits())
297 if (algorithm
.rsaHashedParams()->publicExponent().size() !=
298 key
.algorithm().rsaHashedParams()->publicExponent().size())
300 if (memcmp(algorithm
.rsaHashedParams()->publicExponent().data(),
301 key
.algorithm().rsaHashedParams()->publicExponent().data(),
302 key
.algorithm().rsaHashedParams()->publicExponent().size()) !=
306 case blink::WebCryptoKeyAlgorithmParamsTypeNone
:
307 case blink::WebCryptoKeyAlgorithmParamsTypeHmac
:
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())
326 unsigned int min_length
= mode
== ENCRYPT
? 16 : 24;
328 if (data
.byte_length() < min_length
)
329 return Status::ErrorDataTooSmall();
330 if (data
.byte_length() % 8)
331 return Status::ErrorInvalidAesKwDataLength();
333 if (status
.IsError())
335 return platform::EncryptDecryptAesKw(mode
, sym_key
, data
, buffer
);
338 Status
DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm
& algorithm
,
339 const blink::WebCryptoKey
& key
,
340 const CryptoData
& data
,
341 std::vector
<uint8
>* buffer
) {
342 if (algorithm
.id() != key
.algorithm().id())
343 return Status::ErrorUnexpected();
344 switch (algorithm
.id()) {
345 case blink::WebCryptoAlgorithmIdAesCbc
:
346 return EncryptDecryptAesCbc(DECRYPT
, algorithm
, key
, data
, buffer
);
347 case blink::WebCryptoAlgorithmIdAesGcm
:
348 return EncryptDecryptAesGcm(DECRYPT
, algorithm
, key
, data
, buffer
);
349 case blink::WebCryptoAlgorithmIdRsaOaep
:
350 return DecryptRsaOaep(algorithm
, key
, data
, buffer
);
351 case blink::WebCryptoAlgorithmIdAesKw
:
352 return EncryptDecryptAesKw(DECRYPT
, algorithm
, key
, data
, buffer
);
354 return Status::ErrorUnsupported();
358 Status
EncryptDontCheckUsage(const blink::WebCryptoAlgorithm
& algorithm
,
359 const blink::WebCryptoKey
& key
,
360 const CryptoData
& data
,
361 std::vector
<uint8
>* buffer
) {
362 if (algorithm
.id() != key
.algorithm().id())
363 return Status::ErrorUnexpected();
364 switch (algorithm
.id()) {
365 case blink::WebCryptoAlgorithmIdAesCbc
:
366 return EncryptDecryptAesCbc(ENCRYPT
, algorithm
, key
, data
, buffer
);
367 case blink::WebCryptoAlgorithmIdAesGcm
:
368 return EncryptDecryptAesGcm(ENCRYPT
, algorithm
, key
, data
, buffer
);
369 case blink::WebCryptoAlgorithmIdAesKw
:
370 return EncryptDecryptAesKw(ENCRYPT
, algorithm
, key
, data
, buffer
);
371 case blink::WebCryptoAlgorithmIdRsaOaep
:
372 return EncryptRsaOaep(algorithm
, key
, data
, buffer
);
374 return Status::ErrorUnsupported();
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
,
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())
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
398 format
, CryptoData(buffer
), algorithm
, extractable
, usage_mask
, key
);
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())
411 return EncryptDontCheckUsage(
412 wrapping_algorithm
, wrapping_key
, CryptoData(exported_data
), buffer
);
415 // Returns the internal block size for SHA-*
416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id
) {
418 case blink::WebCryptoAlgorithmIdSha1
:
419 case blink::WebCryptoAlgorithmIdSha256
:
421 case blink::WebCryptoAlgorithmIdSha384
:
422 case blink::WebCryptoAlgorithmIdSha512
:
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
))
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
:
454 case blink::WebCryptoKeyTypePublic
:
455 return blink::WebCryptoKeyUsageVerify
;
456 case blink::WebCryptoKeyTypePrivate
:
457 return blink::WebCryptoKeyUsageSign
;
461 case blink::WebCryptoAlgorithmIdRsaOaep
:
463 case blink::WebCryptoKeyTypePublic
:
464 return blink::WebCryptoKeyUsageEncrypt
|
465 blink::WebCryptoKeyUsageWrapKey
;
466 case blink::WebCryptoKeyTypePrivate
:
467 return blink::WebCryptoKeyUsageDecrypt
|
468 blink::WebCryptoKeyUsageUnwrapKey
;
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
);
486 // Try to infer the key type given the import format.
488 case blink::WebCryptoKeyFormatRaw
:
489 // TODO(eroman): The spec defines Diffie-Hellman raw import for public
490 // keys, so this will need to be updated in the future when DH is
492 return Status::ErrorUnexpected();
493 case blink::WebCryptoKeyFormatSpki
:
494 return CheckKeyUsages(algorithm
, blink::WebCryptoKeyTypePublic
, usages
);
495 case blink::WebCryptoKeyFormatPkcs8
:
496 return CheckKeyUsages(algorithm
, blink::WebCryptoKeyTypePrivate
, usages
);
497 case blink::WebCryptoKeyFormatJwk
:
500 return Status::ErrorUnexpected();
503 // If the key type is not known, then the algorithm is asymmetric. Whether the
504 // key data describes a public or private key isn't known yet. But it must at
505 // least be ONE of those two.
506 DCHECK(IsAlgorithmAsymmetric(algorithm
));
508 if (CheckKeyUsages(algorithm
, blink::WebCryptoKeyTypePublic
, usages
)
510 CheckKeyUsages(algorithm
, blink::WebCryptoKeyTypePrivate
, usages
)
512 return Status::ErrorCreateKeyBadUsages();
515 return Status::Success();
518 // Returns an error if |combined_usage_mask| is invalid for generating a key
519 // pair for |algorithm|. Otherwise returns Status::Success(), and fills
520 // |public_key_usages| with the usages for the public key, and
521 // |private_key_usages| with those for the private key.
522 Status
CheckKeyUsagesForGenerateKeyPair(
523 blink::WebCryptoAlgorithmId algorithm
,
524 blink::WebCryptoKeyUsageMask combined_usage_mask
,
525 blink::WebCryptoKeyUsageMask
* public_key_usages
,
526 blink::WebCryptoKeyUsageMask
* private_key_usages
) {
527 DCHECK(IsAlgorithmAsymmetric(algorithm
));
529 blink::WebCryptoKeyUsageMask all_public_key_usages
=
530 GetValidKeyUsagesForKeyType(algorithm
, blink::WebCryptoKeyTypePublic
);
531 blink::WebCryptoKeyUsageMask all_private_key_usages
=
532 GetValidKeyUsagesForKeyType(algorithm
, blink::WebCryptoKeyTypePrivate
);
534 if (!ContainsKeyUsages(all_public_key_usages
| all_private_key_usages
,
535 combined_usage_mask
))
536 return Status::ErrorCreateKeyBadUsages();
538 *public_key_usages
= combined_usage_mask
& all_public_key_usages
;
539 *private_key_usages
= combined_usage_mask
& all_private_key_usages
;
541 return Status::Success();
544 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
546 bool BigIntegerToLong(const uint8
* data
,
547 unsigned int data_size
,
548 unsigned long* result
) {
549 // TODO(padolph): Is it correct to say that empty data is an error, or does it
550 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
555 for (size_t i
= 0; i
< data_size
; ++i
) {
556 size_t reverse_i
= data_size
- i
- 1;
558 if (reverse_i
>= sizeof(unsigned long) && data
[i
])
559 return false; // Too large for a long.
561 *result
|= data
[i
] << 8 * reverse_i
;
569 void Init() { platform::Init(); }
571 Status
Encrypt(const blink::WebCryptoAlgorithm
& algorithm
,
572 const blink::WebCryptoKey
& key
,
573 const CryptoData
& data
,
574 std::vector
<uint8
>* buffer
) {
575 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageEncrypt
))
576 return Status::ErrorUnexpected();
577 return EncryptDontCheckUsage(algorithm
, key
, data
, buffer
);
580 Status
Decrypt(const blink::WebCryptoAlgorithm
& algorithm
,
581 const blink::WebCryptoKey
& key
,
582 const CryptoData
& data
,
583 std::vector
<uint8
>* buffer
) {
584 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageDecrypt
))
585 return Status::ErrorUnexpected();
586 return DecryptDontCheckKeyUsage(algorithm
, key
, data
, buffer
);
589 Status
Digest(const blink::WebCryptoAlgorithm
& algorithm
,
590 const CryptoData
& data
,
591 std::vector
<uint8
>* buffer
) {
592 switch (algorithm
.id()) {
593 case blink::WebCryptoAlgorithmIdSha1
:
594 case blink::WebCryptoAlgorithmIdSha256
:
595 case blink::WebCryptoAlgorithmIdSha384
:
596 case blink::WebCryptoAlgorithmIdSha512
:
597 return platform::DigestSha(algorithm
.id(), data
, buffer
);
599 return Status::ErrorUnsupported();
603 scoped_ptr
<blink::WebCryptoDigestor
> CreateDigestor(
604 blink::WebCryptoAlgorithmId algorithm
) {
605 return platform::CreateDigestor(algorithm
);
608 Status
GenerateSecretKey(const blink::WebCryptoAlgorithm
& algorithm
,
610 blink::WebCryptoKeyUsageMask usage_mask
,
611 blink::WebCryptoKey
* key
) {
613 CheckKeyUsages(algorithm
.id(), blink::WebCryptoKeyTypeSecret
, usage_mask
);
614 if (status
.IsError())
617 unsigned int keylen_bytes
= 0;
619 // Get the secret key length in bytes from generation parameters.
620 // This resolves any defaults.
621 switch (algorithm
.id()) {
622 case blink::WebCryptoAlgorithmIdAesCbc
:
623 case blink::WebCryptoAlgorithmIdAesGcm
:
624 case blink::WebCryptoAlgorithmIdAesKw
: {
625 if (!IsValidAesKeyLengthBits(algorithm
.aesKeyGenParams()->lengthBits())) {
626 return algorithm
.aesKeyGenParams()->lengthBits() == 192
627 ? Status::ErrorAes192BitUnsupported()
628 : Status::ErrorGenerateKeyLength();
630 keylen_bytes
= algorithm
.aesKeyGenParams()->lengthBits() / 8;
633 case blink::WebCryptoAlgorithmIdHmac
: {
634 const blink::WebCryptoHmacKeyGenParams
* params
=
635 algorithm
.hmacKeyGenParams();
637 if (params
->hasLengthBits()) {
638 if (params
->optionalLengthBits() % 8)
639 return Status::ErrorGenerateKeyLength();
640 keylen_bytes
= params
->optionalLengthBits() / 8;
642 keylen_bytes
= ShaBlockSizeBytes(params
->hash().id());
643 if (keylen_bytes
== 0)
644 return Status::ErrorUnsupported();
650 return Status::ErrorUnsupported();
653 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
654 // probably be able to allowed to generate them too.
655 if (keylen_bytes
== 0)
656 return Status::ErrorGenerateKeyLength();
658 return platform::GenerateSecretKey(
659 algorithm
, extractable
, usage_mask
, keylen_bytes
, key
);
662 Status
GenerateKeyPair(const blink::WebCryptoAlgorithm
& algorithm
,
664 blink::WebCryptoKeyUsageMask combined_usage_mask
,
665 blink::WebCryptoKey
* public_key
,
666 blink::WebCryptoKey
* private_key
) {
667 blink::WebCryptoKeyUsageMask public_key_usage_mask
= 0;
668 blink::WebCryptoKeyUsageMask private_key_usage_mask
= 0;
670 Status status
= CheckKeyUsagesForGenerateKeyPair(algorithm
.id(),
672 &public_key_usage_mask
,
673 &private_key_usage_mask
);
674 if (status
.IsError())
677 // TODO(padolph): Handle other asymmetric algorithm key generation.
678 switch (algorithm
.paramsType()) {
679 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams
: {
680 const blink::WebCryptoRsaHashedKeyGenParams
* params
=
681 algorithm
.rsaHashedKeyGenParams();
683 if (!params
->modulusLengthBits())
684 return Status::ErrorGenerateRsaZeroModulus();
686 unsigned long public_exponent
= 0;
687 if (!BigIntegerToLong(params
->publicExponent().data(),
688 params
->publicExponent().size(),
690 (public_exponent
!= 3 && public_exponent
!= 65537)) {
691 return Status::ErrorGenerateKeyPublicExponent();
694 return platform::GenerateRsaKeyPair(algorithm
,
696 public_key_usage_mask
,
697 private_key_usage_mask
,
698 params
->modulusLengthBits(),
704 return Status::ErrorUnsupported();
708 // Note that this function may be called from the target Blink thread.
709 Status
ImportKey(blink::WebCryptoKeyFormat format
,
710 const CryptoData
& key_data
,
711 const blink::WebCryptoAlgorithm
& algorithm
,
713 blink::WebCryptoKeyUsageMask usage_mask
,
714 blink::WebCryptoKey
* key
) {
715 // This is "best effort" because it is incomplete for JWK (for which the key
716 // type is not yet known). ImportKeyJwk() does extra checks on key usage once
717 // the key type has been determined.
719 BestEffortCheckKeyUsagesForImport(algorithm
.id(), format
, usage_mask
);
720 if (status
.IsError())
724 case blink::WebCryptoKeyFormatRaw
:
725 return ImportKeyRaw(key_data
, algorithm
, extractable
, usage_mask
, key
);
726 case blink::WebCryptoKeyFormatSpki
:
727 return platform::ImportKeySpki(
728 algorithm
, key_data
, extractable
, usage_mask
, key
);
729 case blink::WebCryptoKeyFormatPkcs8
:
730 return platform::ImportKeyPkcs8(
731 algorithm
, key_data
, extractable
, usage_mask
, key
);
732 case blink::WebCryptoKeyFormatJwk
:
733 return ImportKeyJwk(key_data
, algorithm
, extractable
, usage_mask
, key
);
735 return Status::ErrorUnsupported();
739 // TODO(eroman): Move this to anonymous namespace.
740 Status
ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format
,
741 const blink::WebCryptoKey
& key
,
742 std::vector
<uint8
>* buffer
) {
744 case blink::WebCryptoKeyFormatRaw
: {
745 platform::SymKey
* sym_key
;
746 Status status
= ToPlatformSymKey(key
, &sym_key
);
747 if (status
.IsError())
749 return platform::ExportKeyRaw(sym_key
, buffer
);
751 case blink::WebCryptoKeyFormatSpki
: {
752 platform::PublicKey
* public_key
;
753 Status status
= ToPlatformPublicKey(key
, &public_key
);
754 if (status
.IsError())
756 return platform::ExportKeySpki(public_key
, buffer
);
758 case blink::WebCryptoKeyFormatPkcs8
: {
759 platform::PrivateKey
* private_key
;
760 Status status
= ToPlatformPrivateKey(key
, &private_key
);
761 if (status
.IsError())
763 return platform::ExportKeyPkcs8(private_key
, key
.algorithm(), buffer
);
765 case blink::WebCryptoKeyFormatJwk
:
766 return ExportKeyJwk(key
, buffer
);
768 return Status::ErrorUnsupported();
772 Status
ExportKey(blink::WebCryptoKeyFormat format
,
773 const blink::WebCryptoKey
& key
,
774 std::vector
<uint8
>* buffer
) {
775 if (!key
.extractable())
776 return Status::ErrorKeyNotExtractable();
777 return ExportKeyDontCheckExtractability(format
, key
, buffer
);
780 Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
781 const blink::WebCryptoKey
& key
,
782 const CryptoData
& data
,
783 std::vector
<uint8
>* buffer
) {
784 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageSign
))
785 return Status::ErrorUnexpected();
786 if (algorithm
.id() != key
.algorithm().id())
787 return Status::ErrorUnexpected();
789 switch (algorithm
.id()) {
790 case blink::WebCryptoAlgorithmIdHmac
:
791 return SignHmac(algorithm
, key
, data
, buffer
);
792 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
:
793 return SignRsaSsaPkcs1v1_5(algorithm
, key
, data
, buffer
);
795 return Status::ErrorUnsupported();
799 Status
VerifySignature(const blink::WebCryptoAlgorithm
& algorithm
,
800 const blink::WebCryptoKey
& key
,
801 const CryptoData
& signature
,
802 const CryptoData
& data
,
803 bool* signature_match
) {
804 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageVerify
))
805 return Status::ErrorUnexpected();
806 if (algorithm
.id() != key
.algorithm().id())
807 return Status::ErrorUnexpected();
809 if (!signature
.byte_length()) {
810 // None of the algorithms generate valid zero-length signatures so this
811 // will necessarily fail verification. Early return to protect
812 // implementations from dealing with a NULL signature pointer.
813 *signature_match
= false;
814 return Status::Success();
817 switch (algorithm
.id()) {
818 case blink::WebCryptoAlgorithmIdHmac
:
819 return VerifyHmac(algorithm
, key
, signature
, data
, signature_match
);
820 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
:
821 return VerifyRsaSsaPkcs1v1_5(
822 algorithm
, key
, signature
, data
, signature_match
);
824 return Status::ErrorUnsupported();
828 Status
WrapKey(blink::WebCryptoKeyFormat format
,
829 const blink::WebCryptoKey
& key_to_wrap
,
830 const blink::WebCryptoKey
& wrapping_key
,
831 const blink::WebCryptoAlgorithm
& wrapping_algorithm
,
832 std::vector
<uint8
>* buffer
) {
833 if (!KeyUsageAllows(wrapping_key
, blink::WebCryptoKeyUsageWrapKey
))
834 return Status::ErrorUnexpected();
835 if (wrapping_algorithm
.id() != wrapping_key
.algorithm().id())
836 return Status::ErrorUnexpected();
838 return WrapKeyExportAndEncrypt(
839 format
, key_to_wrap
, wrapping_key
, wrapping_algorithm
, buffer
);
842 Status
UnwrapKey(blink::WebCryptoKeyFormat format
,
843 const CryptoData
& wrapped_key_data
,
844 const blink::WebCryptoKey
& wrapping_key
,
845 const blink::WebCryptoAlgorithm
& wrapping_algorithm
,
846 const blink::WebCryptoAlgorithm
& algorithm
,
848 blink::WebCryptoKeyUsageMask usage_mask
,
849 blink::WebCryptoKey
* key
) {
850 if (!KeyUsageAllows(wrapping_key
, blink::WebCryptoKeyUsageUnwrapKey
))
851 return Status::ErrorUnexpected();
852 if (wrapping_algorithm
.id() != wrapping_key
.algorithm().id())
853 return Status::ErrorUnexpected();
855 // Fail-fast if the key usages don't make sense. This avoids decrypting the
856 // key only to then have import fail. It is "best effort" because when
857 // unwrapping JWK for asymmetric algorithms the key type isn't known yet.
859 BestEffortCheckKeyUsagesForImport(algorithm
.id(), format
, usage_mask
);
860 if (status
.IsError())
863 return UnwrapKeyDecryptAndImport(format
,
873 // Note that this function is called from the target Blink thread.
874 bool SerializeKeyForClone(const blink::WebCryptoKey
& key
,
875 blink::WebVector
<uint8
>* key_data
) {
876 return static_cast<webcrypto::platform::Key
*>(key
.handle())
877 ->ThreadSafeSerializeForClone(key_data
);
880 // Note that this function is called from the target Blink thread.
881 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
882 blink::WebCryptoKeyType type
,
884 blink::WebCryptoKeyUsageMask usage_mask
,
885 const CryptoData
& key_data
,
886 blink::WebCryptoKey
* key
) {
887 // TODO(eroman): This should not call into the platform crypto layer.
888 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks
891 // An alternate approach is to defer the key import until the key is used.
892 // However this means that any deserialization errors would have to be
893 // surfaced as WebCrypto errors, leading to slightly different behaviors. For
894 // instance you could clone a key which fails to be deserialized.
895 Status status
= ImportKey(GetCloneFormatForKeyType(type
),
897 KeyAlgorithmToImportAlgorithm(algorithm
),
901 if (status
.IsError())
903 return ValidateDeserializedKey(*key
, algorithm
, type
);
906 Status
ToPlatformSymKey(const blink::WebCryptoKey
& key
,
907 platform::SymKey
** out
) {
908 *out
= static_cast<platform::Key
*>(key
.handle())->AsSymKey();
910 return Status::ErrorUnexpectedKeyType();
911 return Status::Success();
914 Status
ToPlatformPublicKey(const blink::WebCryptoKey
& key
,
915 platform::PublicKey
** out
) {
916 *out
= static_cast<platform::Key
*>(key
.handle())->AsPublicKey();
918 return Status::ErrorUnexpectedKeyType();
919 return Status::Success();
922 Status
ToPlatformPrivateKey(const blink::WebCryptoKey
& key
,
923 platform::PrivateKey
** out
) {
924 *out
= static_cast<platform::Key
*>(key
.handle())->AsPrivateKey();
926 return Status::ErrorUnexpectedKeyType();
927 return Status::Success();
930 // Returns Status::Success() if |usages| is a valid set of key usages for
931 // |algorithm| and |key_type|. Otherwise returns an error.
932 Status
CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm
,
933 blink::WebCryptoKeyType key_type
,
934 blink::WebCryptoKeyUsageMask usages
) {
935 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm
, key_type
),
937 return Status::ErrorCreateKeyBadUsages();
939 return Status::Success();
942 } // namespace webcrypto
944 } // namespace content