1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 "services/network/ignore_errors_cert_verifier.h"
6 
7 #include <iterator>
8 #include <utility>
9 
10 #include "base/base64.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_split.h"
14 #include "crypto/sha2.h"
15 #include "net/base/hash_value.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/net_export.h"
18 #include "net/cert/asn1_util.h"
19 #include "net/cert/cert_verify_result.h"
20 #include "net/cert/x509_certificate.h"
21 #include "net/cert/x509_util.h"
22 #include "services/network/public/cpp/network_switches.h"
23 
24 using ::net::CertVerifier;
25 using ::net::HashValue;
26 using ::net::SHA256HashValue;
27 using ::net::X509Certificate;
28 
29 namespace network {
30 
31 // static
MaybeWrapCertVerifier(const base::CommandLine & command_line,const char * user_data_dir_switch,std::unique_ptr<CertVerifier> verifier)32 std::unique_ptr<CertVerifier> IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
33     const base::CommandLine& command_line,
34     const char* user_data_dir_switch,
35     std::unique_ptr<CertVerifier> verifier) {
36   if ((user_data_dir_switch && !command_line.HasSwitch(user_data_dir_switch)) ||
37       !command_line.HasSwitch(switches::kIgnoreCertificateErrorsSPKIList)) {
38     return verifier;
39   }
40   auto spki_list =
41       base::SplitString(command_line.GetSwitchValueASCII(
42                             switches::kIgnoreCertificateErrorsSPKIList),
43                         ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
44   return std::make_unique<IgnoreErrorsCertVerifier>(
45       std::move(verifier), IgnoreErrorsCertVerifier::MakeWhitelist(spki_list));
46 }
47 
48 // static
MakeWhitelist(const std::vector<std::string> & fingerprints)49 IgnoreErrorsCertVerifier::SPKIHashSet IgnoreErrorsCertVerifier::MakeWhitelist(
50     const std::vector<std::string>& fingerprints) {
51   IgnoreErrorsCertVerifier::SPKIHashSet whitelist;
52   for (const std::string& fingerprint : fingerprints) {
53     HashValue hash;
54     if (!hash.FromString("sha256/" + fingerprint)) {
55       LOG(ERROR) << "Invalid SPKI: " << fingerprint;
56       continue;
57     }
58     SHA256HashValue sha256;
59     DCHECK_EQ(hash.size(), sizeof(sha256));
60     memcpy(&sha256, hash.data(), sizeof(sha256));
61     whitelist.insert(sha256);
62   }
63   return whitelist;
64 }
65 
IgnoreErrorsCertVerifier(std::unique_ptr<CertVerifier> verifier,IgnoreErrorsCertVerifier::SPKIHashSet whitelist)66 IgnoreErrorsCertVerifier::IgnoreErrorsCertVerifier(
67     std::unique_ptr<CertVerifier> verifier,
68     IgnoreErrorsCertVerifier::SPKIHashSet whitelist)
69     : verifier_(std::move(verifier)), whitelist_(std::move(whitelist)) {}
70 
~IgnoreErrorsCertVerifier()71 IgnoreErrorsCertVerifier::~IgnoreErrorsCertVerifier() {}
72 
Verify(const RequestParams & params,net::CertVerifyResult * verify_result,net::CompletionOnceCallback callback,std::unique_ptr<Request> * out_req,const net::NetLogWithSource & net_log)73 int IgnoreErrorsCertVerifier::Verify(const RequestParams& params,
74                                      net::CertVerifyResult* verify_result,
75                                      net::CompletionOnceCallback callback,
76                                      std::unique_ptr<Request>* out_req,
77                                      const net::NetLogWithSource& net_log) {
78   SPKIHashSet spki_fingerprints;
79   base::StringPiece cert_spki;
80   SHA256HashValue hash;
81   if (net::asn1::ExtractSPKIFromDERCert(
82           net::x509_util::CryptoBufferAsStringPiece(
83               params.certificate()->cert_buffer()),
84           &cert_spki)) {
85     crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
86     spki_fingerprints.insert(hash);
87   }
88   for (const auto& intermediate :
89        params.certificate()->intermediate_buffers()) {
90     if (net::asn1::ExtractSPKIFromDERCert(
91             net::x509_util::CryptoBufferAsStringPiece(intermediate.get()),
92             &cert_spki)) {
93       crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
94       spki_fingerprints.insert(hash);
95     }
96   }
97 
98   // Intersect SPKI hashes from the chain with the whitelist.
99   auto whitelist_begin = whitelist_.begin();
100   auto whitelist_end = whitelist_.end();
101   auto fingerprints_begin = spki_fingerprints.begin();
102   auto fingerprints_end = spki_fingerprints.end();
103   bool ignore_errors = false;
104   while (whitelist_begin != whitelist_end &&
105          fingerprints_begin != fingerprints_end) {
106     if (*whitelist_begin < *fingerprints_begin) {
107       ++whitelist_begin;
108     } else if (*fingerprints_begin < *whitelist_begin) {
109       ++fingerprints_begin;
110     } else {
111       ignore_errors = true;
112       break;
113     }
114   }
115 
116   if (ignore_errors) {
117     verify_result->Reset();
118     verify_result->verified_cert = params.certificate();
119     std::transform(spki_fingerprints.begin(), spki_fingerprints.end(),
120                    std::back_inserter(verify_result->public_key_hashes),
121                    [](const SHA256HashValue& v) { return HashValue(v); });
122     if (!params.ocsp_response().empty()) {
123       verify_result->ocsp_result.response_status =
124           net::OCSPVerifyResult::PROVIDED;
125       verify_result->ocsp_result.revocation_status =
126           net::OCSPRevocationStatus::GOOD;
127     }
128     return net::OK;
129   }
130 
131   return verifier_->Verify(params, verify_result, std::move(callback), out_req,
132                            net_log);
133 }
134 
SetConfig(const Config & config)135 void IgnoreErrorsCertVerifier::SetConfig(const Config& config) {
136   verifier_->SetConfig(config);
137 }
138 
set_whitelist(const SPKIHashSet & whitelist)139 void IgnoreErrorsCertVerifier::set_whitelist(const SPKIHashSet& whitelist) {
140   whitelist_ = whitelist;
141 }
142 
143 }  // namespace network
144