summaryrefslogtreecommitdiff
path: root/chromium/net/ssl/server_bound_cert_service.h
blob: 0dc7f4ae39078186985f4fa797118f60fcedc4d8 (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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// 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_SSL_SERVER_BOUND_CERT_SERVICE_H_
#define NET_SSL_SERVER_BOUND_CERT_SERVICE_H_

#include <map>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/ssl/server_bound_cert_store.h"

namespace base {
class TaskRunner;
}

namespace net {

class ServerBoundCertServiceJob;
class ServerBoundCertServiceRequest;
class ServerBoundCertServiceWorker;

// A class for creating and fetching server bound certs. These certs are used
// to identify users' machines; their public keys are used as channel IDs in
// http://tools.ietf.org/html/draft-balfanz-tls-channelid-00.
// As a result although certs are set to be invalid after one year, we don't
// actually expire them. Once generated, certs are valid as long as the users
// want. Users can delete existing certs, and new certs will be generated
// automatically.

// Inherits from NonThreadSafe in order to use the function
// |CalledOnValidThread|.
class NET_EXPORT ServerBoundCertService
    : NON_EXPORTED_BASE(public base::NonThreadSafe) {
 public:
  class NET_EXPORT RequestHandle {
   public:
    RequestHandle();
    ~RequestHandle();

    // Cancel the request.  Does nothing if the request finished or was already
    // cancelled.
    void Cancel();

    bool is_active() const { return request_ != NULL; }

   private:
    friend class ServerBoundCertService;

    void RequestStarted(ServerBoundCertService* service,
                        ServerBoundCertServiceRequest* request,
                        const CompletionCallback& callback);

    void OnRequestComplete(int result);

    ServerBoundCertService* service_;
    ServerBoundCertServiceRequest* request_;
    CompletionCallback callback_;
  };

  // Password used on EncryptedPrivateKeyInfo data stored in EC private_key
  // values.  (This is not used to provide any security, but to workaround NSS
  // being unable to import unencrypted PrivateKeyInfo for EC keys.)
  static const char kEPKIPassword[];

  // This object owns |server_bound_cert_store|.  |task_runner| will
  // be used to post certificate generation worker tasks.  The tasks are
  // safe for use with WorkerPool and SequencedWorkerPool::CONTINUE_ON_SHUTDOWN.
  ServerBoundCertService(
      ServerBoundCertStore* server_bound_cert_store,
      const scoped_refptr<base::TaskRunner>& task_runner);

  ~ServerBoundCertService();

  // Returns the domain to be used for |host|.  The domain is the
  // "registry controlled domain", or the "ETLD + 1" where one exists, or
  // the origin otherwise.
  static std::string GetDomainForHost(const std::string& host);

  // Tests whether the system time is within the supported range for
  // certificate generation.  This value is cached when ServerBoundCertService
  // is created, so if the system time is changed by a huge amount, this may no
  // longer hold.
  bool IsSystemTimeValid() const { return is_system_time_valid_; }

  // Fetches the domain bound cert for the specified host if one exists and
  // creates one otherwise. Returns OK if successful or an error code upon
  // failure.
  //
  // On successful completion, |private_key| stores a DER-encoded
  // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
  // The PrivateKeyInfo is always an ECDSA private key.
  //
  // |callback| must not be null. ERR_IO_PENDING is returned if the operation
  // could not be completed immediately, in which case the result code will
  // be passed to the callback when available.
  //
  // |*out_req| will be initialized with a handle to the async request. This
  // RequestHandle object must be cancelled or destroyed before the
  // ServerBoundCertService is destroyed.
  int GetOrCreateDomainBoundCert(
      const std::string& host,
      std::string* private_key,
      std::string* cert,
      const CompletionCallback& callback,
      RequestHandle* out_req);

  // Fetches the domain bound cert for the specified host if one exists.
  // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error
  // code upon failure.
  //
  // On successful completion, |private_key| stores a DER-encoded
  // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
  // The PrivateKeyInfo is always an ECDSA private key.
  //
  // |callback| must not be null. ERR_IO_PENDING is returned if the operation
  // could not be completed immediately, in which case the result code will
  // be passed to the callback when available. If an in-flight
  // GetDomainBoundCert is pending, and a new GetOrCreateDomainBoundCert
  // request arrives for the same domain, the GetDomainBoundCert request will
  // not complete until a new cert is created.
  //
  // |*out_req| will be initialized with a handle to the async request. This
  // RequestHandle object must be cancelled or destroyed before the
  // ServerBoundCertService is destroyed.
  int GetDomainBoundCert(
      const std::string& host,
      std::string* private_key,
      std::string* cert,
      const CompletionCallback& callback,
      RequestHandle* out_req);

  // Returns the backing ServerBoundCertStore.
  ServerBoundCertStore* GetCertStore();

  // Public only for unit testing.
  int cert_count();
  uint64 requests() const { return requests_; }
  uint64 cert_store_hits() const { return cert_store_hits_; }
  uint64 inflight_joins() const { return inflight_joins_; }
  uint64 workers_created() const { return workers_created_; }

 private:
  // Cancels the specified request. |req| is the handle stored by
  // GetDomainBoundCert(). After a request is canceled, its completion
  // callback will not be called.
  void CancelRequest(ServerBoundCertServiceRequest* req);

  void GotServerBoundCert(int err,
                          const std::string& server_identifier,
                          base::Time expiration_time,
                          const std::string& key,
                          const std::string& cert);
  void GeneratedServerBoundCert(
      const std::string& server_identifier,
      int error,
      scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert);
  void HandleResult(int error,
                    const std::string& server_identifier,
                    const std::string& private_key,
                    const std::string& cert);

  // Searches for an in-flight request for the same domain. If found,
  // attaches to the request and returns true. Returns false if no in-flight
  // request is found.
  bool JoinToInFlightRequest(const base::TimeTicks& request_start,
                             const std::string& domain,
                             std::string* private_key,
                             std::string* cert,
                             bool create_if_missing,
                             const CompletionCallback& callback,
                             RequestHandle* out_req);

  // Looks for the domain bound cert for |domain| in this service's store.
  // Returns OK if it can be found synchronously, ERR_IO_PENDING if the
  // result cannot be obtained synchronously, or a network error code on
  // failure (including failure to find a domain-bound cert of |domain|).
  int LookupDomainBoundCert(const base::TimeTicks& request_start,
                            const std::string& domain,
                            std::string* private_key,
                            std::string* cert,
                            bool create_if_missing,
                            const CompletionCallback& callback,
                            RequestHandle* out_req);

  scoped_ptr<ServerBoundCertStore> server_bound_cert_store_;
  scoped_refptr<base::TaskRunner> task_runner_;

  // inflight_ maps from a server to an active generation which is taking
  // place.
  std::map<std::string, ServerBoundCertServiceJob*> inflight_;
  base::WeakPtrFactory<ServerBoundCertService> weak_ptr_factory_;

  uint64 requests_;
  uint64 cert_store_hits_;
  uint64 inflight_joins_;
  uint64 workers_created_;

  bool is_system_time_valid_;

  DISALLOW_COPY_AND_ASSIGN(ServerBoundCertService);
};

}  // namespace net

#endif  // NET_SSL_SERVER_BOUND_CERT_SERVICE_H_