summaryrefslogtreecommitdiffstats
path: root/net/cert/multi_threaded_cert_verifier.h
blob: 83d00dd583e0bb0668e6706c0514f4b8e3704e5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_CERT_MULTI_THREADED_CERT_VERIFIER_H_
#define NET_CERT_MULTI_THREADED_CERT_VERIFIER_H_

#include <stddef.h>
#include <stdint.h>

#include <set>
#include <string>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/completion_callback.h"
#include "net/base/expiring_cache.h"
#include "net/base/hash_value.h"
#include "net/base/net_export.h"
#include "net/cert/cert_database.h"
#include "net/cert/cert_verifier.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/x509_cert_types.h"

namespace net {

class CertTrustAnchorProvider;
class CertVerifierJob;
class CertVerifierRequest;
class CertVerifierWorker;
class CertVerifyProc;

// MultiThreadedCertVerifier is a CertVerifier implementation that runs
// synchronous CertVerifier implementations on worker threads.
class NET_EXPORT_PRIVATE MultiThreadedCertVerifier
    : public CertVerifier,
      NON_EXPORTED_BASE(public base::NonThreadSafe),
      public CertDatabase::Observer {
 public:
  explicit MultiThreadedCertVerifier(CertVerifyProc* verify_proc);

  // When the verifier is destroyed, all certificate verifications requests are
  // canceled, and their completion callbacks will not be called.
  ~MultiThreadedCertVerifier() override;

  // Configures a source of additional certificates that should be treated as
  // trust anchors during verification, provided that the underlying
  // CertVerifyProc supports additional trust beyond the default implementation.
  // The CertTrustAnchorProvider will only be accessed on the same
  // thread that Verify() is called on; that is, it will not be
  // accessed from worker threads.
  // It must outlive the MultiThreadedCertVerifier.
  void SetCertTrustAnchorProvider(
      CertTrustAnchorProvider* trust_anchor_provider);

  // CertVerifier implementation
  int Verify(X509Certificate* cert,
             const std::string& hostname,
             const std::string& ocsp_response,
             int flags,
             CRLSet* crl_set,
             CertVerifyResult* verify_result,
             const CompletionCallback& callback,
             scoped_ptr<Request>* out_req,
             const BoundNetLog& net_log) override;

  bool SupportsOCSPStapling() override;

 private:
  struct JobToRequestParamsComparator;
  friend class CertVerifierRequest;
  friend class CertVerifierJob;
  friend class MultiThreadedCertVerifierTest;
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, CacheHit);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, DifferentCACerts);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, InflightJoin);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, MultipleInflightJoin);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest, CancelRequest);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest,
                           RequestParamsComparators);
  FRIEND_TEST_ALL_PREFIXES(MultiThreadedCertVerifierTest,
                           CertTrustAnchorProvider);

  // Input parameters of a certificate verification request.
  struct NET_EXPORT_PRIVATE RequestParams {
    RequestParams(const SHA1HashValue& cert_fingerprint_arg,
                  const SHA1HashValue& ca_fingerprint_arg,
                  const std::string& hostname_arg,
                  const std::string& ocsp_response_arg,
                  int flags_arg,
                  const CertificateList& additional_trust_anchors);
    RequestParams(const RequestParams& other);
    ~RequestParams();

    bool operator<(const RequestParams& other) const;

    std::string hostname;
    int flags;
    std::vector<SHA1HashValue> hash_values;
    // The time when verification started.
    // Note: This uses base::Time, rather than base::TimeTicks, to
    // account for system clock changes.
    base::Time start_time;
  };

  // CachedResult contains the result of a certificate verification.
  struct NET_EXPORT_PRIVATE CachedResult {
    CachedResult();
    ~CachedResult();

    int error;  // The return value of CertVerifier::Verify.
    CertVerifyResult result;  // The output of CertVerifier::Verify.
  };

  // Rather than having a single validity point along a monotonically increasing
  // timeline, certificate verification is based on falling within a range of
  // the certificate's NotBefore and NotAfter and based on what the current
  // system clock says (which may advance forwards or backwards as users correct
  // clock skew). CacheValidityPeriod and CacheExpirationFunctor are helpers to
  // ensure that expiration is measured both by the 'general' case (now + cache
  // TTL) and by whether or not significant enough clock skew was introduced
  // since the last verification.
  struct CacheValidityPeriod {
    explicit CacheValidityPeriod(const base::Time& now);
    CacheValidityPeriod(const base::Time& now, const base::Time& expiration);

    base::Time verification_time;
    base::Time expiration_time;
  };

  struct CacheExpirationFunctor {
    // Returns true iff |now| is within the validity period of |expiration|.
    bool operator()(const CacheValidityPeriod& now,
                    const CacheValidityPeriod& expiration) const;
  };

  struct JobComparator {
    bool operator()(const CertVerifierJob* job1,
                    const CertVerifierJob* job2) const;
  };

  using JobSet = std::set<CertVerifierJob*, JobComparator>;

  typedef ExpiringCache<RequestParams, CachedResult, CacheValidityPeriod,
                        CacheExpirationFunctor> CertVerifierCache;

  // Saves |result| into the cache, keyed by |key|.
  void SaveResultToCache(const RequestParams& key, const CachedResult& result);

  // CertDatabase::Observer methods:
  void OnCACertChanged(const X509Certificate* cert) override;

  // Returns an inflight job for |key|. If there is no such job then returns
  // null.
  CertVerifierJob* FindJob(const RequestParams& key);

  // Removes |job| from the inflight set, and passes ownership back to the
  // caller. |job| must already be |inflight_|.
  scoped_ptr<CertVerifierJob> RemoveJob(CertVerifierJob* job);

  // For unit testing.
  void ClearCache() { cache_.Clear(); }
  size_t GetCacheSize() const { return cache_.size(); }
  uint64_t cache_hits() const { return cache_hits_; }
  uint64_t requests() const { return requests_; }
  uint64_t inflight_joins() const { return inflight_joins_; }

  // cache_ maps from a request to a cached result.
  CertVerifierCache cache_;

  // inflight_ holds the jobs for which an active verification is taking place.
  JobSet inflight_;

  uint64_t requests_;
  uint64_t cache_hits_;
  uint64_t inflight_joins_;

  scoped_refptr<CertVerifyProc> verify_proc_;

  CertTrustAnchorProvider* trust_anchor_provider_;

  DISALLOW_COPY_AND_ASSIGN(MultiThreadedCertVerifier);
};

}  // namespace net

#endif  // NET_CERT_MULTI_THREADED_CERT_VERIFIER_H_