1 // Copyright 2013 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 "net/quic/crypto/proof_verifier_chromium.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback_helpers.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram_functions.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/strings/stringprintf.h"
16 #include "crypto/signature_verifier.h"
17 #include "net/base/host_port_pair.h"
18 #include "net/base/net_errors.h"
19 #include "net/cert/cert_status_flags.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/cert/ct_policy_enforcer.h"
22 #include "net/cert/ct_policy_status.h"
23 #include "net/cert/ct_verifier.h"
24 #include "net/cert/x509_util.h"
25 #include "net/http/transport_security_state.h"
26 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
27 
28 using base::StringPrintf;
29 using std::string;
30 
31 namespace net {
32 
ProofVerifyDetailsChromium()33 ProofVerifyDetailsChromium::ProofVerifyDetailsChromium()
34     : pkp_bypassed(false), is_fatal_cert_error(false) {}
35 
~ProofVerifyDetailsChromium()36 ProofVerifyDetailsChromium::~ProofVerifyDetailsChromium() {}
37 
38 ProofVerifyDetailsChromium::ProofVerifyDetailsChromium(
39     const ProofVerifyDetailsChromium&) = default;
40 
Clone() const41 quic::ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
42   ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
43   other->cert_verify_result = cert_verify_result;
44   other->ct_verify_result = ct_verify_result;
45   return other;
46 }
47 
48 // A Job handles the verification of a single proof.  It is owned by the
49 // quic::ProofVerifier. If the verification can not complete synchronously, it
50 // will notify the quic::ProofVerifier upon completion.
51 class ProofVerifierChromium::Job {
52  public:
53   Job(ProofVerifierChromium* proof_verifier,
54       CertVerifier* cert_verifier,
55       CTPolicyEnforcer* ct_policy_enforcer,
56       TransportSecurityState* transport_security_state,
57       CTVerifier* cert_transparency_verifier,
58       int cert_verify_flags,
59       const NetLogWithSource& net_log);
60   ~Job();
61 
62   // Starts the proof verification.  If |quic::QUIC_PENDING| is returned, then
63   // |callback| will be invoked asynchronously when the verification completes.
64   quic::QuicAsyncStatus VerifyProof(
65       const std::string& hostname,
66       const uint16_t port,
67       const std::string& server_config,
68       quic::QuicTransportVersion quic_version,
69       quiche::QuicheStringPiece chlo_hash,
70       const std::vector<std::string>& certs,
71       const std::string& cert_sct,
72       const std::string& signature,
73       std::string* error_details,
74       std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
75       std::unique_ptr<quic::ProofVerifierCallback> callback);
76 
77   // Starts the certificate chain verification of |certs|.  If
78   // |quic::QUIC_PENDING| is returned, then |callback| will be invoked
79   // asynchronously when the verification completes.
80   quic::QuicAsyncStatus VerifyCertChain(
81       const std::string& hostname,
82       const std::vector<std::string>& certs,
83       const std::string& ocsp_response,
84       const std::string& cert_sct,
85       std::string* error_details,
86       std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
87       std::unique_ptr<quic::ProofVerifierCallback> callback);
88 
89  private:
90   enum State {
91     STATE_NONE,
92     STATE_VERIFY_CERT,
93     STATE_VERIFY_CERT_COMPLETE,
94   };
95 
96   // Convert |certs| to |cert_|(X509Certificate). Returns true if successful.
97   bool GetX509Certificate(
98       const std::vector<string>& certs,
99       std::string* error_details,
100       std::unique_ptr<quic::ProofVerifyDetails>* verify_details);
101 
102   // Start the cert verification.
103   quic::QuicAsyncStatus VerifyCert(
104       const string& hostname,
105       const uint16_t port,
106       const std::string& ocsp_response,
107       const std::string& cert_sct,
108       std::string* error_details,
109       std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
110       std::unique_ptr<quic::ProofVerifierCallback> callback);
111 
112   int DoLoop(int last_io_result);
113   void OnIOComplete(int result);
114   int DoVerifyCert(int result);
115   int DoVerifyCertComplete(int result);
116 
117   bool VerifySignature(const std::string& signed_data,
118                        quic::QuicTransportVersion quic_version,
119                        quiche::QuicheStringPiece chlo_hash,
120                        const std::string& signature,
121                        const std::string& cert);
122 
123   bool ShouldAllowUnknownRootForHost(const std::string& hostname);
124 
125   // Proof verifier to notify when this jobs completes.
126   ProofVerifierChromium* proof_verifier_;
127 
128   // The underlying verifier used for verifying certificates.
129   CertVerifier* verifier_;
130   std::unique_ptr<CertVerifier::Request> cert_verifier_request_;
131 
132   CTPolicyEnforcer* policy_enforcer_;
133 
134   TransportSecurityState* transport_security_state_;
135 
136   CTVerifier* cert_transparency_verifier_;
137 
138   // |hostname| specifies the hostname for which |certs| is a valid chain.
139   std::string hostname_;
140   // |port| specifies the target port for the connection.
141   uint16_t port_;
142   // Encoded stapled OCSP response for |certs|.
143   std::string ocsp_response_;
144   // Encoded SignedCertificateTimestampList for |certs|.
145   std::string cert_sct_;
146 
147   std::unique_ptr<quic::ProofVerifierCallback> callback_;
148   std::unique_ptr<ProofVerifyDetailsChromium> verify_details_;
149   std::string error_details_;
150 
151   // X509Certificate from a chain of DER encoded certificates.
152   scoped_refptr<X509Certificate> cert_;
153 
154   // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
155   // passed to CertVerifier::Verify.
156   int cert_verify_flags_;
157 
158   // If set to true, enforces policy checking in DoVerifyCertComplete().
159   bool enforce_policy_checking_;
160 
161   State next_state_;
162 
163   base::TimeTicks start_time_;
164 
165   NetLogWithSource net_log_;
166 
167   DISALLOW_COPY_AND_ASSIGN(Job);
168 };
169 
Job(ProofVerifierChromium * proof_verifier,CertVerifier * cert_verifier,CTPolicyEnforcer * ct_policy_enforcer,TransportSecurityState * transport_security_state,CTVerifier * cert_transparency_verifier,int cert_verify_flags,const NetLogWithSource & net_log)170 ProofVerifierChromium::Job::Job(
171     ProofVerifierChromium* proof_verifier,
172     CertVerifier* cert_verifier,
173     CTPolicyEnforcer* ct_policy_enforcer,
174     TransportSecurityState* transport_security_state,
175     CTVerifier* cert_transparency_verifier,
176     int cert_verify_flags,
177     const NetLogWithSource& net_log)
178     : proof_verifier_(proof_verifier),
179       verifier_(cert_verifier),
180       policy_enforcer_(ct_policy_enforcer),
181       transport_security_state_(transport_security_state),
182       cert_transparency_verifier_(cert_transparency_verifier),
183       cert_verify_flags_(cert_verify_flags),
184       enforce_policy_checking_(true),
185       next_state_(STATE_NONE),
186       start_time_(base::TimeTicks::Now()),
187       net_log_(net_log) {
188   CHECK(proof_verifier_);
189   CHECK(verifier_);
190   CHECK(policy_enforcer_);
191   CHECK(transport_security_state_);
192   CHECK(cert_transparency_verifier_);
193 }
194 
~Job()195 ProofVerifierChromium::Job::~Job() {
196   base::TimeTicks end_time = base::TimeTicks::Now();
197   UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime",
198                       end_time - start_time_);
199   // |hostname_| will always be canonicalized to lowercase.
200   if (hostname_.compare("www.google.com") == 0) {
201     UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.google",
202                         end_time - start_time_);
203   }
204 }
205 
VerifyProof(const string & hostname,const uint16_t port,const string & server_config,quic::QuicTransportVersion quic_version,quiche::QuicheStringPiece chlo_hash,const std::vector<string> & certs,const std::string & cert_sct,const string & signature,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details,std::unique_ptr<quic::ProofVerifierCallback> callback)206 quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
207     const string& hostname,
208     const uint16_t port,
209     const string& server_config,
210     quic::QuicTransportVersion quic_version,
211     quiche::QuicheStringPiece chlo_hash,
212     const std::vector<string>& certs,
213     const std::string& cert_sct,
214     const string& signature,
215     std::string* error_details,
216     std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
217     std::unique_ptr<quic::ProofVerifierCallback> callback) {
218   DCHECK(error_details);
219   DCHECK(verify_details);
220   DCHECK(callback);
221 
222   error_details->clear();
223 
224   if (STATE_NONE != next_state_) {
225     *error_details = "Certificate is already set and VerifyProof has begun";
226     DLOG(DFATAL) << *error_details;
227     return quic::QUIC_FAILURE;
228   }
229 
230   verify_details_.reset(new ProofVerifyDetailsChromium);
231 
232   // Converts |certs| to |cert_|.
233   if (!GetX509Certificate(certs, error_details, verify_details))
234     return quic::QUIC_FAILURE;
235 
236   // Note that this is a completely synchronous operation: The CT Log Verifier
237   // gets all the data it needs for SCT verification and does not do any
238   // external communication.
239   cert_transparency_verifier_->Verify(
240       hostname, cert_.get(), std::string(), cert_sct,
241       &verify_details_->ct_verify_result.scts, net_log_);
242 
243   // We call VerifySignature first to avoid copying of server_config and
244   // signature.
245   if (!signature.empty() && !VerifySignature(server_config, quic_version,
246                                              chlo_hash, signature, certs[0])) {
247     *error_details = "Failed to verify signature of server config";
248     DLOG(WARNING) << *error_details;
249     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
250     *verify_details = std::move(verify_details_);
251     return quic::QUIC_FAILURE;
252   }
253 
254   DCHECK(enforce_policy_checking_);
255   return VerifyCert(hostname, port, /*ocsp_response=*/std::string(), cert_sct,
256                     error_details, verify_details, std::move(callback));
257 }
258 
VerifyCertChain(const string & hostname,const std::vector<string> & certs,const std::string & ocsp_response,const std::string & cert_sct,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details,std::unique_ptr<quic::ProofVerifierCallback> callback)259 quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain(
260     const string& hostname,
261     const std::vector<string>& certs,
262     const std::string& ocsp_response,
263     const std::string& cert_sct,
264     std::string* error_details,
265     std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
266     std::unique_ptr<quic::ProofVerifierCallback> callback) {
267   DCHECK(error_details);
268   DCHECK(verify_details);
269   DCHECK(callback);
270 
271   error_details->clear();
272 
273   if (STATE_NONE != next_state_) {
274     *error_details = "Certificate is already set and VerifyCertChain has begun";
275     DLOG(DFATAL) << *error_details;
276     return quic::QUIC_FAILURE;
277   }
278 
279   verify_details_.reset(new ProofVerifyDetailsChromium);
280 
281   // Converts |certs| to |cert_|.
282   if (!GetX509Certificate(certs, error_details, verify_details))
283     return quic::QUIC_FAILURE;
284 
285   enforce_policy_checking_ = false;
286   // |port| is not needed because |enforce_policy_checking_| is false.
287   return VerifyCert(hostname, /*port=*/0, ocsp_response, cert_sct,
288                     error_details, verify_details, std::move(callback));
289 }
290 
GetX509Certificate(const std::vector<string> & certs,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details)291 bool ProofVerifierChromium::Job::GetX509Certificate(
292     const std::vector<string>& certs,
293     std::string* error_details,
294     std::unique_ptr<quic::ProofVerifyDetails>* verify_details) {
295   if (certs.empty()) {
296     *error_details = "Failed to create certificate chain. Certs are empty.";
297     DLOG(WARNING) << *error_details;
298     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
299     *verify_details = std::move(verify_details_);
300     return false;
301   }
302 
303   // Convert certs to X509Certificate.
304   std::vector<quiche::QuicheStringPiece> cert_pieces(certs.size());
305   for (unsigned i = 0; i < certs.size(); i++) {
306     cert_pieces[i] = quiche::QuicheStringPiece(certs[i]);
307   }
308   cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
309   if (!cert_.get()) {
310     *error_details = "Failed to create certificate chain";
311     DLOG(WARNING) << *error_details;
312     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
313     *verify_details = std::move(verify_details_);
314     return false;
315   }
316   return true;
317 }
318 
VerifyCert(const string & hostname,const uint16_t port,const std::string & ocsp_response,const std::string & cert_sct,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details,std::unique_ptr<quic::ProofVerifierCallback> callback)319 quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert(
320     const string& hostname,
321     const uint16_t port,
322     const std::string& ocsp_response,
323     const std::string& cert_sct,
324     std::string* error_details,
325     std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
326     std::unique_ptr<quic::ProofVerifierCallback> callback) {
327   hostname_ = hostname;
328   port_ = port;
329   ocsp_response_ = ocsp_response;
330   cert_sct_ = cert_sct;
331 
332   next_state_ = STATE_VERIFY_CERT;
333   switch (DoLoop(OK)) {
334     case OK:
335       *verify_details = std::move(verify_details_);
336       return quic::QUIC_SUCCESS;
337     case ERR_IO_PENDING:
338       callback_ = std::move(callback);
339       return quic::QUIC_PENDING;
340     default:
341       *error_details = error_details_;
342       *verify_details = std::move(verify_details_);
343       return quic::QUIC_FAILURE;
344   }
345 }
346 
DoLoop(int last_result)347 int ProofVerifierChromium::Job::DoLoop(int last_result) {
348   int rv = last_result;
349   do {
350     State state = next_state_;
351     next_state_ = STATE_NONE;
352     switch (state) {
353       case STATE_VERIFY_CERT:
354         DCHECK(rv == OK);
355         rv = DoVerifyCert(rv);
356         break;
357       case STATE_VERIFY_CERT_COMPLETE:
358         rv = DoVerifyCertComplete(rv);
359         break;
360       case STATE_NONE:
361       default:
362         rv = ERR_UNEXPECTED;
363         LOG(DFATAL) << "unexpected state " << state;
364         break;
365     }
366   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
367   return rv;
368 }
369 
OnIOComplete(int result)370 void ProofVerifierChromium::Job::OnIOComplete(int result) {
371   int rv = DoLoop(result);
372   if (rv != ERR_IO_PENDING) {
373     std::unique_ptr<quic::ProofVerifierCallback> callback(std::move(callback_));
374     // Callback expects quic::ProofVerifyDetails not ProofVerifyDetailsChromium.
375     std::unique_ptr<quic::ProofVerifyDetails> verify_details(
376         std::move(verify_details_));
377     callback->Run(rv == OK, error_details_, &verify_details);
378     // Will delete |this|.
379     proof_verifier_->OnJobComplete(this);
380   }
381 }
382 
DoVerifyCert(int result)383 int ProofVerifierChromium::Job::DoVerifyCert(int result) {
384   next_state_ = STATE_VERIFY_CERT_COMPLETE;
385 
386   return verifier_->Verify(
387       CertVerifier::RequestParams(cert_, hostname_, cert_verify_flags_,
388                                   ocsp_response_, cert_sct_),
389       &verify_details_->cert_verify_result,
390       base::BindOnce(&ProofVerifierChromium::Job::OnIOComplete,
391                      base::Unretained(this)),
392       &cert_verifier_request_, net_log_);
393 }
394 
ShouldAllowUnknownRootForHost(const std::string & hostname)395 bool ProofVerifierChromium::Job::ShouldAllowUnknownRootForHost(
396     const std::string& hostname) {
397   if (base::Contains(proof_verifier_->hostnames_to_allow_unknown_roots_, "")) {
398     return true;
399   }
400   return base::Contains(proof_verifier_->hostnames_to_allow_unknown_roots_,
401                         hostname);
402 }
403 
DoVerifyCertComplete(int result)404 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
405   base::UmaHistogramSparse("Net.QuicSession.CertVerificationResult", -result);
406   cert_verifier_request_.reset();
407 
408   const CertVerifyResult& cert_verify_result =
409       verify_details_->cert_verify_result;
410   const CertStatus cert_status = cert_verify_result.cert_status;
411 
412   // If the connection was good, check HPKP and CT status simultaneously,
413   // but prefer to treat the HPKP error as more serious, if there was one.
414   if (enforce_policy_checking_ && result == OK) {
415     ct::SCTList verified_scts = ct::SCTsMatchingStatus(
416         verify_details_->ct_verify_result.scts, ct::SCT_STATUS_OK);
417 
418     verify_details_->ct_verify_result.policy_compliance =
419         policy_enforcer_->CheckCompliance(
420             cert_verify_result.verified_cert.get(), verified_scts, net_log_);
421     if (verify_details_->cert_verify_result.cert_status & CERT_STATUS_IS_EV) {
422       if (verify_details_->ct_verify_result.policy_compliance !=
423               ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS &&
424           verify_details_->ct_verify_result.policy_compliance !=
425               ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY) {
426         verify_details_->cert_verify_result.cert_status |=
427             CERT_STATUS_CT_COMPLIANCE_FAILED;
428         verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
429       }
430 
431       // Record the CT compliance status for connections with EV certificates,
432       // to distinguish how often EV status is being dropped due to failing CT
433       // compliance.
434       if (verify_details_->cert_verify_result.is_issued_by_known_root) {
435         UMA_HISTOGRAM_ENUMERATION(
436             "Net.CertificateTransparency.EVCompliance2.QUIC",
437             verify_details_->ct_verify_result.policy_compliance,
438             ct::CTPolicyCompliance::CT_POLICY_COUNT);
439       }
440     }
441 
442     // Record the CT compliance of every connection to get an overall picture of
443     // how many connections are CT-compliant.
444     if (verify_details_->cert_verify_result.is_issued_by_known_root) {
445       UMA_HISTOGRAM_ENUMERATION(
446           "Net.CertificateTransparency.ConnectionComplianceStatus2.QUIC",
447           verify_details_->ct_verify_result.policy_compliance,
448           ct::CTPolicyCompliance::CT_POLICY_COUNT);
449     }
450 
451     int ct_result = OK;
452     TransportSecurityState::CTRequirementsStatus ct_requirement_status =
453         transport_security_state_->CheckCTRequirements(
454             HostPortPair(hostname_, port_),
455             cert_verify_result.is_issued_by_known_root,
456             cert_verify_result.public_key_hashes,
457             cert_verify_result.verified_cert.get(), cert_.get(),
458             verify_details_->ct_verify_result.scts,
459             TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
460             verify_details_->ct_verify_result.policy_compliance);
461     if (ct_requirement_status != TransportSecurityState::CT_NOT_REQUIRED) {
462       verify_details_->ct_verify_result.policy_compliance_required = true;
463       if (verify_details_->cert_verify_result.is_issued_by_known_root) {
464         // Record the CT compliance of connections for which compliance is
465         // required; this helps answer the question: "Of all connections that
466         // are supposed to be serving valid CT information, how many fail to do
467         // so?"
468         UMA_HISTOGRAM_ENUMERATION(
469             "Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2."
470             "QUIC",
471             verify_details_->ct_verify_result.policy_compliance,
472             ct::CTPolicyCompliance::CT_POLICY_COUNT);
473       }
474     } else {
475       verify_details_->ct_verify_result.policy_compliance_required = false;
476     }
477 
478     switch (ct_requirement_status) {
479       case TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
480         verify_details_->cert_verify_result.cert_status |=
481             CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
482         ct_result = ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
483         break;
484       case TransportSecurityState::CT_REQUIREMENTS_MET:
485       case TransportSecurityState::CT_NOT_REQUIRED:
486         // Intentional fallthrough; this case is just here to make sure that all
487         // possible values of CheckCTRequirements() are handled.
488         break;
489     }
490 
491     TransportSecurityState::PKPStatus pin_validity =
492         transport_security_state_->CheckPublicKeyPins(
493             HostPortPair(hostname_, port_),
494             cert_verify_result.is_issued_by_known_root,
495             cert_verify_result.public_key_hashes, cert_.get(),
496             cert_verify_result.verified_cert.get(),
497             TransportSecurityState::ENABLE_PIN_REPORTS,
498             &verify_details_->pinning_failure_log);
499     switch (pin_validity) {
500       case TransportSecurityState::PKPStatus::VIOLATED:
501         result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
502         verify_details_->cert_verify_result.cert_status |=
503             CERT_STATUS_PINNED_KEY_MISSING;
504         break;
505       case TransportSecurityState::PKPStatus::BYPASSED:
506         verify_details_->pkp_bypassed = true;
507         FALLTHROUGH;
508       case TransportSecurityState::PKPStatus::OK:
509         // Do nothing.
510         break;
511     }
512     if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
513       result = ct_result;
514   }
515 
516   if (result == OK &&
517       !verify_details_->cert_verify_result.is_issued_by_known_root &&
518       !ShouldAllowUnknownRootForHost(hostname_)) {
519     result = ERR_QUIC_CERT_ROOT_NOT_KNOWN;
520   }
521 
522   verify_details_->is_fatal_cert_error =
523       IsCertStatusError(cert_status) &&
524       result != ERR_CERT_KNOWN_INTERCEPTION_BLOCKED &&
525       transport_security_state_->ShouldSSLErrorsBeFatal(hostname_);
526 
527   if (result != OK) {
528     std::string error_string = ErrorToString(result);
529     error_details_ = StringPrintf("Failed to verify certificate chain: %s",
530                                   error_string.c_str());
531     DLOG(WARNING) << error_details_;
532   }
533 
534   // Exit DoLoop and return the result to the caller to VerifyProof.
535   DCHECK_EQ(STATE_NONE, next_state_);
536   return result;
537 }
538 
VerifySignature(const string & signed_data,quic::QuicTransportVersion quic_version,quiche::QuicheStringPiece chlo_hash,const string & signature,const string & cert)539 bool ProofVerifierChromium::Job::VerifySignature(
540     const string& signed_data,
541     quic::QuicTransportVersion quic_version,
542     quiche::QuicheStringPiece chlo_hash,
543     const string& signature,
544     const string& cert) {
545   size_t size_bits;
546   X509Certificate::PublicKeyType type;
547   X509Certificate::GetPublicKeyInfo(cert_->cert_buffer(), &size_bits, &type);
548   crypto::SignatureVerifier::SignatureAlgorithm algorithm;
549   switch (type) {
550     case X509Certificate::kPublicKeyTypeRSA:
551       algorithm = crypto::SignatureVerifier::RSA_PSS_SHA256;
552       break;
553     case X509Certificate::kPublicKeyTypeECDSA:
554       algorithm = crypto::SignatureVerifier::ECDSA_SHA256;
555       break;
556     default:
557       LOG(ERROR) << "Unsupported public key type " << type;
558       return false;
559   }
560 
561   crypto::SignatureVerifier verifier;
562   if (!x509_util::SignatureVerifierInitWithCertificate(
563           &verifier, algorithm, base::as_bytes(base::make_span(signature)),
564           cert_->cert_buffer())) {
565     DLOG(WARNING) << "SignatureVerifierInitWithCertificate failed";
566     return false;
567   }
568 
569   verifier.VerifyUpdate(
570       base::as_bytes(base::make_span(quic::kProofSignatureLabel)));
571   uint32_t len = chlo_hash.length();
572   verifier.VerifyUpdate(base::as_bytes(base::make_span(&len, 1)));
573   verifier.VerifyUpdate(base::as_bytes(base::make_span(chlo_hash)));
574   verifier.VerifyUpdate(base::as_bytes(base::make_span(signed_data)));
575 
576   if (!verifier.VerifyFinal()) {
577     DLOG(WARNING) << "VerifyFinal failed";
578     return false;
579   }
580 
581   DVLOG(1) << "VerifyFinal success";
582   return true;
583 }
584 
ProofVerifierChromium(CertVerifier * cert_verifier,CTPolicyEnforcer * ct_policy_enforcer,TransportSecurityState * transport_security_state,CTVerifier * cert_transparency_verifier,std::set<std::string> hostnames_to_allow_unknown_roots)585 ProofVerifierChromium::ProofVerifierChromium(
586     CertVerifier* cert_verifier,
587     CTPolicyEnforcer* ct_policy_enforcer,
588     TransportSecurityState* transport_security_state,
589     CTVerifier* cert_transparency_verifier,
590     std::set<std::string> hostnames_to_allow_unknown_roots)
591     : cert_verifier_(cert_verifier),
592       ct_policy_enforcer_(ct_policy_enforcer),
593       transport_security_state_(transport_security_state),
594       cert_transparency_verifier_(cert_transparency_verifier),
595       hostnames_to_allow_unknown_roots_(hostnames_to_allow_unknown_roots) {
596   DCHECK(cert_verifier_);
597   DCHECK(ct_policy_enforcer_);
598   DCHECK(transport_security_state_);
599   DCHECK(cert_transparency_verifier_);
600 }
601 
~ProofVerifierChromium()602 ProofVerifierChromium::~ProofVerifierChromium() {}
603 
VerifyProof(const std::string & hostname,const uint16_t port,const std::string & server_config,quic::QuicTransportVersion quic_version,quiche::QuicheStringPiece chlo_hash,const std::vector<std::string> & certs,const std::string & cert_sct,const std::string & signature,const quic::ProofVerifyContext * verify_context,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details,std::unique_ptr<quic::ProofVerifierCallback> callback)604 quic::QuicAsyncStatus ProofVerifierChromium::VerifyProof(
605     const std::string& hostname,
606     const uint16_t port,
607     const std::string& server_config,
608     quic::QuicTransportVersion quic_version,
609     quiche::QuicheStringPiece chlo_hash,
610     const std::vector<std::string>& certs,
611     const std::string& cert_sct,
612     const std::string& signature,
613     const quic::ProofVerifyContext* verify_context,
614     std::string* error_details,
615     std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
616     std::unique_ptr<quic::ProofVerifierCallback> callback) {
617   if (!verify_context) {
618     DLOG(FATAL) << "Missing proof verify context";
619     *error_details = "Missing context";
620     return quic::QUIC_FAILURE;
621   }
622   const ProofVerifyContextChromium* chromium_context =
623       reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
624   std::unique_ptr<Job> job = std::make_unique<Job>(
625       this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
626       cert_transparency_verifier_, chromium_context->cert_verify_flags,
627       chromium_context->net_log);
628   quic::QuicAsyncStatus status = job->VerifyProof(
629       hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
630       signature, error_details, verify_details, std::move(callback));
631   if (status == quic::QUIC_PENDING) {
632     Job* job_ptr = job.get();
633     active_jobs_[job_ptr] = std::move(job);
634   }
635   return status;
636 }
637 
VerifyCertChain(const std::string & hostname,const std::vector<std::string> & certs,const std::string & ocsp_response,const std::string & cert_sct,const quic::ProofVerifyContext * verify_context,std::string * error_details,std::unique_ptr<quic::ProofVerifyDetails> * verify_details,std::unique_ptr<quic::ProofVerifierCallback> callback)638 quic::QuicAsyncStatus ProofVerifierChromium::VerifyCertChain(
639     const std::string& hostname,
640     const std::vector<std::string>& certs,
641     const std::string& ocsp_response,
642     const std::string& cert_sct,
643     const quic::ProofVerifyContext* verify_context,
644     std::string* error_details,
645     std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
646     std::unique_ptr<quic::ProofVerifierCallback> callback) {
647   if (!verify_context) {
648     *error_details = "Missing context";
649     return quic::QUIC_FAILURE;
650   }
651   const ProofVerifyContextChromium* chromium_context =
652       reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
653   std::unique_ptr<Job> job = std::make_unique<Job>(
654       this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
655       cert_transparency_verifier_, chromium_context->cert_verify_flags,
656       chromium_context->net_log);
657   quic::QuicAsyncStatus status =
658       job->VerifyCertChain(hostname, certs, ocsp_response, cert_sct,
659                            error_details, verify_details, std::move(callback));
660   if (status == quic::QUIC_PENDING) {
661     Job* job_ptr = job.get();
662     active_jobs_[job_ptr] = std::move(job);
663   }
664   return status;
665 }
666 
667 std::unique_ptr<quic::ProofVerifyContext>
CreateDefaultContext()668 ProofVerifierChromium::CreateDefaultContext() {
669   return std::make_unique<ProofVerifyContextChromium>(0,
670                                                       net::NetLogWithSource());
671 }
672 
OnJobComplete(Job * job)673 void ProofVerifierChromium::OnJobComplete(Job* job) {
674   active_jobs_.erase(job);
675 }
676 
677 }  // namespace net
678