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 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
231 size_t reverse_i = data_size - i - 1; | 231 size_t reverse_i = data_size - i - 1; |
232 | 232 |
233 if (reverse_i >= sizeof(unsigned long) && data[i]) | 233 if (reverse_i >= sizeof(unsigned long) && data[i]) |
234 return false; // Too large for a long. | 234 return false; // Too large for a long. |
235 | 235 |
236 *result |= data[i] << 8 * reverse_i; | 236 *result |= data[i] << 8 * reverse_i; |
237 } | 237 } |
238 return true; | 238 return true; |
239 } | 239 } |
240 | 240 |
241 // TODO(padolph): Move to webcrypto_util | |
242 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( | |
243 const blink::WebCryptoAlgorithm& algorithm) { | |
244 DCHECK(!algorithm.isNull()); | |
245 switch (algorithm.id()) { | |
246 case blink::WebCryptoAlgorithmIdHmac: | |
247 if (algorithm.hmacParams()) | |
248 return algorithm.hmacParams()->hash(); | |
249 else if (algorithm.hmacKeyParams()) | |
250 return algorithm.hmacKeyParams()->hash(); | |
251 break; | |
252 case blink::WebCryptoAlgorithmIdRsaOaep: | |
253 if (algorithm.rsaOaepParams()) | |
254 return algorithm.rsaOaepParams()->hash(); | |
255 break; | |
256 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
257 if (algorithm.rsaSsaParams()) | |
258 return algorithm.rsaSsaParams()->hash(); | |
259 break; | |
260 default: | |
261 break; | |
262 } | |
263 return blink::WebCryptoAlgorithm::createNull(); | |
264 } | |
265 | |
241 } // namespace | 266 } // namespace |
242 | 267 |
243 void WebCryptoImpl::Init() { | 268 void WebCryptoImpl::Init() { |
244 crypto::EnsureNSSInit(); | 269 crypto::EnsureNSSInit(); |
245 } | 270 } |
246 | 271 |
247 bool WebCryptoImpl::EncryptInternal( | 272 bool WebCryptoImpl::EncryptInternal( |
248 const blink::WebCryptoAlgorithm& algorithm, | 273 const blink::WebCryptoAlgorithm& algorithm, |
249 const blink::WebCryptoKey& key, | 274 const blink::WebCryptoKey& key, |
250 const unsigned char* data, | 275 const unsigned char* data, |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
550 type, extractable, algorithm, usage_mask); | 575 type, extractable, algorithm, usage_mask); |
551 return true; | 576 return true; |
552 } | 577 } |
553 | 578 |
554 bool WebCryptoImpl::SignInternal( | 579 bool WebCryptoImpl::SignInternal( |
555 const blink::WebCryptoAlgorithm& algorithm, | 580 const blink::WebCryptoAlgorithm& algorithm, |
556 const blink::WebCryptoKey& key, | 581 const blink::WebCryptoKey& key, |
557 const unsigned char* data, | 582 const unsigned char* data, |
558 unsigned data_size, | 583 unsigned data_size, |
559 blink::WebArrayBuffer* buffer) { | 584 blink::WebArrayBuffer* buffer) { |
585 | |
586 // Note: It is not an error to sign empty data. | |
587 | |
588 DCHECK(buffer); | |
589 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
590 | |
560 blink::WebArrayBuffer result; | 591 blink::WebArrayBuffer result; |
561 | 592 |
562 switch (algorithm.id()) { | 593 switch (algorithm.id()) { |
563 case blink::WebCryptoAlgorithmIdHmac: { | 594 case blink::WebCryptoAlgorithmIdHmac: { |
564 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 595 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); |
565 if (!params) { | 596 if (!params) { |
566 return false; | 597 return false; |
567 } | 598 } |
568 | 599 |
569 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 600 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
570 | 601 |
571 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | 602 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), |
572 WebCryptoAlgorithmToHMACMechanism(params->hash())); | 603 WebCryptoAlgorithmToHMACMechanism(params->hash())); |
573 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
574 | 604 |
575 SECItem param_item = { siBuffer, NULL, 0 }; | 605 SECItem param_item = { siBuffer, NULL, 0 }; |
576 SECItem data_item = { | 606 SECItem data_item = { |
577 siBuffer, | 607 siBuffer, |
578 const_cast<unsigned char*>(data), | 608 const_cast<unsigned char*>(data), |
579 data_size | 609 data_size |
580 }; | 610 }; |
581 // First call is to figure out the length. | 611 // First call is to figure out the length. |
582 SECItem signature_item = { siBuffer, NULL, 0 }; | 612 SECItem signature_item = { siBuffer, NULL, 0 }; |
583 | 613 |
(...skipping 17 matching lines...) Expand all Loading... | |
601 &signature_item, | 631 &signature_item, |
602 &data_item) != SECSuccess) { | 632 &data_item) != SECSuccess) { |
603 NOTREACHED(); | 633 NOTREACHED(); |
604 return false; | 634 return false; |
605 } | 635 } |
606 | 636 |
607 DCHECK_EQ(result.byteLength(), signature_item.len); | 637 DCHECK_EQ(result.byteLength(), signature_item.len); |
608 | 638 |
609 break; | 639 break; |
610 } | 640 } |
641 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
642 // Only private key signing is supported. | |
643 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
644 return false; | |
645 | |
646 const blink::WebCryptoAlgorithm hash_algorithm = | |
647 GetInnerHashAlgorithm(algorithm); | |
648 if (hash_algorithm.isNull()) // TODO(padolph): DCHECK instead? | |
649 return false; | |
650 blink::WebArrayBuffer digest; | |
651 if (!DigestInternal(hash_algorithm, data, data_size, &digest)) | |
Ryan Sleevi
2013/11/21 01:45:57
I'm not sure this is the right approach.
Why not
padolph
2013/11/28 02:29:09
Done. Rewrote to use SEC_SignData (a sequence of S
| |
652 return false; | |
653 const SECItem digest_item = { | |
654 siBuffer, | |
655 reinterpret_cast<unsigned char*>(digest.data()), | |
656 digest.byteLength() | |
657 }; | |
658 | |
659 PrivateKeyHandle* const private_key = | |
660 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
661 DCHECK(private_key); | |
662 DCHECK(private_key->key()); | |
663 const int signature_length = PK11_SignatureLen(private_key->key()); | |
664 if (signature_length <= 0) | |
665 return false; | |
666 result = blink::WebArrayBuffer::create(signature_length, 1); | |
667 SECItem signature_item = { | |
668 siBuffer, | |
669 reinterpret_cast<unsigned char*>(result.data()), | |
670 signature_length | |
671 }; | |
672 if (PK11_Sign(private_key->key(), | |
673 &signature_item, | |
674 &digest_item) != SECSuccess ) { | |
675 return false; | |
676 } | |
677 DCHECK_EQ(result.byteLength(), signature_item.len); | |
678 | |
679 break; | |
680 } | |
611 default: | 681 default: |
612 return false; | 682 return false; |
613 } | 683 } |
614 | 684 |
615 *buffer = result; | 685 *buffer = result; |
616 return true; | 686 return true; |
617 } | 687 } |
618 | 688 |
619 bool WebCryptoImpl::VerifySignatureInternal( | 689 bool WebCryptoImpl::VerifySignatureInternal( |
620 const blink::WebCryptoAlgorithm& algorithm, | 690 const blink::WebCryptoAlgorithm& algorithm, |
(...skipping 13 matching lines...) Expand all Loading... | |
634 // Handling of truncated signatures is underspecified in the WebCrypto | 704 // Handling of truncated signatures is underspecified in the WebCrypto |
635 // spec, so here we fail verification if a truncated signature is being | 705 // spec, so here we fail verification if a truncated signature is being |
636 // verified. | 706 // verified. |
637 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 707 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
638 *signature_match = | 708 *signature_match = |
639 result.byteLength() == signature_size && | 709 result.byteLength() == signature_size && |
640 crypto::SecureMemEqual(result.data(), signature, signature_size); | 710 crypto::SecureMemEqual(result.data(), signature, signature_size); |
641 | 711 |
642 break; | 712 break; |
643 } | 713 } |
714 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: { | |
715 // Only public key signature verification is supported. | |
716 if (key.type() != blink::WebCryptoKeyTypePublic) | |
717 return false; | |
718 | |
719 const blink::WebCryptoAlgorithm hash_algorithm = | |
720 GetInnerHashAlgorithm(algorithm); | |
721 if (hash_algorithm.isNull()) // TODO(padolph): DCHECK instead? | |
722 return false; | |
723 blink::WebArrayBuffer digest; | |
724 if (!DigestInternal(hash_algorithm, data, data_size, &digest)) | |
725 return false; | |
726 const SECItem digest_item = { | |
727 siBuffer, | |
728 reinterpret_cast<unsigned char*>(digest.data()), | |
729 digest.byteLength() | |
730 }; | |
731 | |
732 PublicKeyHandle* const public_key = | |
733 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
734 DCHECK(public_key); | |
735 DCHECK(public_key->key()); | |
736 const SECItem signature_item = { | |
737 siBuffer, | |
738 const_cast<unsigned char*>(signature), | |
739 signature_size | |
740 }; | |
741 *signature_match = PK11_Verify(public_key->key(), | |
742 &signature_item, | |
743 &digest_item, | |
744 NULL) == SECSuccess; | |
745 | |
746 break; | |
747 } | |
644 default: | 748 default: |
645 return false; | 749 return false; |
646 } | 750 } |
647 | 751 |
648 return true; | 752 return true; |
649 } | 753 } |
650 | 754 |
651 } // namespace content | 755 } // namespace content |
OLD | NEW |