1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/quic/crypto/proof_verifier_chromium.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h"
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind_helpers.h"
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/callback_helpers.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/compiler_specific.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/metrics/histogram.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/stl_util.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/stringprintf.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "crypto/signature_verifier.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/base/net_errors.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/base/net_log.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/asn1_util.h"
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/cert_status_flags.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/cert_verifier.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/cert_verify_result.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/single_request_cert_verifier.h"
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/x509_certificate.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/x509_util.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/transport_security_state.h"
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/quic/crypto/crypto_protocol.h"
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/ssl/ssl_config_service.h"
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::StringPiece;
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::StringPrintf;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing std::string;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing std::vector;
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace net {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  other->cert_verify_result = cert_verify_result;
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return other;
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A Job handles the verification of a single proof.  It is owned by the
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// ProofVerifier. If the verification can not complete synchronously, it
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// will notify the ProofVerifier upon completion.
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ProofVerifierChromium::Job {
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Job(ProofVerifierChromium* proof_verifier,
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      CertVerifier* cert_verifier,
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      TransportSecurityState* transport_security_state,
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const BoundNetLog& net_log);
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Starts the proof verification.  If |QUIC_PENDING| is returned, then
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // |callback| will be invoked asynchronously when the verification completes.
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  QuicAsyncStatus VerifyProof(const std::string& hostname,
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              const std::string& server_config,
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              const std::vector<std::string>& certs,
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              const std::string& signature,
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              std::string* error_details,
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              scoped_ptr<ProofVerifyDetails>* verify_details,
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                              ProofVerifierCallback* callback);
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  enum State {
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    STATE_NONE,
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    STATE_VERIFY_CERT,
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    STATE_VERIFY_CERT_COMPLETE,
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  };
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int DoLoop(int last_io_result);
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void OnIOComplete(int result);
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int DoVerifyCert(int result);
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int DoVerifyCertComplete(int result);
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool VerifySignature(const std::string& signed_data,
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       const std::string& signature,
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                       const std::string& cert);
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Proof verifier to notify when this jobs completes.
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ProofVerifierChromium* proof_verifier_;
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The underlying verifier used for verifying certificates.
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<SingleRequestCertVerifier> verifier_;
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  TransportSecurityState* transport_security_state_;
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // |hostname| specifies the hostname for which |certs| is a valid chain.
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string hostname_;
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ProofVerifierCallback> callback_;
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<ProofVerifyDetailsChromium> verify_details_;
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string error_details_;
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // X509Certificate from a chain of DER encoded certificates.
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<X509Certificate> cert_;
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  State next_state_;
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BoundNetLog net_log_;
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Job);
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ProofVerifierChromium::Job::Job(
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ProofVerifierChromium* proof_verifier,
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CertVerifier* cert_verifier,
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    TransportSecurityState* transport_security_state,
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const BoundNetLog& net_log)
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : proof_verifier_(proof_verifier),
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      verifier_(new SingleRequestCertVerifier(cert_verifier)),
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      transport_security_state_(transport_security_state),
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      next_state_(STATE_NONE),
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      net_log_(net_log) {
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
116d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const string& hostname,
117d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const string& server_config,
118d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const vector<string>& certs,
119d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    const string& signature,
120d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    std::string* error_details,
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    scoped_ptr<ProofVerifyDetails>* verify_details,
122d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    ProofVerifierCallback* callback) {
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(error_details);
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(verify_details);
125d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  DCHECK(callback);
126d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  error_details->clear();
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (STATE_NONE != next_state_) {
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *error_details = "Certificate is already set and VerifyProof has begun";
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DLOG(DFATAL) << *error_details;
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return QUIC_FAILURE;
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
135d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  verify_details_.reset(new ProofVerifyDetailsChromium);
136d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (certs.empty()) {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *error_details = "Failed to create certificate chain. Certs are empty.";
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(WARNING) << *error_details;
140d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *verify_details = verify_details_.Pass();
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return QUIC_FAILURE;
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Convert certs to X509Certificate.
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  vector<StringPiece> cert_pieces(certs.size());
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (unsigned i = 0; i < certs.size(); i++) {
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cert_pieces[i] = base::StringPiece(certs[i]);
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!cert_.get()) {
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *error_details = "Failed to create certificate chain";
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(WARNING) << *error_details;
154d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *verify_details = verify_details_.Pass();
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return QUIC_FAILURE;
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // We call VerifySignature first to avoid copying of server_config and
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // signature.
161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!VerifySignature(server_config, signature, certs[0])) {
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    *error_details = "Failed to verify signature of server config";
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(WARNING) << *error_details;
164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *verify_details = verify_details_.Pass();
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return QUIC_FAILURE;
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  hostname_ = hostname;
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  next_state_ = STATE_VERIFY_CERT;
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  switch (DoLoop(OK)) {
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case OK:
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      *verify_details = verify_details_.Pass();
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return QUIC_SUCCESS;
176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    case ERR_IO_PENDING:
177c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      callback_.reset(callback);
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return QUIC_PENDING;
179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    default:
180d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      *error_details = error_details_;
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      *verify_details = verify_details_.Pass();
18246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      return QUIC_FAILURE;
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch  }
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ProofVerifierChromium::Job::DoLoop(int last_result) {
187eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rv = last_result;
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  do {
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    State state = next_state_;
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    next_state_ = STATE_NONE;
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    switch (state) {
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      case STATE_VERIFY_CERT:
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        DCHECK(rv == OK);
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        rv = DoVerifyCert(rv);
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        break;
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      case STATE_VERIFY_CERT_COMPLETE:
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        rv = DoVerifyCertComplete(rv);
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        break;
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      case STATE_NONE:
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      default:
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        rv = ERR_UNEXPECTED;
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        LOG(DFATAL) << "unexpected state " << state;
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        break;
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return rv;
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ProofVerifierChromium::Job::OnIOComplete(int result) {
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int rv = DoLoop(result);
211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (rv != ERR_IO_PENDING) {
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ProofVerifierCallback> callback(callback_.Pass());
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
214116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<ProofVerifyDetails> verify_details(verify_details_.Pass());
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    callback->Run(rv == OK, error_details_, &verify_details);
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Will delete |this|.
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    proof_verifier_->OnJobComplete(this);
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ProofVerifierChromium::Job::DoVerifyCert(int result) {
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  next_state_ = STATE_VERIFY_CERT_COMPLETE;
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int flags = 0;
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return verifier_->Verify(
226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      cert_.get(),
227eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      hostname_,
228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      flags,
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      SSLConfigService::GetCRLSet().get(),
230d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      &verify_details_->cert_verify_result,
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 base::Unretained(this)),
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      net_log_);
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  verifier_.reset();
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const CertVerifyResult& cert_verify_result =
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      verify_details_->cert_verify_result;
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const CertStatus cert_status = cert_verify_result.cert_status;
2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (transport_security_state_ &&
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      (result == OK ||
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
2456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      !transport_security_state_->CheckPublicKeyPins(
2466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          hostname_,
2476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          cert_verify_result.is_issued_by_known_root,
2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          cert_verify_result.public_key_hashes,
2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          &verify_details_->pinning_failure_log)) {
2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (result != OK) {
2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::string error_string = ErrorToString(result);
255d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    error_details_ = StringPrintf("Failed to verify certificate chain: %s",
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                  error_string.c_str());
257d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    DLOG(WARNING) << error_details_;
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Exit DoLoop and return the result to the caller to VerifyProof.
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK_EQ(STATE_NONE, next_state_);
262eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return result;
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
2666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                                 const string& signature,
2676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                                 const string& cert) {
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StringPiece spki;
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  crypto::SignatureVerifier verifier;
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t size_bits;
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  X509Certificate::PublicKeyType type;
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    &type);
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (type == X509Certificate::kPublicKeyTypeRSA) {
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    crypto::SignatureVerifier::HashAlgorithm hash_alg =
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        crypto::SignatureVerifier::SHA256;
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    unsigned int hash_len = 32;  // 32 is the length of a SHA-256 hash.
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool ok = verifier.VerifyInitRSAPSS(
287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        hash_alg, mask_hash_alg, hash_len,
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        reinterpret_cast<const uint8*>(signature.data()), signature.size(),
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        reinterpret_cast<const uint8*>(spki.data()), spki.size());
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!ok) {
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      DLOG(WARNING) << "VerifyInitRSAPSS failed";
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // RFC 5758:
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //        us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   ...
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   as an AlgorithmIdentifier, the encoding MUST omit the parameters
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   field.  That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    //   SHA384, or ecdsa-with-SHA512.
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // See also RFC 5480, Appendix A.
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    static const uint8 kECDSAWithSHA256AlgorithmID[] = {
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      0x30, 0x0a,
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        0x06, 0x08,
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    };
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!verifier.VerifyInit(
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            reinterpret_cast<const uint8*>(signature.data()),
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            signature.size(),
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            reinterpret_cast<const uint8*>(spki.data()),
318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            spki.size())) {
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      DLOG(WARNING) << "VerifyInit failed";
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Unsupported public key type " << type;
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        sizeof(kProofSignatureLabel));
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        signed_data.size());
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!verifier.VerifyFinal()) {
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    DLOG(WARNING) << "VerifyFinal failed";
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DVLOG(1) << "VerifyFinal success";
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ProofVerifierChromium::ProofVerifierChromium(
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CertVerifier* cert_verifier,
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    TransportSecurityState* transport_security_state)
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : cert_verifier_(cert_verifier),
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      transport_security_state_(transport_security_state) {
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ProofVerifierChromium::~ProofVerifierChromium() {
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  STLDeleteElements(&active_jobs_);
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)QuicAsyncStatus ProofVerifierChromium::VerifyProof(
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& hostname,
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& server_config,
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<std::string>& certs,
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& signature,
357effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const ProofVerifyContext* verify_context,
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string* error_details,
359effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    scoped_ptr<ProofVerifyDetails>* verify_details,
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ProofVerifierCallback* callback) {
361effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!verify_context) {
362effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    *error_details = "Missing context";
36346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return QUIC_FAILURE;
364effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
365effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const ProofVerifyContextChromium* chromium_context =
366effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<Job> job(new Job(this,
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              cert_verifier_,
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              transport_security_state_,
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              chromium_context->net_log));
37146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs,
37246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                            signature, error_details,
37346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                            verify_details, callback);
37446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (status == QUIC_PENDING) {
375a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    active_jobs_.insert(job.release());
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return status;
378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ProofVerifierChromium::OnJobComplete(Job* job) {
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  active_jobs_.erase(job);
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  delete job;
383a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace net
386