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