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