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
3// found in the LICENSE file.
4
5#include "net/quic/crypto/proof_verifier_chromium.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback_helpers.h"
10#include "base/compiler_specific.h"
11#include "base/logging.h"
12#include "base/strings/stringprintf.h"
13#include "crypto/signature_verifier.h"
14#include "net/base/net_errors.h"
15#include "net/base/net_log.h"
16#include "net/cert/asn1_util.h"
17#include "net/cert/cert_status_flags.h"
18#include "net/cert/cert_verifier.h"
19#include "net/cert/cert_verify_result.h"
20#include "net/cert/single_request_cert_verifier.h"
21#include "net/cert/x509_certificate.h"
22#include "net/cert/x509_util.h"
23#include "net/quic/crypto/crypto_protocol.h"
24#include "net/ssl/ssl_config_service.h"
25
26using base::StringPiece;
27using base::StringPrintf;
28using std::string;
29using std::vector;
30
31namespace net {
32
33ProofVerifierChromium::ProofVerifierChromium(CertVerifier* cert_verifier,
34                                             const BoundNetLog& net_log)
35  : cert_verifier_(cert_verifier),
36    next_state_(STATE_NONE),
37    net_log_(net_log) {
38}
39
40ProofVerifierChromium::~ProofVerifierChromium() {
41  verifier_.reset();
42}
43
44ProofVerifierChromium::Status ProofVerifierChromium::VerifyProof(
45    const string& hostname,
46    const string& server_config,
47    const vector<string>& certs,
48    const string& signature,
49    std::string* error_details,
50    scoped_ptr<ProofVerifyDetails>* details,
51    ProofVerifierCallback* callback) {
52  DCHECK(error_details);
53  DCHECK(details);
54  DCHECK(callback);
55
56  callback_.reset(callback);
57  error_details->clear();
58
59  DCHECK_EQ(STATE_NONE, next_state_);
60  if (STATE_NONE != next_state_) {
61    *error_details = "Certificate is already set and VerifyProof has begun";
62    DLOG(WARNING) << *error_details;
63    return FAILURE;
64  }
65
66  verify_details_.reset(new ProofVerifyDetailsChromium);
67
68  if (certs.empty()) {
69    *error_details = "Failed to create certificate chain. Certs are empty.";
70    DLOG(WARNING) << *error_details;
71    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
72    details->reset(verify_details_.release());
73    return FAILURE;
74  }
75
76  // Convert certs to X509Certificate.
77  vector<StringPiece> cert_pieces(certs.size());
78  for (unsigned i = 0; i < certs.size(); i++) {
79    cert_pieces[i] = base::StringPiece(certs[i]);
80  }
81  cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
82  if (!cert_.get()) {
83    *error_details = "Failed to create certificate chain";
84    DLOG(WARNING) << *error_details;
85    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
86    details->reset(verify_details_.release());
87    return FAILURE;
88  }
89
90  // We call VerifySignature first to avoid copying of server_config and
91  // signature.
92  if (!VerifySignature(server_config, signature, certs[0])) {
93    *error_details = "Failed to verify signature of server config";
94    DLOG(WARNING) << *error_details;
95    verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
96    details->reset(verify_details_.release());
97    return FAILURE;
98  }
99
100  hostname_ = hostname;
101
102  next_state_ = STATE_VERIFY_CERT;
103  switch (DoLoop(OK)) {
104    case OK:
105      details->reset(verify_details_.release());
106      return SUCCESS;
107    case ERR_IO_PENDING:
108      return PENDING;
109    default:
110      *error_details = error_details_;
111      details->reset(verify_details_.release());
112      return FAILURE;
113  }
114}
115
116int ProofVerifierChromium::DoLoop(int last_result) {
117  int rv = last_result;
118  do {
119    State state = next_state_;
120    next_state_ = STATE_NONE;
121    switch (state) {
122      case STATE_VERIFY_CERT:
123        DCHECK(rv == OK);
124        rv = DoVerifyCert(rv);
125        break;
126      case STATE_VERIFY_CERT_COMPLETE:
127        rv = DoVerifyCertComplete(rv);
128        break;
129      case STATE_NONE:
130      default:
131        rv = ERR_UNEXPECTED;
132        LOG(DFATAL) << "unexpected state " << state;
133        break;
134    }
135  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
136  return rv;
137}
138
139void ProofVerifierChromium::OnIOComplete(int result) {
140  int rv = DoLoop(result);
141  if (rv != ERR_IO_PENDING) {
142    scoped_ptr<ProofVerifyDetails> scoped_details(verify_details_.release());
143    callback_->Run(rv == OK, error_details_, &scoped_details);
144    callback_.reset();
145  }
146}
147
148int ProofVerifierChromium::DoVerifyCert(int result) {
149  next_state_ = STATE_VERIFY_CERT_COMPLETE;
150
151  int flags = 0;
152  verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
153  return verifier_->Verify(
154      cert_.get(),
155      hostname_,
156      flags,
157      SSLConfigService::GetCRLSet().get(),
158      &verify_details_->cert_verify_result,
159      base::Bind(&ProofVerifierChromium::OnIOComplete,
160                 base::Unretained(this)),
161      net_log_);
162}
163
164int ProofVerifierChromium::DoVerifyCertComplete(int result) {
165  verifier_.reset();
166
167  if (result <= ERR_FAILED) {
168    error_details_ = StringPrintf("Failed to verify certificate chain: %s",
169                                  ErrorToString(result));
170    DLOG(WARNING) << error_details_;
171    result = ERR_FAILED;
172  }
173
174  // Exit DoLoop and return the result to the caller to VerifyProof.
175  DCHECK_EQ(STATE_NONE, next_state_);
176  return result;
177}
178
179bool ProofVerifierChromium::VerifySignature(const string& signed_data,
180                                            const string& signature,
181                                            const string& cert) {
182  StringPiece spki;
183  if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
184    DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
185    return false;
186  }
187
188  crypto::SignatureVerifier verifier;
189
190  size_t size_bits;
191  X509Certificate::PublicKeyType type;
192  X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
193                                    &type);
194  if (type == X509Certificate::kPublicKeyTypeRSA) {
195    crypto::SignatureVerifier::HashAlgorithm hash_alg =
196        crypto::SignatureVerifier::SHA256;
197    crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
198    unsigned int hash_len = 32;  // 32 is the length of a SHA-256 hash.
199
200    bool ok = verifier.VerifyInitRSAPSS(
201        hash_alg, mask_hash_alg, hash_len,
202        reinterpret_cast<const uint8*>(signature.data()), signature.size(),
203        reinterpret_cast<const uint8*>(spki.data()), spki.size());
204    if (!ok) {
205      DLOG(WARNING) << "VerifyInitRSAPSS failed";
206      return false;
207    }
208  } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
209    // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
210    // RFC 5758:
211    //   ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
212    //        us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
213    //   ...
214    //   When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
215    //   ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
216    //   as an AlgorithmIdentifier, the encoding MUST omit the parameters
217    //   field.  That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
218    //   component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
219    //   SHA384, or ecdsa-with-SHA512.
220    // See also RFC 5480, Appendix A.
221    static const uint8 kECDSAWithSHA256AlgorithmID[] = {
222      0x30, 0x0a,
223        0x06, 0x08,
224          0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
225    };
226
227    if (!verifier.VerifyInit(
228            kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
229            reinterpret_cast<const uint8*>(signature.data()),
230            signature.size(),
231            reinterpret_cast<const uint8*>(spki.data()),
232            spki.size())) {
233      DLOG(WARNING) << "VerifyInit failed";
234      return false;
235    }
236  } else {
237    LOG(ERROR) << "Unsupported public key type " << type;
238    return false;
239  }
240
241  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
242                        sizeof(kProofSignatureLabel));
243  verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
244                        signed_data.size());
245
246  if (!verifier.VerifyFinal()) {
247    DLOG(WARNING) << "VerifyFinal failed";
248    return false;
249  }
250
251  DVLOG(1) << "VerifyFinal success";
252  return true;
253}
254
255}  // namespace net
256