• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2023, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/pki/verify.h>
16 
17 #include <assert.h>
18 
19 #include <chrono>
20 #include <optional>
21 #include <string_view>
22 
23 #include <openssl/base.h>
24 #include <openssl/bytestring.h>
25 #include <openssl/pool.h>
26 
27 #include <openssl/pki/signature_verify_cache.h>
28 
29 #include "cert_errors.h"
30 #include "cert_issuer_source_static.h"
31 #include "certificate_policies.h"
32 #include "common_cert_errors.h"
33 #include "encode_values.h"
34 #include "input.h"
35 #include "parse_certificate.h"
36 #include "parse_values.h"
37 #include "parsed_certificate.h"
38 #include "path_builder.h"
39 #include "simple_path_builder_delegate.h"
40 #include "trust_store.h"
41 #include "trust_store_in_memory.h"
42 #include "verify_certificate_chain.h"
43 
44 BSSL_NAMESPACE_BEGIN
45 
46 namespace {
47 
48 std::optional<std::shared_ptr<const ParsedCertificate>>
InternalParseCertificate(Span<const uint8_t> cert,std::string * out_diagnostic)49 InternalParseCertificate(Span<const uint8_t> cert, std::string *out_diagnostic) {
50   ParseCertificateOptions default_options{};
51   // We follow Chromium in setting |allow_invalid_serial_numbers| in order to
52   // not choke on 21-byte serial numbers, which are common.
53   //
54   // The reason for the discrepancy is that unsigned numbers with the high bit
55   // otherwise set get an extra 0 byte in front to keep them positive. So if you
56   // do:
57   //    var num [20]byte
58   //    fillWithRandom(num[:])
59   //    serialNumber := new(big.Int).SetBytes(num[:])
60   //    encodeASN1Integer(serialNumber)
61   //
62   // Then half of your serial numbers will be encoded with 21 bytes. (And
63   // 1/512th will have 19 bytes instead of 20.)
64   default_options.allow_invalid_serial_numbers = true;
65 
66   UniquePtr<CRYPTO_BUFFER> buffer(
67       CRYPTO_BUFFER_new(cert.data(), cert.size(), nullptr));
68   CertErrors errors;
69   std::shared_ptr<const ParsedCertificate> parsed_cert(
70       ParsedCertificate::Create(std::move(buffer), default_options, &errors));
71   if (!parsed_cert) {
72     *out_diagnostic = errors.ToDebugString();
73     return {};
74   }
75   return parsed_cert;
76 }
77 }  // namespace
78 
79 
CertPool()80 CertPool::CertPool() {}
81 
CertificateVerifyOptions()82 CertificateVerifyOptions::CertificateVerifyOptions() {}
83 
WrapTrustStore(std::unique_ptr<TrustStoreInMemory> trust_store)84 static std::unique_ptr<VerifyTrustStore> WrapTrustStore(
85     std::unique_ptr<TrustStoreInMemory> trust_store) {
86   std::unique_ptr<VerifyTrustStore> ret(new VerifyTrustStore);
87   ret->trust_store = std::move(trust_store);
88   return ret;
89 }
90 
~VerifyTrustStore()91 VerifyTrustStore::~VerifyTrustStore() {}
92 
FromDER(std::string_view der_certs,std::string * out_diagnostic)93 std::unique_ptr<VerifyTrustStore> VerifyTrustStore::FromDER(
94     std::string_view der_certs, std::string *out_diagnostic) {
95   auto store = std::make_unique<TrustStoreInMemory>();
96   CBS cbs = StringAsBytes(der_certs);
97 
98   for (size_t cert_num = 1; CBS_len(&cbs) != 0; cert_num++) {
99     CBS cert;
100     if (!CBS_get_asn1_element(&cbs, &cert, CBS_ASN1_SEQUENCE)) {
101       *out_diagnostic = "failed to get ASN.1 SEQUENCE from input at cert " +
102                         std::to_string(cert_num);
103       return {};
104     }
105 
106     auto parsed_cert = InternalParseCertificate(cert, out_diagnostic);
107     if (!parsed_cert.has_value()) {
108       return {};
109     }
110     store->AddTrustAnchor(parsed_cert.value());
111   }
112 
113   return WrapTrustStore(std::move(store));
114 }
115 
FromDER(const std::vector<std::string_view> & der_roots,std::string * out_diagnostic)116 std::unique_ptr<VerifyTrustStore> VerifyTrustStore::FromDER(
117     const std::vector<std::string_view> &der_roots,
118     std::string *out_diagnostic) {
119   auto store = std::make_unique<TrustStoreInMemory>();
120 
121   for (const std::string_view &cert : der_roots) {
122     auto parsed_cert = InternalParseCertificate(StringAsBytes(cert), out_diagnostic);
123     if (!parsed_cert.has_value()) {
124       return {};
125     }
126     store->AddTrustAnchor(parsed_cert.value());
127   }
128 
129   return WrapTrustStore(std::move(store));
130 }
131 
~CertPool()132 CertPool::~CertPool() {}
133 
134 
FromCerts(const std::vector<std::string_view> & der_certs,std::string * out_diagnostic)135 std::unique_ptr<CertPool> CertPool::FromCerts(
136     const std::vector<std::string_view> &der_certs,
137     std::string *out_diagnostic) {
138   auto pool = std::make_unique<CertPool>();
139   pool->impl_ = std::make_unique<CertIssuerSourceStatic>();
140 
141   for (const std::string_view &cert : der_certs) {
142     auto parsed_cert =
143         InternalParseCertificate(StringAsBytes(cert), out_diagnostic);
144     if (!parsed_cert.has_value()) {
145       return {};
146     }
147     pool->impl_->AddCert(std::move(parsed_cert.value()));
148   }
149 
150   return pool;
151 }
152 
CertificateVerifyStatus()153 CertificateVerifyStatus::CertificateVerifyStatus() {}
154 
IterationCount() const155 size_t CertificateVerifyStatus::IterationCount() const {
156   return iteration_count_;
157 }
158 
MaxDepthSeen() const159 size_t CertificateVerifyStatus::MaxDepthSeen() const { return max_depth_seen_; }
160 
161 // PathBuilderDelegateImpl implements a deadline and allows for the
162 // use of a SignatureVerifyCache if an implementation is provided.
163 class PathBuilderDelegateImpl : public SimplePathBuilderDelegate {
164  public:
PathBuilderDelegateImpl(size_t min_rsa_modulus_length_bits,DigestPolicy digest_policy,std::chrono::time_point<std::chrono::steady_clock> deadline,SignatureVerifyCache * cache)165   PathBuilderDelegateImpl(
166       size_t min_rsa_modulus_length_bits, DigestPolicy digest_policy,
167       std::chrono::time_point<std::chrono::steady_clock> deadline,
168       SignatureVerifyCache *cache)
169       : SimplePathBuilderDelegate(min_rsa_modulus_length_bits, digest_policy),
170         deadline_(deadline),
171         cache_(cache) {}
172 
IsDeadlineExpired()173   bool IsDeadlineExpired() override {
174     return (std::chrono::steady_clock::now() > deadline_);
175   }
176 
GetVerifyCache()177   SignatureVerifyCache *GetVerifyCache() override { return cache_; }
178 
179  private:
180   const std::chrono::time_point<std::chrono::steady_clock> deadline_;
181   SignatureVerifyCache *cache_;
182 };
183 
CertificateVerifyInternal(const CertificateVerifyOptions & opts,VerifyError * out_error,CertificateVerifyStatus * out_status,bool all_paths)184 std::optional<std::vector<std::vector<std::string>>> CertificateVerifyInternal(
185     const CertificateVerifyOptions &opts, VerifyError *out_error,
186     CertificateVerifyStatus *out_status, bool all_paths) {
187   VerifyError dummy;
188   if (!out_error) {
189     out_error = &dummy;
190   }
191   if (out_status != nullptr) {
192     out_status->iteration_count_ = 0;
193     out_status->max_depth_seen_ = 0;
194   }
195 
196   std::string diagnostic;
197   std::optional<std::shared_ptr<const ParsedCertificate>> maybe_leaf =
198       InternalParseCertificate(StringAsBytes(opts.leaf_cert), &diagnostic);
199 
200   if (!maybe_leaf.has_value()) {
201     *out_error = {VerifyError::StatusCode::CERTIFICATE_INVALID, 0, diagnostic};
202     return {};
203   }
204   std::shared_ptr<const ParsedCertificate> leaf_cert = maybe_leaf.value();
205 
206   int64_t now;
207   if (opts.time.has_value()) {
208     now = opts.time.value();
209   } else {
210     now = time(NULL);
211   }
212 
213   der::GeneralizedTime verification_time;
214   if (!der::EncodePosixTimeAsGeneralizedTime(now, &verification_time)) {
215     *out_error = {VerifyError::StatusCode::VERIFICATION_FAILURE, -1,
216                   "\nCould not encode verification time\n"};
217     return {};
218   }
219 
220   TrustStore *trust_store = nullptr;
221   if (opts.trust_store) {
222     trust_store = opts.trust_store->trust_store.get();
223   }
224 
225   auto digest_policy = SimplePathBuilderDelegate::DigestPolicy::kStrong;
226   // TODO(b/111551631): remove this
227   if (opts.insecurely_allow_sha1) {
228     digest_policy = SimplePathBuilderDelegate::DigestPolicy::kWeakAllowSha1;
229   }
230 
231   std::chrono::time_point<std::chrono::steady_clock> deadline =
232       std::chrono::time_point<std::chrono::steady_clock>::max();
233   if (opts.deadline.has_value()) {
234     deadline = opts.deadline.value();
235   }
236 
237   PathBuilderDelegateImpl path_builder_delegate(
238       opts.min_rsa_modulus_length, digest_policy, deadline,
239       opts.signature_verify_cache);
240 
241   KeyPurpose key_purpose = KeyPurpose::SERVER_AUTH;
242   switch (opts.key_purpose) {
243     case CertificateVerifyOptions::KeyPurpose::ANY_EKU:
244       key_purpose = KeyPurpose::ANY_EKU;
245       break;
246     case CertificateVerifyOptions::KeyPurpose::SERVER_AUTH:
247       key_purpose = KeyPurpose::SERVER_AUTH;
248       break;
249     case CertificateVerifyOptions::KeyPurpose::CLIENT_AUTH:
250       key_purpose = KeyPurpose::CLIENT_AUTH;
251       break;
252     case CertificateVerifyOptions::KeyPurpose::SERVER_AUTH_STRICT:
253       key_purpose = KeyPurpose::SERVER_AUTH_STRICT;
254       break;
255     case CertificateVerifyOptions::KeyPurpose::CLIENT_AUTH_STRICT:
256       key_purpose = KeyPurpose::CLIENT_AUTH_STRICT;
257       break;
258     case CertificateVerifyOptions::KeyPurpose::SERVER_AUTH_STRICT_LEAF:
259       key_purpose = KeyPurpose::SERVER_AUTH_STRICT_LEAF;
260       break;
261     case CertificateVerifyOptions::KeyPurpose::CLIENT_AUTH_STRICT_LEAF:
262       key_purpose = KeyPurpose::CLIENT_AUTH_STRICT_LEAF;
263       break;
264   }
265   CertPathBuilder path_builder(leaf_cert, trust_store, &path_builder_delegate,
266                                verification_time, key_purpose,
267                                InitialExplicitPolicy::kFalse,
268                                /* user_initial_policy_set= */
269                                {der::Input(kAnyPolicyOid)},
270                                InitialPolicyMappingInhibit::kFalse,
271                                InitialAnyPolicyInhibit::kFalse);
272 
273   CertIssuerSourceStatic intermediates;
274   for (const std::string_view &cert : opts.intermediates) {
275     std::string diag_string;
276     std::optional<std::shared_ptr<const ParsedCertificate>> parsed =
277         InternalParseCertificate(StringAsBytes(cert), &diag_string);
278     if (!parsed.has_value()) {
279       if (path_builder_delegate.IsDebugLogEnabled()) {
280         path_builder_delegate.DebugLog("skipping bad intermediate: " +
281                                        diag_string);
282       }
283       continue;
284     }
285     intermediates.AddCert(std::move(parsed.value()));
286   }
287   path_builder.AddCertIssuerSource(&intermediates);
288 
289   if (opts.extra_intermediates != nullptr) {
290     path_builder.AddCertIssuerSource(opts.extra_intermediates->impl_.get());
291   }
292 
293   if (opts.max_iteration_count > 0) {
294     path_builder.SetIterationLimit(opts.max_iteration_count);
295   }
296 
297   if (opts.max_path_building_depth > 0) {
298     path_builder.SetDepthLimit(opts.max_path_building_depth);
299   }
300 
301   path_builder.SetExploreAllPaths(all_paths);
302 
303   CertPathBuilder::Result result = path_builder.Run();
304 
305   if (out_status != nullptr) {
306     out_status->iteration_count_ = result.iteration_count;
307     out_status->max_depth_seen_ = result.max_depth_seen;
308   }
309 
310   *out_error = result.GetBestPathVerifyError();
311 
312   if (result.HasValidPath()) {
313     std::vector<std::vector<std::string>> ret;
314     if (!all_paths) {
315       auto best_path = result.GetBestValidPath();
316       ret.push_back(std::vector<std::string>());
317       for (size_t i = 0; i < best_path->certs.size(); i++) {
318         ret[0].emplace_back(BytesAsStringView(best_path->certs[i]->der_cert()));
319       }
320       return ret;
321     }
322     for (const auto &path : result.paths) {
323       if (!path->IsValid()) {
324         continue;
325       }
326       std::vector<std::string> ret_path;
327       for (const auto &cert : path->certs) {
328         ret_path.emplace_back(BytesAsStringView(cert->der_cert()));
329       }
330       ret.push_back(ret_path);
331     }
332     return ret;
333   }
334 
335   return {};
336 }
337 
CertificateVerify(const CertificateVerifyOptions & opts,VerifyError * out_error,CertificateVerifyStatus * out_status)338 std::optional<std::vector<std::string>> CertificateVerify(
339     const CertificateVerifyOptions &opts, VerifyError *out_error,
340     CertificateVerifyStatus *out_status) {
341   auto single_path = CertificateVerifyInternal(opts, out_error, out_status,
342                                                /*all_paths=*/false);
343   if (!single_path.has_value()) {
344     return {};
345   }
346   return single_path.value()[0];
347 }
348 
CertificateVerifyAllPaths(const CertificateVerifyOptions & opts)349 std::optional<std::vector<std::vector<std::string>>> CertificateVerifyAllPaths(
350     const CertificateVerifyOptions &opts) {
351   return CertificateVerifyInternal(opts, nullptr, nullptr, /*all_paths=*/true);
352 }
353 
354 BSSL_NAMESPACE_END
355