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 |