| Index: net/quic/chromium/crypto/proof_verifier_chromium.cc
|
| diff --git a/net/quic/chromium/crypto/proof_verifier_chromium.cc b/net/quic/chromium/crypto/proof_verifier_chromium.cc
|
| index d66b9ff7bb081f60b3214381d26fe078bab44a4c..9a7396eb798887a98bd60d23f7cff066ae7cb61f 100644
|
| --- a/net/quic/chromium/crypto/proof_verifier_chromium.cc
|
| +++ b/net/quic/chromium/crypto/proof_verifier_chromium.cc
|
| @@ -78,6 +78,16 @@ class ProofVerifierChromium::Job {
|
| std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| std::unique_ptr<ProofVerifierCallback> callback);
|
|
|
| + // Starts the certificate chain verification of |certs|. If |QUIC_PENDING| is
|
| + // returned, then |callback| will be invoked asynchronously when the
|
| + // verification completes.
|
| + QuicAsyncStatus VerifyCertChain(
|
| + const std::string& hostname,
|
| + const std::vector<std::string>& certs,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| + std::unique_ptr<ProofVerifierCallback> callback);
|
| +
|
| private:
|
| enum State {
|
| STATE_NONE,
|
| @@ -85,6 +95,19 @@ class ProofVerifierChromium::Job {
|
| STATE_VERIFY_CERT_COMPLETE,
|
| };
|
|
|
| + // Convert |certs| to |cert_|(X509Certificate). Returns true if successful.
|
| + bool GetX509Certificate(const vector<string>& certs,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details);
|
| +
|
| + // Start the cert verification.
|
| + QuicAsyncStatus VerifyCert(
|
| + const string& hostname,
|
| + const uint16_t port,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| + std::unique_ptr<ProofVerifierCallback> callback);
|
| +
|
| int DoLoop(int last_io_result);
|
| void OnIOComplete(int result);
|
| int DoVerifyCert(int result);
|
| @@ -125,6 +148,9 @@ class ProofVerifierChromium::Job {
|
| // passed to CertVerifier::Verify.
|
| int cert_verify_flags_;
|
|
|
| + // If set to true, enforces policy checking in DoVerifyCertComplete().
|
| + bool enforce_policy_checking_;
|
| +
|
| State next_state_;
|
|
|
| base::TimeTicks start_time_;
|
| @@ -148,6 +174,7 @@ ProofVerifierChromium::Job::Job(
|
| transport_security_state_(transport_security_state),
|
| cert_transparency_verifier_(cert_transparency_verifier),
|
| cert_verify_flags_(cert_verify_flags),
|
| + enforce_policy_checking_(true),
|
| next_state_(STATE_NONE),
|
| start_time_(base::TimeTicks::Now()),
|
| net_log_(net_log) {
|
| @@ -195,27 +222,9 @@ QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
|
|
|
| verify_details_.reset(new ProofVerifyDetailsChromium);
|
|
|
| - if (certs.empty()) {
|
| - *error_details = "Failed to create certificate chain. Certs are empty.";
|
| - DLOG(WARNING) << *error_details;
|
| - verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
|
| - *verify_details = std::move(verify_details_);
|
| - return QUIC_FAILURE;
|
| - }
|
| -
|
| - // Convert certs to X509Certificate.
|
| - vector<StringPiece> cert_pieces(certs.size());
|
| - for (unsigned i = 0; i < certs.size(); i++) {
|
| - cert_pieces[i] = base::StringPiece(certs[i]);
|
| - }
|
| - cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
|
| - if (!cert_.get()) {
|
| - *error_details = "Failed to create certificate chain";
|
| - DLOG(WARNING) << *error_details;
|
| - verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
|
| - *verify_details = std::move(verify_details_);
|
| + // Converts |certs| to |cert_|.
|
| + if (!GetX509Certificate(certs, error_details, verify_details))
|
| return QUIC_FAILURE;
|
| - }
|
|
|
| if (!cert_sct.empty()) {
|
| // Note that this is a completely synchronous operation: The CT Log Verifier
|
| @@ -228,7 +237,8 @@ QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
|
|
|
| // We call VerifySignature first to avoid copying of server_config and
|
| // signature.
|
| - if (!VerifySignature(server_config, quic_version, chlo_hash, signature,
|
| + if (!signature.empty() &&
|
| + !VerifySignature(server_config, quic_version, chlo_hash, signature,
|
| certs[0])) {
|
| *error_details = "Failed to verify signature of server config";
|
| DLOG(WARNING) << *error_details;
|
| @@ -237,6 +247,75 @@ QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
|
| return QUIC_FAILURE;
|
| }
|
|
|
| + DCHECK(enforce_policy_checking_);
|
| + return VerifyCert(hostname, port, error_details, verify_details,
|
| + std::move(callback));
|
| +}
|
| +
|
| +QuicAsyncStatus ProofVerifierChromium::Job::VerifyCertChain(
|
| + const string& hostname,
|
| + const vector<string>& certs,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| + std::unique_ptr<ProofVerifierCallback> callback) {
|
| + DCHECK(error_details);
|
| + DCHECK(verify_details);
|
| + DCHECK(callback);
|
| +
|
| + error_details->clear();
|
| +
|
| + if (STATE_NONE != next_state_) {
|
| + *error_details = "Certificate is already set and VerifyCertChain has begun";
|
| + DLOG(DFATAL) << *error_details;
|
| + return QUIC_FAILURE;
|
| + }
|
| +
|
| + verify_details_.reset(new ProofVerifyDetailsChromium);
|
| +
|
| + // Converts |certs| to |cert_|.
|
| + if (!GetX509Certificate(certs, error_details, verify_details))
|
| + return QUIC_FAILURE;
|
| +
|
| + enforce_policy_checking_ = false;
|
| + // |port| is not needed because |enforce_policy_checking_| is false.
|
| + return VerifyCert(hostname, /*port=*/0, error_details, verify_details,
|
| + std::move(callback));
|
| +}
|
| +
|
| +bool ProofVerifierChromium::Job::GetX509Certificate(
|
| + const vector<string>& certs,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details) {
|
| + if (certs.empty()) {
|
| + *error_details = "Failed to create certificate chain. Certs are empty.";
|
| + DLOG(WARNING) << *error_details;
|
| + verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
|
| + *verify_details = std::move(verify_details_);
|
| + return false;
|
| + }
|
| +
|
| + // Convert certs to X509Certificate.
|
| + vector<StringPiece> cert_pieces(certs.size());
|
| + for (unsigned i = 0; i < certs.size(); i++) {
|
| + cert_pieces[i] = base::StringPiece(certs[i]);
|
| + }
|
| + cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
|
| + if (!cert_.get()) {
|
| + *error_details = "Failed to create certificate chain";
|
| + DLOG(WARNING) << *error_details;
|
| + verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
|
| + *verify_details = std::move(verify_details_);
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +QuicAsyncStatus ProofVerifierChromium::Job::VerifyCert(
|
| + const string& hostname,
|
| + const uint16_t port,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| + std::unique_ptr<ProofVerifierCallback> callback) {
|
| hostname_ = hostname;
|
| port_ = port;
|
|
|
| @@ -315,7 +394,8 @@ int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
|
|
|
| // If the connection was good, check HPKP and CT status simultaneously,
|
| // but prefer to treat the HPKP error as more serious, if there was one.
|
| - if ((result == OK ||
|
| + if (enforce_policy_checking_ &&
|
| + (result == OK ||
|
| (IsCertificateError(result) && IsCertStatusMinorError(cert_status)))) {
|
| if ((cert_verify_result.cert_status & CERT_STATUS_IS_EV)) {
|
| ct::EVPolicyCompliance ev_policy_compliance =
|
| @@ -505,9 +585,32 @@ QuicAsyncStatus ProofVerifierChromium::VerifyProof(
|
| QuicAsyncStatus status = job->VerifyProof(
|
| hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct,
|
| signature, error_details, verify_details, std::move(callback));
|
| - if (status == QUIC_PENDING) {
|
| + if (status == QUIC_PENDING)
|
| active_jobs_.insert(job.release());
|
| + return status;
|
| +}
|
| +
|
| +QuicAsyncStatus ProofVerifierChromium::VerifyCertChain(
|
| + const std::string& hostname,
|
| + const std::vector<std::string>& certs,
|
| + const ProofVerifyContext* verify_context,
|
| + std::string* error_details,
|
| + std::unique_ptr<ProofVerifyDetails>* verify_details,
|
| + std::unique_ptr<ProofVerifierCallback> callback) {
|
| + if (!verify_context) {
|
| + *error_details = "Missing context";
|
| + return QUIC_FAILURE;
|
| }
|
| + const ProofVerifyContextChromium* chromium_context =
|
| + reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
|
| + std::unique_ptr<Job> job(
|
| + new Job(this, cert_verifier_, ct_policy_enforcer_,
|
| + transport_security_state_, cert_transparency_verifier_,
|
| + chromium_context->cert_verify_flags, chromium_context->net_log));
|
| + QuicAsyncStatus status = job->VerifyCertChain(
|
| + hostname, certs, error_details, verify_details, std::move(callback));
|
| + if (status == QUIC_PENDING)
|
| + active_jobs_.insert(job.release());
|
| return status;
|
| }
|
|
|
|
|