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 |