• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/cert/pki/path_builder.h"
6 
7 #include <cstdint>
8 
9 #include "net/base/net_errors.h"
10 #include "net/cert/pki/cert_issuer_source_static.h"
11 #include "net/cert/pki/common_cert_errors.h"
12 #include "net/cert/pki/crl.h"
13 #include "net/cert/pki/parse_certificate.h"
14 #include "net/cert/pki/parsed_certificate.h"
15 #include "net/cert/pki/simple_path_builder_delegate.h"
16 #include "net/cert/pki/trust_store_in_memory.h"
17 #include "net/cert/pki/verify_certificate_chain.h"
18 #include "net/der/encode_values.h"
19 #include "net/der/input.h"
20 #include "third_party/boringssl/src/include/openssl/pool.h"
21 
22 #include "net/cert/pki/nist_pkits_unittest.h"
23 
24 constexpr int64_t kOneYear = 60 * 60 * 24 * 365;
25 
26 namespace net {
27 
28 namespace {
29 
30 class CrlCheckingPathBuilderDelegate : public SimplePathBuilderDelegate {
31  public:
CrlCheckingPathBuilderDelegate(const std::vector<std::string> & der_crls,int64_t verify_time,int64_t max_age,size_t min_rsa_modulus_length_bits,DigestPolicy digest_policy)32   CrlCheckingPathBuilderDelegate(const std::vector<std::string>& der_crls,
33                                  int64_t verify_time,
34                                  int64_t max_age,
35                                  size_t min_rsa_modulus_length_bits,
36                                  DigestPolicy digest_policy)
37       : SimplePathBuilderDelegate(min_rsa_modulus_length_bits, digest_policy),
38         der_crls_(der_crls),
39         verify_time_(verify_time),
40         max_age_(max_age) {}
41 
CheckPathAfterVerification(const CertPathBuilder & path_builder,CertPathBuilderResultPath * path)42   void CheckPathAfterVerification(const CertPathBuilder& path_builder,
43                                   CertPathBuilderResultPath* path) override {
44     SimplePathBuilderDelegate::CheckPathAfterVerification(path_builder, path);
45 
46     if (!path->IsValid())
47       return;
48 
49     // It would be preferable if this test could use
50     // CheckValidatedChainRevocation somehow, but that only supports getting
51     // CRLs by http distributionPoints. So this just settles for writing a
52     // little bit of wrapper code to test CheckCRL directly.
53     const ParsedCertificateList& certs = path->certs;
54     for (size_t reverse_i = 0; reverse_i < certs.size(); ++reverse_i) {
55       size_t i = certs.size() - reverse_i - 1;
56 
57       // Trust anchors bypass OCSP/CRL revocation checks. (The only way to
58       // revoke trust anchors is via CRLSet or the built-in SPKI block list).
59       if (reverse_i == 0 && path->last_cert_trust.IsTrustAnchor())
60         continue;
61 
62       // RFC 5280 6.3.3.  [If the CRL was not specified in a distribution
63       //                  point], assume a DP with both the reasons and the
64       //                  cRLIssuer fields omitted and a distribution point
65       //                  name of the certificate issuer.
66       // Since this implementation only supports URI names in distribution
67       // points, this means a default-initialized ParsedDistributionPoint is
68       // sufficient.
69       ParsedDistributionPoint fake_cert_dp;
70       const ParsedDistributionPoint* cert_dp = &fake_cert_dp;
71 
72       // If the target cert does have a distribution point, use it.
73       std::vector<ParsedDistributionPoint> distribution_points;
74       ParsedExtension crl_dp_extension;
75       if (certs[i]->GetExtension(der::Input(kCrlDistributionPointsOid),
76                                  &crl_dp_extension)) {
77         ASSERT_TRUE(ParseCrlDistributionPoints(crl_dp_extension.value,
78                                                &distribution_points));
79         // TODO(mattm): some test cases (some of the 4.14.* onlySomeReasons
80         // tests)) have two CRLs and two distribution points, one point
81         // corresponding to each CRL.  Should select the matching point for
82         // each CRL.  (Doesn't matter currently since we don't support
83         // reasons.)
84 
85         // Look for a DistributionPoint without reasons.
86         for (const auto& dp : distribution_points) {
87           if (!dp.reasons) {
88             cert_dp = &dp;
89             break;
90           }
91         }
92         // If there were only DistributionPoints with reasons, just use the
93         // first one.
94         if (cert_dp == &fake_cert_dp && !distribution_points.empty())
95           cert_dp = &distribution_points[0];
96       }
97 
98       bool cert_good = false;
99 
100       for (const auto& der_crl : der_crls_) {
101         CRLRevocationStatus crl_status =
102             CheckCRL(der_crl, certs, i, *cert_dp, verify_time_, max_age_);
103         if (crl_status == CRLRevocationStatus::REVOKED) {
104           path->errors.GetErrorsForCert(i)->AddError(
105               cert_errors::kCertificateRevoked);
106           return;
107         }
108         if (crl_status == CRLRevocationStatus::GOOD) {
109           cert_good = true;
110           break;
111         }
112       }
113       if (!cert_good) {
114         // PKITS tests assume hard-fail revocation checking.
115         // From PKITS 4.4: "When running the tests in this section, the
116         // application should be configured in such a way that the
117         // certification path is not accepted unless valid, up-to-date
118         // revocation data is available for every certificate in the path."
119         path->errors.GetErrorsForCert(i)->AddError(
120             cert_errors::kUnableToCheckRevocation);
121       }
122     }
123   }
124 
125  private:
126   std::vector<std::string> der_crls_;
127   int64_t verify_time_;
128   int64_t max_age_;
129 };
130 
131 class PathBuilderPkitsTestDelegate {
132  public:
RunTest(std::vector<std::string> cert_ders,std::vector<std::string> crl_ders,const PkitsTestInfo & orig_info)133   static void RunTest(std::vector<std::string> cert_ders,
134                       std::vector<std::string> crl_ders,
135                       const PkitsTestInfo& orig_info) {
136     PkitsTestInfo info = orig_info;
137 
138     ASSERT_FALSE(cert_ders.empty());
139     ParsedCertificateList certs;
140     for (const std::string& der : cert_ders) {
141       CertErrors errors;
142       ASSERT_TRUE(ParsedCertificate::CreateAndAddToVector(
143           bssl::UniquePtr<CRYPTO_BUFFER>(
144               CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(der.data()),
145                                 der.size(), nullptr)),
146           {}, &certs, &errors))
147           << errors.ToDebugString();
148     }
149     // First entry in the PKITS chain is the trust anchor.
150     // TODO(mattm): test with all possible trust anchors in the trust store?
151     TrustStoreInMemory trust_store;
152 
153     trust_store.AddTrustAnchor(certs[0]);
154 
155     // TODO(mattm): test with other irrelevant certs in cert_issuer_sources?
156     CertIssuerSourceStatic cert_issuer_source;
157     for (size_t i = 1; i < cert_ders.size() - 1; ++i)
158       cert_issuer_source.AddCert(certs[i]);
159 
160     std::shared_ptr<const ParsedCertificate> target_cert(certs.back());
161 
162     int64_t verify_time;
163     ASSERT_TRUE(der::GeneralizedTimeToPosixTime(info.time, &verify_time));
164     CrlCheckingPathBuilderDelegate path_builder_delegate(
165         crl_ders, verify_time, /*max_age=*/kOneYear * 2, 1024,
166         SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1);
167 
168     std::string_view test_number = info.test_number;
169     if (test_number == "4.4.19" || test_number == "4.5.3" ||
170         test_number == "4.5.4" || test_number == "4.5.6") {
171       // 4.4.19 - fails since CRL is signed by a certificate that is not part
172       //          of the verified chain, which is not supported.
173       // 4.5.3 - fails since non-URI distribution point names are not supported
174       // 4.5.4, 4.5.6 - fails since CRL is signed by a certificate that is not
175       //                part of verified chain, and also non-URI distribution
176       //                point names not supported
177       info.should_validate = false;
178     } else if (test_number == "4.14.1" || test_number == "4.14.4" ||
179                test_number == "4.14.5" || test_number == "4.14.7" ||
180                test_number == "4.14.18" || test_number == "4.14.19" ||
181                test_number == "4.14.22" || test_number == "4.14.24" ||
182                test_number == "4.14.25" || test_number == "4.14.28" ||
183                test_number == "4.14.29" || test_number == "4.14.30" ||
184                test_number == "4.14.33") {
185       // 4.14 tests:
186       // .1 - fails since non-URI distribution point names not supported
187       // .2, .3 - fails since non-URI distribution point names not supported
188       //          (but test is expected to fail for other reason)
189       // .4, .5 - fails since non-URI distribution point names not supported,
190       //          also uses nameRelativeToCRLIssuer which is not supported
191       // .6 - fails since non-URI distribution point names not supported, also
192       //      uses nameRelativeToCRLIssuer which is not supported (but test is
193       //      expected to fail for other reason)
194       // .7 - fails since relative distributionPointName not supported
195       // .8, .9 - fails since relative distributionPointName not supported (but
196       //          test is expected to fail for other reason)
197       // .10, .11, .12, .13, .14, .27, .35 - PASS
198       // .15, .16, .17, .20, .21 - fails since onlySomeReasons is not supported
199       //                           (but test is expected to fail for other
200       //                           reason)
201       // .18, .19 - fails since onlySomeReasons is not supported
202       // .22, .24, .25, .28, .29, .30, .33 - fails since indirect CRLs are not
203       //                                     supported
204       // .23, .26, .31, .32, .34 - fails since indirect CRLs are not supported
205       //                           (but test is expected to fail for other
206       //                           reason)
207       info.should_validate = false;
208     } else if (test_number == "4.15.1" || test_number == "4.15.5") {
209       // 4.15 tests:
210       // .1 - fails due to unhandled critical deltaCRLIndicator extension
211       // .2, .3, .6, .7, .8, .9, .10 - PASS since expected cert status is
212       //                               reflected in base CRL and delta CRL is
213       //                               ignored
214       // .5 - fails, cert status is "on hold" in base CRL but the delta CRL
215       //      which removes the cert from CRL is ignored
216       info.should_validate = false;
217     } else if (test_number == "4.15.4") {
218       // 4.15.4 - Invalid delta-CRL Test4 has the target cert marked revoked in
219       // a delta-CRL. Since delta-CRLs are not supported, the chain validates
220       // successfully.
221       info.should_validate = true;
222     }
223 
224     CertPathBuilder path_builder(
225         std::move(target_cert), &trust_store, &path_builder_delegate, info.time,
226         KeyPurpose::ANY_EKU, info.initial_explicit_policy,
227         info.initial_policy_set, info.initial_policy_mapping_inhibit,
228         info.initial_inhibit_any_policy);
229     path_builder.AddCertIssuerSource(&cert_issuer_source);
230 
231     CertPathBuilder::Result result = path_builder.Run();
232 
233     if (info.should_validate != result.HasValidPath()) {
234       for (size_t i = 0; i < result.paths.size(); ++i) {
235         const net::CertPathBuilderResultPath* result_path =
236             result.paths[i].get();
237         LOG(ERROR) << "path " << i << " errors:\n"
238                    << result_path->errors.ToDebugString(result_path->certs);
239       }
240     }
241 
242     ASSERT_EQ(info.should_validate, result.HasValidPath());
243 
244     if (result.HasValidPath()) {
245       EXPECT_EQ(info.user_constrained_policy_set,
246                 result.GetBestValidPath()->user_constrained_policy_set);
247     }
248   }
249 };
250 
251 }  // namespace
252 
253 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
254                                PkitsTest01SignatureVerification,
255                                PathBuilderPkitsTestDelegate);
256 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
257                                PkitsTest02ValidityPeriods,
258                                PathBuilderPkitsTestDelegate);
259 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
260                                PkitsTest03VerifyingNameChaining,
261                                PathBuilderPkitsTestDelegate);
262 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
263                                PkitsTest04BasicCertificateRevocationTests,
264                                PathBuilderPkitsTestDelegate);
265 INSTANTIATE_TYPED_TEST_SUITE_P(
266     PathBuilder,
267     PkitsTest05VerifyingPathswithSelfIssuedCertificates,
268     PathBuilderPkitsTestDelegate);
269 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
270                                PkitsTest06VerifyingBasicConstraints,
271                                PathBuilderPkitsTestDelegate);
272 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
273                                PkitsTest07KeyUsage,
274                                PathBuilderPkitsTestDelegate);
275 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
276                                PkitsTest08CertificatePolicies,
277                                PathBuilderPkitsTestDelegate);
278 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
279                                PkitsTest09RequireExplicitPolicy,
280                                PathBuilderPkitsTestDelegate);
281 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
282                                PkitsTest10PolicyMappings,
283                                PathBuilderPkitsTestDelegate);
284 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
285                                PkitsTest11InhibitPolicyMapping,
286                                PathBuilderPkitsTestDelegate);
287 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
288                                PkitsTest12InhibitAnyPolicy,
289                                PathBuilderPkitsTestDelegate);
290 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
291                                PkitsTest13NameConstraints,
292                                PathBuilderPkitsTestDelegate);
293 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
294                                PkitsTest14DistributionPoints,
295                                PathBuilderPkitsTestDelegate);
296 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
297                                PkitsTest15DeltaCRLs,
298                                PathBuilderPkitsTestDelegate);
299 INSTANTIATE_TYPED_TEST_SUITE_P(PathBuilder,
300                                PkitsTest16PrivateCertificateExtensions,
301                                PathBuilderPkitsTestDelegate);
302 
303 }  // namespace net
304