Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: net/cert/cert_verify_proc_unittest.cc

Issue 2731603002: Check TBSCertificate.algorithm and Certificate.signatureAlgorithm for (Closed)
Patch Set: Use rsleevi's background comment Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert/cert_verify_proc_mac.cc ('k') | net/cert/internal/signature_algorithm.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "net/cert/cert_verify_proc.h" 5 #include "net/cert/cert_verify_proc.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/sha1.h" 14 #include "base/sha1.h"
15 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "base/test/histogram_tester.h" 16 #include "base/test/histogram_tester.h"
17 #include "base/test/scoped_feature_list.h" 17 #include "base/test/scoped_feature_list.h"
18 #include "build/build_config.h" 18 #include "build/build_config.h"
19 #include "crypto/sha2.h" 19 #include "crypto/sha2.h"
20 #include "net/base/net_errors.h" 20 #include "net/base/net_errors.h"
21 #include "net/cert/asn1_util.h" 21 #include "net/cert/asn1_util.h"
22 #include "net/cert/cert_status_flags.h" 22 #include "net/cert/cert_status_flags.h"
23 #include "net/cert/cert_verifier.h" 23 #include "net/cert/cert_verifier.h"
24 #include "net/cert/cert_verify_result.h" 24 #include "net/cert/cert_verify_result.h"
25 #include "net/cert/crl_set.h" 25 #include "net/cert/crl_set.h"
26 #include "net/cert/crl_set_storage.h" 26 #include "net/cert/crl_set_storage.h"
27 #include "net/cert/internal/signature_algorithm.h"
27 #include "net/cert/test_root_certs.h" 28 #include "net/cert/test_root_certs.h"
28 #include "net/cert/x509_certificate.h" 29 #include "net/cert/x509_certificate.h"
30 #include "net/der/input.h"
31 #include "net/der/parser.h"
29 #include "net/test/cert_test_util.h" 32 #include "net/test/cert_test_util.h"
30 #include "net/test/gtest_util.h" 33 #include "net/test/gtest_util.h"
31 #include "net/test/test_certificate_data.h" 34 #include "net/test/test_certificate_data.h"
32 #include "net/test/test_data_directory.h" 35 #include "net/test/test_data_directory.h"
33 #include "testing/gmock/include/gmock/gmock.h" 36 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h" 37 #include "testing/gtest/include/gtest/gtest.h"
35 38
36 #if defined(OS_ANDROID) 39 #if defined(OS_ANDROID)
37 #include "base/android/build_info.h" 40 #include "base/android/build_info.h"
38 #endif 41 #endif
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after
614 CertificateList(), &verify_result); 617 CertificateList(), &verify_result);
615 EXPECT_THAT(error, IsOk()); 618 EXPECT_THAT(error, IsOk());
616 EXPECT_EQ(0U, verify_result.cert_status); 619 EXPECT_EQ(0U, verify_result.cert_status);
617 620
618 error = Verify(leaf.get(), "foo.test2.example.com", flags, NULL, 621 error = Verify(leaf.get(), "foo.test2.example.com", flags, NULL,
619 CertificateList(), &verify_result); 622 CertificateList(), &verify_result);
620 EXPECT_THAT(error, IsOk()); 623 EXPECT_THAT(error, IsOk());
621 EXPECT_EQ(0U, verify_result.cert_status); 624 EXPECT_EQ(0U, verify_result.cert_status);
622 } 625 }
623 626
627 // This fixture is for testing the verification of a certificate chain which
628 // has some sort of mismatched signature algorithm (i.e.
629 // Certificate.signatureAlgorithm and TBSCertificate.algorithm are different).
630 class CertVerifyProcInspectSignatureAlgorithmsTest : public ::testing::Test {
631 protected:
632 // In the test setup, SHA384 is given special treatment as an unknown
633 // algorithm.
634 static constexpr DigestAlgorithm kUnknownDigestAlgorithm =
635 DigestAlgorithm::Sha384;
636
637 struct CertParams {
638 // Certificate.signatureAlgorithm
639 DigestAlgorithm cert_algorithm;
640
641 // TBSCertificate.algorithm
642 DigestAlgorithm tbs_algorithm;
643 };
644
645 // On iOS trying to import a certificate with mismatched signature will
646 // fail. Consequently the rest of the tests can't be performed.
647 WARN_UNUSED_RESULT bool SupportsImportingMismatchedAlgorithms() const {
648 #if defined(OS_IOS)
649 LOG(INFO) << "Skipping test on iOS because certs with mismatched "
650 "algorithms cannot be imported";
651 return false;
652 #else
653 return true;
654 #endif
655 }
656
657 // Shorthand for VerifyChain() where only the leaf's parameters need
658 // to be specified.
659 WARN_UNUSED_RESULT int VerifyLeaf(const CertParams& leaf_params) {
660 return VerifyChain({// Target
661 leaf_params,
662 // Root
663 {DigestAlgorithm::Sha256, DigestAlgorithm::Sha256}});
664 }
665
666 // Shorthand for VerifyChain() where only the intermediate's parameters need
667 // to be specified.
668 WARN_UNUSED_RESULT int VerifyIntermediate(
669 const CertParams& intermediate_params) {
670 return VerifyChain({// Target
671 {DigestAlgorithm::Sha256, DigestAlgorithm::Sha256},
672 // Intermediate
673 intermediate_params,
674 // Root
675 {DigestAlgorithm::Sha256, DigestAlgorithm::Sha256}});
676 }
677
678 // Shorthand for VerifyChain() where only the root's parameters need to be
679 // specified.
680 WARN_UNUSED_RESULT int VerifyRoot(const CertParams& root_params) {
681 return VerifyChain({// Target
682 {DigestAlgorithm::Sha256, DigestAlgorithm::Sha256},
683 // Intermediate
684 {DigestAlgorithm::Sha256, DigestAlgorithm::Sha256},
685 // Root
686 root_params});
687 }
688
689 // Manufactures a certificate chain where each certificate has the indicated
690 // signature algorithms, and then returns the result of verifying this chain.
691 //
692 // TODO(eroman): Instead of building certificates at runtime, move their
693 // generation to external scripts.
694 WARN_UNUSED_RESULT int VerifyChain(
695 const std::vector<CertParams>& chain_params) {
696 auto chain = CreateChain(chain_params);
697 if (!chain) {
698 ADD_FAILURE() << "Failed creating certificate chain";
699 return ERR_UNEXPECTED;
700 }
701
702 int flags = 0;
703 CertVerifyResult dummy_result;
704 CertVerifyResult verify_result;
705
706 scoped_refptr<CertVerifyProc> verify_proc =
707 new MockCertVerifyProc(dummy_result);
708
709 return verify_proc->Verify(chain.get(), "test.example.com", std::string(),
710 flags, NULL, CertificateList(), &verify_result);
711 }
712
713 private:
714 // Overwrites the AlgorithmIdentifier pointed to by |algorithm_sequence| with
715 // |algorithm|. Note this violates the constness of StringPiece.
716 WARN_UNUSED_RESULT static bool SetAlgorithmSequence(
717 DigestAlgorithm algorithm,
718 base::StringPiece* algorithm_sequence) {
719 // This string of bytes is the full SEQUENCE for an AlgorithmIdentifier.
720 std::vector<uint8_t> replacement_sequence;
721 switch (algorithm) {
722 case DigestAlgorithm::Sha1:
723 // sha1WithRSAEncryption
724 replacement_sequence = {0x30, 0x0D, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
725 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00};
726 break;
727 case DigestAlgorithm::Sha256:
728 // sha256WithRSAEncryption
729 replacement_sequence = {0x30, 0x0D, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
730 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00};
731 break;
732 case kUnknownDigestAlgorithm:
733 // This shouldn't be anything meaningful (modified numbers at random).
734 replacement_sequence = {0x30, 0x0D, 0x06, 0x09, 0x8a, 0x87, 0x18, 0x46,
735 0xd7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00};
736 break;
737 default:
738 ADD_FAILURE() << "Unsupported digest algorithm";
739 return false;
740 }
741
742 // For this simple replacement to work (without modifying any
743 // other sequence lengths) the original algorithm and replacement
744 // algorithm must have the same encoded length.
745 if (algorithm_sequence->size() != replacement_sequence.size()) {
746 ADD_FAILURE() << "AlgorithmIdentifier must have length "
747 << replacement_sequence.size();
748 return false;
749 }
750
751 memcpy(const_cast<char*>(algorithm_sequence->data()),
752 replacement_sequence.data(), replacement_sequence.size());
753 return true;
754 }
755
756 // Locate the serial number bytes.
757 WARN_UNUSED_RESULT static bool ExtractSerialNumberFromDERCert(
758 base::StringPiece der_cert,
759 base::StringPiece* serial_value) {
760 der::Parser parser((der::Input(der_cert)));
761 der::Parser certificate;
762 if (!parser.ReadSequence(&certificate))
763 return false;
764
765 der::Parser tbs_certificate;
766 if (!certificate.ReadSequence(&tbs_certificate))
767 return false;
768
769 bool unused;
770 if (!tbs_certificate.SkipOptionalTag(
771 der::kTagConstructed | der::kTagContextSpecific | 0, &unused)) {
772 return false;
773 }
774
775 // serialNumber
776 der::Input serial_value_der;
777 if (!tbs_certificate.ReadTag(der::kInteger, &serial_value_der))
778 return false;
779
780 *serial_value = serial_value_der.AsStringPiece();
781 return true;
782 }
783
784 // Creates a certificate (based on some base certificate file) using the
785 // specified signature algorithms.
786 static scoped_refptr<X509Certificate> CreateCertificate(
787 const CertParams& params) {
788 // Dosn't really matter which base certificate is used, so long as it is
789 // valid and uses a signature AlgorithmIdentifier with the same encoded
790 // length as sha1WithRSASignature.
791 const char* kLeafFilename = "name_constraint_good.pem";
792
793 auto cert = CreateCertificateChainFromFile(
794 GetTestCertsDirectory(), kLeafFilename, X509Certificate::FORMAT_AUTO);
795 if (!cert) {
796 ADD_FAILURE() << "Failed to load certificate: " << kLeafFilename;
797 return nullptr;
798 }
799
800 // Start with the DER bytes of a valid certificate. This will be the basis
801 // for building a modified certificate.
802 std::string cert_der;
803 if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &cert_der)) {
804 ADD_FAILURE() << "Failed getting DER bytes";
805 return nullptr;
806 }
807
808 // Parse the certificate and identify the locations of interest within
809 // |cert_der|.
810 base::StringPiece cert_algorithm_sequence;
811 base::StringPiece tbs_algorithm_sequence;
812 if (!asn1::ExtractSignatureAlgorithmsFromDERCert(
813 cert_der, &cert_algorithm_sequence, &tbs_algorithm_sequence)) {
814 ADD_FAILURE() << "Failed parsing certificate algorithms";
815 return nullptr;
816 }
817
818 base::StringPiece serial_value;
819 if (!ExtractSerialNumberFromDERCert(cert_der, &serial_value)) {
820 ADD_FAILURE() << "Failed parsing certificate serial number";
821 return nullptr;
822 }
823
824 // Give each certificate a unique serial number based on its content (which
825 // in turn is a function of |params|, otherwise importing it may fail.
826
827 // Upper bound for last entry in DigestAlgorithm
828 const int kNumDigestAlgorithms = 15;
829 *const_cast<char*>(serial_value.data()) +=
830 static_cast<int>(params.tbs_algorithm) * kNumDigestAlgorithms +
831 static_cast<int>(params.cert_algorithm);
832
833 // Change the signature AlgorithmIdentifiers.
834 if (!SetAlgorithmSequence(params.cert_algorithm,
835 &cert_algorithm_sequence) ||
836 !SetAlgorithmSequence(params.tbs_algorithm, &tbs_algorithm_sequence)) {
837 return nullptr;
838 }
839
840 // NOTE: The signature is NOT recomputed over TBSCertificate -- for these
841 // tests it isn't needed.
842 return X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
843 }
844
845 static scoped_refptr<X509Certificate> CreateChain(
846 const std::vector<CertParams>& params) {
847 // Manufacture a chain with the given combinations of signature algorithms.
848 // This chain isn't actually a valid chain, but it is good enough for
849 // testing the base CertVerifyProc.
850 CertificateList certs;
851 for (const auto& cert_params : params) {
852 certs.push_back(CreateCertificate(cert_params));
853 if (!certs.back())
854 return nullptr;
855 }
856
857 X509Certificate::OSCertHandles intermediates;
858 for (size_t i = 1; i < certs.size(); ++i)
859 intermediates.push_back(certs[i]->os_cert_handle());
860
861 return X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
862 intermediates);
863 }
864 };
865
866 // This is a control test to make sure that the test helper
867 // VerifyLeaf() works as expected. There is no actual mismatch in the
868 // algorithms used here.
869 //
870 // Certificate.signatureAlgorithm: sha1WithRSASignature
871 // TBSCertificate.algorithm: sha1WithRSAEncryption
872 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafSha1Sha1) {
873 int rv = VerifyLeaf({DigestAlgorithm::Sha1, DigestAlgorithm::Sha1});
874 ASSERT_THAT(rv, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM));
875 }
876
877 // This is a control test to make sure that the test helper
878 // VerifyLeaf() works as expected. There is no actual mismatch in the
879 // algorithms used here.
880 //
881 // Certificate.signatureAlgorithm: sha256WithRSASignature
882 // TBSCertificate.algorithm: sha256WithRSAEncryption
883 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafSha256Sha256) {
884 int rv = VerifyLeaf({DigestAlgorithm::Sha256, DigestAlgorithm::Sha256});
885 ASSERT_THAT(rv, IsOk());
886 }
887
888 // Mismatched signature algorithms in the leaf certificate.
889 //
890 // Certificate.signatureAlgorithm: sha1WithRSASignature
891 // TBSCertificate.algorithm: sha256WithRSAEncryption
892 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafSha1Sha256) {
893 if (!SupportsImportingMismatchedAlgorithms())
894 return;
895
896 int rv = VerifyLeaf({DigestAlgorithm::Sha1, DigestAlgorithm::Sha256});
897 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
898 }
899
900 // Mismatched signature algorithms in the leaf certificate.
901 //
902 // Certificate.signatureAlgorithm: sha256WithRSAEncryption
903 // TBSCertificate.algorithm: sha1WithRSASignature
904 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafSha256Sha1) {
905 if (!SupportsImportingMismatchedAlgorithms())
906 return;
907
908 int rv = VerifyLeaf({DigestAlgorithm::Sha256, DigestAlgorithm::Sha1});
909 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
910 }
911
912 // Unrecognized signature algorithm in the leaf certificate.
913 //
914 // Certificate.signatureAlgorithm: sha256WithRSAEncryption
915 // TBSCertificate.algorithm: ?
916 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafSha256Unknown) {
917 if (!SupportsImportingMismatchedAlgorithms())
918 return;
919
920 int rv = VerifyLeaf({DigestAlgorithm::Sha256, kUnknownDigestAlgorithm});
921 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
922 }
923
924 // Unrecognized signature algorithm in the leaf certificate.
925 //
926 // Certificate.signatureAlgorithm: ?
927 // TBSCertificate.algorithm: sha256WithRSAEncryption
928 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, LeafUnknownSha256) {
929 if (!SupportsImportingMismatchedAlgorithms())
930 return;
931
932 int rv = VerifyLeaf({kUnknownDigestAlgorithm, DigestAlgorithm::Sha256});
933 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
934 }
935
936 // Mismatched signature algorithms in the intermediate certificate.
937 //
938 // Certificate.signatureAlgorithm: sha1WithRSASignature
939 // TBSCertificate.algorithm: sha256WithRSAEncryption
940 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, IntermediateSha1Sha256) {
941 if (!SupportsImportingMismatchedAlgorithms())
942 return;
943
944 int rv = VerifyIntermediate({DigestAlgorithm::Sha1, DigestAlgorithm::Sha256});
945 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
946 }
947
948 // Mismatched signature algorithms in the intermediate certificate.
949 //
950 // Certificate.signatureAlgorithm: sha256WithRSAEncryption
951 // TBSCertificate.algorithm: sha1WithRSASignature
952 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, IntermediateSha256Sha1) {
953 if (!SupportsImportingMismatchedAlgorithms())
954 return;
955
956 int rv = VerifyIntermediate({DigestAlgorithm::Sha256, DigestAlgorithm::Sha1});
957 ASSERT_THAT(rv, IsError(ERR_CERT_INVALID));
958 }
959
960 // Mismatched signature algorithms in the root certificate.
961 //
962 // Certificate.signatureAlgorithm: sha256WithRSAEncryption
963 // TBSCertificate.algorithm: sha1WithRSASignature
964 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, RootSha256Sha1) {
965 if (!SupportsImportingMismatchedAlgorithms())
966 return;
967
968 int rv = VerifyRoot({DigestAlgorithm::Sha256, DigestAlgorithm::Sha1});
969 ASSERT_THAT(rv, IsOk());
970 }
971
972 // Unrecognized signature algorithm in the root certificate.
973 //
974 // Certificate.signatureAlgorithm: ?
975 // TBSCertificate.algorithm: sha256WithRSAEncryption
976 TEST_F(CertVerifyProcInspectSignatureAlgorithmsTest, RootUnknownSha256) {
977 if (!SupportsImportingMismatchedAlgorithms())
978 return;
979
980 int rv = VerifyRoot({kUnknownDigestAlgorithm, DigestAlgorithm::Sha256});
981 ASSERT_THAT(rv, IsOk());
982 }
983
624 TEST_P(CertVerifyProcInternalTest, NameConstraintsFailure) { 984 TEST_P(CertVerifyProcInternalTest, NameConstraintsFailure) {
625 if (!SupportsReturningVerifiedChain()) { 985 if (!SupportsReturningVerifiedChain()) {
626 LOG(INFO) << "Skipping this test in this platform."; 986 LOG(INFO) << "Skipping this test in this platform.";
627 return; 987 return;
628 } 988 }
629 989
630 CertificateList ca_cert_list = 990 CertificateList ca_cert_list =
631 CreateCertificateListFromFile(GetTestCertsDirectory(), "root_ca_cert.pem", 991 CreateCertificateListFromFile(GetTestCertsDirectory(), "root_ca_cert.pem",
632 X509Certificate::FORMAT_AUTO); 992 X509Certificate::FORMAT_AUTO);
633 ASSERT_EQ(1U, ca_cert_list.size()); 993 ASSERT_EQ(1U, ca_cert_list.size());
(...skipping 1316 matching lines...) Expand 10 before | Expand all | Expand 10 after
1950 int flags = 0; 2310 int flags = 0;
1951 CertVerifyResult verify_result; 2311 CertVerifyResult verify_result;
1952 int error = verify_proc->Verify(cert.get(), "127.0.0.1", std::string(), flags, 2312 int error = verify_proc->Verify(cert.get(), "127.0.0.1", std::string(), flags,
1953 NULL, CertificateList(), &verify_result); 2313 NULL, CertificateList(), &verify_result);
1954 EXPECT_EQ(OK, error); 2314 EXPECT_EQ(OK, error);
1955 histograms.ExpectTotalCount(kTLSFeatureExtensionHistogram, 0); 2315 histograms.ExpectTotalCount(kTLSFeatureExtensionHistogram, 0);
1956 histograms.ExpectTotalCount(kTLSFeatureExtensionOCSPHistogram, 0); 2316 histograms.ExpectTotalCount(kTLSFeatureExtensionOCSPHistogram, 0);
1957 } 2317 }
1958 2318
1959 } // namespace net 2319 } // namespace net
OLDNEW
« no previous file with comments | « net/cert/cert_verify_proc_mac.cc ('k') | net/cert/internal/signature_algorithm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698