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