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

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

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