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.
5 #include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h"
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"
36 namespace extensions {
38 namespace api_epkp = api::enterprise_platform_keys_private;
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.";
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)
65 certificate_profile(certificate_profile),
66 require_user_consent(require_user_consent),
70 EPKPChallengeKeyBase::PrepareKeyContext::~PrepareKeyContext() {
73 EPKPChallengeKeyBase::EPKPChallengeKeyBase()
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();
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) {
99 EPKPChallengeKeyBase::~EPKPChallengeKeyBase() {
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,
112 case chromeos::CrosSettingsProvider::TRUSTED:
113 if (!settings->GetBoolean(chromeos::kDeviceAttestationEnabled, &value))
116 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
117 // Do nothing. This function will be called again when the values are
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.
129 bool EPKPChallengeKeyBase::IsEnterpriseDevice() const {
130 return install_attributes_->IsEnterpriseDevice();
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();
140 bool EPKPChallengeKeyBase::IsUserManaged() const {
141 std::string email = GetUserEmail();
143 // TODO(davidyu): Use BrowserPolicyConnector::GetUserAffiliation() and fix
145 return email.empty() ? false :
146 gaia::ExtractDomainName(email) == GetEnterpriseDomain();
149 std::string EPKPChallengeKeyBase::GetEnterpriseDomain() const {
150 return install_attributes_->GetDomain();
153 std::string EPKPChallengeKeyBase::GetUserEmail() const {
154 SigninManagerBase* signin_manager =
155 SigninManagerFactory::GetForProfile(GetProfile());
157 return std::string();
159 return gaia::CanonicalizeEmail(signin_manager->GetAuthenticatedUsername());
162 std::string EPKPChallengeKeyBase::GetDeviceId() const {
163 return install_attributes_->GetDeviceId();
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,
177 require_user_consent,
179 cryptohome_client_->TpmAttestationIsPrepared(base::Bind(
180 &EPKPChallengeKeyBase::IsAttestationPreparedCallback, this, context));
183 void EPKPChallengeKeyBase::IsAttestationPreparedCallback(
184 const PrepareKeyContext& context,
185 chromeos::DBusMethodCallStatus status,
187 if (status == chromeos::DBUS_METHOD_CALL_FAILURE) {
188 context.callback.Run(PREPARE_KEY_DBUS_ERROR);
192 context.callback.Run(PREPARE_KEY_RESET_REQUIRED);
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));
201 void EPKPChallengeKeyBase::DoesKeyExistCallback(
202 const PrepareKeyContext& context,
203 chromeos::DBusMethodCallStatus status,
205 if (status == chromeos::DBUS_METHOD_CALL_FAILURE) {
206 context.callback.Run(PREPARE_KEY_DBUS_ERROR);
211 // The key exists. Do nothing more.
212 context.callback.Run(PREPARE_KEY_OK);
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.
219 base::Bind(&EPKPChallengeKeyBase::AskForUserConsentCallback, this,
222 // User consent is not required. Skip to the next step.
223 AskForUserConsentCallback(context, true);
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.
235 void EPKPChallengeKeyBase::AskForUserConsentCallback(
236 const PrepareKeyContext& context,
239 // The user rejects the request.
240 context.callback.Run(PREPARE_KEY_USER_REJECTED);
244 // Generate a new key and have it signed by PCA.
245 attestation_flow_->GetCertificate(
246 context.certificate_profile,
248 std::string(), // Not used.
249 true, // Force a new key to be generated.
250 base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this,
254 void EPKPChallengeKeyBase::GetCertificateCallback(
255 const base::Callback<void(PrepareKeyResult)>& callback,
257 const std::string& pem_certificate_chain) {
259 callback.Run(PREPARE_KEY_GET_CERTIFICATE_FAILED);
263 callback.Run(PREPARE_KEY_OK);
266 // Implementation of ChallengeMachineKey()
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.";
273 const char EPKPChallengeMachineKey::kKeyName[] = "attest-ent-machine";
275 EPKPChallengeMachineKey::EPKPChallengeMachineKey() : EPKPChallengeKeyBase() {
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,
286 install_attributes) {
289 EPKPChallengeMachineKey::~EPKPChallengeMachineKey() {
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());
297 std::string challenge;
298 if (!base::Base64Decode(params->challenge, &challenge)) {
299 SetError(kChallengeBadBase64Error);
303 // Check if the device is enterprise enrolled.
304 if (!IsEnterpriseDevice()) {
305 SetError(kNonEnterpriseDeviceError);
309 // Check if the extension is whitelisted in the user policy.
310 if (!IsExtensionWhitelisted()) {
311 SetError(kExtensionNotWhitelistedError);
315 // Check if the user domain is the same as the enrolled enterprise domain.
316 if (!IsUserManaged()) {
317 SetError(kUserNotManaged);
321 // Check if RA is enabled in the device policy.
322 GetDeviceAttestationEnabled(
323 base::Bind(&EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback,
329 void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback(
330 const std::string& challenge, bool enabled) {
332 SetError(kDevicePolicyDisabledError);
337 PrepareKey(chromeos::attestation::KEY_DEVICE,
338 std::string(), // Not used.
340 chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE,
341 false, // user consent is not required.
342 base::Bind(&EPKPChallengeMachineKey::PrepareKeyCallback, this,
346 void EPKPChallengeMachineKey::PrepareKeyCallback(
347 const std::string& challenge, PrepareKeyResult result) {
348 if (result != PREPARE_KEY_OK) {
349 SetError(base::StringPrintf(kGetCertificateFailedError, result));
354 // Everything is checked. Sign the challenge.
355 async_caller_->TpmAttestationSignEnterpriseChallenge(
356 chromeos::attestation::KEY_DEVICE,
357 std::string(), // Not used.
359 GetEnterpriseDomain(),
361 chromeos::attestation::CHALLENGE_OPTION_NONE,
363 base::Bind(&EPKPChallengeMachineKey::SignChallengeCallback, this));
366 void EPKPChallengeMachineKey::SignChallengeCallback(
367 bool success, const std::string& response) {
369 SetError(kSignChallengeFailedError);
374 std::string encoded_response;
375 base::Base64Encode(response, &encoded_response);
377 results_ = api_epkp::ChallengeMachineKey::Results::Create(encoded_response);
381 // Implementation of ChallengeUserKey()
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.";
390 const char EPKPChallengeUserKey::kKeyName[] = "attest-ent-user";
392 EPKPChallengeUserKey::EPKPChallengeUserKey() : EPKPChallengeKeyBase() {
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,
403 install_attributes) {
406 EPKPChallengeUserKey::~EPKPChallengeUserKey() {
409 void EPKPChallengeUserKey::RegisterProfilePrefs(
410 user_prefs::PrefRegistrySyncable* registry) {
411 registry->RegisterBooleanPref(
412 prefs::kAttestationEnabled,
414 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
415 registry->RegisterListPref(prefs::kAttestationExtensionWhitelist,
416 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
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());
424 std::string challenge;
425 if (!base::Base64Decode(params->challenge, &challenge)) {
426 SetError(kChallengeBadBase64Error);
430 // Check if RA is enabled in the user policy.
431 if (!IsRemoteAttestationEnabledForUser()) {
432 SetError(kUserPolicyDisabledError);
436 // Check if the extension is whitelisted in the user policy.
437 if (!IsExtensionWhitelisted()) {
438 SetError(kExtensionNotWhitelistedError);
442 if (IsEnterpriseDevice()) {
443 // Check if the user domain is the same as the enrolled enterprise domain.
444 if (!IsUserManaged()) {
445 SetError(kUserNotManaged);
449 // Check if RA is enabled in the device policy.
450 GetDeviceAttestationEnabled(
451 base::Bind(&EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback,
454 params->register_key,
455 false)); // user consent is not required.
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(
461 params->register_key,
462 true, // user consent is required.
463 true); // attestation is enabled.
469 void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback(
470 const std::string& challenge,
472 bool require_user_consent,
475 SetError(kDevicePolicyDisabledError);
480 PrepareKey(chromeos::attestation::KEY_USER,
483 chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE,
484 require_user_consent,
485 base::Bind(&EPKPChallengeUserKey::PrepareKeyCallback, this,
486 challenge, register_key));
489 void EPKPChallengeUserKey::PrepareKeyCallback(const std::string& challenge,
491 PrepareKeyResult result) {
492 if (result != PREPARE_KEY_OK) {
493 SetError(base::StringPrintf(kGetCertificateFailedError, result));
498 // Everything is checked. Sign the challenge.
499 async_caller_->TpmAttestationSignEnterpriseChallenge(
500 chromeos::attestation::KEY_USER,
506 chromeos::attestation::CHALLENGE_INCLUDE_SIGNED_PUBLIC_KEY :
507 chromeos::attestation::CHALLENGE_OPTION_NONE,
509 base::Bind(&EPKPChallengeUserKey::SignChallengeCallback, this,
513 void EPKPChallengeUserKey::SignChallengeCallback(bool register_key,
515 const std::string& response) {
517 SetError(kSignChallengeFailedError);
523 async_caller_->TpmAttestationRegisterKey(
524 chromeos::attestation::KEY_USER,
527 base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response));
529 RegisterKeyCallback(response, true, cryptohome::MOUNT_ERROR_NONE);
533 void EPKPChallengeUserKey::RegisterKeyCallback(
534 const std::string& response,
536 cryptohome::MountError return_code) {
537 if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) {
538 SetError(kKeyRegistrationFailedError);
543 std::string encoded_response;
544 base::Base64Encode(response, &encoded_response);
546 results_ = api_epkp::ChallengeUserKey::Results::Create(encoded_response);
550 bool EPKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const {
551 return GetProfile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
554 } // namespace extensions