OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/chromium/crypto/proof_verifier_chromium.h" | 5 #include "net/quic/chromium/crypto/proof_verifier_chromium.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 const std::string& server_config, | 71 const std::string& server_config, |
72 QuicVersion quic_version, | 72 QuicVersion quic_version, |
73 base::StringPiece chlo_hash, | 73 base::StringPiece chlo_hash, |
74 const std::vector<std::string>& certs, | 74 const std::vector<std::string>& certs, |
75 const std::string& cert_sct, | 75 const std::string& cert_sct, |
76 const std::string& signature, | 76 const std::string& signature, |
77 std::string* error_details, | 77 std::string* error_details, |
78 std::unique_ptr<ProofVerifyDetails>* verify_details, | 78 std::unique_ptr<ProofVerifyDetails>* verify_details, |
79 std::unique_ptr<ProofVerifierCallback> callback); | 79 std::unique_ptr<ProofVerifierCallback> callback); |
80 | 80 |
| 81 // Starts the certificate chain verification of |certs|. If |QUIC_PENDING| is |
| 82 // returned, then |callback| will be invoked asynchronously when the |
| 83 // verification completes. |
| 84 QuicAsyncStatus VerifyCertChain( |
| 85 const std::string& hostname, |
| 86 const std::vector<std::string>& certs, |
| 87 std::string* error_details, |
| 88 std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 89 std::unique_ptr<ProofVerifierCallback> callback); |
| 90 |
81 private: | 91 private: |
82 enum State { | 92 enum State { |
83 STATE_NONE, | 93 STATE_NONE, |
84 STATE_VERIFY_CERT, | 94 STATE_VERIFY_CERT, |
85 STATE_VERIFY_CERT_COMPLETE, | 95 STATE_VERIFY_CERT_COMPLETE, |
86 }; | 96 }; |
87 | 97 |
| 98 // Convert |certs| to |cert_|(X509Certificate). Returns true if successful. |
| 99 bool GetX509Certificate(const vector<string>& certs, |
| 100 std::string* error_details, |
| 101 std::unique_ptr<ProofVerifyDetails>* verify_details); |
| 102 |
| 103 // Start the cert verification. |
| 104 QuicAsyncStatus VerifyCert( |
| 105 const string& hostname, |
| 106 const uint16_t port, |
| 107 std::string* error_details, |
| 108 std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 109 std::unique_ptr<ProofVerifierCallback> callback); |
| 110 |
88 int DoLoop(int last_io_result); | 111 int DoLoop(int last_io_result); |
89 void OnIOComplete(int result); | 112 void OnIOComplete(int result); |
90 int DoVerifyCert(int result); | 113 int DoVerifyCert(int result); |
91 int DoVerifyCertComplete(int result); | 114 int DoVerifyCertComplete(int result); |
92 | 115 |
93 bool VerifySignature(const std::string& signed_data, | 116 bool VerifySignature(const std::string& signed_data, |
94 QuicVersion quic_version, | 117 QuicVersion quic_version, |
95 StringPiece chlo_hash, | 118 StringPiece chlo_hash, |
96 const std::string& signature, | 119 const std::string& signature, |
97 const std::string& cert); | 120 const std::string& cert); |
(...skipping 20 matching lines...) Expand all Loading... |
118 std::unique_ptr<ProofVerifyDetailsChromium> verify_details_; | 141 std::unique_ptr<ProofVerifyDetailsChromium> verify_details_; |
119 std::string error_details_; | 142 std::string error_details_; |
120 | 143 |
121 // X509Certificate from a chain of DER encoded certificates. | 144 // X509Certificate from a chain of DER encoded certificates. |
122 scoped_refptr<X509Certificate> cert_; | 145 scoped_refptr<X509Certificate> cert_; |
123 | 146 |
124 // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is | 147 // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is |
125 // passed to CertVerifier::Verify. | 148 // passed to CertVerifier::Verify. |
126 int cert_verify_flags_; | 149 int cert_verify_flags_; |
127 | 150 |
| 151 // If set to true, enforces policy checking in DoVerifyCertComplete(). |
| 152 bool enforce_policy_checking_; |
| 153 |
128 State next_state_; | 154 State next_state_; |
129 | 155 |
130 base::TimeTicks start_time_; | 156 base::TimeTicks start_time_; |
131 | 157 |
132 BoundNetLog net_log_; | 158 BoundNetLog net_log_; |
133 | 159 |
134 DISALLOW_COPY_AND_ASSIGN(Job); | 160 DISALLOW_COPY_AND_ASSIGN(Job); |
135 }; | 161 }; |
136 | 162 |
137 ProofVerifierChromium::Job::Job( | 163 ProofVerifierChromium::Job::Job( |
138 ProofVerifierChromium* proof_verifier, | 164 ProofVerifierChromium* proof_verifier, |
139 CertVerifier* cert_verifier, | 165 CertVerifier* cert_verifier, |
140 CTPolicyEnforcer* ct_policy_enforcer, | 166 CTPolicyEnforcer* ct_policy_enforcer, |
141 TransportSecurityState* transport_security_state, | 167 TransportSecurityState* transport_security_state, |
142 CTVerifier* cert_transparency_verifier, | 168 CTVerifier* cert_transparency_verifier, |
143 int cert_verify_flags, | 169 int cert_verify_flags, |
144 const BoundNetLog& net_log) | 170 const BoundNetLog& net_log) |
145 : proof_verifier_(proof_verifier), | 171 : proof_verifier_(proof_verifier), |
146 verifier_(cert_verifier), | 172 verifier_(cert_verifier), |
147 policy_enforcer_(ct_policy_enforcer), | 173 policy_enforcer_(ct_policy_enforcer), |
148 transport_security_state_(transport_security_state), | 174 transport_security_state_(transport_security_state), |
149 cert_transparency_verifier_(cert_transparency_verifier), | 175 cert_transparency_verifier_(cert_transparency_verifier), |
150 cert_verify_flags_(cert_verify_flags), | 176 cert_verify_flags_(cert_verify_flags), |
| 177 enforce_policy_checking_(true), |
151 next_state_(STATE_NONE), | 178 next_state_(STATE_NONE), |
152 start_time_(base::TimeTicks::Now()), | 179 start_time_(base::TimeTicks::Now()), |
153 net_log_(net_log) { | 180 net_log_(net_log) { |
154 CHECK(proof_verifier_); | 181 CHECK(proof_verifier_); |
155 CHECK(verifier_); | 182 CHECK(verifier_); |
156 CHECK(policy_enforcer_); | 183 CHECK(policy_enforcer_); |
157 CHECK(transport_security_state_); | 184 CHECK(transport_security_state_); |
158 CHECK(cert_transparency_verifier_); | 185 CHECK(cert_transparency_verifier_); |
159 } | 186 } |
160 | 187 |
(...skipping 27 matching lines...) Expand all Loading... |
188 error_details->clear(); | 215 error_details->clear(); |
189 | 216 |
190 if (STATE_NONE != next_state_) { | 217 if (STATE_NONE != next_state_) { |
191 *error_details = "Certificate is already set and VerifyProof has begun"; | 218 *error_details = "Certificate is already set and VerifyProof has begun"; |
192 DLOG(DFATAL) << *error_details; | 219 DLOG(DFATAL) << *error_details; |
193 return QUIC_FAILURE; | 220 return QUIC_FAILURE; |
194 } | 221 } |
195 | 222 |
196 verify_details_.reset(new ProofVerifyDetailsChromium); | 223 verify_details_.reset(new ProofVerifyDetailsChromium); |
197 | 224 |
198 if (certs.empty()) { | 225 // Converts |certs| to |cert_|. |
199 *error_details = "Failed to create certificate chain. Certs are empty."; | 226 if (!GetX509Certificate(certs, error_details, verify_details)) |
200 DLOG(WARNING) << *error_details; | |
201 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; | |
202 *verify_details = std::move(verify_details_); | |
203 return QUIC_FAILURE; | 227 return QUIC_FAILURE; |
204 } | |
205 | |
206 // Convert certs to X509Certificate. | |
207 vector<StringPiece> cert_pieces(certs.size()); | |
208 for (unsigned i = 0; i < certs.size(); i++) { | |
209 cert_pieces[i] = base::StringPiece(certs[i]); | |
210 } | |
211 cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces); | |
212 if (!cert_.get()) { | |
213 *error_details = "Failed to create certificate chain"; | |
214 DLOG(WARNING) << *error_details; | |
215 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; | |
216 *verify_details = std::move(verify_details_); | |
217 return QUIC_FAILURE; | |
218 } | |
219 | 228 |
220 if (!cert_sct.empty()) { | 229 if (!cert_sct.empty()) { |
221 // Note that this is a completely synchronous operation: The CT Log Verifier | 230 // Note that this is a completely synchronous operation: The CT Log Verifier |
222 // gets all the data it needs for SCT verification and does not do any | 231 // gets all the data it needs for SCT verification and does not do any |
223 // external communication. | 232 // external communication. |
224 cert_transparency_verifier_->Verify(cert_.get(), std::string(), cert_sct, | 233 cert_transparency_verifier_->Verify(cert_.get(), std::string(), cert_sct, |
225 &verify_details_->ct_verify_result, | 234 &verify_details_->ct_verify_result, |
226 net_log_); | 235 net_log_); |
227 } | 236 } |
228 | 237 |
229 // We call VerifySignature first to avoid copying of server_config and | 238 // We call VerifySignature first to avoid copying of server_config and |
230 // signature. | 239 // signature. |
231 if (!VerifySignature(server_config, quic_version, chlo_hash, signature, | 240 if (!signature.empty() && |
| 241 !VerifySignature(server_config, quic_version, chlo_hash, signature, |
232 certs[0])) { | 242 certs[0])) { |
233 *error_details = "Failed to verify signature of server config"; | 243 *error_details = "Failed to verify signature of server config"; |
234 DLOG(WARNING) << *error_details; | 244 DLOG(WARNING) << *error_details; |
235 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; | 245 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; |
236 *verify_details = std::move(verify_details_); | 246 *verify_details = std::move(verify_details_); |
237 return QUIC_FAILURE; | 247 return QUIC_FAILURE; |
238 } | 248 } |
239 | 249 |
| 250 DCHECK(enforce_policy_checking_); |
| 251 return VerifyCert(hostname, port, error_details, verify_details, |
| 252 std::move(callback)); |
| 253 } |
| 254 |
| 255 QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain( |
| 256 const string& hostname, |
| 257 const vector<string>& certs, |
| 258 std::string* error_details, |
| 259 std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 260 std::unique_ptr<ProofVerifierCallback> callback) { |
| 261 DCHECK(error_details); |
| 262 DCHECK(verify_details); |
| 263 DCHECK(callback); |
| 264 |
| 265 error_details->clear(); |
| 266 |
| 267 if (STATE_NONE != next_state_) { |
| 268 *error_details = "Certificate is already set and VerifyCertChain has begun"; |
| 269 DLOG(DFATAL) << *error_details; |
| 270 return QUIC_FAILURE; |
| 271 } |
| 272 |
| 273 verify_details_.reset(new ProofVerifyDetailsChromium); |
| 274 |
| 275 // Converts |certs| to |cert_|. |
| 276 if (!GetX509Certificate(certs, error_details, verify_details)) |
| 277 return QUIC_FAILURE; |
| 278 |
| 279 enforce_policy_checking_ = false; |
| 280 // |port| is not needed because |enforce_policy_checking_| is false. |
| 281 return VerifyCert(hostname, /*port=*/0, error_details, verify_details, |
| 282 std::move(callback)); |
| 283 } |
| 284 |
| 285 bool ProofVerifierChromium::Job::GetX509Certificate( |
| 286 const vector<string>& certs, |
| 287 std::string* error_details, |
| 288 std::unique_ptr<ProofVerifyDetails>* verify_details) { |
| 289 if (certs.empty()) { |
| 290 *error_details = "Failed to create certificate chain. Certs are empty."; |
| 291 DLOG(WARNING) << *error_details; |
| 292 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; |
| 293 *verify_details = std::move(verify_details_); |
| 294 return false; |
| 295 } |
| 296 |
| 297 // Convert certs to X509Certificate. |
| 298 vector<StringPiece> cert_pieces(certs.size()); |
| 299 for (unsigned i = 0; i < certs.size(); i++) { |
| 300 cert_pieces[i] = base::StringPiece(certs[i]); |
| 301 } |
| 302 cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces); |
| 303 if (!cert_.get()) { |
| 304 *error_details = "Failed to create certificate chain"; |
| 305 DLOG(WARNING) << *error_details; |
| 306 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID; |
| 307 *verify_details = std::move(verify_details_); |
| 308 return false; |
| 309 } |
| 310 return true; |
| 311 } |
| 312 |
| 313 QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert( |
| 314 const string& hostname, |
| 315 const uint16_t port, |
| 316 std::string* error_details, |
| 317 std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 318 std::unique_ptr<ProofVerifierCallback> callback) { |
240 hostname_ = hostname; | 319 hostname_ = hostname; |
241 port_ = port; | 320 port_ = port; |
242 | 321 |
243 next_state_ = STATE_VERIFY_CERT; | 322 next_state_ = STATE_VERIFY_CERT; |
244 switch (DoLoop(OK)) { | 323 switch (DoLoop(OK)) { |
245 case OK: | 324 case OK: |
246 *verify_details = std::move(verify_details_); | 325 *verify_details = std::move(verify_details_); |
247 return QUIC_SUCCESS; | 326 return QUIC_SUCCESS; |
248 case ERR_IO_PENDING: | 327 case ERR_IO_PENDING: |
249 callback_ = std::move(callback); | 328 callback_ = std::move(callback); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 | 387 |
309 const CertVerifyResult& cert_verify_result = | 388 const CertVerifyResult& cert_verify_result = |
310 verify_details_->cert_verify_result; | 389 verify_details_->cert_verify_result; |
311 const CertStatus cert_status = cert_verify_result.cert_status; | 390 const CertStatus cert_status = cert_verify_result.cert_status; |
312 verify_details_->ct_verify_result.ct_policies_applied = result == OK; | 391 verify_details_->ct_verify_result.ct_policies_applied = result == OK; |
313 verify_details_->ct_verify_result.ev_policy_compliance = | 392 verify_details_->ct_verify_result.ev_policy_compliance = |
314 ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; | 393 ct::EVPolicyCompliance::EV_POLICY_DOES_NOT_APPLY; |
315 | 394 |
316 // If the connection was good, check HPKP and CT status simultaneously, | 395 // If the connection was good, check HPKP and CT status simultaneously, |
317 // but prefer to treat the HPKP error as more serious, if there was one. | 396 // but prefer to treat the HPKP error as more serious, if there was one. |
318 if ((result == OK || | 397 if (enforce_policy_checking_ && |
| 398 (result == OK || |
319 (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) { | 399 (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) { |
320 if ((cert_verify_result.cert_status & CERT_STATUS_IS_EV)) { | 400 if ((cert_verify_result.cert_status & CERT_STATUS_IS_EV)) { |
321 ct::EVPolicyCompliance ev_policy_compliance = | 401 ct::EVPolicyCompliance ev_policy_compliance = |
322 policy_enforcer_->DoesConformToCTEVPolicy( | 402 policy_enforcer_->DoesConformToCTEVPolicy( |
323 cert_verify_result.verified_cert.get(), | 403 cert_verify_result.verified_cert.get(), |
324 SSLConfigService::GetEVCertsWhitelist().get(), | 404 SSLConfigService::GetEVCertsWhitelist().get(), |
325 verify_details_->ct_verify_result.verified_scts, net_log_); | 405 verify_details_->ct_verify_result.verified_scts, net_log_); |
326 verify_details_->ct_verify_result.ev_policy_compliance = | 406 verify_details_->ct_verify_result.ev_policy_compliance = |
327 ev_policy_compliance; | 407 ev_policy_compliance; |
328 if (ev_policy_compliance != | 408 if (ev_policy_compliance != |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 } | 578 } |
499 const ProofVerifyContextChromium* chromium_context = | 579 const ProofVerifyContextChromium* chromium_context = |
500 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); | 580 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); |
501 std::unique_ptr<Job> job( | 581 std::unique_ptr<Job> job( |
502 new Job(this, cert_verifier_, ct_policy_enforcer_, | 582 new Job(this, cert_verifier_, ct_policy_enforcer_, |
503 transport_security_state_, cert_transparency_verifier_, | 583 transport_security_state_, cert_transparency_verifier_, |
504 chromium_context->cert_verify_flags, chromium_context->net_log)); | 584 chromium_context->cert_verify_flags, chromium_context->net_log)); |
505 QuicAsyncStatus status = job->VerifyProof( | 585 QuicAsyncStatus status = job->VerifyProof( |
506 hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct, | 586 hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct, |
507 signature, error_details, verify_details, std::move(callback)); | 587 signature, error_details, verify_details, std::move(callback)); |
508 if (status == QUIC_PENDING) { | 588 if (status == QUIC_PENDING) |
509 active_jobs_.insert(job.release()); | 589 active_jobs_.insert(job.release()); |
510 } | |
511 return status; | 590 return status; |
512 } | 591 } |
513 | 592 |
| 593 QuicAsyncStatus ProofVerifierChromium::VerifyCertChain( |
| 594 const std::string& hostname, |
| 595 const std::vector<std::string>& certs, |
| 596 const ProofVerifyContext* verify_context, |
| 597 std::string* error_details, |
| 598 std::unique_ptr<ProofVerifyDetails>* verify_details, |
| 599 std::unique_ptr<ProofVerifierCallback> callback) { |
| 600 if (!verify_context) { |
| 601 *error_details = "Missing context"; |
| 602 return QUIC_FAILURE; |
| 603 } |
| 604 const ProofVerifyContextChromium* chromium_context = |
| 605 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context); |
| 606 std::unique_ptr<Job> job( |
| 607 new Job(this, cert_verifier_, ct_policy_enforcer_, |
| 608 transport_security_state_, cert_transparency_verifier_, |
| 609 chromium_context->cert_verify_flags, chromium_context->net_log)); |
| 610 QuicAsyncStatus status = job->VerifyCertChain( |
| 611 hostname, certs, error_details, verify_details, std::move(callback)); |
| 612 if (status == QUIC_PENDING) |
| 613 active_jobs_.insert(job.release()); |
| 614 return status; |
| 615 } |
| 616 |
514 void ProofVerifierChromium::OnJobComplete(Job* job) { | 617 void ProofVerifierChromium::OnJobComplete(Job* job) { |
515 active_jobs_.erase(job); | 618 active_jobs_.erase(job); |
516 delete job; | 619 delete job; |
517 } | 620 } |
518 | 621 |
519 } // namespace net | 622 } // namespace net |
OLD | NEW |