Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: chrome/browser/chromeos/attestation/platform_verification_flow.cc

Issue 50093002: Added a timeout for platform verification key generation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: use base::Timer Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "platform_verification_flow.h" 5 #include "platform_verification_flow.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
9 #include "base/prefs/pref_service.h" 10 #include "base/prefs/pref_service.h"
11 #include "base/time/time.h"
12 #include "base/timer/timer.h"
10 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" 13 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
11 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h" 14 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
12 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h" 15 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
13 #include "chrome/browser/chromeos/login/user.h" 16 #include "chrome/browser/chromeos/login/user.h"
14 #include "chrome/browser/chromeos/login/user_manager.h" 17 #include "chrome/browser/chromeos/login/user_manager.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h" 18 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/prefs/scoped_user_pref_update.h" 19 #include "chrome/browser/prefs/scoped_user_pref_update.h"
17 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/pref_names.h" 21 #include "chrome/common/pref_names.h"
19 #include "chromeos/attestation/attestation_flow.h" 22 #include "chromeos/attestation/attestation_flow.h"
20 #include "chromeos/cryptohome/async_method_caller.h" 23 #include "chromeos/cryptohome/async_method_caller.h"
21 #include "chromeos/dbus/cryptohome_client.h" 24 #include "chromeos/dbus/cryptohome_client.h"
22 #include "chromeos/dbus/dbus_thread_manager.h" 25 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "components/user_prefs/pref_registry_syncable.h" 26 #include "components/user_prefs/pref_registry_syncable.h"
24 #include "components/user_prefs/user_prefs.h" 27 #include "components/user_prefs/user_prefs.h"
25 #include "content/public/browser/browser_context.h" 28 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/user_metrics.h" 30 #include "content/public/browser/user_metrics.h"
28 #include "content/public/browser/web_contents.h" 31 #include "content/public/browser/web_contents.h"
29 32
30 namespace { 33 namespace {
31 34
35 const int kTimeoutInSeconds = 8;
36
32 // A callback method to handle DBus errors. 37 // A callback method to handle DBus errors.
33 void DBusCallback(const base::Callback<void(bool)>& on_success, 38 void DBusCallback(const base::Callback<void(bool)>& on_success,
34 const base::Closure& on_failure, 39 const base::Closure& on_failure,
35 chromeos::DBusMethodCallStatus call_status, 40 chromeos::DBusMethodCallStatus call_status,
36 bool result) { 41 bool result) {
37 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) { 42 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) {
38 on_success.Run(result); 43 on_success.Run(result);
39 } else { 44 } else {
40 LOG(ERROR) << "PlatformVerificationFlow: DBus call failed!"; 45 LOG(ERROR) << "PlatformVerificationFlow: DBus call failed!";
41 on_failure.Run(); 46 on_failure.Run();
(...skipping 30 matching lines...) Expand all
72 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate); 77 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
73 }; 78 };
74 79
75 PlatformVerificationFlow::PlatformVerificationFlow() 80 PlatformVerificationFlow::PlatformVerificationFlow()
76 : attestation_flow_(NULL), 81 : attestation_flow_(NULL),
77 async_caller_(cryptohome::AsyncMethodCaller::GetInstance()), 82 async_caller_(cryptohome::AsyncMethodCaller::GetInstance()),
78 cryptohome_client_(DBusThreadManager::Get()->GetCryptohomeClient()), 83 cryptohome_client_(DBusThreadManager::Get()->GetCryptohomeClient()),
79 user_manager_(UserManager::Get()), 84 user_manager_(UserManager::Get()),
80 delegate_(NULL), 85 delegate_(NULL),
81 testing_prefs_(NULL), 86 testing_prefs_(NULL),
82 weak_factory_(this) { 87 timeout_delay_(base::TimeDelta::FromSeconds(kTimeoutInSeconds)) {
83 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 88 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
84 scoped_ptr<ServerProxy> attestation_ca_client(new AttestationCAClient()); 89 scoped_ptr<ServerProxy> attestation_ca_client(new AttestationCAClient());
85 default_attestation_flow_.reset(new AttestationFlow( 90 default_attestation_flow_.reset(new AttestationFlow(
86 async_caller_, 91 async_caller_,
87 cryptohome_client_, 92 cryptohome_client_,
88 attestation_ca_client.Pass())); 93 attestation_ca_client.Pass()));
89 attestation_flow_ = default_attestation_flow_.get(); 94 attestation_flow_ = default_attestation_flow_.get();
90 default_delegate_.reset(new DefaultDelegate()); 95 default_delegate_.reset(new DefaultDelegate());
91 delegate_ = default_delegate_.get(); 96 delegate_ = default_delegate_.get();
92 } 97 }
93 98
94 PlatformVerificationFlow::PlatformVerificationFlow( 99 PlatformVerificationFlow::PlatformVerificationFlow(
95 AttestationFlow* attestation_flow, 100 AttestationFlow* attestation_flow,
96 cryptohome::AsyncMethodCaller* async_caller, 101 cryptohome::AsyncMethodCaller* async_caller,
97 CryptohomeClient* cryptohome_client, 102 CryptohomeClient* cryptohome_client,
98 UserManager* user_manager, 103 UserManager* user_manager,
99 Delegate* delegate) 104 Delegate* delegate)
100 : attestation_flow_(attestation_flow), 105 : attestation_flow_(attestation_flow),
101 async_caller_(async_caller), 106 async_caller_(async_caller),
102 cryptohome_client_(cryptohome_client), 107 cryptohome_client_(cryptohome_client),
103 user_manager_(user_manager), 108 user_manager_(user_manager),
104 delegate_(delegate), 109 delegate_(delegate),
105 testing_prefs_(NULL), 110 testing_prefs_(NULL),
106 weak_factory_(this) { 111 timeout_delay_(base::TimeDelta::FromSeconds(kTimeoutInSeconds)) {
107 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 112 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
108 } 113 }
109 114
110 PlatformVerificationFlow::~PlatformVerificationFlow() { 115 PlatformVerificationFlow::~PlatformVerificationFlow() {
111 } 116 }
112 117
113 void PlatformVerificationFlow::ChallengePlatformKey( 118 void PlatformVerificationFlow::ChallengePlatformKey(
114 content::WebContents* web_contents, 119 content::WebContents* web_contents,
115 const std::string& service_id, 120 const std::string& service_id,
116 const std::string& challenge, 121 const std::string& challenge,
117 const ChallengeCallback& callback) { 122 const ChallengeCallback& callback) {
118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
119 if (!IsAttestationEnabled(web_contents)) { 124 if (!IsAttestationEnabled(web_contents)) {
120 LOG(INFO) << "PlatformVerificationFlow: Feature disabled."; 125 LOG(INFO) << "PlatformVerificationFlow: Feature disabled.";
121 ReportError(callback, POLICY_REJECTED); 126 ReportError(callback, POLICY_REJECTED);
122 return; 127 return;
123 } 128 }
129 ChallengeContext context = {web_contents, service_id, challenge, callback};
124 BoolDBusMethodCallback dbus_callback = base::Bind( 130 BoolDBusMethodCallback dbus_callback = base::Bind(
125 &DBusCallback, 131 &DBusCallback,
126 base::Bind(&PlatformVerificationFlow::CheckConsent, 132 base::Bind(&PlatformVerificationFlow::CheckConsent, this, context),
127 weak_factory_.GetWeakPtr(),
128 web_contents,
129 service_id,
130 challenge,
131 callback),
132 base::Bind(&ReportError, callback, INTERNAL_ERROR)); 133 base::Bind(&ReportError, callback, INTERNAL_ERROR));
133 cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback); 134 cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback);
134 } 135 }
135 136
136 void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents, 137 void PlatformVerificationFlow::CheckConsent(const ChallengeContext& context,
137 const std::string& service_id,
138 const std::string& challenge,
139 const ChallengeCallback& callback,
140 bool attestation_enrolled) { 138 bool attestation_enrolled) {
141 ConsentType consent_type = CONSENT_TYPE_NONE; 139 ConsentType consent_type = CONSENT_TYPE_NONE;
142 if (!attestation_enrolled || IsFirstUse(web_contents)) { 140 if (!attestation_enrolled || IsFirstUse(context.web_contents)) {
143 consent_type = CONSENT_TYPE_ATTESTATION; 141 consent_type = CONSENT_TYPE_ATTESTATION;
144 } else if (IsAlwaysAskRequired(web_contents)) { 142 } else if (IsAlwaysAskRequired(context.web_contents)) {
145 consent_type = CONSENT_TYPE_ALWAYS; 143 consent_type = CONSENT_TYPE_ALWAYS;
146 } 144 }
147 Delegate::ConsentCallback consent_callback = base::Bind( 145 Delegate::ConsentCallback consent_callback = base::Bind(
148 &PlatformVerificationFlow::OnConsentResponse, 146 &PlatformVerificationFlow::OnConsentResponse,
149 weak_factory_.GetWeakPtr(), 147 this,
150 web_contents, 148 context,
151 service_id,
152 challenge,
153 callback,
154 consent_type); 149 consent_type);
155 if (consent_type == CONSENT_TYPE_NONE) { 150 if (consent_type == CONSENT_TYPE_NONE) {
156 consent_callback.Run(CONSENT_RESPONSE_NONE); 151 consent_callback.Run(CONSENT_RESPONSE_NONE);
157 } else { 152 } else {
158 delegate_->ShowConsentPrompt(consent_type, 153 delegate_->ShowConsentPrompt(consent_type,
159 web_contents, 154 context.web_contents,
160 consent_callback); 155 consent_callback);
161 } 156 }
162 } 157 }
163 158
164 void PlatformVerificationFlow::RegisterProfilePrefs( 159 void PlatformVerificationFlow::RegisterProfilePrefs(
165 user_prefs::PrefRegistrySyncable* prefs) { 160 user_prefs::PrefRegistrySyncable* prefs) {
166 prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime, 161 prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime,
167 false, 162 false,
168 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 163 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
169 prefs->RegisterDictionaryPref( 164 prefs->RegisterDictionaryPref(
170 prefs::kRAConsentDomains, 165 prefs::kRAConsentDomains,
171 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 166 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
172 prefs->RegisterBooleanPref(prefs::kRAConsentAlways, 167 prefs->RegisterBooleanPref(prefs::kRAConsentAlways,
173 false, 168 false,
174 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 169 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
175 } 170 }
176 171
177 void PlatformVerificationFlow::OnConsentResponse( 172 void PlatformVerificationFlow::OnConsentResponse(
178 content::WebContents* web_contents, 173 const ChallengeContext& context,
179 const std::string& service_id,
180 const std::string& challenge,
181 const ChallengeCallback& callback,
182 ConsentType consent_type, 174 ConsentType consent_type,
183 ConsentResponse consent_response) { 175 ConsentResponse consent_response) {
184 if (consent_type != CONSENT_TYPE_NONE) { 176 if (consent_type != CONSENT_TYPE_NONE) {
185 if (consent_response == CONSENT_RESPONSE_NONE) { 177 if (consent_response == CONSENT_RESPONSE_NONE) {
186 // No user response - do not proceed and do not modify any settings. 178 // No user response - do not proceed and do not modify any settings.
187 LOG(WARNING) << "PlatformVerificationFlow: No response from user."; 179 LOG(WARNING) << "PlatformVerificationFlow: No response from user.";
188 ReportError(callback, USER_REJECTED); 180 ReportError(context.callback, USER_REJECTED);
189 return; 181 return;
190 } 182 }
191 if (!UpdateSettings(web_contents, consent_type, consent_response)) { 183 if (!UpdateSettings(context.web_contents, consent_type, consent_response)) {
192 ReportError(callback, INTERNAL_ERROR); 184 ReportError(context.callback, INTERNAL_ERROR);
193 return; 185 return;
194 } 186 }
195 if (consent_response == CONSENT_RESPONSE_DENY) { 187 if (consent_response == CONSENT_RESPONSE_DENY) {
196 LOG(INFO) << "PlatformVerificationFlow: User rejected request."; 188 LOG(INFO) << "PlatformVerificationFlow: User rejected request.";
197 content::RecordAction( 189 content::RecordAction(
198 content::UserMetricsAction("PlatformVerificationRejected")); 190 content::UserMetricsAction("PlatformVerificationRejected"));
199 ReportError(callback, USER_REJECTED); 191 ReportError(context.callback, USER_REJECTED);
200 return; 192 return;
201 } else if (consent_response == CONSENT_RESPONSE_ALLOW) { 193 } else if (consent_response == CONSENT_RESPONSE_ALLOW) {
202 content::RecordAction( 194 content::RecordAction(
203 content::UserMetricsAction("PlatformVerificationAccepted")); 195 content::UserMetricsAction("PlatformVerificationAccepted"));
204 } 196 }
205 } 197 }
206 198
207 // At this point all user interaction is complete and we can proceed with the 199 // At this point all user interaction is complete and we can proceed with the
208 // certificate request. 200 // certificate request.
209 chromeos::User* user = GetUser(web_contents); 201 chromeos::User* user = GetUser(context.web_contents);
210 if (!user) { 202 if (!user) {
211 ReportError(callback, INTERNAL_ERROR); 203 ReportError(context.callback, INTERNAL_ERROR);
212 LOG(ERROR) << "Profile does not map to a valid user."; 204 LOG(ERROR) << "Profile does not map to a valid user.";
213 return; 205 return;
214 } 206 }
207
208 scoped_ptr<base::Timer> timer(new base::Timer(false, // Don't retain.
DaleCurtis 2013/10/30 22:53:17 Timer(false, false) is just OneShotTimer(). Why t
209 false)); // Don't repeat.
210 base::Closure timeout_callback = base::Bind(
211 &PlatformVerificationFlow::OnCertificateTimeout,
212 this,
213 context);
214 timer->Start(FROM_HERE, timeout_delay_, timeout_callback);
215
215 AttestationFlow::CertificateCallback certificate_callback = base::Bind( 216 AttestationFlow::CertificateCallback certificate_callback = base::Bind(
216 &PlatformVerificationFlow::OnCertificateReady, 217 &PlatformVerificationFlow::OnCertificateReady,
217 weak_factory_.GetWeakPtr(), 218 this,
219 context,
218 user->email(), 220 user->email(),
219 service_id, 221 base::Passed(&timer));
220 challenge,
221 callback);
222 attestation_flow_->GetCertificate( 222 attestation_flow_->GetCertificate(
223 PROFILE_CONTENT_PROTECTION_CERTIFICATE, 223 PROFILE_CONTENT_PROTECTION_CERTIFICATE,
224 user->email(), 224 user->email(),
225 service_id, 225 context.service_id,
226 false, // Don't force a new key. 226 false, // Don't force a new key.
227 certificate_callback); 227 certificate_callback);
228 } 228 }
229 229
230 void PlatformVerificationFlow::OnCertificateReady( 230 void PlatformVerificationFlow::OnCertificateReady(
231 const ChallengeContext& context,
231 const std::string& user_id, 232 const std::string& user_id,
232 const std::string& service_id, 233 scoped_ptr<base::Timer> timer,
233 const std::string& challenge,
234 const ChallengeCallback& callback,
235 bool operation_success, 234 bool operation_success,
236 const std::string& certificate) { 235 const std::string& certificate) {
236 // Log failure before checking the timer so all failures are logged, even if
237 // they took too long.
237 if (!operation_success) { 238 if (!operation_success) {
238 LOG(WARNING) << "PlatformVerificationFlow: Failed to certify platform."; 239 LOG(WARNING) << "PlatformVerificationFlow: Failed to certify platform.";
239 ReportError(callback, PLATFORM_NOT_VERIFIED); 240 }
241 if (!timer->IsRunning()) {
242 LOG(WARNING) << "PlatformVerificationFlow: Certificate ready but call has "
243 << "already timed out.";
244 return;
245 }
246 timer->Stop();
247 if (!operation_success) {
248 ReportError(context.callback, PLATFORM_NOT_VERIFIED);
240 return; 249 return;
241 } 250 }
242 cryptohome::AsyncMethodCaller::DataCallback cryptohome_callback = base::Bind( 251 cryptohome::AsyncMethodCaller::DataCallback cryptohome_callback = base::Bind(
243 &PlatformVerificationFlow::OnChallengeReady, 252 &PlatformVerificationFlow::OnChallengeReady,
244 weak_factory_.GetWeakPtr(), 253 this,
245 certificate, 254 context,
246 challenge, 255 certificate);
247 callback);
248 std::string key_name = kContentProtectionKeyPrefix; 256 std::string key_name = kContentProtectionKeyPrefix;
249 key_name += service_id; 257 key_name += context.service_id;
250 async_caller_->TpmAttestationSignSimpleChallenge(KEY_USER, 258 async_caller_->TpmAttestationSignSimpleChallenge(KEY_USER,
251 user_id, 259 user_id,
252 key_name, 260 key_name,
253 challenge, 261 context.challenge,
254 cryptohome_callback); 262 cryptohome_callback);
255 } 263 }
256 264
265 void PlatformVerificationFlow::OnCertificateTimeout(
266 const ChallengeContext& context) {
267 LOG(WARNING) << "PlatformVerificationFlow: Timing out.";
268 ReportError(context.callback, TIMEOUT);
269 }
270
257 void PlatformVerificationFlow::OnChallengeReady( 271 void PlatformVerificationFlow::OnChallengeReady(
272 const ChallengeContext& context,
258 const std::string& certificate, 273 const std::string& certificate,
259 const std::string& challenge,
260 const ChallengeCallback& callback,
261 bool operation_success, 274 bool operation_success,
262 const std::string& response_data) { 275 const std::string& response_data) {
263 if (!operation_success) { 276 if (!operation_success) {
264 LOG(ERROR) << "PlatformVerificationFlow: Failed to sign challenge."; 277 LOG(ERROR) << "PlatformVerificationFlow: Failed to sign challenge.";
265 ReportError(callback, INTERNAL_ERROR); 278 ReportError(context.callback, INTERNAL_ERROR);
266 return; 279 return;
267 } 280 }
268 SignedData signed_data_pb; 281 SignedData signed_data_pb;
269 if (response_data.empty() || !signed_data_pb.ParseFromString(response_data)) { 282 if (response_data.empty() || !signed_data_pb.ParseFromString(response_data)) {
270 LOG(ERROR) << "PlatformVerificationFlow: Failed to parse response data."; 283 LOG(ERROR) << "PlatformVerificationFlow: Failed to parse response data.";
271 ReportError(callback, INTERNAL_ERROR); 284 ReportError(context.callback, INTERNAL_ERROR);
272 return; 285 return;
273 } 286 }
274 callback.Run(SUCCESS, 287 context.callback.Run(SUCCESS,
275 signed_data_pb.data(), 288 signed_data_pb.data(),
276 signed_data_pb.signature(), 289 signed_data_pb.signature(),
277 certificate); 290 certificate);
278 LOG(INFO) << "PlatformVerificationFlow: Platform successfully verified."; 291 LOG(INFO) << "PlatformVerificationFlow: Platform successfully verified.";
279 } 292 }
280 293
281 PrefService* PlatformVerificationFlow::GetPrefs( 294 PrefService* PlatformVerificationFlow::GetPrefs(
282 content::WebContents* web_contents) { 295 content::WebContents* web_contents) {
283 if (testing_prefs_) 296 if (testing_prefs_)
284 return testing_prefs_; 297 return testing_prefs_;
285 return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()); 298 return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext());
286 } 299 }
287 300
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 bool allow_domain) { 418 bool allow_domain) {
406 PrefService* pref_service = GetPrefs(web_contents); 419 PrefService* pref_service = GetPrefs(web_contents);
407 CHECK(pref_service); 420 CHECK(pref_service);
408 DictionaryPrefUpdate updater(pref_service, prefs::kRAConsentDomains); 421 DictionaryPrefUpdate updater(pref_service, prefs::kRAConsentDomains);
409 const GURL& url = GetURL(web_contents); 422 const GURL& url = GetURL(web_contents);
410 updater->SetBoolean(url.host(), allow_domain); 423 updater->SetBoolean(url.host(), allow_domain);
411 } 424 }
412 425
413 } // namespace attestation 426 } // namespace attestation
414 } // namespace chromeos 427 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698