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/pref_registry/pref_registry_syncable.h" 32 #include "components/signin/core/browser/signin_manager.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 555