Upstream version 9.37.195.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 // A Job handles the verification of a single proof.  It is owned by the
37 // ProofVerifier. If the verification can not complete synchronously, it
38 // will notify the ProofVerifier upon completion.
39 class ProofVerifierChromium::Job {
40  public:
41   Job(ProofVerifierChromium* proof_verifier,
42       CertVerifier* cert_verifier,
43       TransportSecurityState* transport_security_state,
44       const BoundNetLog& net_log);
45
46   // Starts the proof verification.  If |QUIC_PENDING| is returned, then
47   // |callback| will be invoked asynchronously when the verification completes.
48   QuicAsyncStatus VerifyProof(const std::string& hostname,
49                               const std::string& server_config,
50                               const std::vector<std::string>& certs,
51                               const std::string& signature,
52                               std::string* error_details,
53                               scoped_ptr<ProofVerifyDetails>* verify_details,
54                               ProofVerifierCallback* callback);
55
56  private:
57   enum State {
58     STATE_NONE,
59     STATE_VERIFY_CERT,
60     STATE_VERIFY_CERT_COMPLETE,
61   };
62
63   int DoLoop(int last_io_result);
64   void OnIOComplete(int result);
65   int DoVerifyCert(int result);
66   int DoVerifyCertComplete(int result);
67
68   bool VerifySignature(const std::string& signed_data,
69                        const std::string& signature,
70                        const std::string& cert);
71
72   // Proof verifier to notify when this jobs completes.
73   ProofVerifierChromium* proof_verifier_;
74
75   // The underlying verifier used for verifying certificates.
76   scoped_ptr<SingleRequestCertVerifier> verifier_;
77
78   TransportSecurityState* transport_security_state_;
79
80   // |hostname| specifies the hostname for which |certs| is a valid chain.
81   std::string hostname_;
82
83   scoped_ptr<ProofVerifierCallback> callback_;
84   scoped_ptr<ProofVerifyDetailsChromium> verify_details_;
85   std::string error_details_;
86
87   // X509Certificate from a chain of DER encoded certificates.
88   scoped_refptr<X509Certificate> cert_;
89
90   State next_state_;
91
92   BoundNetLog net_log_;
93
94   DISALLOW_COPY_AND_ASSIGN(Job);
95 };
96
97 ProofVerifierChromium::Job::Job(
98     ProofVerifierChromium* proof_verifier,
99     CertVerifier* cert_verifier,
100     TransportSecurityState* transport_security_state,
101     const BoundNetLog& net_log)
102     : proof_verifier_(proof_verifier),
103       verifier_(new SingleRequestCertVerifier(cert_verifier)),
104       transport_security_state_(transport_security_state),
105       next_state_(STATE_NONE),
106       net_log_(net_log) {
107 }
108
109 QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
110     const string& hostname,
111     const string& server_config,
112     const vector<string>& certs,
113     const string& signature,
114     std::string* error_details,
115     scoped_ptr<ProofVerifyDetails>* verify_details,
116     ProofVerifierCallback* callback) {
117   DCHECK(error_details);
118   DCHECK(verify_details);
119   DCHECK(callback);
120
121   error_details->clear();
122
123   if (STATE_NONE != next_state_) {
124     *error_details = "Certificate is already set and VerifyProof has begun";
125     DLOG(DFATAL) << *error_details;
126     return QUIC_FAILURE;
127   }
128
129   verify_details_.reset(new ProofVerifyDetailsChromium);
130
131   if (certs.empty()) {
132     *error_details = "Failed to create certificate chain. Certs are empty.";
133     DLOG(WARNING) << *error_details;
134     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
135     verify_details->reset(verify_details_.release());
136     return QUIC_FAILURE;
137   }
138
139   // Convert certs to X509Certificate.
140   vector<StringPiece> cert_pieces(certs.size());
141   for (unsigned i = 0; i < certs.size(); i++) {
142     cert_pieces[i] = base::StringPiece(certs[i]);
143   }
144   cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
145   if (!cert_.get()) {
146     *error_details = "Failed to create certificate chain";
147     DLOG(WARNING) << *error_details;
148     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
149     verify_details->reset(verify_details_.release());
150     return QUIC_FAILURE;
151   }
152
153   // We call VerifySignature first to avoid copying of server_config and
154   // signature.
155   if (!VerifySignature(server_config, signature, certs[0])) {
156     *error_details = "Failed to verify signature of server config";
157     DLOG(WARNING) << *error_details;
158     verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
159     verify_details->reset(verify_details_.release());
160     return QUIC_FAILURE;
161   }
162
163   hostname_ = hostname;
164
165   next_state_ = STATE_VERIFY_CERT;
166   switch (DoLoop(OK)) {
167     case OK:
168       verify_details->reset(verify_details_.release());
169       return QUIC_SUCCESS;
170     case ERR_IO_PENDING:
171       callback_.reset(callback);
172       return QUIC_PENDING;
173     default:
174       *error_details = error_details_;
175       verify_details->reset(verify_details_.release());
176       return QUIC_FAILURE;
177   }
178 }
179
180 int ProofVerifierChromium::Job::DoLoop(int last_result) {
181   int rv = last_result;
182   do {
183     State state = next_state_;
184     next_state_ = STATE_NONE;
185     switch (state) {
186       case STATE_VERIFY_CERT:
187         DCHECK(rv == OK);
188         rv = DoVerifyCert(rv);
189         break;
190       case STATE_VERIFY_CERT_COMPLETE:
191         rv = DoVerifyCertComplete(rv);
192         break;
193       case STATE_NONE:
194       default:
195         rv = ERR_UNEXPECTED;
196         LOG(DFATAL) << "unexpected state " << state;
197         break;
198     }
199   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
200   return rv;
201 }
202
203 void ProofVerifierChromium::Job::OnIOComplete(int result) {
204   int rv = DoLoop(result);
205   if (rv != ERR_IO_PENDING) {
206     scoped_ptr<ProofVerifierCallback> callback(callback_.release());
207     // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
208     scoped_ptr<ProofVerifyDetails> verify_details(verify_details_.release());
209     callback->Run(rv == OK, error_details_, &verify_details);
210     // Will delete |this|.
211     proof_verifier_->OnJobComplete(this);
212   }
213 }
214
215 int ProofVerifierChromium::Job::DoVerifyCert(int result) {
216   next_state_ = STATE_VERIFY_CERT_COMPLETE;
217
218   int flags = 0;
219   return verifier_->Verify(
220       cert_.get(),
221       hostname_,
222       flags,
223       SSLConfigService::GetCRLSet().get(),
224       &verify_details_->cert_verify_result,
225       base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
226                  base::Unretained(this)),
227       net_log_);
228 }
229
230 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
231   verifier_.reset();
232
233 #if defined(OFFICIAL_BUILD) && !defined(OS_ANDROID) && !defined(OS_IOS)
234   // TODO(wtc): The following code was copied from ssl_client_socket_nss.cc.
235   // Convert it to a new function that can be called by both files. These
236   // variables simulate the arguments to the new function.
237   const CertVerifyResult& cert_verify_result =
238       verify_details_->cert_verify_result;
239   bool sni_available = true;
240   const std::string& host = hostname_;
241   TransportSecurityState* transport_security_state = transport_security_state_;
242   std::string* pinning_failure_log = &verify_details_->pinning_failure_log;
243
244   // Take care of any mandates for public key pinning.
245   //
246   // Pinning is only enabled for official builds to make sure that others don't
247   // end up with pins that cannot be easily updated.
248   //
249   // TODO(agl): We might have an issue here where a request for foo.example.com
250   // merges into a SPDY connection to www.example.com, and gets a different
251   // certificate.
252
253   // Perform pin validation if, and only if, all these conditions obtain:
254   //
255   // * a TransportSecurityState object is available;
256   // * the server's certificate chain is valid (or suffers from only a minor
257   //   error);
258   // * the server's certificate chain chains up to a known root (i.e. not a
259   //   user-installed trust anchor); and
260   // * the build is recent (very old builds should fail open so that users
261   //   have some chance to recover).
262   //
263   const CertStatus cert_status = cert_verify_result.cert_status;
264   if (transport_security_state &&
265       (result == OK ||
266        (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
267       cert_verify_result.is_issued_by_known_root &&
268       TransportSecurityState::IsBuildTimely()) {
269     if (transport_security_state->HasPublicKeyPins(host, sni_available)) {
270       if (!transport_security_state->CheckPublicKeyPins(
271               host,
272               sni_available,
273               cert_verify_result.public_key_hashes,
274               pinning_failure_log)) {
275         LOG(ERROR) << *pinning_failure_log;
276         result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
277         UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", false);
278         TransportSecurityState::ReportUMAOnPinFailure(host);
279       } else {
280         UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", true);
281       }
282     }
283   }
284 #endif
285
286   if (result <= ERR_FAILED) {
287     error_details_ = StringPrintf("Failed to verify certificate chain: %s",
288                                   ErrorToString(result));
289     DLOG(WARNING) << error_details_;
290     result = ERR_FAILED;
291   }
292
293   // Exit DoLoop and return the result to the caller to VerifyProof.
294   DCHECK_EQ(STATE_NONE, next_state_);
295   return result;
296 }
297
298 bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
299                                             const string& signature,
300                                             const string& cert) {
301   StringPiece spki;
302   if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
303     DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
304     return false;
305   }
306
307   crypto::SignatureVerifier verifier;
308
309   size_t size_bits;
310   X509Certificate::PublicKeyType type;
311   X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
312                                     &type);
313   if (type == X509Certificate::kPublicKeyTypeRSA) {
314     crypto::SignatureVerifier::HashAlgorithm hash_alg =
315         crypto::SignatureVerifier::SHA256;
316     crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
317     unsigned int hash_len = 32;  // 32 is the length of a SHA-256 hash.
318
319     bool ok = verifier.VerifyInitRSAPSS(
320         hash_alg, mask_hash_alg, hash_len,
321         reinterpret_cast<const uint8*>(signature.data()), signature.size(),
322         reinterpret_cast<const uint8*>(spki.data()), spki.size());
323     if (!ok) {
324       DLOG(WARNING) << "VerifyInitRSAPSS failed";
325       return false;
326     }
327   } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
328     // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
329     // RFC 5758:
330     //   ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
331     //        us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
332     //   ...
333     //   When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
334     //   ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
335     //   as an AlgorithmIdentifier, the encoding MUST omit the parameters
336     //   field.  That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
337     //   component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
338     //   SHA384, or ecdsa-with-SHA512.
339     // See also RFC 5480, Appendix A.
340     static const uint8 kECDSAWithSHA256AlgorithmID[] = {
341       0x30, 0x0a,
342         0x06, 0x08,
343           0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
344     };
345
346     if (!verifier.VerifyInit(
347             kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
348             reinterpret_cast<const uint8*>(signature.data()),
349             signature.size(),
350             reinterpret_cast<const uint8*>(spki.data()),
351             spki.size())) {
352       DLOG(WARNING) << "VerifyInit failed";
353       return false;
354     }
355   } else {
356     LOG(ERROR) << "Unsupported public key type " << type;
357     return false;
358   }
359
360   verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
361                         sizeof(kProofSignatureLabel));
362   verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
363                         signed_data.size());
364
365   if (!verifier.VerifyFinal()) {
366     DLOG(WARNING) << "VerifyFinal failed";
367     return false;
368   }
369
370   DVLOG(1) << "VerifyFinal success";
371   return true;
372 }
373
374 ProofVerifierChromium::ProofVerifierChromium(
375     CertVerifier* cert_verifier,
376     TransportSecurityState* transport_security_state)
377     : cert_verifier_(cert_verifier),
378       transport_security_state_(transport_security_state) {
379 }
380
381 ProofVerifierChromium::~ProofVerifierChromium() {
382   STLDeleteElements(&active_jobs_);
383 }
384
385 QuicAsyncStatus ProofVerifierChromium::VerifyProof(
386     const std::string& hostname,
387     const std::string& server_config,
388     const std::vector<std::string>& certs,
389     const std::string& signature,
390     const ProofVerifyContext* verify_context,
391     std::string* error_details,
392     scoped_ptr<ProofVerifyDetails>* verify_details,
393     ProofVerifierCallback* callback) {
394   if (!verify_context) {
395     *error_details = "Missing context";
396     return QUIC_FAILURE;
397   }
398   const ProofVerifyContextChromium* chromium_context =
399       reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
400   scoped_ptr<Job> job(new Job(this,
401                               cert_verifier_,
402                               transport_security_state_,
403                               chromium_context->net_log));
404   QuicAsyncStatus status = job->VerifyProof(hostname, server_config, certs,
405                                             signature, error_details,
406                                             verify_details, callback);
407   if (status == QUIC_PENDING) {
408     active_jobs_.insert(job.release());
409   }
410   return status;
411 }
412
413 void ProofVerifierChromium::OnJobComplete(Job* job) {
414   active_jobs_.erase(job);
415   delete job;
416 }
417
418 }  // namespace net