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