Implement Enterprise Key API.

Proposal: https://docs.google.com/a/google.com/document/d/1KxtQCk4SJdAZId8WxtnCxR3kS2KvhFDsU0SdAeP18Xc/edit

The logic of the API is implemented. Add prefernces and policies are added.
The underlying cryptohome_client will be implemented in another CL.

BUG=chromium:219963
TEST=unit_tests

Review URL: https://chromiumcodereview.appspot.com/13132004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@195043 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 6a129369..dad016ad 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -112,7 +112,7 @@
 #   persistent IDs for all fields (but not for groups!) are needed. These are
 #   specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
 #   because doing so would break the deployed wire format!
-#   For your editing convenience: highest ID currently used: 199
+#   For your editing convenience: highest ID currently used: 201
 #
 # Placeholders:
 #   The following placeholder strings are automatically substituted:
@@ -4520,6 +4520,49 @@
 
       If not specified, will not modify the Variations seed URL.''',
     },
+    {
+      'name': 'Attestation',
+      'type': 'group',
+      'caption': 'Remote Attestation',
+      'desc': 'Configure the remote attestation with TPM mechanism.',
+      'policies': [
+        {
+          'name': 'AttestationEnabledForUser',
+          'type': 'main',
+          'schema': { 'type': 'boolean' },
+          'supported_on': ['chrome_os:28-'],
+          'features': {
+            'dynamic_refresh': True,
+            'per_profile': True,
+          },
+          'example_value': True,
+          'id': 200,
+          'caption': '''Enable remote attestation for the user.''',
+          'desc': '''If true, the user can use the hardware on Chrome devices to remote attest its identity to the privacy CA via the Enterprise Platform Keys API chrome.enterprise.platformKeysPrivate.challengeUserKey().
+
+          If it is set to false, or if it is not set, calls to the API will fail with an error code.''',
+        },
+        {
+          'name': 'AttestationExtensionWhitelist',
+          'type': 'list',
+          'schema': {
+            'type': 'array',
+            'items': { 'type': 'string' },
+          },
+          'supported_on': ['chrome_os:28-'],
+          'features': {
+            'dynamic_refresh': True,
+            'per_profile': True,
+          },
+          'example_value': ['ghdilpkmfbfdnomkmaiogjhjnggaggoi'],
+          'id': 201,
+          'caption': '''Extensions allowed to to use the remote attestation API.''',
+          'desc': '''This policy specifies the allowed extensions to use Enterprise Platform Keys API chrome.enterprise.platformKeysPrivate.challengeUserKey() for remote attestation. Extensions must be added to this list to use the API.
+
+          If an extension is not in the list, or the list is not set, the call to the API will fail with an error code.''',
+        },
+      ],
+    },
   ],
   'messages': {
     # Messages that are not associated to any policies.
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.cc b/chrome/browser/chromeos/settings/cros_settings_names.cc
index 6d9989c..7a0a93b 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.cc
+++ b/chrome/browser/chromeos/settings/cros_settings_names.cc
@@ -120,4 +120,7 @@
 // when pinging the Variations server.
 const char kVariationsRestrictParameter[] =
     "cros.variations_restrict_parameter";
+
+// A boolean pref that indicates whether attestation is enabled for the device.
+const char kDeviceAttestationEnabled[] = "cros.device.attestation_enabled";
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.h b/chrome/browser/chromeos/settings/cros_settings_names.h
index 67b0592..72810555 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.h
+++ b/chrome/browser/chromeos/settings/cros_settings_names.h
@@ -60,6 +60,8 @@
 extern const char kKioskDisableBailoutShortcut[];
 
 extern const char kVariationsRestrictParameter[];
+
+extern const char kDeviceAttestationEnabled[];
 }  // namespace chromeos
 
 #endif  // CHROME_BROWSER_CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
new file mode 100644
index 0000000..336dbf6
--- /dev/null
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -0,0 +1,340 @@
+// 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_platform_keys_private/enterprise_platform_keys_private_api.h"
+
+#include <string>
+
+#include "base/base64.h"
+#include "base/callback.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/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/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_platform_keys_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 "google_apis/gaia/gaia_auth_util.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace extensions {
+
+namespace api_epkp = api::enterprise_platform_keys_private;
+
+// Base class
+
+EPKPChallengeKeyBase::EPKPChallengeKeyBase()
+    : cryptohome_client_(
+          chromeos::DBusThreadManager::Get()->GetCryptohomeClient()),
+      async_caller_(cryptohome::AsyncMethodCaller::GetInstance()),
+      install_attributes_(g_browser_process->browser_policy_connector()->
+                          GetInstallAttributes()) {
+}
+
+EPKPChallengeKeyBase::~EPKPChallengeKeyBase() {
+}
+
+void EPKPChallengeKeyBase::GetDeviceAttestationEnabled(
+    const base::Callback<void(bool)>& callback) const {
+  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
+  chromeos::CrosSettingsProvider::TrustedStatus status =
+      settings->PrepareTrustedValues(
+          base::Bind(&EPKPChallengeKeyBase::GetDeviceAttestationEnabled, this,
+                     callback));
+
+  bool value = false;
+  switch (status) {
+    case chromeos::CrosSettingsProvider::TRUSTED:
+      if (!settings->GetBoolean(chromeos::kDeviceAttestationEnabled, &value))
+        value = false;
+      break;
+    case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
+      // Do nothing. This function will be called again when the values are
+      // ready.
+      return;
+    case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
+      // If the value cannot be trusted, we assume that the device attestation
+      // is false to be on the safe side.
+      break;
+  }
+
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, value));
+}
+
+bool EPKPChallengeKeyBase::IsEnterpriseDevice() const {
+  return install_attributes_->IsEnterpriseDevice();
+}
+
+std::string EPKPChallengeKeyBase::GetEnterpriseDomain() const {
+  return install_attributes_->GetDomain();
+}
+
+std::string EPKPChallengeKeyBase::GetDeviceId() const {
+  return install_attributes_->GetDeviceId();
+}
+
+// Implementation of ChallengeMachineKey()
+
+const char EPKPChallengeMachineKey::kKeyName[] = "attest-ent-machine";
+
+EPKPChallengeMachineKey::~EPKPChallengeMachineKey() {
+}
+
+bool EPKPChallengeMachineKey::RunImpl() {
+  scoped_ptr<api_epkp::ChallengeMachineKey::Params>
+      params(api_epkp::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.
+  GetDeviceAttestationEnabled(
+      base::Bind(&EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback,
+                 this, challenge));
+
+  return true;
+}
+
+void EPKPChallengeMachineKey::GetDeviceAttestationEnabledCallback(
+    const std::string& challenge, bool enabled) {
+  if (!enabled) {
+    SetError("Remote attestation is not enabled for your device.");
+    SendResponse(false);
+    return;
+  }
+
+  // Everything is checked. Sign the challenge.
+  async_caller_->TpmAttestationSignEnterpriseChallenge(
+      chromeos::CryptohomeClient::DEVICE_KEY,
+      kKeyName,
+      GetEnterpriseDomain(),
+      GetDeviceId(),
+      chromeos::CryptohomeClient::CHALLENGE_RESPONSE_OPTION_NONE,
+      challenge,
+      base::Bind(&EPKPChallengeMachineKey::SignChallengeCallback, this));
+}
+
+void EPKPChallengeMachineKey::SignChallengeCallback(
+    bool success, const std::string& response) {
+  if (!success) {
+    SetError("Challenge failed.");
+    SendResponse(false);
+    return;
+  }
+
+  std::string encoded_response;
+  if (!base::Base64Encode(response, &encoded_response)) {
+    SetError("Response cannot be encoded in base64.");
+    SendResponse(false);
+    return;
+  }
+
+  results_ = api_epkp::ChallengeMachineKey::Results::Create(encoded_response);
+  SendResponse(true);
+}
+
+// Implementation of ChallengeUserKey()
+
+const char EPKPChallengeUserKey::kKeyName[] = "attest-ent-user";
+
+EPKPChallengeUserKey::~EPKPChallengeUserKey() {
+}
+
+void EPKPChallengeUserKey::RegisterUserPrefs(PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(prefs::kAttestationEnabled, false,
+                                PrefRegistrySyncable::UNSYNCABLE_PREF);
+  registry->RegisterListPref(prefs::kAttestationExtensionWhitelist,
+                             PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+bool EPKPChallengeUserKey::RunImpl() {
+  scoped_ptr<api_epkp::ChallengeUserKey::Params> params(
+      api_epkp::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 the user domain is the same as the enrolled enterprise domain.
+    std::string enterprise_domain = GetEnterpriseDomain();
+    if (user_domain != enterprise_domain) {
+      SetError("User domain " + user_domain + " and Enterprise domain " +
+               enterprise_domain + " don't match");
+      SendResponse(false);
+      return false;
+    }
+
+    // Check if RA is enabled in the device policy.
+    GetDeviceAttestationEnabled(
+        base::Bind(&EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback,
+                   this, challenge, params->register_key, user_domain));
+  } else {
+    // If this is a personal device, we should explicitly ask the user before
+    // we use the key.
+    AskForUserConsent(
+        base::Bind(&EPKPChallengeUserKey::UserConsentCallback, this,
+                   challenge, params->register_key, user_domain));
+  }
+
+  return true;
+}
+
+void EPKPChallengeUserKey::GetDeviceAttestationEnabledCallback(
+    const std::string& challenge,
+    bool register_key,
+    const std::string& domain,
+    bool enabled) {
+  if (!enabled) {
+    SetError("Remote attestation is not enabled for your device.");
+    SendResponse(false);
+    return;
+  }
+
+  // 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(&EPKPChallengeUserKey::UserConsentCallback, this,
+                 challenge, register_key, domain, true));
+}
+
+void EPKPChallengeUserKey::UserConsentCallback(const std::string& challenge,
+                                               bool register_key,
+                                               const std::string& domain,
+                                               bool action) {
+  if (!action) {
+      SetError("User rejects the action.");
+      SendResponse(false);
+      return;
+  }
+
+  // Everything is checked. Sign the challenge.
+  async_caller_->TpmAttestationSignEnterpriseChallenge(
+      chromeos::CryptohomeClient::USER_KEY,
+      kKeyName,
+      domain,
+      GetDeviceId(),
+      register_key ? chromeos::CryptohomeClient::INCLUDE_SIGNED_PUBLIC_KEY :
+          chromeos::CryptohomeClient::CHALLENGE_RESPONSE_OPTION_NONE,
+      challenge,
+      base::Bind(&EPKPChallengeUserKey::SignChallengeCallback, this,
+                 register_key));
+}
+
+void EPKPChallengeUserKey::SignChallengeCallback(bool register_key,
+                                                 bool success,
+                                                 const std::string& response) {
+  if (!success) {
+    SetError("Challenge failed.");
+    SendResponse(false);
+    return;
+  }
+
+  if (register_key) {
+    async_caller_->TpmAttestationRegisterKey(
+        chromeos::CryptohomeClient::USER_KEY,
+        kKeyName,
+        base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this, response));
+  } else {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&EPKPChallengeUserKey::RegisterKeyCallback, this,
+                   response, true, cryptohome::MOUNT_ERROR_NONE));
+  }
+}
+
+void EPKPChallengeUserKey::RegisterKeyCallback(
+    const std::string& response,
+    bool success,
+    cryptohome::MountError return_code) {
+  if (!success || return_code != cryptohome::MOUNT_ERROR_NONE) {
+    SetError("Key registration failed.");
+    SendResponse(false);
+    return;
+  }
+
+  std::string encoded_response;
+  if (!base::Base64Encode(response, &encoded_response)) {
+    SetError("Response cannot be encoded in base64.");
+    SendResponse(false);
+    return;
+  }
+
+  results_ = api_epkp::ChallengeUserKey::Results::Create(encoded_response);
+  SendResponse(true);
+}
+
+void EPKPChallengeUserKey::AskForUserConsent(
+    const base::Callback<void(bool)>& callback) {
+  // TODO(davidyu): right now we just simply reject the request before we have
+  // a way to ask for user consent.
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, false));
+}
+
+bool EPKPChallengeUserKey::IsExtensionWhitelisted() const {
+  const base::ListValue* list =
+      profile()->GetPrefs()->GetList(prefs::kAttestationExtensionWhitelist);
+  StringValue value(extension_->id());
+  return list->Find(value) != list->end();
+}
+
+bool EPKPChallengeUserKey::IsRemoteAttestationEnabledForUser() const {
+  return profile()->GetPrefs()->GetBoolean(prefs::kAttestationEnabled);
+}
+
+std::string EPKPChallengeUserKey::GetUserDomain() const {
+  SigninManager* signin_manager =
+      SigninManagerFactory::GetForProfile(profile());
+  if (!signin_manager)
+    return "";
+
+  return gaia::ExtractDomainName(
+      gaia::CanonicalizeEmail(signin_manager->GetAuthenticatedUsername()));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
new file mode 100644
index 0000000..a0194a2c
--- /dev/null
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
@@ -0,0 +1,123 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_PLATFORM_KEYS_PRIVATE_ENTERPRISE_PLATFORM_KEYS_PRIVATE_API_H__
+#define CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_PLATFORM_KEYS_PRIVATE_ENTERPRISE_PLATFORM_KEYS_PRIVATE_API_H__
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/extensions/api/enterprise_platform_keys_private.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+class PrefRegistrySyncable;
+class PrefService;
+
+namespace chromeos {
+class CryptohomeClient;
+}  // namespace chromeos
+
+namespace cryptohome {
+class AsyncMethodCaller;
+}  // namespace cryptohome
+
+namespace policy {
+class EnterpriseInstallAttributes;
+}  // namespace policy
+
+namespace extensions {
+
+class EPKPChallengeKeyBase : public AsyncExtensionFunction {
+ protected:
+  EPKPChallengeKeyBase();
+  virtual ~EPKPChallengeKeyBase();
+
+  // Returns a trusted value from CroSettings indicating if the device
+  // attestation is enabled.
+  void GetDeviceAttestationEnabled(
+      const base::Callback<void(bool)>& callback) const;
+
+  // Returns true if the device is enterprise managed.
+  bool IsEnterpriseDevice() const;
+
+  // Returns the enterprise domain the device is enrolled to.
+  std::string GetEnterpriseDomain() const;
+
+  // Returns the enterprise virtual device ID.
+  std::string GetDeviceId() const;
+
+  chromeos::CryptohomeClient* cryptohome_client_;
+  cryptohome::AsyncMethodCaller* async_caller_;
+
+ private:
+  policy::EnterpriseInstallAttributes* install_attributes_;
+};
+
+class EPKPChallengeMachineKey : public EPKPChallengeKeyBase {
+ protected:
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  static const char kKeyName[];
+
+  virtual ~EPKPChallengeMachineKey();
+
+  void GetDeviceAttestationEnabledCallback(const std::string& challenge,
+                                           bool enabled);
+  void SignChallengeCallback(bool success, const std::string& response);
+
+  DECLARE_EXTENSION_FUNCTION(
+      "enterprise.platformKeysPrivate.challengeMachineKey",
+      ENTERPRISE_PLATFORMKEYSPRIVATE_CHALLENGEMACHINEKEY);
+};
+
+typedef EPKPChallengeMachineKey
+    EnterprisePlatformKeysPrivateChallengeMachineKeyFunction;
+
+class EPKPChallengeUserKey : public EPKPChallengeKeyBase {
+ public:
+  static void RegisterUserPrefs(PrefRegistrySyncable* registry);
+
+ protected:
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  static const char kKeyName[];
+
+  virtual ~EPKPChallengeUserKey();
+
+  void GetDeviceAttestationEnabledCallback(const std::string& challenge,
+                                           bool register_key,
+                                           const std::string& domain,
+                                           bool enabled);
+  void UserConsentCallback(const std::string& challenge,
+                           bool register_key,
+                           const std::string& domain,
+                           bool action);
+  void SignChallengeCallback(bool register_key,
+                             bool success,
+                             const std::string& response);
+  void RegisterKeyCallback(const std::string& response,
+                           bool success,
+                           cryptohome::MountError return_code);
+
+  void AskForUserConsent(const base::Callback<void(bool)>& callback);
+  bool IsExtensionWhitelisted() const;
+  bool IsRemoteAttestationEnabledForUser() const;
+  std::string GetUserDomain() const;
+
+  DECLARE_EXTENSION_FUNCTION(
+      "enterprise.platformKeysPrivate.challengeUserKey",
+      ENTERPRISE_PLATFORMKEYSPRIVATE_CHALLENGEUSERKEY);
+};
+
+typedef EPKPChallengeUserKey
+    EnterprisePlatformKeysPrivateChallengeUserKeyFunction;
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_ENTERPRISE_PLATFORM_KEYS_PRIVATE_ENTERPRISE_PLATFORM_KEYS_PRIVATE_API_H__
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index 91c244e..0d0fa22 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -503,6 +503,8 @@
   APP_CURRENTWINDOWINTERNAL_FULLSCREEN,
   DEVELOPERPRIVATE_LOADUNPACKEDCROS,
   NETWORKINGPRIVATE_REQUESTNETWORKSCAN,
+  ENTERPRISE_PLATFORMKEYSPRIVATE_CHALLENGEMACHINEKEY,
+  ENTERPRISE_PLATFORMKEYSPRIVATE_CHALLENGEUSERKEY,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list.cc b/chrome/browser/policy/configuration_policy_handler_list.cc
index 7465b76c..4c071fd 100644
--- a/chrome/browser/policy/configuration_policy_handler_list.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list.cc
@@ -374,6 +374,9 @@
   { key::kRebootAfterUpdate,
     prefs::kRebootAfterUpdate,
     Value::TYPE_BOOLEAN },
+  { key::kAttestationEnabledForUser,
+    prefs::kAttestationEnabled,
+    Value::TYPE_BOOLEAN },
 #endif  // defined(OS_CHROMEOS)
 
 #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS)
@@ -432,6 +435,12 @@
           key::kExtensionAllowedTypes, prefs::kExtensionAllowedTypes,
           kExtensionAllowedTypesMap,
           kExtensionAllowedTypesMap + arraysize(kExtensionAllowedTypesMap)));
+#if defined(OS_CHROMEOS)
+  handlers_.push_back(
+      new ExtensionListPolicyHandler(key::kAttestationExtensionWhitelist,
+                                     prefs::kAttestationExtensionWhitelist,
+                                     false));
+#endif  // defined(OS_CHROMEOS)
 
 #if !defined(OS_CHROMEOS)
   handlers_.push_back(new DownloadDirPolicyHandler());
diff --git a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
index f91c87e..507c118 100644
--- a/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
+++ b/chrome/browser/policy/configuration_policy_pref_store_unittest.cc
@@ -308,7 +308,9 @@
         PolicyAndPref(key::kAudioOutputAllowed,
                       prefs::kAudioOutputAllowed),
         PolicyAndPref(key::kAudioCaptureAllowed,
-                      prefs::kAudioCaptureAllowed)));
+                      prefs::kAudioCaptureAllowed),
+        PolicyAndPref(key::kAttestationEnabledForUser,
+                      prefs::kAttestationEnabled)));
 #endif  // defined(OS_CHROMEOS)
 
 // Test cases for integer-valued policy settings.
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 52389b2..611914f1 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -133,6 +133,7 @@
 #include "chrome/browser/chromeos/settings/device_settings_cache.h"
 #include "chrome/browser/chromeos/status/data_promo_notification.h"
 #include "chrome/browser/chromeos/system/automatic_reboot_manager.h"
+#include "chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h"
 #else
 #include "chrome/browser/extensions/default_apps.h"
 #endif
@@ -354,6 +355,8 @@
   chromeos::OAuth2LoginManager::RegisterUserPrefs(registry);
   chromeos::Preferences::RegisterUserPrefs(registry);
   chromeos::ProxyConfigServiceImpl::RegisterUserPrefs(registry);
+  extensions::EnterprisePlatformKeysPrivateChallengeUserKeyFunction::
+      RegisterUserPrefs(registry);
   FlagsUI::RegisterUserPrefs(registry);
 #endif
 
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 84a6c0a0..d67de53 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -754,6 +754,8 @@
             'browser/extensions/default_apps.h',
           ],
           'sources': [
+            'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc',
+            'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h',
             'browser/extensions/api/input_ime/input_ime_api.cc',
             'browser/extensions/api/input_ime/input_ime_api.h',
             'browser/extensions/api/rtc_private/rtc_private_api.cc',
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 4d7e941..77263ba 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -154,6 +154,12 @@
       "16CA7A47AAE4BE49B1E75A6B960C3875E945B264"   // Release
     ]
   },
+  "enterprise.platformKeysPrivate": {
+    "channel": "dev",
+    "extension_types": ["extension", "packaged_app"],
+    "whitelist": [
+    ]
+  },
   "experimental": {
     "channel": "stable",
     "extension_types": [
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index a89e95c..d7020623 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -38,6 +38,7 @@
           'downloads.idl',
           'echo_private.json',
           'downloads_internal.idl',
+          'enterprise_platform_keys_private.json',
           'events.json',
           'experimental_accessibility.json',
           'experimental_discovery.idl',
diff --git a/chrome/common/extensions/api/enterprise_platform_keys_private.json b/chrome/common/extensions/api/enterprise_platform_keys_private.json
new file mode 100644
index 0000000..483586c
--- /dev/null
+++ b/chrome/common/extensions/api/enterprise_platform_keys_private.json
@@ -0,0 +1,67 @@
+// 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.
+
+[
+  {
+    "namespace": "enterprise.platformKeysPrivate",
+    "nodoc": true,
+    "platforms": ["chromeos"],
+    "types": [],
+    "functions": [
+      {
+        "name": "challengeMachineKey",
+        "type": "function",
+        "description": "Challenge a machine key.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "challenge",
+            "description": "Challenge to be signed in base64."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "description": "Callback function.",
+            "parameters": [
+              {
+                "name": "response",
+                "description": "Response in base64.",
+                "type": "string"
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "challengeUserKey",
+        "type": "function",
+        "description": "Challenge an user key.",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "challenge",
+            "description": "Challenge to be signed in base64."
+          },
+          {
+            "type": "boolean",
+            "name": "registerKey",
+            "description": "If true, the key will be registered."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "description": "Callback function.",
+            "parameters": [
+              {
+                "name": "response",
+                "description": "Response in base64.",
+                "type": "string"
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  }
+]
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index f9719f3..7500e002 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -66,6 +66,7 @@
     kDownloads,
     kDownloadsInternal,
     kEchoPrivate,
+    kEnterprisePlatformKeysPrivate,
     kExperimental,
     kFileBrowserHandler,
     kFileBrowserHandlerInternal,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 531fc79..a9abe97 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -165,6 +165,9 @@
       APIPermissionInfo::kFlagCannotBeOptional },
     { APIPermission::kStreamsPrivate, "streamsPrivate",
       APIPermissionInfo::kFlagCannotBeOptional },
+    { APIPermission::kEnterprisePlatformKeysPrivate,
+      "enterprise.platformKeysPrivate",
+      APIPermissionInfo::kFlagCannotBeOptional },
 
     // Full url access permissions.
     { APIPermission::kDebugger, "debugger",
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 4b23daf..e71db7ed 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -719,6 +719,7 @@
   skip.insert(APIPermission::kDial);
   skip.insert(APIPermission::kDownloadsInternal);
   skip.insert(APIPermission::kEchoPrivate);
+  skip.insert(APIPermission::kEnterprisePlatformKeysPrivate);
   skip.insert(APIPermission::kFileBrowserHandlerInternal);
   skip.insert(APIPermission::kFileBrowserPrivate);
   skip.insert(APIPermission::kInputMethodPrivate);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 9d275e7..820868f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -871,6 +871,12 @@
 // show a warning indicating that the organization may track the browsing
 // session.
 const char kUsedPolicyCertificatesOnce[] = "used_policy_certificates_once";
+
+// Indicates whether the remote attestation is enabled for the user.
+const char kAttestationEnabled[] = "attestation.enabled";
+// The list of extensions allowed to use the platformKeysPrivate API for
+// remote attestation.
+const char kAttestationExtensionWhitelist[] = "attestation.extension_whitelist";
 #endif  // defined(OS_CHROMEOS)
 
 // The disabled messages in IPC logging.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 534b899f..222af2d 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -313,6 +313,8 @@
 extern const char kPowerPresentationIdleDelayFactor[];
 extern const char kTermsOfServiceURL[];
 extern const char kUsedPolicyCertificatesOnce[];
+extern const char kAttestationEnabled[];
+extern const char kAttestationExtensionWhitelist[];
 #endif  // defined(OS_CHROMEOS)
 extern const char kIpcDisabledMessages[];
 extern const char kShowHomeButton[];
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 9df2eff..460b11b16 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1735,6 +1735,22 @@
     ]
   },
 
+  "AttestationEnabledForUser": {
+    "os": ["chromeos"],
+    "test_policy": { "AttestationEnabledForUser": true },
+    "pref_mappings": [
+      { "pref": "attestation.enabled" }
+    ]
+  },
+
+  "AttestationExtensionWhitelist": {
+    "os": ["chromeos"],
+    "test_policy": { "AttestationExtensionWhitelist": ["test_ext_id1", "test_ext_id2"] },
+    "pref_mappings": [
+      { "pref": "attestation.extension_whitelist" }
+    ]
+  },
+
   "----- Chrome OS device policies ---------------------------------------": {},
 
   "DevicePolicyRefreshRate": {