Home | History | Annotate | Download | only in attestation
      1 // Copyright 2013 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 CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
      6 #define CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
      7 
      8 #include <string>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/callback.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/time/time.h"
     15 #include "base/timer/timer.h"
     16 #include "url/gurl.h"
     17 
     18 class HostContentSettingsMap;
     19 class PrefService;
     20 
     21 namespace content {
     22 class WebContents;
     23 }
     24 
     25 namespace cryptohome {
     26 class AsyncMethodCaller;
     27 }
     28 
     29 namespace user_manager {
     30 class User;
     31 }
     32 
     33 namespace user_prefs {
     34 class PrefRegistrySyncable;
     35 }
     36 
     37 namespace chromeos {
     38 
     39 class CryptohomeClient;
     40 
     41 namespace attestation {
     42 
     43 class AttestationFlow;
     44 class PlatformVerificationFlowTest;
     45 
     46 // This class allows platform verification for the content protection use case.
     47 // All methods must only be called on the UI thread.  Example:
     48 //   scoped_refptr<PlatformVerificationFlow> verifier =
     49 //       new PlatformVerificationFlow();
     50 //   PlatformVerificationFlow::Callback callback = base::Bind(&MyCallback);
     51 //   verifier->ChallengePlatformKey(my_web_contents, "my_id", "some_challenge",
     52 //                                  callback);
     53 //
     54 // This class is RefCountedThreadSafe because it may need to outlive its caller.
     55 // The attestation flow that needs to happen to establish a certified platform
     56 // key may take minutes on some hardware.  This class will timeout after a much
     57 // shorter time so the caller can proceed without platform verification but it
     58 // is important that the pending operation be allowed to finish.  If the
     59 // attestation flow is aborted at any stage, it will need to start over.  If we
     60 // use weak pointers, the attestation flow will stop when the next callback is
     61 // run.  So we need the instance to stay alive until the platform key is fully
     62 // certified so the next time ChallegePlatformKey() is invoked it will be quick.
     63 class PlatformVerificationFlow
     64     : public base::RefCountedThreadSafe<PlatformVerificationFlow> {
     65  public:
     66   enum Result {
     67     SUCCESS,                // The operation succeeded.
     68     INTERNAL_ERROR,         // The operation failed unexpectedly.
     69     PLATFORM_NOT_VERIFIED,  // The platform cannot be verified.  For example:
     70                             // - It is not a Chrome device.
     71                             // - It is not running a verified OS image.
     72     USER_REJECTED,          // The user explicitly rejected the operation.
     73     POLICY_REJECTED,        // The operation is not allowed by policy/settings.
     74     TIMEOUT,                // The operation timed out.
     75   };
     76 
     77   enum ConsentResponse {
     78     CONSENT_RESPONSE_NONE,
     79     CONSENT_RESPONSE_ALLOW,
     80     CONSENT_RESPONSE_DENY,
     81   };
     82 
     83   // An interface which allows settings and UI to be abstracted for testing
     84   // purposes.  For normal operation the default implementation should be used.
     85   class Delegate {
     86    public:
     87     virtual ~Delegate() {}
     88 
     89     // This callback will be called when a user has given a |response| to a
     90     // consent request of the specified |type|.
     91     typedef base::Callback<void(ConsentResponse response)> ConsentCallback;
     92 
     93     // Invokes consent UI within the context of |web_contents| and calls
     94     // |callback| when the user responds.
     95     // Precondition: The last committed URL for |web_contents| has a valid
     96     //               origin.
     97     virtual void ShowConsentPrompt(content::WebContents* web_contents,
     98                                    const ConsentCallback& callback) = 0;
     99 
    100     // Gets prefs associated with the given |web_contents|.  If no prefs are
    101     // associated with |web_contents| then NULL is returned.
    102     virtual PrefService* GetPrefs(content::WebContents* web_contents) = 0;
    103 
    104     // Gets the URL associated with the given |web_contents|.
    105     virtual const GURL& GetURL(content::WebContents* web_contents) = 0;
    106 
    107     // Gets the user associated with the given |web_contents|.  NULL may be
    108     // returned.
    109     virtual user_manager::User* GetUser(content::WebContents* web_contents) = 0;
    110 
    111     // Gets the content settings map associated with the given |web_contents|.
    112     virtual HostContentSettingsMap* GetContentSettings(
    113         content::WebContents* web_contents) = 0;
    114 
    115     // Returns true iff |web_contents| belongs to a guest or incognito session.
    116     virtual bool IsGuestOrIncognito(content::WebContents* web_contents) = 0;
    117   };
    118 
    119   // This callback will be called when a challenge operation completes.  If
    120   // |result| is SUCCESS then |signed_data| holds the data which was signed
    121   // by the platform key (this is the original challenge appended with a random
    122   // nonce) and |signature| holds the RSA-PKCS1-v1.5 signature.  The
    123   // |platform_key_certificate| certifies the key used to generate the
    124   // signature.  This key may be generated on demand and is not guaranteed to
    125   // persist across multiple calls to this method.  The browser does not check
    126   // the validity of |signature| or |platform_key_certificate|.
    127   typedef base::Callback<void(Result result,
    128                               const std::string& signed_data,
    129                               const std::string& signature,
    130                               const std::string& platform_key_certificate)>
    131       ChallengeCallback;
    132 
    133   // A constructor that uses the default implementation of all dependencies
    134   // including Delegate.
    135   PlatformVerificationFlow();
    136 
    137   // An alternate constructor which specifies dependent objects explicitly.
    138   // This is useful in testing.  The caller retains ownership of all pointers.
    139   PlatformVerificationFlow(AttestationFlow* attestation_flow,
    140                            cryptohome::AsyncMethodCaller* async_caller,
    141                            CryptohomeClient* cryptohome_client,
    142                            Delegate* delegate);
    143 
    144   // Invokes an asynchronous operation to challenge a platform key.  Any user
    145   // interaction will be associated with |web_contents|.  The |service_id| is an
    146   // arbitrary value but it should uniquely identify the origin of the request
    147   // and should not be determined by that origin; its purpose is to prevent
    148   // collusion between multiple services.  The |challenge| is also an arbitrary
    149   // value but it should be time sensitive or associated to some kind of session
    150   // because its purpose is to prevent certificate replay.  The |callback| will
    151   // be called when the operation completes.  The duration of the operation can
    152   // vary depending on system state, hardware capabilities, and interaction with
    153   // the user.
    154   void ChallengePlatformKey(content::WebContents* web_contents,
    155                             const std::string& service_id,
    156                             const std::string& challenge,
    157                             const ChallengeCallback& callback);
    158 
    159   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
    160 
    161   void set_timeout_delay(const base::TimeDelta& timeout_delay) {
    162     timeout_delay_ = timeout_delay;
    163   }
    164 
    165  private:
    166   friend class base::RefCountedThreadSafe<PlatformVerificationFlow>;
    167   friend class PlatformVerificationFlowTest;
    168 
    169   // Holds the arguments of a ChallengePlatformKey call.  This is convenient for
    170   // use with base::Bind so we don't get too many arguments.
    171   struct ChallengeContext {
    172     ChallengeContext(content::WebContents* web_contents,
    173                      const std::string& service_id,
    174                      const std::string& challenge,
    175                      const ChallengeCallback& callback);
    176     ~ChallengeContext();
    177 
    178     content::WebContents* web_contents;
    179     std::string service_id;
    180     std::string challenge;
    181     ChallengeCallback callback;
    182   };
    183 
    184   ~PlatformVerificationFlow();
    185 
    186   // Checks whether we need to prompt the user for consent before proceeding and
    187   // invokes the consent UI if so.  The arguments to ChallengePlatformKey are
    188   // in |context| and |attestation_enrolled| specifies whether attestation has
    189   // been enrolled for this device.
    190   void CheckConsent(const ChallengeContext& context,
    191                     bool attestation_enrolled);
    192 
    193   // A callback called when the user has given their consent response.  The
    194   // arguments to ChallengePlatformKey are in |context|.  |consent_required| and
    195   // |consent_response| indicate whether consent was required and user response,
    196   // respectively.  If the response indicates that the operation should proceed,
    197   // this method invokes a certificate request.
    198   void OnConsentResponse(const ChallengeContext& context,
    199                          bool consent_required,
    200                          ConsentResponse consent_response);
    201 
    202   // Initiates the flow to get a platform key certificate.  The arguments to
    203   // ChallengePlatformKey are in |context|.  |user_id| identifies the user for
    204   // which to get a certificate.  If |force_new_key| is true then any existing
    205   // key for the same user and service will be ignored and a new key will be
    206   // generated and certified.
    207   void GetCertificate(const ChallengeContext& context,
    208                       const std::string& user_id,
    209                       bool force_new_key);
    210 
    211   // A callback called when an attestation certificate request operation
    212   // completes.  The arguments to ChallengePlatformKey are in |context|.
    213   // |user_id| identifies the user for which the certificate was requested.
    214   // |operation_success| is true iff the certificate request operation
    215   // succeeded.  |certificate| holds the certificate for the platform key on
    216   // success.  If the certificate request was successful, this method invokes a
    217   // request to sign the challenge.  If the operation timed out prior to this
    218   // method being called, this method does nothing - notably, the callback is
    219   // not invoked.
    220   void OnCertificateReady(const ChallengeContext& context,
    221                           const std::string& user_id,
    222                           scoped_ptr<base::Timer> timer,
    223                           bool operation_success,
    224                           const std::string& certificate);
    225 
    226   // A callback run after a constant delay to handle timeouts for lengthy
    227   // certificate requests.  |context.callback| will be invoked with a TIMEOUT
    228   // result.
    229   void OnCertificateTimeout(const ChallengeContext& context);
    230 
    231   // A callback called when a challenge signing request has completed.  The
    232   // |certificate| is the platform certificate for the key which signed the
    233   // |challenge|.  The arguments to ChallengePlatformKey are in |context|.
    234   // |operation_success| is true iff the challenge signing operation was
    235   // successful.  If it was successful, |response_data| holds the challenge
    236   // response and the method will invoke |context.callback|.
    237   void OnChallengeReady(const ChallengeContext& context,
    238                         const std::string& certificate,
    239                         bool operation_success,
    240                         const std::string& response_data);
    241 
    242   // Checks whether policy or profile settings associated with |web_contents|
    243   // have attestation for content protection explicitly disabled.
    244   bool IsAttestationEnabled(content::WebContents* web_contents);
    245 
    246   // Updates user settings for the profile associated with |web_contents| based
    247   // on the |consent_response| to the request of type |consent_type|.
    248   bool UpdateSettings(content::WebContents* web_contents,
    249                       ConsentResponse consent_response);
    250 
    251   // Finds the domain-specific consent pref in |content_settings| for |url|.  If
    252   // a pref exists for the domain, returns true and sets |pref_value| if it is
    253   // not NULL.
    254   bool GetDomainPref(HostContentSettingsMap* content_settings,
    255                      const GURL& url,
    256                      bool* pref_value);
    257 
    258   // Records the domain-specific consent pref in |content_settings| for |url|.
    259   // The pref will be set to |allow_domain|.
    260   void RecordDomainConsent(HostContentSettingsMap* content_settings,
    261                            const GURL& url,
    262                            bool allow_domain);
    263 
    264   // Returns true iff |certificate| is an expired X.509 certificate.
    265   bool IsExpired(const std::string& certificate);
    266 
    267   AttestationFlow* attestation_flow_;
    268   scoped_ptr<AttestationFlow> default_attestation_flow_;
    269   cryptohome::AsyncMethodCaller* async_caller_;
    270   CryptohomeClient* cryptohome_client_;
    271   Delegate* delegate_;
    272   scoped_ptr<Delegate> default_delegate_;
    273   base::TimeDelta timeout_delay_;
    274 
    275   DISALLOW_COPY_AND_ASSIGN(PlatformVerificationFlow);
    276 };
    277 
    278 }  // namespace attestation
    279 }  // namespace chromeos
    280 
    281 #endif  // CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_
    282