• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 #ifndef NET_SSL_SERVER_BOUND_CERT_SERVICE_H_
6 #define NET_SSL_SERVER_BOUND_CERT_SERVICE_H_
7 
8 #include <map>
9 #include <string>
10 #include <vector>
11 
12 #include "base/basictypes.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/threading/non_thread_safe.h"
16 #include "base/time/time.h"
17 #include "net/base/completion_callback.h"
18 #include "net/base/net_export.h"
19 #include "net/ssl/server_bound_cert_store.h"
20 
21 namespace base {
22 class TaskRunner;
23 }
24 
25 namespace net {
26 
27 class ServerBoundCertServiceJob;
28 class ServerBoundCertServiceRequest;
29 class ServerBoundCertServiceWorker;
30 
31 // A class for creating and fetching server bound certs. These certs are used
32 // to identify users' machines; their public keys are used as channel IDs in
33 // http://tools.ietf.org/html/draft-balfanz-tls-channelid-00.
34 // As a result although certs are set to be invalid after one year, we don't
35 // actually expire them. Once generated, certs are valid as long as the users
36 // want. Users can delete existing certs, and new certs will be generated
37 // automatically.
38 
39 // Inherits from NonThreadSafe in order to use the function
40 // |CalledOnValidThread|.
41 class NET_EXPORT ServerBoundCertService
NON_EXPORTED_BASE(public base::NonThreadSafe)42     : NON_EXPORTED_BASE(public base::NonThreadSafe) {
43  public:
44   class NET_EXPORT RequestHandle {
45    public:
46     RequestHandle();
47     ~RequestHandle();
48 
49     // Cancel the request.  Does nothing if the request finished or was already
50     // cancelled.
51     void Cancel();
52 
53     bool is_active() const { return request_ != NULL; }
54 
55    private:
56     friend class ServerBoundCertService;
57 
58     void RequestStarted(ServerBoundCertService* service,
59                         ServerBoundCertServiceRequest* request,
60                         const CompletionCallback& callback);
61 
62     void OnRequestComplete(int result);
63 
64     ServerBoundCertService* service_;
65     ServerBoundCertServiceRequest* request_;
66     CompletionCallback callback_;
67   };
68 
69   // Password used on EncryptedPrivateKeyInfo data stored in EC private_key
70   // values.  (This is not used to provide any security, but to workaround NSS
71   // being unable to import unencrypted PrivateKeyInfo for EC keys.)
72   static const char kEPKIPassword[];
73 
74   // This object owns |server_bound_cert_store|.  |task_runner| will
75   // be used to post certificate generation worker tasks.  The tasks are
76   // safe for use with WorkerPool and SequencedWorkerPool::CONTINUE_ON_SHUTDOWN.
77   ServerBoundCertService(
78       ServerBoundCertStore* server_bound_cert_store,
79       const scoped_refptr<base::TaskRunner>& task_runner);
80 
81   ~ServerBoundCertService();
82 
83   // Returns the domain to be used for |host|.  The domain is the
84   // "registry controlled domain", or the "ETLD + 1" where one exists, or
85   // the origin otherwise.
86   static std::string GetDomainForHost(const std::string& host);
87 
88   // Tests whether the system time is within the supported range for
89   // certificate generation.  This value is cached when ServerBoundCertService
90   // is created, so if the system time is changed by a huge amount, this may no
91   // longer hold.
92   bool IsSystemTimeValid() const { return is_system_time_valid_; }
93 
94   // Fetches the domain bound cert for the specified host if one exists and
95   // creates one otherwise. Returns OK if successful or an error code upon
96   // failure.
97   //
98   // On successful completion, |private_key| stores a DER-encoded
99   // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
100   // The PrivateKeyInfo is always an ECDSA private key.
101   //
102   // |callback| must not be null. ERR_IO_PENDING is returned if the operation
103   // could not be completed immediately, in which case the result code will
104   // be passed to the callback when available.
105   //
106   // |*out_req| will be initialized with a handle to the async request. This
107   // RequestHandle object must be cancelled or destroyed before the
108   // ServerBoundCertService is destroyed.
109   int GetOrCreateDomainBoundCert(
110       const std::string& host,
111       std::string* private_key,
112       std::string* cert,
113       const CompletionCallback& callback,
114       RequestHandle* out_req);
115 
116   // Fetches the domain bound cert for the specified host if one exists.
117   // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error
118   // code upon failure.
119   //
120   // On successful completion, |private_key| stores a DER-encoded
121   // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
122   // The PrivateKeyInfo is always an ECDSA private key.
123   //
124   // |callback| must not be null. ERR_IO_PENDING is returned if the operation
125   // could not be completed immediately, in which case the result code will
126   // be passed to the callback when available. If an in-flight
127   // GetDomainBoundCert is pending, and a new GetOrCreateDomainBoundCert
128   // request arrives for the same domain, the GetDomainBoundCert request will
129   // not complete until a new cert is created.
130   //
131   // |*out_req| will be initialized with a handle to the async request. This
132   // RequestHandle object must be cancelled or destroyed before the
133   // ServerBoundCertService is destroyed.
134   int GetDomainBoundCert(
135       const std::string& host,
136       std::string* private_key,
137       std::string* cert,
138       const CompletionCallback& callback,
139       RequestHandle* out_req);
140 
141   // Returns the backing ServerBoundCertStore.
142   ServerBoundCertStore* GetCertStore();
143 
144   // Public only for unit testing.
145   int cert_count();
146   uint64 requests() const { return requests_; }
147   uint64 cert_store_hits() const { return cert_store_hits_; }
148   uint64 inflight_joins() const { return inflight_joins_; }
149   uint64 workers_created() const { return workers_created_; }
150 
151  private:
152   // Cancels the specified request. |req| is the handle stored by
153   // GetDomainBoundCert(). After a request is canceled, its completion
154   // callback will not be called.
155   void CancelRequest(ServerBoundCertServiceRequest* req);
156 
157   void GotServerBoundCert(int err,
158                           const std::string& server_identifier,
159                           base::Time expiration_time,
160                           const std::string& key,
161                           const std::string& cert);
162   void GeneratedServerBoundCert(
163       const std::string& server_identifier,
164       int error,
165       scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert);
166   void HandleResult(int error,
167                     const std::string& server_identifier,
168                     const std::string& private_key,
169                     const std::string& cert);
170 
171   // Searches for an in-flight request for the same domain. If found,
172   // attaches to the request and returns true. Returns false if no in-flight
173   // request is found.
174   bool JoinToInFlightRequest(const base::TimeTicks& request_start,
175                              const std::string& domain,
176                              std::string* private_key,
177                              std::string* cert,
178                              bool create_if_missing,
179                              const CompletionCallback& callback,
180                              RequestHandle* out_req);
181 
182   // Looks for the domain bound cert for |domain| in this service's store.
183   // Returns OK if it can be found synchronously, ERR_IO_PENDING if the
184   // result cannot be obtained synchronously, or a network error code on
185   // failure (including failure to find a domain-bound cert of |domain|).
186   int LookupDomainBoundCert(const base::TimeTicks& request_start,
187                             const std::string& domain,
188                             std::string* private_key,
189                             std::string* cert,
190                             bool create_if_missing,
191                             const CompletionCallback& callback,
192                             RequestHandle* out_req);
193 
194   scoped_ptr<ServerBoundCertStore> server_bound_cert_store_;
195   scoped_refptr<base::TaskRunner> task_runner_;
196 
197   // inflight_ maps from a server to an active generation which is taking
198   // place.
199   std::map<std::string, ServerBoundCertServiceJob*> inflight_;
200 
201   uint64 requests_;
202   uint64 cert_store_hits_;
203   uint64 inflight_joins_;
204   uint64 workers_created_;
205 
206   bool is_system_time_valid_;
207 
208   base::WeakPtrFactory<ServerBoundCertService> weak_ptr_factory_;
209 
210   DISALLOW_COPY_AND_ASSIGN(ServerBoundCertService);
211 };
212 
213 }  // namespace net
214 
215 #endif  // NET_SSL_SERVER_BOUND_CERT_SERVICE_H_
216