Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / quic / crypto / proof_verifier_chromium.cc
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/metrics/histogram.h"
13 #include "base/stl_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "crypto/signature_verifier.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/net_log.h"
18 #include "net/cert/asn1_util.h"
19 #include "net/cert/cert_status_flags.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/cert/cert_verify_result.h"
22 #include "net/cert/single_request_cert_verifier.h"
23 #include "net/cert/x509_certificate.h"
24 #include "net/cert/x509_util.h"
25 #include "net/http/transport_security_state.h"
26 #include "net/quic/crypto/crypto_protocol.h"
27 #include "net/ssl/ssl_config_service.h"
28
29 using base::StringPiece;
30 using base::StringPrintf;
31 using std::string;
32 using std::vector;
33
34 namespace net {
35
36 ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
37   ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
38   other->cert_verify_result = cert_verify_result;
39   return other;
40 }
41
42 // A Job handles the verification of a single proof.  It is owned by the
43 // ProofVerifier. If the verification can not complete synchronously, it
44 // will notify the ProofVerifier upon completion.
45 class ProofVerifierChromium::Job {
46  public:
47   Job(ProofVerifierChromium* proof_verifier,
48       CertVerifier* cert_verifier,
49       TransportSecurityState* transport_security_state,
50       const BoundNetLog& net_log);
51
52   // Starts the proof verification.  If |QUIC_PENDING| is returned, then
53   // |callback| will be invoked asynchronously when the verification completes.
54   QuicAsyncStatus VerifyProof(const std::string& hostname,
55                               const std::string& server_config,
56                               const std::vector<std::string>& certs,
57                               const std::string& signature,
58                               std::string* error_details,
59                               scoped_ptr<ProofVerifyDetails>* verify_details,
60                               ProofVerifierCallback* callback);
61
62  private:
63   enum State {
64     STATE_NONE,
65     STATE_VERIFY_CERT,
66     STATE_VERIFY_CERT_COMPLETE,
67   };
68
69   int DoLoop(int last_io_result);
70   void OnIOComplete(int result);
71   int DoVerifyCert(int result);
72   int DoVerifyCertComplete(int result);
73
74   bool VerifySignature(const std::string& signed_data,
75                        const std::string& signature,
76                        const std::string& cert);
77
78   // Proof verifier to notify when this jobs completes.
79   ProofVerifierChromium* proof_verifier_;
80
81   // The underlying verifier used for verifying certificates.
82   scoped_ptr<SingleRequestCertVerifier> verifier_;
83
84   TransportSecurityState* transport_security_state_;
85
86   // |hostname| specifies the hostname for which |certs| is a valid chain.
87   std::string hostname_;
88
89   scoped_ptr<ProofVerifierCallback> callback_;
90   scoped_ptr<ProofVerifyDetailsChromium> verify_details_;
91   std::string error_details_;
92
93   // X509Certificate from a chain of DER encoded certificates.
94   scoped_refptr<X509Certificate> cert_;
95
96   State next_state_;
97
98   BoundNetLog net_log_;
99
100   DISALLOW_COPY_AND_ASSIGN(Job);
101 };
102
103 ProofVerifierChromium::Job::Job(
104     ProofVerifierChromium* proof_verifier,
105     CertVerifier* cert_verifier,
106     TransportSecurityState* transport_security_state,
107     const BoundNetLog& net_log)
108     : proof_verifier_(proof_verifier),
109       verifier_(new SingleRequestCertVerifier(cert_verifier)),
110       transport_security_state_(transport_security_state),
111       next_state_(STATE_NONE),
112       net_log_(net_log) {
113 }
114
115 QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
116     const string& hostname,
117     const string& server_config,
118     const vector<string>& certs,
119     const string& signature,
120     std::string* error_details,
121     scoped_ptr<ProofVerifyDetails>* verify_details,
122     ProofVerifierCallback* callback) {
123   DCHECK(error_details);
124   DCHECK(verify_details);
125   DCHECK(callback);
126
127   error_details->clear();
128
129   if (STATE_NONE != next_state_) {
130     *error_details = "Certificate is already set and VerifyProof has begun";
131     DLOG(DFATAL) << *error_details;
132     return QUIC_FAILURE;
133   }
134
135   verify_details_.reset(new ProofVerifyDetailsChromium);
136
137   if (certs.empty()) {
138     *error_details = "Failed to create certificate chain. Certs are empty.";
139     DLOG(WARNING) << *error_details;
140     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
141     *verify_details = verify_details_.Pass();
142     return QUIC_FAILURE;
143   }
144
145   // Convert certs to X509Certificate.
146   vector<StringPiece> cert_pieces(certs.size());
147   for (unsigned i = 0; i < certs.size(); i++) {
148     cert_pieces[i] = base::StringPiece(certs[i]);
149   }
150   cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
151   if (!cert_.get()) {
152     *error_details = "Failed to create certificate chain";
153     DLOG(WARNING) << *error_details;
154     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
155     *verify_details = verify_details_.Pass();
156     return QUIC_FAILURE;
157   }
158
159   // We call VerifySignature first to avoid copying of server_config and
160   // signature.
161   if (!VerifySignature(server_config, signature, certs[0])) {
162     *error_details = "Failed to verify signature of server config";
163     DLOG(WARNING) << *error_details;
164     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
165     *verify_details = verify_details_.Pass();
166     return QUIC_FAILURE;
167   }
168
169   hostname_ = hostname;
170
171   next_state_ = STATE_VERIFY_CERT;
172   switch (DoLoop(OK)) {
173     case OK:
174       *verify_details = verify_details_.Pass();
175       return QUIC_SUCCESS;
176     case ERR_IO_PENDING:
177       callback_.reset(callback);
178       return QUIC_PENDING;
179     default:
180       *error_details = error_details_;
181       *verify_details = verify_details_.Pass();
182       return QUIC_FAILURE;
183   }
184 }
185
186 int ProofVerifierChromium::Job::DoLoop(int last_result) {
187   int rv = last_result;
188   do {
189     State state = next_state_;
190     next_state_ = STATE_NONE;
191     switch (state) {
192       case STATE_VERIFY_CERT:
193         DCHECK(rv == OK);
194         rv = DoVerifyCert(rv);
195         break;
196       case STATE_VERIFY_CERT_COMPLETE:
197         rv = DoVerifyCertComplete(rv);
198         break;
199       case STATE_NONE:
200       default:
201         rv = ERR_UNEXPECTED;
202         LOG(DFATAL) << "unexpected state " << state;
203         break;
204     }
205   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
206   return rv;
207 }
208
209 void ProofVerifierChromium::Job::OnIOComplete(int result) {
210   int rv = DoLoop(result);
211   if (rv != ERR_IO_PENDING) {
212     scoped_ptr<ProofVerifierCallback> callback(callback_.Pass());
213     // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
214     scoped_ptr<ProofVerifyDetails> verify_details(verify_details_.Pass());
215     callback->Run(rv == OK, error_details_, &verify_details);
216     // Will delete |this|.
217     proof_verifier_->OnJobComplete(this);
218   }
219 }
220
221 int ProofVerifierChromium::Job::DoVerifyCert(int result) {
222   next_state_ = STATE_VERIFY_CERT_COMPLETE;
223
224   int flags = 0;
225   return verifier_->Verify(
226       cert_.get(),
227       hostname_,
228       flags,
229       SSLConfigService::GetCRLSet().get(),
230       &verify_details_->cert_verify_result,
231       base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
232                  base::Unretained(this)),
233       net_log_);
234 }
235
236 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
237   verifier_.reset();
238
239   const CertVerifyResult& cert_verify_result =
240       verify_details_->cert_verify_result;
241   const CertStatus cert_status = cert_verify_result.cert_status;
242   if (transport_security_state_ &&
243       (result == OK ||
244        (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
245       !transport_security_state_->CheckPublicKeyPins(
246           hostname_,
247           cert_verify_result.is_issued_by_known_root,
248           cert_verify_result.public_key_hashes,
249           &verify_details_->pinning_failure_log)) {
250     result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
251   }
252
253   if (result != OK) {
254     std::string error_string = ErrorToString(result);
255     error_details_ = StringPrintf("Failed to verify certificate chain: %s",
256                                   error_string.c_str());
257     DLOG(WARNING) << error_details_;
258   }
259
260   // Exit DoLoop and return the result to the caller to VerifyProof.
261   DCHECK_EQ(STATE_NONE, next_state_);
262   return result;
263 }
264
265 bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
266                                                  const string& signature,
267                                                  const string& cert) {
268   StringPiece spki;
269   if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
270     DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
271     return false;
272   }
273
274   crypto::SignatureVerifier verifier;
275
276   size_t size_bits;
277   X509Certificate::PublicKeyType type;
278   X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
279                                     &type);
280   if (type == X509Certificate::kPublicKeyTypeRSA) {
281     crypto::SignatureVerifier::HashAlgorithm hash_alg =
282         crypto::SignatureVerifier::SHA256;
283     crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
284     unsigned int hash_len = 32;  // 32 is the length of a SHA-256 hash.
285
286     bool ok = verifier.VerifyInitRSAPSS(
287         hash_alg, mask_hash_alg, hash_len,
288         reinterpret_cast<const uint8*>(signature.data()), signature.size(),
289         reinterpret_cast<const uint8*>(spki.data()), spki.size());
290     if (!ok) {
291       DLOG(WARNING) << "VerifyInitRSAPSS failed";
292       return false;
293     }
294   } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
295     // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
296     // RFC 5758:
297     //   ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
298     //        us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
299     //   ...
300     //   When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
301     //   ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
302     //   as an AlgorithmIdentifier, the encoding MUST omit the parameters
303     //   field.  That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
304     //   component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
305     //   SHA384, or ecdsa-with-SHA512.
306     // See also RFC 5480, Appendix A.
307     static const uint8 kECDSAWithSHA256AlgorithmID[] = {
308       0x30, 0x0a,
309         0x06, 0x08,
310           0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
311     };
312
313     if (!verifier.VerifyInit(
314             kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
315             reinterpret_cast<const uint8*>(signature.data()),
316             signature.size(),
317             reinterpret_cast<const uint8*>(spki.data()),
318             spki.size())) {
319       DLOG(WARNING) << "VerifyInit failed";
320       return false;
321     }
322   } else {
323     LOG(ERROR) << "Unsupported public key type " << type;
324     return false;
325   }
326
327   verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
328                         sizeof(kProofSignatureLabel));
329   verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
330                         signed_data.size());
331
332   if (!verifier.VerifyFinal()) {
333     DLOG(WARNING) << "VerifyFinal failed";
334     return false;
335   }
336
337   DVLOG(1) << "VerifyFinal success";
338   return true;
339 }
340
341 ProofVerifierChromium::ProofVerifierChromium(
342     CertVerifier* cert_verifier,
343     TransportSecurityState* transport_security_state)
344     : cert_verifier_(cert_verifier),
345       transport_security_state_(transport_security_state) {
346 }
347
348 ProofVerifierChromium::~ProofVerifierChromium() {
349   STLDeleteElements(&active_jobs_);
350 }
351
352 QuicAsyncStatus ProofVerifierChromium::VerifyProof(
353     const std::string& hostname,
354     const std::string& server_config,
355     const std::vector<std::string>& certs,
356     const std::string& signature,
357     const ProofVerifyContext* verify_context,
358     std::string* error_details,
359     scoped_ptr<ProofVerifyDetails>* verify_details,
360     ProofVerifierCallback* callback) {
361   if (!verify_context) {
362     *error_details = "Missing context";
363     return QUIC_FAILURE;
364   }
365   const ProofVerifyContextChromium* chromium_context =
366       reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
367   scoped_ptr<Job> job(new Job(this,
368                               cert_verifier_,
369                               transport_security_state_,
370                               chromium_context->net_log));
371   QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs,
372                                             signature, error_details,
373                                             verify_details, callback);
374   if (status == QUIC_PENDING) {
375     active_jobs_.insert(job.release());
376   }
377   return status;
378 }
379
380 void ProofVerifierChromium::OnJobComplete(Job* job) {
381   active_jobs_.erase(job);
382   delete job;
383 }
384
385 }  // namespace net