Home | History | Annotate | Download | only in ssl
      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 
     21 namespace base {
     22 class TaskRunner;
     23 }
     24 
     25 namespace net {
     26 
     27 class ChannelIDServiceJob;
     28 class ChannelIDServiceRequest;
     29 class 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|.
     41 class 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