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_manager {
33 namespace user_prefs {
34 class PrefRegistrySyncable;
39 class CryptohomeClient;
41 namespace attestation {
43 class AttestationFlow;
44 class PlatformVerificationFlowTest;
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",
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> {
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.
77 enum ConsentResponse {
78 CONSENT_RESPONSE_NONE,
79 CONSENT_RESPONSE_ALLOW,
80 CONSENT_RESPONSE_DENY,
83 // An interface which allows settings and UI to be abstracted for testing
84 // purposes. For normal operation the default implementation should be used.
87 virtual ~Delegate() {}
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;
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
97 virtual void ShowConsentPrompt(content::WebContents* web_contents,
98 const ConsentCallback& callback) = 0;
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;
104 // Gets the URL associated with the given |web_contents|.
105 virtual const GURL& GetURL(content::WebContents* web_contents) = 0;
107 // Gets the user associated with the given |web_contents|. NULL may be
109 virtual user_manager::User* GetUser(content::WebContents* web_contents) = 0;
111 // Gets the content settings map associated with the given |web_contents|.
112 virtual HostContentSettingsMap* GetContentSettings(
113 content::WebContents* web_contents) = 0;
115 // Returns true iff |web_contents| belongs to a guest or incognito session.
116 virtual bool IsGuestOrIncognito(content::WebContents* web_contents) = 0;
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)>
133 // A constructor that uses the default implementation of all dependencies
134 // including Delegate.
135 PlatformVerificationFlow();
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,
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
154 void ChallengePlatformKey(content::WebContents* web_contents,
155 const std::string& service_id,
156 const std::string& challenge,
157 const ChallengeCallback& callback);
159 static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* prefs);
161 void set_timeout_delay(const base::TimeDelta& timeout_delay) {
162 timeout_delay_ = timeout_delay;
166 friend class base::RefCountedThreadSafe<PlatformVerificationFlow>;
167 friend class PlatformVerificationFlowTest;
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);
178 content::WebContents* web_contents;
179 std::string service_id;
180 std::string challenge;
181 ChallengeCallback callback;
184 ~PlatformVerificationFlow();
186 // Checks whether the device has already been enrolled for attestation. The
187 // arguments to ChallengePlatformKey are in |context| and
188 // |attestation_prepared| specifies whether attestation has been prepared on
190 void CheckEnrollment(const ChallengeContext& context,
191 bool attestation_prepared);
193 // Checks whether we need to prompt the user for consent before proceeding and
194 // invokes the consent UI if so. The arguments to ChallengePlatformKey are
195 // in |context| and |attestation_enrolled| specifies whether attestation has
196 // been enrolled for this device.
197 void CheckConsent(const ChallengeContext& context,
198 bool attestation_enrolled);
200 // A callback called when the user has given their consent response. The
201 // arguments to ChallengePlatformKey are in |context|. |consent_required| and
202 // |consent_response| indicate whether consent was required and user response,
203 // respectively. If the response indicates that the operation should proceed,
204 // this method invokes a certificate request.
205 void OnConsentResponse(const ChallengeContext& context,
206 bool consent_required,
207 ConsentResponse consent_response);
209 // Initiates the flow to get a platform key certificate. The arguments to
210 // ChallengePlatformKey are in |context|. |user_id| identifies the user for
211 // which to get a certificate. If |force_new_key| is true then any existing
212 // key for the same user and service will be ignored and a new key will be
213 // generated and certified.
214 void GetCertificate(const ChallengeContext& context,
215 const std::string& user_id,
218 // A callback called when an attestation certificate request operation
219 // completes. The arguments to ChallengePlatformKey are in |context|.
220 // |user_id| identifies the user for which the certificate was requested.
221 // |operation_success| is true iff the certificate request operation
222 // succeeded. |certificate| holds the certificate for the platform key on
223 // success. If the certificate request was successful, this method invokes a
224 // request to sign the challenge. If the operation timed out prior to this
225 // method being called, this method does nothing - notably, the callback is
227 void OnCertificateReady(const ChallengeContext& context,
228 const std::string& user_id,
229 scoped_ptr<base::Timer> timer,
230 bool operation_success,
231 const std::string& certificate);
233 // A callback run after a constant delay to handle timeouts for lengthy
234 // certificate requests. |context.callback| will be invoked with a TIMEOUT
236 void OnCertificateTimeout(const ChallengeContext& context);
238 // A callback called when a challenge signing request has completed. The
239 // |certificate| is the platform certificate for the key which signed the
240 // |challenge|. The arguments to ChallengePlatformKey are in |context|.
241 // |operation_success| is true iff the challenge signing operation was
242 // successful. If it was successful, |response_data| holds the challenge
243 // response and the method will invoke |context.callback|.
244 void OnChallengeReady(const ChallengeContext& context,
245 const std::string& certificate,
246 bool operation_success,
247 const std::string& response_data);
249 // Checks whether policy or profile settings associated with |web_contents|
250 // have attestation for content protection explicitly disabled.
251 bool IsAttestationEnabled(content::WebContents* web_contents);
253 // Updates user settings for the profile associated with |web_contents| based
254 // on the |consent_response| to the request of type |consent_type|.
255 bool UpdateSettings(content::WebContents* web_contents,
256 ConsentResponse consent_response);
258 // Finds the domain-specific consent pref in |content_settings| for |url|. If
259 // a pref exists for the domain, returns true and sets |pref_value| if it is
261 bool GetDomainPref(HostContentSettingsMap* content_settings,
265 // Records the domain-specific consent pref in |content_settings| for |url|.
266 // The pref will be set to |allow_domain|.
267 void RecordDomainConsent(HostContentSettingsMap* content_settings,
271 // Returns true iff |certificate| is an expired X.509 certificate.
272 bool IsExpired(const std::string& certificate);
274 AttestationFlow* attestation_flow_;
275 scoped_ptr<AttestationFlow> default_attestation_flow_;
276 cryptohome::AsyncMethodCaller* async_caller_;
277 CryptohomeClient* cryptohome_client_;
279 scoped_ptr<Delegate> default_delegate_;
280 base::TimeDelta timeout_delay_;
282 DISALLOW_COPY_AND_ASSIGN(PlatformVerificationFlow);
285 } // namespace attestation
286 } // namespace chromeos
288 #endif // CHROME_BROWSER_CHROMEOS_ATTESTATION_PLATFORM_VERIFICATION_FLOW_H_