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