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

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

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

Powered by Google App Engine
This is Rietveld 408576698