blob: 366894c7fb21acbd91f79ff0bfbcedceecdc0cb3 [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,
83 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:5284 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
85 std::unique_ptr<quic::ProofVerifierCallback> callback);
rtennetid073dd22016-08-04 01:58:3386
[email protected]5c78ce62014-03-13 19:48:0187 private:
88 enum State {
89 STATE_NONE,
90 STATE_VERIFY_CERT,
91 STATE_VERIFY_CERT_COMPLETE,
92 };
93
rtennetid073dd22016-08-04 01:58:3394 // Convert |certs| to |cert_|(X509Certificate). Returns true if successful.
Ryan Hamilton8d9ee76e2018-05-29 23:52:5295 bool GetX509Certificate(
96 const std::vector<string>& certs,
97 std::string* error_details,
98 std::unique_ptr<quic::ProofVerifyDetails>* verify_details);
rtennetid073dd22016-08-04 01:58:3399
100 // Start the cert verification.
Ryan Hamilton8d9ee76e2018-05-29 23:52:52101 quic::QuicAsyncStatus VerifyCert(
rtennetid073dd22016-08-04 01:58:33102 const string& hostname,
103 const uint16_t port,
104 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52105 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
106 std::unique_ptr<quic::ProofVerifierCallback> callback);
rtennetid073dd22016-08-04 01:58:33107
[email protected]5c78ce62014-03-13 19:48:01108 int DoLoop(int last_io_result);
109 void OnIOComplete(int result);
110 int DoVerifyCert(int result);
111 int DoVerifyCertComplete(int result);
112
113 bool VerifySignature(const std::string& signed_data,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52114 quic::QuicTransportVersion quic_version,
115 quic::QuicStringPiece chlo_hash,
[email protected]5c78ce62014-03-13 19:48:01116 const std::string& signature,
117 const std::string& cert);
118
119 // Proof verifier to notify when this jobs completes.
120 ProofVerifierChromium* proof_verifier_;
121
122 // The underlying verifier used for verifying certificates.
eroman7f9236a2015-05-11 21:23:43123 CertVerifier* verifier_;
danakjad1777e2016-04-16 00:56:42124 std::unique_ptr<CertVerifier::Request> cert_verifier_request_;
[email protected]5c78ce62014-03-13 19:48:01125
estark6f9b3d82016-01-12 21:37:05126 CTPolicyEnforcer* policy_enforcer_;
rsleevi9541f8632015-07-31 00:07:00127
[email protected]080b77932014-08-04 01:22:46128 TransportSecurityState* transport_security_state_;
129
rtenneti052774e2015-11-24 21:00:12130 CTVerifier* cert_transparency_verifier_;
131
[email protected]5c78ce62014-03-13 19:48:01132 // |hostname| specifies the hostname for which |certs| is a valid chain.
133 std::string hostname_;
elawrence954bb5472016-04-04 22:03:11134 // |port| specifies the target port for the connection.
135 uint16_t port_;
[email protected]5c78ce62014-03-13 19:48:01136
Ryan Hamilton8d9ee76e2018-05-29 23:52:52137 std::unique_ptr<quic::ProofVerifierCallback> callback_;
danakjad1777e2016-04-16 00:56:42138 std::unique_ptr<ProofVerifyDetailsChromium> verify_details_;
[email protected]5c78ce62014-03-13 19:48:01139 std::string error_details_;
140
141 // X509Certificate from a chain of DER encoded certificates.
142 scoped_refptr<X509Certificate> cert_;
143
rtennetia75df622015-06-21 23:59:50144 // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
145 // passed to CertVerifier::Verify.
146 int cert_verify_flags_;
147
rtennetid073dd22016-08-04 01:58:33148 // If set to true, enforces policy checking in DoVerifyCertComplete().
149 bool enforce_policy_checking_;
150
[email protected]5c78ce62014-03-13 19:48:01151 State next_state_;
152
rtennetidd4f1bd72015-12-23 19:17:50153 base::TimeTicks start_time_;
154
tfarina428341112016-09-22 13:38:20155 NetLogWithSource net_log_;
[email protected]5c78ce62014-03-13 19:48:01156
157 DISALLOW_COPY_AND_ASSIGN(Job);
158};
159
[email protected]080b77932014-08-04 01:22:46160ProofVerifierChromium::Job::Job(
161 ProofVerifierChromium* proof_verifier,
162 CertVerifier* cert_verifier,
estark6f9b3d82016-01-12 21:37:05163 CTPolicyEnforcer* ct_policy_enforcer,
[email protected]080b77932014-08-04 01:22:46164 TransportSecurityState* transport_security_state,
rtenneti052774e2015-11-24 21:00:12165 CTVerifier* cert_transparency_verifier,
rtennetia75df622015-06-21 23:59:50166 int cert_verify_flags,
tfarina428341112016-09-22 13:38:20167 const NetLogWithSource& net_log)
[email protected]5c78ce62014-03-13 19:48:01168 : proof_verifier_(proof_verifier),
eroman7f9236a2015-05-11 21:23:43169 verifier_(cert_verifier),
estark6f9b3d82016-01-12 21:37:05170 policy_enforcer_(ct_policy_enforcer),
[email protected]080b77932014-08-04 01:22:46171 transport_security_state_(transport_security_state),
rtenneti052774e2015-11-24 21:00:12172 cert_transparency_verifier_(cert_transparency_verifier),
rtennetia75df622015-06-21 23:59:50173 cert_verify_flags_(cert_verify_flags),
rtennetid073dd22016-08-04 01:58:33174 enforce_policy_checking_(true),
[email protected]5c78ce62014-03-13 19:48:01175 next_state_(STATE_NONE),
rtennetidd4f1bd72015-12-23 19:17:50176 start_time_(base::TimeTicks::Now()),
rsleevid6de8302016-06-21 01:33:20177 net_log_(net_log) {
rsleevibe81cd62016-06-24 01:38:59178 CHECK(proof_verifier_);
179 CHECK(verifier_);
180 CHECK(policy_enforcer_);
181 CHECK(transport_security_state_);
182 CHECK(cert_transparency_verifier_);
rsleevid6de8302016-06-21 01:33:20183}
[email protected]2662ed562013-07-03 10:27:46184
rtennetidd4f1bd72015-12-23 19:17:50185ProofVerifierChromium::Job::~Job() {
186 base::TimeTicks end_time = base::TimeTicks::Now();
187 UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime",
188 end_time - start_time_);
189 // |hostname_| will always be canonicalized to lowercase.
190 if (hostname_.compare("www.google.com") == 0) {
191 UMA_HISTOGRAM_TIMES("Net.QuicSession.VerifyProofTime.google",
192 end_time - start_time_);
193 }
194}
195
Ryan Hamilton8d9ee76e2018-05-29 23:52:52196quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
[email protected]72e65992013-07-30 17:16:14197 const string& hostname,
elawrence954bb5472016-04-04 22:03:11198 const uint16_t port,
[email protected]72e65992013-07-30 17:16:14199 const string& server_config,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52200 quic::QuicTransportVersion quic_version,
201 quic::QuicStringPiece chlo_hash,
rch872e00e2016-12-02 02:48:18202 const std::vector<string>& certs,
rjshadec86dbfa2015-11-12 20:16:25203 const std::string& cert_sct,
[email protected]72e65992013-07-30 17:16:14204 const string& signature,
205 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52206 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
207 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]2662ed562013-07-03 10:27:46208 DCHECK(error_details);
[email protected]c817c672014-03-21 22:25:34209 DCHECK(verify_details);
[email protected]72e65992013-07-30 17:16:14210 DCHECK(callback);
211
[email protected]2662ed562013-07-03 10:27:46212 error_details->clear();
213
[email protected]2662ed562013-07-03 10:27:46214 if (STATE_NONE != next_state_) {
215 *error_details = "Certificate is already set and VerifyProof has begun";
[email protected]5c78ce62014-03-13 19:48:01216 DLOG(DFATAL) << *error_details;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52217 return quic::QUIC_FAILURE;
[email protected]2662ed562013-07-03 10:27:46218 }
219
[email protected]72e65992013-07-30 17:16:14220 verify_details_.reset(new ProofVerifyDetailsChromium);
221
rtennetid073dd22016-08-04 01:58:33222 // Converts |certs| to |cert_|.
223 if (!GetX509Certificate(certs, error_details, verify_details))
Ryan Hamilton8d9ee76e2018-05-29 23:52:52224 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33225
rch71bd2332017-02-04 00:06:47226 // Note that this is a completely synchronous operation: The CT Log Verifier
227 // gets all the data it needs for SCT verification and does not do any
228 // external communication.
Rob Percivalbc658a22017-12-13 08:24:42229 cert_transparency_verifier_->Verify(
230 hostname, cert_.get(), std::string(), cert_sct,
231 &verify_details_->ct_verify_result.scts, net_log_);
rtennetid073dd22016-08-04 01:58:33232
233 // We call VerifySignature first to avoid copying of server_config and
234 // signature.
Ryan Hamiltona3ee93a72018-08-01 22:03:08235 if (!signature.empty() && !VerifySignature(server_config, quic_version,
236 chlo_hash, signature, certs[0])) {
rtennetid073dd22016-08-04 01:58:33237 *error_details = "Failed to verify signature of server config";
238 DLOG(WARNING) << *error_details;
239 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
240 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52241 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33242 }
243
244 DCHECK(enforce_policy_checking_);
245 return VerifyCert(hostname, port, error_details, verify_details,
246 std::move(callback));
247}
248
Ryan Hamilton8d9ee76e2018-05-29 23:52:52249quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain(
rtennetid073dd22016-08-04 01:58:33250 const string& hostname,
rch872e00e2016-12-02 02:48:18251 const std::vector<string>& certs,
rtennetid073dd22016-08-04 01:58:33252 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52253 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
254 std::unique_ptr<quic::ProofVerifierCallback> callback) {
rtennetid073dd22016-08-04 01:58:33255 DCHECK(error_details);
256 DCHECK(verify_details);
257 DCHECK(callback);
258
259 error_details->clear();
260
261 if (STATE_NONE != next_state_) {
262 *error_details = "Certificate is already set and VerifyCertChain has begun";
263 DLOG(DFATAL) << *error_details;
Ryan Hamilton8d9ee76e2018-05-29 23:52:52264 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33265 }
266
267 verify_details_.reset(new ProofVerifyDetailsChromium);
268
269 // Converts |certs| to |cert_|.
270 if (!GetX509Certificate(certs, error_details, verify_details))
Ryan Hamilton8d9ee76e2018-05-29 23:52:52271 return quic::QUIC_FAILURE;
rtennetid073dd22016-08-04 01:58:33272
273 enforce_policy_checking_ = false;
274 // |port| is not needed because |enforce_policy_checking_| is false.
275 return VerifyCert(hostname, /*port=*/0, error_details, verify_details,
276 std::move(callback));
277}
278
279bool ProofVerifierChromium::Job::GetX509Certificate(
rch872e00e2016-12-02 02:48:18280 const std::vector<string>& certs,
rtennetid073dd22016-08-04 01:58:33281 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52282 std::unique_ptr<quic::ProofVerifyDetails>* verify_details) {
rtennetic14d86fd2016-07-10 16:33:34283 if (certs.empty()) {
284 *error_details = "Failed to create certificate chain. Certs are empty.";
285 DLOG(WARNING) << *error_details;
286 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
287 *verify_details = std::move(verify_details_);
rtennetid073dd22016-08-04 01:58:33288 return false;
rtennetic14d86fd2016-07-10 16:33:34289 }
290
291 // Convert certs to X509Certificate.
Ryan Hamilton8d9ee76e2018-05-29 23:52:52292 std::vector<quic::QuicStringPiece> cert_pieces(certs.size());
rtennetic14d86fd2016-07-10 16:33:34293 for (unsigned i = 0; i < certs.size(); i++) {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52294 cert_pieces[i] = quic::QuicStringPiece(certs[i]);
rtennetic14d86fd2016-07-10 16:33:34295 }
296 cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
297 if (!cert_.get()) {
298 *error_details = "Failed to create certificate chain";
299 DLOG(WARNING) << *error_details;
300 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
301 *verify_details = std::move(verify_details_);
rtennetid073dd22016-08-04 01:58:33302 return false;
rtennetic14d86fd2016-07-10 16:33:34303 }
rtennetid073dd22016-08-04 01:58:33304 return true;
305}
[email protected]2662ed562013-07-03 10:27:46306
Ryan Hamilton8d9ee76e2018-05-29 23:52:52307quic::QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert(
rtennetid073dd22016-08-04 01:58:33308 const string& hostname,
309 const uint16_t port,
310 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52311 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
312 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]2662ed562013-07-03 10:27:46313 hostname_ = hostname;
elawrence954bb5472016-04-04 22:03:11314 port_ = port;
[email protected]2662ed562013-07-03 10:27:46315
316 next_state_ = STATE_VERIFY_CERT;
[email protected]72e65992013-07-30 17:16:14317 switch (DoLoop(OK)) {
318 case OK:
dchengc7eeda422015-12-26 03:56:48319 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52320 return quic::QUIC_SUCCESS;
[email protected]72e65992013-07-30 17:16:14321 case ERR_IO_PENDING:
ckrasic6567aa52016-07-08 09:24:35322 callback_ = std::move(callback);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52323 return quic::QUIC_PENDING;
[email protected]72e65992013-07-30 17:16:14324 default:
325 *error_details = error_details_;
dchengc7eeda422015-12-26 03:56:48326 *verify_details = std::move(verify_details_);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52327 return quic::QUIC_FAILURE;
[email protected]72e65992013-07-30 17:16:14328 }
[email protected]2662ed562013-07-03 10:27:46329}
330
[email protected]5c78ce62014-03-13 19:48:01331int ProofVerifierChromium::Job::DoLoop(int last_result) {
[email protected]2662ed562013-07-03 10:27:46332 int rv = last_result;
333 do {
334 State state = next_state_;
335 next_state_ = STATE_NONE;
336 switch (state) {
337 case STATE_VERIFY_CERT:
338 DCHECK(rv == OK);
339 rv = DoVerifyCert(rv);
340 break;
341 case STATE_VERIFY_CERT_COMPLETE:
342 rv = DoVerifyCertComplete(rv);
343 break;
344 case STATE_NONE:
345 default:
346 rv = ERR_UNEXPECTED;
347 LOG(DFATAL) << "unexpected state " << state;
348 break;
349 }
350 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
351 return rv;
352}
353
[email protected]5c78ce62014-03-13 19:48:01354void ProofVerifierChromium::Job::OnIOComplete(int result) {
[email protected]2662ed562013-07-03 10:27:46355 int rv = DoLoop(result);
356 if (rv != ERR_IO_PENDING) {
Ryan Hamilton8d9ee76e2018-05-29 23:52:52357 std::unique_ptr<quic::ProofVerifierCallback> callback(std::move(callback_));
358 // Callback expects quic::ProofVerifyDetails not ProofVerifyDetailsChromium.
359 std::unique_ptr<quic::ProofVerifyDetails> verify_details(
danakjad1777e2016-04-16 00:56:42360 std::move(verify_details_));
[email protected]5c78ce62014-03-13 19:48:01361 callback->Run(rv == OK, error_details_, &verify_details);
362 // Will delete |this|.
363 proof_verifier_->OnJobComplete(this);
[email protected]2662ed562013-07-03 10:27:46364 }
365}
366
[email protected]5c78ce62014-03-13 19:48:01367int ProofVerifierChromium::Job::DoVerifyCert(int result) {
[email protected]2662ed562013-07-03 10:27:46368 next_state_ = STATE_VERIFY_CERT_COMPLETE;
369
rtennetia75df622015-06-21 23:59:50370 return verifier_->Verify(
rsleevi06bd78552016-06-08 22:34:46371 CertVerifier::RequestParams(cert_, hostname_, cert_verify_flags_,
Ryan Sleevi73bdca62018-08-22 16:34:23372 std::string()),
Ryan Sleevib369d712018-08-20 16:43:22373 &verify_details_->cert_verify_result,
rtennetia75df622015-06-21 23:59:50374 base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
375 base::Unretained(this)),
376 &cert_verifier_request_, net_log_);
[email protected]2662ed562013-07-03 10:27:46377}
378
[email protected]5c78ce62014-03-13 19:48:01379int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
Ilya Sherman0eb39802017-12-08 20:58:18380 base::UmaHistogramSparse("Net.QuicSession.CertVerificationResult", -result);
eroman7f9236a2015-05-11 21:23:43381 cert_verifier_request_.reset();
[email protected]2662ed562013-07-03 10:27:46382
[email protected]080b77932014-08-04 01:22:46383 const CertVerifyResult& cert_verify_result =
384 verify_details_->cert_verify_result;
[email protected]080b77932014-08-04 01:22:46385 const CertStatus cert_status = cert_verify_result.cert_status;
rsleevi4a6ca8c2016-06-24 03:05:22386
387 // If the connection was good, check HPKP and CT status simultaneously,
388 // but prefer to treat the HPKP error as more serious, if there was one.
rtennetid073dd22016-08-04 01:58:33389 if (enforce_policy_checking_ &&
390 (result == OK ||
rsleevi4a6ca8c2016-06-24 03:05:22391 (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) {
Ryan Sleevi8a9c9c12018-05-09 02:36:23392 ct::SCTList verified_scts = ct::SCTsMatchingStatus(
eranm4bed0b572016-08-14 21:00:35393 verify_details_->ct_verify_result.scts, ct::SCT_STATUS_OK);
estark0fc8d0782016-02-25 20:41:20394
Emily Stark627238f2017-11-29 03:29:54395 verify_details_->ct_verify_result.policy_compliance =
396 policy_enforcer_->CheckCompliance(
eranm4bed0b572016-08-14 21:00:35397 cert_verify_result.verified_cert.get(), verified_scts, net_log_);
Emily Stark0d9809e2017-10-18 08:29:15398 if (verify_details_->cert_verify_result.cert_status & CERT_STATUS_IS_EV) {
Emily Stark627238f2017-11-29 03:29:54399 if (verify_details_->ct_verify_result.policy_compliance !=
Ryan Sleevi8a9c9c12018-05-09 02:36:23400 ct::CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS &&
401 verify_details_->ct_verify_result.policy_compliance !=
402 ct::CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY) {
Emily Stark0d9809e2017-10-18 08:29:15403 verify_details_->cert_verify_result.cert_status |=
404 CERT_STATUS_CT_COMPLIANCE_FAILED;
405 verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
406 }
407
408 // Record the CT compliance status for connections with EV certificates,
409 // to distinguish how often EV status is being dropped due to failing CT
410 // compliance.
Emily Starkefce7832017-11-30 03:16:16411 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
412 UMA_HISTOGRAM_ENUMERATION(
413 "Net.CertificateTransparency.EVCompliance2.QUIC",
414 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45415 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16416 }
rsleevicd7390e2017-06-14 10:18:26417 }
rsleevi9541f8632015-07-31 00:07:00418
Emily Stark0d9809e2017-10-18 08:29:15419 // Record the CT compliance of every connection to get an overall picture of
420 // how many connections are CT-compliant.
Emily Starkefce7832017-11-30 03:16:16421 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
422 UMA_HISTOGRAM_ENUMERATION(
423 "Net.CertificateTransparency.ConnectionComplianceStatus2.QUIC",
424 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45425 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16426 }
Emily Starkc96e9bc2017-10-10 00:10:39427
rsleevi4a6ca8c2016-06-24 03:05:22428 int ct_result = OK;
Emily Stark0d9809e2017-10-18 08:29:15429 TransportSecurityState::CTRequirementsStatus ct_requirement_status =
430 transport_security_state_->CheckCTRequirements(
estarkbf1b52962017-05-05 17:05:25431 HostPortPair(hostname_, port_),
432 cert_verify_result.is_issued_by_known_root,
433 cert_verify_result.public_key_hashes,
434 cert_verify_result.verified_cert.get(), cert_.get(),
435 verify_details_->ct_verify_result.scts,
436 TransportSecurityState::ENABLE_EXPECT_CT_REPORTS,
Emily Stark627238f2017-11-29 03:29:54437 verify_details_->ct_verify_result.policy_compliance);
Emily Stark0d9809e2017-10-18 08:29:15438 if (ct_requirement_status != TransportSecurityState::CT_NOT_REQUIRED) {
Emily Stark8b411de02017-11-23 20:21:27439 verify_details_->ct_verify_result.policy_compliance_required = true;
Emily Starkefce7832017-11-30 03:16:16440 if (verify_details_->cert_verify_result.is_issued_by_known_root) {
441 // Record the CT compliance of connections for which compliance is
442 // required; this helps answer the question: "Of all connections that
443 // are supposed to be serving valid CT information, how many fail to do
444 // so?"
445 UMA_HISTOGRAM_ENUMERATION(
446 "Net.CertificateTransparency.CTRequiredConnectionComplianceStatus2."
447 "QUIC",
448 verify_details_->ct_verify_result.policy_compliance,
Kunihiko Sakamoto36469732018-09-27 03:33:45449 ct::CTPolicyCompliance::CT_POLICY_COUNT);
Emily Starkefce7832017-11-30 03:16:16450 }
Emily Stark8b411de02017-11-23 20:21:27451 } else {
452 verify_details_->ct_verify_result.policy_compliance_required = false;
Emily Stark0d9809e2017-10-18 08:29:15453 }
454
455 switch (ct_requirement_status) {
456 case TransportSecurityState::CT_REQUIREMENTS_NOT_MET:
457 verify_details_->cert_verify_result.cert_status |=
458 CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
459 ct_result = ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
Emily Stark8b411de02017-11-23 20:21:27460 break;
Emily Stark0d9809e2017-10-18 08:29:15461 case TransportSecurityState::CT_REQUIREMENTS_MET:
462 case TransportSecurityState::CT_NOT_REQUIRED:
463 // Intentional fallthrough; this case is just here to make sure that all
464 // possible values of CheckCTRequirements() are handled.
465 break;
rsleevi4a6ca8c2016-06-24 03:05:22466 }
467
dadrian8f8946652016-06-21 23:48:31468 TransportSecurityState::PKPStatus pin_validity =
469 transport_security_state_->CheckPublicKeyPins(
470 HostPortPair(hostname_, port_),
471 cert_verify_result.is_issued_by_known_root,
472 cert_verify_result.public_key_hashes, cert_.get(),
473 cert_verify_result.verified_cert.get(),
474 TransportSecurityState::ENABLE_PIN_REPORTS,
475 &verify_details_->pinning_failure_log);
476 switch (pin_validity) {
477 case TransportSecurityState::PKPStatus::VIOLATED:
478 result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
479 verify_details_->cert_verify_result.cert_status |=
480 CERT_STATUS_PINNED_KEY_MISSING;
481 break;
482 case TransportSecurityState::PKPStatus::BYPASSED:
483 verify_details_->pkp_bypassed = true;
Nico Weber63e03762018-01-26 17:55:14484 FALLTHROUGH;
dadrian8f8946652016-06-21 23:48:31485 case TransportSecurityState::PKPStatus::OK:
486 // Do nothing.
487 break;
rsleevi9545d342016-06-21 03:17:37488 }
rsleevi4a6ca8c2016-06-24 03:05:22489 if (result != ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN && ct_result != OK)
490 result = ct_result;
[email protected]080b77932014-08-04 01:22:46491 }
[email protected]080b77932014-08-04 01:22:46492
Carlos IL81133382017-12-06 17:18:45493 verify_details_->is_fatal_cert_error =
494 IsCertStatusError(cert_status) && !IsCertStatusMinorError(cert_status) &&
495 transport_security_state_->ShouldSSLErrorsBeFatal(hostname_);
496
[email protected]0cceb922014-07-01 02:00:56497 if (result != OK) {
[email protected]3030374e32014-08-07 16:12:06498 std::string error_string = ErrorToString(result);
[email protected]72e65992013-07-30 17:16:14499 error_details_ = StringPrintf("Failed to verify certificate chain: %s",
[email protected]3030374e32014-08-07 16:12:06500 error_string.c_str());
[email protected]72e65992013-07-30 17:16:14501 DLOG(WARNING) << error_details_;
[email protected]2662ed562013-07-03 10:27:46502 }
503
504 // Exit DoLoop and return the result to the caller to VerifyProof.
505 DCHECK_EQ(STATE_NONE, next_state_);
506 return result;
507}
508
Michael Warres74ee3ce2017-10-09 15:26:37509bool ProofVerifierChromium::Job::VerifySignature(
510 const string& signed_data,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52511 quic::QuicTransportVersion quic_version,
512 quic::QuicStringPiece chlo_hash,
Michael Warres74ee3ce2017-10-09 15:26:37513 const string& signature,
514 const string& cert) {
[email protected]2662ed562013-07-03 10:27:46515 size_t size_bits;
516 X509Certificate::PublicKeyType type;
Matt Muellera4193272017-12-07 00:23:34517 X509Certificate::GetPublicKeyInfo(cert_->cert_buffer(), &size_bits, &type);
David Benjamin8982fe4f2018-02-06 19:30:32518 crypto::SignatureVerifier::SignatureAlgorithm algorithm;
519 switch (type) {
520 case X509Certificate::kPublicKeyTypeRSA:
521 algorithm = crypto::SignatureVerifier::RSA_PSS_SHA256;
522 break;
523 case X509Certificate::kPublicKeyTypeECDSA:
524 algorithm = crypto::SignatureVerifier::ECDSA_SHA256;
525 break;
526 default:
527 LOG(ERROR) << "Unsupported public key type " << type;
528 return false;
529 }
[email protected]2662ed562013-07-03 10:27:46530
David Benjamin8982fe4f2018-02-06 19:30:32531 crypto::SignatureVerifier verifier;
David Benjamin03c28a42018-05-11 23:12:07532 if (!x509_util::SignatureVerifierInitWithCertificate(
533 &verifier, algorithm, base::as_bytes(base::make_span(signature)),
534 cert_->cert_buffer())) {
535 DLOG(WARNING) << "SignatureVerifierInitWithCertificate failed";
[email protected]2662ed562013-07-03 10:27:46536 return false;
537 }
538
Ryan Hamilton8d9ee76e2018-05-29 23:52:52539 verifier.VerifyUpdate(
540 base::as_bytes(base::make_span(quic::kProofSignatureLabel)));
zhongyi7cbefb312016-10-11 19:03:47541 uint32_t len = chlo_hash.length();
jdoerrie2917a61e2018-05-02 09:39:14542 verifier.VerifyUpdate(base::as_bytes(base::make_span(&len, 1)));
543 verifier.VerifyUpdate(base::as_bytes(base::make_span(chlo_hash)));
544 verifier.VerifyUpdate(base::as_bytes(base::make_span(signed_data)));
[email protected]2662ed562013-07-03 10:27:46545
546 if (!verifier.VerifyFinal()) {
547 DLOG(WARNING) << "VerifyFinal failed";
548 return false;
549 }
550
[email protected]3e5fed12013-11-22 22:21:41551 DVLOG(1) << "VerifyFinal success";
[email protected]2662ed562013-07-03 10:27:46552 return true;
553}
554
[email protected]080b77932014-08-04 01:22:46555ProofVerifierChromium::ProofVerifierChromium(
556 CertVerifier* cert_verifier,
estark6f9b3d82016-01-12 21:37:05557 CTPolicyEnforcer* ct_policy_enforcer,
rtenneti052774e2015-11-24 21:00:12558 TransportSecurityState* transport_security_state,
559 CTVerifier* cert_transparency_verifier)
[email protected]080b77932014-08-04 01:22:46560 : cert_verifier_(cert_verifier),
estark6f9b3d82016-01-12 21:37:05561 ct_policy_enforcer_(ct_policy_enforcer),
rtenneti052774e2015-11-24 21:00:12562 transport_security_state_(transport_security_state),
rsleevid6de8302016-06-21 01:33:20563 cert_transparency_verifier_(cert_transparency_verifier) {
564 DCHECK(cert_verifier_);
565 DCHECK(ct_policy_enforcer_);
566 DCHECK(transport_security_state_);
567 DCHECK(cert_transparency_verifier_);
568}
[email protected]5c78ce62014-03-13 19:48:01569
Ryan Hamiltona3ee93a72018-08-01 22:03:08570ProofVerifierChromium::~ProofVerifierChromium() {}
[email protected]5c78ce62014-03-13 19:48:01571
Ryan Hamilton8d9ee76e2018-05-29 23:52:52572quic::QuicAsyncStatus ProofVerifierChromium::VerifyProof(
[email protected]5c78ce62014-03-13 19:48:01573 const std::string& hostname,
elawrence954bb5472016-04-04 22:03:11574 const uint16_t port,
[email protected]5c78ce62014-03-13 19:48:01575 const std::string& server_config,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52576 quic::QuicTransportVersion quic_version,
577 quic::QuicStringPiece chlo_hash,
[email protected]5c78ce62014-03-13 19:48:01578 const std::vector<std::string>& certs,
rjshadec86dbfa2015-11-12 20:16:25579 const std::string& cert_sct,
[email protected]5c78ce62014-03-13 19:48:01580 const std::string& signature,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52581 const quic::ProofVerifyContext* verify_context,
[email protected]5c78ce62014-03-13 19:48:01582 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52583 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
584 std::unique_ptr<quic::ProofVerifierCallback> callback) {
[email protected]c817c672014-03-21 22:25:34585 if (!verify_context) {
Ryan Hamilton8bb19a12018-07-23 20:29:24586 DLOG(FATAL) << "Missing proof verify context";
[email protected]c817c672014-03-21 22:25:34587 *error_details = "Missing context";
Ryan Hamilton8d9ee76e2018-05-29 23:52:52588 return quic::QUIC_FAILURE;
[email protected]c817c672014-03-21 22:25:34589 }
590 const ProofVerifyContextChromium* chromium_context =
591 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
Jeremy Roman0579ed62017-08-29 15:56:19592 std::unique_ptr<Job> job = std::make_unique<Job>(
avib3635452016-10-21 18:33:53593 this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
594 cert_transparency_verifier_, chromium_context->cert_verify_flags,
595 chromium_context->net_log);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52596 quic::QuicAsyncStatus status = job->VerifyProof(
elawrence954bb5472016-04-04 22:03:11597 hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
ckrasic6567aa52016-07-08 09:24:35598 signature, error_details, verify_details, std::move(callback));
Ryan Hamilton8d9ee76e2018-05-29 23:52:52599 if (status == quic::QUIC_PENDING) {
avib3635452016-10-21 18:33:53600 Job* job_ptr = job.get();
601 active_jobs_[job_ptr] = std::move(job);
602 }
rtennetid073dd22016-08-04 01:58:33603 return status;
604}
605
Ryan Hamilton8d9ee76e2018-05-29 23:52:52606quic::QuicAsyncStatus ProofVerifierChromium::VerifyCertChain(
rtennetid073dd22016-08-04 01:58:33607 const std::string& hostname,
608 const std::vector<std::string>& certs,
Dan Zhang10042412019-05-09 18:31:01609 const std::string& ocsp_response,
610 const std::string& cert_sct,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52611 const quic::ProofVerifyContext* verify_context,
rtennetid073dd22016-08-04 01:58:33612 std::string* error_details,
Ryan Hamilton8d9ee76e2018-05-29 23:52:52613 std::unique_ptr<quic::ProofVerifyDetails>* verify_details,
614 std::unique_ptr<quic::ProofVerifierCallback> callback) {
rtennetid073dd22016-08-04 01:58:33615 if (!verify_context) {
616 *error_details = "Missing context";
Ryan Hamilton8d9ee76e2018-05-29 23:52:52617 return quic::QUIC_FAILURE;
[email protected]5c78ce62014-03-13 19:48:01618 }
Dan Zhang10042412019-05-09 18:31:01619 // TODO(mattm): use |ocsp_response| and |cert_sct|.
rtennetid073dd22016-08-04 01:58:33620 const ProofVerifyContextChromium* chromium_context =
621 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
Jeremy Roman0579ed62017-08-29 15:56:19622 std::unique_ptr<Job> job = std::make_unique<Job>(
avib3635452016-10-21 18:33:53623 this, cert_verifier_, ct_policy_enforcer_, transport_security_state_,
624 cert_transparency_verifier_, chromium_context->cert_verify_flags,
625 chromium_context->net_log);
Ryan Hamilton8d9ee76e2018-05-29 23:52:52626 quic::QuicAsyncStatus status = job->VerifyCertChain(
rtennetid073dd22016-08-04 01:58:33627 hostname, certs, error_details, verify_details, std::move(callback));
Ryan Hamilton8d9ee76e2018-05-29 23:52:52628 if (status == quic::QUIC_PENDING) {
avib3635452016-10-21 18:33:53629 Job* job_ptr = job.get();
630 active_jobs_[job_ptr] = std::move(job);
631 }
[email protected]5c78ce62014-03-13 19:48:01632 return status;
633}
634
Ryan Hamilton8bb19a12018-07-23 20:29:24635std::unique_ptr<quic::ProofVerifyContext>
636ProofVerifierChromium::CreateDefaultContext() {
637 return std::make_unique<ProofVerifyContextChromium>(0,
638 net::NetLogWithSource());
639}
640
[email protected]5c78ce62014-03-13 19:48:01641void ProofVerifierChromium::OnJobComplete(Job* job) {
642 active_jobs_.erase(job);
[email protected]5c78ce62014-03-13 19:48:01643}
644
[email protected]2662ed562013-07-03 10:27:46645} // namespace net