xref: /aosp_15_r20/external/cronet/net/cert/cert_verify_proc_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/cert_verify_proc_android.h"
6 
7 #include <set>
8 #include <string>
9 #include <string_view>
10 #include <vector>
11 
12 #include "base/check_op.h"
13 #include "base/containers/adapters.h"
14 #include "base/metrics/histogram_functions.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/notreached.h"
17 #include "crypto/sha2.h"
18 #include "net/android/cert_verify_result_android.h"
19 #include "net/android/network_library.h"
20 #include "net/base/net_errors.h"
21 #include "net/cert/asn1_util.h"
22 #include "net/cert/cert_net_fetcher.h"
23 #include "net/cert/cert_status_flags.h"
24 #include "net/cert/cert_verify_proc.h"
25 #include "net/cert/cert_verify_result.h"
26 #include "net/cert/crl_set.h"
27 #include "net/cert/known_roots.h"
28 #include "net/cert/test_root_certs.h"
29 #include "net/cert/x509_certificate.h"
30 #include "net/cert/x509_util.h"
31 #include "third_party/boringssl/src/pki/cert_errors.h"
32 #include "third_party/boringssl/src/pki/parsed_certificate.h"
33 #include "url/gurl.h"
34 
35 namespace net {
36 
37 namespace {
38 
39 // Android ignores the authType parameter to
40 // X509TrustManager.checkServerTrusted, so pass in a dummy value. See
41 // https://crbug.com/627154.
42 const char kAuthType[] = "RSA";
43 
44 // The maximum number of AIA fetches that TryVerifyWithAIAFetching() will
45 // attempt. If a valid chain cannot be built after this many fetches,
46 // TryVerifyWithAIAFetching() will give up and return
47 // CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT.
48 const unsigned int kMaxAIAFetches = 5;
49 
50 // Starting at certs[start], this function searches |certs| for an issuer of
51 // certs[start], then for an issuer of that issuer, and so on until it finds a
52 // certificate |cert| for which |certs| does not contain an issuer of
53 // |cert|. Returns a pointer to this |cert|, or nullptr if all certificates
54 // while path-building from |start| have an issuer in |certs| (including if
55 // there is a loop). Note that the returned certificate will be equal to |start|
56 // if |start| does not have an issuer in |certs|.
57 //
58 // TODO(estark): when searching for an issuer, this always uses the first
59 // encountered issuer in |certs|, and does not handle the situation where
60 // |certs| contains more than one issuer for a given certificate.
FindLastCertWithUnknownIssuer(const bssl::ParsedCertificateList & certs,const std::shared_ptr<const bssl::ParsedCertificate> & start)61 std::shared_ptr<const bssl::ParsedCertificate> FindLastCertWithUnknownIssuer(
62     const bssl::ParsedCertificateList& certs,
63     const std::shared_ptr<const bssl::ParsedCertificate>& start) {
64   DCHECK_GE(certs.size(), 1u);
65   std::set<std::shared_ptr<const bssl::ParsedCertificate>> used_in_path;
66   std::shared_ptr<const bssl::ParsedCertificate> last = start;
67   while (true) {
68     used_in_path.insert(last);
69     std::shared_ptr<const bssl::ParsedCertificate> last_issuer;
70     // Find an issuer for |last| (which might be |last| itself if self-signed).
71     for (const auto& cert : certs) {
72       if (cert->normalized_subject() == last->normalized_issuer()) {
73         last_issuer = cert;
74         break;
75       }
76     }
77     if (!last_issuer) {
78       // There is no issuer for |last| in |certs|.
79       return last;
80     }
81     if (last_issuer->normalized_subject() == last_issuer->normalized_issuer()) {
82       // A chain can be built from |start| to a self-signed certificate, so
83       // return nullptr to indicate that there is no certificate with an unknown
84       // issuer.
85       return nullptr;
86     }
87     if (used_in_path.find(last_issuer) != used_in_path.end()) {
88       // |certs| contains a loop.
89       return nullptr;
90     }
91     // Continue the search for |last_issuer|'s issuer.
92     last = last_issuer;
93   }
94   NOTREACHED();
95   return nullptr;
96 }
97 
98 // Uses |fetcher| to fetch issuers from |uri|. If the fetch succeeds, the
99 // certificate is parsed and added to |cert_list|. Returns true if the fetch was
100 // successful and the result could be parsed as a certificate, and false
101 // otherwise.
PerformAIAFetchAndAddResultToVector(scoped_refptr<CertNetFetcher> fetcher,std::string_view uri,bssl::ParsedCertificateList * cert_list)102 bool PerformAIAFetchAndAddResultToVector(
103     scoped_refptr<CertNetFetcher> fetcher,
104     std::string_view uri,
105     bssl::ParsedCertificateList* cert_list) {
106   GURL url(uri);
107   if (!url.is_valid())
108     return false;
109   std::unique_ptr<CertNetFetcher::Request> request(fetcher->FetchCaIssuers(
110       url, CertNetFetcher::DEFAULT, CertNetFetcher::DEFAULT));
111   Error error;
112   std::vector<uint8_t> aia_fetch_bytes;
113   request->WaitForResult(&error, &aia_fetch_bytes);
114   if (error != OK)
115     return false;
116   bssl::CertErrors errors;
117   return bssl::ParsedCertificate::CreateAndAddToVector(
118       x509_util::CreateCryptoBuffer(aia_fetch_bytes),
119       x509_util::DefaultParseCertificateOptions(), cert_list, &errors);
120 }
121 
122 // Uses android::VerifyX509CertChain() to verify the certificates in |certs| for
123 // |hostname| and returns the verification status. If the verification was
124 // successful, this function populates |verify_result| and |verified_chain|;
125 // otherwise it leaves them untouched.
AttemptVerificationAfterAIAFetch(const bssl::ParsedCertificateList & certs,const std::string & hostname,CertVerifyResult * verify_result,std::vector<std::string> * verified_chain)126 android::CertVerifyStatusAndroid AttemptVerificationAfterAIAFetch(
127     const bssl::ParsedCertificateList& certs,
128     const std::string& hostname,
129     CertVerifyResult* verify_result,
130     std::vector<std::string>* verified_chain) {
131   std::vector<std::string> cert_bytes;
132   for (const auto& cert : certs) {
133     cert_bytes.push_back(cert->der_cert().AsString());
134   }
135 
136   bool is_issued_by_known_root;
137   std::vector<std::string> candidate_verified_chain;
138   android::CertVerifyStatusAndroid status;
139   android::VerifyX509CertChain(cert_bytes, kAuthType, hostname, &status,
140                                &is_issued_by_known_root,
141                                &candidate_verified_chain);
142 
143   if (status == android::CERT_VERIFY_STATUS_ANDROID_OK) {
144     verify_result->is_issued_by_known_root = is_issued_by_known_root;
145     *verified_chain = candidate_verified_chain;
146   }
147   return status;
148 }
149 
150 // After a CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT error is encountered, this
151 // function can be called to fetch intermediates and retry verification.
152 //
153 // It will start from the first certificate in |cert_bytes| and construct a
154 // chain as far as it can using certificates in |cert_bytes|, and then
155 // iteratively fetch issuers from any AIA URLs in the last certificate in this
156 // chain. It will fetch issuers until it encounters a chain that verifies with
157 // status CERT_VERIFY_STATUS_ANDROID_OK, or it runs out of AIA URLs to fetch, or
158 // it has attempted |kMaxAIAFetches| fetches.
159 //
160 // If it finds a chain that verifies successfully, it returns
161 // CERT_VERIFY_STATUS_ANDROID_OK and sets |verify_result| and |verified_chain|
162 // correspondingly. Otherwise, it returns
163 // CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT and does not modify
164 // |verify_result| or |verified_chain|.
TryVerifyWithAIAFetching(const std::vector<std::string> & cert_bytes,const std::string & hostname,scoped_refptr<CertNetFetcher> cert_net_fetcher,CertVerifyResult * verify_result,std::vector<std::string> * verified_chain)165 android::CertVerifyStatusAndroid TryVerifyWithAIAFetching(
166     const std::vector<std::string>& cert_bytes,
167     const std::string& hostname,
168     scoped_refptr<CertNetFetcher> cert_net_fetcher,
169     CertVerifyResult* verify_result,
170     std::vector<std::string>* verified_chain) {
171   if (!cert_net_fetcher)
172     return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
173 
174   // Convert the certificates into ParsedCertificates for ease of pulling out
175   // AIA URLs.
176   bssl::CertErrors errors;
177   bssl::ParsedCertificateList certs;
178   for (const auto& cert : cert_bytes) {
179     if (!bssl::ParsedCertificate::CreateAndAddToVector(
180             x509_util::CreateCryptoBuffer(cert),
181             x509_util::DefaultParseCertificateOptions(), &certs, &errors)) {
182       return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
183     }
184   }
185 
186   // Build a chain as far as possible from the target certificate at index 0,
187   // using the initially provided certificates.
188   std::shared_ptr<const bssl::ParsedCertificate> last_cert_with_unknown_issuer =
189       FindLastCertWithUnknownIssuer(certs, certs[0]);
190   if (!last_cert_with_unknown_issuer) {
191     // |certs| either contains a loop, or contains a full chain to a self-signed
192     // certificate. Do not attempt AIA fetches for such a chain.
193     return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
194   }
195 
196   unsigned int num_aia_fetches = 0;
197   while (true) {
198     // If chain-building has terminated in a certificate that does not have an
199     // AIA URL, give up.
200     //
201     // TODO(estark): Instead of giving up at this point, it would be more robust
202     // to go back to the certificate before |last_cert| in the chain and attempt
203     // an AIA fetch from that point (if one hasn't already been done). This
204     // would accomodate chains where the server serves Leaf -> I1 signed by a
205     // root not in the client's trust store, but AIA fetching would yield an
206     // intermediate I2 signed by a root that *is* in the client's trust store.
207     if (!last_cert_with_unknown_issuer->has_authority_info_access())
208       return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
209 
210     for (const auto& uri : last_cert_with_unknown_issuer->ca_issuers_uris()) {
211       num_aia_fetches++;
212       if (num_aia_fetches > kMaxAIAFetches)
213         return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
214       if (!PerformAIAFetchAndAddResultToVector(cert_net_fetcher, uri, &certs))
215         continue;
216       android::CertVerifyStatusAndroid status =
217           AttemptVerificationAfterAIAFetch(certs, hostname, verify_result,
218                                            verified_chain);
219       if (status == android::CERT_VERIFY_STATUS_ANDROID_OK)
220         return status;
221     }
222 
223     // If verification still failed but the path expanded, continue to attempt
224     // AIA fetches.
225     std::shared_ptr<const bssl::ParsedCertificate>
226         new_last_cert_with_unknown_issuer =
227             FindLastCertWithUnknownIssuer(certs, last_cert_with_unknown_issuer);
228     if (!new_last_cert_with_unknown_issuer ||
229         new_last_cert_with_unknown_issuer == last_cert_with_unknown_issuer) {
230       // The last round of AIA fetches (if there were any) didn't expand the
231       // path, or it did such that |certs| now contains a full path to an
232       // (untrusted) root or a loop.
233       //
234       // TODO(estark): As above, it would be more robust to go back one
235       // certificate and attempt an AIA fetch from that point.
236       return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
237     }
238     last_cert_with_unknown_issuer = new_last_cert_with_unknown_issuer;
239   }
240 
241   NOTREACHED();
242   return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
243 }
244 
245 // Returns true if the certificate verification call was successful (regardless
246 // of its result), i.e. if |verify_result| was set. Otherwise returns false.
VerifyFromAndroidTrustManager(const std::vector<std::string> & cert_bytes,const std::string & hostname,int flags,scoped_refptr<CertNetFetcher> cert_net_fetcher,CertVerifyResult * verify_result)247 bool VerifyFromAndroidTrustManager(
248     const std::vector<std::string>& cert_bytes,
249     const std::string& hostname,
250     int flags,
251     scoped_refptr<CertNetFetcher> cert_net_fetcher,
252     CertVerifyResult* verify_result) {
253   android::CertVerifyStatusAndroid status;
254   std::vector<std::string> verified_chain;
255 
256   android::VerifyX509CertChain(cert_bytes, kAuthType, hostname, &status,
257                                &verify_result->is_issued_by_known_root,
258                                &verified_chain);
259 
260   // If verification resulted in a NO_TRUSTED_ROOT error, then fetch
261   // intermediates and retry.
262   if (status == android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT &&
263       !(flags & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES)) {
264     status = TryVerifyWithAIAFetching(cert_bytes, hostname,
265                                       std::move(cert_net_fetcher),
266                                       verify_result, &verified_chain);
267   }
268 
269   switch (status) {
270     case android::CERT_VERIFY_STATUS_ANDROID_FAILED:
271       return false;
272     case android::CERT_VERIFY_STATUS_ANDROID_OK:
273       break;
274     case android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT:
275       verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
276       break;
277     case android::CERT_VERIFY_STATUS_ANDROID_EXPIRED:
278     case android::CERT_VERIFY_STATUS_ANDROID_NOT_YET_VALID:
279       verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
280       break;
281     case android::CERT_VERIFY_STATUS_ANDROID_UNABLE_TO_PARSE:
282       verify_result->cert_status |= CERT_STATUS_INVALID;
283       break;
284     case android::CERT_VERIFY_STATUS_ANDROID_INCORRECT_KEY_USAGE:
285       verify_result->cert_status |= CERT_STATUS_INVALID;
286       break;
287     default:
288       NOTREACHED();
289       verify_result->cert_status |= CERT_STATUS_INVALID;
290       break;
291   }
292 
293   // Save the verified chain.
294   if (!verified_chain.empty()) {
295     std::vector<std::string_view> verified_chain_pieces(verified_chain.size());
296     for (size_t i = 0; i < verified_chain.size(); i++) {
297       verified_chain_pieces[i] = std::string_view(verified_chain[i]);
298     }
299     scoped_refptr<X509Certificate> verified_cert =
300         X509Certificate::CreateFromDERCertChain(verified_chain_pieces);
301     if (verified_cert.get())
302       verify_result->verified_cert = std::move(verified_cert);
303     else
304       verify_result->cert_status |= CERT_STATUS_INVALID;
305   }
306 
307   // Extract the public key hashes and check whether or not any are known
308   // roots. Walk from the end of the chain (root) to leaf, to optimize for
309   // known root checks.
310   for (const auto& cert : base::Reversed(verified_chain)) {
311     std::string_view spki_bytes;
312     if (!asn1::ExtractSPKIFromDERCert(cert, &spki_bytes)) {
313       verify_result->cert_status |= CERT_STATUS_INVALID;
314       continue;
315     }
316 
317     HashValue sha256(HASH_VALUE_SHA256);
318     crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length);
319     verify_result->public_key_hashes.push_back(sha256);
320 
321     if (!verify_result->is_issued_by_known_root) {
322       verify_result->is_issued_by_known_root =
323           GetNetTrustAnchorHistogramIdForSPKI(sha256) != 0;
324     }
325   }
326 
327   // Reverse the hash list, to maintain the leaf->root ordering.
328   std::reverse(verify_result->public_key_hashes.begin(),
329                verify_result->public_key_hashes.end());
330 
331   return true;
332 }
333 
GetChainDEREncodedBytes(X509Certificate * cert,std::vector<std::string> * chain_bytes)334 void GetChainDEREncodedBytes(X509Certificate* cert,
335                              std::vector<std::string>* chain_bytes) {
336   chain_bytes->reserve(1 + cert->intermediate_buffers().size());
337   chain_bytes->emplace_back(
338       net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
339   for (const auto& handle : cert->intermediate_buffers()) {
340     chain_bytes->emplace_back(
341         net::x509_util::CryptoBufferAsStringPiece(handle.get()));
342   }
343 }
344 
345 }  // namespace
346 
CertVerifyProcAndroid(scoped_refptr<CertNetFetcher> cert_net_fetcher,scoped_refptr<CRLSet> crl_set)347 CertVerifyProcAndroid::CertVerifyProcAndroid(
348     scoped_refptr<CertNetFetcher> cert_net_fetcher,
349     scoped_refptr<CRLSet> crl_set)
350     : CertVerifyProc(std::move(crl_set)),
351       cert_net_fetcher_(std::move(cert_net_fetcher)) {}
352 
353 CertVerifyProcAndroid::~CertVerifyProcAndroid() = default;
354 
VerifyInternal(X509Certificate * cert,const std::string & hostname,const std::string & ocsp_response,const std::string & sct_list,int flags,CertVerifyResult * verify_result,const NetLogWithSource & net_log,std::optional<base::Time>)355 int CertVerifyProcAndroid::VerifyInternal(X509Certificate* cert,
356                                           const std::string& hostname,
357                                           const std::string& ocsp_response,
358                                           const std::string& sct_list,
359                                           int flags,
360                                           CertVerifyResult* verify_result,
361                                           const NetLogWithSource& net_log,
362                                           std::optional<base::Time>) {
363   std::vector<std::string> cert_bytes;
364   GetChainDEREncodedBytes(cert, &cert_bytes);
365   if (!VerifyFromAndroidTrustManager(cert_bytes, hostname, flags,
366                                      cert_net_fetcher_, verify_result)) {
367     return ERR_FAILED;
368   }
369 
370   if (IsCertStatusError(verify_result->cert_status))
371     return MapCertStatusToNetError(verify_result->cert_status);
372 
373   if (TestRootCerts::HasInstance() &&
374       !verify_result->verified_cert->intermediate_buffers().empty() &&
375       TestRootCerts::GetInstance()->IsKnownRoot(x509_util::CryptoBufferAsSpan(
376           verify_result->verified_cert->intermediate_buffers().back().get()))) {
377     verify_result->is_issued_by_known_root = true;
378   }
379 
380   LogNameNormalizationMetrics(".Android", verify_result->verified_cert.get(),
381                               verify_result->is_issued_by_known_root);
382 
383   return OK;
384 }
385 
386 }  // namespace net
387