blob: d806652a9fed1284a698d9cb2259195d91575f2b [file] [log] [blame]
[email protected]2662ed562013-07-03 10:27:461// 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
Ryan Hamiltona3ee93a72018-08-01 22:03:085#include "net/quic/crypto/proof_verifier_chromium.h"
[email protected]2662ed562013-07-03 10:27:466
dchengc7eeda422015-12-26 03:56:487#include <utility>
8
[email protected]2662ed562013-07-03 10:27:469#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback_helpers.h"
[email protected]2662ed562013-07-03 10:27:4612#include "base/logging.h"
Ilya Sherman0eb39802017-12-08 20:58:1813#include "base/metrics/histogram_functions.h"
asvitkinec3c93722015-06-17 14:48:3714#include "base/metrics/histogram_macros.h"
[email protected]2662ed562013-07-03 10:27:4615#include "base/strings/stringprintf.h"
16#include "crypto/signature_verifier.h"
estark1a66df72015-07-28 15:24:0017#include "net/base/host_port_pair.h"
[email protected]2662ed562013-07-03 10:27:4618#include "net/base/net_errors.h"
[email protected]2662ed562013-07-03 10:27:4619#include "net/cert/cert_status_flags.h"
20#include "net/cert/cert_verifier.h"
estark6f9b3d82016-01-12 21:37:0521#include "net/cert/ct_policy_enforcer.h"
estark723b5eeb2016-02-18 21:01:1222#include "net/cert/ct_policy_status.h"
rtenneti052774e2015-11-24 21:00:1223#include "net/cert/ct_verifier.h"
[email protected]2662ed562013-07-03 10:27:4624#include "net/cert/x509_util.h"
[email protected]080b77932014-08-04 01:22:4625#include "net/http/transport_security_state.h"
Victor Vasiliev6bb59d22019-03-08 21:34:5126#include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
[email protected]2662ed562013-07-03 10:27:4627
[email protected]2662ed562013-07-03 10:27:4628using base::StringPrintf;
29using std::string;
[email protected]2662ed562013-07-03 10:27:4630
31namespace net {
32
dadriandf302c42016-06-10 18:48:5933ProofVerifyDetailsChromium::ProofVerifyDetailsChromium()
Carlos IL81133382017-12-06 17:18:4534 : pkp_bypassed(false), is_fatal_cert_error(false) {}
dadriandf302c42016-06-10 18:48:5935
36ProofVerifyDetailsChromium::~ProofVerifyDetailsChromium() {}
37
38ProofVerifyDetailsChromium::ProofVerifyDetailsChromium(
39 const ProofVerifyDetailsChromium&) = default;
40
Ryan Hamilton8d9ee76e2018-05-29 23:52:5241quic::ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
[email protected]92bc621d2014-07-29 21:42:1342 ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
43 other->cert_verify_result = cert_verify_result;
rtenneti052774e2015-11-24 21:00:1244 other->ct_verify_result = ct_verify_result;
[email protected]92bc621d2014-07-29 21:42:1345 return other;
46}
47
[email protected]5c78ce62014-03-13 19:48:0148// A Job handles the verification of a single proof. It is owned by the
Ryan Hamilton8d9ee76e2018-05-29 23:52:5249// quic::ProofVerifier. If the verification can not complete synchronously, it
50// will notify the quic::ProofVerifier upon completion.
[email protected]5c78ce62014-03-13 19:48:0151class ProofVerifierChromium::Job {
52 public:
53 Job(ProofVerifierChromium* proof_verifier,
54 CertVerifier* cert_verifier,
estark6f9b3d82016-01-12 21:37:0555 CTPolicyEnforcer* ct_policy_enforcer,
[email protected]080b77932014-08-04 01:22:4656 TransportSecurityState* transport_security_state,
rtenneti052774e2015-11-24 21:00:1257 CTVerifier* cert_transparency_verifier,
rtennetia75df622015-06-21 23:59:5058 int cert_verify_flags,
tfarina428341112016-09-22 13:38:2059 const NetLogWithSource& net_log);
rtennetidd4f1bd72015-12-23 19:17:5060 ~Job();
[email protected]5c78ce62014-03-13 19:48:0161
Ryan Hamilton8d9ee76e2018-05-29 23:52:5262 // Starts the proof verification. If |quic::QUIC_PENDING| is returned, then
[email protected]05bfc260f2014-06-07 06:31:2563 // |callback| will be invoked asynchronously when the verification completes.
Ryan Hamilton8d9ee76e2018-05-29 23:52:5264 quic::QuicAsyncStatus VerifyProof(
danakjad1777e2016-04-16 00:56:4265 const std::string& hostname,
66 const uint16_t port,
67 const std::string& server_config,
Ryan Hamilton8d9ee76e2018-05-29 23:52:5268 quic::QuicTransportVersion quic_version,
69 quic::QuicStringPiece chlo_hash,
danakjad1777e2016-04-16 00:56:4270 const std::vector<std::string>& certs,
71 const std::string& cert_sct,
72 const std::string& signature,
73 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:5274 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
75 std::unique_ptr<quic::ProofVerifierCallback> callback);
[email protected]5c78ce62014-03-13 19:48:0176
Ryan Hamilton8d9ee76e2018-05-29 23:52:5277 // 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(
rtennetid073dd22016-08-04 01:58:3381 const std::string& hostname,
82 const std::vector<std::string>& certs,
Matt Mueller7d5464b2019-05-15 20:18:4583 const std::string& ocsp_response,
84 const std::string& cert_sct,
rtennetid073dd22016-08-04 01:58:3385 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:5286 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
87 std::unique_ptr<quic::ProofVerifierCallback> callback);
rtennetid073dd22016-08-04 01:58:3388
[email protected]5c78ce62014-03-13 19:48:0189 private:
90 enum State {
91 STATE_NONE,
92 STATE_VERIFY_CERT,
93 STATE_VERIFY_CERT_COMPLETE,
94 };
95
rtennetid073dd22016-08-04 01:58:3396 // Convert |certs| to |cert_|(X509Certificate). Returns true if successful.
Ryan Hamilton8d9ee76e2018-05-29 23:52:5297 bool GetX509Certificate(
98 const std::vector<string>& certs,
99 std::string* error_details,
100 std::unique_ptr<quic::ProofVerifyDetails>* verify_details);
rtennetid073dd22016-08-04 01:58:33101
102 // Start the cert verification.
Ryan Hamilton8d9ee76e2018-05-29 23:52:52103 quic::QuicAsyncStatus VerifyCert(
rtennetid073dd22016-08-04 01:58:33104 const string& hostname,
105 const uint16_t port,
Matt Mueller7d5464b2019-05-15 20:18:45106 const std::string& ocsp_response,
107 const std::string& cert_sct,
rtennetid073dd22016-08-04 01:58:33108 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52109 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
110 std::unique_ptr<quic::ProofVerifierCallback> callback);
rtennetid073dd22016-08-04 01:58:33111
[email protected]5c78ce62014-03-13 19:48:01112 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,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52118 quic::QuicTransportVersion quic_version,
119 quic::QuicStringPiece chlo_hash,
[email protected]5c78ce62014-03-13 19:48:01120 const std::string& signature,
121 const std::string& cert);
122
123 // Proof verifier to notify when this jobs completes.
124 ProofVerifierChromium* proof_verifier_;
125
126 // The underlying verifier used for verifying certificates.
eroman7f9236a2015-05-11 21:23:43127 CertVerifier* verifier_;
danakjad1777e2016-04-16 00:56:42128 std::unique_ptr<CertVerifier::Request> cert_verifier_request_;
[email protected]5c78ce62014-03-13 19:48:01129
estark6f9b3d82016-01-12 21:37:05130 CTPolicyEnforcer* policy_enforcer_;
rsleevi9541f8632015-07-31 00:07:00131
[email protected]080b77932014-08-04 01:22:46132 TransportSecurityState* transport_security_state_;
133
rtenneti052774e2015-11-24 21:00:12134 CTVerifier* cert_transparency_verifier_;
135
[email protected]5c78ce62014-03-13 19:48:01136 // |hostname| specifies the hostname for which |certs| is a valid chain.
137 std::string hostname_;
elawrence954bb5472016-04-04 22:03:11138 // |port| specifies the target port for the connection.
139 uint16_t port_;
Matt Mueller7d5464b2019-05-15 20:18:45140 // Encoded stapled OCSP response for |certs|.
141 std::string ocsp_response_;
142 // Encoded SignedCertificateTimestampList for |certs|.
143 std::string cert_sct_;
[email protected]5c78ce62014-03-13 19:48:01144
Ryan Hamilton8d9ee76e2018-05-29 23:52:52145 std::unique_ptr<quic::ProofVerifierCallback> callback_;
danakjad1777e2016-04-16 00:56:42146 std::unique_ptr<ProofVerifyDetailsChromium> verify_details_;
[email protected]5c78ce62014-03-13 19:48:01147 std::string error_details_;
148
149 // X509Certificate from a chain of DER encoded certificates.
150 scoped_refptr<X509Certificate> cert_;
151
rtennetia75df622015-06-21 23:59:50152 // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
153 // passed to CertVerifier::Verify.
154 int cert_verify_flags_;
155
rtennetid073dd22016-08-04 01:58:33156 // If set to true, enforces policy checking in DoVerifyCertComplete().
157 bool enforce_policy_checking_;
158
[email protected]5c78ce62014-03-13 19:48:01159 State next_state_;
160
rtennetidd4f1bd72015-12-23 19:17:50161 base::TimeTicks start_time_;
162
tfarina428341112016-09-22 13:38:20163 NetLogWithSource net_log_;
[email protected]5c78ce62014-03-13 19:48:01164
165 DISALLOW_COPY_AND_ASSIGN(Job);
166};
167
[email protected]080b77932014-08-04 01:22:46168ProofVerifierChromium::Job::Job(
169 ProofVerifierChromium* proof_verifier,
170 CertVerifier* cert_verifier,
estark6f9b3d82016-01-12 21:37:05171 CTPolicyEnforcer* ct_policy_enforcer,
[email protected]080b77932014-08-04 01:22:46172 TransportSecurityState* transport_security_state,
rtenneti052774e2015-11-24 21:00:12173 CTVerifier* cert_transparency_verifier,
rtennetia75df622015-06-21 23:59:50174 int cert_verify_flags,
tfarina428341112016-09-22 13:38:20175 const NetLogWithSource& net_log)
[email protected]5c78ce62014-03-13 19:48:01176 : proof_verifier_(proof_verifier),
eroman7f9236a2015-05-11 21:23:43177 verifier_(cert_verifier),
estark6f9b3d82016-01-12 21:37:05178 policy_enforcer_(ct_policy_enforcer),
[email protected]080b77932014-08-04 01:22:46179 transport_security_state_(transport_security_state),
rtenneti052774e2015-11-24 21:00:12180 cert_transparency_verifier_(cert_transparency_verifier),
rtennetia75df622015-06-21 23:59:50181 cert_verify_flags_(cert_verify_flags),
rtennetid073dd22016-08-04 01:58:33182 enforce_policy_checking_(true),
[email protected]5c78ce62014-03-13 19:48:01183 next_state_(STATE_NONE),
rtennetidd4f1bd72015-12-23 19:17:50184 start_time_(base::TimeTicks::Now()),
rsleevid6de8302016-06-21 01:33:20185 net_log_(net_log) {
rsleevibe81cd62016-06-24 01:38:59186 CHECK(proof_verifier_);
187 CHECK(verifier_);
188 CHECK(policy_enforcer_);
189 CHECK(transport_security_state_);
190 CHECK(cert_transparency_verifier_);
rsleevid6de8302016-06-21 01:33:20191}
[email protected]2662ed562013-07-03 10:27:46192
rtennetidd4f1bd72015-12-23 19:17:50193ProofVerifierChromium::Job::~Job() {
194 base::TimeTicks end_time = base::TimeTicks::Now();
195 UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime",
196 end_time - start_time_);
197 // |hostname_| will always be canonicalized to lowercase.
198 if (hostname_.compare("www.google.com") == 0) {
199 UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.google",
200 end_time - start_time_);
201 }
202}
203
Ryan Hamilton8d9ee76e2018-05-29 23:52:52204quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
[email protected]72e65992013-07-30 17:16:14205 const string& hostname,
elawrence954bb5472016-04-04 22:03:11206 const uint16_t port,
[email protected]72e65992013-07-30 17:16:14207 const string& server_config,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52208 quic::QuicTransportVersion quic_version,
209 quic::QuicStringPiece chlo_hash,
rch872e00e2016-12-02 02:48:18210 const std::vector<string>& certs,
rjshadec86dbfa2015-11-12 20:16:25211 const std::string& cert_sct,
[email protected]72e65992013-07-30 17:16:14212 const string& signature,
213 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52214 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
215 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]2662ed562013-07-03 10:27:46216 DCHECK(error_details);
[email protected]c817c672014-03-21 22:25:34217 DCHECK(verify_details);
[email protected]72e65992013-07-30 17:16:14218 DCHECK(callback);
219
[email protected]2662ed562013-07-03 10:27:46220 error_details->clear();
221
[email protected]2662ed562013-07-03 10:27:46222 if (STATE_NONE != next_state_) {
223 *error_details = "Certificate is already set and VerifyProof has begun";
[email protected]5c78ce62014-03-13 19:48:01224 DLOG(DFATAL) << *error_details;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52225 return quic::QUIC_FAILURE;
[email protected]2662ed562013-07-03 10:27:46226 }
227
[email protected]72e65992013-07-30 17:16:14228 verify_details_.reset(new ProofVerifyDetailsChromium);
229
rtennetid073dd22016-08-04 01:58:33230 // Converts |certs| to |cert_|.
231 if (!GetX509Certificate(certs, error_details, verify_details))
Ryan Hamilton8d9ee76e2018-05-29 23:52:52232 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33233
rch71bd2332017-02-04 00:06:47234 // Note that this is a completely synchronous operation: The CT Log Verifier
235 // gets all the data it needs for SCT verification and does not do any
236 // external communication.
Rob Percivalbc658a22017-12-13 08:24:42237 cert_transparency_verifier_->Verify(
238 hostname, cert_.get(), std::string(), cert_sct,
239 &verify_details_->ct_verify_result.scts, net_log_);
rtennetid073dd22016-08-04 01:58:33240
241 // We call VerifySignature first to avoid copying of server_config and
242 // signature.
Ryan Hamiltona3ee93a72018-08-01 22:03:08243 if (!signature.empty() && !VerifySignature(server_config, quic_version,
244 chlo_hash, signature, certs[0])) {
rtennetid073dd22016-08-04 01:58:33245 *error_details = "Failed to verify signature of server config";
246 DLOG(WARNING) << *error_details;
247 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
248 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52249 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33250 }
251
252 DCHECK(enforce_policy_checking_);
Matt Mueller7d5464b2019-05-15 20:18:45253 return VerifyCert(hostname, port, /*ocsp_response=*/std::string(), cert_sct,
254 error_details, verify_details, std::move(callback));
rtennetid073dd22016-08-04 01:58:33255}
256
Ryan Hamilton8d9ee76e2018-05-29 23:52:52257quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain(
rtennetid073dd22016-08-04 01:58:33258 const string& hostname,
rch872e00e2016-12-02 02:48:18259 const std::vector<string>& certs,
Matt Mueller7d5464b2019-05-15 20:18:45260 const std::string& ocsp_response,
261 const std::string& cert_sct,
rtennetid073dd22016-08-04 01:58:33262 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52263 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
264 std::unique_ptr<quic::ProofVerifierCallback> callback) {
rtennetid073dd22016-08-04 01:58:33265 DCHECK(error_details);
266 DCHECK(verify_details);
267 DCHECK(callback);
268
269 error_details->clear();
270
271 if (STATE_NONE != next_state_) {
272 *error_details = "Certificate is already set and VerifyCertChain has begun";
273 DLOG(DFATAL) << *error_details;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52274 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33275 }
276
277 verify_details_.reset(new ProofVerifyDetailsChromium);
278
279 // Converts |certs| to |cert_|.
280 if (!GetX509Certificate(certs, error_details, verify_details))
Ryan Hamilton8d9ee76e2018-05-29 23:52:52281 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33282
283 enforce_policy_checking_ = false;
284 // |port| is not needed because |enforce_policy_checking_| is false.
Matt Mueller7d5464b2019-05-15 20:18:45285 return VerifyCert(hostname, /*port=*/0, ocsp_response, cert_sct,
286 error_details, verify_details, std::move(callback));
rtennetid073dd22016-08-04 01:58:33287}
288
289bool ProofVerifierChromium::Job::GetX509Certificate(
rch872e00e2016-12-02 02:48:18290 const std::vector<string>& certs,
rtennetid073dd22016-08-04 01:58:33291 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52292 std::unique_ptr<quic::ProofVerifyDetails>* verify_details) {
rtennetic14d86fd2016-07-10 16:33:34293 if (certs.empty()) {
294 *error_details = "Failed to create certificate chain. Certs are empty.";
295 DLOG(WARNING) << *error_details;
296 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
297 *verify_details = std::move(verify_details_);
rtennetid073dd22016-08-04 01:58:33298 return false;
rtennetic14d86fd2016-07-10 16:33:34299 }
300
301 // Convert certs to X509Certificate.
Ryan Hamilton8d9ee76e2018-05-29 23:52:52302 std::vector<quic::QuicStringPiece> cert_pieces(certs.size());
rtennetic14d86fd2016-07-10 16:33:34303 for (unsigned i = 0; i < certs.size(); i++) {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52304 cert_pieces[i] = quic::QuicStringPiece(certs[i]);
rtennetic14d86fd2016-07-10 16:33:34305 }
306 cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
307 if (!cert_.get()) {
308 *error_details = "Failed to create certificate chain";
309 DLOG(WARNING) << *error_details;
310 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
311 *verify_details = std::move(verify_details_);
rtennetid073dd22016-08-04 01:58:33312 return false;
rtennetic14d86fd2016-07-10 16:33:34313 }
rtennetid073dd22016-08-04 01:58:33314 return true;
315}
[email protected]2662ed562013-07-03 10:27:46316
Ryan Hamilton8d9ee76e2018-05-29 23:52:52317quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert(
rtennetid073dd22016-08-04 01:58:33318 const string& hostname,
319 const uint16_t port,
Matt Mueller7d5464b2019-05-15 20:18:45320 const std::string& ocsp_response,
321 const std::string& cert_sct,
rtennetid073dd22016-08-04 01:58:33322 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52323 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
324 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]2662ed562013-07-03 10:27:46325 hostname_ = hostname;
elawrence954bb5472016-04-04 22:03:11326 port_ = port;
Matt Mueller7d5464b2019-05-15 20:18:45327 ocsp_response_ = ocsp_response;
328 cert_sct_ = cert_sct;
[email protected]2662ed562013-07-03 10:27:46329
330 next_state_ = STATE_VERIFY_CERT;
[email protected]72e65992013-07-30 17:16:14331 switch (DoLoop(OK)) {
332 case OK:
dchengc7eeda422015-12-26 03:56:48333 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52334 return quic::QUIC_SUCCESS;
[email protected]72e65992013-07-30 17:16:14335 case ERR_IO_PENDING:
ckrasic6567aa52016-07-08 09:24:35336 callback_ = std::move(callback);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52337 return quic::QUIC_PENDING;
[email protected]72e65992013-07-30 17:16:14338 default:
339 *error_details = error_details_;
dchengc7eeda422015-12-26 03:56:48340 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52341 return quic::QUIC_FAILURE;
[email protected]72e65992013-07-30 17:16:14342 }
[email protected]2662ed562013-07-03 10:27:46343}
344
[email protected]5c78ce62014-03-13 19:48:01345int ProofVerifierChromium::Job::DoLoop(int last_result) {
[email protected]2662ed562013-07-03 10:27:46346 int rv = last_result;
347 do {
348 State state = next_state_;
349 next_state_ = STATE_NONE;
350 switch (state) {
351 case STATE_VERIFY_CERT:
352 DCHECK(rv == OK);
353 rv = DoVerifyCert(rv);
354 break;
355 case STATE_VERIFY_CERT_COMPLETE:
356 rv = DoVerifyCertComplete(rv);
357 break;
358 case STATE_NONE:
359 default:
360 rv = ERR_UNEXPECTED;
361 LOG(DFATAL) << "unexpected state " << state;
362 break;
363 }
364 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
365 return rv;
366}
367
[email protected]5c78ce62014-03-13 19:48:01368void ProofVerifierChromium::Job::OnIOComplete(int result) {
[email protected]2662ed562013-07-03 10:27:46369 int rv = DoLoop(result);
370 if (rv != ERR_IO_PENDING) {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52371 std::unique_ptr<quic::ProofVerifierCallback> callback(std::move(callback_));
372 // Callback expects quic::ProofVerifyDetails not ProofVerifyDetailsChromium.
373 std::unique_ptr<quic::ProofVerifyDetails> verify_details(
danakjad1777e2016-04-16 00:56:42374 std::move(verify_details_));
[email protected]5c78ce62014-03-13 19:48:01375 callback->Run(rv == OK, error_details_, &verify_details);
376 // Will delete |this|.
377 proof_verifier_->OnJobComplete(this);
[email protected]2662ed562013-07-03 10:27:46378 }
379}
380
[email protected]5c78ce62014-03-13 19:48:01381int ProofVerifierChromium::Job::DoVerifyCert(int result) {
[email protected]2662ed562013-07-03 10:27:46382 next_state_ = STATE_VERIFY_CERT_COMPLETE;
383
rtennetia75df622015-06-21 23:59:50384 return verifier_->Verify(
rsleevi06bd78552016-06-08 22:34:46385 CertVerifier::RequestParams(cert_, hostname_, cert_verify_flags_,
Matt Mueller7d5464b2019-05-15 20:18:45386 ocsp_response_, cert_sct_),
Ryan Sleevib369d712018-08-20 16:43:22387 &verify_details_->cert_verify_result,
Yannic Bonenberger3c96beb2019-09-03 20:41:37388 base::BindOnce(&ProofVerifierChromium::Job::OnIOComplete,
389 base::Unretained(this)),
rtennetia75df622015-06-21 23:59:50390 &cert_verifier_request_, net_log_);
[email protected]2662ed562013-07-03 10:27:46391}
392
[email protected]5c78ce62014-03-13 19:48:01393int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
Ilya Sherman0eb39802017-12-08 20:58:18394 base::UmaHistogramSparse("Net.QuicSession.CertVerificationResult", -result);
eroman7f9236a2015-05-11 21:23:43395 cert_verifier_request_.reset();
[email protected]2662ed562013-07-03 10:27:46396
[email protected]080b77932014-08-04 01:22:46397 const CertVerifyResult& cert_verify_result =
398 verify_details_->cert_verify_result;
[email protected]080b77932014-08-04 01:22:46399 const CertStatus cert_status = cert_verify_result.cert_status;
rsleevi4a6ca8c2016-06-24 03:05:22400
401 // If the connection was good, check HPKP and CT status simultaneously,
402 // but prefer to treat the HPKP error as more serious, if there was one.
Matt Mueller936511442019-09-03 18:15:12403 if (enforce_policy_checking_ && result == OK) {
Ryan Sleevi8a9c9c12018-05-09 02:36:23404 ct::SCTList verified_scts = ct::SCTsMatchingStatus(
eranm4bed0b572016-08-14 21:00:35405 verify_details_->ct_verify_result.scts, ct::SCT_STATUS_OK);
estark0fc8d0782016-02-25 20:41:20406
Emily Stark627238f2017-11-29 03:29:54407 verify_details_->ct_verify_result.policy_compliance =
408 policy_enforcer_->CheckCompliance(
eranm4bed0b572016-08-14 21:00:35409 cert_verify_result.verified_cert.get(), verified_scts, net_log_);
Emily Stark0d9809e2017-10-18 08:29:15410 if (verify_details_->cert_verify_result.cert_status & CERT_STATUS_IS_EV) {
Emily Stark627238f2017-11-29 03:29:54411 if (verify_details_->ct_verify_result.policy_compliance !=
Ryan Sleevi8a9c9c12018-05-09 02:36:23412 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS &&
413 verify_details_->ct_verify_result.policy_compliance !=
414 ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY) {
Emily Stark0d9809e2017-10-18 08:29:15415 verify_details_->cert_verify_result.cert_status |=
416 CERT_STATUS_CT_COMPLIANCE_FAILED;
417 verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
418 }
419
420 // Record the CT compliance status for connections with EV certificates,
421 // to distinguish how often EV status is being dropped due to failing CT
422 // compliance.
Emily Starkefce7832017-11-30 03:16:16423 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
424 UMA_HISTOGRAM_ENUMERATION(
425 "Net.CertificateTransparency.EVCompliance2.QUIC",
426 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45427 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16428 }
rsleevicd7390e2017-06-14 10:18:26429 }
rsleevi9541f8632015-07-31 00:07:00430
Emily Stark0d9809e2017-10-18 08:29:15431 // Record the CT compliance of every connection to get an overall picture of
432 // how many connections are CT-compliant.
Emily Starkefce7832017-11-30 03:16:16433 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
434 UMA_HISTOGRAM_ENUMERATION(
435 "Net.CertificateTransparency.ConnectionComplianceStatus2.QUIC",
436 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45437 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16438 }
Emily Starkc96e9bc2017-10-10 00:10:39439
rsleevi4a6ca8c2016-06-24 03:05:22440 int ct_result = OK;
Emily Stark0d9809e2017-10-18 08:29:15441 TransportSecurityState::CTRequirementsStatus ct_requirement_status =
442 transport_security_state_->CheckCTRequirements(
estarkbf1b52962017-05-05 17:05:25443 HostPortPair(hostname_, port_),
444 cert_verify_result.is_issued_by_known_root,
445 cert_verify_result.public_key_hashes,
446 cert_verify_result.verified_cert.get(), cert_.get(),
447 verify_details_->ct_verify_result.scts,
448 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
Emily Stark627238f2017-11-29 03:29:54449 verify_details_->ct_verify_result.policy_compliance);
Emily Stark0d9809e2017-10-18 08:29:15450 if (ct_requirement_status != TransportSecurityState::CT_NOT_REQUIRED) {
Emily Stark8b411de02017-11-23 20:21:27451 verify_details_->ct_verify_result.policy_compliance_required = true;
Emily Starkefce7832017-11-30 03:16:16452 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
453 // Record the CT compliance of connections for which compliance is
454 // required; this helps answer the question: "Of all connections that
455 // are supposed to be serving valid CT information, how many fail to do
456 // so?"
457 UMA_HISTOGRAM_ENUMERATION(
458 "Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2."
459 "QUIC",
460 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45461 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16462 }
Emily Stark8b411de02017-11-23 20:21:27463 } else {
464 verify_details_->ct_verify_result.policy_compliance_required = false;
Emily Stark0d9809e2017-10-18 08:29:15465 }
466
467 switch (ct_requirement_status) {
468 case TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
469 verify_details_->cert_verify_result.cert_status |=
470 CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
471 ct_result = ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
Emily Stark8b411de02017-11-23 20:21:27472 break;
Emily Stark0d9809e2017-10-18 08:29:15473 case TransportSecurityState::CT_REQUIREMENTS_MET:
474 case TransportSecurityState::CT_NOT_REQUIRED:
475 // Intentional fallthrough; this case is just here to make sure that all
476 // possible values of CheckCTRequirements() are handled.
477 break;
rsleevi4a6ca8c2016-06-24 03:05:22478 }
479
dadrian8f8946652016-06-21 23:48:31480 TransportSecurityState::PKPStatus pin_validity =
481 transport_security_state_->CheckPublicKeyPins(
482 HostPortPair(hostname_, port_),
483 cert_verify_result.is_issued_by_known_root,
484 cert_verify_result.public_key_hashes, cert_.get(),
485 cert_verify_result.verified_cert.get(),
486 TransportSecurityState::ENABLE_PIN_REPORTS,
487 &verify_details_->pinning_failure_log);
488 switch (pin_validity) {
489 case TransportSecurityState::PKPStatus::VIOLATED:
490 result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
491 verify_details_->cert_verify_result.cert_status |=
492 CERT_STATUS_PINNED_KEY_MISSING;
493 break;
494 case TransportSecurityState::PKPStatus::BYPASSED:
495 verify_details_->pkp_bypassed = true;
Nico Weber63e03762018-01-26 17:55:14496 FALLTHROUGH;
dadrian8f8946652016-06-21 23:48:31497 case TransportSecurityState::PKPStatus::OK:
498 // Do nothing.
499 break;
rsleevi9545d342016-06-21 03:17:37500 }
rsleevi4a6ca8c2016-06-24 03:05:22501 if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
502 result = ct_result;
[email protected]080b77932014-08-04 01:22:46503 }
[email protected]080b77932014-08-04 01:22:46504
Nick Harper3f3ae7b2019-08-22 20:33:37505 if (result == OK &&
506 !verify_details_->cert_verify_result.is_issued_by_known_root &&
507 !base::Contains(proof_verifier_->hostnames_to_allow_unknown_roots_,
508 hostname_)) {
509 result = ERR_QUIC_CERT_ROOT_NOT_KNOWN;
510 }
511
Carlos IL81133382017-12-06 17:18:45512 verify_details_->is_fatal_cert_error =
Matt Mueller936511442019-09-03 18:15:12513 IsCertStatusError(cert_status) &&
Carlos IL81133382017-12-06 17:18:45514 transport_security_state_->ShouldSSLErrorsBeFatal(hostname_);
515
[email protected]0cceb922014-07-01 02:00:56516 if (result != OK) {
[email protected]3030374e32014-08-07 16:12:06517 std::string error_string = ErrorToString(result);
[email protected]72e65992013-07-30 17:16:14518 error_details_ = StringPrintf("Failed to verify certificate chain: %s",
[email protected]3030374e32014-08-07 16:12:06519 error_string.c_str());
[email protected]72e65992013-07-30 17:16:14520 DLOG(WARNING) << error_details_;
[email protected]2662ed562013-07-03 10:27:46521 }
522
523 // Exit DoLoop and return the result to the caller to VerifyProof.
524 DCHECK_EQ(STATE_NONE, next_state_);
525 return result;
526}
527
Michael Warres74ee3ce2017-10-09 15:26:37528bool ProofVerifierChromium::Job::VerifySignature(
529 const string& signed_data,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52530 quic::QuicTransportVersion quic_version,
531 quic::QuicStringPiece chlo_hash,
Michael Warres74ee3ce2017-10-09 15:26:37532 const string& signature,
533 const string& cert) {
[email protected]2662ed562013-07-03 10:27:46534 size_t size_bits;
535 X509Certificate::PublicKeyType type;
Matt Muellera4193272017-12-07 00:23:34536 X509Certificate::GetPublicKeyInfo(cert_->cert_buffer(), &size_bits, &type);
David Benjamin8982fe4f2018-02-06 19:30:32537 crypto::SignatureVerifier::SignatureAlgorithm algorithm;
538 switch (type) {
539 case X509Certificate::kPublicKeyTypeRSA:
540 algorithm = crypto::SignatureVerifier::RSA_PSS_SHA256;
541 break;
542 case X509Certificate::kPublicKeyTypeECDSA:
543 algorithm = crypto::SignatureVerifier::ECDSA_SHA256;
544 break;
545 default:
546 LOG(ERROR) << "Unsupported public key type " << type;
547 return false;
548 }
[email protected]2662ed562013-07-03 10:27:46549
David Benjamin8982fe4f2018-02-06 19:30:32550 crypto::SignatureVerifier verifier;
David Benjamin03c28a42018-05-11 23:12:07551 if (!x509_util::SignatureVerifierInitWithCertificate(
552 &verifier, algorithm, base::as_bytes(base::make_span(signature)),
553 cert_->cert_buffer())) {
554 DLOG(WARNING) << "SignatureVerifierInitWithCertificate failed";
[email protected]2662ed562013-07-03 10:27:46555 return false;
556 }
557
Ryan Hamilton8d9ee76e2018-05-29 23:52:52558 verifier.VerifyUpdate(
559 base::as_bytes(base::make_span(quic::kProofSignatureLabel)));
zhongyi7cbefb312016-10-11 19:03:47560 uint32_t len = chlo_hash.length();
jdoerrie2917a61e2018-05-02 09:39:14561 verifier.VerifyUpdate(base::as_bytes(base::make_span(&len, 1)));
562 verifier.VerifyUpdate(base::as_bytes(base::make_span(chlo_hash)));
563 verifier.VerifyUpdate(base::as_bytes(base::make_span(signed_data)));
[email protected]2662ed562013-07-03 10:27:46564
565 if (!verifier.VerifyFinal()) {
566 DLOG(WARNING) << "VerifyFinal failed";
567 return false;
568 }
569
[email protected]3e5fed12013-11-22 22:21:41570 DVLOG(1) << "VerifyFinal success";
[email protected]2662ed562013-07-03 10:27:46571 return true;
572}
573
[email protected]080b77932014-08-04 01:22:46574ProofVerifierChromium::ProofVerifierChromium(
575 CertVerifier* cert_verifier,
estark6f9b3d82016-01-12 21:37:05576 CTPolicyEnforcer* ct_policy_enforcer,
rtenneti052774e2015-11-24 21:00:12577 TransportSecurityState* transport_security_state,
Nick Harper3f3ae7b2019-08-22 20:33:37578 CTVerifier* cert_transparency_verifier,
579 std::set<std::string> hostnames_to_allow_unknown_roots)
[email protected]080b77932014-08-04 01:22:46580 : cert_verifier_(cert_verifier),
estark6f9b3d82016-01-12 21:37:05581 ct_policy_enforcer_(ct_policy_enforcer),
rtenneti052774e2015-11-24 21:00:12582 transport_security_state_(transport_security_state),
Nick Harper3f3ae7b2019-08-22 20:33:37583 cert_transparency_verifier_(cert_transparency_verifier),
584 hostnames_to_allow_unknown_roots_(hostnames_to_allow_unknown_roots) {
rsleevid6de8302016-06-21 01:33:20585 DCHECK(cert_verifier_);
586 DCHECK(ct_policy_enforcer_);
587 DCHECK(transport_security_state_);
588 DCHECK(cert_transparency_verifier_);
589}
[email protected]5c78ce62014-03-13 19:48:01590
Ryan Hamiltona3ee93a72018-08-01 22:03:08591ProofVerifierChromium::~ProofVerifierChromium() {}
[email protected]5c78ce62014-03-13 19:48:01592
Ryan Hamilton8d9ee76e2018-05-29 23:52:52593quic::QuicAsyncStatus ProofVerifierChromium::VerifyProof(
[email protected]5c78ce62014-03-13 19:48:01594 const std::string& hostname,
elawrence954bb5472016-04-04 22:03:11595 const uint16_t port,
[email protected]5c78ce62014-03-13 19:48:01596 const std::string& server_config,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52597 quic::QuicTransportVersion quic_version,
598 quic::QuicStringPiece chlo_hash,
[email protected]5c78ce62014-03-13 19:48:01599 const std::vector<std::string>& certs,
rjshadec86dbfa2015-11-12 20:16:25600 const std::string& cert_sct,
[email protected]5c78ce62014-03-13 19:48:01601 const std::string& signature,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52602 const quic::ProofVerifyContext* verify_context,
[email protected]5c78ce62014-03-13 19:48:01603 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52604 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
605 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]c817c672014-03-21 22:25:34606 if (!verify_context) {
Ryan Hamilton8bb19a12018-07-23 20:29:24607 DLOG(FATAL) << "Missing proof verify context";
[email protected]c817c672014-03-21 22:25:34608 *error_details = "Missing context";
Ryan Hamilton8d9ee76e2018-05-29 23:52:52609 return quic::QUIC_FAILURE;
[email protected]c817c672014-03-21 22:25:34610 }
611 const ProofVerifyContextChromium* chromium_context =
612 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
Jeremy Roman0579ed62017-08-29 15:56:19613 std::unique_ptr<Job> job = std::make_unique<Job>(
avib3635452016-10-21 18:33:53614 this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
615 cert_transparency_verifier_, chromium_context->cert_verify_flags,
616 chromium_context->net_log);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52617 quic::QuicAsyncStatus status = job->VerifyProof(
elawrence954bb5472016-04-04 22:03:11618 hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
ckrasic6567aa52016-07-08 09:24:35619 signature, error_details, verify_details, std::move(callback));
Ryan Hamilton8d9ee76e2018-05-29 23:52:52620 if (status == quic::QUIC_PENDING) {
avib3635452016-10-21 18:33:53621 Job* job_ptr = job.get();
622 active_jobs_[job_ptr] = std::move(job);
623 }
rtennetid073dd22016-08-04 01:58:33624 return status;
625}
626
Ryan Hamilton8d9ee76e2018-05-29 23:52:52627quic::QuicAsyncStatus ProofVerifierChromium::VerifyCertChain(
rtennetid073dd22016-08-04 01:58:33628 const std::string& hostname,
629 const std::vector<std::string>& certs,
Dan Zhang10042412019-05-09 18:31:01630 const std::string& ocsp_response,
631 const std::string& cert_sct,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52632 const quic::ProofVerifyContext* verify_context,
rtennetid073dd22016-08-04 01:58:33633 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52634 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
635 std::unique_ptr<quic::ProofVerifierCallback> callback) {
rtennetid073dd22016-08-04 01:58:33636 if (!verify_context) {
637 *error_details = "Missing context";
Ryan Hamilton8d9ee76e2018-05-29 23:52:52638 return quic::QUIC_FAILURE;
[email protected]5c78ce62014-03-13 19:48:01639 }
rtennetid073dd22016-08-04 01:58:33640 const ProofVerifyContextChromium* chromium_context =
641 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
Jeremy Roman0579ed62017-08-29 15:56:19642 std::unique_ptr<Job> job = std::make_unique<Job>(
avib3635452016-10-21 18:33:53643 this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
644 cert_transparency_verifier_, chromium_context->cert_verify_flags,
645 chromium_context->net_log);
Matt Mueller7d5464b2019-05-15 20:18:45646 quic::QuicAsyncStatus status =
647 job->VerifyCertChain(hostname, certs, ocsp_response, cert_sct,
648 error_details, verify_details, std::move(callback));
Ryan Hamilton8d9ee76e2018-05-29 23:52:52649 if (status == quic::QUIC_PENDING) {
avib3635452016-10-21 18:33:53650 Job* job_ptr = job.get();
651 active_jobs_[job_ptr] = std::move(job);
652 }
[email protected]5c78ce62014-03-13 19:48:01653 return status;
654}
655
Ryan Hamilton8bb19a12018-07-23 20:29:24656std::unique_ptr<quic::ProofVerifyContext>
657ProofVerifierChromium::CreateDefaultContext() {
658 return std::make_unique<ProofVerifyContextChromium>(0,
659 net::NetLogWithSource());
660}
661
[email protected]5c78ce62014-03-13 19:48:01662void ProofVerifierChromium::OnJobComplete(Job* job) {
663 active_jobs_.erase(job);
[email protected]5c78ce62014-03-13 19:48:01664}
665
[email protected]2662ed562013-07-03 10:27:46666} // namespace net