Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(945)

Unified Diff: chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.cc

Issue 13132004: Implement Enterprise Key API. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.cc
diff --git a/chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.cc b/chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.cc
new file mode 100644
index 0000000000000000000000000000000000000000..68d4fa3f79a568f6c41c0ac06acb3c430e79569d
--- /dev/null
+++ b/chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.cc
@@ -0,0 +1,367 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/enterprise_enterprise_key_private/enterprise_enterprise_key_private_api.h"
+
+#include <string>
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 newline
davidyu 2013/04/09 09:30:08 Done.
+#include "base/base64.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/prefs/pref_service.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/cryptohome_library.h"
+#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/cros_settings_names.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/common/extensions/api/enterprise_enterprise_key_private.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/cryptohome/async_method_caller.h"
+#include "chromeos/dbus/cryptohome_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "components/user_prefs/pref_registry_syncable.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace extensions {
+
+namespace api_eekp = api::enterprise_enterprise_key_private;
+
+// Base
+
+const char* EEKPChallengeKeyBase::kKeyName = "attest-ent-default";
+
+EEKPChallengeKeyBase::EEKPChallengeKeyBase()
+ : cryptohome_client_(
+ chromeos::DBusThreadManager::Get()->GetCryptohomeClient()),
+ async_caller_(cryptohome::AsyncMethodCaller::GetInstance()) {
+ chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
+ chromeos::CryptohomeLibrary* cryptohome =
+ cros_library->GetCryptohomeLibrary();
+ install_attributes_ = new policy::EnterpriseInstallAttributes(cryptohome);
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 Please use the instance that you can retrieve from
davidyu 2013/04/09 09:30:08 Done.
+}
+
+EEKPChallengeKeyBase::~EEKPChallengeKeyBase() {
+ delete install_attributes_;
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 This should have been wrapped in a scoped_ptr, but
davidyu 2013/04/09 09:30:08 Done.
+}
+
+bool EEKPChallengeKeyBase::IsRemoteAttestationEnabledForDevice() const {
+ chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+ bool value;
+ return settings->GetBoolean(chromeos::kDeviceAttestationEnabled, &value) &&
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 This should probably retrieve the trusted value, s
davidyu 2013/04/09 09:30:08 Done.
+ value;
+}
+
+bool EEKPChallengeKeyBase::IsEnterpriseDevice() const {
+ return install_attributes_->IsEnterpriseDevice();
+}
+
+std::string EEKPChallengeKeyBase::GetEnterpriseDomain() const {
+ return install_attributes_->GetDomain();
+}
+
+std::string EEKPChallengeKeyBase::GetDeviceId() const {
+ return install_attributes_->GetDeviceId();
+}
+
+// ChallengeMachineKey()
+
+EEKPChallengeMachineKey::EEKPChallengeMachineKey()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
+}
+
+EEKPChallengeMachineKey::~EEKPChallengeMachineKey() {
+}
+
+bool EEKPChallengeMachineKey::RunImpl() {
+ scoped_ptr<api_eekp::ChallengeMachineKey::Params>
+ params(api_eekp::ChallengeMachineKey::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ std::string challenge;
+ if (!base::Base64Decode(params->challenge, &challenge)) {
+ SetError("Challenge is not base64 encoded.");
+ SendResponse(false);
+ return false;
+ }
+
+ // Check if the device is enterprise enrolled.
+ if (!IsEnterpriseDevice()) {
+ SetError("The device is not enterprise enrolled.");
+ SendResponse(false);
+ return false;
+ }
+
+ // Check if RA is enabled in the device policy.
+ if (!IsRemoteAttestationEnabledForDevice()) {
+ SetError("Remote attestation is not enabled for your device.");
+ SendResponse(false);
+ return false;
+ }
+
+ LOG(ERROR) << "About to call TpmAttestationSignEnterpriseChallenge()";
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 DVLOG would be more appropriate.
davidyu 2013/04/09 09:30:08 Removed.
+ async_caller_->TpmAttestationSignEnterpriseChallenge(
+ chromeos::CryptohomeClient::DEVICE_KEY,
+ kKeyName,
+ GetEnterpriseDomain(),
+ GetDeviceId(),
+ challenge,
+ base::Bind(&EEKPChallengeMachineKey::SignChallengeCallback,
+ weak_factory_.GetWeakPtr()));
+
+ AddRef();
+ return true;
+}
+
+void EEKPChallengeMachineKey::SignChallengeCallback(
+ bool success, const std::string& response) {
+ LOG(ERROR) << "TpmAttestationSignEnterpriseChallenge() returned";
+ if (!success) {
+ SetError("Challenge failed.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ std::string encoded_response;
+ if (!base::Base64Encode(response, &encoded_response)) {
+ SetError("Response cannot be encoded in base64.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ results_ = api_eekp::ChallengeMachineKey::Results::Create(encoded_response);
+ SendResponse(true);
+ Release();
+}
+
+// ChallengeUserKey()
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 huh?
davidyu 2013/04/09 09:30:08 I just want to say that the methods below are for
+
+EEKPChallengeUserKey::EEKPChallengeUserKey()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
+}
+
+EEKPChallengeUserKey::~EEKPChallengeUserKey() {
+}
+
+void EEKPChallengeUserKey::RegisterUserPrefs(PrefRegistrySyncable* registry) {
+ registry->RegisterBooleanPref(prefs::kAttestationEnabled, false,
+ PrefRegistrySyncable::UNSYNCABLE_PREF);
+ registry->RegisterListPref(prefs::kAttestationExtensionWhitelist,
+ PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+bool EEKPChallengeUserKey::RunImpl() {
+ scoped_ptr<api_eekp::ChallengeUserKey::Params> params(
+ api_eekp::ChallengeUserKey::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ std::string challenge;
+ if (!base::Base64Decode(params->challenge, &challenge)) {
+ SetError("Challenge is not base64 encoded.");
+ SendResponse(false);
+ return false;
+ }
+
+ // Check if RA is enabled in the user policy.
+ if (!IsRemoteAttestationEnabledForUser()) {
+ SetError("Remote attestation is not enabled for your account.");
+ SendResponse(false);
+ return false;
+ }
+
+ // Check if the extension is whitelisted in the user policy.
+ if (!IsExtensionWhitelisted()) {
+ SetError("The extension does not have permission to call this function.");
+ SendResponse(false);
+ return false;
+ }
+
+ std::string user_domain = GetUserDomain();
+
+ if (IsEnterpriseDevice()) {
+ // Check if RA is enabled in the device policy.
+ if (!IsRemoteAttestationEnabledForDevice()) {
+ SetError("Remote attestation is not enabled for your device.");
+ SendResponse(false);
+ return false;
+ }
+
+ // Check if the user domain is the same as the enrolled enterprise domain.
+ std::string enterprise_domain = GetEnterpriseDomain();
+ if (user_domain != GetEnterpriseDomain()) {
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 You could use BrowserPolicyConnector::GetUserAffil
davidyu 2013/04/09 09:30:08 I could. However, for personal devices, we still n
Mattias Nissler (ping if slow) 2013/04/10 16:53:25 Wait, this code only runs for enterprise devices,
davidyu 2013/04/11 07:04:21 Right. For this branch, it runs for enterprise dev
+ SetError("User domain " + user_domain + " and Enterprise domain " +
+ enterprise_domain + " don't match");
+ SendResponse(false);
+ return false;
+ }
+
+ // If remote attestation is enabled at the device level, we don't need to
+ // ask for user consent.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EEKPChallengeUserKey::UserConsentCallback,
+ weak_factory_.GetWeakPtr(),
+ params->challenge, params->register_key, user_domain, true));
+ } else {
+ // If this is a personal device, we should explicitly ask the user before
+ // we use the key.
+ AskForUserConsent(base::Bind(&EEKPChallengeUserKey::UserConsentCallback,
+ weak_factory_.GetWeakPtr(),
+ challenge, params->register_key, user_domain));
+ }
+
+ AddRef();
+ return true;
+}
+
+void EEKPChallengeUserKey::UserConsentCallback(const std::string& challenge,
+ bool register_key,
+ const std::string& domain,
+ bool action) {
+ if (!action) {
+ SetError("User rejects the action.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ async_caller_->TpmAttestationSignEnterpriseChallenge(
+ chromeos::CryptohomeClient::USER_KEY,
+ kKeyName,
+ domain,
+ GetDeviceId(),
+ challenge,
+ base::Bind(&EEKPChallengeUserKey::SignChallengeCallback,
+ weak_factory_.GetWeakPtr(),
+ register_key));
+}
+
+void EEKPChallengeUserKey::SignChallengeCallback(bool register_key,
+ bool success,
+ const std::string& response) {
+ if (!success) {
+ SetError("Challenge failed.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ if (register_key) {
+ cryptohome_client_->TpmAttestationGetPublicKey(
+ chromeos::CryptohomeClient::USER_KEY,
+ kKeyName,
+ base::Bind(&EEKPChallengeUserKey::GetPublicKeyCallback,
+ weak_factory_.GetWeakPtr(),
+ response));
+ } else {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&EEKPChallengeUserKey::RegisterKeyCallback,
+ weak_factory_.GetWeakPtr(),
+ response, "", true, cryptohome::MOUNT_ERROR_NONE));
+ }
+}
+
+void EEKPChallengeUserKey::GetPublicKeyCallback(
+ const std::string& response,
+ chromeos::DBusMethodCallStatus call_status,
+ bool result,
+ const std::string& public_key) {
+ if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS || !result) {
+ SetError("Cannot get public key.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ async_caller_->TpmAttestationRegisterKey(
+ chromeos::CryptohomeClient::USER_KEY,
+ kKeyName,
+ base::Bind(&EEKPChallengeUserKey::RegisterKeyCallback,
+ weak_factory_.GetWeakPtr(),
+ response, public_key));
+}
+
+void EEKPChallengeUserKey::RegisterKeyCallback(
+ const std::string& response,
+ const std::string& public_key,
+ bool success,
+ cryptohome::MountError return_code) {
+ if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) {
+ SetError("Key registration failed.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ std::string encoded_response, encoded_public_key;
+ if (!base::Base64Encode(response, &encoded_response)) {
+ SetError("Response cannot be encoded in base64.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ if (!base::Base64Encode(public_key, &encoded_public_key)) {
+ SetError("Public key cannot be encoded in base64.");
+ SendResponse(false);
+ Release();
+ return;
+ }
+
+ results_ = api_eekp::ChallengeUserKey::Results::Create(
+ encoded_response, encoded_public_key);
+ SendResponse(true);
+ Release();
+}
+
+void EEKPChallengeUserKey::AskForUserConsent(
+ const base::Callback<void(bool)>& callback) {
+ // TODO(davidyu): right now we just simply reject the request before we have
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 That'll make testing rather hard?
davidyu 2013/04/09 09:30:08 I'll fix this once we have a conclusion about how
+ // a way to ask for user consent.
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, false));
+}
+
+bool EEKPChallengeUserKey::IsExtensionWhitelisted() const {
+ const base::ListValue* list =
+ profile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist);
+ std::string id;
+ for (int i = 0; i < static_cast<int>(list->GetSize()); ++i) {
+ list->GetString(i, &id);
+ if (id == extension_->id()) {
Mattias Nissler (ping if slow) 2013/04/04 12:51:34 no need for braces for single-line conditional/bod
davidyu 2013/04/09 09:30:08 Done.
+ return true;
+ }
+ }
+ return false;
+}
+
+bool EEKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const {
+ return profile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
+}
+
+std::string EEKPChallengeUserKey::GetUserDomain() const {
+ SigninManager* signin_manager =
+ SigninManagerFactory::GetForProfile(profile());
+ if (!signin_manager) {
+ return "";
+ }
+
+ std::string email = signin_manager->GetAuthenticatedUsername();
+ std::string::size_type i = email.find('@');
+ if (i == std::string::npos) {
+ return "";
+ }
+
+ return email.substr(i + 1);
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698