Home | History | Annotate | Download | only in enterprise_platform_keys_private
      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