Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
| 6 | 6 |
| 7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
| 8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
| 9 #include <sechash.h> | 9 #include <sechash.h> |
| 10 | 10 |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 if (result != SECSuccess) | 365 if (result != SECSuccess) |
| 366 return false; | 366 return false; |
| 367 | 367 |
| 368 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug | 368 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug |
| 369 // above). | 369 // above). |
| 370 webcrypto::ShrinkBuffer(buffer, output_len); | 370 webcrypto::ShrinkBuffer(buffer, output_len); |
| 371 | 371 |
| 372 return true; | 372 return true; |
| 373 } | 373 } |
| 374 | 374 |
| 375 // Constants for RFC 3394 AES Key Wrap / Unwrap. | |
| 376 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP; | |
|
Ryan Sleevi
2014/01/16 23:41:15
I don't see there being any benefit from adding th
padolph
2014/02/19 03:55:43
Done.
| |
| 377 // The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1. | |
| 378 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; | |
|
Ryan Sleevi
2014/01/16 23:41:15
You can make this a function-local const.
padolph
2014/02/19 03:55:43
This is used in two separate functions. I don't wa
| |
| 379 | |
| 380 // Performs RFC 3394 AES Key Wrap (encryption) of the input data. | |
| 381 bool AesKwEncrypt( | |
| 382 const blink::WebCryptoKey& key, | |
| 383 const unsigned char* data, | |
| 384 unsigned data_size, | |
| 385 blink::WebArrayBuffer* buffer) { | |
|
Ryan Sleevi
2014/01/16 23:41:15
From an API design perspective, having the AES-KW
| |
| 386 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 387 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 388 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages()); | |
| 389 | |
| 390 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
| 391 if (data_size < 16 || data_size % 8) | |
| 392 return false; | |
| 393 DCHECK(data); | |
|
Ryan Sleevi
2014/01/16 23:41:15
Why not DCHECK on line 389?
padolph
2014/02/19 03:55:43
Eric prefers this pattern. You won't hit the check
| |
| 394 | |
| 395 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
| 396 arraysize(kAesIv)}; | |
| 397 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
| 398 DCHECK(param_item); | |
| 399 | |
| 400 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS | |
| 401 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a | |
| 402 // generic secret blob, since we can't be certain what it is at this point. | |
|
Ryan Sleevi
2014/01/16 23:41:15
Pronouns considered harmful: https://groups.google
padolph
2014/02/19 03:55:43
Done.
| |
| 403 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 404 crypto::ScopedPK11SymKey key_to_be_wrapped( | |
| 405 PK11_ImportSymKey(PK11_GetInternalSlot(), | |
| 406 CKK_GENERIC_SECRET, | |
| 407 PK11_OriginGenerated, | |
| 408 CKA_ENCRYPT, | |
| 409 &data_item, | |
| 410 0)); | |
| 411 if (!key_to_be_wrapped) | |
| 412 return false; | |
| 413 | |
| 414 // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not | |
| 415 // specify a maximum allowed data length, but since we are only wrapping keys, | |
| 416 // which are usually small, a reasonable max size is whatever will fit into an | |
| 417 // unsigned. | |
| 418 if (data_size > UINT_MAX - 8) | |
| 419 return false; | |
| 420 const unsigned int output_length = data_size + 8; | |
| 421 | |
| 422 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
| 423 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
| 424 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
| 425 | |
| 426 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 427 | |
| 428 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism, | |
| 429 param_item.get(), | |
| 430 wrapping_key->key(), | |
| 431 key_to_be_wrapped.get(), | |
| 432 &wrapped_key_item)) { | |
| 433 return false; | |
| 434 } | |
| 435 if (output_length != wrapped_key_item.len) { | |
| 436 buffer->reset(); | |
| 437 return false; | |
| 438 } | |
| 439 | |
| 440 return true; | |
| 441 } | |
| 442 | |
| 443 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data. | |
| 444 bool AesKwDecrypt( | |
| 445 const blink::WebCryptoKey& key, | |
| 446 const unsigned char* data, | |
| 447 unsigned data_size, | |
| 448 blink::WebArrayBuffer* buffer) { | |
| 449 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 450 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 451 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages()); | |
| 452 | |
| 453 // The ciphertext data size must be at least 24 bytes and a multiple of | |
| 454 // 8 bytes. | |
| 455 if (data_size < 24 || data_size % 8 != 0) | |
| 456 return false; | |
| 457 DCHECK(data); | |
| 458 | |
| 459 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 460 | |
| 461 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
| 462 arraysize(kAesIv)}; | |
| 463 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
| 464 DCHECK(param_item); | |
| 465 | |
| 466 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 467 | |
| 468 // The plaintext length is always 64 bits less than the data size. | |
| 469 const unsigned int plaintext_length = data_size - 8; | |
| 470 | |
| 471 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey( | |
| 472 wrapping_key->key(), | |
| 473 kAesKwMechanism, | |
| 474 param_item.get(), | |
| 475 &cipher_text, | |
| 476 CKK_GENERIC_SECRET, // Import the key material without knowing its kind. | |
| 477 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key. | |
| 478 plaintext_length)); | |
| 479 if (!unwrapped_key) | |
| 480 return false; | |
| 481 | |
| 482 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess) | |
| 483 return false; | |
| 484 | |
| 485 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get()); | |
| 486 if (!key_data || key_data->len != plaintext_length) | |
| 487 return false; | |
| 488 | |
| 489 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
| 490 | |
| 491 return true; | |
| 492 } | |
| 493 | |
| 375 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 494 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
| 376 const blink::WebCryptoAlgorithm& algorithm) { | 495 const blink::WebCryptoAlgorithm& algorithm) { |
| 377 switch (algorithm.id()) { | 496 switch (algorithm.id()) { |
| 378 case blink::WebCryptoAlgorithmIdAesCbc: | 497 case blink::WebCryptoAlgorithmIdAesCbc: |
| 379 case blink::WebCryptoAlgorithmIdAesGcm: | 498 case blink::WebCryptoAlgorithmIdAesGcm: |
| 380 case blink::WebCryptoAlgorithmIdAesKw: | 499 case blink::WebCryptoAlgorithmIdAesKw: |
| 381 return CKM_AES_KEY_GEN; | 500 return CKM_AES_KEY_GEN; |
| 382 case blink::WebCryptoAlgorithmIdHmac: | 501 case blink::WebCryptoAlgorithmIdHmac: |
| 383 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); | 502 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); |
| 384 default: | 503 default: |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 DCHECK(key.handle()); | 822 DCHECK(key.handle()); |
| 704 DCHECK(buffer); | 823 DCHECK(buffer); |
| 705 | 824 |
| 706 // TODO(eroman): Use a switch() statement. | 825 // TODO(eroman): Use a switch() statement. |
| 707 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 826 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 708 return AesCbcEncryptDecrypt( | 827 return AesCbcEncryptDecrypt( |
| 709 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | 828 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
| 710 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { | 829 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { |
| 711 return AesGcmEncryptDecrypt( | 830 return AesGcmEncryptDecrypt( |
| 712 true, algorithm, key, data, data_size, buffer); | 831 true, algorithm, key, data, data_size, buffer); |
| 832 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
| 833 return AesKwEncrypt(key, data, data_size, buffer); | |
| 713 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 834 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
| 714 | 835 |
| 715 // RSAES encryption does not support empty input | 836 // RSAES encryption does not support empty input |
| 716 if (!data_size) | 837 if (!data_size) |
| 717 return false; | 838 return false; |
| 718 DCHECK(data); | 839 DCHECK(data); |
| 719 | 840 |
| 720 if (key.type() != blink::WebCryptoKeyTypePublic) | 841 if (key.type() != blink::WebCryptoKeyTypePublic) |
| 721 return false; | 842 return false; |
| 722 | 843 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 759 DCHECK(key.handle()); | 880 DCHECK(key.handle()); |
| 760 DCHECK(buffer); | 881 DCHECK(buffer); |
| 761 | 882 |
| 762 // TODO(eroman): Use a switch() statement. | 883 // TODO(eroman): Use a switch() statement. |
| 763 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 884 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 764 return AesCbcEncryptDecrypt( | 885 return AesCbcEncryptDecrypt( |
| 765 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | 886 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
| 766 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { | 887 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { |
| 767 return AesGcmEncryptDecrypt( | 888 return AesGcmEncryptDecrypt( |
| 768 false, algorithm, key, data, data_size, buffer); | 889 false, algorithm, key, data, data_size, buffer); |
| 890 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
| 891 return AesKwDecrypt(key, data, data_size, buffer); | |
| 769 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 892 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
| 770 | 893 |
| 771 // RSAES decryption does not support empty input | 894 // RSAES decryption does not support empty input |
| 772 if (!data_size) | 895 if (!data_size) |
| 773 return false; | 896 return false; |
| 774 DCHECK(data); | 897 DCHECK(data); |
| 775 | 898 |
| 776 if (key.type() != blink::WebCryptoKeyTypePrivate) | 899 if (key.type() != blink::WebCryptoKeyTypePrivate) |
| 777 return false; | 900 return false; |
| 778 | 901 |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1201 | 1324 |
| 1202 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1325 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
| 1203 blink::WebCryptoKeyTypePublic, | 1326 blink::WebCryptoKeyTypePublic, |
| 1204 extractable, | 1327 extractable, |
| 1205 algorithm, | 1328 algorithm, |
| 1206 usage_mask); | 1329 usage_mask); |
| 1207 return true; | 1330 return true; |
| 1208 } | 1331 } |
| 1209 | 1332 |
| 1210 } // namespace content | 1333 } // namespace content |
| OLD | NEW |