enterprise_platform_keys_private_api.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.h" 12#include "base/prefs/pref_service.h" 13#include "base/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/enterprise_install_attributes.h" 18#include "chrome/browser/chromeos/settings/cros_settings.h" 19#include "chrome/browser/chromeos/settings/cros_settings_names.h" 20#include "chrome/browser/policy/browser_policy_connector.h" 21#include "chrome/browser/profiles/profile.h" 22#include "chrome/browser/signin/signin_manager.h" 23#include "chrome/browser/signin/signin_manager_factory.h" 24#include "chrome/common/extensions/api/enterprise_platform_keys_private.h" 25#include "chrome/common/pref_names.h" 26#include "chromeos/attestation/attestation_constants.h" 27#include "chromeos/attestation/attestation_flow.h" 28#include "chromeos/cryptohome/async_method_caller.h" 29#include "chromeos/dbus/cryptohome_client.h" 30#include "chromeos/dbus/dbus_method_call_status.h" 31#include "chromeos/dbus/dbus_thread_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 36namespace extensions { 37 38namespace api_epkp = api::enterprise_platform_keys_private; 39 40// Base class 41 42EPKPChallengeKeyBase::EPKPChallengeKeyBase() 43 : cryptohome_client_( 44 chromeos::DBusThreadManager::Get()->GetCryptohomeClient()), 45 async_caller_(cryptohome::AsyncMethodCaller::GetInstance()), 46 install_attributes_(g_browser_process->browser_policy_connector()-> 47 GetInstallAttributes()) { 48 scoped_ptr<chromeos::attestation::ServerProxy> ca_client( 49 new chromeos::attestation::AttestationCAClient()); 50 attestation_flow_.reset( 51 new chromeos::attestation::AttestationFlow( 52 async_caller_, cryptohome_client_, ca_client.Pass())); 53} 54 55EPKPChallengeKeyBase::~EPKPChallengeKeyBase() { 56} 57 58void EPKPChallengeKeyBase::GetDeviceAttestationEnabled( 59 const base::Callback<void(bool)>& callback) const { 60 chromeos::CrosSettings* settings = chromeos::CrosSettings::Get(); 61 chromeos::CrosSettingsProvider::TrustedStatus status = 62 settings->PrepareTrustedValues( 63 base::Bind(&EPKPChallengeKeyBase::GetDeviceAttestationEnabled, this, 64 callback)); 65 66 bool value = false; 67 switch (status) { 68 case chromeos::CrosSettingsProvider::TRUSTED: 69 if (!settings->GetBoolean(chromeos::kDeviceAttestationEnabled, &value)) 70 value = false; 71 break; 72 case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED: 73 // Do nothing. This function will be called again when the values are 74 // ready. 75 return; 76 case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED: 77 // If the value cannot be trusted, we assume that the device attestation 78 // is false to be on the safe side. 79 break; 80 } 81 82 callback.Run(value); 83} 84 85bool EPKPChallengeKeyBase::IsEnterpriseDevice() const { 86 return install_attributes_->IsEnterpriseDevice(); 87} 88 89std::string EPKPChallengeKeyBase::GetEnterpriseDomain() const { 90 return install_attributes_->GetDomain(); 91} 92 93std::string EPKPChallengeKeyBase::GetDeviceId() const { 94 return install_attributes_->GetDeviceId(); 95} 96 97void EPKPChallengeKeyBase::PrepareKey( 98 chromeos::attestation::AttestationKeyType key_type, 99 const std::string& key_name, 100 chromeos::attestation::AttestationCertificateProfile certificate_profile, 101 bool require_user_consent, 102 const base::Callback<void(PrepareKeyResult)>& callback) { 103 cryptohome_client_->TpmAttestationDoesKeyExist( 104 key_type, key_name, base::Bind( 105 &EPKPChallengeKeyBase::DoesKeyExistCallback, this, 106 certificate_profile, require_user_consent, callback)); 107} 108 109void EPKPChallengeKeyBase::DoesKeyExistCallback( 110 chromeos::attestation::AttestationCertificateProfile certificate_profile, 111 bool require_user_consent, 112 const base::Callback<void(PrepareKeyResult)>& callback, 113 chromeos::DBusMethodCallStatus status, 114 bool result) { 115 if (status == chromeos::DBUS_METHOD_CALL_FAILURE) { 116 callback.Run(PREPARE_KEY_DBUS_ERROR); 117 return; 118 } 119 120 if (result) { 121 // The key exists. Do nothing more. 122 callback.Run(PREPARE_KEY_OK); 123 } else { 124 // The key does not exist. Create a new key and have it signed by PCA. 125 if (require_user_consent) { 126 // We should ask the user explicitly before sending any private 127 // information to PCA. 128 AskForUserConsent( 129 base::Bind(&EPKPChallengeKeyBase::AskForUserConsentCallback, this, 130 certificate_profile, callback)); 131 } else { 132 // User consent is not required. Skip to the next step. 133 AskForUserConsentCallback(certificate_profile, callback, true); 134 } 135 } 136} 137 138void EPKPChallengeKeyBase::AskForUserConsent( 139 const base::Callback<void(bool)>& callback) const { 140 // TODO(davidyu): right now we just simply reject the request before we have 141 // a way to ask for user consent. 142 callback.Run(false); 143} 144 145void EPKPChallengeKeyBase::AskForUserConsentCallback( 146 chromeos::attestation::AttestationCertificateProfile certificate_profile, 147 const base::Callback<void(PrepareKeyResult)>& callback, 148 bool result) { 149 if (!result) { 150 // The user rejects the request. 151 callback.Run(PREPARE_KEY_USER_REJECTED); 152 return; 153 } 154 155 // Generate a new key and have it signed by PCA. 156 attestation_flow_->GetCertificate( 157 certificate_profile, 158 true, // Force a new key to be generated. 159 base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, this, 160 callback)); 161} 162 163void EPKPChallengeKeyBase::GetCertificateCallback( 164 const base::Callback<void(PrepareKeyResult)>& callback, 165 bool success, 166 const std::string& pem_certificate_chain) { 167 if (!success) { 168 callback.Run(PREPARE_KEY_GET_CERTIFICATE_FAILED); 169 return; 170 } 171 172 callback.Run(PREPARE_KEY_OK); 173} 174 175// Implementation of ChallengeMachineKey() 176 177const char EPKPChallengeMachineKey::kKeyName[] = "attest-ent-machine"; 178 179EPKPChallengeMachineKey::~EPKPChallengeMachineKey() { 180} 181 182bool EPKPChallengeMachineKey::RunImpl() { 183 scoped_ptr<api_epkp::ChallengeMachineKey::Params> 184 params(api_epkp::ChallengeMachineKey::Params::Create(*args_)); 185 EXTENSION_FUNCTION_VALIDATE(params.get()); 186 187 std::string challenge; 188 if (!base::Base64Decode(params->challenge, &challenge)) { 189 SetError("Challenge is not base64 encoded."); 190 SendResponse(false); 191 return false; 192 } 193 194 // Check if the device is enterprise enrolled. 195 if (!IsEnterpriseDevice()) { 196 SetError("The device is not enterprise enrolled."); 197 SendResponse(false); 198 return false; 199 } 200 201 // Check if RA is enabled in the device policy. 202 GetDeviceAttestationEnabled( 203 base::Bind(&EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback, 204 this, challenge)); 205 206 return true; 207} 208 209void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback( 210 const std::string& challenge, bool enabled) { 211 if (!enabled) { 212 SetError("Remote attestation is not enabled for your device."); 213 SendResponse(false); 214 return; 215 } 216 217 PrepareKey(chromeos::attestation::KEY_DEVICE, 218 kKeyName, 219 chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, 220 false, // user consent is not required. 221 base::Bind(&EPKPChallengeMachineKey::PrepareKeyCallback, this, 222 challenge)); 223} 224 225void EPKPChallengeMachineKey::PrepareKeyCallback( 226 const std::string& challenge, PrepareKeyResult result) { 227 if (result != PREPARE_KEY_OK) { 228 SetError(base::StringPrintf( 229 "Failed to get Enterprise machince certificate. Error code = %d", 230 result)); 231 SendResponse(false); 232 return; 233 } 234 235 // Everything is checked. Sign the challenge. 236 async_caller_->TpmAttestationSignEnterpriseChallenge( 237 chromeos::attestation::KEY_DEVICE, 238 kKeyName, 239 GetEnterpriseDomain(), 240 GetDeviceId(), 241 chromeos::attestation::CHALLENGE_OPTION_NONE, 242 challenge, 243 base::Bind(&EPKPChallengeMachineKey::SignChallengeCallback, this)); 244} 245 246void EPKPChallengeMachineKey::SignChallengeCallback( 247 bool success, const std::string& response) { 248 if (!success) { 249 SetError("Challenge failed."); 250 SendResponse(false); 251 return; 252 } 253 254 std::string encoded_response; 255 if (!base::Base64Encode(response, &encoded_response)) { 256 SetError("Response cannot be encoded in base64."); 257 SendResponse(false); 258 return; 259 } 260 261 results_ = api_epkp::ChallengeMachineKey::Results::Create(encoded_response); 262 SendResponse(true); 263} 264 265// Implementation of ChallengeUserKey() 266 267const char EPKPChallengeUserKey::kKeyName[] = "attest-ent-user"; 268 269EPKPChallengeUserKey::~EPKPChallengeUserKey() { 270} 271 272void EPKPChallengeUserKey::RegisterUserPrefs( 273 user_prefs::PrefRegistrySyncable* registry) { 274 registry->RegisterBooleanPref( 275 prefs::kAttestationEnabled, 276 false, 277 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 278 registry->RegisterListPref(prefs::kAttestationExtensionWhitelist, 279 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 280} 281 282bool EPKPChallengeUserKey::RunImpl() { 283 scoped_ptr<api_epkp::ChallengeUserKey::Params> params( 284 api_epkp::ChallengeUserKey::Params::Create(*args_)); 285 EXTENSION_FUNCTION_VALIDATE(params.get()); 286 287 std::string challenge; 288 if (!base::Base64Decode(params->challenge, &challenge)) { 289 SetError("Challenge is not base64 encoded."); 290 SendResponse(false); 291 return false; 292 } 293 294 // Check if RA is enabled in the user policy. 295 if (!IsRemoteAttestationEnabledForUser()) { 296 SetError("Remote attestation is not enabled for your account."); 297 SendResponse(false); 298 return false; 299 } 300 301 // Check if the extension is whitelisted in the user policy. 302 if (!IsExtensionWhitelisted()) { 303 SetError("The extension does not have permission to call this function."); 304 SendResponse(false); 305 return false; 306 } 307 308 std::string user_domain = GetUserDomain(); 309 310 if (IsEnterpriseDevice()) { 311 // Check if the user domain is the same as the enrolled enterprise domain. 312 std::string enterprise_domain = GetEnterpriseDomain(); 313 if (user_domain != enterprise_domain) { 314 SetError("User domain " + user_domain + " and Enterprise domain " + 315 enterprise_domain + " don't match"); 316 SendResponse(false); 317 return false; 318 } 319 320 // Check if RA is enabled in the device policy. 321 GetDeviceAttestationEnabled( 322 base::Bind(&EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback, 323 this, 324 challenge, 325 params->register_key, 326 user_domain, 327 false)); // user consent is not required. 328 } else { 329 // For personal devices, we don't need to check if RA is enabled in the 330 // device, but we need to ask for user consent if the key does not exist. 331 GetDeviceAttestationEnabledCallback( 332 challenge, 333 params->register_key, 334 user_domain, 335 true, // user consent is required. 336 true); // attestation is enabled. 337 } 338 339 return true; 340} 341 342void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback( 343 const std::string& challenge, 344 bool register_key, 345 const std::string& domain, 346 bool require_user_consent, 347 bool enabled) { 348 if (!enabled) { 349 SetError("Remote attestation is not enabled for your device."); 350 SendResponse(false); 351 return; 352 } 353 354 PrepareKey(chromeos::attestation::KEY_USER, 355 kKeyName, 356 chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE, 357 require_user_consent, 358 base::Bind(&EPKPChallengeUserKey::PrepareKeyCallback, this, 359 challenge, register_key, domain)); 360} 361 362void EPKPChallengeUserKey::PrepareKeyCallback(const std::string& challenge, 363 bool register_key, 364 const std::string& domain, 365 PrepareKeyResult result) { 366 if (result != PREPARE_KEY_OK) { 367 SetError(base::StringPrintf( 368 "Cannot get a key to sign the challenge. Error code = %d", result)); 369 SendResponse(false); 370 return; 371 } 372 373 // Everything is checked. Sign the challenge. 374 async_caller_->TpmAttestationSignEnterpriseChallenge( 375 chromeos::attestation::KEY_USER, 376 kKeyName, 377 domain, 378 GetDeviceId(), 379 register_key ? 380 chromeos::attestation::CHALLENGE_INCLUDE_SIGNED_PUBLIC_KEY : 381 chromeos::attestation::CHALLENGE_OPTION_NONE, 382 challenge, 383 base::Bind(&EPKPChallengeUserKey::SignChallengeCallback, this, 384 register_key)); 385} 386 387void EPKPChallengeUserKey::SignChallengeCallback(bool register_key, 388 bool success, 389 const std::string& response) { 390 if (!success) { 391 SetError("Challenge failed."); 392 SendResponse(false); 393 return; 394 } 395 396 if (register_key) { 397 async_caller_->TpmAttestationRegisterKey( 398 chromeos::attestation::KEY_USER, 399 kKeyName, 400 base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response)); 401 } else { 402 RegisterKeyCallback(response, true, cryptohome::MOUNT_ERROR_NONE); 403 } 404} 405 406void EPKPChallengeUserKey::RegisterKeyCallback( 407 const std::string& response, 408 bool success, 409 cryptohome::MountError return_code) { 410 if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) { 411 SetError("Key registration failed."); 412 SendResponse(false); 413 return; 414 } 415 416 std::string encoded_response; 417 if (!base::Base64Encode(response, &encoded_response)) { 418 SetError("Response cannot be encoded in base64."); 419 SendResponse(false); 420 return; 421 } 422 423 results_ = api_epkp::ChallengeUserKey::Results::Create(encoded_response); 424 SendResponse(true); 425} 426 427bool EPKPChallengeUserKey::IsExtensionWhitelisted() const { 428 const base::ListValue* list = 429 profile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist); 430 StringValue value(extension_->id()); 431 return list->Find(value) != list->end(); 432} 433 434bool EPKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const { 435 return profile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled); 436} 437 438std::string EPKPChallengeUserKey::GetUserDomain() const { 439 SigninManagerBase* signin_manager = 440 SigninManagerFactory::GetForProfile(profile()); 441 if (!signin_manager) 442 return std::string(); 443 444 return gaia::ExtractDomainName( 445 gaia::CanonicalizeEmail(signin_manager->GetAuthenticatedUsername())); 446} 447 448} // namespace extensions 449