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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 buffer_data + output_len, | 168 buffer_data + output_len, |
| 169 &final_output_chunk_len, | 169 &final_output_chunk_len, |
| 170 output_max_len - output_len)) { | 170 output_max_len - output_len)) { |
| 171 return false; | 171 return false; |
| 172 } | 172 } |
| 173 | 173 |
| 174 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 174 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
| 175 return true; | 175 return true; |
| 176 } | 176 } |
| 177 | 177 |
| 178 // The RFC 3394 AES Key Wrap / Unwrap Mechanism. | |
| 179 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP; | |
| 180 | |
| 181 // Creates an NSS SECItem representing the Default IV specified for AES Key | |
| 182 // Wrap. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1. | |
| 183 crypto::ScopedSECItem CreateAesKwIvItem() { | |
| 184 const unsigned int kAesKwIvLength = 8; | |
|
eroman
2013/12/20 01:58:14
Can you instead define this in terms of:
arraysi
padolph
2013/12/23 19:58:33
Done.
| |
| 185 const unsigned char kAesIv[kAesKwIvLength] = {0xA6, 0xA6, 0xA6, 0xA6, | |
| 186 0xA6, 0xA6, 0xA6, 0xA6}; | |
| 187 SECItem iv_item = | |
| 188 {siBuffer, const_cast<unsigned char*>(kAesIv), kAesKwIvLength}; | |
| 189 SECItem* param_item = PK11_ParamFromIV(kAesKwMechanism, &iv_item); | |
|
eroman
2013/12/20 01:58:14
I will have to verify this, but my expectation is
padolph
2013/12/23 19:58:33
This function was not saving too much code duplica
| |
| 190 DCHECK(param_item); | |
| 191 return crypto::ScopedSECItem(param_item); | |
| 192 } | |
| 193 | |
| 194 // Performs RFC 3394 AES Key Wrap (encryption) of the input data. | |
| 195 bool AesKwEncrypt( | |
| 196 const blink::WebCryptoKey& key, | |
| 197 const unsigned char* data, | |
| 198 unsigned data_size, | |
| 199 blink::WebArrayBuffer* buffer) { | |
| 200 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 201 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 202 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages()); | |
| 203 | |
| 204 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
| 205 // TODO(padolph): Should this be a DCHECK() instead? | |
|
eroman
2013/12/20 01:58:14
This must be a runtime check since blink layer doe
padolph
2013/12/23 19:58:33
Done.
| |
| 206 if (data_size < 16 || data_size % 8) | |
| 207 return false; | |
| 208 DCHECK(data); | |
| 209 | |
| 210 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS | |
| 211 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a | |
| 212 // generic secret blob, since we can't be certain what it is at this point. | |
| 213 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 214 crypto::ScopedPK11SymKey key_to_be_wrapped( | |
| 215 PK11_ImportSymKey(PK11_GetInternalSlot(), | |
| 216 CKK_GENERIC_SECRET, | |
| 217 PK11_OriginGenerated, | |
| 218 CKA_ENCRYPT, | |
| 219 &data_item, | |
| 220 0)); | |
| 221 if (!key_to_be_wrapped) | |
| 222 return false; | |
| 223 | |
| 224 // AES Key Wrap always adds 8 bytes to the input data size. | |
| 225 const unsigned int output_length = data_size + 8; | |
|
eroman
2013/12/20 01:58:14
Paranoia: possibility of integer overflow? I shoul
padolph
2013/12/23 19:58:33
RFC 3394 does not specify the max allowed input le
| |
| 226 | |
| 227 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
| 228 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
| 229 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
| 230 | |
| 231 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 232 | |
| 233 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism, | |
| 234 CreateAesKwIvItem().get(), | |
| 235 wrapping_key->key(), | |
| 236 key_to_be_wrapped.get(), | |
| 237 &wrapped_key_item)) { | |
| 238 return false; | |
| 239 } | |
| 240 DCHECK_EQ(output_length, wrapped_key_item.len); | |
|
eroman
2013/12/20 01:58:14
Please make this a runtime check and fail if they
padolph
2013/12/23 19:58:33
Done.
| |
| 241 | |
| 242 return true; | |
| 243 } | |
| 244 | |
| 245 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data. | |
| 246 bool AesKwDecrypt( | |
| 247 const blink::WebCryptoKey& key, | |
| 248 const unsigned char* data, | |
| 249 unsigned data_size, | |
| 250 blink::WebArrayBuffer* buffer) { | |
| 251 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
| 252 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 253 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages()); | |
| 254 | |
| 255 // The ciphertext data size must be at least 24 bytes and a multiple of | |
| 256 // 8 bytes. This is a DCHECK() because this function is not callable with | |
| 257 // arbitrary data: it only receives data representing an assumed-good internal | |
| 258 // key to be wrapped. | |
| 259 DCHECK(data_size >= 24 && data_size % 8 == 0); | |
| 260 DCHECK(data); | |
| 261 | |
| 262 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 263 | |
| 264 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
| 265 | |
| 266 // The plaintext length is always 64 bits less than the data size. | |
| 267 const unsigned int plaintext_length = data_size - 8; | |
|
eroman
2013/12/20 01:58:14
Isn't it possible to have 0-length keys? In fact w
padolph
2013/12/23 19:58:33
Done.
| |
| 268 | |
| 269 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey( | |
| 270 wrapping_key->key(), | |
| 271 kAesKwMechanism, | |
| 272 CreateAesKwIvItem().get(), | |
| 273 &cipher_text, | |
| 274 CKK_GENERIC_SECRET, // Import the key material without knowing its kind. | |
| 275 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key. | |
| 276 plaintext_length)); | |
| 277 if (!unwrapped_key) | |
| 278 return false; | |
| 279 | |
| 280 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess) | |
| 281 return false; | |
| 282 | |
| 283 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get()); | |
| 284 if (!key_data) | |
| 285 return false; | |
| 286 DCHECK_EQ(plaintext_length, key_data->len); | |
| 287 | |
| 288 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
| 289 | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 178 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism( | 293 CK_MECHANISM_TYPE HmacAlgorithmToGenMechanism( |
| 179 const blink::WebCryptoAlgorithm& algorithm) { | 294 const blink::WebCryptoAlgorithm& algorithm) { |
| 180 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac); | 295 DCHECK_EQ(algorithm.id(), blink::WebCryptoAlgorithmIdHmac); |
| 181 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); | 296 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); |
| 182 DCHECK(params); | 297 DCHECK(params); |
| 183 switch (params->hash().id()) { | 298 switch (params->hash().id()) { |
| 184 case blink::WebCryptoAlgorithmIdSha1: | 299 case blink::WebCryptoAlgorithmIdSha1: |
| 185 return CKM_SHA_1_HMAC; | 300 return CKM_SHA_1_HMAC; |
| 186 case blink::WebCryptoAlgorithmIdSha256: | 301 case blink::WebCryptoAlgorithmIdSha256: |
| 187 return CKM_SHA256_HMAC; | 302 return CKM_SHA256_HMAC; |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 518 const blink::WebCryptoAlgorithm& algorithm, | 633 const blink::WebCryptoAlgorithm& algorithm, |
| 519 const blink::WebCryptoKey& key, | 634 const blink::WebCryptoKey& key, |
| 520 const unsigned char* data, | 635 const unsigned char* data, |
| 521 unsigned data_size, | 636 unsigned data_size, |
| 522 blink::WebArrayBuffer* buffer) { | 637 blink::WebArrayBuffer* buffer) { |
| 523 | 638 |
| 524 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 639 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 525 DCHECK(key.handle()); | 640 DCHECK(key.handle()); |
| 526 DCHECK(buffer); | 641 DCHECK(buffer); |
| 527 | 642 |
| 528 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 643 switch (algorithm.id()) { |
|
eroman
2013/12/20 01:58:14
switching to a switch statement would best be left
padolph
2013/12/23 19:58:33
Reverted and added a TODO.
| |
| 529 return AesCbcEncryptDecrypt( | 644 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 530 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | 645 return AesCbcEncryptDecrypt( |
| 531 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 646 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
| 647 } | |
| 648 case blink::WebCryptoAlgorithmIdAesKw: { | |
| 649 return AesKwEncrypt(key, data, data_size, buffer); | |
| 650 } | |
| 651 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: { | |
| 652 // RSAES encryption does not support empty input | |
| 653 if (!data_size) | |
| 654 return false; | |
| 655 DCHECK(data); | |
| 532 | 656 |
| 533 // RSAES encryption does not support empty input | 657 if (key.type() != blink::WebCryptoKeyTypePublic) |
| 534 if (!data_size) | 658 return false; |
| 535 return false; | |
| 536 DCHECK(data); | |
| 537 | 659 |
| 538 if (key.type() != blink::WebCryptoKeyTypePublic) | 660 PublicKeyHandle* const public_key = |
| 539 return false; | 661 reinterpret_cast<PublicKeyHandle*>(key.handle()); |
| 540 | 662 |
| 541 PublicKeyHandle* const public_key = | 663 const unsigned encrypted_length_bytes = |
| 542 reinterpret_cast<PublicKeyHandle*>(key.handle()); | 664 SECKEY_PublicKeyStrength(public_key->key()); |
| 543 | 665 |
| 544 const unsigned encrypted_length_bytes = | 666 // RSAES can operate on messages up to a length of k - 11, where k is the |
| 545 SECKEY_PublicKeyStrength(public_key->key()); | 667 // octet length of the RSA modulus. |
| 668 if (encrypted_length_bytes < 11 || | |
| 669 encrypted_length_bytes - 11 < data_size) { | |
| 670 return false; | |
| 671 } | |
| 546 | 672 |
| 547 // RSAES can operate on messages up to a length of k - 11, where k is the | 673 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); |
| 548 // octet length of the RSA modulus. | 674 unsigned char* const buffer_data = |
| 549 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) | 675 reinterpret_cast<unsigned char*>(buffer->data()); |
| 550 return false; | |
| 551 | 676 |
| 552 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); | 677 if (PK11_PubEncryptPKCS1(public_key->key(), |
| 553 unsigned char* const buffer_data = | 678 buffer_data, |
| 554 reinterpret_cast<unsigned char*>(buffer->data()); | 679 const_cast<unsigned char*>(data), |
| 555 | 680 data_size, |
| 556 if (PK11_PubEncryptPKCS1(public_key->key(), | 681 NULL) != SECSuccess) { |
| 557 buffer_data, | 682 return false; |
| 558 const_cast<unsigned char*>(data), | 683 } |
| 559 data_size, | 684 return true; |
| 560 NULL) != SECSuccess) { | 685 } |
| 686 default: { | |
| 561 return false; | 687 return false; |
| 562 } | 688 } |
| 563 return true; | |
| 564 } | 689 } |
| 565 | |
| 566 return false; | |
| 567 } | 690 } |
| 568 | 691 |
| 569 bool WebCryptoImpl::DecryptInternal( | 692 bool WebCryptoImpl::DecryptInternal( |
| 570 const blink::WebCryptoAlgorithm& algorithm, | 693 const blink::WebCryptoAlgorithm& algorithm, |
| 571 const blink::WebCryptoKey& key, | 694 const blink::WebCryptoKey& key, |
| 572 const unsigned char* data, | 695 const unsigned char* data, |
| 573 unsigned data_size, | 696 unsigned data_size, |
| 574 blink::WebArrayBuffer* buffer) { | 697 blink::WebArrayBuffer* buffer) { |
| 575 | 698 |
| 576 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 699 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 577 DCHECK(key.handle()); | 700 DCHECK(key.handle()); |
| 578 DCHECK(buffer); | 701 DCHECK(buffer); |
| 579 | 702 |
| 580 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 703 switch (algorithm.id()) { |
|
eroman
2013/12/20 01:58:14
Same comment.
padolph
2013/12/23 19:58:33
Reverted and added a TODO.
| |
| 581 return AesCbcEncryptDecrypt( | 704 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 582 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | 705 return AesCbcEncryptDecrypt( |
| 583 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 706 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
| 707 } | |
| 708 case blink::WebCryptoAlgorithmIdAesKw: { | |
| 709 return AesKwDecrypt(key, data, data_size, buffer); | |
| 710 } | |
| 711 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: { | |
| 712 // RSAES decryption does not support empty input | |
| 713 if (!data_size) | |
| 714 return false; | |
| 715 DCHECK(data); | |
| 584 | 716 |
| 585 // RSAES decryption does not support empty input | 717 if (key.type() != blink::WebCryptoKeyTypePrivate) |
| 586 if (!data_size) | 718 return false; |
| 587 return false; | |
| 588 DCHECK(data); | |
| 589 | 719 |
| 590 if (key.type() != blink::WebCryptoKeyTypePrivate) | 720 PrivateKeyHandle* const private_key = |
| 591 return false; | 721 reinterpret_cast<PrivateKeyHandle*>(key.handle()); |
| 592 | 722 |
| 593 PrivateKeyHandle* const private_key = | 723 const int modulus_length_bytes = |
| 594 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | 724 PK11_GetPrivateModulusLen(private_key->key()); |
| 725 if (modulus_length_bytes <= 0) | |
| 726 return false; | |
| 727 const unsigned max_output_length_bytes = modulus_length_bytes; | |
| 595 | 728 |
| 596 const int modulus_length_bytes = | 729 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); |
| 597 PK11_GetPrivateModulusLen(private_key->key()); | 730 unsigned char* const buffer_data = |
| 598 if (modulus_length_bytes <= 0) | 731 reinterpret_cast<unsigned char*>(buffer->data()); |
| 599 return false; | |
| 600 const unsigned max_output_length_bytes = modulus_length_bytes; | |
| 601 | 732 |
| 602 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); | 733 unsigned output_length_bytes = 0; |
| 603 unsigned char* const buffer_data = | 734 if (PK11_PrivDecryptPKCS1(private_key->key(), |
| 604 reinterpret_cast<unsigned char*>(buffer->data()); | 735 buffer_data, |
| 605 | 736 &output_length_bytes, |
| 606 unsigned output_length_bytes = 0; | 737 max_output_length_bytes, |
| 607 if (PK11_PrivDecryptPKCS1(private_key->key(), | 738 const_cast<unsigned char*>(data), |
| 608 buffer_data, | 739 data_size) != SECSuccess) { |
| 609 &output_length_bytes, | 740 return false; |
| 610 max_output_length_bytes, | 741 } |
| 611 const_cast<unsigned char*>(data), | 742 DCHECK_LE(output_length_bytes, max_output_length_bytes); |
| 612 data_size) != SECSuccess) { | 743 webcrypto::ShrinkBuffer(buffer, output_length_bytes); |
| 744 return true; | |
| 745 } | |
| 746 default: { | |
| 613 return false; | 747 return false; |
| 614 } | 748 } |
| 615 DCHECK_LE(output_length_bytes, max_output_length_bytes); | |
| 616 webcrypto::ShrinkBuffer(buffer, output_length_bytes); | |
| 617 return true; | |
| 618 } | 749 } |
| 619 | |
| 620 return false; | |
| 621 } | 750 } |
| 622 | 751 |
| 623 bool WebCryptoImpl::DigestInternal( | 752 bool WebCryptoImpl::DigestInternal( |
| 624 const blink::WebCryptoAlgorithm& algorithm, | 753 const blink::WebCryptoAlgorithm& algorithm, |
| 625 const unsigned char* data, | 754 const unsigned char* data, |
| 626 unsigned data_size, | 755 unsigned data_size, |
| 627 blink::WebArrayBuffer* buffer) { | 756 blink::WebArrayBuffer* buffer) { |
| 628 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | 757 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); |
| 629 if (hash_type == HASH_AlgNULL) { | 758 if (hash_type == HASH_AlgNULL) { |
| 630 return false; | 759 return false; |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1011 | 1140 |
| 1012 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1141 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
| 1013 blink::WebCryptoKeyTypePublic, | 1142 blink::WebCryptoKeyTypePublic, |
| 1014 extractable, | 1143 extractable, |
| 1015 algorithm, | 1144 algorithm, |
| 1016 usage_mask); | 1145 usage_mask); |
| 1017 return true; | 1146 return true; |
| 1018 } | 1147 } |
| 1019 | 1148 |
| 1020 } // namespace content | 1149 } // namespace content |
| OLD | NEW |