1// Copyright 2014 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_CHANNEL_ID_SERVICE_H_
6#define NET_SSL_CHANNEL_ID_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/channel_id_store.h"
20
21namespace base {
22class TaskRunner;
23}
24
25namespace net {
26
27class ChannelIDServiceJob;
28class ChannelIDServiceRequest;
29class ChannelIDServiceWorker;
30
31// A class for creating and fetching domain bound certs. They 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|.
41class NET_EXPORT ChannelIDService
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 ChannelIDService;
57
58    void RequestStarted(ChannelIDService* service,
59                        ChannelIDServiceRequest* request,
60                        const CompletionCallback& callback);
61
62    void OnRequestComplete(int result);
63
64    ChannelIDService* service_;
65    ChannelIDServiceRequest* 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 |channel_id_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  ChannelIDService(
78      ChannelIDStore* channel_id_store,
79      const scoped_refptr<base::TaskRunner>& task_runner);
80
81  ~ChannelIDService();
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 ChannelIDService
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  // ChannelIDService is destroyed.
109  int GetOrCreateChannelID(
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  // GetChannelID is pending, and a new GetOrCreateDomainBoundCert
128  // request arrives for the same domain, the GetChannelID 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  // ChannelIDService is destroyed.
134  int GetChannelID(
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 ChannelIDStore.
142  ChannelIDStore* GetChannelIDStore();
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  // GetChannelID(). After a request is canceled, its completion
154  // callback will not be called.
155  void CancelRequest(ChannelIDServiceRequest* req);
156
157  void GotChannelID(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 GeneratedChannelID(
163      const std::string& server_identifier,
164      int error,
165      scoped_ptr<ChannelIDStore::ChannelID> channel_id);
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 LookupChannelID(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<ChannelIDStore> channel_id_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, ChannelIDServiceJob*> 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<ChannelIDService> weak_ptr_factory_;
209
210  DISALLOW_COPY_AND_ASSIGN(ChannelIDService);
211};
212
213}  // namespace net
214
215#endif  // NET_SSL_CHANNEL_ID_SERVICE_H_
216