Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / enterprise_platform_keys_private / enterprise_platform_keys_private_api.cc
1 // Copyright (c) 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 #include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h"
6
7 #include <string>
8
9 #include "base/base64.h"
10 #include "base/callback.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
19 #include "chrome/browser/chromeos/settings/cros_settings.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/common/extensions/api/enterprise_platform_keys_private.h"
23 #include "chrome/common/pref_names.h"
24 #include "chromeos/attestation/attestation_constants.h"
25 #include "chromeos/attestation/attestation_flow.h"
26 #include "chromeos/cryptohome/async_method_caller.h"
27 #include "chromeos/dbus/cryptohome_client.h"
28 #include "chromeos/dbus/dbus_method_call_status.h"
29 #include "chromeos/dbus/dbus_thread_manager.h"
30 #include "chromeos/settings/cros_settings_names.h"
31 #include "components/signin/core/browser/signin_manager.h"
32 #include "components/user_prefs/pref_registry_syncable.h"
33 #include "google_apis/gaia/gaia_auth_util.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
35
36 namespace extensions {
37
38 namespace api_epkp = api::enterprise_platform_keys_private;
39
40 // Base class
41
42 const char EPKPChallengeKeyBase::kChallengeBadBase64Error[] =
43     "Challenge is not base64 encoded.";
44 const char EPKPChallengeKeyBase::kDevicePolicyDisabledError[] =
45     "Remote attestation is not enabled for your device.";
46 const char EPKPChallengeKeyBase::kExtensionNotWhitelistedError[] =
47     "The extension does not have permission to call this function.";
48 const char EPKPChallengeKeyBase::kResponseBadBase64Error[] =
49     "Response cannot be encoded in base64.";
50 const char EPKPChallengeKeyBase::kSignChallengeFailedError[] =
51     "Failed to sign the challenge.";
52 const char EPKPChallengeKeyBase::kUserNotManaged[] =
53     "The user account is not enterprise managed.";
54
55 EPKPChallengeKeyBase::PrepareKeyContext::PrepareKeyContext(
56     chromeos::attestation::AttestationKeyType key_type,
57     const std::string& user_id,
58     const std::string& key_name,
59     chromeos::attestation::AttestationCertificateProfile certificate_profile,
60     bool require_user_consent,
61     const base::Callback<void(PrepareKeyResult)>& callback)
62     : key_type(key_type),
63       user_id(user_id),
64       key_name(key_name),
65       certificate_profile(certificate_profile),
66       require_user_consent(require_user_consent),
67       callback(callback) {
68 }
69
70 EPKPChallengeKeyBase::PrepareKeyContext::~PrepareKeyContext() {
71 }
72
73 EPKPChallengeKeyBase::EPKPChallengeKeyBase()
74     : cryptohome_client_(
75           chromeos::DBusThreadManager::Get()->GetCryptohomeClient()),
76       async_caller_(cryptohome::AsyncMethodCaller::GetInstance()),
77       install_attributes_(g_browser_process->platform_part()
78                               ->browser_policy_connector_chromeos()
79                               ->GetInstallAttributes()) {
80   scoped_ptr<chromeos::attestation::ServerProxy> ca_client(
81       new chromeos::attestation::AttestationCAClient());
82   default_attestation_flow_.reset(
83       new chromeos::attestation::AttestationFlow(
84           async_caller_, cryptohome_client_, ca_client.Pass()));
85   attestation_flow_ = default_attestation_flow_.get();
86 }
87
88 EPKPChallengeKeyBase::EPKPChallengeKeyBase(
89     chromeos::CryptohomeClient* cryptohome_client,
90     cryptohome::AsyncMethodCaller* async_caller,
91     chromeos::attestation::AttestationFlow* attestation_flow,
92     policy::EnterpriseInstallAttributes* install_attributes) :
93     cryptohome_client_(cryptohome_client),
94     async_caller_(async_caller),
95     attestation_flow_(attestation_flow),
96     install_attributes_(install_attributes) {
97 }
98
99 EPKPChallengeKeyBase::~EPKPChallengeKeyBase() {
100 }
101
102 void EPKPChallengeKeyBase::GetDeviceAttestationEnabled(
103     const base::Callback<void(bool)>& callback) const {
104   chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
105   chromeos::CrosSettingsProvider::TrustedStatus status =
106       settings->PrepareTrustedValues(
107           base::Bind(&EPKPChallengeKeyBase::GetDeviceAttestationEnabled, this,
108                      callback));
109
110   bool value = false;
111   switch (status) {
112     case chromeos::CrosSettingsProvider::TRUSTED:
113       if (!settings->GetBoolean(chromeos::kDeviceAttestationEnabled, &value))
114         value = false;
115       break;
116     case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
117       // Do nothing. This function will be called again when the values are
118       // ready.
119       return;
120     case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
121       // If the value cannot be trusted, we assume that the device attestation
122       // is false to be on the safe side.
123       break;
124   }
125
126   callback.Run(value);
127 }
128
129 bool EPKPChallengeKeyBase::IsEnterpriseDevice() const {
130   return install_attributes_->IsEnterpriseDevice();
131 }
132
133 bool EPKPChallengeKeyBase::IsExtensionWhitelisted() const {
134   const base::ListValue* list =
135       GetProfile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist);
136   base::StringValue value(extension_->id());
137   return list->Find(value) != list->end();
138 }
139
140 bool EPKPChallengeKeyBase::IsUserManaged() const {
141   std::string email = GetUserEmail();
142
143   // TODO(davidyu): Use BrowserPolicyConnector::GetUserAffiliation() and fix
144   // the test.
145   return email.empty() ? false :
146       gaia::ExtractDomainName(email) == GetEnterpriseDomain();
147 }
148
149 std::string EPKPChallengeKeyBase::GetEnterpriseDomain() const {
150   return install_attributes_->GetDomain();
151 }
152
153 std::string EPKPChallengeKeyBase::GetUserEmail() const {
154   SigninManagerBase* signin_manager =
155       SigninManagerFactory::GetForProfile(GetProfile());
156   if (!signin_manager)
157     return std::string();
158
159   return gaia::CanonicalizeEmail(signin_manager->GetAuthenticatedUsername());
160 }
161
162 std::string EPKPChallengeKeyBase::GetDeviceId() const {
163   return install_attributes_->GetDeviceId();
164 }
165
166 void EPKPChallengeKeyBase::PrepareKey(
167     chromeos::attestation::AttestationKeyType key_type,
168     const std::string& user_id,
169     const std::string& key_name,
170     chromeos::attestation::AttestationCertificateProfile certificate_profile,
171     bool require_user_consent,
172     const base::Callback<void(PrepareKeyResult)>& callback) {
173   const PrepareKeyContext context = PrepareKeyContext(key_type,
174                                                       user_id,
175                                                       key_name,
176                                                       certificate_profile,
177                                                       require_user_consent,
178                                                       callback);
179   cryptohome_client_->TpmAttestationIsPrepared(base::Bind(
180       &EPKPChallengeKeyBase::IsAttestationPreparedCallback, this, context));
181 }
182
183 void EPKPChallengeKeyBase::IsAttestationPreparedCallback(
184     const PrepareKeyContext& context,
185     chromeos::DBusMethodCallStatus status,
186     bool result) {
187   if (status == chromeos::DBUS_METHOD_CALL_FAILURE) {
188     context.callback.Run(PREPARE_KEY_DBUS_ERROR);
189     return;
190   }
191   if (!result) {
192     context.callback.Run(PREPARE_KEY_RESET_REQUIRED);
193     return;
194   }
195   // Attestation is available, see if the key we need already exists.
196   cryptohome_client_->TpmAttestationDoesKeyExist(
197       context.key_type, context.user_id, context.key_name, base::Bind(
198           &EPKPChallengeKeyBase::DoesKeyExistCallback, this, context));
199 }
200
201 void EPKPChallengeKeyBase::DoesKeyExistCallback(
202     const PrepareKeyContext& context,
203     chromeos::DBusMethodCallStatus status,
204     bool result) {
205   if (status == chromeos::DBUS_METHOD_CALL_FAILURE) {
206     context.callback.Run(PREPARE_KEY_DBUS_ERROR);
207     return;
208   }
209
210   if (result) {
211     // The key exists. Do nothing more.
212     context.callback.Run(PREPARE_KEY_OK);
213   } else {
214     // The key does not exist. Create a new key and have it signed by PCA.
215     if (context.require_user_consent) {
216       // We should ask the user explicitly before sending any private
217       // information to PCA.
218       AskForUserConsent(
219           base::Bind(&EPKPChallengeKeyBase::AskForUserConsentCallback, this,
220                      context));
221     } else {
222       // User consent is not required. Skip to the next step.
223       AskForUserConsentCallback(context, true);
224     }
225   }
226 }
227
228 void EPKPChallengeKeyBase::AskForUserConsent(
229     const base::Callback<void(bool)>& callback) const {
230   // TODO(davidyu): right now we just simply reject the request before we have
231   // a way to ask for user consent.
232   callback.Run(false);
233 }
234
235 void EPKPChallengeKeyBase::AskForUserConsentCallback(
236     const PrepareKeyContext& context,
237     bool result) {
238   if (!result) {
239     // The user rejects the request.
240     context.callback.Run(PREPARE_KEY_USER_REJECTED);
241     return;
242   }
243
244   // Generate a new key and have it signed by PCA.
245   attestation_flow_->GetCertificate(
246       context.certificate_profile,
247       context.user_id,
248       std::string(),  // Not used.
249       true,  // Force a new key to be generated.
250       base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this,
251                  context.callback));
252 }
253
254 void EPKPChallengeKeyBase::GetCertificateCallback(
255     const base::Callback<void(PrepareKeyResult)>& callback,
256     bool success,
257     const std::string& pem_certificate_chain) {
258   if (!success) {
259     callback.Run(PREPARE_KEY_GET_CERTIFICATE_FAILED);
260     return;
261   }
262
263   callback.Run(PREPARE_KEY_OK);
264 }
265
266 // Implementation of ChallengeMachineKey()
267
268 const char EPKPChallengeMachineKey::kGetCertificateFailedError[] =
269     "Failed to get Enterprise machine certificate. Error code = %d";
270 const char EPKPChallengeMachineKey::kNonEnterpriseDeviceError[] =
271     "The device is not enterprise enrolled.";
272
273 const char EPKPChallengeMachineKey::kKeyName[] = "attest-ent-machine";
274
275 EPKPChallengeMachineKey::EPKPChallengeMachineKey() : EPKPChallengeKeyBase() {
276 }
277
278 EPKPChallengeMachineKey::EPKPChallengeMachineKey(
279     chromeos::CryptohomeClient* cryptohome_client,
280     cryptohome::AsyncMethodCaller* async_caller,
281     chromeos::attestation::AttestationFlow* attestation_flow,
282     policy::EnterpriseInstallAttributes* install_attributes) :
283     EPKPChallengeKeyBase(cryptohome_client,
284                          async_caller,
285                          attestation_flow,
286                          install_attributes) {
287 }
288
289 EPKPChallengeMachineKey::~EPKPChallengeMachineKey() {
290 }
291
292 bool EPKPChallengeMachineKey::RunAsync() {
293   scoped_ptr<api_epkp::ChallengeMachineKey::Params>
294       params(api_epkp::ChallengeMachineKey::Params::Create(*args_));
295   EXTENSION_FUNCTION_VALIDATE(params.get());
296
297   std::string challenge;
298   if (!base::Base64Decode(params->challenge, &challenge)) {
299     SetError(kChallengeBadBase64Error);
300     return false;
301   }
302
303   // Check if the device is enterprise enrolled.
304   if (!IsEnterpriseDevice()) {
305     SetError(kNonEnterpriseDeviceError);
306     return false;
307   }
308
309   // Check if the extension is whitelisted in the user policy.
310   if (!IsExtensionWhitelisted()) {
311     SetError(kExtensionNotWhitelistedError);
312     return false;
313   }
314
315   // Check if the user domain is the same as the enrolled enterprise domain.
316   if (!IsUserManaged()) {
317     SetError(kUserNotManaged);
318     return false;
319   }
320
321   // Check if RA is enabled in the device policy.
322   GetDeviceAttestationEnabled(
323       base::Bind(&EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback,
324                  this, challenge));
325
326   return true;
327 }
328
329 void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback(
330     const std::string& challenge, bool enabled) {
331   if (!enabled) {
332     SetError(kDevicePolicyDisabledError);
333     SendResponse(false);
334     return;
335   }
336
337   PrepareKey(chromeos::attestation::KEY_DEVICE,
338              std::string(),  // Not used.
339              kKeyName,
340              chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
341              false,  // user consent is not required.
342              base::Bind(&EPKPChallengeMachineKey::PrepareKeyCallback, this,
343                         challenge));
344 }
345
346 void EPKPChallengeMachineKey::PrepareKeyCallback(
347     const std::string& challenge, PrepareKeyResult result) {
348   if (result != PREPARE_KEY_OK) {
349     SetError(base::StringPrintf(kGetCertificateFailedError, result));
350     SendResponse(false);
351     return;
352   }
353
354   // Everything is checked. Sign the challenge.
355   async_caller_->TpmAttestationSignEnterpriseChallenge(
356       chromeos::attestation::KEY_DEVICE,
357       std::string(),  // Not used.
358       kKeyName,
359       GetEnterpriseDomain(),
360       GetDeviceId(),
361       chromeos::attestation::CHALLENGE_OPTION_NONE,
362       challenge,
363       base::Bind(&EPKPChallengeMachineKey::SignChallengeCallback, this));
364 }
365
366 void EPKPChallengeMachineKey::SignChallengeCallback(
367     bool success, const std::string& response) {
368   if (!success) {
369     SetError(kSignChallengeFailedError);
370     SendResponse(false);
371     return;
372   }
373
374   std::string encoded_response;
375   base::Base64Encode(response, &encoded_response);
376
377   results_ = api_epkp::ChallengeMachineKey::Results::Create(encoded_response);
378   SendResponse(true);
379 }
380
381 // Implementation of ChallengeUserKey()
382
383 const char EPKPChallengeUserKey::kGetCertificateFailedError[] =
384     "Failed to get Enterprise user certificate. Error code = %d";
385 const char EPKPChallengeUserKey::kKeyRegistrationFailedError[] =
386     "Key registration failed.";
387 const char EPKPChallengeUserKey::kUserPolicyDisabledError[] =
388     "Remote attestation is not enabled for your account.";
389
390 const char EPKPChallengeUserKey::kKeyName[] = "attest-ent-user";
391
392 EPKPChallengeUserKey::EPKPChallengeUserKey() : EPKPChallengeKeyBase() {
393 }
394
395 EPKPChallengeUserKey::EPKPChallengeUserKey(
396     chromeos::CryptohomeClient* cryptohome_client,
397     cryptohome::AsyncMethodCaller* async_caller,
398     chromeos::attestation::AttestationFlow* attestation_flow,
399     policy::EnterpriseInstallAttributes* install_attributes) :
400     EPKPChallengeKeyBase(cryptohome_client,
401                          async_caller,
402                          attestation_flow,
403                          install_attributes) {
404 }
405
406 EPKPChallengeUserKey::~EPKPChallengeUserKey() {
407 }
408
409 void EPKPChallengeUserKey::RegisterProfilePrefs(
410     user_prefs::PrefRegistrySyncable* registry) {
411   registry->RegisterBooleanPref(
412       prefs::kAttestationEnabled,
413       false,
414       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
415   registry->RegisterListPref(prefs::kAttestationExtensionWhitelist,
416                              user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
417 }
418
419 bool EPKPChallengeUserKey::RunAsync() {
420   scoped_ptr<api_epkp::ChallengeUserKey::Params> params(
421       api_epkp::ChallengeUserKey::Params::Create(*args_));
422   EXTENSION_FUNCTION_VALIDATE(params.get());
423
424   std::string challenge;
425   if (!base::Base64Decode(params->challenge, &challenge)) {
426     SetError(kChallengeBadBase64Error);
427     return false;
428   }
429
430   // Check if RA is enabled in the user policy.
431   if (!IsRemoteAttestationEnabledForUser()) {
432     SetError(kUserPolicyDisabledError);
433     return false;
434   }
435
436   // Check if the extension is whitelisted in the user policy.
437   if (!IsExtensionWhitelisted()) {
438     SetError(kExtensionNotWhitelistedError);
439     return false;
440   }
441
442   if (IsEnterpriseDevice()) {
443     // Check if the user domain is the same as the enrolled enterprise domain.
444     if (!IsUserManaged()) {
445       SetError(kUserNotManaged);
446       return false;
447     }
448
449     // Check if RA is enabled in the device policy.
450     GetDeviceAttestationEnabled(
451         base::Bind(&EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback,
452                    this,
453                    challenge,
454                    params->register_key,
455                    false));  // user consent is not required.
456   } else {
457     // For personal devices, we don't need to check if RA is enabled in the
458     // device, but we need to ask for user consent if the key does not exist.
459     GetDeviceAttestationEnabledCallback(
460         challenge,
461         params->register_key,
462         true,  // user consent is required.
463         true);  // attestation is enabled.
464   }
465
466   return true;
467 }
468
469 void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback(
470     const std::string& challenge,
471     bool register_key,
472     bool require_user_consent,
473     bool enabled) {
474   if (!enabled) {
475     SetError(kDevicePolicyDisabledError);
476     SendResponse(false);
477     return;
478   }
479
480   PrepareKey(chromeos::attestation::KEY_USER,
481              GetUserEmail(),
482              kKeyName,
483              chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
484              require_user_consent,
485              base::Bind(&EPKPChallengeUserKey::PrepareKeyCallback, this,
486                         challenge, register_key));
487 }
488
489 void EPKPChallengeUserKey::PrepareKeyCallback(const std::string& challenge,
490                                               bool register_key,
491                                               PrepareKeyResult result) {
492   if (result != PREPARE_KEY_OK) {
493     SetError(base::StringPrintf(kGetCertificateFailedError, result));
494     SendResponse(false);
495     return;
496   }
497
498   // Everything is checked. Sign the challenge.
499   async_caller_->TpmAttestationSignEnterpriseChallenge(
500       chromeos::attestation::KEY_USER,
501       GetUserEmail(),
502       kKeyName,
503       GetUserEmail(),
504       GetDeviceId(),
505       register_key ?
506           chromeos::attestation::CHALLENGE_INCLUDE_SIGNED_PUBLIC_KEY :
507           chromeos::attestation::CHALLENGE_OPTION_NONE,
508       challenge,
509       base::Bind(&EPKPChallengeUserKey::SignChallengeCallback, this,
510                  register_key));
511 }
512
513 void EPKPChallengeUserKey::SignChallengeCallback(bool register_key,
514                                                  bool success,
515                                                  const std::string& response) {
516   if (!success) {
517     SetError(kSignChallengeFailedError);
518     SendResponse(false);
519     return;
520   }
521
522   if (register_key) {
523     async_caller_->TpmAttestationRegisterKey(
524         chromeos::attestation::KEY_USER,
525         GetUserEmail(),
526         kKeyName,
527         base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response));
528   } else {
529     RegisterKeyCallback(response, true, cryptohome::MOUNT_ERROR_NONE);
530   }
531 }
532
533 void EPKPChallengeUserKey::RegisterKeyCallback(
534     const std::string& response,
535     bool success,
536     cryptohome::MountError return_code) {
537   if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) {
538     SetError(kKeyRegistrationFailedError);
539     SendResponse(false);
540     return;
541   }
542
543   std::string encoded_response;
544   base::Base64Encode(response, &encoded_response);
545
546   results_ = api_epkp::ChallengeUserKey::Results::Create(encoded_response);
547   SendResponse(true);
548 }
549
550 bool EPKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const {
551   return GetProfile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
552 }
553
554 }  // namespace extensions