Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / net / quic / crypto / proof_verifier_chromium.cc
blob6b91d653dc938cc2d8debbad41d67263176d6796
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.
5 #include "net/quic/crypto/proof_verifier_chromium.h"
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_macros.h"
13 #include "base/profiler/scoped_tracker.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "crypto/signature_verifier.h"
17 #include "net/base/host_port_pair.h"
18 #include "net/base/net_errors.h"
19 #include "net/cert/asn1_util.h"
20 #include "net/cert/cert_policy_enforcer.h"
21 #include "net/cert/cert_status_flags.h"
22 #include "net/cert/cert_verifier.h"
23 #include "net/cert/cert_verify_result.h"
24 #include "net/cert/ct_verify_result.h"
25 #include "net/cert/x509_certificate.h"
26 #include "net/cert/x509_util.h"
27 #include "net/http/transport_security_state.h"
28 #include "net/log/net_log.h"
29 #include "net/quic/crypto/crypto_protocol.h"
30 #include "net/ssl/ssl_config_service.h"
32 using base::StringPiece;
33 using base::StringPrintf;
34 using std::string;
35 using std::vector;
37 namespace net {
39 ProofVerifyDetails* ProofVerifyDetailsChromium::Clone() const {
40 ProofVerifyDetailsChromium* other = new ProofVerifyDetailsChromium;
41 other->cert_verify_result = cert_verify_result;
42 return other;
45 // A Job handles the verification of a single proof. It is owned by the
46 // ProofVerifier. If the verification can not complete synchronously, it
47 // will notify the ProofVerifier upon completion.
48 class ProofVerifierChromium::Job {
49 public:
50 Job(ProofVerifierChromium* proof_verifier,
51 CertVerifier* cert_verifier,
52 CertPolicyEnforcer* cert_policy_enforcer,
53 TransportSecurityState* transport_security_state,
54 int cert_verify_flags,
55 const BoundNetLog& net_log);
57 // Starts the proof verification. If |QUIC_PENDING| is returned, then
58 // |callback| will be invoked asynchronously when the verification completes.
59 QuicAsyncStatus VerifyProof(const std::string& hostname,
60 const std::string& server_config,
61 const std::vector<std::string>& certs,
62 const std::string& signature,
63 std::string* error_details,
64 scoped_ptr<ProofVerifyDetails>* verify_details,
65 ProofVerifierCallback* callback);
67 private:
68 enum State {
69 STATE_NONE,
70 STATE_VERIFY_CERT,
71 STATE_VERIFY_CERT_COMPLETE,
74 int DoLoop(int last_io_result);
75 void OnIOComplete(int result);
76 int DoVerifyCert(int result);
77 int DoVerifyCertComplete(int result);
79 bool VerifySignature(const std::string& signed_data,
80 const std::string& signature,
81 const std::string& cert);
83 // Proof verifier to notify when this jobs completes.
84 ProofVerifierChromium* proof_verifier_;
86 // The underlying verifier used for verifying certificates.
87 CertVerifier* verifier_;
88 scoped_ptr<CertVerifier::Request> cert_verifier_request_;
90 CertPolicyEnforcer* policy_enforcer_;
92 TransportSecurityState* transport_security_state_;
94 // |hostname| specifies the hostname for which |certs| is a valid chain.
95 std::string hostname_;
97 scoped_ptr<ProofVerifierCallback> callback_;
98 scoped_ptr<ProofVerifyDetailsChromium> verify_details_;
99 std::string error_details_;
101 // X509Certificate from a chain of DER encoded certificates.
102 scoped_refptr<X509Certificate> cert_;
104 // |cert_verify_flags| is bitwise OR'd of CertVerifier::VerifyFlags and it is
105 // passed to CertVerifier::Verify.
106 int cert_verify_flags_;
108 State next_state_;
110 BoundNetLog net_log_;
112 DISALLOW_COPY_AND_ASSIGN(Job);
115 ProofVerifierChromium::Job::Job(
116 ProofVerifierChromium* proof_verifier,
117 CertVerifier* cert_verifier,
118 CertPolicyEnforcer* cert_policy_enforcer,
119 TransportSecurityState* transport_security_state,
120 int cert_verify_flags,
121 const BoundNetLog& net_log)
122 : proof_verifier_(proof_verifier),
123 verifier_(cert_verifier),
124 policy_enforcer_(cert_policy_enforcer),
125 transport_security_state_(transport_security_state),
126 cert_verify_flags_(cert_verify_flags),
127 next_state_(STATE_NONE),
128 net_log_(net_log) {}
130 QuicAsyncStatus ProofVerifierChromium::Job::VerifyProof(
131 const string& hostname,
132 const string& server_config,
133 const vector<string>& certs,
134 const string& signature,
135 std::string* error_details,
136 scoped_ptr<ProofVerifyDetails>* verify_details,
137 ProofVerifierCallback* callback) {
138 DCHECK(error_details);
139 DCHECK(verify_details);
140 DCHECK(callback);
142 error_details->clear();
144 if (STATE_NONE != next_state_) {
145 *error_details = "Certificate is already set and VerifyProof has begun";
146 DLOG(DFATAL) << *error_details;
147 return QUIC_FAILURE;
150 verify_details_.reset(new ProofVerifyDetailsChromium);
152 if (certs.empty()) {
153 *error_details = "Failed to create certificate chain. Certs are empty.";
154 DLOG(WARNING) << *error_details;
155 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
156 *verify_details = verify_details_.Pass();
157 return QUIC_FAILURE;
160 // Convert certs to X509Certificate.
161 vector<StringPiece> cert_pieces(certs.size());
162 for (unsigned i = 0; i < certs.size(); i++) {
163 cert_pieces[i] = base::StringPiece(certs[i]);
165 cert_ = X509Certificate::CreateFromDERCertChain(cert_pieces);
166 if (!cert_.get()) {
167 *error_details = "Failed to create certificate chain";
168 DLOG(WARNING) << *error_details;
169 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
170 *verify_details = verify_details_.Pass();
171 return QUIC_FAILURE;
174 // We call VerifySignature first to avoid copying of server_config and
175 // signature.
176 if (!VerifySignature(server_config, signature, certs[0])) {
177 *error_details = "Failed to verify signature of server config";
178 DLOG(WARNING) << *error_details;
179 verify_details_->cert_verify_result.cert_status = CERT_STATUS_INVALID;
180 *verify_details = verify_details_.Pass();
181 return QUIC_FAILURE;
184 hostname_ = hostname;
186 next_state_ = STATE_VERIFY_CERT;
187 switch (DoLoop(OK)) {
188 case OK:
189 *verify_details = verify_details_.Pass();
190 return QUIC_SUCCESS;
191 case ERR_IO_PENDING:
192 callback_.reset(callback);
193 return QUIC_PENDING;
194 default:
195 *error_details = error_details_;
196 *verify_details = verify_details_.Pass();
197 return QUIC_FAILURE;
201 int ProofVerifierChromium::Job::DoLoop(int last_result) {
202 int rv = last_result;
203 do {
204 State state = next_state_;
205 next_state_ = STATE_NONE;
206 switch (state) {
207 case STATE_VERIFY_CERT:
208 DCHECK(rv == OK);
209 rv = DoVerifyCert(rv);
210 break;
211 case STATE_VERIFY_CERT_COMPLETE:
212 rv = DoVerifyCertComplete(rv);
213 break;
214 case STATE_NONE:
215 default:
216 rv = ERR_UNEXPECTED;
217 LOG(DFATAL) << "unexpected state " << state;
218 break;
220 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
221 return rv;
224 void ProofVerifierChromium::Job::OnIOComplete(int result) {
225 int rv = DoLoop(result);
226 if (rv != ERR_IO_PENDING) {
227 scoped_ptr<ProofVerifierCallback> callback(callback_.Pass());
228 // Callback expects ProofVerifyDetails not ProofVerifyDetailsChromium.
229 scoped_ptr<ProofVerifyDetails> verify_details(verify_details_.Pass());
230 callback->Run(rv == OK, error_details_, &verify_details);
231 // Will delete |this|.
232 proof_verifier_->OnJobComplete(this);
236 int ProofVerifierChromium::Job::DoVerifyCert(int result) {
237 next_state_ = STATE_VERIFY_CERT_COMPLETE;
239 return verifier_->Verify(
240 cert_.get(), hostname_, std::string(), cert_verify_flags_,
241 SSLConfigService::GetCRLSet().get(), &verify_details_->cert_verify_result,
242 base::Bind(&ProofVerifierChromium::Job::OnIOComplete,
243 base::Unretained(this)),
244 &cert_verifier_request_, net_log_);
247 int ProofVerifierChromium::Job::DoVerifyCertComplete(int result) {
248 cert_verifier_request_.reset();
250 const CertVerifyResult& cert_verify_result =
251 verify_details_->cert_verify_result;
252 const CertStatus cert_status = cert_verify_result.cert_status;
253 if (result == OK && policy_enforcer_ &&
254 (cert_verify_result.cert_status & CERT_STATUS_IS_EV)) {
255 // QUIC does not support OCSP stapling or the CT TLS extension; as a
256 // result, CT can never be verified, thus the result is always empty.
257 ct::CTVerifyResult empty_ct_result;
258 if (!policy_enforcer_->DoesConformToCTEVPolicy(
259 cert_verify_result.verified_cert.get(),
260 SSLConfigService::GetEVCertsWhitelist().get(), empty_ct_result,
261 net_log_)) {
262 verify_details_->cert_verify_result.cert_status |=
263 CERT_STATUS_CT_COMPLIANCE_FAILED;
264 verify_details_->cert_verify_result.cert_status &= ~CERT_STATUS_IS_EV;
268 // TODO(estark): replace 0 below with the port of the connection.
269 if (transport_security_state_ &&
270 (result == OK ||
271 (IsCertificateError(result) && IsCertStatusMinorError(cert_status))) &&
272 !transport_security_state_->CheckPublicKeyPins(
273 HostPortPair(hostname_, 0),
274 cert_verify_result.is_issued_by_known_root,
275 cert_verify_result.public_key_hashes, cert_.get(),
276 cert_verify_result.verified_cert.get(),
277 TransportSecurityState::ENABLE_PIN_REPORTS,
278 &verify_details_->pinning_failure_log)) {
279 result = ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN;
282 if (result != OK) {
283 std::string error_string = ErrorToString(result);
284 error_details_ = StringPrintf("Failed to verify certificate chain: %s",
285 error_string.c_str());
286 DLOG(WARNING) << error_details_;
289 // Exit DoLoop and return the result to the caller to VerifyProof.
290 DCHECK_EQ(STATE_NONE, next_state_);
291 return result;
294 bool ProofVerifierChromium::Job::VerifySignature(const string& signed_data,
295 const string& signature,
296 const string& cert) {
297 // TODO(rtenneti): Remove ScopedTracker below once crbug.com/422516 is fixed.
298 tracked_objects::ScopedTracker tracking_profile(
299 FROM_HERE_WITH_EXPLICIT_FUNCTION(
300 "422516 ProofVerifierChromium::Job::VerifySignature"));
302 StringPiece spki;
303 if (!asn1::ExtractSPKIFromDERCert(cert, &spki)) {
304 DLOG(WARNING) << "ExtractSPKIFromDERCert failed";
305 return false;
308 crypto::SignatureVerifier verifier;
310 size_t size_bits;
311 X509Certificate::PublicKeyType type;
312 X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits,
313 &type);
314 if (type == X509Certificate::kPublicKeyTypeRSA) {
315 crypto::SignatureVerifier::HashAlgorithm hash_alg =
316 crypto::SignatureVerifier::SHA256;
317 crypto::SignatureVerifier::HashAlgorithm mask_hash_alg = hash_alg;
318 unsigned int hash_len = 32; // 32 is the length of a SHA-256 hash.
320 bool ok = verifier.VerifyInitRSAPSS(
321 hash_alg, mask_hash_alg, hash_len,
322 reinterpret_cast<const uint8*>(signature.data()), signature.size(),
323 reinterpret_cast<const uint8*>(spki.data()), spki.size());
324 if (!ok) {
325 DLOG(WARNING) << "VerifyInitRSAPSS failed";
326 return false;
328 } else if (type == X509Certificate::kPublicKeyTypeECDSA) {
329 // This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
330 // RFC 5758:
331 // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
332 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
333 // ...
334 // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
335 // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
336 // as an AlgorithmIdentifier, the encoding MUST omit the parameters
337 // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
338 // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
339 // SHA384, or ecdsa-with-SHA512.
340 // See also RFC 5480, Appendix A.
341 static const uint8 kECDSAWithSHA256AlgorithmID[] = {
342 0x30, 0x0a,
343 0x06, 0x08,
344 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
347 if (!verifier.VerifyInit(
348 kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
349 reinterpret_cast<const uint8*>(signature.data()),
350 signature.size(),
351 reinterpret_cast<const uint8*>(spki.data()),
352 spki.size())) {
353 DLOG(WARNING) << "VerifyInit failed";
354 return false;
356 } else {
357 LOG(ERROR) << "Unsupported public key type " << type;
358 return false;
361 verifier.VerifyUpdate(reinterpret_cast<const uint8*>(kProofSignatureLabel),
362 sizeof(kProofSignatureLabel));
363 verifier.VerifyUpdate(reinterpret_cast<const uint8*>(signed_data.data()),
364 signed_data.size());
366 if (!verifier.VerifyFinal()) {
367 DLOG(WARNING) << "VerifyFinal failed";
368 return false;
371 DVLOG(1) << "VerifyFinal success";
372 return true;
375 ProofVerifierChromium::ProofVerifierChromium(
376 CertVerifier* cert_verifier,
377 CertPolicyEnforcer* cert_policy_enforcer,
378 TransportSecurityState* transport_security_state)
379 : cert_verifier_(cert_verifier),
380 cert_policy_enforcer_(cert_policy_enforcer),
381 transport_security_state_(transport_security_state) {}
383 ProofVerifierChromium::~ProofVerifierChromium() {
384 STLDeleteElements(&active_jobs_);
387 QuicAsyncStatus ProofVerifierChromium::VerifyProof(
388 const std::string& hostname,
389 const std::string& server_config,
390 const std::vector<std::string>& certs,
391 const std::string& signature,
392 const ProofVerifyContext* verify_context,
393 std::string* error_details,
394 scoped_ptr<ProofVerifyDetails>* verify_details,
395 ProofVerifierCallback* callback) {
396 if (!verify_context) {
397 *error_details = "Missing context";
398 return QUIC_FAILURE;
400 const ProofVerifyContextChromium* chromium_context =
401 reinterpret_cast<const ProofVerifyContextChromium*>(verify_context);
402 scoped_ptr<Job> job(new Job(
403 this, cert_verifier_, cert_policy_enforcer_, transport_security_state_,
404 chromium_context->cert_verify_flags, chromium_context->net_log));
405 QuicAsyncStatus status =
406 job->VerifyProof(hostname, server_config, certs, signature, error_details,
407 verify_details, callback);
408 if (status == QUIC_PENDING) {
409 active_jobs_.insert(job.release());
411 return status;
414 void ProofVerifierChromium::OnJobComplete(Job* job) {
415 active_jobs_.erase(job);
416 delete job;
419 } // namespace net