Merge "attestation: Initial license file"
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..699d270
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+dkrahn@chromium.org
+namnguyen@chromium.org
diff --git a/attestation.gyp b/attestation.gyp
new file mode 100644
index 0000000..c89261a
--- /dev/null
+++ b/attestation.gyp
@@ -0,0 +1,178 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'target_defaults': {
+    'variables': {
+      'deps': [  # This is a list of pkg-config dependencies
+        'libchrome-<(libbase_ver)',
+        'libchromeos-<(libbase_ver)',
+        'protobuf-lite',
+      ],
+    },
+  },
+  'targets': [
+    # A library for just the protobufs.
+    {
+      'target_name': 'proto_library',
+      'type': 'static_library',
+      # Use -fPIC so this code can be linked into a shared library.
+      'cflags!': ['-fPIE'],
+      'cflags': [
+        '-fPIC',
+        '-fvisibility=default',
+      ],
+      'variables': {
+        'proto_in_dir': 'common',
+        'proto_out_dir': 'include/attestation/common',
+      },
+      'sources': [
+        '<(proto_in_dir)/attestation_ca.proto',
+        '<(proto_in_dir)/common.proto',
+        '<(proto_in_dir)/database.proto',
+        '<(proto_in_dir)/interface.proto',
+        'common/print_common_proto.cc',
+        'common/print_interface_proto.cc',
+      ],
+      'includes': ['../common-mk/protoc.gypi'],
+    },
+    # A library for common code.
+    {
+      'target_name': 'common_library',
+      'type': 'static_library',
+      'sources': [
+        'common/crypto_utility_impl.cc',
+        'common/tpm_utility_v1.cc',
+      ],
+      'all_dependent_settings': {
+        'variables': {
+          'deps': [
+            'openssl',
+          ],
+        },
+        'libraries': [
+          '-ltspi',
+        ],
+      },
+      'dependencies': [
+        'proto_library',
+      ],
+    },
+    # A library for client code.
+    {
+      'target_name': 'client_library',
+      'type': 'static_library',
+      # Use -fPIC so this code can be linked into a shared library.
+      'cflags!': ['-fPIE'],
+      'cflags': [
+        '-fPIC',
+        '-fvisibility=default',
+      ],
+      'sources': [
+        'client/dbus_proxy.cc',
+      ],
+      'dependencies': [
+        'proto_library',
+      ],
+    },
+    # A shared library for clients.
+    {
+      'target_name': 'libattestation',
+      'type': 'shared_library',
+      'cflags': ['-fvisibility=default'],
+      'sources': [
+      ],
+      'dependencies': [
+        'client_library',
+        'proto_library',
+      ],
+    },
+    # A client command line utility.
+    {
+      'target_name': 'attestation_client',
+      'type': 'executable',
+      'sources': [
+        'client/main.cc',
+      ],
+      'dependencies': [
+        'client_library',
+        'common_library',
+        'proto_library',
+      ]
+    },
+    # A library for server code.
+    {
+      'target_name': 'server_library',
+      'type': 'static_library',
+      'sources': [
+        'server/attestation_service.cc',
+        'server/dbus_service.cc',
+        'server/database_impl.cc',
+        'server/pkcs11_key_store.cc',
+      ],
+      'all_dependent_settings': {
+        'libraries': [
+          '-lchaps',
+        ],
+      },
+      'dependencies': [
+        'proto_library',
+      ],
+    },
+    # The attestation daemon.
+    {
+      'target_name': 'attestationd',
+      'type': 'executable',
+      'sources': [
+        'server/main.cc',
+      ],
+      'variables': {
+        'deps': [
+          'libminijail',
+        ],
+      },
+      'dependencies': [
+        'common_library',
+        'proto_library',
+        'server_library',
+      ],
+    },
+  ],
+  'conditions': [
+    ['USE_test == 1', {
+      'targets': [
+        {
+          'target_name': 'attestation_testrunner',
+          'type': 'executable',
+          'includes': ['../common-mk/common_test.gypi'],
+          'variables': {
+            'deps': [
+              'libchrome-test-<(libbase_ver)',
+              'libchromeos-test-<(libbase_ver)',
+            ],
+          },
+          'sources': [
+            'attestation_testrunner.cc',
+            'client/dbus_proxy_test.cc',
+            'common/crypto_utility_impl_test.cc',
+            'common/mock_crypto_utility.cc',
+            'common/mock_tpm_utility.cc',
+            'server/attestation_service_test.cc',
+            'server/database_impl_test.cc',
+            'server/dbus_service_test.cc',
+            'server/mock_database.cc',
+            'server/mock_key_store.cc',
+            'server/pkcs11_key_store_test.cc',
+          ],
+          'dependencies': [
+            'common_library',
+            'client_library',
+            'proto_library',
+            'server_library',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/attestation_testrunner.cc b/attestation_testrunner.cc
new file mode 100644
index 0000000..3380ea6
--- /dev/null
+++ b/attestation_testrunner.cc
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium OS 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 <base/at_exit.h>
+#include <base/command_line.h>
+#include <base/logging.h>
+#include <chromeos/syslog_logging.h>
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  base::CommandLine::Init(argc, argv);
+  chromeos::InitLog(chromeos::kLogToStderr);
+  // Enable verbose logging while running unit tests.
+  logging::SetMinLogLevel(logging::LOG_VERBOSE);
+  base::AtExitManager exit_manager;
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/client/dbus_proxy.cc b/client/dbus_proxy.cc
new file mode 100644
index 0000000..77fea34
--- /dev/null
+++ b/client/dbus_proxy.cc
@@ -0,0 +1,196 @@
+// Copyright 2015 The Chromium OS 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 "attestation/client/dbus_proxy.h"
+
+#include <chromeos/bind_lambda.h>
+#include <chromeos/dbus/dbus_method_invoker.h>
+
+#include "attestation/common/dbus_interface.h"
+
+namespace {
+
+// Use a two minute timeout because TPM operations can take a long time and
+// there may be a few of them queued up.
+const int kDBusTimeoutMS = 120000;
+
+}  // namespace
+
+namespace attestation {
+
+DBusProxy::DBusProxy() {}
+DBusProxy::~DBusProxy() {
+  if (bus_) {
+    bus_->ShutdownAndBlock();
+  }
+}
+
+bool DBusProxy::Initialize() {
+  dbus::Bus::Options options;
+  options.bus_type = dbus::Bus::SYSTEM;
+  bus_ = new dbus::Bus(options);
+  object_proxy_ = bus_->GetObjectProxy(
+      attestation::kAttestationServiceName,
+      dbus::ObjectPath(attestation::kAttestationServicePath));
+  return (object_proxy_ != nullptr);
+}
+
+void DBusProxy::CreateGoogleAttestedKey(
+    const CreateGoogleAttestedKeyRequest& request,
+    const CreateGoogleAttestedKeyCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    CreateGoogleAttestedKeyReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kCreateGoogleAttestedKey,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::GetKeyInfo(const GetKeyInfoRequest& request,
+                           const GetKeyInfoCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    GetKeyInfoReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kGetKeyInfo,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::GetEndorsementInfo(const GetEndorsementInfoRequest& request,
+                                   const GetEndorsementInfoCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    GetEndorsementInfoReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kGetEndorsementInfo,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::GetAttestationKeyInfo(
+    const GetAttestationKeyInfoRequest& request,
+    const GetAttestationKeyInfoCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    GetAttestationKeyInfoReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kGetAttestationKeyInfo,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::ActivateAttestationKey(
+    const ActivateAttestationKeyRequest& request,
+    const ActivateAttestationKeyCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    ActivateAttestationKeyReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kActivateAttestationKey,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::CreateCertifiableKey(
+    const CreateCertifiableKeyRequest& request,
+    const CreateCertifiableKeyCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    CreateCertifiableKeyReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kCreateCertifiableKey,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::Decrypt(const DecryptRequest& request,
+                        const DecryptCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    DecryptReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kDecrypt,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::Sign(const SignRequest& request, const SignCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    SignReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kSign,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+void DBusProxy::RegisterKeyWithChapsToken(
+    const RegisterKeyWithChapsTokenRequest& request,
+    const RegisterKeyWithChapsTokenCallback& callback) {
+  auto on_error = [callback](chromeos::Error* error) {
+    RegisterKeyWithChapsTokenReply reply;
+    reply.set_status(STATUS_NOT_AVAILABLE);
+    callback.Run(reply);
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
+      object_proxy_,
+      attestation::kAttestationInterface,
+      attestation::kRegisterKeyWithChapsToken,
+      callback,
+      base::Bind(on_error),
+      request);
+}
+
+}  // namespace attestation
diff --git a/client/dbus_proxy.h b/client/dbus_proxy.h
new file mode 100644
index 0000000..39dbc3f
--- /dev/null
+++ b/client/dbus_proxy.h
@@ -0,0 +1,65 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_CLIENT_DBUS_PROXY_H_
+#define ATTESTATION_CLIENT_DBUS_PROXY_H_
+
+#include "attestation/common/attestation_interface.h"
+
+#include <string>
+
+#include <base/memory/ref_counted.h>
+#include <dbus/bus.h>
+#include <dbus/object_proxy.h>
+
+namespace attestation {
+
+// An implementation of AttestationInterface that forwards requests over D-Bus.
+// Usage:
+//   std::unique_ptr<AttestationInterface> attestation = new DBusProxy();
+//   attestation->Initialize();
+//   attestation->CreateGoogleAttestedKey(...);
+class DBusProxy : public AttestationInterface {
+ public:
+  DBusProxy();
+  virtual ~DBusProxy();
+
+  // AttestationInterface methods.
+  bool Initialize() override;
+  void CreateGoogleAttestedKey(
+      const CreateGoogleAttestedKeyRequest& request,
+      const CreateGoogleAttestedKeyCallback& callback) override;
+  void GetKeyInfo(const GetKeyInfoRequest& request,
+                  const GetKeyInfoCallback& callback) override;
+  void GetEndorsementInfo(const GetEndorsementInfoRequest& request,
+                          const GetEndorsementInfoCallback& callback) override;
+  void GetAttestationKeyInfo(
+      const GetAttestationKeyInfoRequest& request,
+      const GetAttestationKeyInfoCallback& callback) override;
+  void ActivateAttestationKey(
+      const ActivateAttestationKeyRequest& request,
+      const ActivateAttestationKeyCallback& callback) override;
+  void CreateCertifiableKey(
+      const CreateCertifiableKeyRequest& request,
+      const CreateCertifiableKeyCallback& callback) override;
+  void Decrypt(const DecryptRequest& request,
+               const DecryptCallback& callback) override;
+  void Sign(const SignRequest& request, const SignCallback& callback) override;
+  void RegisterKeyWithChapsToken(
+      const RegisterKeyWithChapsTokenRequest& request,
+      const RegisterKeyWithChapsTokenCallback& callback) override;
+
+  // Useful for testing.
+  void set_object_proxy(dbus::ObjectProxy* object_proxy) {
+    object_proxy_ = object_proxy;
+  }
+
+ private:
+  scoped_refptr<dbus::Bus> bus_;
+  dbus::ObjectProxy* object_proxy_;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_CLIENT_DBUS_PROXY_H_
diff --git a/client/dbus_proxy_test.cc b/client/dbus_proxy_test.cc
new file mode 100644
index 0000000..19eb606
--- /dev/null
+++ b/client/dbus_proxy_test.cc
@@ -0,0 +1,402 @@
+// Copyright 2015 The Chromium OS 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 <string>
+
+#include <chromeos/bind_lambda.h>
+#include <dbus/mock_object_proxy.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "attestation/client/dbus_proxy.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::StrictMock;
+using testing::WithArgs;
+
+namespace attestation {
+
+class DBusProxyTest : public testing::Test {
+ public:
+  ~DBusProxyTest() override = default;
+  void SetUp() override {
+    mock_object_proxy_ = new StrictMock<dbus::MockObjectProxy>(
+        nullptr, "", dbus::ObjectPath(""));
+    proxy_.set_object_proxy(mock_object_proxy_.get());
+  }
+ protected:
+  scoped_refptr<StrictMock<dbus::MockObjectProxy>> mock_object_proxy_;
+  DBusProxy proxy_;
+};
+
+TEST_F(DBusProxyTest, CreateGoogleAttestedKey) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    CreateGoogleAttestedKeyRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ(KEY_TYPE_ECC, request_proto.key_type());
+    EXPECT_EQ(KEY_USAGE_SIGN, request_proto.key_usage());
+    EXPECT_EQ(ENTERPRISE_MACHINE_CERTIFICATE,
+              request_proto.certificate_profile());
+    EXPECT_EQ("user", request_proto.username());
+    EXPECT_EQ("origin", request_proto.origin());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    CreateGoogleAttestedKeyReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_certificate_chain("certificate");
+    reply_proto.set_server_error("server_error");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const CreateGoogleAttestedKeyReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("certificate", reply.certificate_chain());
+    EXPECT_EQ("server_error", reply.server_error());
+  };
+  CreateGoogleAttestedKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
+  request.set_username("user");
+  request.set_origin("origin");
+  proxy_.CreateGoogleAttestedKey(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, GetKeyInfo) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    GetKeyInfoRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ("username", request_proto.username());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    GetKeyInfoReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_key_type(KEY_TYPE_ECC);
+    reply_proto.set_key_usage(KEY_USAGE_SIGN);
+    reply_proto.set_public_key("public_key");
+    reply_proto.set_certify_info("certify_info");
+    reply_proto.set_certify_info_signature("signature");
+    reply_proto.set_certificate("certificate");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const GetKeyInfoReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(KEY_TYPE_ECC, reply.key_type());
+    EXPECT_EQ(KEY_USAGE_SIGN, reply.key_usage());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("signature", reply.certify_info_signature());
+    EXPECT_EQ("certificate", reply.certificate());
+  };
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  request.set_username("username");
+  proxy_.GetKeyInfo(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, GetEndorsementInfo) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    GetEndorsementInfoRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ(KEY_TYPE_ECC, request_proto.key_type());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    GetEndorsementInfoReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_ek_public_key("public_key");
+    reply_proto.set_ek_certificate("certificate");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const GetEndorsementInfoReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.ek_public_key());
+    EXPECT_EQ("certificate", reply.ek_certificate());
+  };
+  GetEndorsementInfoRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  proxy_.GetEndorsementInfo(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, GetAttestationKeyInfo) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    GetAttestationKeyInfoRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ(KEY_TYPE_ECC, request_proto.key_type());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    GetAttestationKeyInfoReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_public_key("public_key");
+    reply_proto.set_public_key_tpm_format("public_key_tpm_format");
+    reply_proto.set_certificate("certificate");
+    reply_proto.mutable_pcr0_quote()->set_quote("pcr0");
+    reply_proto.mutable_pcr1_quote()->set_quote("pcr1");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const GetAttestationKeyInfoReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("public_key_tpm_format", reply.public_key_tpm_format());
+    EXPECT_EQ("certificate", reply.certificate());
+    EXPECT_EQ("pcr0", reply.pcr0_quote().quote());
+    EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
+  };
+  GetAttestationKeyInfoRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  proxy_.GetAttestationKeyInfo(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, ActivateAttestationKey) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    ActivateAttestationKeyRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ(KEY_TYPE_ECC, request_proto.key_type());
+    EXPECT_EQ("encrypted1",
+              request_proto.encrypted_certificate().asym_ca_contents());
+    EXPECT_EQ("encrypted2",
+              request_proto.encrypted_certificate().sym_ca_attestation());
+    EXPECT_TRUE(request_proto.save_certificate());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    ActivateAttestationKeyReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_certificate("certificate");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const ActivateAttestationKeyReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("certificate", reply.certificate());
+  };
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(true);
+  proxy_.ActivateAttestationKey(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, CreateCertifiableKey) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    CreateCertifiableKeyRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ(KEY_TYPE_ECC, request_proto.key_type());
+    EXPECT_EQ(KEY_USAGE_SIGN, request_proto.key_usage());
+    EXPECT_EQ("user", request_proto.username());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    CreateCertifiableKeyReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_public_key("public_key");
+    reply_proto.set_certify_info("certify_info");
+    reply_proto.set_certify_info_signature("signature");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const CreateCertifiableKeyReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("signature", reply.certify_info_signature());
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_username("user");
+  proxy_.CreateCertifiableKey(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, Decrypt) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    DecryptRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ("user", request_proto.username());
+    EXPECT_EQ("data", request_proto.encrypted_data());
+    // Create reply protobuf.
+    scoped_ptr<dbus::Response> response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    DecryptReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_decrypted_data("data");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const DecryptReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("data", reply.decrypted_data());
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_encrypted_data("data");
+  proxy_.Decrypt(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, Sign) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    SignRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ("user", request_proto.username());
+    EXPECT_EQ("data", request_proto.data_to_sign());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    SignReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    reply_proto.set_signature("signature");
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const SignReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("signature", reply.signature());
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  proxy_.Sign(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+TEST_F(DBusProxyTest, RegisterKeyWithChapsToken) {
+  auto fake_dbus_call = [](
+      dbus::MethodCall* method_call,
+      const dbus::MockObjectProxy::ResponseCallback& response_callback) {
+    // Verify request protobuf.
+    dbus::MessageReader reader(method_call);
+    RegisterKeyWithChapsTokenRequest request_proto;
+    EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&request_proto));
+    EXPECT_EQ("label", request_proto.key_label());
+    EXPECT_EQ("user", request_proto.username());
+    // Create reply protobuf.
+    auto response = dbus::Response::CreateEmpty();
+    dbus::MessageWriter writer(response.get());
+    RegisterKeyWithChapsTokenReply reply_proto;
+    reply_proto.set_status(STATUS_SUCCESS);
+    writer.AppendProtoAsArrayOfBytes(reply_proto);
+    response_callback.Run(response.release());
+  };
+  EXPECT_CALL(*mock_object_proxy_, CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](
+      const RegisterKeyWithChapsTokenReply& reply) {
+    callback_count++;
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  proxy_.RegisterKeyWithChapsToken(request, base::Bind(callback));
+  EXPECT_EQ(1, callback_count);
+}
+
+}  // namespace attestation
diff --git a/client/main.cc b/client/main.cc
new file mode 100644
index 0000000..f3792a0
--- /dev/null
+++ b/client/main.cc
@@ -0,0 +1,491 @@
+// Copyright 2014 The Chromium OS 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 <stdio.h>
+#include <sysexits.h>
+
+#include <memory>
+#include <string>
+
+#include <base/command_line.h>
+#include <base/files/file_util.h>
+#include <base/message_loop/message_loop.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/daemons/daemon.h>
+#include <chromeos/syslog_logging.h>
+
+#include "attestation/client/dbus_proxy.h"
+#include "attestation/common/attestation_ca.pb.h"
+#include "attestation/common/crypto_utility_impl.h"
+#include "attestation/common/interface.pb.h"
+#include "attestation/common/print_interface_proto.h"
+
+namespace attestation {
+
+const char kCreateAndCertifyCommand[] = "create_and_certify";
+const char kCreateCommand[] = "create";
+const char kInfoCommand[] = "info";
+const char kEndorsementCommand[] = "endorsement";
+const char kAttestationKeyCommand[] = "attestation_key";
+const char kActivateCommand[] = "activate";
+const char kEncryptForActivateCommand[] = "encrypt_for_activate";
+const char kEncryptCommand[] = "encrypt";
+const char kDecryptCommand[] = "decrypt";
+const char kSignCommand[] = "sign";
+const char kVerifyCommand[] = "verify";
+const char kRegisterCommand[] = "register";
+const char kUsage[] = R"(
+Usage: attestation_client <command> [<args>]
+Commands:
+  create_and_certify [--user=<email>] [--label=<keylabel>]
+      Creates a key and requests certification by the Google Attestation CA.
+      This is the default command.
+  create [--user=<email>] [--label=<keylabel] [--usage=sign|decrypt]
+      Creates a certifiable key.
+
+  info [--user=<email>] [--label=<keylabel>]
+      Prints info about a key.
+  endorsement
+      Prints info about the TPM endorsement.
+  attestation_key
+      Prints info about the TPM attestation key.
+
+  activate --input=<input_file>
+      Activates an attestation key using the encrypted credential in
+      |input_file|.
+  encrypt_for_activate --input=<input_file> --output=<output_file>
+      Encrypts the content of |input_file| as required by the TPM for activating
+      an attestation key. The result is written to |output_file|.
+
+  encrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
+          --output=<output_file>
+      Encrypts the contents of |input_file| as required by the TPM for a decrypt
+      operation. The result is written to |output_file|.
+  decrypt [--user=<email>] [--label=<keylabel>] --input=<input_file>
+      Decrypts the contents of |input_file|.
+
+  sign [--user=<email>] [--label=<keylabel>] --input=<input_file>
+          [--output=<output_file>]
+      Signs the contents of |input_file|.
+  verify [--user=<email>] [--label=<keylabel] --input=<signed_data_file>
+          --signature=<signature_file>
+      Verifies the signature in |signature_file| against the contents of
+      |input_file|.
+
+  register [--user=<email>] [--label=<keylabel]
+      Registers a key with a PKCS #11 token.
+)";
+
+// The Daemon class works well as a client loop as well.
+using ClientLoopBase = chromeos::Daemon;
+
+class ClientLoop : public ClientLoopBase {
+ public:
+  ClientLoop() = default;
+  ~ClientLoop() override = default;
+
+ protected:
+  int OnInit() override {
+    int exit_code = ClientLoopBase::OnInit();
+    if (exit_code != EX_OK) {
+      return exit_code;
+    }
+    attestation_.reset(new attestation::DBusProxy());
+    if (!attestation_->Initialize()) {
+      return EX_UNAVAILABLE;
+    }
+    exit_code = ScheduleCommand();
+    if (exit_code == EX_USAGE) {
+      printf("%s", kUsage);
+    }
+    return exit_code;
+  }
+
+  void OnShutdown(int* exit_code) override {
+    attestation_.reset();
+    ClientLoopBase::OnShutdown(exit_code);
+  }
+
+ private:
+  // Posts tasks according to the command line options.
+  int ScheduleCommand() {
+    base::Closure task;
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    const auto& args = command_line->GetArgs();
+    if (command_line->HasSwitch("help") || command_line->HasSwitch("h") ||
+        (!args.empty() && args.front() == "help")) {
+      return EX_USAGE;
+    }
+    if (args.empty() || args.front() == kCreateAndCertifyCommand) {
+      task = base::Bind(&ClientLoop::CallCreateGoogleAttestedKey,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"));
+    } else if (args.front() == kCreateCommand) {
+      std::string usage_str = command_line->GetSwitchValueASCII("usage");
+      KeyUsage usage;
+      if (usage_str.empty() || usage_str == "sign") {
+        usage = KEY_USAGE_SIGN;
+      } else if (usage_str == "decrypt") {
+        usage = KEY_USAGE_DECRYPT;
+      } else {
+        return EX_USAGE;
+      }
+      task = base::Bind(&ClientLoop::CallCreateCertifiableKey,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        usage);
+    } else if (args.front() == kInfoCommand) {
+      task = base::Bind(&ClientLoop::CallGetKeyInfo,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"));
+    } else if (args.front() == kEndorsementCommand) {
+      task = base::Bind(&ClientLoop::CallGetEndorsementInfo,
+                        weak_factory_.GetWeakPtr());
+    } else if (args.front() == kAttestationKeyCommand) {
+      task = base::Bind(&ClientLoop::CallGetAttestationKeyInfo,
+                        weak_factory_.GetWeakPtr());
+    } else if (args.front() == kActivateCommand) {
+      if (!command_line->HasSwitch("input")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::CallActivateAttestationKey,
+                        weak_factory_.GetWeakPtr(),
+                        input);
+    } else if (args.front() == kEncryptForActivateCommand) {
+      if (!command_line->HasSwitch("input") ||
+          !command_line->HasSwitch("output")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::EncryptForActivate,
+                        weak_factory_.GetWeakPtr(),
+                        input);
+    } else if (args.front() == kEncryptCommand) {
+      if (!command_line->HasSwitch("input") ||
+          !command_line->HasSwitch("output")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::Encrypt,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input);
+    } else if (args.front() == kDecryptCommand) {
+      if (!command_line->HasSwitch("input")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::CallDecrypt,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input);
+    } else if (args.front() == kSignCommand) {
+      if (!command_line->HasSwitch("input")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::CallSign,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input);
+    } else if (args.front() == kVerifyCommand) {
+      if (!command_line->HasSwitch("input") ||
+          !command_line->HasSwitch("signature")) {
+        return EX_USAGE;
+      }
+      std::string input;
+      base::FilePath filename(command_line->GetSwitchValueASCII("input"));
+      if (!base::ReadFileToString(filename, &input)) {
+        LOG(ERROR) << "Failed to read file: " << filename.value();
+        return EX_NOINPUT;
+      }
+      std::string signature;
+      base::FilePath filename2(command_line->GetSwitchValueASCII("signature"));
+      if (!base::ReadFileToString(filename2, &signature)) {
+        LOG(ERROR) << "Failed to read file: " << filename2.value();
+        return EX_NOINPUT;
+      }
+      task = base::Bind(&ClientLoop::VerifySignature,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"),
+                        input,
+                        signature);
+    } else if (args.front() == kRegisterCommand) {
+      task = base::Bind(&ClientLoop::CallRegister,
+                        weak_factory_.GetWeakPtr(),
+                        command_line->GetSwitchValueASCII("label"),
+                        command_line->GetSwitchValueASCII("user"));
+    } else {
+      return EX_USAGE;
+    }
+    base::MessageLoop::current()->PostTask(FROM_HERE, task);
+    return EX_OK;
+  }
+
+  template <typename ProtobufType>
+  void PrintReplyAndQuit(const ProtobufType& reply) {
+    printf("%s\n", GetProtoDebugString(reply).c_str());
+    Quit();
+  }
+
+  void WriteOutput(const std::string& output) {
+    base::FilePath filename(base::CommandLine::ForCurrentProcess()->
+        GetSwitchValueASCII("output"));
+    if (base::WriteFile(filename, output.data(), output.size()) !=
+        static_cast<int>(output.size())) {
+      LOG(ERROR) << "Failed to write file: " << filename.value();
+      QuitWithExitCode(EX_IOERR);
+    }
+  }
+
+  void CallCreateGoogleAttestedKey(const std::string& label,
+                                   const std::string& username) {
+    CreateGoogleAttestedKeyRequest request;
+    request.set_key_label(label);
+    request.set_key_type(KEY_TYPE_RSA);
+    request.set_key_usage(KEY_USAGE_SIGN);
+    request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
+    request.set_username(username);
+    attestation_->CreateGoogleAttestedKey(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateGoogleAttestedKeyReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void CallGetKeyInfo(const std::string& label, const std::string& username) {
+    GetKeyInfoRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    attestation_->GetKeyInfo(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<GetKeyInfoReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void CallGetEndorsementInfo() {
+    GetEndorsementInfoRequest request;
+    request.set_key_type(KEY_TYPE_RSA);
+    attestation_->GetEndorsementInfo(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<GetEndorsementInfoReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void CallGetAttestationKeyInfo() {
+    GetAttestationKeyInfoRequest request;
+    request.set_key_type(KEY_TYPE_RSA);
+    attestation_->GetAttestationKeyInfo(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<GetAttestationKeyInfoReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void CallActivateAttestationKey(const std::string& input) {
+    ActivateAttestationKeyRequest request;
+    request.set_key_type(KEY_TYPE_RSA);
+    request.mutable_encrypted_certificate()->ParseFromString(input);
+    request.set_save_certificate(true);
+    attestation_->ActivateAttestationKey(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<ActivateAttestationKeyReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void EncryptForActivate(const std::string& input) {
+    GetEndorsementInfoRequest request;
+    request.set_key_type(KEY_TYPE_RSA);
+    attestation_->GetEndorsementInfo(
+        request,
+        base::Bind(&ClientLoop::EncryptForActivate2,
+                   weak_factory_.GetWeakPtr(),
+                   input));
+  }
+
+  void EncryptForActivate2(const std::string& input,
+                           const GetEndorsementInfoReply& endorsement_info) {
+    if (endorsement_info.status() != STATUS_SUCCESS) {
+      PrintReplyAndQuit(endorsement_info);
+    }
+    GetAttestationKeyInfoRequest request;
+    request.set_key_type(KEY_TYPE_RSA);
+    attestation_->GetAttestationKeyInfo(
+        request,
+        base::Bind(&ClientLoop::EncryptForActivate3,
+                   weak_factory_.GetWeakPtr(),
+                   input,
+                   endorsement_info));
+  }
+
+  void EncryptForActivate3(
+      const std::string& input,
+      const GetEndorsementInfoReply& endorsement_info,
+      const GetAttestationKeyInfoReply& attestation_key_info) {
+    if (attestation_key_info.status() != STATUS_SUCCESS) {
+      PrintReplyAndQuit(attestation_key_info);
+    }
+    CryptoUtilityImpl crypto(nullptr);
+    EncryptedIdentityCredential encrypted;
+    if (!crypto.EncryptIdentityCredential(
+        input,
+        endorsement_info.ek_public_key(),
+        attestation_key_info.public_key_tpm_format(),
+        &encrypted)) {
+      QuitWithExitCode(EX_SOFTWARE);
+    }
+    std::string output;
+    encrypted.SerializeToString(&output);
+    WriteOutput(output);
+    Quit();
+  }
+
+  void CallCreateCertifiableKey(const std::string& label,
+                                const std::string& username,
+                                KeyUsage usage) {
+    CreateCertifiableKeyRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    request.set_key_type(KEY_TYPE_RSA);
+    request.set_key_usage(usage);
+    attestation_->CreateCertifiableKey(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<CreateCertifiableKeyReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void Encrypt(const std::string& label,
+               const std::string& username,
+               const std::string& input) {
+    GetKeyInfoRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::Encrypt2,
+                                                 weak_factory_.GetWeakPtr(),
+                                                 input));
+  }
+
+  void Encrypt2(const std::string& input,
+                const GetKeyInfoReply& key_info) {
+    CryptoUtilityImpl crypto(nullptr);
+    std::string output;
+    if (!crypto.EncryptForUnbind(key_info.public_key(), input, &output)) {
+      QuitWithExitCode(EX_SOFTWARE);
+    }
+    WriteOutput(output);
+    Quit();
+  }
+
+  void CallDecrypt(const std::string& label,
+                   const std::string& username,
+                   const std::string& input) {
+    DecryptRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    request.set_encrypted_data(input);
+    attestation_->Decrypt(
+        request,
+        base::Bind(&ClientLoop::PrintReplyAndQuit<DecryptReply>,
+                   weak_factory_.GetWeakPtr()));
+  }
+
+  void CallSign(const std::string& label,
+                const std::string& username,
+                const std::string& input) {
+    SignRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    request.set_data_to_sign(input);
+    attestation_->Sign(request, base::Bind(&ClientLoop::OnSignComplete,
+                                           weak_factory_.GetWeakPtr()));
+  }
+
+  void OnSignComplete(const SignReply& reply) {
+    if (reply.status() == STATUS_SUCCESS &&
+        base::CommandLine::ForCurrentProcess()->HasSwitch("output")) {
+      WriteOutput(reply.signature());
+    }
+    PrintReplyAndQuit<SignReply>(reply);
+  }
+
+  void VerifySignature(const std::string& label,
+                       const std::string& username,
+                       const std::string& input,
+                       const std::string& signature) {
+    GetKeyInfoRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    attestation_->GetKeyInfo(request, base::Bind(&ClientLoop::VerifySignature2,
+                                                 weak_factory_.GetWeakPtr(),
+                                                 input, signature));
+  }
+
+  void VerifySignature2(const std::string& input,
+                        const std::string& signature,
+                        const GetKeyInfoReply& key_info) {
+    CryptoUtilityImpl crypto(nullptr);
+    if (crypto.VerifySignature(key_info.public_key(), input, signature)) {
+      printf("Signature is OK!\n");
+    } else {
+      printf("Signature is BAD!\n");
+    }
+    Quit();
+  }
+
+  void CallRegister(const std::string& label, const std::string& username) {
+    RegisterKeyWithChapsTokenRequest request;
+    request.set_key_label(label);
+    request.set_username(username);
+    attestation_->RegisterKeyWithChapsToken(request, base::Bind(
+        &ClientLoop::PrintReplyAndQuit<RegisterKeyWithChapsTokenReply>,
+        weak_factory_.GetWeakPtr()));
+  }
+
+  std::unique_ptr<attestation::AttestationInterface> attestation_;
+
+  // Declare this last so weak pointers will be destroyed first.
+  base::WeakPtrFactory<ClientLoop> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(ClientLoop);
+};
+
+}  // namespace attestation
+
+int main(int argc, char* argv[]) {
+  base::CommandLine::Init(argc, argv);
+  chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+  attestation::ClientLoop loop;
+  return loop.Run();
+}
diff --git a/common/attestation_ca.proto b/common/attestation_ca.proto
new file mode 100644
index 0000000..c844702
--- /dev/null
+++ b/common/attestation_ca.proto
@@ -0,0 +1,181 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+option optimize_for = LITE_RUNTIME;
+
+import "common.proto";
+
+package attestation;
+
+// This message holds all information to be sent to the attestation server in
+// order to complete enrollment.
+message AttestationEnrollmentRequest {
+  // The EK cert, in X.509 form, encrypted using the server's public key with
+  // the following parameters:
+  //   Key encryption: RSA-OAEP with no custom parameters.
+  //   Data encryption: 256-bit key, AES-CBC with PKCS5 padding.
+  //   MAC: HMAC-SHA-512 using the AES key.
+  optional EncryptedData encrypted_endorsement_credential = 1;
+  // The AIK public key, in TPM_PUBKEY form.
+  optional bytes identity_public_key = 2;
+  // PCR0 quoted by AIK.
+  optional Quote pcr0_quote = 3;
+  // PCR1 quoted by AIK.
+  optional Quote pcr1_quote = 4;
+}
+
+enum ResponseStatus {
+  OK = 0;
+  // Internal server error.
+  SERVER_ERROR = 1;
+  // The server cannot parse the request.
+  BAD_REQUEST = 2;
+  // The server rejects the request.
+  REJECT = 3;
+  // Only appears in enrollment response. The server returns the same generated
+  // id and reports the quota limit exceeded status when the number of reset
+  // action in a specified time window is more than self reset limitation.
+  QUOTA_LIMIT_EXCEEDED = 4;
+}
+
+// The response from the attestation server for the enrollment request.
+message AttestationEnrollmentResponse {
+  optional ResponseStatus status = 1;
+  // Detail response message. Included when the result is not OK.
+  optional string detail = 2;
+  optional EncryptedIdentityCredential encrypted_identity_credential = 3;
+}
+
+// The certificate request to be sent to the attestation server.
+message AttestationCertificateRequest {
+  // The AIK cert in X.509 format.
+  optional bytes identity_credential = 1;
+  // A certified public key in TPM_PUBKEY.
+  optional bytes certified_public_key = 3;
+  // The serialized TPM_CERTIFY_INFO for the certified key.
+  optional bytes certified_key_info = 4;
+  // The signature of the TPM_CERTIFY_INFO by the AIK.
+  optional bytes certified_key_proof = 5;
+  // A message identifier to be included in the response.
+  optional bytes message_id = 10;
+  // The certificate profile defines the type of certificate to issue.
+  optional CertificateProfile profile = 11;
+  // Information about the origin of the request which may be used depending on
+  // the certificate profile.
+  optional string origin = 12;
+  // The index of a temporal value.  This may be used or ignored depending on
+  // the certificate profile.
+  optional int32 temporal_index = 13;
+}
+
+// The response from the attestation server for the certificate request.
+message AttestationCertificateResponse {
+  optional ResponseStatus status = 1;
+  // Detail response message. Included when the result is not OK.
+  optional string detail = 2;
+  // The credential of the certified key in X.509 format.
+  optional bytes certified_key_credential = 3;
+  // The issuer intermediate CA certificate in X.509 format.
+  optional bytes intermediate_ca_cert = 5;
+  // A message identifier from the request this message is responding to.
+  optional bytes message_id = 6;
+  // Additional intermediate CA certificates that can help in validation.
+  // Certificate chaining order is from the leaf to the root. That is,
+  // |certified_key_credential| is signed by
+  // |intermediate_ca_cert|, which is signed by
+  // |additional_intermediate_ca_cert(0)|, which is signed by
+  // |additional_intermediate_ca_cert(1)|, ... and so on.
+  repeated bytes additional_intermediate_ca_cert = 7;
+}
+
+// The reset request to be sent to the attestation server.
+message AttestationResetRequest {
+  // The AIK cert, in X.509 form, encrypted using the server's public key with
+  // the following parameters:
+  //   Key encryption: RSA-OAEP with no custom parameters.
+  //   Data encryption: 256-bit key, AES-CBC with PKCS5 padding.
+  //   MAC: HMAC-SHA-512 using the AES key.
+  optional EncryptedData encrypted_identity_credential = 1;
+
+  // The one time token to make sure the reset process can be triggered only once.
+  optional bytes token = 2;
+
+  // The EK cert, in X.509 form, encrypted using the server's public key with
+  // the following parameters:
+  //   Key encryption: RSA-OAEP with no custom parameters.
+  //   Data encryption: 256-bit key, AES-CBC with PKCS5 padding.
+  //   MAC: HMAC-SHA-512 using the AES key.
+  optional EncryptedData encrypted_endorsement_credential = 3;
+}
+
+// The response from the attestation server for the reset request.
+message AttestationResetResponse {
+  // The response status.
+  optional ResponseStatus status = 1;
+  // Detail response message. Included when the result is not OK.
+  optional string detail = 2;
+}
+
+// The challenge data (as in challenge-response) generated by the server.
+// Before transmitted to the client, this message will be wrapped as a
+// SignedData message, in which the data field is the serialized Challenge
+// message, and the signature field is the signature of the data field signed
+// by the enterprise server using a hard-coded key. The signature algorithm is
+// RSASSA-PKCS1-v1_5-SHA256.
+message Challenge {
+  // A string for the client to sanity check a legitimate challenge.
+  optional string prefix = 1;
+  // A 256-bit random value generated by the server.
+  optional bytes nonce = 2;
+  // A timestamp for a stateless server to limit the timeframe during which the
+  // challenge may be replayed.
+  optional int64 timestamp = 3;
+}
+
+// The response data (as in challenge-response) generated by the client.
+// Before transmitted to the server, this message will be wrapped as a
+// SignedData message, in which the data field is the serialized
+// ChallengeResponse message, and the signature field is the signature of the
+// data field signed by the client using the key being challenged. The
+// signature algorithm is RSASSA-PKCS1-v1_5-SHA256.
+message ChallengeResponse {
+  // The original challenge data.
+  optional SignedData challenge = 1;
+  // A 256-bit random value generated by the client. Mixing in this nonce
+  // prevents a caller from using a challenge to sign arbitrary data.
+  optional bytes nonce = 2;
+  // The KeyInfo message encrypted using a public encryption key, pushed via
+  // policy with the following parameters:
+  //   Key encryption: RSA-OAEP with no custom parameters.
+  //   Data encryption: 256-bit key, AES-CBC with PKCS5 padding.
+  //   MAC: HMAC-SHA-512 using the AES key.
+  optional EncryptedData encrypted_key_info = 3;
+}
+
+// The data type of the message decrypted from
+// ChallengeResponse.encrypted_key_info.encrypted_data field. This message holds
+// information required by enterprise server to complete the verification.
+message KeyInfo {
+  // Indicates whether the key is an EMK or EUK.
+  optional KeyProfile key_type = 1;
+  // Domain information about the device or user associated with the key. For an
+  // EMK, this value is the enrolled domain. For an EUK, this value is the
+  // user's email address.
+  optional string domain = 2;
+  // The virtual device ID associated with the device or user.
+  optional bytes device_id = 3;
+  // If the key is an EUK, this value is the PCA-issued certificate for the key.
+  optional bytes certificate = 4;
+  // If the key is an EUK, this value may hold a SignedPublicKeyAndChallenge
+  // with a random challenge.  The SignedPublicKeyAndChallenge specification is
+  // here: https://developer.mozilla.org/en-US/docs/HTML/Element/keygen.
+  optional bytes signed_public_key_and_challenge = 5;
+}
+
+enum KeyProfile {
+  // Enterprise machine key.
+  EMK = 0;
+  // Enterprise user key.
+  EUK = 1;
+}
diff --git a/common/attestation_interface.h b/common/attestation_interface.h
new file mode 100644
index 0000000..ac72bd3
--- /dev/null
+++ b/common/attestation_interface.h
@@ -0,0 +1,94 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_ATTESTATION_INTERFACE_H_
+#define ATTESTATION_COMMON_ATTESTATION_INTERFACE_H_
+
+#include <string>
+
+#include <base/callback_forward.h>
+
+#include "attestation/common/interface.pb.h"
+
+namespace attestation {
+
+// The main attestation interface implemented by proxies and services. The
+// anticipated flow looks like this:
+//   [APP] -> AttestationInterface -> [IPC] -> AttestationInterface
+class AttestationInterface {
+ public:
+  virtual ~AttestationInterface() = default;
+
+  // Performs initialization tasks that may take a long time. This method must
+  // be successfully called before calling any other method. Returns true on
+  // success.
+  virtual bool Initialize() = 0;
+
+  // Processes a CreateGoogleAttestedKeyRequest and responds with a
+  // CreateGoogleAttestedKeyReply.
+  using CreateGoogleAttestedKeyCallback =
+      base::Callback<void(const CreateGoogleAttestedKeyReply&)>;
+  virtual void CreateGoogleAttestedKey(
+      const CreateGoogleAttestedKeyRequest& request,
+      const CreateGoogleAttestedKeyCallback& callback) = 0;
+
+  // Processes a GetKeyInfoRequest and responds with a GetKeyInfoReply.
+  using GetKeyInfoCallback = base::Callback<void(const GetKeyInfoReply&)>;
+  virtual void GetKeyInfo(const GetKeyInfoRequest& request,
+                          const GetKeyInfoCallback& callback) = 0;
+
+  // Processes a GetEndorsementInfoRequest and responds with a
+  // GetEndorsementInfoReply.
+  using GetEndorsementInfoCallback =
+      base::Callback<void(const GetEndorsementInfoReply&)>;
+  virtual void GetEndorsementInfo(
+      const GetEndorsementInfoRequest& request,
+      const GetEndorsementInfoCallback& callback) = 0;
+
+  // Processes a GetAttestationKeyInfoRequest and responds with a
+  // GetAttestationKeyInfoReply.
+  using GetAttestationKeyInfoCallback =
+      base::Callback<void(const GetAttestationKeyInfoReply&)>;
+  virtual void GetAttestationKeyInfo(
+      const GetAttestationKeyInfoRequest& request,
+      const GetAttestationKeyInfoCallback& callback) = 0;
+
+  // Processes a ActivateAttestationKeyRequest and responds with a
+  // ActivateAttestationKeyReply.
+  using ActivateAttestationKeyCallback =
+      base::Callback<void(const ActivateAttestationKeyReply&)>;
+  virtual void ActivateAttestationKey(
+      const ActivateAttestationKeyRequest& request,
+      const ActivateAttestationKeyCallback& callback) = 0;
+
+  // Processes a CreateCertifiableKeyRequest and responds with a
+  // CreateCertifiableKeyReply.
+  using CreateCertifiableKeyCallback =
+      base::Callback<void(const CreateCertifiableKeyReply&)>;
+  virtual void CreateCertifiableKey(
+      const CreateCertifiableKeyRequest& request,
+      const CreateCertifiableKeyCallback& callback) = 0;
+
+  // Processes a DecryptRequest and responds with a DecryptReply.
+  using DecryptCallback = base::Callback<void(const DecryptReply&)>;
+  virtual void Decrypt(const DecryptRequest& request,
+                       const DecryptCallback& callback) = 0;
+
+  // Processes a SignRequest and responds with a SignReply.
+  using SignCallback = base::Callback<void(const SignReply&)>;
+  virtual void Sign(const SignRequest& request,
+                    const SignCallback& callback) = 0;
+
+  // Processes a RegisterKeyWithChapsTokenRequest and responds with a
+  // RegisterKeyWithChapsTokenReply.
+  using RegisterKeyWithChapsTokenCallback =
+      base::Callback<void(const RegisterKeyWithChapsTokenReply&)>;
+  virtual void RegisterKeyWithChapsToken(
+      const RegisterKeyWithChapsTokenRequest& request,
+      const RegisterKeyWithChapsTokenCallback& callback) = 0;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_ATTESTATION_INTERFACE_H_
diff --git a/common/common.proto b/common/common.proto
new file mode 100644
index 0000000..bdb2775
--- /dev/null
+++ b/common/common.proto
@@ -0,0 +1,96 @@
+// Copyright 2015 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.
+
+option optimize_for = LITE_RUNTIME;
+
+package attestation;
+
+// Describes key type.
+enum KeyType {
+  KEY_TYPE_RSA = 1;
+  KEY_TYPE_ECC = 2;
+}
+
+// Describes allowed key usage.
+enum KeyUsage {
+  KEY_USAGE_SIGN = 1;
+  KEY_USAGE_DECRYPT = 2;
+}
+
+// Enumerates various certificate profiles supported by the Attestation CA.
+enum CertificateProfile {
+  // A certificate intended for enterprise-owned devices.  It has the following
+  // subjectName fields:
+  //   CN=<stable device identifier>
+  //   OU=state:[verified|developer]
+  //   O=Chrome Device Enterprise
+  ENTERPRISE_MACHINE_CERTIFICATE = 0;
+
+  // A certificate intended for enterprise-owned user accounts.  It has the
+  // following subjectName fields:
+  //   OU=state:[verified|developer]
+  //   O=Chrome Device Enterprise
+  ENTERPRISE_USER_CERTIFICATE = 1;
+
+  // A certificate intended for platform verification by providers of protected
+  // content.  It has the following subjectName fields:
+  //   O=Chrome Device Content Protection
+  CONTENT_PROTECTION_CERTIFICATE = 2;
+
+  // Like above, but it also includes a stable ID and origin.
+  //   CN=<origin-specific device identifier>
+  //   OU=<origin>
+  //   O=Chrome Device Content Protection
+  CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID = 3;
+
+  // A certificate intended for cast devices.
+  CAST_CERTIFICATE = 4;
+
+  GFSC_CERTIFICATE = 5;
+}
+
+// Holds information about a quote generated by the TPM.
+message Quote {
+  // The quote; a signature generated with the AIK.
+  optional bytes quote = 1;
+  // The serialized data that was quoted; this assists in verifying the quote.
+  optional bytes quoted_data = 2;
+  // The value of the PCR(s) at the time the quote was generated.
+  optional bytes quoted_pcr_value = 3;
+  // Source data which was originally used to extend the PCR. If this field
+  // exists it can be expected that SHA1(pcr_source_hint) was extended into the
+  // PCR.
+  optional bytes pcr_source_hint = 4;
+}
+
+// Holds encrypted data and information required to decrypt it.
+message EncryptedData {
+  // A key that has been sealed to the TPM or wrapped by another key.
+  optional bytes wrapped_key = 2;
+  // The initialization vector used during encryption.
+  optional bytes iv = 3;
+  // MAC of (iv || encrypted_data).
+  optional bytes mac = 4;
+  optional bytes encrypted_data = 5;
+  // An identifier for the wrapping key to assist in decryption.
+  optional bytes wrapping_key_id = 6;
+}
+
+// The wrapper message of any data and its signature.
+message SignedData {
+  // The data to be signed.
+  optional bytes data = 1;
+  // The signature of the data field.
+  optional bytes signature = 2;
+}
+
+// These two fields are suitable for passing to Tspi_TPM_ActivateIdentity()
+// directly.
+message EncryptedIdentityCredential {
+  // TPM_ASYM_CA_CONTENTS, encrypted with EK public key.
+  optional bytes asym_ca_contents = 1;
+  // TPM_SYM_CA_ATTESTATION, encrypted with the key in aysm_ca_contents.
+  optional bytes sym_ca_attestation = 2;
+}
+
diff --git a/common/crypto_utility.h b/common/crypto_utility.h
new file mode 100644
index 0000000..430c4ad
--- /dev/null
+++ b/common/crypto_utility.h
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_CRYPTO_UTILITY_H_
+#define ATTESTATION_COMMON_CRYPTO_UTILITY_H_
+
+#include <string>
+
+#include "attestation/common/common.pb.h"
+
+namespace attestation {
+
+// A class which provides helpers for cryptography-related tasks.
+class CryptoUtility {
+ public:
+  virtual ~CryptoUtility() = default;
+
+  // Generates |num_bytes| of |random_data|. Returns true on success.
+  virtual bool GetRandom(size_t num_bytes, std::string* random_data) const = 0;
+
+  // Creates a random |aes_key| and seals it to the TPM's PCR0, producing a
+  // |sealed_key|. Returns true on success.
+  virtual bool CreateSealedKey(std::string* aes_key,
+                               std::string* sealed_key) = 0;
+
+  // Encrypts the given |data| using the |aes_key|. The |sealed_key| will be
+  // embedded in the |encrypted_data| to assist with decryption. It can be
+  // extracted from the |encrypted_data| using UnsealKey(). Returns true on
+  // success.
+  virtual bool EncryptData(const std::string& data,
+                           const std::string& aes_key,
+                           const std::string& sealed_key,
+                           std::string* encrypted_data) = 0;
+
+  // Extracts and unseals the |aes_key| from the |sealed_key| embedded in
+  // the given |encrypted_data|. The |sealed_key| is also provided as an output
+  // so callers can make subsequent calls to EncryptData() with the same key.
+  // Returns true on success.
+  virtual bool UnsealKey(const std::string& encrypted_data,
+                         std::string* aes_key,
+                         std::string* sealed_key) = 0;
+
+  // Decrypts |encrypted_data| using |aes_key|, producing the decrypted |data|.
+  // Returns true on success.
+  virtual bool DecryptData(const std::string& encrypted_data,
+                           const std::string& aes_key,
+                           std::string* data) = 0;
+
+  // Convert |public_key| from PKCS #1 RSAPublicKey to X.509
+  // SubjectPublicKeyInfo. On success returns true and provides the
+  // |public_key_info|.
+  virtual bool GetRSASubjectPublicKeyInfo(const std::string& public_key,
+                                          std::string* public_key_info) = 0;
+
+  // Convert |public_key_info| from X.509 SubjectPublicKeyInfo to PKCS #1
+  // RSAPublicKey. On success returns true and provides the |public_key|.
+  virtual bool GetRSAPublicKey(const std::string& public_key_info,
+                               std::string* public_key) = 0;
+
+  // Encrypts a |credential| in a format compatible with TPM attestation key
+  // activation. The |ek_public_key_info| must be provided in X.509
+  // SubjectPublicKeyInfo format and the |aik_public_key| must be provided in
+  // TPM_PUBKEY format.
+  virtual bool EncryptIdentityCredential(
+      const std::string& credential,
+      const std::string& ek_public_key_info,
+      const std::string& aik_public_key,
+      EncryptedIdentityCredential* encrypted) = 0;
+
+  // Encrypts |data| in a format compatible with the TPM unbind operation. The
+  // |public_key| must be provided in X.509 SubjectPublicKeyInfo format.
+  virtual bool EncryptForUnbind(const std::string& public_key,
+                                const std::string& data,
+                                std::string* encrypted_data) = 0;
+
+  // Verifies a PKCS #1 v1.5 SHA-256 |signature| over |data|. The |public_key|
+  // must be provided in X.509 SubjectPublicKeyInfo format.
+  virtual bool VerifySignature(const std::string& public_key,
+                               const std::string& data,
+                               const std::string& signature) = 0;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_CRYPTO_UTILITY_H_
diff --git a/common/crypto_utility_impl.cc b/common/crypto_utility_impl.cc
new file mode 100644
index 0000000..abf0b4c
--- /dev/null
+++ b/common/crypto_utility_impl.cc
@@ -0,0 +1,460 @@
+// Copyright 2015 The Chromium OS 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 "attestation/common/crypto_utility_impl.h"
+
+#include <limits>
+#include <string>
+
+#include <arpa/inet.h>
+#include <base/sha1.h>
+#include <base/stl_util.h>
+#include <crypto/scoped_openssl_types.h>
+#include <crypto/secure_util.h>
+#include <crypto/sha2.h>
+#include <openssl/bio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/x509.h>
+
+namespace {
+
+const size_t kAesKeySize = 32;
+const size_t kAesBlockSize = 16;
+
+std::string GetOpenSSLError() {
+  BIO* bio = BIO_new(BIO_s_mem());
+  ERR_print_errors(bio);
+  char* data = nullptr;
+  int data_len = BIO_get_mem_data(bio, &data);
+  std::string error_string(data, data_len);
+  BIO_free(bio);
+  return error_string;
+}
+
+unsigned char* StringAsOpenSSLBuffer(std::string* s) {
+  return reinterpret_cast<unsigned char*>(string_as_array(s));
+}
+
+}  // namespace
+
+namespace attestation {
+
+CryptoUtilityImpl::CryptoUtilityImpl(TpmUtility* tpm_utility)
+    : tpm_utility_(tpm_utility) {
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+}
+
+CryptoUtilityImpl::~CryptoUtilityImpl() {
+  EVP_cleanup();
+  ERR_free_strings();
+}
+
+bool CryptoUtilityImpl::GetRandom(size_t num_bytes,
+                                  std::string* random_data) const {
+  // OpenSSL takes a signed integer.
+  if (num_bytes > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    return false;
+  }
+  random_data->resize(num_bytes);
+  unsigned char* buffer = StringAsOpenSSLBuffer(random_data);
+  return (RAND_bytes(buffer, num_bytes) == 1);
+}
+
+bool CryptoUtilityImpl::CreateSealedKey(std::string* aes_key,
+                                        std::string* sealed_key) {
+  if (!GetRandom(kAesKeySize, aes_key)) {
+    LOG(ERROR) << __func__ << ": GetRandom failed.";
+    return false;
+  }
+  if (!tpm_utility_->SealToPCR0(*aes_key, sealed_key)) {
+    LOG(ERROR) << __func__ << ": Failed to seal cipher key.";
+    return false;
+  }
+  return true;
+}
+
+bool CryptoUtilityImpl::EncryptData(const std::string& data,
+                                    const std::string& aes_key,
+                                    const std::string& sealed_key,
+                                    std::string* encrypted_data) {
+  std::string iv;
+  if (!GetRandom(kAesBlockSize, &iv)) {
+    LOG(ERROR) << __func__ << ": GetRandom failed.";
+    return false;
+  }
+  std::string raw_encrypted_data;
+  if (!AesEncrypt(data, aes_key, iv, &raw_encrypted_data)) {
+    LOG(ERROR) << __func__ << ": AES encryption failed.";
+    return false;
+  }
+  EncryptedData encrypted_pb;
+  encrypted_pb.set_wrapped_key(sealed_key);
+  encrypted_pb.set_iv(iv);
+  encrypted_pb.set_encrypted_data(raw_encrypted_data);
+  encrypted_pb.set_mac(HmacSha512(iv + raw_encrypted_data, aes_key));
+  if (!encrypted_pb.SerializeToString(encrypted_data)) {
+    LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
+    return false;
+  }
+  return true;
+}
+
+bool CryptoUtilityImpl::UnsealKey(const std::string& encrypted_data,
+                                  std::string* aes_key,
+                                  std::string* sealed_key) {
+  EncryptedData encrypted_pb;
+  if (!encrypted_pb.ParseFromString(encrypted_data)) {
+    LOG(ERROR) << __func__ << ": Failed to parse protobuf.";
+    return false;
+  }
+  *sealed_key = encrypted_pb.wrapped_key();
+  if (!tpm_utility_->Unseal(*sealed_key, aes_key)) {
+    LOG(ERROR) << __func__ << ": Cannot unseal aes key.";
+    return false;
+  }
+  return true;
+}
+
+bool CryptoUtilityImpl::DecryptData(const std::string& encrypted_data,
+                                    const std::string& aes_key,
+                                    std::string* data) {
+  EncryptedData encrypted_pb;
+  if (!encrypted_pb.ParseFromString(encrypted_data)) {
+    LOG(ERROR) << __func__ << ": Failed to parse protobuf.";
+    return false;
+  }
+  std::string mac = HmacSha512(
+      encrypted_pb.iv() + encrypted_pb.encrypted_data(),
+      aes_key);
+  if (mac.length() != encrypted_pb.mac().length()) {
+    LOG(ERROR) << __func__ << ": Corrupted data in encrypted pb.";
+    return false;
+  }
+  if (!crypto::SecureMemEqual(mac.data(), encrypted_pb.mac().data(),
+                              mac.length())) {
+    LOG(ERROR) << __func__ << ": Corrupted data in encrypted pb.";
+    return false;
+  }
+  if (!AesDecrypt(encrypted_pb.encrypted_data(), aes_key, encrypted_pb.iv(),
+                  data)) {
+    LOG(ERROR) << __func__ << ": AES decryption failed.";
+    return false;
+  }
+  return true;
+}
+
+bool CryptoUtilityImpl::GetRSASubjectPublicKeyInfo(
+    const std::string& public_key,
+    std::string* public_key_info) {
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
+  crypto::ScopedRSA rsa(d2i_RSAPublicKey(nullptr, &asn1_ptr,
+                                         public_key.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  unsigned char* buffer = nullptr;
+  int length = i2d_RSA_PUBKEY(rsa.get(), &buffer);
+  if (length <= 0) {
+    LOG(ERROR) << __func__ << ": Failed to encode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  crypto::ScopedOpenSSLBytes scoped_buffer(buffer);
+  public_key_info->assign(reinterpret_cast<char*>(buffer), length);
+  return true;
+}
+
+bool CryptoUtilityImpl::GetRSAPublicKey(const std::string& public_key_info,
+                                        std::string* public_key) {
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(
+      public_key_info.data());
+  crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr,
+                                       public_key_info.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  unsigned char* buffer = NULL;
+  int length = i2d_RSAPublicKey(rsa.get(), &buffer);
+  if (length <= 0) {
+    LOG(ERROR) << __func__ << ": Failed to encode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  crypto::ScopedOpenSSLBytes scoped_buffer(buffer);
+  public_key->assign(reinterpret_cast<char*>(buffer), length);
+  return true;
+}
+
+bool CryptoUtilityImpl::EncryptIdentityCredential(
+    const std::string& credential,
+    const std::string& ek_public_key_info,
+    const std::string& aik_public_key,
+    EncryptedIdentityCredential* encrypted) {
+  const char kAlgAES256 = 9;  // This comes from TPM_ALG_AES256.
+  const char kEncModeCBC = 2;  // This comes from TPM_SYM_MODE_CBC.
+  const char kAsymContentHeader[] =
+      {0, 0, 0, kAlgAES256, 0, kEncModeCBC, 0, kAesKeySize};
+  const char kSymContentHeader[12] = {};
+
+  // Generate an AES key and encrypt the credential.
+  std::string aes_key;
+  if (!GetRandom(kAesKeySize, &aes_key)) {
+    LOG(ERROR) << __func__ << ": GetRandom failed.";
+    return false;
+  }
+  std::string encrypted_credential;
+  if (!TssCompatibleEncrypt(credential, aes_key, &encrypted_credential)) {
+    LOG(ERROR) << __func__ << ": Failed to encrypt credential.";
+    return false;
+  }
+
+  // Construct a TPM_ASYM_CA_CONTENTS structure.
+  std::string asym_header(std::begin(kAsymContentHeader),
+                          std::end(kAsymContentHeader));
+  std::string asym_content = asym_header + aes_key +
+                             base::SHA1HashString(aik_public_key);
+
+  // Encrypt the TPM_ASYM_CA_CONTENTS with the EK public key.
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(
+      ek_public_key_info.data());
+  crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr,
+                                       ek_public_key_info.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode EK public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  std::string encrypted_asym_content;
+  if (!TpmCompatibleOAEPEncrypt(asym_content, rsa.get(),
+                                &encrypted_asym_content)) {
+    LOG(ERROR) << __func__ << ": Failed to encrypt with EK public key.";
+    return false;
+  }
+
+  // Construct a TPM_SYM_CA_ATTESTATION structure.
+  uint32_t length = htonl(encrypted_credential.size());
+  auto length_bytes = reinterpret_cast<const char*>(&length);
+  std::string length_blob(length_bytes, sizeof(uint32_t));
+  std::string sym_header(std::begin(kSymContentHeader),
+                         std::end(kSymContentHeader));
+  std::string sym_content = length_blob + sym_header + encrypted_credential;
+
+  encrypted->set_asym_ca_contents(encrypted_asym_content);
+  encrypted->set_sym_ca_attestation(sym_content);
+  return true;
+}
+
+bool CryptoUtilityImpl::EncryptForUnbind(const std::string& public_key,
+                                         const std::string& data,
+                                         std::string* encrypted_data) {
+  // Construct a TPM_BOUND_DATA structure.
+  const char kBoundDataHeader[] = {1, 1, 0, 0, 2 /* TPM_PT_BIND */};
+  std::string header(std::begin(kBoundDataHeader), std::end(kBoundDataHeader));
+  std::string bound_data = header + data;
+
+  // Encrypt using the TPM_ES_RSAESOAEP_SHA1_MGF1 scheme.
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
+  crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  if (!TpmCompatibleOAEPEncrypt(bound_data, rsa.get(), encrypted_data)) {
+    LOG(ERROR) << __func__ << ": Failed to encrypt with public key.";
+    return false;
+  }
+  return true;
+}
+
+bool CryptoUtilityImpl::VerifySignature(const std::string& public_key,
+                                        const std::string& data,
+                                        const std::string& signature) {
+  auto asn1_ptr = reinterpret_cast<const unsigned char*>(public_key.data());
+  crypto::ScopedRSA rsa(d2i_RSA_PUBKEY(NULL, &asn1_ptr, public_key.size()));
+  if (!rsa.get()) {
+    LOG(ERROR) << __func__ << ": Failed to decode public key: "
+               << GetOpenSSLError();
+    return false;
+  }
+  std::string digest = crypto::SHA256HashString(data);
+  auto digest_buffer = reinterpret_cast<const unsigned char*>(digest.data());
+  std::string mutable_signature(signature);
+  unsigned char* signature_buffer = StringAsOpenSSLBuffer(&mutable_signature);
+  return (RSA_verify(NID_sha256, digest_buffer, digest.size(),
+                     signature_buffer, signature.size(), rsa.get()) == 1);
+}
+
+bool CryptoUtilityImpl::AesEncrypt(const std::string& data,
+                                   const std::string& key,
+                                   const std::string& iv,
+                                   std::string* encrypted_data) {
+  if (key.size() != kAesKeySize || iv.size() != kAesBlockSize) {
+    return false;
+  }
+  if (data.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    // EVP_EncryptUpdate takes a signed int.
+    return false;
+  }
+  std::string mutable_data(data);
+  unsigned char* input_buffer = StringAsOpenSSLBuffer(&mutable_data);
+  std::string mutable_key(key);
+  unsigned char* key_buffer = StringAsOpenSSLBuffer(&mutable_key);
+  std::string mutable_iv(iv);
+  unsigned char* iv_buffer = StringAsOpenSSLBuffer(&mutable_iv);
+  // Allocate enough space for the output (including padding).
+  encrypted_data->resize(data.size() + kAesBlockSize);
+  auto output_buffer = reinterpret_cast<unsigned char*>(
+      string_as_array(encrypted_data));
+  int output_size = 0;
+  const EVP_CIPHER* cipher = EVP_aes_256_cbc();
+  EVP_CIPHER_CTX encryption_context;
+  EVP_CIPHER_CTX_init(&encryption_context);
+  if (!EVP_EncryptInit_ex(&encryption_context, cipher, nullptr, key_buffer,
+                          iv_buffer)) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    return false;
+  }
+  if (!EVP_EncryptUpdate(&encryption_context, output_buffer, &output_size,
+                         input_buffer, data.size())) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    EVP_CIPHER_CTX_cleanup(&encryption_context);
+    return false;
+  }
+  size_t total_size = output_size;
+  output_buffer += output_size;
+  output_size = 0;
+  if (!EVP_EncryptFinal_ex(&encryption_context, output_buffer, &output_size)) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    EVP_CIPHER_CTX_cleanup(&encryption_context);
+    return false;
+  }
+  total_size += output_size;
+  encrypted_data->resize(total_size);
+  EVP_CIPHER_CTX_cleanup(&encryption_context);
+  return true;
+}
+
+bool CryptoUtilityImpl::AesDecrypt(const std::string& encrypted_data,
+                                   const std::string& key,
+                                   const std::string& iv,
+                                   std::string* data) {
+  if (key.size() != kAesKeySize || iv.size() != kAesBlockSize) {
+    return false;
+  }
+  if (encrypted_data.size() >
+      static_cast<size_t>(std::numeric_limits<int>::max())) {
+    // EVP_DecryptUpdate takes a signed int.
+    return false;
+  }
+  std::string mutable_encrypted_data(encrypted_data);
+  unsigned char* input_buffer = StringAsOpenSSLBuffer(&mutable_encrypted_data);
+  std::string mutable_key(key);
+  unsigned char* key_buffer = StringAsOpenSSLBuffer(&mutable_key);
+  std::string mutable_iv(iv);
+  unsigned char* iv_buffer = StringAsOpenSSLBuffer(&mutable_iv);
+  // Allocate enough space for the output.
+  data->resize(encrypted_data.size());
+  unsigned char* output_buffer = StringAsOpenSSLBuffer(data);
+  int output_size = 0;
+  const EVP_CIPHER* cipher = EVP_aes_256_cbc();
+  EVP_CIPHER_CTX decryption_context;
+  EVP_CIPHER_CTX_init(&decryption_context);
+  if (!EVP_DecryptInit_ex(&decryption_context, cipher, nullptr, key_buffer,
+                          iv_buffer)) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    return false;
+  }
+  if (!EVP_DecryptUpdate(&decryption_context, output_buffer, &output_size,
+                         input_buffer, encrypted_data.size())) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    EVP_CIPHER_CTX_cleanup(&decryption_context);
+    return false;
+  }
+  size_t total_size = output_size;
+  output_buffer += output_size;
+  output_size = 0;
+  if (!EVP_DecryptFinal_ex(&decryption_context, output_buffer, &output_size)) {
+    LOG(ERROR) << __func__ << ": " << GetOpenSSLError();
+    EVP_CIPHER_CTX_cleanup(&decryption_context);
+    return false;
+  }
+  total_size += output_size;
+  data->resize(total_size);
+  EVP_CIPHER_CTX_cleanup(&decryption_context);
+  return true;
+}
+
+std::string CryptoUtilityImpl::HmacSha512(const std::string& data,
+                                          const std::string& key) {
+  unsigned char mac[SHA512_DIGEST_LENGTH];
+  std::string mutable_data(data);
+  unsigned char* data_buffer = StringAsOpenSSLBuffer(&mutable_data);
+  HMAC(EVP_sha512(), key.data(), key.size(), data_buffer, data.size(), mac,
+       nullptr);
+  return std::string(std::begin(mac), std::end(mac));
+}
+
+bool CryptoUtilityImpl::TssCompatibleEncrypt(const std::string& input,
+                                             const std::string& key,
+                                             std::string* output) {
+  CHECK(output);
+  CHECK_EQ(key.size(), kAesKeySize);
+  std::string iv;
+  if (!GetRandom(kAesBlockSize, &iv)) {
+    LOG(ERROR) << __func__ << ": GetRandom failed.";
+    return false;
+  }
+  std::string encrypted;
+  if (!AesEncrypt(input, key, iv, &encrypted)) {
+    LOG(ERROR) << __func__ << ": Encryption failed.";
+    return false;
+  }
+  *output = iv + encrypted;
+  return true;
+}
+
+bool CryptoUtilityImpl::TpmCompatibleOAEPEncrypt(const std::string& input,
+                                                 RSA* key,
+                                                 std::string* output) {
+  CHECK(output);
+  // The custom OAEP parameter as specified in TPM Main Part 1, Section 31.1.1.
+  const unsigned char oaep_param[4] = {'T', 'C', 'P', 'A'};
+  std::string padded_input;
+  padded_input.resize(RSA_size(key));
+  auto padded_buffer = reinterpret_cast<unsigned char*>(
+      string_as_array(&padded_input));
+  auto input_buffer = reinterpret_cast<const unsigned char*>(input.data());
+  int result = RSA_padding_add_PKCS1_OAEP(padded_buffer, padded_input.size(),
+                                          input_buffer, input.size(),
+                                          oaep_param, arraysize(oaep_param));
+  if (!result) {
+    LOG(ERROR) << __func__ << ": Failed to add OAEP padding: "
+               << GetOpenSSLError();
+    return false;
+  }
+  output->resize(padded_input.size());
+  auto output_buffer = reinterpret_cast<unsigned char*>(
+      string_as_array(output));
+  result = RSA_public_encrypt(padded_input.size(), padded_buffer,
+                              output_buffer, key, RSA_NO_PADDING);
+  if (result == -1) {
+    LOG(ERROR) << __func__ << ": Failed to encrypt OAEP padded input: "
+               << GetOpenSSLError();
+    return false;
+  }
+  return true;
+}
+
+}  // namespace attestation
diff --git a/common/crypto_utility_impl.h b/common/crypto_utility_impl.h
new file mode 100644
index 0000000..04521c0
--- /dev/null
+++ b/common/crypto_utility_impl.h
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_CRYPTO_UTILITY_IMPL_H_
+#define ATTESTATION_COMMON_CRYPTO_UTILITY_IMPL_H_
+
+#include "attestation/common/crypto_utility.h"
+
+#include <string>
+
+#include <openssl/rsa.h>
+
+#include "attestation/common/tpm_utility.h"
+
+namespace attestation {
+
+// An implementation of CryptoUtility.
+class CryptoUtilityImpl : public CryptoUtility {
+ public:
+  // Does not take ownership of pointers.
+  explicit CryptoUtilityImpl(TpmUtility* tpm_utility);
+  ~CryptoUtilityImpl() override;
+
+  // CryptoUtility methods.
+  bool GetRandom(size_t num_bytes, std::string* random_data) const override;
+  bool CreateSealedKey(std::string* aes_key, std::string* sealed_key) override;
+  bool EncryptData(const std::string& data,
+                   const std::string& aes_key,
+                   const std::string& sealed_key,
+                   std::string* encrypted_data) override;
+  bool UnsealKey(const std::string& encrypted_data,
+                 std::string* aes_key,
+                 std::string* sealed_key) override;
+  bool DecryptData(const std::string& encrypted_data,
+                   const std::string& aes_key,
+                   std::string* data) override;
+  bool GetRSASubjectPublicKeyInfo(const std::string& public_key,
+                                  std::string* spki) override;
+  bool GetRSAPublicKey(const std::string& public_key_info,
+                       std::string* public_key) override;
+  bool EncryptIdentityCredential(
+      const std::string& credential,
+      const std::string& ek_public_key_info,
+      const std::string& aik_public_key,
+      EncryptedIdentityCredential* encrypted) override;
+  bool EncryptForUnbind(const std::string& public_key,
+                        const std::string& data,
+                        std::string* encrypted_data) override;
+  bool VerifySignature(const std::string& public_key,
+                       const std::string& data,
+                       const std::string& signature) override;
+
+ private:
+  // Encrypts |data| using |key| and |iv| for AES in CBC mode with PKCS #5
+  // padding and produces the |encrypted_data|. Returns true on success.
+  bool AesEncrypt(const std::string& data,
+                  const std::string& key,
+                  const std::string& iv,
+                  std::string* encrypted_data);
+
+  // Decrypts |encrypted_data| using |key| and |iv| for AES in CBC mode with
+  // PKCS #5 padding and produces the decrypted |data|. Returns true on success.
+  bool AesDecrypt(const std::string& encrypted_data,
+                  const std::string& key,
+                  const std::string& iv,
+                  std::string* data);
+
+  // Computes and returns an HMAC of |data| using |key| and SHA-512.
+  std::string HmacSha512(const std::string& data, const std::string& key);
+
+  // Encrypt like trousers does. This is like AesEncrypt but a random IV is
+  // included in the output.
+  bool TssCompatibleEncrypt(const std::string& input,
+                            const std::string& key,
+                            std::string* output);
+
+  // Encrypts using RSA-OAEP and the TPM-specific OAEP parameter.
+  bool TpmCompatibleOAEPEncrypt(const std::string& input,
+                                RSA* key,
+                                std::string* output);
+
+  TpmUtility* tpm_utility_;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_CRYPTO_UTILITY_IMPL_H_
diff --git a/common/crypto_utility_impl_test.cc b/common/crypto_utility_impl_test.cc
new file mode 100644
index 0000000..fdd16b8
--- /dev/null
+++ b/common/crypto_utility_impl_test.cc
@@ -0,0 +1,229 @@
+// Copyright 2015 The Chromium OS 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 <memory>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "attestation/common/crypto_utility_impl.h"
+#include "attestation/common/mock_tpm_utility.h"
+
+using testing::_;
+using testing::NiceMock;
+using testing::Return;
+
+namespace {
+
+const char kValidPublicKeyHex[] =
+    "3082010A0282010100"
+    "961037BC12D2A298BEBF06B2D5F8C9B64B832A2237F8CF27D5F96407A6041A4D"
+    "AD383CB5F88E625F412E8ACD5E9D69DF0F4FA81FCE7955829A38366CBBA5A2B1"
+    "CE3B48C14B59E9F094B51F0A39155874C8DE18A0C299EBF7A88114F806BE4F25"
+    "3C29A509B10E4B19E31675AFE3B2DA77077D94F43D8CE61C205781ED04D183B4"
+    "C349F61B1956C64B5398A3A98FAFF17D1B3D9120C832763EDFC8F4137F6EFBEF"
+    "46D8F6DE03BD00E49DEF987C10BDD5B6F8758B6A855C23C982DDA14D8F0F2B74"
+    "E6DEFA7EEE5A6FC717EB0FF103CB8049F693A2C8A5039EF1F5C025DC44BD8435"
+    "E8D8375DADE00E0C0F5C196E04B8483CC98B1D5B03DCD7E0048B2AB343FFC11F"
+    "0203"
+    "010001";
+
+std::string HexDecode(const std::string hex) {
+  std::vector<uint8_t> output;
+  CHECK(base::HexStringToBytes(hex, &output));
+  return std::string(reinterpret_cast<char*>(output.data()), output.size());
+}
+
+}  // namespace
+
+namespace attestation {
+
+class CryptoUtilityImplTest : public testing::Test {
+ public:
+  ~CryptoUtilityImplTest() override = default;
+  void SetUp() override {
+    crypto_utility_.reset(new CryptoUtilityImpl(&mock_tpm_utility_));
+  }
+
+ protected:
+  NiceMock<MockTpmUtility> mock_tpm_utility_;
+  std::unique_ptr<CryptoUtilityImpl> crypto_utility_;
+};
+
+TEST_F(CryptoUtilityImplTest, GetRandomSuccess) {
+  std::string random1;
+  EXPECT_TRUE(crypto_utility_->GetRandom(20, &random1));
+  std::string random2;
+  EXPECT_TRUE(crypto_utility_->GetRandom(20, &random2));
+  EXPECT_NE(random1, random2);
+}
+
+TEST_F(CryptoUtilityImplTest, GetRandomIntOverflow) {
+  size_t num_bytes = -1;
+  std::string buffer;
+  EXPECT_FALSE(crypto_utility_->GetRandom(num_bytes, &buffer));
+}
+
+TEST_F(CryptoUtilityImplTest, PairwiseSealedEncryption) {
+  std::string key;
+  std::string sealed_key;
+  EXPECT_TRUE(crypto_utility_->CreateSealedKey(&key, &sealed_key));
+  std::string data("test");
+  std::string encrypted_data;
+  EXPECT_TRUE(crypto_utility_->EncryptData(data, key, sealed_key,
+                                           &encrypted_data));
+  key.clear();
+  sealed_key.clear();
+  data.clear();
+  EXPECT_TRUE(crypto_utility_->UnsealKey(encrypted_data, &key, &sealed_key));
+  EXPECT_TRUE(crypto_utility_->DecryptData(encrypted_data, key, &data));
+  EXPECT_EQ("test", data);
+}
+
+TEST_F(CryptoUtilityImplTest, SealFailure) {
+  EXPECT_CALL(mock_tpm_utility_, SealToPCR0(_, _))
+      .WillRepeatedly(Return(false));
+  std::string key;
+  std::string sealed_key;
+  EXPECT_FALSE(crypto_utility_->CreateSealedKey(&key, &sealed_key));
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptNoData) {
+  std::string key(32, 0);
+  std::string output;
+  EXPECT_TRUE(crypto_utility_->EncryptData(std::string(), key, key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptInvalidKey) {
+  std::string key(12, 0);
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->EncryptData(std::string(), key, key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, UnsealInvalidData) {
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->UnsealKey("invalid", &output, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, UnsealError) {
+  EXPECT_CALL(mock_tpm_utility_, Unseal(_, _))
+      .WillRepeatedly(Return(false));
+  std::string key(32, 0);
+  std::string data;
+  EXPECT_TRUE(crypto_utility_->EncryptData("data", key, key, &data));
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->UnsealKey(data, &output, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, DecryptInvalidKey) {
+  std::string key(12, 0);
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->DecryptData(std::string(), key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, DecryptInvalidData) {
+  std::string key(32, 0);
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->DecryptData("invalid", key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, DecryptInvalidData2) {
+  std::string key(32, 0);
+  std::string output;
+  EncryptedData proto;
+  std::string input;
+  proto.SerializeToString(&input);
+  EXPECT_FALSE(crypto_utility_->DecryptData(input, key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, GetRSASubjectPublicKeyInfo) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string output;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key, &output));
+}
+
+TEST_F(CryptoUtilityImplTest, GetRSASubjectPublicKeyInfoBadInput) {
+  std::string public_key = "bad_public_key";
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                           &output));
+}
+
+TEST_F(CryptoUtilityImplTest, GetRSASubjectPublicKeyInfoPairWise) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string output;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key, &output));
+  std::string public_key2;
+  EXPECT_TRUE(crypto_utility_->GetRSAPublicKey(output, &public_key2));
+  EXPECT_EQ(public_key, public_key2);
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptIdentityCredential) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string public_key_info;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                          &public_key_info));
+  EncryptedIdentityCredential output;
+  EXPECT_TRUE(crypto_utility_->EncryptIdentityCredential("credential",
+                                                         public_key_info,
+                                                         "aik",
+                                                         &output));
+  EXPECT_TRUE(output.has_asym_ca_contents());
+  EXPECT_TRUE(output.has_sym_ca_attestation());
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptIdentityCredentialBadEK) {
+  EncryptedIdentityCredential output;
+  EXPECT_FALSE(crypto_utility_->EncryptIdentityCredential("credential",
+                                                          "bad_ek",
+                                                          "aik",
+                                                          &output));
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptForUnbind) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string public_key_info;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                          &public_key_info));
+  std::string output;
+  EXPECT_TRUE(crypto_utility_->EncryptForUnbind(public_key_info, "input",
+                                                &output));
+  EXPECT_FALSE(output.empty());
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptForUnbindBadKey) {
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->EncryptForUnbind("bad_key", "input", &output));
+}
+
+TEST_F(CryptoUtilityImplTest, EncryptForUnbindLargeInput) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string public_key_info;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                          &public_key_info));
+  std::string input(1000, 'A');
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->EncryptForUnbind(public_key_info, input,
+                                                 &output));
+}
+
+TEST_F(CryptoUtilityImplTest, VerifySignatureBadSignature) {
+  std::string public_key = HexDecode(kValidPublicKeyHex);
+  std::string public_key_info;
+  EXPECT_TRUE(crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                          &public_key_info));
+  std::string output;
+  EXPECT_FALSE(crypto_utility_->VerifySignature(public_key_info, "input",
+                                                "signature"));
+}
+
+TEST_F(CryptoUtilityImplTest, VerifySignatureBadKey) {
+  EXPECT_FALSE(crypto_utility_->VerifySignature("bad_key", "input", ""));
+}
+
+}  // namespace attestation
diff --git a/common/database.proto b/common/database.proto
new file mode 100644
index 0000000..74d0f99
--- /dev/null
+++ b/common/database.proto
@@ -0,0 +1,113 @@
+// Copyright 2015 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.
+
+option optimize_for = LITE_RUNTIME;
+
+import "common.proto";
+
+package attestation;
+
+// Holds TPM credentials that the attestation server will need to see. These
+// credentials must be cleared once the attestation server has certified the
+// AIK.
+message TPMCredentials {
+  optional bytes endorsement_public_key = 1;
+  optional bytes endorsement_credential = 2;
+  optional bytes platform_credential = 3;
+  optional bytes conformance_credential = 4;
+  // The |endorsement_credential| encrypted with a public key associated with
+  // the default Chrome OS Privacy CA.
+  optional EncryptedData default_encrypted_endorsement_credential = 5;
+  optional EncryptedData alternate_encrypted_endorsement_credential = 6;
+}
+
+// Holds information relevant to a particular AIK.
+message IdentityKey {
+  // The DER encoded public key.
+  optional bytes identity_public_key = 1;
+  // The TPM-specific key blob that can be loaded back into the TPM.
+  optional bytes identity_key_blob = 2;
+  // A credential issued by the attestation server.
+  optional bytes identity_credential = 3;
+}
+
+// Holds information required to verify the binding of an AIK to an EK. This
+// information should be cleared once the attestation server has certified the
+// AIK.
+message IdentityBinding {
+  // The binding data, as output by the TPM_MakeIdentity operation.
+  optional bytes identity_binding = 1;
+  // The AIK public key, DER encoded.
+  optional bytes identity_public_key_der = 2;
+  // The AIK public key, in TPM_PUBKEY form.
+  optional bytes identity_public_key = 3;
+  // The label used during AIK creation.
+  optional bytes identity_label = 4;
+  // The PCA public key used during AIK creation, in TPM_PUBKEY form.
+  optional bytes pca_public_key = 5;
+}
+
+// Holds owner delegation information.
+message Delegation {
+  // The delegate owner blob.
+  optional bytes blob = 1;
+  // The authorization secret.
+  optional bytes secret = 2;
+  // Whether this delegate has permissions to call TPM_ResetLockValue.
+  optional bool has_reset_lock_permissions = 3;
+}
+
+// Holds information about a certified key.
+message CertifiedKey {
+  // The TPM-wrapped key blob.
+  optional bytes key_blob = 1;
+  // The public key in ASN.1 DER form.
+  optional bytes public_key = 2;
+  // The credential of the certified key in X.509 format.
+  optional bytes certified_key_credential = 3;
+  // The issuer intermediate CA certificate in X.509 format.
+  optional bytes intermediate_ca_cert = 4;
+  // A key name.  This is not necessarily a unique identifier.
+  optional bytes key_name = 5;
+  // An arbitrary payload associated with the key.
+  optional bytes payload = 6;
+  // Addtional intermediate CA certificates that helps chaining up to the root
+  // CA. See |AttestationCertificateResponse.additional_intermediate_ca_cert|
+  // for more detail.
+  repeated bytes additional_intermediate_ca_cert = 7;
+  // The public key in TPM_PUBKEY form.
+  optional bytes public_key_tpm_format = 8;
+  // The serialized TPM_CERTIFY_INFO for the certified key.
+  optional bytes certified_key_info = 9;
+  // The signature of the TPM_CERTIFY_INFO by the AIK.
+  optional bytes certified_key_proof = 10;
+  // The original key type specified when the key was created.
+  optional KeyType key_type = 11;
+  // The original key usage specified when the key was created.
+  optional KeyUsage key_usage = 12;
+}
+
+// Holds all information that a client stores locally.
+message AttestationDatabase {
+  optional TPMCredentials credentials = 2;
+  optional IdentityBinding identity_binding = 3;
+  optional IdentityKey identity_key = 4;
+  optional Quote pcr0_quote = 5;
+  optional Quote pcr1_quote = 12;
+  optional Delegation delegate = 6;
+  repeated CertifiedKey device_keys = 7;
+
+  message TemporalIndexRecord {
+    optional bytes user_hash = 1;
+    optional bytes origin_hash = 2;
+    optional int32 temporal_index = 3;
+  }
+  repeated TemporalIndexRecord temporal_index_record = 8;
+
+  optional IdentityBinding alternate_identity_binding = 9;
+  optional IdentityKey alternate_identity_key = 10;
+  optional Quote alternate_pcr0_quote = 11;
+  optional Quote alternate_pcr1_quote = 13;
+}
+
diff --git a/common/dbus_interface.h b/common/dbus_interface.h
new file mode 100644
index 0000000..ffe90ab
--- /dev/null
+++ b/common/dbus_interface.h
@@ -0,0 +1,28 @@
+// Copyright 2014 The Chromium OS 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 ATTESTATION_COMMON_DBUS_INTERFACE_H_
+#define ATTESTATION_COMMON_DBUS_INTERFACE_H_
+
+namespace attestation {
+
+// TODO(namnguyen): Move to chromeos/system_api once we're ready.
+constexpr char kAttestationInterface[] = "org.chromium.Attestation";
+constexpr char kAttestationServicePath[] = "/org/chromium/Attestation";
+constexpr char kAttestationServiceName[] = "org.chromium.Attestation";
+
+// Methods exported by attestation.
+constexpr char kCreateGoogleAttestedKey[] = "CreateGoogleAttestedKey";
+constexpr char kGetKeyInfo[] = "GetKeyInfo";
+constexpr char kGetEndorsementInfo[] = "GetEndorsementInfo";
+constexpr char kGetAttestationKeyInfo[] = "GetAttestationKeyInfo";
+constexpr char kActivateAttestationKey[] = "ActivateAttestationKey";
+constexpr char kCreateCertifiableKey[] = "CreateCertifiableKey";
+constexpr char kDecrypt[] = "Decrypt";
+constexpr char kSign[] = "Sign";
+constexpr char kRegisterKeyWithChapsToken[] = "RegisterKeyWithChapsToken";
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_DBUS_INTERFACE_H_
diff --git a/common/interface.proto b/common/interface.proto
new file mode 100644
index 0000000..e73953d
--- /dev/null
+++ b/common/interface.proto
@@ -0,0 +1,161 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+option optimize_for = LITE_RUNTIME;
+
+import "common.proto";
+
+package attestation;
+
+enum AttestationStatus {
+  STATUS_SUCCESS = 0;
+  STATUS_UNEXPECTED_DEVICE_ERROR = 1;
+  STATUS_NOT_AVAILABLE = 2;
+  STATUS_NOT_READY = 3;
+  STATUS_NOT_ALLOWED = 4;
+  STATUS_INVALID_PARAMETER = 5;
+  STATUS_REQUEST_DENIED_BY_CA = 6;
+  STATUS_CA_NOT_AVAILABLE = 7;
+}
+
+message CreateGoogleAttestedKeyRequest {
+  // An arbitrary label which can be used to reference the key later.
+  optional string key_label = 1;
+  optional KeyType key_type = 2;
+  optional KeyUsage key_usage = 3;
+  // Describes the certificate to be requested of the CA.
+  optional CertificateProfile certificate_profile = 4;
+  // Provided if the new key should be accessible only by a particular user. If
+  // this field is not set or is the empty string, the key will be accessible
+  // system-wide.
+  optional string username = 5;
+  // If the |certificate_profile| is intended to be bound to a particular origin
+  // this field specifies the origin. For most profiles this is not required.
+  optional string origin = 6;
+}
+
+message CreateGoogleAttestedKeyReply {
+  optional AttestationStatus status = 1;
+  // More information about a server-side error. This only exists
+  // if status=REQUEST_DENIED_BY_CA.
+  optional string server_error = 2;
+  // A PEM-encoded list of X.509 certificates starting with the requested
+  // certificate issued by the CA and followed by certificates for any
+  // intermediate authorities, in order. The Google Attestation CA root
+  // certificate is well-known and not included.
+  optional string certificate_chain = 3;
+}
+
+message GetKeyInfoRequest {
+  optional string key_label = 1;
+  optional string username = 2;
+}
+
+message GetKeyInfoReply {
+  optional AttestationStatus status = 1;
+  optional KeyType key_type = 2;
+  optional KeyUsage key_usage = 3;
+  // The public key (X.509/DER SubjectPublicKeyInfo).
+  optional bytes public_key = 4;
+  // The serialized TPM_CERTIFY_INFO or TPM2B_ATTEST for the new key.
+  optional bytes certify_info = 5;
+  // The signature of certify_info by the Attestation Key.
+  optional bytes certify_info_signature = 6;
+  // The certificate data associated with the key (if any).
+  optional bytes certificate = 7;
+}
+
+message GetEndorsementInfoRequest {
+  optional KeyType key_type = 1;
+}
+
+message GetEndorsementInfoReply {
+  optional AttestationStatus status = 1;
+  // The endorsement public key (X.509/DER SubjectPublicKeyInfo).
+  optional bytes ek_public_key = 2;
+  // The endorsement certificate (X.509/DER).
+  optional bytes ek_certificate = 3;
+}
+
+message GetAttestationKeyInfoRequest {
+  optional KeyType key_type = 1;
+}
+
+message GetAttestationKeyInfoReply {
+  optional AttestationStatus status = 1;
+  // The attestation public key (X.509/DER SubjectPublicKeyInfo).
+  optional bytes public_key = 2;
+  // The attestation public key in TPM_PUBKEY form.
+  optional bytes public_key_tpm_format = 3;
+  // The attestation key certificate.
+  optional bytes certificate = 4;
+  // A quote of PCR0 at the time of attestation key creation.
+  optional Quote pcr0_quote = 5;
+  // A quote of PCR1 at the time of attestation key creation.
+  optional Quote pcr1_quote = 6;
+}
+
+message ActivateAttestationKeyRequest {
+  optional KeyType key_type = 1;
+  optional EncryptedIdentityCredential encrypted_certificate = 2;
+  optional bool save_certificate = 3;
+}
+
+message ActivateAttestationKeyReply {
+  optional AttestationStatus status = 1;
+  // The decrypted attestation key certificate.
+  optional bytes certificate = 2;
+}
+
+message CreateCertifiableKeyRequest {
+  // An arbitrary label which can be used to reference the key later.
+  optional string key_label = 1;
+  // Provided if the new key should be accessible only by a
+  // particular user. If this field is not set or is the empty
+  // string, the key will be accessible system-wide.
+  optional string username = 2;
+  optional KeyType key_type = 3;
+  optional KeyUsage key_usage = 4;
+}
+
+message CreateCertifiableKeyReply {
+  optional AttestationStatus status = 1;
+  // The new public key (X.509/DER SubjectPublicKeyInfo).
+  optional bytes public_key = 2;
+  // The serialized TPM_CERTIFY_INFO or TPM2B_ATTEST for the new key.
+  optional bytes certify_info = 3;
+  // The signature of certify_info by the Attestation Key.
+  optional bytes certify_info_signature = 4;
+}
+
+message DecryptRequest {
+  optional string key_label = 1;
+  optional string username = 2;
+  optional bytes encrypted_data = 3;
+}
+
+message DecryptReply {
+  optional AttestationStatus status = 1;
+  optional bytes decrypted_data = 2;
+}
+
+message SignRequest {
+  optional string key_label = 1;
+  optional string username = 2;
+  optional bytes data_to_sign = 3;
+}
+
+message SignReply {
+  optional AttestationStatus status = 1;
+  optional bytes signature = 2;
+}
+
+message RegisterKeyWithChapsTokenRequest {
+  optional string key_label = 1;
+  optional string username = 2;
+}
+
+message RegisterKeyWithChapsTokenReply {
+  optional AttestationStatus status = 1;
+}
diff --git a/common/mock_attestation_interface.h b/common/mock_attestation_interface.h
new file mode 100644
index 0000000..eebd05b
--- /dev/null
+++ b/common/mock_attestation_interface.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_MOCK_ATTESTATION_INTERFACE_H_
+#define ATTESTATION_COMMON_MOCK_ATTESTATION_INTERFACE_H_
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "attestation/common/attestation_interface.h"
+
+namespace attestation {
+
+class MockAttestationInterface : public AttestationInterface {
+ public:
+  MockAttestationInterface() = default;
+  virtual ~MockAttestationInterface() = default;
+
+  MOCK_METHOD0(Initialize, bool());
+  MOCK_METHOD2(CreateGoogleAttestedKey, void(
+      const CreateGoogleAttestedKeyRequest&,
+      const CreateGoogleAttestedKeyCallback&));
+  MOCK_METHOD2(GetKeyInfo, void(const GetKeyInfoRequest&,
+                                const GetKeyInfoCallback&));
+  MOCK_METHOD2(GetEndorsementInfo, void(const GetEndorsementInfoRequest&,
+                                        const GetEndorsementInfoCallback&));
+  MOCK_METHOD2(GetAttestationKeyInfo,
+               void(const GetAttestationKeyInfoRequest&,
+                    const GetAttestationKeyInfoCallback&));
+  MOCK_METHOD2(ActivateAttestationKey,
+               void(const ActivateAttestationKeyRequest&,
+                    const ActivateAttestationKeyCallback&));
+  MOCK_METHOD2(CreateCertifiableKey, void(const CreateCertifiableKeyRequest&,
+                                          const CreateCertifiableKeyCallback&));
+  MOCK_METHOD2(Decrypt, void(const DecryptRequest&, const DecryptCallback&));
+  MOCK_METHOD2(Sign, void(const SignRequest&, const SignCallback&));
+  MOCK_METHOD2(RegisterKeyWithChapsToken,
+               void(const RegisterKeyWithChapsTokenRequest&,
+                    const RegisterKeyWithChapsTokenCallback&));
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_MOCK_ATTESTATION_INTERFACE_H_
+
diff --git a/common/mock_crypto_utility.cc b/common/mock_crypto_utility.cc
new file mode 100644
index 0000000..176728c
--- /dev/null
+++ b/common/mock_crypto_utility.cc
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium OS 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 "attestation/common/mock_crypto_utility.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::WithArgs;
+
+namespace {
+
+bool FakeRandom(size_t num_bytes, std::string* output) {
+  *output = std::string(num_bytes, 'A');
+  return true;
+}
+
+bool CopyString(const std::string& s1, std::string* s2) {
+  *s2 = s1;
+  return true;
+}
+
+}  // namespace
+
+namespace attestation {
+
+MockCryptoUtility::MockCryptoUtility() {
+  ON_CALL(*this, GetRandom(_, _)).WillByDefault(Invoke(FakeRandom));
+  ON_CALL(*this, CreateSealedKey(_, _)).WillByDefault(Return(true));
+  ON_CALL(*this, UnsealKey(_, _, _)).WillByDefault(Return(true));
+  ON_CALL(*this, EncryptData(_, _, _, _))
+      .WillByDefault(WithArgs<0, 3>(Invoke(CopyString)));
+  ON_CALL(*this, DecryptData(_, _, _))
+      .WillByDefault(WithArgs<0, 2>(Invoke(CopyString)));
+  ON_CALL(*this, GetRSASubjectPublicKeyInfo(_, _))
+      .WillByDefault(Invoke(CopyString));
+}
+
+MockCryptoUtility::~MockCryptoUtility() {}
+
+}  // namespace attestation
diff --git a/common/mock_crypto_utility.h b/common/mock_crypto_utility.h
new file mode 100644
index 0000000..4aaa1db
--- /dev/null
+++ b/common/mock_crypto_utility.h
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_MOCK_CRYPTO_UTILITY_H_
+#define ATTESTATION_COMMON_MOCK_CRYPTO_UTILITY_H_
+
+#include "attestation/common/crypto_utility.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+namespace attestation {
+
+class MockCryptoUtility : public CryptoUtility {
+ public:
+  MockCryptoUtility();
+  ~MockCryptoUtility() override;
+
+  MOCK_CONST_METHOD2(GetRandom, bool(size_t, std::string*));
+
+  MOCK_METHOD2(CreateSealedKey, bool(std::string* aes_key,
+                                     std::string* sealed_key));
+
+  MOCK_METHOD4(EncryptData, bool(const std::string& data,
+                                 const std::string& aes_key,
+                                 const std::string& sealed_key,
+                                 std::string* encrypted_data));
+
+  MOCK_METHOD3(UnsealKey, bool(const std::string& encrypted_data,
+                               std::string* aes_key,
+                               std::string* sealed_key));
+
+  MOCK_METHOD3(DecryptData, bool(const std::string& encrypted_data,
+                                 const std::string& aes_key,
+                                 std::string* data));
+  MOCK_METHOD2(GetRSASubjectPublicKeyInfo, bool(const std::string&,
+                                                std::string*));
+  MOCK_METHOD2(GetRSAPublicKey, bool(const std::string&, std::string*));
+  MOCK_METHOD4(EncryptIdentityCredential, bool(const std::string&,
+                                               const std::string&,
+                                               const std::string&,
+                                               EncryptedIdentityCredential*));
+  MOCK_METHOD3(EncryptForUnbind, bool(const std::string&,
+                                      const std::string&,
+                                      std::string*));
+  MOCK_METHOD3(VerifySignature, bool(const std::string&,
+                                     const std::string&,
+                                     const std::string&));
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_MOCK_CRYPTO_UTILITY_H_
diff --git a/common/mock_tpm_utility.cc b/common/mock_tpm_utility.cc
new file mode 100644
index 0000000..055bccb
--- /dev/null
+++ b/common/mock_tpm_utility.cc
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium OS 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 "attestation/common/mock_tpm_utility.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::WithArgs;
+
+namespace {
+
+class TransformString {
+ public:
+  explicit TransformString(std::string method) : method_(method) {}
+  bool operator()(const std::string& in, std::string* out) {
+    *out = attestation::MockTpmUtility::Transform(method_, in);
+    return true;
+  }
+
+ private:
+  std::string method_;
+};
+
+class UntransformString {
+ public:
+  explicit UntransformString(std::string method) : method_(method) {}
+  bool operator()(const std::string& in, std::string* out) {
+    std::string suffix = "_fake_transform_" + method_;
+    auto position = in.find(suffix);
+    if (position == std::string::npos) {
+      return false;
+    }
+    *out = in.substr(0, position);
+    return true;
+  }
+
+ private:
+  std::string method_;
+};
+
+}  // namespace
+
+namespace attestation {
+
+MockTpmUtility::MockTpmUtility() {
+  ON_CALL(*this, IsTpmReady()).WillByDefault(Return(true));
+  ON_CALL(*this, ActivateIdentity(_, _, _, _, _, _))
+      .WillByDefault(Return(true));
+  ON_CALL(*this, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
+      .WillByDefault(Return(true));
+  ON_CALL(*this, SealToPCR0(_, _))
+      .WillByDefault(Invoke(TransformString("SealToPCR0")));
+  ON_CALL(*this, Unseal(_, _))
+      .WillByDefault(Invoke(UntransformString("SealToPCR0")));
+  ON_CALL(*this, Unbind(_, _, _))
+      .WillByDefault(WithArgs<1, 2>(Invoke(TransformString("Unbind"))));
+  ON_CALL(*this, Sign(_, _, _))
+      .WillByDefault(WithArgs<1, 2>(Invoke(TransformString("Sign"))));
+}
+
+MockTpmUtility::~MockTpmUtility() {}
+
+// static
+std::string MockTpmUtility::Transform(const std::string& method,
+                                      const std::string& input) {
+  return input + "_fake_transform_" + method;
+}
+
+}  // namespace attestation
diff --git a/common/mock_tpm_utility.h b/common/mock_tpm_utility.h
new file mode 100644
index 0000000..5ebf93f
--- /dev/null
+++ b/common/mock_tpm_utility.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_MOCK_TPM_UTILITY_H_
+#define ATTESTATION_COMMON_MOCK_TPM_UTILITY_H_
+
+#include "attestation/common/tpm_utility.h"
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+namespace attestation {
+
+class MockTpmUtility : public TpmUtility {
+ public:
+  MockTpmUtility();
+  ~MockTpmUtility() override;
+  // By default this class will fake seal/unbind/sign operations by passing the
+  // input through Transform(<method>). E.g. The expected output of a fake Sign
+  // operation on "foo" can be computed by calling
+  // MockTpmUtility::Transform("Sign", "foo").
+  static std::string Transform(const std::string& method,
+                               const std::string& input);
+
+  MOCK_METHOD0(IsTpmReady, bool());
+  MOCK_METHOD6(ActivateIdentity, bool(const std::string&,
+                                      const std::string&,
+                                      const std::string&,
+                                      const std::string&,
+                                      const std::string&,
+                                      std::string*));
+  MOCK_METHOD9(CreateCertifiedKey, bool(KeyType,
+                                        KeyUsage,
+                                        const std::string&,
+                                        const std::string&,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*,
+                                        std::string*));
+  MOCK_METHOD2(SealToPCR0, bool(const std::string&, std::string*));
+  MOCK_METHOD2(Unseal, bool(const std::string&, std::string*));
+  MOCK_METHOD1(GetEndorsementPublicKey, bool(std::string*));
+  MOCK_METHOD3(Unbind, bool(const std::string&, const std::string&,
+                            std::string*));
+  MOCK_METHOD3(Sign, bool(const std::string&, const std::string&,
+                          std::string*));
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_MOCK_TPM_UTILITY_H_
diff --git a/common/print_common_proto.cc b/common/print_common_proto.cc
new file mode 100644
index 0000000..5f5cc37
--- /dev/null
+++ b/common/print_common_proto.cc
@@ -0,0 +1,221 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#include "attestation/common/print_common_proto.h"
+
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+namespace attestation {
+
+std::string GetProtoDebugString(KeyType value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(KeyType value, int indent_size) {
+  if (value == KEY_TYPE_RSA) {
+    return "KEY_TYPE_RSA";
+  }
+  if (value == KEY_TYPE_ECC) {
+    return "KEY_TYPE_ECC";
+  }
+  return "<unknown>";
+}
+
+std::string GetProtoDebugString(KeyUsage value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(KeyUsage value, int indent_size) {
+  if (value == KEY_USAGE_SIGN) {
+    return "KEY_USAGE_SIGN";
+  }
+  if (value == KEY_USAGE_DECRYPT) {
+    return "KEY_USAGE_DECRYPT";
+  }
+  return "<unknown>";
+}
+
+std::string GetProtoDebugString(CertificateProfile value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(CertificateProfile value,
+                                          int indent_size) {
+  if (value == ENTERPRISE_MACHINE_CERTIFICATE) {
+    return "ENTERPRISE_MACHINE_CERTIFICATE";
+  }
+  if (value == ENTERPRISE_USER_CERTIFICATE) {
+    return "ENTERPRISE_USER_CERTIFICATE";
+  }
+  if (value == CONTENT_PROTECTION_CERTIFICATE) {
+    return "CONTENT_PROTECTION_CERTIFICATE";
+  }
+  if (value == CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID) {
+    return "CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID";
+  }
+  if (value == CAST_CERTIFICATE) {
+    return "CAST_CERTIFICATE";
+  }
+  if (value == GFSC_CERTIFICATE) {
+    return "GFSC_CERTIFICATE";
+  }
+  return "<unknown>";
+}
+
+std::string GetProtoDebugString(const Quote& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const Quote& value, int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_quote()) {
+    output += indent + "  quote: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.quote().data(), value.quote().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_quoted_data()) {
+    output += indent + "  quoted_data: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.quoted_data().data(),
+                                        value.quoted_data().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_quoted_pcr_value()) {
+    output += indent + "  quoted_pcr_value: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.quoted_pcr_value().data(),
+                        value.quoted_pcr_value().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_pcr_source_hint()) {
+    output += indent + "  pcr_source_hint: ";
+    base::StringAppendF(
+        &output, "%s", base::HexEncode(value.pcr_source_hint().data(),
+                                       value.pcr_source_hint().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const EncryptedData& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const EncryptedData& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_wrapped_key()) {
+    output += indent + "  wrapped_key: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.wrapped_key().data(),
+                                        value.wrapped_key().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_iv()) {
+    output += indent + "  iv: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.iv().data(), value.iv().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_mac()) {
+    output += indent + "  mac: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.mac().data(), value.mac().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_encrypted_data()) {
+    output += indent + "  encrypted_data: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.encrypted_data().data(),
+                                        value.encrypted_data().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_wrapping_key_id()) {
+    output += indent + "  wrapping_key_id: ";
+    base::StringAppendF(
+        &output, "%s", base::HexEncode(value.wrapping_key_id().data(),
+                                       value.wrapping_key_id().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const SignedData& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const SignedData& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_data()) {
+    output += indent + "  data: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.data().data(), value.data().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_signature()) {
+    output += indent + "  signature: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.signature().data(),
+                                        value.signature().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const EncryptedIdentityCredential& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const EncryptedIdentityCredential& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_asym_ca_contents()) {
+    output += indent + "  asym_ca_contents: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.asym_ca_contents().data(),
+                        value.asym_ca_contents().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_sym_ca_attestation()) {
+    output += indent + "  sym_ca_attestation: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.sym_ca_attestation().data(),
+                        value.sym_ca_attestation().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+}  // namespace attestation
diff --git a/common/print_common_proto.h b/common/print_common_proto.h
new file mode 100644
index 0000000..96d36be
--- /dev/null
+++ b/common/print_common_proto.h
@@ -0,0 +1,38 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#ifndef ATTESTATION_COMMON_PRINT_COMMON_PROTO_H_
+#define ATTESTATION_COMMON_PRINT_COMMON_PROTO_H_
+
+#include <string>
+
+#include "attestation/common/common.pb.h"
+
+namespace attestation {
+
+std::string GetProtoDebugStringWithIndent(KeyType value, int indent_size);
+std::string GetProtoDebugString(KeyType value);
+std::string GetProtoDebugStringWithIndent(KeyUsage value, int indent_size);
+std::string GetProtoDebugString(KeyUsage value);
+std::string GetProtoDebugStringWithIndent(CertificateProfile value,
+                                          int indent_size);
+std::string GetProtoDebugString(CertificateProfile value);
+std::string GetProtoDebugStringWithIndent(const Quote& value, int indent_size);
+std::string GetProtoDebugString(const Quote& value);
+std::string GetProtoDebugStringWithIndent(const EncryptedData& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const EncryptedData& value);
+std::string GetProtoDebugStringWithIndent(const SignedData& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const SignedData& value);
+std::string GetProtoDebugStringWithIndent(
+    const EncryptedIdentityCredential& value,
+    int indent_size);
+std::string GetProtoDebugString(const EncryptedIdentityCredential& value);
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_PRINT_COMMON_PROTO_H_
diff --git a/common/print_interface_proto.cc b/common/print_interface_proto.cc
new file mode 100644
index 0000000..42cb017
--- /dev/null
+++ b/common/print_interface_proto.cc
@@ -0,0 +1,671 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#include "attestation/common/print_interface_proto.h"
+
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+#include "attestation/common/print_common_proto.h"
+
+namespace attestation {
+
+std::string GetProtoDebugString(AttestationStatus value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(AttestationStatus value,
+                                          int indent_size) {
+  if (value == STATUS_SUCCESS) {
+    return "STATUS_SUCCESS";
+  }
+  if (value == STATUS_UNEXPECTED_DEVICE_ERROR) {
+    return "STATUS_UNEXPECTED_DEVICE_ERROR";
+  }
+  if (value == STATUS_NOT_AVAILABLE) {
+    return "STATUS_NOT_AVAILABLE";
+  }
+  if (value == STATUS_NOT_READY) {
+    return "STATUS_NOT_READY";
+  }
+  if (value == STATUS_NOT_ALLOWED) {
+    return "STATUS_NOT_ALLOWED";
+  }
+  if (value == STATUS_INVALID_PARAMETER) {
+    return "STATUS_INVALID_PARAMETER";
+  }
+  if (value == STATUS_REQUEST_DENIED_BY_CA) {
+    return "STATUS_REQUEST_DENIED_BY_CA";
+  }
+  if (value == STATUS_CA_NOT_AVAILABLE) {
+    return "STATUS_CA_NOT_AVAILABLE";
+  }
+  return "<unknown>";
+}
+
+std::string GetProtoDebugString(const CreateGoogleAttestedKeyRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const CreateGoogleAttestedKeyRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_key_usage()) {
+    output += indent + "  key_usage: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_usage(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_certificate_profile()) {
+    output += indent + "  certificate_profile: ";
+    base::StringAppendF(&output, "%s", GetProtoDebugStringWithIndent(
+                                           value.certificate_profile(),
+                                           indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  if (value.has_origin()) {
+    output += indent + "  origin: ";
+    base::StringAppendF(&output, "%s", value.origin().c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const CreateGoogleAttestedKeyReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const CreateGoogleAttestedKeyReply& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_server_error()) {
+    output += indent + "  server_error: ";
+    base::StringAppendF(&output, "%s", value.server_error().c_str());
+    output += "\n";
+  }
+  if (value.has_certificate_chain()) {
+    output += indent + "  certificate_chain: ";
+    base::StringAppendF(&output, "%s", value.certificate_chain().c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetKeyInfoRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const GetKeyInfoRequest& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetKeyInfoReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const GetKeyInfoReply& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_key_usage()) {
+    output += indent + "  key_usage: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_usage(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_public_key()) {
+    output += indent + "  public_key: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.public_key().data(),
+                                        value.public_key().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certify_info()) {
+    output += indent + "  certify_info: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.certify_info().data(),
+                                        value.certify_info().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certify_info_signature()) {
+    output += indent + "  certify_info_signature: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.certify_info_signature().data(),
+                        value.certify_info_signature().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certificate()) {
+    output += indent + "  certificate: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.certificate().data(),
+                                        value.certificate().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetEndorsementInfoRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const GetEndorsementInfoRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetEndorsementInfoReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const GetEndorsementInfoReply& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_ek_public_key()) {
+    output += indent + "  ek_public_key: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.ek_public_key().data(),
+                                        value.ek_public_key().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_ek_certificate()) {
+    output += indent + "  ek_certificate: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.ek_certificate().data(),
+                                        value.ek_certificate().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetAttestationKeyInfoRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const GetAttestationKeyInfoRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const GetAttestationKeyInfoReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const GetAttestationKeyInfoReply& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_public_key()) {
+    output += indent + "  public_key: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.public_key().data(),
+                                        value.public_key().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_public_key_tpm_format()) {
+    output += indent + "  public_key_tpm_format: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.public_key_tpm_format().data(),
+                        value.public_key_tpm_format().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certificate()) {
+    output += indent + "  certificate: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.certificate().data(),
+                                        value.certificate().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_pcr0_quote()) {
+    output += indent + "  pcr0_quote: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.pcr0_quote(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_pcr1_quote()) {
+    output += indent + "  pcr1_quote: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.pcr1_quote(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const ActivateAttestationKeyRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const ActivateAttestationKeyRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_encrypted_certificate()) {
+    output += indent + "  encrypted_certificate: ";
+    base::StringAppendF(&output, "%s", GetProtoDebugStringWithIndent(
+                                           value.encrypted_certificate(),
+                                           indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_save_certificate()) {
+    output += indent + "  save_certificate: ";
+    base::StringAppendF(&output, "%s",
+                        value.save_certificate() ? "true" : "false");
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const ActivateAttestationKeyReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const ActivateAttestationKeyReply& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_certificate()) {
+    output += indent + "  certificate: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.certificate().data(),
+                                        value.certificate().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const CreateCertifiableKeyRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const CreateCertifiableKeyRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  if (value.has_key_type()) {
+    output += indent + "  key_type: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_type(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_key_usage()) {
+    output += indent + "  key_usage: ";
+    base::StringAppendF(&output, "%s",
+                        GetProtoDebugStringWithIndent(value.key_usage(),
+                                                      indent_size + 2).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const CreateCertifiableKeyReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const CreateCertifiableKeyReply& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_public_key()) {
+    output += indent + "  public_key: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.public_key().data(),
+                                        value.public_key().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certify_info()) {
+    output += indent + "  certify_info: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.certify_info().data(),
+                                        value.certify_info().size()).c_str());
+    output += "\n";
+  }
+  if (value.has_certify_info_signature()) {
+    output += indent + "  certify_info_signature: ";
+    base::StringAppendF(
+        &output, "%s",
+        base::HexEncode(value.certify_info_signature().data(),
+                        value.certify_info_signature().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const DecryptRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const DecryptRequest& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  if (value.has_encrypted_data()) {
+    output += indent + "  encrypted_data: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.encrypted_data().data(),
+                                        value.encrypted_data().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const DecryptReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const DecryptReply& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_decrypted_data()) {
+    output += indent + "  decrypted_data: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.decrypted_data().data(),
+                                        value.decrypted_data().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const SignRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const SignRequest& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  if (value.has_data_to_sign()) {
+    output += indent + "  data_to_sign: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.data_to_sign().data(),
+                                        value.data_to_sign().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const SignReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const SignReply& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  if (value.has_signature()) {
+    output += indent + "  signature: ";
+    base::StringAppendF(&output, "%s",
+                        base::HexEncode(value.signature().data(),
+                                        value.signature().size()).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const RegisterKeyWithChapsTokenRequest& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const RegisterKeyWithChapsTokenRequest& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_key_label()) {
+    output += indent + "  key_label: ";
+    base::StringAppendF(&output, "%s", value.key_label().c_str());
+    output += "\n";
+  }
+  if (value.has_username()) {
+    output += indent + "  username: ";
+    base::StringAppendF(&output, "%s", value.username().c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+std::string GetProtoDebugString(const RegisterKeyWithChapsTokenReply& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(
+    const RegisterKeyWithChapsTokenReply& value,
+    int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output =
+      base::StringPrintf("[%s] {\n", value.GetTypeName().c_str());
+
+  if (value.has_status()) {
+    output += indent + "  status: ";
+    base::StringAppendF(
+        &output, "%s",
+        GetProtoDebugStringWithIndent(value.status(), indent_size + 2).c_str());
+    output += "\n";
+  }
+  output += indent + "}\n";
+  return output;
+}
+
+}  // namespace attestation
diff --git a/common/print_interface_proto.h b/common/print_interface_proto.h
new file mode 100644
index 0000000..207bad0
--- /dev/null
+++ b/common/print_interface_proto.h
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#ifndef ATTESTATION_COMMON_PRINT_INTERFACE_PROTO_H_
+#define ATTESTATION_COMMON_PRINT_INTERFACE_PROTO_H_
+
+#include <string>
+
+#include "attestation/common/interface.pb.h"
+
+namespace attestation {
+
+std::string GetProtoDebugStringWithIndent(AttestationStatus value,
+                                          int indent_size);
+std::string GetProtoDebugString(AttestationStatus value);
+std::string GetProtoDebugStringWithIndent(
+    const CreateGoogleAttestedKeyRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const CreateGoogleAttestedKeyRequest& value);
+std::string GetProtoDebugStringWithIndent(
+    const CreateGoogleAttestedKeyReply& value,
+    int indent_size);
+std::string GetProtoDebugString(const CreateGoogleAttestedKeyReply& value);
+std::string GetProtoDebugStringWithIndent(const GetKeyInfoRequest& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const GetKeyInfoRequest& value);
+std::string GetProtoDebugStringWithIndent(const GetKeyInfoReply& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const GetKeyInfoReply& value);
+std::string GetProtoDebugStringWithIndent(
+    const GetEndorsementInfoRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const GetEndorsementInfoRequest& value);
+std::string GetProtoDebugStringWithIndent(const GetEndorsementInfoReply& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const GetEndorsementInfoReply& value);
+std::string GetProtoDebugStringWithIndent(
+    const GetAttestationKeyInfoRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const GetAttestationKeyInfoRequest& value);
+std::string GetProtoDebugStringWithIndent(
+    const GetAttestationKeyInfoReply& value,
+    int indent_size);
+std::string GetProtoDebugString(const GetAttestationKeyInfoReply& value);
+std::string GetProtoDebugStringWithIndent(
+    const ActivateAttestationKeyRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const ActivateAttestationKeyRequest& value);
+std::string GetProtoDebugStringWithIndent(
+    const ActivateAttestationKeyReply& value,
+    int indent_size);
+std::string GetProtoDebugString(const ActivateAttestationKeyReply& value);
+std::string GetProtoDebugStringWithIndent(
+    const CreateCertifiableKeyRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const CreateCertifiableKeyRequest& value);
+std::string GetProtoDebugStringWithIndent(
+    const CreateCertifiableKeyReply& value,
+    int indent_size);
+std::string GetProtoDebugString(const CreateCertifiableKeyReply& value);
+std::string GetProtoDebugStringWithIndent(const DecryptRequest& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const DecryptRequest& value);
+std::string GetProtoDebugStringWithIndent(const DecryptReply& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const DecryptReply& value);
+std::string GetProtoDebugStringWithIndent(const SignRequest& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const SignRequest& value);
+std::string GetProtoDebugStringWithIndent(const SignReply& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const SignReply& value);
+std::string GetProtoDebugStringWithIndent(
+    const RegisterKeyWithChapsTokenRequest& value,
+    int indent_size);
+std::string GetProtoDebugString(const RegisterKeyWithChapsTokenRequest& value);
+std::string GetProtoDebugStringWithIndent(
+    const RegisterKeyWithChapsTokenReply& value,
+    int indent_size);
+std::string GetProtoDebugString(const RegisterKeyWithChapsTokenReply& value);
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_PRINT_INTERFACE_PROTO_H_
diff --git a/common/proto_print.py b/common/proto_print.py
new file mode 100755
index 0000000..3c0703a
--- /dev/null
+++ b/common/proto_print.py
@@ -0,0 +1,405 @@
+#!/usr/bin/python2
+
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""A C++ code generator for printing protobufs which use the LITE_RUNTIME.
+
+Normally printing a protobuf would be done with Message::DebugString(). However,
+this is not available when using only MessageLite. This script generates code to
+emulate Message::DebugString() without using reflection. The input must be a
+valid .proto file.
+
+Usage: proto_print.py [--subdir=foo] <bar.proto>
+
+Files named print_bar_proto.h and print_bar_proto.cc will be created in the
+current working directory.
+"""
+
+from __future__ import print_function
+
+import argparse
+import collections
+from datetime import date
+import os
+import re
+import subprocess
+
+
+# Holds information about a protobuf message field.
+#
+# Attributes:
+#   repeated: Whether the field is a repeated field.
+#   type_: The type of the field. E.g. int32.
+#   name: The name of the field.
+Field = collections.namedtuple('Field', 'repeated type_ name')
+
+
+class Message(object):
+  """Holds information about a protobuf message.
+
+  Attributes:
+    name: The name of the message.
+    fields: A list of Field tuples.
+  """
+
+  def __init__(self, name):
+    """Initializes a Message instance.
+
+    Args:
+      name: The protobuf message name.
+    """
+    self.name = name
+    self.fields = []
+
+  def AddField(self, attribute, field_type, field_name):
+    """Adds a new field to the message.
+
+    Args:
+      attribute: This should be 'optional', 'required', or 'repeated'.
+      field_type: The type of the field. E.g. int32.
+      field_name: The name of the field.
+    """
+    self.fields.append(Field(repeated=attribute == 'repeated',
+                             type_=field_type, name=field_name))
+
+
+class Enum(object):
+  """Holds information about a protobuf enum.
+
+  Attributes:
+    name: The name of the enum.
+    values: A list of enum value names.
+  """
+
+  def __init__(self, name):
+    """Initializes a Enum instance.
+
+    Args:
+      name: The protobuf enum name.
+    """
+    self.name = name
+    self.values = []
+
+  def AddValue(self, value_name):
+    """Adds a new value to the enum.
+
+    Args:
+      value_name: The name of the value.
+    """
+    self.values.append(value_name)
+
+
+def ParseProto(input_file):
+  """Parses a proto file and returns a tuple of parsed information.
+
+  Args:
+    input_file: The proto file to parse.
+
+  Returns:
+    A tuple in the form (package, imports, messages, enums) where
+      package: A string holding the proto package.
+      imports: A list of strings holding proto imports.
+      messages: A list of Message objects; one for each message in the proto.
+      enums: A list of Enum objects; one for each enum in the proto.
+  """
+  package = ''
+  imports = []
+  messages = []
+  enums = []
+  current_message_stack = []
+  current_enum = None
+  package_re = re.compile(r'package\s+(\w+);')
+  import_re = re.compile(r'import\s+"(\w+).proto";')
+  message_re = re.compile(r'message\s+(\w+)\s*{')
+  field_re = re.compile(r'(optional|required|repeated)\s+(\w+)\s+(\w+)\s*=')
+  enum_re = re.compile(r'enum\s+(\w+)\s*{')
+  enum_value_re = re.compile(r'(\w+)\s*=')
+  for line in input_file:
+    line = line.strip()
+    if not line or line.startswith('//'):
+      continue
+    # Close off the current scope. Enums first because they can't be nested.
+    if line == '}':
+      if current_enum:
+        enums.append(current_enum)
+        current_enum = None
+      if current_message_stack:
+        messages.append(current_message_stack.pop())
+      continue
+    # Look for a message definition.
+    match = message_re.search(line)
+    if match:
+      prefix = ''
+      if current_message_stack:
+        prefix = '::'.join([m.name for m in current_message_stack]) + '::'
+      current_message_stack.append(Message(prefix + match.group(1)))
+      continue
+    # Look for a message field definition.
+    if current_message_stack:
+      match = field_re.search(line)
+      if match:
+        current_message_stack[-1].AddField(match.group(1),
+                                           match.group(2),
+                                           match.group(3))
+        continue
+    # Look for an enum definition.
+    match = enum_re.search(line)
+    if match:
+      current_enum = Enum(match.group(1))
+      continue
+    # Look for an enum value.
+    if current_enum:
+      match = enum_value_re.search(line)
+      if match:
+        current_enum.AddValue(match.group(1))
+        continue
+    # Look for a package statement.
+    match = package_re.search(line)
+    if match:
+      package = match.group(1)
+    # Look for an import statement.
+    match = import_re.search(line)
+    if match:
+      imports.append(match.group(1))
+  return package, imports, messages, enums
+
+
+def GenerateFileHeaders(proto_name, package, imports, subdir, header_file_name,
+                        header_file, impl_file):
+  """Generates and prints file headers.
+
+  Args:
+    proto_name: The name of the proto file.
+    package: The protobuf package.
+    imports: A list of imported protos.
+    subdir: The --subdir arg.
+    header_file_name: The header file name.
+    header_file: The header file handle, open for writing.
+    impl_file: The implementation file handle, open for writing.
+  """
+  if subdir:
+    guard_name = '%s_%s_PRINT_%s_PROTO_H_' % (package.upper(),
+                                              subdir.upper(),
+                                              proto_name.upper())
+    package_with_subdir = '%s/%s' % (package, subdir)
+  else:
+    guard_name = '%s_PRINT_%s_PROTO_H_' % (package.upper(), proto_name.upper())
+    package_with_subdir = package
+  includes = '\n'.join(
+      ['#include "%(package_with_subdir)s/print_%(import)s_proto.h"' % {
+          'package_with_subdir': package_with_subdir,
+          'import': current_import} for current_import in imports])
+  header = """\
+// Copyright %(year)s The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#ifndef %(guard_name)s
+#define %(guard_name)s
+
+#include <string>
+
+#include "%(package_with_subdir)s/%(proto)s.pb.h"
+
+namespace %(package)s {
+""" % {'year': date.today().year,
+       'guard_name': guard_name,
+       'package': package,
+       'proto': proto_name,
+       'package_with_subdir': package_with_subdir}
+  impl = """\
+// Copyright %(year)s The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// THIS CODE IS GENERATED.
+
+#include "%(package_with_subdir)s/%(header_file_name)s"
+
+#include <string>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
+
+%(includes)s
+
+namespace %(package)s {
+""" % {'year': date.today().year,
+       'package': package,
+       'package_with_subdir': package_with_subdir,
+       'header_file_name': header_file_name,
+       'includes': includes}
+
+  header_file.write(header)
+  impl_file.write(impl)
+
+
+def GenerateFileFooters(proto_name, package, subdir, header_file, impl_file):
+  """Generates and prints file footers.
+
+  Args:
+    proto_name: The name of the proto file.
+    package: The protobuf package.
+    subdir: The --subdir arg.
+    header_file: The header file handle, open for writing.
+    impl_file: The implementation file handle, open for writing.
+  """
+  if subdir:
+    guard_name = '%s_%s_PRINT_%s_PROTO_H_' % (package.upper(),
+                                              subdir.upper(),
+                                              proto_name.upper())
+  else:
+    guard_name = '%s_PRINT_%s_PROTO_H_' % (package.upper(), proto_name.upper())
+  header = """
+
+}  // namespace %(package)s
+
+#endif  // %(guard_name)s
+""" % {'guard_name': guard_name, 'package': package}
+  impl = """
+}  // namespace %(package)s
+""" % {'package': package}
+
+  header_file.write(header)
+  impl_file.write(impl)
+
+
+def GenerateEnumPrinter(enum, header_file, impl_file):
+  """Generates and prints a function to print an enum value.
+
+  Args:
+    enum: An Enum instance.
+    header_file: The header file handle, open for writing.
+    impl_file: The implementation file handle, open for writing.
+  """
+  declare = """
+std::string GetProtoDebugStringWithIndent(%(name)s value, int indent_size);
+std::string GetProtoDebugString(%(name)s value);""" % {'name': enum.name}
+  define_begin = """
+std::string GetProtoDebugString(%(name)s value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(%(name)s value, int indent_size) {
+""" % {'name': enum.name}
+  define_end = """
+  return "<unknown>";
+}
+"""
+  condition = """
+  if (value == %(value_name)s) {
+    return "%(value_name)s";
+  }"""
+
+  header_file.write(declare)
+  impl_file.write(define_begin)
+  for value_name in enum.values:
+    impl_file.write(condition % {'value_name': value_name})
+  impl_file.write(define_end)
+
+
+def GenerateMessagePrinter(message, header_file, impl_file):
+  """Generates and prints a function to print a message.
+
+  Args:
+    message: A Message instance.
+    header_file: The header file handle, open for writing.
+    impl_file: The implementation file handle, open for writing.
+  """
+  declare = """
+std::string GetProtoDebugStringWithIndent(const %(name)s& value,
+                                          int indent_size);
+std::string GetProtoDebugString(const %(name)s& value);""" % {'name':
+                                                              message.name}
+  define_begin = """
+std::string GetProtoDebugString(const %(name)s& value) {
+  return GetProtoDebugStringWithIndent(value, 0);
+}
+
+std::string GetProtoDebugStringWithIndent(const %(name)s& value,
+                                          int indent_size) {
+  std::string indent(indent_size, ' ');
+  std::string output = base::StringPrintf("[%%s] {\\n",
+                                          value.GetTypeName().c_str());
+""" % {'name': message.name}
+  define_end = """
+  output += indent + "}\\n";
+  return output;
+}
+"""
+  singular_field = """
+  if (value.has_%(name)s()) {
+    output += indent + "  %(name)s: ";
+    base::StringAppendF(&output, %(format)s);
+    output += "\\n";
+  }"""
+  repeated_field = """
+  output += indent + "  %(name)s: {";
+  for (int i = 0; i < value.%(name)s_size(); ++i) {
+    base::StringAppendF(&output, %(format)s);
+  }
+  output += "}\\n";"""
+  singular_field_get = 'value.%(name)s()'
+  repeated_field_get = 'value.%(name)s(i)'
+  formats = {'bool': '"%%s", %(value)s ? "true" : "false"',
+             'int32': '"%%d", %(value)s',
+             'int64': '"%%ld", %(value)s',
+             'uint32': '"%%u", %(value)s',
+             'uint64': '"%%lu", %(value)s',
+             'string': '"%%s", %(value)s.c_str()',
+             'bytes': """"%%s", base::HexEncode(%(value)s.data(),
+                                                %(value)s.size()).c_str()"""}
+  subtype_format = ('"%%s", GetProtoDebugStringWithIndent(%(value)s, '
+                    'indent_size + 2).c_str()')
+
+  header_file.write(declare)
+  impl_file.write(define_begin)
+  for field in message.fields:
+    if field.repeated:
+      value_get = repeated_field_get % {'name': field.name}
+      field_code = repeated_field
+    else:
+      value_get = singular_field_get % {'name': field.name}
+      field_code = singular_field
+    if field.type_ in formats:
+      value_format = formats[field.type_] % {'value': value_get}
+    else:
+      value_format = subtype_format % {'value': value_get}
+    impl_file.write(field_code % {'name': field.name,
+                                  'format': value_format})
+  impl_file.write(define_end)
+
+
+def FormatFile(filename):
+  subprocess.call(['clang-format', '-i', '-style=Chromium', filename])
+
+
+def main():
+  parser = argparse.ArgumentParser(description='print proto code generator')
+  parser.add_argument('input_file')
+  parser.add_argument('--subdir', default='')
+  args = parser.parse_args()
+  with open(args.input_file) as input_file:
+    package, imports, messages, enums = ParseProto(input_file)
+  proto_name = os.path.basename(args.input_file).rsplit('.', 1)[0]
+  header_file_name = 'print_%s_proto.h' % proto_name
+  impl_file_name = 'print_%s_proto.cc' % proto_name
+  with open(header_file_name, 'w') as header_file:
+    with open(impl_file_name, 'w') as impl_file:
+      GenerateFileHeaders(proto_name, package, imports, args.subdir,
+                          header_file_name, header_file, impl_file)
+      for enum in enums:
+        GenerateEnumPrinter(enum, header_file, impl_file)
+      for message in messages:
+        GenerateMessagePrinter(message, header_file, impl_file)
+      GenerateFileFooters(proto_name, package, args.subdir, header_file,
+                          impl_file)
+  FormatFile(header_file_name)
+  FormatFile(impl_file_name)
+
+if __name__ == '__main__':
+  main()
diff --git a/common/tpm_utility.h b/common/tpm_utility.h
new file mode 100644
index 0000000..e9cc1e3
--- /dev/null
+++ b/common/tpm_utility.h
@@ -0,0 +1,85 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_TPM_UTILITY_H_
+#define ATTESTATION_COMMON_TPM_UTILITY_H_
+
+#include <string>
+
+#include "attestation/common/interface.pb.h"
+
+namespace attestation {
+
+// A class which provides helpers for TPM-related tasks.
+class TpmUtility {
+ public:
+  virtual ~TpmUtility() = default;
+
+  // Returns true iff the TPM is enabled, owned, and ready for attestation.
+  virtual bool IsTpmReady() = 0;
+
+  // Activates an attestation identity key. Effectively this decrypts a
+  // certificate or some other type of credential with the endorsement key. The
+  // |delegate_blob| and |delegate_secret| must be authorized to activate with
+  // owner privilege. The |identity_key_blob| is the key to which the credential
+  // is bound. The |asym_ca_contents| and |sym_ca_attestation| parameters are
+  // encrypted TPM structures, typically created by a CA (TPM_ASYM_CA_CONTENTS
+  // and TPM_SYM_CA_ATTESTATION respectively). On success returns true and
+  // populates the decrypted |credential|.
+  virtual bool ActivateIdentity(const std::string& delegate_blob,
+                                const std::string& delegate_secret,
+                                const std::string& identity_key_blob,
+                                const std::string& asym_ca_contents,
+                                const std::string& sym_ca_attestation,
+                                std::string* credential) = 0;
+
+  // Generates and certifies a non-migratable key in the TPM. The new key will
+  // correspond to |key_type| and |key_usage|. The parent key will be the
+  // storage root key. The new key will be certified with the attestation
+  // identity key represented by |identity_key_blob|. The |external_data| will
+  // be included in the |key_info|. On success, returns true and populates
+  // |public_key_tpm_format| with the public key of |key_blob| in TPM_PUBKEY
+  // format, |key_info| with the TPM_CERTIFY_INFO that was signed, and |proof|
+  // with the signature of |key_info| by the identity key.
+  virtual bool CreateCertifiedKey(KeyType key_type,
+                                  KeyUsage key_usage,
+                                  const std::string& identity_key_blob,
+                                  const std::string& external_data,
+                                  std::string* key_blob,
+                                  std::string* public_key,
+                                  std::string* public_key_tpm_format,
+                                  std::string* key_info,
+                                  std::string* proof) = 0;
+
+  // Seals |data| to the current value of PCR0 with the SRK and produces the
+  // |sealed_data|. Returns true on success.
+  virtual bool SealToPCR0(const std::string& data,
+                          std::string* sealed_data) = 0;
+
+  // Unseals |sealed_data| previously sealed with the SRK and produces the
+  // unsealed |data|. Returns true on success.
+  virtual bool Unseal(const std::string& sealed_data, std::string* data) = 0;
+
+  // Reads the endorsement public key from the TPM.
+  virtual bool GetEndorsementPublicKey(std::string* public_key) = 0;
+
+  // Unbinds |bound_data| with the key loaded from |key_blob| by decrypting
+  // using the TPM_ES_RSAESOAEP_SHA1_MGF1 scheme. The input must be in the
+  // format of a TPM_BOUND_DATA structure. On success returns true and provides
+  // the decrypted |data|.
+  virtual bool Unbind(const std::string& key_blob,
+                      const std::string& bound_data,
+                      std::string* data) = 0;
+
+  // Signs |data_to_sign| with the key loaded from |key_blob| using the
+  // TPM_SS_RSASSAPKCS1v15_DER scheme with SHA-256. On success returns true and
+  // provides the |signature|.
+  virtual bool Sign(const std::string& key_blob,
+                    const std::string& data_to_sign,
+                    std::string* signature) = 0;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_TPM_UTILITY_H_
diff --git a/common/tpm_utility_v1.cc b/common/tpm_utility_v1.cc
new file mode 100644
index 0000000..6e918f0
--- /dev/null
+++ b/common/tpm_utility_v1.cc
@@ -0,0 +1,708 @@
+// Copyright 2015 The Chromium OS 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 "attestation/common/tpm_utility_v1.h"
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/stl_util.h>
+#include <crypto/scoped_openssl_types.h>
+#include <crypto/sha2.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <trousers/scoped_tss_type.h>
+#include <trousers/trousers.h>
+#include <trousers/tss.h>
+
+#define TPM_LOG(severity, result) \
+    LOG(severity) << "TPM error 0x" << std::hex << result \
+                  << " (" << Trspi_Error_String(result) << "): "
+
+using trousers::ScopedTssContext;
+using trousers::ScopedTssKey;
+using trousers::ScopedTssMemory;
+using trousers::ScopedTssPcrs;
+
+namespace {
+
+using ScopedByteArray = scoped_ptr<BYTE, base::FreeDeleter>;
+using ScopedTssEncryptedData = trousers::ScopedTssObject<TSS_HENCDATA>;
+using ScopedTssHash = trousers::ScopedTssObject<TSS_HHASH>;
+
+const char* kTpmEnabledFile = "/sys/class/misc/tpm0/device/enabled";
+const char* kTpmOwnedFile = "/sys/class/misc/tpm0/device/owned";
+const unsigned int kWellKnownExponent = 65537;
+const unsigned char kSha256DigestInfo[] = {
+  0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+  0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+};
+
+std::string GetFirstByte(const char* file_name) {
+  std::string content;
+  base::ReadFileToString(base::FilePath(file_name), &content);
+  if (content.size() > 1) {
+    content.resize(1);
+  }
+  return content;
+}
+
+BYTE* StringAsTSSBuffer(std::string* s) {
+  return reinterpret_cast<BYTE*>(string_as_array(s));
+}
+
+std::string TSSBufferAsString(const BYTE* buffer, size_t length) {
+  return std::string(reinterpret_cast<const char*>(buffer), length);
+}
+
+}  // namespace
+
+namespace attestation {
+
+TpmUtilityV1::~TpmUtilityV1() {}
+
+bool TpmUtilityV1::Initialize() {
+  if (!ConnectContext(&context_handle_, &tpm_handle_)) {
+    LOG(ERROR) << __func__ << ": Failed to connect to the TPM.";
+    return false;
+  }
+  if (!IsTpmReady()) {
+    LOG(WARNING) << __func__ << ": TPM is not owned; attestation services will "
+                 << "not be available until ownership is taken.";
+  }
+  return true;
+}
+
+bool TpmUtilityV1::IsTpmReady() {
+  if (!is_ready_) {
+    is_ready_ = (GetFirstByte(kTpmEnabledFile) == "1" &&
+                 GetFirstByte(kTpmOwnedFile) == "1");
+  }
+  return is_ready_;
+}
+
+bool TpmUtilityV1::ActivateIdentity(const std::string& delegate_blob,
+                                    const std::string& delegate_secret,
+                                    const std::string& identity_key_blob,
+                                    const std::string& asym_ca_contents,
+                                    const std::string& sym_ca_attestation,
+                                    std::string* credential) {
+  CHECK(credential);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+
+  // Connect to the TPM as the owner delegate.
+  ScopedTssContext context_handle;
+  TSS_HTPM tpm_handle;
+  if (!ConnectContextAsDelegate(delegate_blob, delegate_secret,
+                                &context_handle, &tpm_handle)) {
+    LOG(ERROR) << __func__ << ": Could not connect to the TPM.";
+    return false;
+  }
+  // Load the Storage Root Key.
+  TSS_RESULT result;
+  ScopedTssKey srk_handle(context_handle);
+  if (!LoadSrk(context_handle, &srk_handle)) {
+    LOG(ERROR) << __func__ << ": Failed to load SRK.";
+    return false;
+  }
+  // Load the AIK (which is wrapped by the SRK).
+  std::string mutable_identity_key_blob(identity_key_blob);
+  BYTE* identity_key_blob_buffer = StringAsTSSBuffer(
+      &mutable_identity_key_blob);
+  ScopedTssKey identity_key(context_handle);
+  result = Tspi_Context_LoadKeyByBlob(
+      context_handle,
+      srk_handle,
+      identity_key_blob.size(),
+      identity_key_blob_buffer,
+      identity_key.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load AIK.";
+    return false;
+  }
+  std::string mutable_asym_ca_contents(asym_ca_contents);
+  BYTE* asym_ca_contents_buffer = StringAsTSSBuffer(&mutable_asym_ca_contents);
+  std::string mutable_sym_ca_attestation(sym_ca_attestation);
+  BYTE* sym_ca_attestation_buffer = StringAsTSSBuffer(
+      &mutable_sym_ca_attestation);
+  UINT32 credential_length = 0;
+  ScopedTssMemory credential_buffer(context_handle);
+  result = Tspi_TPM_ActivateIdentity(tpm_handle, identity_key,
+                                     asym_ca_contents.size(),
+                                     asym_ca_contents_buffer,
+                                     sym_ca_attestation.size(),
+                                     sym_ca_attestation_buffer,
+                                     &credential_length,
+                                     credential_buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to activate identity.";
+    return false;
+  }
+  credential->assign(TSSBufferAsString(credential_buffer.value(),
+                                       credential_length));
+  return true;
+}
+
+bool TpmUtilityV1::CreateCertifiedKey(KeyType key_type,
+                                      KeyUsage key_usage,
+                                      const std::string& identity_key_blob,
+                                      const std::string& external_data,
+                                      std::string* key_blob,
+                                      std::string* public_key,
+                                      std::string* public_key_tpm_format,
+                                      std::string* key_info,
+                                      std::string* proof) {
+  CHECK(key_blob && public_key && public_key_tpm_format && key_info && proof);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+  if (key_type != KEY_TYPE_RSA) {
+    LOG(ERROR) << "Only RSA supported on TPM v1.2.";
+    return false;
+  }
+
+  // Load the AIK (which is wrapped by the SRK).
+  ScopedTssKey identity_key(context_handle_);
+  if (!LoadKeyFromBlob(identity_key_blob, context_handle_, srk_handle_,
+                       &identity_key)) {
+    LOG(ERROR) << __func__ << "Failed to load AIK.";
+    return false;
+  }
+
+  // Create a non-migratable RSA key.
+  ScopedTssKey key(context_handle_);
+  UINT32 tss_key_type = (key_usage == KEY_USAGE_SIGN) ? TSS_KEY_TYPE_SIGNING :
+                                                        TSS_KEY_TYPE_BIND;
+  UINT32 init_flags = tss_key_type |
+                      TSS_KEY_NOT_MIGRATABLE |
+                      TSS_KEY_VOLATILE |
+                      TSS_KEY_NO_AUTHORIZATION |
+                      TSS_KEY_SIZE_2048;
+  TSS_RESULT result = Tspi_Context_CreateObject(context_handle_,
+                                                TSS_OBJECT_TYPE_RSAKEY,
+                                                init_flags, key.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create object.";
+    return false;
+  }
+  if (key_usage == KEY_USAGE_SIGN) {
+    result = Tspi_SetAttribUint32(key,
+                                  TSS_TSPATTRIB_KEY_INFO,
+                                  TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
+                                  TSS_SS_RSASSAPKCS1V15_DER);
+  } else {
+    result = Tspi_SetAttribUint32(key,
+                                  TSS_TSPATTRIB_KEY_INFO,
+                                  TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
+                                  TSS_ES_RSAESOAEP_SHA1_MGF1);
+  }
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to set scheme.";
+    return false;
+  }
+  result = Tspi_Key_CreateKey(key, srk_handle_, 0);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create key.";
+    return false;
+  }
+  result = Tspi_Key_LoadKey(key, srk_handle_);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load key.";
+    return false;
+  }
+
+  // Certify the key.
+  TSS_VALIDATION validation;
+  memset(&validation, 0, sizeof(validation));
+  validation.ulExternalDataLength = external_data.size();
+  std::string mutable_external_data(external_data);
+  validation.rgbExternalData = StringAsTSSBuffer(&mutable_external_data);
+  result = Tspi_Key_CertifyKey(key, identity_key, &validation);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to certify key.";
+    return false;
+  }
+  ScopedTssMemory scoped_certified_data(0, validation.rgbData);
+  ScopedTssMemory scoped_proof(0, validation.rgbValidationData);
+
+  // Get the certified public key.
+  if (!GetDataAttribute(context_handle_,
+                        key,
+                        TSS_TSPATTRIB_KEY_BLOB,
+                        TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,
+                        public_key_tpm_format)) {
+    LOG(ERROR) << __func__ << ": Failed to read public key.";
+    return false;
+  }
+  if (!ConvertPublicKeyToDER(*public_key_tpm_format, public_key)) {
+    return false;
+  }
+
+  // Get the certified key blob so we can load it later.
+  if (!GetDataAttribute(context_handle_,
+                        key,
+                        TSS_TSPATTRIB_KEY_BLOB,
+                        TSS_TSPATTRIB_KEYBLOB_BLOB,
+                        key_blob)) {
+    LOG(ERROR) << __func__ << ": Failed to read key blob.";
+    return false;
+  }
+
+  // Get the data that was certified.
+  key_info->assign(TSSBufferAsString(validation.rgbData,
+                                     validation.ulDataLength));
+
+  // Get the certification proof.
+  proof->assign(TSSBufferAsString(validation.rgbValidationData,
+                                  validation.ulValidationDataLength));
+  return true;
+}
+
+bool TpmUtilityV1::SealToPCR0(const std::string& data,
+                              std::string* sealed_data) {
+  CHECK(sealed_data);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+
+  // Create a PCRS object which holds the value of PCR0.
+  ScopedTssPcrs pcrs_handle(context_handle_);
+  TSS_RESULT result;
+  if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle_,
+                                                   TSS_OBJECT_TYPE_PCRS,
+                                                   TSS_PCRS_STRUCT_INFO,
+                                                   pcrs_handle.ptr()))) {
+    TPM_LOG(ERROR, result)
+        << __func__ << ": Error calling Tspi_Context_CreateObject";
+    return false;
+  }
+  UINT32 pcr_length = 0;
+  ScopedTssMemory pcr_value(context_handle_);
+  Tspi_TPM_PcrRead(tpm_handle_, 0, &pcr_length, pcr_value.ptr());
+  Tspi_PcrComposite_SetPcrValue(pcrs_handle, 0, pcr_length, pcr_value.value());
+
+  // Create a ENCDATA object to receive the sealed data.
+  ScopedTssKey encrypted_data_handle(context_handle_);
+  if (TPM_ERROR(result = Tspi_Context_CreateObject(
+      context_handle_,
+      TSS_OBJECT_TYPE_ENCDATA,
+      TSS_ENCDATA_SEAL,
+      encrypted_data_handle.ptr()))) {
+    TPM_LOG(ERROR, result)
+        << __func__ << ": Error calling Tspi_Context_CreateObject";
+    return false;
+  }
+
+  // Seal the given value with the SRK.
+  std::string mutable_data(data);
+  BYTE* data_buffer = StringAsTSSBuffer(&mutable_data);
+  if (TPM_ERROR(result = Tspi_Data_Seal(
+      encrypted_data_handle,
+      srk_handle_,
+      data.size(),
+      data_buffer,
+      pcrs_handle))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Data_Seal";
+    return false;
+  }
+
+  // Extract the sealed value.
+  ScopedTssMemory encrypted_data(context_handle_);
+  UINT32 encrypted_data_length = 0;
+  if (TPM_ERROR(result = Tspi_GetAttribData(encrypted_data_handle,
+                                            TSS_TSPATTRIB_ENCDATA_BLOB,
+                                            TSS_TSPATTRIB_ENCDATABLOB_BLOB,
+                                            &encrypted_data_length,
+                                            encrypted_data.ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_GetAttribData";
+    return false;
+  }
+  sealed_data->assign(TSSBufferAsString(encrypted_data.value(),
+                                        encrypted_data_length));
+  return true;
+}
+
+bool TpmUtilityV1::Unseal(const std::string& sealed_data, std::string* data) {
+  CHECK(data);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+
+  // Create an ENCDATA object with the sealed value.
+  ScopedTssKey encrypted_data_handle(context_handle_);
+  TSS_RESULT result;
+  if (TPM_ERROR(result = Tspi_Context_CreateObject(
+      context_handle_,
+      TSS_OBJECT_TYPE_ENCDATA,
+      TSS_ENCDATA_SEAL,
+      encrypted_data_handle.ptr()))) {
+    TPM_LOG(ERROR, result)
+        << __func__ << ": Error calling Tspi_Context_CreateObject";
+    return false;
+  }
+
+  std::string mutable_sealed_data(sealed_data);
+  BYTE* sealed_data_buffer = StringAsTSSBuffer(&mutable_sealed_data);
+  if (TPM_ERROR(result = Tspi_SetAttribData(encrypted_data_handle,
+      TSS_TSPATTRIB_ENCDATA_BLOB,
+      TSS_TSPATTRIB_ENCDATABLOB_BLOB,
+      sealed_data.size(),
+      sealed_data_buffer))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_SetAttribData";
+    return false;
+  }
+
+  // Unseal using the SRK.
+  ScopedTssMemory decrypted_data(context_handle_);
+  UINT32 decrypted_data_length = 0;
+  if (TPM_ERROR(result = Tspi_Data_Unseal(encrypted_data_handle,
+                                          srk_handle_,
+                                          &decrypted_data_length,
+                                          decrypted_data.ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Data_Unseal";
+    return false;
+  }
+  data->assign(TSSBufferAsString(decrypted_data.value(),
+                                 decrypted_data_length));
+  return true;
+}
+
+bool TpmUtilityV1::GetEndorsementPublicKey(std::string* public_key) {
+  // Get a handle to the EK public key.
+  ScopedTssKey ek_public_key_object(context_handle_);
+  TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey(tpm_handle_, false, nullptr,
+                                                    ek_public_key_object.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to get key.";
+    return false;
+  }
+  // Get the public key in TPM_PUBKEY form.
+  std::string ek_public_key_blob;
+  if (!GetDataAttribute(context_handle_,
+                        ek_public_key_object,
+                        TSS_TSPATTRIB_KEY_BLOB,
+                        TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,
+                        &ek_public_key_blob)) {
+    LOG(ERROR) << __func__ << ": Failed to read public key.";
+    return false;
+  }
+  // Get the public key in DER encoded form.
+  if (!ConvertPublicKeyToDER(ek_public_key_blob, public_key)) {
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::Unbind(const std::string& key_blob,
+                          const std::string& bound_data,
+                          std::string* data) {
+  CHECK(data);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+  ScopedTssKey key_handle(context_handle_);
+  if (!LoadKeyFromBlob(key_blob, context_handle_, srk_handle_, &key_handle)) {
+    return false;
+  }
+  TSS_RESULT result;
+  ScopedTssEncryptedData data_handle(context_handle_);
+  if (TPM_ERROR(result = Tspi_Context_CreateObject(context_handle_,
+                                                   TSS_OBJECT_TYPE_ENCDATA,
+                                                   TSS_ENCDATA_BIND,
+                                                   data_handle.ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Tspi_Context_CreateObject failed.";
+    return false;
+  }
+  std::string mutable_bound_data(bound_data);
+  if (TPM_ERROR(result = Tspi_SetAttribData(
+      data_handle,
+      TSS_TSPATTRIB_ENCDATA_BLOB,
+      TSS_TSPATTRIB_ENCDATABLOB_BLOB,
+      bound_data.size(),
+      StringAsTSSBuffer(&mutable_bound_data)))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Tspi_SetAttribData failed.";
+    return false;
+  }
+
+  ScopedTssMemory decrypted_data(context_handle_);
+  UINT32 length = 0;
+  if (TPM_ERROR(result = Tspi_Data_Unbind(data_handle, key_handle,
+                                          &length, decrypted_data.ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Tspi_Data_Unbind failed.";
+    return false;
+  }
+  data->assign(TSSBufferAsString(decrypted_data.value(), length));
+  return true;
+}
+
+bool TpmUtilityV1::Sign(const std::string& key_blob,
+                        const std::string& data_to_sign,
+                        std::string* signature) {
+  CHECK(signature);
+  if (!SetupSrk()) {
+    LOG(ERROR) << "SRK is not ready.";
+    return false;
+  }
+  ScopedTssKey key_handle(context_handle_);
+  if (!LoadKeyFromBlob(key_blob, context_handle_, srk_handle_, &key_handle)) {
+    return false;
+  }
+  // Construct an ASN.1 DER DigestInfo.
+  std::string digest_to_sign(std::begin(kSha256DigestInfo),
+                             std::end(kSha256DigestInfo));
+  digest_to_sign += crypto::SHA256HashString(data_to_sign);
+  // Create a hash object to hold the digest.
+  ScopedTssHash hash_handle(context_handle_);
+  TSS_RESULT result = Tspi_Context_CreateObject(context_handle_,
+                                                TSS_OBJECT_TYPE_HASH,
+                                                TSS_HASH_OTHER,
+                                                hash_handle.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to create hash object.";
+    return false;
+  }
+  result = Tspi_Hash_SetHashValue(hash_handle,
+                                  digest_to_sign.size(),
+                                  StringAsTSSBuffer(&digest_to_sign));
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to set hash data.";
+    return false;
+  }
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context_handle_);
+  result = Tspi_Hash_Sign(hash_handle, key_handle, &length, buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to generate signature.";
+    return false;
+  }
+  signature->assign(TSSBufferAsString(buffer.value(), length));
+  return true;
+}
+
+bool TpmUtilityV1::ConnectContext(ScopedTssContext* context, TSS_HTPM* tpm) {
+  *tpm = 0;
+  TSS_RESULT result;
+  if (TPM_ERROR(result = Tspi_Context_Create(context->ptr()))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_Context_Create";
+    return false;
+  }
+  if (TPM_ERROR(result = Tspi_Context_Connect(*context, nullptr))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_Connect";
+    return false;
+  }
+  if (TPM_ERROR(result = Tspi_Context_GetTpmObject(*context, tpm))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_GetTpmObject";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::ConnectContextAsDelegate(const std::string& delegate_blob,
+                                            const std::string& delegate_secret,
+                                            ScopedTssContext* context,
+                                            TSS_HTPM* tpm) {
+  *tpm = 0;
+  if (!ConnectContext(context, tpm)) {
+    return false;
+  }
+  TSS_RESULT result;
+  TSS_HPOLICY tpm_usage_policy;
+  if (TPM_ERROR(result = Tspi_GetPolicyObject(*tpm,
+                                              TSS_POLICY_USAGE,
+                                              &tpm_usage_policy))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetPolicyObject";
+    return false;
+  }
+  std::string mutable_delegate_secret(delegate_secret);
+  BYTE* secret_buffer = StringAsTSSBuffer(&mutable_delegate_secret);
+  if (TPM_ERROR(result = Tspi_Policy_SetSecret(tpm_usage_policy,
+                                               TSS_SECRET_MODE_PLAIN,
+                                               delegate_secret.size(),
+                                               secret_buffer))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Policy_SetSecret";
+    return false;
+  }
+  std::string mutable_delegate_blob(delegate_blob);
+  BYTE* blob_buffer = StringAsTSSBuffer(&mutable_delegate_blob);
+  if (TPM_ERROR(result = Tspi_SetAttribData(
+      tpm_usage_policy,
+      TSS_TSPATTRIB_POLICY_DELEGATION_INFO,
+      TSS_TSPATTRIB_POLDEL_OWNERBLOB,
+      delegate_blob.size(),
+      blob_buffer))) {
+    TPM_LOG(ERROR, result) << __func__ << ": Error calling Tspi_SetAttribData";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::SetupSrk() {
+  if (!IsTpmReady()) {
+    return false;
+  }
+  if (srk_handle_) {
+    return true;
+  }
+  srk_handle_.reset(context_handle_, 0);
+  if (!LoadSrk(context_handle_, &srk_handle_)) {
+    LOG(ERROR) << __func__ << ": Failed to load SRK.";
+    return false;
+  }
+  // In order to wrap a key with the SRK we need access to the SRK public key
+  // and we need to get it manually. Once it's in the key object, we don't need
+  // to do this again.
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context_handle_);
+  TSS_RESULT result;
+  result = Tspi_Key_GetPubKey(srk_handle_, &length, buffer.ptr());
+  if (result != TSS_SUCCESS) {
+    TPM_LOG(INFO, result) << __func__ << ": Failed to read SRK public key.";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::LoadSrk(TSS_HCONTEXT context_handle,
+                           ScopedTssKey* srk_handle) {
+  TSS_RESULT result;
+  TSS_UUID uuid = TSS_UUID_SRK;
+  if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(context_handle,
+                                                    TSS_PS_TYPE_SYSTEM,
+                                                    uuid,
+                                                    srk_handle->ptr()))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_Context_LoadKeyByUUID";
+    return false;
+  }
+  // Check if the SRK wants a password.
+  UINT32 auth_usage;
+  if (TPM_ERROR(result = Tspi_GetAttribUint32(*srk_handle,
+                                              TSS_TSPATTRIB_KEY_INFO,
+                                              TSS_TSPATTRIB_KEYINFO_AUTHUSAGE,
+                                              &auth_usage))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetAttribUint32";
+    return false;
+  }
+  if (auth_usage) {
+    // Give it an empty password if needed.
+    TSS_HPOLICY usage_policy;
+    if (TPM_ERROR(result = Tspi_GetPolicyObject(*srk_handle,
+                                                TSS_POLICY_USAGE,
+                                                &usage_policy))) {
+    TPM_LOG(ERROR, result) << __func__
+                           << ": Error calling Tspi_GetPolicyObject";
+      return false;
+    }
+
+    BYTE empty_password[] = {};
+    if (TPM_ERROR(result = Tspi_Policy_SetSecret(usage_policy,
+                                                 TSS_SECRET_MODE_PLAIN,
+                                                 0, empty_password))) {
+      TPM_LOG(ERROR, result) << __func__
+                             << ": Error calling Tspi_Policy_SetSecret";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool TpmUtilityV1::LoadKeyFromBlob(const std::string& key_blob,
+                                   TSS_HCONTEXT context_handle,
+                                   TSS_HKEY parent_key_handle,
+                                   ScopedTssKey* key_handle) {
+  std::string mutable_key_blob(key_blob);
+  BYTE* key_blob_buffer = StringAsTSSBuffer(&mutable_key_blob);
+  TSS_RESULT result = Tspi_Context_LoadKeyByBlob(
+      context_handle,
+      parent_key_handle,
+      key_blob.size(),
+      key_blob_buffer,
+      key_handle->ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << ": Failed to load key by blob.";
+    return false;
+  }
+  return true;
+}
+
+bool TpmUtilityV1::GetDataAttribute(TSS_HCONTEXT context,
+                                    TSS_HOBJECT object,
+                                    TSS_FLAG flag,
+                                    TSS_FLAG sub_flag,
+                                    std::string* data) {
+  UINT32 length = 0;
+  ScopedTssMemory buffer(context);
+  TSS_RESULT result = Tspi_GetAttribData(object, flag, sub_flag, &length,
+                                         buffer.ptr());
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << __func__ << "Failed to read object attribute.";
+    return false;
+  }
+  data->assign(TSSBufferAsString(buffer.value(), length));
+  return true;
+}
+
+bool TpmUtilityV1::ConvertPublicKeyToDER(const std::string& public_key,
+                                         std::string* public_key_der) {
+  // Parse the serialized TPM_PUBKEY.
+  UINT64 offset = 0;
+  std::string mutable_public_key(public_key);
+  BYTE* buffer = StringAsTSSBuffer(&mutable_public_key);
+  TPM_PUBKEY parsed;
+  TSS_RESULT result = Trspi_UnloadBlob_PUBKEY(&offset, buffer, &parsed);
+  if (TPM_ERROR(result)) {
+    TPM_LOG(ERROR, result) << "Failed to parse TPM_PUBKEY.";
+    return false;
+  }
+  ScopedByteArray scoped_key(parsed.pubKey.key);
+  ScopedByteArray scoped_parms(parsed.algorithmParms.parms);
+  TPM_RSA_KEY_PARMS* parms =
+      reinterpret_cast<TPM_RSA_KEY_PARMS*>(parsed.algorithmParms.parms);
+  crypto::ScopedRSA rsa(RSA_new());
+  CHECK(rsa.get());
+  // Get the public exponent.
+  if (parms->exponentSize == 0) {
+    rsa.get()->e = BN_new();
+    CHECK(rsa.get()->e);
+    BN_set_word(rsa.get()->e, kWellKnownExponent);
+  } else {
+    rsa.get()->e = BN_bin2bn(parms->exponent, parms->exponentSize, nullptr);
+    CHECK(rsa.get()->e);
+  }
+  // Get the modulus.
+  rsa.get()->n = BN_bin2bn(parsed.pubKey.key, parsed.pubKey.keyLength, nullptr);
+  CHECK(rsa.get()->n);
+
+  // DER encode.
+  int der_length = i2d_RSAPublicKey(rsa.get(), nullptr);
+  if (der_length < 0) {
+    LOG(ERROR) << "Failed to DER-encode public key.";
+    return false;
+  }
+  public_key_der->resize(der_length);
+  unsigned char* der_buffer = reinterpret_cast<unsigned char*>(
+      string_as_array(public_key_der));
+  der_length = i2d_RSAPublicKey(rsa.get(), &der_buffer);
+  if (der_length < 0) {
+    LOG(ERROR) << "Failed to DER-encode public key.";
+    return false;
+  }
+  public_key_der->resize(der_length);
+  return true;
+}
+
+}  // namespace attestation
diff --git a/common/tpm_utility_v1.h b/common/tpm_utility_v1.h
new file mode 100644
index 0000000..79b9073
--- /dev/null
+++ b/common/tpm_utility_v1.h
@@ -0,0 +1,108 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_COMMON_TPM_UTILITY_V1_H_
+#define ATTESTATION_COMMON_TPM_UTILITY_V1_H_
+
+#include "attestation/common/tpm_utility.h"
+
+#include <string>
+
+#include <base/macros.h>
+#include <trousers/scoped_tss_type.h>
+#include <trousers/tss.h>
+
+namespace attestation {
+
+// A TpmUtility implementation for TPM v1.2 modules.
+class TpmUtilityV1 : public TpmUtility {
+ public:
+  TpmUtilityV1() = default;
+  ~TpmUtilityV1() override;
+
+  // Initializes a TpmUtilityV1 instance. This method must be called
+  // successfully before calling any other methods.
+  bool Initialize();
+
+  // TpmUtility methods.
+  bool IsTpmReady() override;
+  bool ActivateIdentity(const std::string& delegate_blob,
+                        const std::string& delegate_secret,
+                        const std::string& identity_key_blob,
+                        const std::string& asym_ca_contents,
+                        const std::string& sym_ca_attestation,
+                        std::string* credential) override;
+  bool CreateCertifiedKey(KeyType key_type,
+                          KeyUsage key_usage,
+                          const std::string& identity_key_blob,
+                          const std::string& external_data,
+                          std::string* key_blob,
+                          std::string* public_key,
+                          std::string* public_key_tpm_format,
+                          std::string* key_info,
+                          std::string* proof) override;
+  bool SealToPCR0(const std::string& data, std::string* sealed_data) override;
+  bool Unseal(const std::string& sealed_data, std::string* data) override;
+  bool GetEndorsementPublicKey(std::string* public_key) override;
+  bool Unbind(const std::string& key_blob,
+              const std::string& bound_data,
+              std::string* data) override;
+  bool Sign(const std::string& key_blob,
+            const std::string& data_to_sign,
+            std::string* signature) override;
+
+ private:
+  // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+  // its matching TPM object iff the context can be created and a TPM object
+  // exists in the TSS. Returns true on success.
+  bool ConnectContext(trousers::ScopedTssContext* context_handle,
+                      TSS_HTPM* tpm_handle);
+
+  // Populates |context_handle| with a valid TSS_HCONTEXT and |tpm_handle| with
+  // its matching TPM object authorized by the given |delegate_blob| and
+  // |delegate_secret|. Returns true on success.
+  bool ConnectContextAsDelegate(const std::string& delegate_blob,
+                                const std::string& delegate_secret,
+                                trousers::ScopedTssContext* context,
+                                TSS_HTPM* tpm);
+
+  // Sets up srk_handle_ if necessary. Returns true iff the SRK is ready.
+  bool SetupSrk();
+
+  // Loads the storage root key (SRK) and populates |srk_handle|. The
+  // |context_handle| must be connected and valid. Returns true on success.
+  bool LoadSrk(TSS_HCONTEXT context_handle, trousers::ScopedTssKey* srk_handle);
+
+  // Loads a key in the TPM given a |key_blob| and a |parent_key_handle|. The
+  // |context_handle| must be connected and valid. Returns true and populates
+  // |key_handle| on success.
+  bool LoadKeyFromBlob(const std::string& key_blob,
+                       TSS_HCONTEXT context_handle,
+                       TSS_HKEY parent_key_handle,
+                       trousers::ScopedTssKey* key_handle);
+
+  // Retrieves a |data| attribute defined by |flag| and |sub_flag| from a TSS
+  // |object_handle|. The |context_handle| is only used for TSS memory
+  // management.
+  bool GetDataAttribute(TSS_HCONTEXT context_handle,
+                        TSS_HOBJECT object_handle,
+                        TSS_FLAG flag,
+                        TSS_FLAG sub_flag,
+                        std::string* data);
+
+  // Converts a public in TPM_PUBKEY format to a DER-encoded RSAPublicKey.
+  bool ConvertPublicKeyToDER(const std::string& public_key,
+                             std::string* public_key_der);
+
+  bool is_ready_{false};
+  trousers::ScopedTssContext context_handle_;
+  TSS_HTPM tpm_handle_{0};
+  trousers::ScopedTssKey srk_handle_{0};
+
+  DISALLOW_COPY_AND_ASSIGN(TpmUtilityV1);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_TPM_UTILITY_V1_H_
diff --git a/server/attestation_service.cc b/server/attestation_service.cc
new file mode 100644
index 0000000..407cfcd
--- /dev/null
+++ b/server/attestation_service.cc
@@ -0,0 +1,925 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/attestation_service.h"
+
+#include <string>
+
+#include <base/callback.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/data_encoding.h>
+#include <chromeos/http/http_utils.h>
+#include <chromeos/mime_utils.h>
+#include <crypto/sha2.h>
+
+#include "attestation/common/attestation_ca.pb.h"
+#include "attestation/common/database.pb.h"
+#include "attestation/server/database_impl.h"
+
+namespace {
+
+#ifndef USE_TEST_ACA
+const char kACAWebOrigin[] = "https://chromeos-ca.gstatic.com";
+#else
+const char kACAWebOrigin[] = "https://asbestos-qa.corp.google.com";
+#endif
+const size_t kNonceSize = 20;  // As per TPM_NONCE definition.
+const int kNumTemporalValues = 5;
+
+}  // namespace
+
+namespace attestation {
+
+AttestationService::AttestationService()
+    : attestation_ca_origin_(kACAWebOrigin),
+      weak_factory_(this) {}
+
+bool AttestationService::Initialize() {
+  LOG(INFO) << "Attestation service started.";
+  worker_thread_.reset(new base::Thread("Attestation Service Worker"));
+  worker_thread_->StartWithOptions(
+      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
+  if (!tpm_utility_) {
+    default_tpm_utility_.reset(new TpmUtilityV1());
+    if (!default_tpm_utility_->Initialize()) {
+      return false;
+    }
+    tpm_utility_ = default_tpm_utility_.get();
+  }
+  if (!crypto_utility_) {
+    default_crypto_utility_.reset(new CryptoUtilityImpl(tpm_utility_));
+    crypto_utility_ = default_crypto_utility_.get();
+  }
+  if (!database_) {
+    default_database_.reset(new DatabaseImpl(crypto_utility_));
+    worker_thread_->task_runner()->PostTask(FROM_HERE, base::Bind(
+        &DatabaseImpl::Initialize,
+        base::Unretained(default_database_.get())));
+    database_ = default_database_.get();
+  }
+  if (!key_store_) {
+    pkcs11_token_manager_.reset(new chaps::TokenManagerClient());
+    default_key_store_.reset(new Pkcs11KeyStore(pkcs11_token_manager_.get()));
+    key_store_ = default_key_store_.get();
+  }
+  return true;
+}
+
+void AttestationService::CreateGoogleAttestedKey(
+    const CreateGoogleAttestedKeyRequest& request,
+    const CreateGoogleAttestedKeyCallback& callback) {
+  auto result = std::make_shared<CreateGoogleAttestedKeyReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::CreateGoogleAttestedKeyTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<CreateGoogleAttestedKeyReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::CreateGoogleAttestedKeyTask(
+    const CreateGoogleAttestedKeyRequest& request,
+    const std::shared_ptr<CreateGoogleAttestedKeyReply>& result) {
+  LOG(INFO) << "Creating attested key: " << request.key_label();
+  if (!IsPreparedForEnrollment()) {
+    LOG(ERROR) << "Attestation: TPM is not ready.";
+    result->set_status(STATUS_NOT_READY);
+    return;
+  }
+  if (!IsEnrolled()) {
+    std::string enroll_request;
+    if (!CreateEnrollRequest(&enroll_request)) {
+      result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+      return;
+    }
+    std::string enroll_reply;
+    if (!SendACARequestAndBlock(kEnroll,
+                                enroll_request,
+                                &enroll_reply)) {
+      result->set_status(STATUS_CA_NOT_AVAILABLE);
+      return;
+    }
+    std::string server_error;
+    if (!FinishEnroll(enroll_reply, &server_error)) {
+      if (server_error.empty()) {
+        result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+        return;
+      }
+      result->set_status(STATUS_REQUEST_DENIED_BY_CA);
+      result->set_server_error(server_error);
+      return;
+    }
+  }
+  CertifiedKey key;
+  if (!CreateKey(request.username(), request.key_label(), request.key_type(),
+                 request.key_usage(), &key)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  std::string certificate_request;
+  std::string message_id;
+  if (!CreateCertificateRequest(request.username(),
+                                key,
+                                request.certificate_profile(),
+                                request.origin(),
+                                &certificate_request,
+                                &message_id)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  std::string certificate_reply;
+  if (!SendACARequestAndBlock(kGetCertificate,
+                              certificate_request,
+                              &certificate_reply)) {
+    result->set_status(STATUS_CA_NOT_AVAILABLE);
+    return;
+  }
+  std::string certificate_chain;
+  std::string server_error;
+  if (!FinishCertificateRequest(certificate_reply,
+                                request.username(),
+                                request.key_label(),
+                                message_id,
+                                &key,
+                                &certificate_chain,
+                                &server_error)) {
+    if (server_error.empty()) {
+      result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+      return;
+    }
+    result->set_status(STATUS_REQUEST_DENIED_BY_CA);
+    result->set_server_error(server_error);
+    return;
+  }
+  result->set_certificate_chain(certificate_chain);
+}
+
+void AttestationService::GetKeyInfo(const GetKeyInfoRequest& request,
+                                    const GetKeyInfoCallback& callback) {
+  auto result = std::make_shared<GetKeyInfoReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::GetKeyInfoTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<GetKeyInfoReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::GetKeyInfoTask(
+    const GetKeyInfoRequest& request,
+    const std::shared_ptr<GetKeyInfoReply>& result) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(request.username(), request.key_label(), &key)) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  std::string public_key_info;
+  if (!GetSubjectPublicKeyInfo(key.key_type(), key.public_key(),
+                               &public_key_info)) {
+    LOG(ERROR) << __func__ << ": Bad public key.";
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_key_type(key.key_type());
+  result->set_key_usage(key.key_usage());
+  result->set_public_key(public_key_info);
+  result->set_certify_info(key.certified_key_info());
+  result->set_certify_info_signature(key.certified_key_proof());
+  if (key.has_intermediate_ca_cert()) {
+    result->set_certificate(CreatePEMCertificateChain(key));
+  } else {
+    result->set_certificate(key.certified_key_credential());
+  }
+}
+
+void AttestationService::GetEndorsementInfo(
+    const GetEndorsementInfoRequest& request,
+    const GetEndorsementInfoCallback& callback) {
+  auto result = std::make_shared<GetEndorsementInfoReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::GetEndorsementInfoTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<GetEndorsementInfoReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::GetEndorsementInfoTask(
+    const GetEndorsementInfoRequest& request,
+    const std::shared_ptr<GetEndorsementInfoReply>& result) {
+  if (request.key_type() != KEY_TYPE_RSA) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  auto database_pb = database_->GetProtobuf();
+  if (!database_pb.has_credentials() ||
+      !database_pb.credentials().has_endorsement_public_key()) {
+    // Try to read the public key directly.
+    std::string public_key;
+    if (!tpm_utility_->GetEndorsementPublicKey(&public_key)) {
+      result->set_status(STATUS_NOT_AVAILABLE);
+      return;
+    }
+    database_pb.mutable_credentials()->set_endorsement_public_key(public_key);
+  }
+  std::string public_key_info;
+  if (!GetSubjectPublicKeyInfo(
+      request.key_type(),
+      database_pb.credentials().endorsement_public_key(),
+      &public_key_info)) {
+    LOG(ERROR) << __func__ << ": Bad public key.";
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_ek_public_key(public_key_info);
+  if (database_pb.credentials().has_endorsement_credential()) {
+    result->set_ek_certificate(
+        database_pb.credentials().endorsement_credential());
+  }
+}
+
+void AttestationService::GetAttestationKeyInfo(
+    const GetAttestationKeyInfoRequest& request,
+    const GetAttestationKeyInfoCallback& callback) {
+  auto result = std::make_shared<GetAttestationKeyInfoReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::GetAttestationKeyInfoTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<GetAttestationKeyInfoReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::GetAttestationKeyInfoTask(
+    const GetAttestationKeyInfoRequest& request,
+    const std::shared_ptr<GetAttestationKeyInfoReply>& result) {
+  if (request.key_type() != KEY_TYPE_RSA) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  auto database_pb = database_->GetProtobuf();
+  if (!IsPreparedForEnrollment() || !database_pb.has_identity_key()) {
+    result->set_status(STATUS_NOT_AVAILABLE);
+    return;
+  }
+  if (database_pb.identity_key().has_identity_public_key()) {
+    std::string public_key_info;
+    if (!GetSubjectPublicKeyInfo(
+        request.key_type(),
+        database_pb.identity_key().identity_public_key(),
+        &public_key_info)) {
+      LOG(ERROR) << __func__ << ": Bad public key.";
+      result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+      return;
+    }
+    result->set_public_key(public_key_info);
+  }
+  if (database_pb.has_identity_binding() &&
+      database_pb.identity_binding().has_identity_public_key()) {
+    result->set_public_key_tpm_format(
+        database_pb.identity_binding().identity_public_key());
+  }
+  if (database_pb.identity_key().has_identity_credential()) {
+    result->set_certificate(database_pb.identity_key().identity_credential());
+  }
+  if (database_pb.has_pcr0_quote()) {
+    *result->mutable_pcr0_quote() = database_pb.pcr0_quote();
+  }
+  if (database_pb.has_pcr1_quote()) {
+    *result->mutable_pcr1_quote() = database_pb.pcr1_quote();
+  }
+}
+
+void AttestationService::ActivateAttestationKey(
+    const ActivateAttestationKeyRequest& request,
+    const ActivateAttestationKeyCallback& callback) {
+  auto result = std::make_shared<ActivateAttestationKeyReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::ActivateAttestationKeyTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<ActivateAttestationKeyReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::ActivateAttestationKeyTask(
+    const ActivateAttestationKeyRequest& request,
+    const std::shared_ptr<ActivateAttestationKeyReply>& result) {
+  if (request.key_type() != KEY_TYPE_RSA) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  std::string certificate;
+  auto database_pb = database_->GetProtobuf();
+  if (!tpm_utility_->ActivateIdentity(
+      database_pb.delegate().blob(),
+      database_pb.delegate().secret(),
+      database_pb.identity_key().identity_key_blob(),
+      request.encrypted_certificate().asym_ca_contents(),
+      request.encrypted_certificate().sym_ca_attestation(),
+      &certificate)) {
+    LOG(ERROR) << __func__ << ": Failed to activate identity.";
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  if (request.save_certificate()) {
+    database_->GetMutableProtobuf()->mutable_identity_key()->
+        set_identity_credential(certificate);
+    if (!database_->SaveChanges()) {
+      LOG(ERROR) << __func__ << ": Failed to persist database changes.";
+      result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    }
+  }
+  result->set_certificate(certificate);
+}
+
+void AttestationService::CreateCertifiableKey(
+    const CreateCertifiableKeyRequest& request,
+    const CreateCertifiableKeyCallback& callback) {
+  auto result = std::make_shared<CreateCertifiableKeyReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::CreateCertifiableKeyTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<CreateCertifiableKeyReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::CreateCertifiableKeyTask(
+    const CreateCertifiableKeyRequest& request,
+    const std::shared_ptr<CreateCertifiableKeyReply>& result) {
+  CertifiedKey key;
+  if (!CreateKey(request.username(), request.key_label(), request.key_type(),
+                 request.key_usage(), &key)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  std::string public_key_info;
+  if (!GetSubjectPublicKeyInfo(key.key_type(), key.public_key(),
+                               &public_key_info)) {
+    LOG(ERROR) << __func__ << ": Bad public key.";
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_public_key(public_key_info);
+  result->set_certify_info(key.certified_key_info());
+  result->set_certify_info_signature(key.certified_key_proof());
+}
+
+void AttestationService::Decrypt(const DecryptRequest& request,
+                                 const DecryptCallback& callback) {
+  auto result = std::make_shared<DecryptReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::DecryptTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<DecryptReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::DecryptTask(
+    const DecryptRequest& request,
+    const std::shared_ptr<DecryptReply>& result) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(request.username(), request.key_label(), &key)) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  std::string data;
+  if (!tpm_utility_->Unbind(key.key_blob(), request.encrypted_data(), &data)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_decrypted_data(data);
+}
+
+void AttestationService::Sign(const SignRequest& request,
+                              const SignCallback& callback) {
+  auto result = std::make_shared<SignReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::SignTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<SignReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::SignTask(const SignRequest& request,
+                                  const std::shared_ptr<SignReply>& result) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(request.username(), request.key_label(), &key)) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  std::string signature;
+  if (!tpm_utility_->Sign(key.key_blob(), request.data_to_sign(), &signature)) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  result->set_signature(signature);
+}
+
+void AttestationService::RegisterKeyWithChapsToken(
+    const RegisterKeyWithChapsTokenRequest& request,
+    const RegisterKeyWithChapsTokenCallback& callback) {
+  auto result = std::make_shared<RegisterKeyWithChapsTokenReply>();
+  base::Closure task = base::Bind(
+      &AttestationService::RegisterKeyWithChapsTokenTask,
+      base::Unretained(this),
+      request,
+      result);
+  base::Closure reply = base::Bind(
+      &AttestationService::TaskRelayCallback<RegisterKeyWithChapsTokenReply>,
+      GetWeakPtr(),
+      callback,
+      result);
+  worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply);
+}
+
+void AttestationService::RegisterKeyWithChapsTokenTask(
+    const RegisterKeyWithChapsTokenRequest& request,
+    const std::shared_ptr<RegisterKeyWithChapsTokenReply>& result) {
+  CertifiedKey key;
+  if (!FindKeyByLabel(request.username(), request.key_label(), &key)) {
+    result->set_status(STATUS_INVALID_PARAMETER);
+    return;
+  }
+  if (!key_store_->Register(request.username(), request.key_label(),
+                            key.key_type(), key.key_usage(), key.key_blob(),
+                            key.public_key(), key.certified_key_credential())) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  if (key.has_intermediate_ca_cert() &&
+      !key_store_->RegisterCertificate(request.username(),
+                                       key.intermediate_ca_cert())) {
+    result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+    return;
+  }
+  for (int i = 0; i < key.additional_intermediate_ca_cert_size(); ++i) {
+    if (!key_store_->RegisterCertificate(
+            request.username(),
+            key.additional_intermediate_ca_cert(i))) {
+      result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
+      return;
+    }
+  }
+  DeleteKey(request.username(), request.key_label());
+}
+
+bool AttestationService::IsPreparedForEnrollment() {
+  if (!tpm_utility_->IsTpmReady()) {
+    return false;
+  }
+  auto database_pb = database_->GetProtobuf();
+  if (!database_pb.has_credentials()) {
+    return false;
+  }
+  return (database_pb.credentials().has_endorsement_credential() ||
+          database_pb.credentials()
+              .has_default_encrypted_endorsement_credential());
+}
+
+bool AttestationService::IsEnrolled() {
+  auto database_pb = database_->GetProtobuf();
+  return database_pb.has_identity_key() &&
+         database_pb.identity_key().has_identity_credential();
+}
+
+bool AttestationService::CreateEnrollRequest(std::string* enroll_request) {
+  if (!IsPreparedForEnrollment()) {
+    LOG(ERROR) << __func__ << ": Enrollment is not possible, attestation data "
+               << "does not exist.";
+    return false;
+  }
+  auto database_pb = database_->GetProtobuf();
+  AttestationEnrollmentRequest request_pb;
+  *request_pb.mutable_encrypted_endorsement_credential() =
+      database_pb.credentials().default_encrypted_endorsement_credential();
+  request_pb.set_identity_public_key(
+      database_pb.identity_binding().identity_public_key());
+  *request_pb.mutable_pcr0_quote() = database_pb.pcr0_quote();
+  *request_pb.mutable_pcr1_quote() = database_pb.pcr1_quote();
+  if (!request_pb.SerializeToString(enroll_request)) {
+    LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
+    return false;
+  }
+  return true;
+}
+
+bool AttestationService::FinishEnroll(const std::string& enroll_response,
+                                      std::string* server_error) {
+  if (!tpm_utility_->IsTpmReady()) {
+    return false;
+  }
+  AttestationEnrollmentResponse response_pb;
+  if (!response_pb.ParseFromString(enroll_response)) {
+    LOG(ERROR) << __func__ << ": Failed to parse response from CA.";
+    return false;
+  }
+  if (response_pb.status() != OK) {
+    *server_error = response_pb.detail();
+    LOG(ERROR) << __func__ << ": Error received from CA: "
+               << response_pb.detail();
+    return false;
+  }
+  std::string credential;
+  auto database_pb = database_->GetProtobuf();
+  if (!tpm_utility_->ActivateIdentity(
+      database_pb.delegate().blob(),
+      database_pb.delegate().secret(),
+      database_pb.identity_key().identity_key_blob(),
+      response_pb.encrypted_identity_credential().asym_ca_contents(),
+      response_pb.encrypted_identity_credential().sym_ca_attestation(),
+      &credential)) {
+    LOG(ERROR) << __func__ << ": Failed to activate identity.";
+    return false;
+  }
+  database_->GetMutableProtobuf()->mutable_identity_key()->
+      set_identity_credential(credential);
+  if (!database_->SaveChanges()) {
+    LOG(ERROR) << __func__ << ": Failed to persist database changes.";
+    return false;
+  }
+  LOG(INFO) << "Attestation: Enrollment complete.";
+  return true;
+}
+
+bool AttestationService::CreateCertificateRequest(
+    const std::string& username,
+    const CertifiedKey& key,
+    CertificateProfile profile,
+    const std::string& origin,
+    std::string* certificate_request,
+    std::string* message_id) {
+  if (!tpm_utility_->IsTpmReady()) {
+    return false;
+  }
+  if (!IsEnrolled()) {
+    LOG(ERROR) << __func__ << ": Device is not enrolled for attestation.";
+    return false;
+  }
+  AttestationCertificateRequest request_pb;
+  if (!crypto_utility_->GetRandom(kNonceSize, message_id)) {
+    LOG(ERROR) << __func__ << ": GetRandom(message_id) failed.";
+    return false;
+  }
+  request_pb.set_message_id(*message_id);
+  auto database_pb = database_->GetProtobuf();
+  request_pb.set_identity_credential(
+      database_pb.identity_key().identity_credential());
+  request_pb.set_profile(profile);
+  if (!origin.empty() &&
+      (profile == CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID)) {
+    request_pb.set_origin(origin);
+    request_pb.set_temporal_index(ChooseTemporalIndex(username, origin));
+  }
+  request_pb.set_certified_public_key(key.public_key_tpm_format());
+  request_pb.set_certified_key_info(key.certified_key_info());
+  request_pb.set_certified_key_proof(key.certified_key_proof());
+  if (!request_pb.SerializeToString(certificate_request)) {
+    LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
+    return false;
+  }
+  return true;
+}
+
+bool AttestationService::FinishCertificateRequest(
+    const std::string& certificate_response,
+    const std::string& username,
+    const std::string& key_label,
+    const std::string& message_id,
+    CertifiedKey* key,
+    std::string* certificate_chain,
+    std::string* server_error) {
+  if (!tpm_utility_->IsTpmReady()) {
+    return false;
+  }
+  AttestationCertificateResponse response_pb;
+  if (!response_pb.ParseFromString(certificate_response)) {
+    LOG(ERROR) << __func__ << ": Failed to parse response from Privacy CA.";
+    return false;
+  }
+  if (response_pb.status() != OK) {
+    *server_error = response_pb.detail();
+    LOG(ERROR) << __func__ << ": Error received from Privacy CA: "
+               << response_pb.detail();
+    return false;
+  }
+  if (message_id != response_pb.message_id()) {
+    LOG(ERROR) << __func__ << ": Message ID mismatch.";
+    return false;
+  }
+
+  // Finish populating the CertifiedKey protobuf and store it.
+  key->set_certified_key_credential(response_pb.certified_key_credential());
+  key->set_intermediate_ca_cert(response_pb.intermediate_ca_cert());
+  key->mutable_additional_intermediate_ca_cert()->MergeFrom(
+      response_pb.additional_intermediate_ca_cert());
+  if (!SaveKey(username, key_label, *key)) {
+    return false;
+  }
+  LOG(INFO) << "Attestation: Certified key credential received and stored.";
+  *certificate_chain = CreatePEMCertificateChain(*key);
+  return true;
+}
+
+bool AttestationService::SendACARequestAndBlock(ACARequestType request_type,
+                                                const std::string& request,
+                                                std::string* reply) {
+  std::shared_ptr<chromeos::http::Transport> transport = http_transport_;
+  if (!transport) {
+    transport = chromeos::http::Transport::CreateDefault();
+  }
+  std::unique_ptr<chromeos::http::Response> response = PostBinaryAndBlock(
+      GetACAURL(request_type),
+      request.data(),
+      request.size(),
+      chromeos::mime::application::kOctet_stream,
+      {},  // headers
+      transport,
+      nullptr);  // error
+  if (!response || !response->IsSuccessful()) {
+    LOG(ERROR) << "HTTP request to Attestation CA failed.";
+    return false;
+  }
+  *reply = response->ExtractDataAsString();
+  return true;
+}
+
+bool AttestationService::FindKeyByLabel(const std::string& username,
+                                        const std::string& key_label,
+                                        CertifiedKey* key) {
+  if (!username.empty()) {
+    std::string key_data;
+    if (!key_store_->Read(username, key_label, &key_data)) {
+      LOG(INFO) << "Key not found: " << key_label;
+      return false;
+    }
+    if (key && !key->ParseFromString(key_data)) {
+      LOG(ERROR) << "Failed to parse key: " << key_label;
+      return false;
+    }
+    return true;
+  }
+  auto database_pb = database_->GetProtobuf();
+  for (int i = 0; i < database_pb.device_keys_size(); ++i) {
+    if (database_pb.device_keys(i).key_name() == key_label) {
+      *key = database_pb.device_keys(i);
+      return true;
+    }
+  }
+  LOG(INFO) << "Key not found: " << key_label;
+  return false;
+}
+
+bool AttestationService::CreateKey(const std::string& username,
+                                   const std::string& key_label,
+                                   KeyType key_type,
+                                   KeyUsage key_usage,
+                                   CertifiedKey* key) {
+  std::string nonce;
+  if (!crypto_utility_->GetRandom(kNonceSize, &nonce)) {
+    LOG(ERROR) << __func__ << ": GetRandom(nonce) failed.";
+    return false;
+  }
+  std::string key_blob;
+  std::string public_key;
+  std::string public_key_tpm_format;
+  std::string key_info;
+  std::string proof;
+  auto database_pb = database_->GetProtobuf();
+  if (!tpm_utility_->CreateCertifiedKey(
+      key_type,
+      key_usage,
+      database_pb.identity_key().identity_key_blob(),
+      nonce,
+      &key_blob,
+      &public_key,
+      &public_key_tpm_format,
+      &key_info,
+      &proof)) {
+    return false;
+  }
+  key->set_key_blob(key_blob);
+  key->set_public_key(public_key);
+  key->set_key_name(key_label);
+  key->set_public_key_tpm_format(public_key_tpm_format);
+  key->set_certified_key_info(key_info);
+  key->set_certified_key_proof(proof);
+  return SaveKey(username, key_label, *key);
+}
+
+bool AttestationService::SaveKey(const std::string& username,
+                                 const std::string& key_label,
+                                 const CertifiedKey& key) {
+  if (!username.empty()) {
+    std::string key_data;
+    if (!key.SerializeToString(&key_data)) {
+      LOG(ERROR) << __func__ << ": Failed to serialize protobuf.";
+      return false;
+    }
+    if (!key_store_->Write(username, key_label, key_data)) {
+      LOG(ERROR) << __func__ << ": Failed to store certified key for user.";
+      return false;
+    }
+  } else {
+    if (!AddDeviceKey(key_label, key)) {
+      LOG(ERROR) << __func__ << ": Failed to store certified key for device.";
+      return false;
+    }
+  }
+  return true;
+}
+
+void AttestationService::DeleteKey(const std::string& username,
+                                   const std::string& key_label) {
+  if (!username.empty()) {
+    key_store_->Delete(username, key_label);
+  } else {
+    RemoveDeviceKey(key_label);
+  }
+}
+
+bool AttestationService::AddDeviceKey(const std::string& key_label,
+                                      const CertifiedKey& key) {
+  // If a key by this name already exists, reuse the field.
+  auto* database_pb = database_->GetMutableProtobuf();
+  bool found = false;
+  for (int i = 0; i < database_pb->device_keys_size(); ++i) {
+    if (database_pb->device_keys(i).key_name() == key_label) {
+      found = true;
+      *database_pb->mutable_device_keys(i) = key;
+      break;
+    }
+  }
+  if (!found)
+    *database_pb->add_device_keys() = key;
+  return database_->SaveChanges();
+}
+
+void AttestationService::RemoveDeviceKey(const std::string& key_label) {
+  auto* database_pb = database_->GetMutableProtobuf();
+  bool found = false;
+  for (int i = 0; i < database_pb->device_keys_size(); ++i) {
+    if (database_pb->device_keys(i).key_name() == key_label) {
+      found = true;
+      int last = database_pb->device_keys_size() - 1;
+      if (i < last) {
+        database_pb->mutable_device_keys()->SwapElements(i, last);
+      }
+      database_pb->mutable_device_keys()->RemoveLast();
+      break;
+    }
+  }
+  if (found) {
+    if (!database_->SaveChanges()) {
+      LOG(WARNING) << __func__ << ": Failed to persist key deletion.";
+    }
+  }
+}
+
+std::string AttestationService::CreatePEMCertificateChain(
+    const CertifiedKey& key) {
+  if (key.certified_key_credential().empty()) {
+    LOG(WARNING) << "Certificate is empty.";
+    return std::string();
+  }
+  std::string pem = CreatePEMCertificate(key.certified_key_credential());
+  if (!key.intermediate_ca_cert().empty()) {
+    pem += "\n";
+    pem += CreatePEMCertificate(key.intermediate_ca_cert());
+  }
+  for (int i = 0; i < key.additional_intermediate_ca_cert_size(); ++i) {
+    pem += "\n";
+    pem += CreatePEMCertificate(key.additional_intermediate_ca_cert(i));
+  }
+  return pem;
+}
+
+std::string AttestationService::CreatePEMCertificate(
+    const std::string& certificate) {
+  const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----\n";
+  const char kEndCertificate[] = "-----END CERTIFICATE-----";
+
+  std::string pem = kBeginCertificate;
+  pem += chromeos::data_encoding::Base64EncodeWrapLines(certificate);
+  pem += kEndCertificate;
+  return pem;
+}
+
+
+int AttestationService::ChooseTemporalIndex(const std::string& user,
+                                            const std::string& origin) {
+  std::string user_hash = crypto::SHA256HashString(user);
+  std::string origin_hash = crypto::SHA256HashString(origin);
+  int histogram[kNumTemporalValues] = {};
+  auto database_pb = database_->GetProtobuf();
+  for (int i = 0; i < database_pb.temporal_index_record_size(); ++i) {
+    const AttestationDatabase::TemporalIndexRecord& record =
+        database_pb.temporal_index_record(i);
+    // Ignore out-of-range index values.
+    if (record.temporal_index() < 0 ||
+        record.temporal_index() >= kNumTemporalValues)
+      continue;
+    if (record.origin_hash() == origin_hash) {
+      if (record.user_hash() == user_hash) {
+        // We've previously chosen this index for this user, reuse it.
+        return record.temporal_index();
+      } else {
+        // We've previously chosen this index for another user.
+        ++histogram[record.temporal_index()];
+      }
+    }
+  }
+  int least_used_index = 0;
+  for (int i = 1; i < kNumTemporalValues; ++i) {
+    if (histogram[i] < histogram[least_used_index])
+      least_used_index = i;
+  }
+  if (histogram[least_used_index] > 0) {
+    LOG(WARNING) << "Unique origin-specific identifiers have been exhausted.";
+  }
+  // Record our choice for later reference.
+  AttestationDatabase::TemporalIndexRecord* new_record =
+      database_pb.add_temporal_index_record();
+  new_record->set_origin_hash(origin_hash);
+  new_record->set_user_hash(user_hash);
+  new_record->set_temporal_index(least_used_index);
+  database_->SaveChanges();
+  return least_used_index;
+}
+
+std::string AttestationService::GetACAURL(ACARequestType request_type) const {
+  std::string url = attestation_ca_origin_;
+  switch (request_type) {
+    case kEnroll:
+      url += "/enroll";
+      break;
+    case kGetCertificate:
+      url += "/sign";
+      break;
+    default:
+      NOTREACHED();
+  }
+  return url;
+}
+
+bool AttestationService::GetSubjectPublicKeyInfo(
+    KeyType key_type,
+    const std::string& public_key,
+    std::string* public_key_info) const {
+  // Only RSA is supported currently.
+  if (key_type != KEY_TYPE_RSA) {
+    return false;
+  }
+  return crypto_utility_->GetRSASubjectPublicKeyInfo(public_key,
+                                                     public_key_info);
+}
+
+base::WeakPtr<AttestationService> AttestationService::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
+}  // namespace attestation
diff --git a/server/attestation_service.h b/server/attestation_service.h
new file mode 100644
index 0000000..8218abe
--- /dev/null
+++ b/server/attestation_service.h
@@ -0,0 +1,301 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_ATTESTATION_SERVICE_H_
+#define ATTESTATION_SERVER_ATTESTATION_SERVICE_H_
+
+#include "attestation/common/attestation_interface.h"
+
+#include <memory>
+#include <string>
+
+#include <base/callback.h>
+#include <base/macros.h>
+#include <base/memory/weak_ptr.h>
+#include <base/threading/thread.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/http/http_transport.h>
+
+#include "attestation/common/crypto_utility.h"
+#include "attestation/common/crypto_utility_impl.h"
+#include "attestation/common/tpm_utility.h"
+#include "attestation/common/tpm_utility_v1.h"
+#include "attestation/server/database.h"
+#include "attestation/server/database_impl.h"
+#include "attestation/server/key_store.h"
+#include "attestation/server/pkcs11_key_store.h"
+
+namespace attestation {
+
+// An implementation of AttestationInterface for the core attestation service.
+// Access to TPM, network and local file-system resources occurs asynchronously
+// with the exception of Initialize(). All methods must be called on the same
+// thread that originally called Initialize().
+// Usage:
+//   std::unique_ptr<AttestationInterface> attestation =
+//       new AttestationService();
+//   CHECK(attestation->Initialize());
+//   attestation->CreateGoogleAttestedKey(...);
+//
+// THREADING NOTES:
+// This class runs a worker thread and delegates all calls to it. This keeps the
+// public methods non-blocking while allowing complex implementation details
+// with dependencies on the TPM, network, and filesystem to be coded in a more
+// readable way. It also serves to serialize method execution which reduces
+// complexity with TPM state.
+//
+// Tasks that run on the worker thread are bound with base::Unretained which is
+// safe because the thread is owned by this class (so it is guaranteed not to
+// process a task after destruction). Weak pointers are used to post replies
+// back to the main thread.
+class AttestationService : public AttestationInterface {
+ public:
+  AttestationService();
+  ~AttestationService() override = default;
+
+  // AttestationInterface methods.
+  bool Initialize() override;
+  void CreateGoogleAttestedKey(
+      const CreateGoogleAttestedKeyRequest& request,
+      const CreateGoogleAttestedKeyCallback& callback) override;
+  void GetKeyInfo(const GetKeyInfoRequest& request,
+                  const GetKeyInfoCallback& callback) override;
+  void GetEndorsementInfo(const GetEndorsementInfoRequest& request,
+                          const GetEndorsementInfoCallback& callback) override;
+  void GetAttestationKeyInfo(
+      const GetAttestationKeyInfoRequest& request,
+      const GetAttestationKeyInfoCallback& callback) override;
+  void ActivateAttestationKey(
+      const ActivateAttestationKeyRequest& request,
+      const ActivateAttestationKeyCallback& callback) override;
+  void CreateCertifiableKey(
+      const CreateCertifiableKeyRequest& request,
+      const CreateCertifiableKeyCallback& callback) override;
+  void Decrypt(const DecryptRequest& request,
+               const DecryptCallback& callback) override;
+  void Sign(const SignRequest& request, const SignCallback& callback) override;
+  void RegisterKeyWithChapsToken(
+      const RegisterKeyWithChapsTokenRequest& request,
+      const RegisterKeyWithChapsTokenCallback& callback) override;
+
+  // Mutators useful for testing.
+  void set_crypto_utility(CryptoUtility* crypto_utility) {
+    crypto_utility_ = crypto_utility;
+  }
+
+  void set_database(Database* database) {
+    database_ = database;
+  }
+
+  void set_http_transport(
+      const std::shared_ptr<chromeos::http::Transport>& transport) {
+    http_transport_ = transport;
+  }
+
+  void set_key_store(KeyStore* key_store) {
+    key_store_ = key_store;
+  }
+
+  void set_tpm_utility(TpmUtility* tpm_utility) {
+    tpm_utility_ = tpm_utility;
+  }
+
+  // So tests don't need to duplicate URL decisions.
+  const std::string& attestation_ca_origin() {
+    return attestation_ca_origin_;
+  }
+
+ private:
+  enum ACARequestType {
+    kEnroll,          // Enrolls a device, certifying an identity key.
+    kGetCertificate,  // Issues a certificate for a TPM-backed key.
+  };
+
+  // A relay callback which allows the use of weak pointer semantics for a reply
+  // to TaskRunner::PostTaskAndReply.
+  template<typename ReplyProtobufType>
+  void TaskRelayCallback(
+      const base::Callback<void(const ReplyProtobufType&)> callback,
+      const std::shared_ptr<ReplyProtobufType>& reply) {
+    callback.Run(*reply);
+  }
+
+  // A blocking implementation of CreateGoogleAttestedKey appropriate to run on
+  // the worker thread.
+  void CreateGoogleAttestedKeyTask(
+      const CreateGoogleAttestedKeyRequest& request,
+      const std::shared_ptr<CreateGoogleAttestedKeyReply>& result);
+
+  // A blocking implementation of GetKeyInfo.
+  void GetKeyInfoTask(
+      const GetKeyInfoRequest& request,
+      const std::shared_ptr<GetKeyInfoReply>& result);
+
+  // A blocking implementation of GetEndorsementInfo.
+  void GetEndorsementInfoTask(
+      const GetEndorsementInfoRequest& request,
+      const std::shared_ptr<GetEndorsementInfoReply>& result);
+
+  // A blocking implementation of GetAttestationKeyInfo.
+  void GetAttestationKeyInfoTask(
+      const GetAttestationKeyInfoRequest& request,
+      const std::shared_ptr<GetAttestationKeyInfoReply>& result);
+
+  // A blocking implementation of ActivateAttestationKey.
+  void ActivateAttestationKeyTask(
+      const ActivateAttestationKeyRequest& request,
+      const std::shared_ptr<ActivateAttestationKeyReply>& result);
+
+  // A blocking implementation of CreateCertifiableKey.
+  void CreateCertifiableKeyTask(
+      const CreateCertifiableKeyRequest& request,
+      const std::shared_ptr<CreateCertifiableKeyReply>& result);
+
+  // A blocking implementation of Decrypt.
+  void DecryptTask(const DecryptRequest& request,
+                   const std::shared_ptr<DecryptReply>& result);
+
+  // A blocking implementation of Sign.
+  void SignTask(const SignRequest& request,
+                const std::shared_ptr<SignReply>& result);
+
+  // A synchronous implementation of RegisterKeyWithChapsToken.
+  void RegisterKeyWithChapsTokenTask(
+      const RegisterKeyWithChapsTokenRequest& request,
+      const std::shared_ptr<RegisterKeyWithChapsTokenReply>& result);
+
+  // Returns true iff all information required for enrollment with the Google
+  // Attestation CA is available.
+  bool IsPreparedForEnrollment();
+
+  // Returns true iff enrollment with the Google Attestation CA has been
+  // completed.
+  bool IsEnrolled();
+
+  // Creates an enrollment request compatible with the Google Attestation CA.
+  // Returns true on success.
+  bool CreateEnrollRequest(std::string* enroll_request);
+
+  // Finishes enrollment given an |enroll_response| from the Google Attestation
+  // CA. Returns true on success. On failure, returns false and sets
+  // |server_error| to the error string from the CA.
+  bool FinishEnroll(const std::string& enroll_response,
+                    std::string* server_error);
+
+  // Creates a |certificate_request| compatible with the Google Attestation CA
+  // for the given |key|, according to the given |profile|, |username| and
+  // |origin|.
+  bool CreateCertificateRequest(const std::string& username,
+                                const CertifiedKey& key,
+                                CertificateProfile profile,
+                                const std::string& origin,
+                                std::string* certificate_request,
+                                std::string* message_id);
+
+  // Finishes a certificate request by decoding the |certificate_response| to
+  // recover the |certificate_chain| and storing it in association with the
+  // |key| identified by |username| and |key_label|. Returns true on success. On
+  // failure, returns false and sets |server_error| to the error string from the
+  // CA.
+  bool FinishCertificateRequest(const std::string& certificate_response,
+                                const std::string& username,
+                                const std::string& key_label,
+                                const std::string& message_id,
+                                CertifiedKey* key,
+                                std::string* certificate_chain,
+                                std::string* server_error);
+
+  // Sends a |request_type| |request| to the Google Attestation CA and waits for
+  // the |reply|. Returns true on success.
+  bool SendACARequestAndBlock(ACARequestType request_type,
+                              const std::string& request,
+                              std::string* reply);
+
+  // Creates, certifies, and saves a new |key| for |username| with the given
+  // |key_label|, |key_type|, and |key_usage|. Returns true on success.
+  bool CreateKey(const std::string& username,
+                 const std::string& key_label,
+                 KeyType key_type,
+                 KeyUsage key_usage,
+                 CertifiedKey* key);
+
+  // Finds the |key| associated with |username| and |key_label|. Returns false
+  // if such a key does not exist.
+  bool FindKeyByLabel(const std::string& username,
+                      const std::string& key_label,
+                      CertifiedKey* key);
+
+  // Saves the |key| associated with |username| and |key_label|. Returns true on
+  // success.
+  bool SaveKey(const std::string& username,
+               const std::string& key_label,
+               const CertifiedKey& key);
+
+  // Deletes the key associated with |username| and |key_label|.
+  void DeleteKey(const std::string& username,
+                 const std::string& key_label);
+
+  // Adds named device-wide key to the attestation database.
+  bool AddDeviceKey(const std::string& key_label, const CertifiedKey& key);
+
+  // Removes a device-wide key from the attestation database.
+  void RemoveDeviceKey(const std::string& key_label);
+
+  // Creates a PEM certificate chain from the credential fields of a |key|.
+  std::string CreatePEMCertificateChain(const CertifiedKey& key);
+
+  // Creates a certificate in PEM format from a DER encoded X.509 certificate.
+  std::string CreatePEMCertificate(const std::string& certificate);
+
+  // Chooses a temporal index which will be used by the ACA to create a
+  // certificate.  This decision factors in the currently signed-in |user| and
+  // the |origin| of the certificate request.  The strategy is to find an index
+  // which has not already been used by another user for the same origin.
+  int ChooseTemporalIndex(const std::string& user, const std::string& origin);
+
+  // Creates a Google Attestation CA URL for the given |request_type|.
+  std::string GetACAURL(ACARequestType request_type) const;
+
+  // Creates a X.509/DER SubjectPublicKeyInfo for the given |key_type| and
+  // |public_key|. On success returns true and provides |public_key_info|.
+  bool GetSubjectPublicKeyInfo(KeyType key_type,
+                               const std::string& public_key,
+                               std::string* public_key_info) const;
+
+  base::WeakPtr<AttestationService> GetWeakPtr();
+
+
+  const std::string attestation_ca_origin_;
+
+  // Other than initialization and destruction, these are used only by the
+  // worker thread.
+  CryptoUtility* crypto_utility_{nullptr};
+  Database* database_{nullptr};
+  std::shared_ptr<chromeos::http::Transport> http_transport_;
+  KeyStore* key_store_{nullptr};
+  TpmUtility* tpm_utility_{nullptr};
+
+  // Default implementations for the above interfaces. These will be setup
+  // during Initialize() if the corresponding interface has not been set with a
+  // mutator.
+  std::unique_ptr<CryptoUtilityImpl> default_crypto_utility_;
+  std::unique_ptr<DatabaseImpl> default_database_;
+  std::unique_ptr<Pkcs11KeyStore> default_key_store_;
+  std::unique_ptr<chaps::TokenManagerClient> pkcs11_token_manager_;
+  std::unique_ptr<TpmUtilityV1> default_tpm_utility_;
+
+  // All work is done in the background. This serves to serialize requests and
+  // allow synchronous implementation of complex methods. This is intentionally
+  // declared after the thread-owned members.
+  std::unique_ptr<base::Thread> worker_thread_;
+
+  // Declared last so any weak pointers are destroyed first.
+  base::WeakPtrFactory<AttestationService> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AttestationService);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_ATTESTATION_SERVICE_H_
diff --git a/server/attestation_service_test.cc b/server/attestation_service_test.cc
new file mode 100644
index 0000000..2004f51
--- /dev/null
+++ b/server/attestation_service_test.cc
@@ -0,0 +1,1178 @@
+// Copyright 2015 The Chromium OS 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 <string>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/message_loop/message_loop.h>
+#include <base/run_loop.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/data_encoding.h>
+#include <chromeos/http/http_transport_fake.h>
+#include <chromeos/mime_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "attestation/common/attestation_ca.pb.h"
+#include "attestation/common/mock_crypto_utility.h"
+#include "attestation/common/mock_tpm_utility.h"
+#include "attestation/server/attestation_service.h"
+#include "attestation/server/mock_database.h"
+#include "attestation/server/mock_key_store.h"
+
+using chromeos::http::fake::ServerRequest;
+using chromeos::http::fake::ServerResponse;
+using testing::_;
+using testing::DoAll;
+using testing::NiceMock;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgumentPointee;
+
+namespace attestation {
+
+class AttestationServiceTest : public testing::Test {
+ public:
+  enum FakeCAState {
+    kSuccess,         // Valid successful response.
+    kCommandFailure,  // Valid error response.
+    kHttpFailure,     // Responds with an HTTP error.
+    kBadMessageID,    // Valid successful response but a message ID mismatch.
+  };
+
+  ~AttestationServiceTest() override = default;
+  void SetUp() override {
+    service_.reset(new AttestationService);
+    service_->set_database(&mock_database_);
+    service_->set_crypto_utility(&mock_crypto_utility_);
+    fake_http_transport_ = std::make_shared<chromeos::http::fake::Transport>();
+    service_->set_http_transport(fake_http_transport_);
+    service_->set_key_store(&mock_key_store_);
+    service_->set_tpm_utility(&mock_tpm_utility_);
+    // Setup a fake wrapped EK certificate by default.
+    mock_database_.GetMutableProtobuf()->mutable_credentials()->
+        mutable_default_encrypted_endorsement_credential()->
+            set_wrapping_key_id("default");
+    // Setup a fake Attestation CA for success by default.
+    SetupFakeCAEnroll(kSuccess);
+    SetupFakeCASign(kSuccess);
+    CHECK(service_->Initialize());
+  }
+
+ protected:
+  void SetupFakeCAEnroll(FakeCAState state) {
+    fake_http_transport_->AddHandler(
+        service_->attestation_ca_origin() + "/enroll",
+        chromeos::http::request_type::kPost,
+        base::Bind(&AttestationServiceTest::FakeCAEnroll,
+                   base::Unretained(this),
+                   state));
+  }
+
+  void SetupFakeCASign(FakeCAState state) {
+    fake_http_transport_->AddHandler(
+        service_->attestation_ca_origin() + "/sign",
+        chromeos::http::request_type::kPost,
+        base::Bind(&AttestationServiceTest::FakeCASign,
+                   base::Unretained(this),
+                   state));
+  }
+
+  std::string GetFakeCertificateChain() {
+    const std::string kBeginCertificate = "-----BEGIN CERTIFICATE-----\n";
+    const std::string kEndCertificate = "-----END CERTIFICATE-----";
+    std::string pem = kBeginCertificate;
+    pem += chromeos::data_encoding::Base64EncodeWrapLines("fake_cert");
+    pem += kEndCertificate + "\n" + kBeginCertificate;
+    pem += chromeos::data_encoding::Base64EncodeWrapLines("fake_ca_cert");
+    pem += kEndCertificate + "\n" + kBeginCertificate;
+    pem += chromeos::data_encoding::Base64EncodeWrapLines("fake_ca_cert2");
+    pem += kEndCertificate;
+    return pem;
+  }
+
+  CreateGoogleAttestedKeyRequest GetCreateRequest() {
+    CreateGoogleAttestedKeyRequest request;
+    request.set_key_label("label");
+    request.set_key_type(KEY_TYPE_ECC);
+    request.set_key_usage(KEY_USAGE_SIGN);
+    request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
+    request.set_username("user");
+    request.set_origin("origin");
+    return request;
+  }
+
+  void Run() {
+    run_loop_.Run();
+  }
+
+  void RunUntilIdle() {
+    run_loop_.RunUntilIdle();
+  }
+
+  void Quit() {
+    run_loop_.Quit();
+  }
+
+  std::shared_ptr<chromeos::http::fake::Transport> fake_http_transport_;
+  NiceMock<MockCryptoUtility> mock_crypto_utility_;
+  NiceMock<MockDatabase> mock_database_;
+  NiceMock<MockKeyStore> mock_key_store_;
+  NiceMock<MockTpmUtility> mock_tpm_utility_;
+  std::unique_ptr<AttestationService> service_;
+
+ private:
+  void FakeCAEnroll(FakeCAState state,
+                    const ServerRequest& request,
+                    ServerResponse* response) {
+    AttestationEnrollmentRequest request_pb;
+    EXPECT_TRUE(request_pb.ParseFromString(request.GetDataAsString()));
+    if (state == kHttpFailure) {
+      response->ReplyText(chromeos::http::status_code::NotFound, std::string(),
+                          chromeos::mime::application::kOctet_stream);
+      return;
+    }
+    AttestationEnrollmentResponse response_pb;
+    if (state == kCommandFailure) {
+      response_pb.set_status(SERVER_ERROR);
+      response_pb.set_detail("fake_enroll_error");
+    } else if (state == kSuccess) {
+      response_pb.set_status(OK);
+      response_pb.set_detail("");
+      response_pb.mutable_encrypted_identity_credential()->
+          set_asym_ca_contents("1234");
+      response_pb.mutable_encrypted_identity_credential()->
+          set_sym_ca_attestation("5678");
+    } else {
+      NOTREACHED();
+    }
+    std::string tmp;
+    response_pb.SerializeToString(&tmp);
+    response->ReplyText(chromeos::http::status_code::Ok, tmp,
+                        chromeos::mime::application::kOctet_stream);
+  }
+
+  void FakeCASign(FakeCAState state,
+                  const ServerRequest& request,
+                  ServerResponse* response) {
+    AttestationCertificateRequest request_pb;
+    EXPECT_TRUE(request_pb.ParseFromString(request.GetDataAsString()));
+    if (state == kHttpFailure) {
+      response->ReplyText(chromeos::http::status_code::NotFound, std::string(),
+                          chromeos::mime::application::kOctet_stream);
+      return;
+    }
+    AttestationCertificateResponse response_pb;
+    if (state == kCommandFailure) {
+      response_pb.set_status(SERVER_ERROR);
+      response_pb.set_detail("fake_sign_error");
+    } else if (state == kSuccess || state == kBadMessageID) {
+      response_pb.set_status(OK);
+      response_pb.set_detail("");
+      if (state == kSuccess) {
+        response_pb.set_message_id(request_pb.message_id());
+      }
+      response_pb.set_certified_key_credential("fake_cert");
+      response_pb.set_intermediate_ca_cert("fake_ca_cert");
+      *response_pb.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+    }
+    std::string tmp;
+    response_pb.SerializeToString(&tmp);
+    response->ReplyText(chromeos::http::status_code::Ok, tmp,
+                        chromeos::mime::application::kOctet_stream);
+  }
+
+  base::MessageLoop message_loop_;
+  base::RunLoop run_loop_;
+};
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeySuccess) {
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(GetFakeCertificateChain(), reply.certificate_chain());
+    EXPECT_FALSE(reply.has_server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeySuccessNoUser) {
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(GetFakeCertificateChain(), reply.certificate_chain());
+    EXPECT_FALSE(reply.has_server_error());
+    Quit();
+  };
+  CreateGoogleAttestedKeyRequest request = GetCreateRequest();
+  request.clear_username();
+  service_->CreateGoogleAttestedKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithEnrollHttpError) {
+  SetupFakeCAEnroll(kHttpFailure);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_CA_NOT_AVAILABLE, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithSignHttpError) {
+  SetupFakeCASign(kHttpFailure);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_CA_NOT_AVAILABLE, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithCAEnrollFailure) {
+  SetupFakeCAEnroll(kCommandFailure);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_REQUEST_DENIED_BY_CA, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("fake_enroll_error", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithCASignFailure) {
+  SetupFakeCASign(kCommandFailure);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_EQ(STATUS_REQUEST_DENIED_BY_CA, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("fake_sign_error", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithBadCAMessageID) {
+  SetupFakeCASign(kBadMessageID);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithNoEKCertificate) {
+  // Remove the default credential setup.
+  mock_database_.GetMutableProtobuf()->clear_credentials();
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithRNGFailure) {
+  EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithRNGFailure2) {
+  EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _))
+      .WillOnce(Return(true))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithDBFailure) {
+  EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithDBFailureNoUser) {
+  EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  CreateGoogleAttestedKeyRequest request = GetCreateRequest();
+  request.clear_username();
+  service_->CreateGoogleAttestedKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithKeyWriteFailure) {
+  EXPECT_CALL(mock_key_store_, Write(_, _, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmNotReady) {
+  EXPECT_CALL(mock_tpm_utility_, IsTpmReady())
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmActivateFailure) {
+  EXPECT_CALL(mock_tpm_utility_, ActivateIdentity(_, _, _, _, _, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmCreateFailure) {
+  EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateGoogleAttestedKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_certificate_chain());
+    EXPECT_EQ("", reply.server_error());
+    Quit();
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyAndCancel) {
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const CreateGoogleAttestedKeyReply& reply) {
+    callback_count++;
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  // Bring down the service, which should cancel any callbacks.
+  service_.reset();
+  EXPECT_EQ(0, callback_count);
+}
+
+TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyAndCancel2) {
+  // Set expectations on the outputs.
+  int callback_count = 0;
+  auto callback = [&callback_count](const CreateGoogleAttestedKeyReply& reply) {
+    callback_count++;
+  };
+  service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback));
+  // Give threads a chance to run.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+  // Bring down the service, which should cancel any callbacks.
+  service_.reset();
+  // Pump the loop to make sure no callbacks were posted.
+  RunUntilIdle();
+  EXPECT_EQ(0, callback_count);
+}
+
+TEST_F(AttestationServiceTest, GetKeyInfoSuccess) {
+  // Setup a certified key in the key store.
+  CertifiedKey key;
+  key.set_public_key("public_key");
+  key.set_certified_key_credential("fake_cert");
+  key.set_intermediate_ca_cert("fake_ca_cert");
+  *key.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+  key.set_key_name("label");
+  key.set_certified_key_info("certify_info");
+  key.set_certified_key_proof("signature");
+  key.set_key_type(KEY_TYPE_RSA);
+  key.set_key_usage(KEY_USAGE_SIGN);
+  std::string key_bytes;
+  key.SerializeToString(&key_bytes);
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillOnce(DoAll(SetArgumentPointee<2>(key_bytes), Return(true)));
+
+  // Set expectations on the outputs.
+  auto callback = [this](const GetKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(KEY_TYPE_RSA, reply.key_type());
+    EXPECT_EQ(KEY_USAGE_SIGN, reply.key_usage());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("signature", reply.certify_info_signature());
+    EXPECT_EQ(GetFakeCertificateChain(), reply.certificate());
+    Quit();
+  };
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->GetKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetKeyInfoSuccessNoUser) {
+  // Setup a certified key in the device key store.
+  CertifiedKey& key = *mock_database_.GetMutableProtobuf()->add_device_keys();
+  key.set_public_key("public_key");
+  key.set_certified_key_credential("fake_cert");
+  key.set_intermediate_ca_cert("fake_ca_cert");
+  *key.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+  key.set_key_name("label");
+  key.set_certified_key_info("certify_info");
+  key.set_certified_key_proof("signature");
+  key.set_key_type(KEY_TYPE_RSA);
+  key.set_key_usage(KEY_USAGE_SIGN);
+
+  // Set expectations on the outputs.
+  auto callback = [this](const GetKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(KEY_TYPE_RSA, reply.key_type());
+    EXPECT_EQ(KEY_USAGE_SIGN, reply.key_usage());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("signature", reply.certify_info_signature());
+    EXPECT_EQ(GetFakeCertificateChain(), reply.certificate());
+    Quit();
+  };
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  service_->GetKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetKeyInfoNoKey) {
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillRepeatedly(Return(false));
+
+  // Set expectations on the outputs.
+  auto callback = [this](const GetKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_INVALID_PARAMETER, reply.status());
+    Quit();
+  };
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->GetKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetKeyInfoBadPublicKey) {
+  EXPECT_CALL(mock_crypto_utility_, GetRSASubjectPublicKeyInfo(_, _))
+      .WillRepeatedly(Return(false));
+
+  // Set expectations on the outputs.
+  auto callback = [this](const GetKeyInfoReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->GetKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetEndorsementInfoSuccess) {
+  AttestationDatabase* database = mock_database_.GetMutableProtobuf();
+  database->mutable_credentials()->set_endorsement_public_key("public_key");
+  database->mutable_credentials()->set_endorsement_credential("certificate");
+  // Set expectations on the outputs.
+  auto callback = [this](const GetEndorsementInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.ek_public_key());
+    EXPECT_EQ("certificate", reply.ek_certificate());
+    Quit();
+  };
+  GetEndorsementInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetEndorsementInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetEndorsementInfoNoInfo) {
+  // Set expectations on the outputs.
+  auto callback = [this](const GetEndorsementInfoReply& reply) {
+    EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+    EXPECT_FALSE(reply.has_ek_public_key());
+    EXPECT_FALSE(reply.has_ek_certificate());
+    Quit();
+  };
+  GetEndorsementInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetEndorsementInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetEndorsementInfoNoCert) {
+  AttestationDatabase* database = mock_database_.GetMutableProtobuf();
+  database->mutable_credentials()->set_endorsement_public_key("public_key");
+  // Set expectations on the outputs.
+  auto callback = [this](const GetEndorsementInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.ek_public_key());
+    EXPECT_FALSE(reply.has_ek_certificate());
+    Quit();
+  };
+  GetEndorsementInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetEndorsementInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetAttestationKeyInfoSuccess) {
+  AttestationDatabase* database = mock_database_.GetMutableProtobuf();
+  database->mutable_identity_key()->set_identity_public_key("public_key");
+  database->mutable_identity_key()->set_identity_credential("certificate");
+  database->mutable_pcr0_quote()->set_quote("pcr0");
+  database->mutable_pcr1_quote()->set_quote("pcr1");
+  database->mutable_identity_binding()->set_identity_public_key("public_key2");
+  // Set expectations on the outputs.
+  auto callback = [this](const GetAttestationKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("public_key2", reply.public_key_tpm_format());
+    EXPECT_EQ("certificate", reply.certificate());
+    EXPECT_EQ("pcr0", reply.pcr0_quote().quote());
+    EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
+    Quit();
+  };
+  GetAttestationKeyInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetAttestationKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetAttestationKeyInfoNoInfo) {
+  // Set expectations on the outputs.
+  auto callback = [this](const GetAttestationKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_public_key_tpm_format());
+    EXPECT_FALSE(reply.has_certificate());
+    EXPECT_FALSE(reply.has_pcr0_quote());
+    EXPECT_FALSE(reply.has_pcr1_quote());
+    Quit();
+  };
+  GetAttestationKeyInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetAttestationKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, GetAttestationKeyInfoSomeInfo) {
+  AttestationDatabase* database = mock_database_.GetMutableProtobuf();
+  database->mutable_identity_key()->set_identity_credential("certificate");
+  database->mutable_pcr1_quote()->set_quote("pcr1");
+  // Set expectations on the outputs.
+  auto callback = [this](const GetAttestationKeyInfoReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_public_key_tpm_format());
+    EXPECT_EQ("certificate", reply.certificate());
+    EXPECT_FALSE(reply.has_pcr0_quote());
+    EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
+    Quit();
+  };
+  GetAttestationKeyInfoRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  service_->GetAttestationKeyInfo(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, ActivateAttestationKeySuccess) {
+  EXPECT_CALL(mock_database_, SaveChanges()).Times(1);
+  EXPECT_CALL(mock_tpm_utility_, ActivateIdentity(_, _, _, "encrypted1",
+                                                  "encrypted2", _))
+      .WillOnce(DoAll(SetArgumentPointee<5>(std::string("certificate")),
+                      Return(true)));
+  // Set expectations on the outputs.
+  auto callback = [this](const ActivateAttestationKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("certificate", reply.certificate());
+    Quit();
+  };
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(true);
+  service_->ActivateAttestationKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, ActivateAttestationKeySuccessNoSave) {
+  EXPECT_CALL(mock_database_, GetMutableProtobuf()).Times(0);
+  EXPECT_CALL(mock_database_, SaveChanges()).Times(0);
+  EXPECT_CALL(mock_tpm_utility_, ActivateIdentity(_, _, _, "encrypted1",
+                                                  "encrypted2", _))
+      .WillOnce(DoAll(SetArgumentPointee<5>(std::string("certificate")),
+                      Return(true)));
+  // Set expectations on the outputs.
+  auto callback = [this](const ActivateAttestationKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("certificate", reply.certificate());
+    Quit();
+  };
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(false);
+  service_->ActivateAttestationKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, ActivateAttestationKeySaveFailure) {
+  EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const ActivateAttestationKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(true);
+  service_->ActivateAttestationKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, ActivateAttestationKeyActivateFailure) {
+  EXPECT_CALL(mock_tpm_utility_, ActivateIdentity(_, _, _, "encrypted1",
+                                                  "encrypted2", _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const ActivateAttestationKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_RSA);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(true);
+  service_->ActivateAttestationKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeySuccess) {
+  // Configure a fake TPM response.
+  EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(KEY_TYPE_ECC,
+                                                    KEY_USAGE_SIGN,
+                                                    _, _, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgumentPointee<5>(std::string("public_key")),
+                      SetArgumentPointee<7>(std::string("certify_info")),
+                      SetArgumentPointee<8>(
+                          std::string("certify_info_signature")),
+                      Return(true)));
+  // Expect the key to be written exactly once.
+  EXPECT_CALL(mock_key_store_, Write("user", "label", _)).Times(1);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("certify_info_signature", reply.certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_username("user");
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeySuccessNoUser) {
+  // Configure a fake TPM response.
+  EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(KEY_TYPE_ECC,
+                                                    KEY_USAGE_SIGN,
+                                                    _, _, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgumentPointee<5>(std::string("public_key")),
+                      SetArgumentPointee<7>(std::string("certify_info")),
+                      SetArgumentPointee<8>(
+                          std::string("certify_info_signature")),
+                      Return(true)));
+  // Expect the key to be written exactly once.
+  EXPECT_CALL(mock_database_, SaveChanges()).Times(1);
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ("public_key", reply.public_key());
+    EXPECT_EQ("certify_info", reply.certify_info());
+    EXPECT_EQ("certify_info_signature", reply.certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeyRNGFailure) {
+  EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_certify_info());
+    EXPECT_FALSE(reply.has_certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeyTpmCreateFailure) {
+  EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_certify_info());
+    EXPECT_FALSE(reply.has_certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeyDBFailure) {
+  EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_certify_info());
+    EXPECT_FALSE(reply.has_certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_username("username");
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, CreateCertifiableKeyDBFailureNoUser) {
+  EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const CreateCertifiableKeyReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_public_key());
+    EXPECT_FALSE(reply.has_certify_info());
+    EXPECT_FALSE(reply.has_certify_info_signature());
+    Quit();
+  };
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  service_->CreateCertifiableKey(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, DecryptSuccess) {
+  // Set expectations on the outputs.
+  auto callback = [this](const DecryptReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
+              reply.decrypted_data());
+    Quit();
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_encrypted_data("data");
+  service_->Decrypt(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, DecryptSuccessNoUser) {
+  mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label");
+  // Set expectations on the outputs.
+  auto callback = [this](const DecryptReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
+              reply.decrypted_data());
+    Quit();
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_encrypted_data("data");
+  service_->Decrypt(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, DecryptKeyNotFound) {
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const DecryptReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_decrypted_data());
+    Quit();
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_encrypted_data("data");
+  service_->Decrypt(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, DecryptKeyNotFoundNoUser) {
+  // Set expectations on the outputs.
+  auto callback = [this](const DecryptReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_decrypted_data());
+    Quit();
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_encrypted_data("data");
+  service_->Decrypt(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, DecryptUnbindFailure) {
+  EXPECT_CALL(mock_tpm_utility_, Unbind(_, _, _)).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const DecryptReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_decrypted_data());
+    Quit();
+  };
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_encrypted_data("data");
+  service_->Decrypt(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignSuccess) {
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignSuccessNoUser) {
+  mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label");
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignKeyNotFound) {
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignKeyNotFoundNoUser) {
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, SignUnbindFailure) {
+  EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const SignReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    EXPECT_FALSE(reply.has_signature());
+    Quit();
+  };
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  service_->Sign(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterSuccess) {
+  // Setup a key in the user key store.
+  CertifiedKey key;
+  key.set_key_blob("key_blob");
+  key.set_public_key("public_key");
+  key.set_certified_key_credential("fake_cert");
+  key.set_intermediate_ca_cert("fake_ca_cert");
+  *key.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+  key.set_key_name("label");
+  key.set_key_type(KEY_TYPE_RSA);
+  key.set_key_usage(KEY_USAGE_SIGN);
+  std::string key_bytes;
+  key.SerializeToString(&key_bytes);
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillOnce(DoAll(SetArgumentPointee<2>(key_bytes), Return(true)));
+  // Cardinality is verified here to verify various steps are performed and to
+  // catch performance regressions.
+  EXPECT_CALL(mock_key_store_, Register("user",
+                                        "label",
+                                        KEY_TYPE_RSA,
+                                        KEY_USAGE_SIGN,
+                                        "key_blob",
+                                        "public_key",
+                                        "fake_cert")).Times(1);
+  EXPECT_CALL(mock_key_store_, RegisterCertificate("user", "fake_ca_cert"))
+      .Times(1);
+  EXPECT_CALL(mock_key_store_, RegisterCertificate("user", "fake_ca_cert2"))
+      .Times(1);
+  EXPECT_CALL(mock_key_store_, Delete("user", "label")).Times(1);
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterSuccessNoUser) {
+  // Setup a key in the device_keys field.
+  CertifiedKey& key = *mock_database_.GetMutableProtobuf()->add_device_keys();
+  key.set_key_blob("key_blob");
+  key.set_public_key("public_key");
+  key.set_certified_key_credential("fake_cert");
+  key.set_intermediate_ca_cert("fake_ca_cert");
+  *key.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+  key.set_key_name("label");
+  key.set_key_type(KEY_TYPE_RSA);
+  key.set_key_usage(KEY_USAGE_SIGN);
+  // Cardinality is verified here to verify various steps are performed and to
+  // catch performance regressions.
+  EXPECT_CALL(mock_key_store_, Register("",
+                                        "label",
+                                        KEY_TYPE_RSA,
+                                        KEY_USAGE_SIGN,
+                                        "key_blob",
+                                        "public_key",
+                                        "fake_cert")).Times(1);
+  EXPECT_CALL(mock_key_store_, RegisterCertificate("", "fake_ca_cert"))
+      .Times(1);
+  EXPECT_CALL(mock_key_store_, RegisterCertificate("", "fake_ca_cert2"))
+      .Times(1);
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_EQ(0, mock_database_.GetMutableProtobuf()->device_keys_size());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterNoKey) {
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterNoKeyNoUser) {
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterFailure) {
+  // Setup a key in the user key store.
+  CertifiedKey key;
+  key.set_key_name("label");
+  std::string key_bytes;
+  key.SerializeToString(&key_bytes);
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillOnce(DoAll(SetArgumentPointee<2>(key_bytes), Return(true)));
+  EXPECT_CALL(mock_key_store_, Register(_, _, _, _, _, _, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterIntermediateFailure) {
+  // Setup a key in the user key store.
+  CertifiedKey key;
+  key.set_key_name("label");
+  key.set_intermediate_ca_cert("fake_ca_cert");
+  std::string key_bytes;
+  key.SerializeToString(&key_bytes);
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillOnce(DoAll(SetArgumentPointee<2>(key_bytes), Return(true)));
+  EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+TEST_F(AttestationServiceTest, RegisterAdditionalFailure) {
+  // Setup a key in the user key store.
+  CertifiedKey key;
+  key.set_key_name("label");
+  *key.add_additional_intermediate_ca_cert() = "fake_ca_cert2";
+  std::string key_bytes;
+  key.SerializeToString(&key_bytes);
+  EXPECT_CALL(mock_key_store_, Read("user", "label", _))
+      .WillOnce(DoAll(SetArgumentPointee<2>(key_bytes), Return(true)));
+  EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _))
+      .WillRepeatedly(Return(false));
+  // Set expectations on the outputs.
+  auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) {
+    EXPECT_NE(STATUS_SUCCESS, reply.status());
+    Quit();
+  };
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  service_->RegisterKeyWithChapsToken(request, base::Bind(callback));
+  Run();
+}
+
+}  // namespace attestation
diff --git a/server/attestationd-seccomp-amd64.policy b/server/attestationd-seccomp-amd64.policy
new file mode 100644
index 0000000..d7e1ad9
--- /dev/null
+++ b/server/attestationd-seccomp-amd64.policy
@@ -0,0 +1,68 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Tested on link
+gettid: 1
+getuid: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getresuid: 1
+getresgid: 1
+
+clock_getres: 1
+clock_gettime: 1
+gettimeofday: 1
+time: 1
+
+socket: 1
+socketpair: 1
+connect: 1
+getsockname: 1
+pipe: 1
+sendmsg: 1
+sendto: 1
+recvmsg: 1
+recvfrom: 1
+
+epoll_create: 1
+epoll_wait: 1
+epoll_ctl: 1
+poll: 1
+
+open: 1
+read: 1
+write: 1
+close: 1
+
+inotify_init: 1
+inotify_add_watch: 1
+inotify_rm_watch: 1
+select: 1
+
+fstat: 1
+stat: 1
+lseek: 1
+lstat: 1
+fcntl: 1
+
+futex: 1
+set_robust_list: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+rt_sigprocmask: 1
+signalfd4: 1
+
+brk: 1
+mmap: 1
+madvise: 1
+mprotect: 1
+munmap: 1
+
+clone: 1
+# These calls are attempted but apparently not necessary; return EPERM
+prctl: return 1
+ioctl: return 1
diff --git a/server/attestationd-seccomp-arm.policy b/server/attestationd-seccomp-arm.policy
new file mode 100644
index 0000000..16d2a9f
--- /dev/null
+++ b/server/attestationd-seccomp-arm.policy
@@ -0,0 +1,50 @@
+# Tested on daisy_spring board
+gettid: 1
+getuid32: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getresuid32: 1
+getresgid32: 1
+
+clock_getres: 1
+clock_gettime: 1
+gettimeofday: 1
+
+# Allow socket(domain==PF_LOCAL) or socket(domain==PF_NETLINK)
+socket: arg0 == 0x1 || arg0 == 0x10
+socketpair: 1
+connect: 1
+getsockname: 1
+pipe: 1
+send: 1
+sendmsg: 1
+recvmsg: 1
+
+epoll_create: 1
+epoll_wait: 1
+epoll_ctl: 1
+poll: 1
+
+open: 1
+read: 1
+write: 1
+close: 1
+
+fstat64: 1
+stat64: 1
+_llseek: 1
+fcntl64: 1
+
+futex: 1
+
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+rt_sigprocmask: 1
+signalfd4: 1
+
+brk: 1
+mmap2: 1
+munmap: 1
diff --git a/server/attestationd-seccomp-x86.policy b/server/attestationd-seccomp-x86.policy
new file mode 100644
index 0000000..015e01e
--- /dev/null
+++ b/server/attestationd-seccomp-x86.policy
@@ -0,0 +1,45 @@
+# Tested on alex board
+gettid: 1
+geteuid32: 1
+getegid32: 1
+getuid32: 1
+getgid32: 1
+getresuid32: 1
+getresgid32: 1
+
+clock_getres: 1
+clock_gettime: 1
+gettimeofday: 1
+time: 1
+
+# TODO(namnguyen): filter socket system calls.
+socketcall: 1
+pipe: 1
+
+open: 1
+read: 1
+write: 1
+close: 1
+
+brk: 1
+mmap2: 1
+munmap: 1
+
+fstat64: 1
+stat64: 1
+_llseek: 1
+fcntl64: 1
+
+futex: 1
+
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+rt_sigprocmask: 1
+signalfd4: 1
+
+epoll_create: 1
+epoll_wait: 1
+epoll_ctl: 1
+poll: 1
diff --git a/server/attestationd.conf b/server/attestationd.conf
new file mode 100644
index 0000000..e9165ed
--- /dev/null
+++ b/server/attestationd.conf
@@ -0,0 +1,12 @@
+# Copyright 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+description     "Chromium OS device attestation service."
+author          "chromium-os-dev@chromium.org"
+
+start on started tcsd and started boot-services
+stop on stopping boot-services
+respawn
+
+exec /usr/sbin/attestationd
diff --git a/server/database.h b/server/database.h
new file mode 100644
index 0000000..40ca511
--- /dev/null
+++ b/server/database.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_DATABASE_H_
+#define ATTESTATION_SERVER_DATABASE_H_
+
+#include "attestation/common/database.pb.h"
+
+namespace attestation {
+
+// Manages a persistent database of attestation-related data.
+class Database {
+ public:
+  virtual ~Database() = default;
+
+  // Const access to the database protobuf.
+  virtual const AttestationDatabase& GetProtobuf() const = 0;
+
+  // Mutable access to the database protobuf. Changes made to the protobuf will
+  // be reflected immediately by GetProtobuf() but will not be persisted to disk
+  // until SaveChanges is called successfully.
+  virtual AttestationDatabase* GetMutableProtobuf() = 0;
+
+  // Writes the current database protobuf to disk.
+  virtual bool SaveChanges() = 0;
+
+  // Reloads the database protobuf from disk.
+  virtual bool Reload() = 0;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_DATABASE_H_
diff --git a/server/database_impl.cc b/server/database_impl.cc
new file mode 100644
index 0000000..387f220
--- /dev/null
+++ b/server/database_impl.cc
@@ -0,0 +1,187 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/database_impl.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/important_file_writer.h>
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <chromeos/secure_blob.h>
+
+using base::FilePath;
+
+namespace {
+
+const char kDatabasePath[] =
+    "/mnt/stateful_partition/unencrypted/preserve/attestation.epb";
+const mode_t kDatabasePermissions = 0600;
+
+// A base::FilePathWatcher::Callback that just relays to |callback|.
+void FileWatcherCallback(const base::Closure& callback, const FilePath&, bool) {
+  callback.Run();
+}
+
+}  // namespace
+
+namespace attestation {
+
+DatabaseImpl::DatabaseImpl(CryptoUtility* crypto) : io_(this), crypto_(crypto) {
+}
+
+DatabaseImpl::~DatabaseImpl() {
+  chromeos::SecureMemset(string_as_array(&database_key_), 0,
+                         database_key_.size());
+}
+
+void DatabaseImpl::Initialize() {
+  // Start thread-checking now.
+  thread_checker_.DetachFromThread();
+  DCHECK(thread_checker_.CalledOnValidThread());
+  io_->Watch(base::Bind(base::IgnoreResult(&DatabaseImpl::Reload),
+                        base::Unretained(this)));
+  if (!Reload()) {
+    LOG(WARNING) << "Creating new attestation database.";
+  }
+}
+
+const AttestationDatabase& DatabaseImpl::GetProtobuf() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return protobuf_;
+}
+
+AttestationDatabase* DatabaseImpl::GetMutableProtobuf() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return &protobuf_;
+}
+
+bool DatabaseImpl::SaveChanges() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  std::string buffer;
+  if (!EncryptProtobuf(&buffer)) {
+    return false;
+  }
+  return io_->Write(buffer);
+}
+
+bool DatabaseImpl::Reload() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  LOG(INFO) << "Loading attestation database.";
+  std::string buffer;
+  if (!io_->Read(&buffer)) {
+    return false;
+  }
+  return DecryptProtobuf(buffer);
+}
+
+bool DatabaseImpl::Read(std::string* data) {
+  const int kMask = base::FILE_PERMISSION_OTHERS_MASK;
+  FilePath path(kDatabasePath);
+  int permissions = 0;
+  if (base::GetPosixFilePermissions(path, &permissions) &&
+      (permissions & kMask) != 0) {
+    base::SetPosixFilePermissions(path, permissions & ~kMask);
+  }
+  return base::ReadFileToString(path, data);
+}
+
+bool DatabaseImpl::Write(const std::string& data) {
+  FilePath file_path(kDatabasePath);
+  if (!base::CreateDirectory(file_path.DirName())) {
+    LOG(ERROR) << "Cannot create directory: " << file_path.DirName().value();
+    return false;
+  }
+  if (!base::ImportantFileWriter::WriteFileAtomically(file_path, data)) {
+    LOG(ERROR) << "Failed to write file: " << file_path.value();
+    return false;
+  }
+  if (!base::SetPosixFilePermissions(file_path, kDatabasePermissions)) {
+    LOG(ERROR) << "Failed to set permissions for file: " << file_path.value();
+    return false;
+  }
+  // Sync the parent directory.
+  std::string dir_name = file_path.DirName().value();
+  int dir_fd = HANDLE_EINTR(open(dir_name.c_str(), O_RDONLY|O_DIRECTORY));
+  if (dir_fd < 0) {
+    PLOG(WARNING) << "Could not open " << dir_name << " for syncing";
+    return false;
+  }
+  // POSIX specifies EINTR as a possible return value of fsync().
+  int result = HANDLE_EINTR(fsync(dir_fd));
+  if (result < 0) {
+    PLOG(WARNING) << "Failed to sync " << dir_name;
+    close(dir_fd);
+    return false;
+  }
+  // close() may not be retried on error.
+  result = IGNORE_EINTR(close(dir_fd));
+  if (result < 0) {
+    PLOG(WARNING) << "Failed to close after sync " << dir_name;
+    return false;
+  }
+  return true;
+}
+
+void DatabaseImpl::Watch(const base::Closure& callback) {
+  if (!file_watcher_) {
+    file_watcher_.reset(new base::FilePathWatcher());
+    file_watcher_->Watch(FilePath(kDatabasePath), false,
+                         base::Bind(&FileWatcherCallback, callback));
+  }
+}
+
+bool DatabaseImpl::EncryptProtobuf(std::string* encrypted_output) {
+  std::string serial_proto;
+  if (!protobuf_.SerializeToString(&serial_proto)) {
+    LOG(ERROR) << "Failed to serialize db.";
+    return false;
+  }
+  if (database_key_.empty() || sealed_database_key_.empty()) {
+    if (!crypto_->CreateSealedKey(&database_key_, &sealed_database_key_)) {
+      LOG(ERROR) << "Failed to generate database key.";
+      return false;
+    }
+  }
+  if (!crypto_->EncryptData(serial_proto, database_key_, sealed_database_key_,
+                            encrypted_output)) {
+    LOG(ERROR) << "Attestation: Failed to encrypt database.";
+    return false;
+  }
+  return true;
+}
+
+bool DatabaseImpl::DecryptProtobuf(const std::string& encrypted_input) {
+  if (!crypto_->UnsealKey(encrypted_input, &database_key_,
+                          &sealed_database_key_)) {
+    LOG(ERROR) << "Attestation: Could not unseal decryption key.";
+    return false;
+  }
+  std::string serial_proto;
+  if (!crypto_->DecryptData(encrypted_input, database_key_, &serial_proto)) {
+    LOG(ERROR) << "Attestation: Failed to decrypt database.";
+    return false;
+  }
+  if (!protobuf_.ParseFromString(serial_proto)) {
+    // Previously the DB was encrypted with CryptoLib::AesEncrypt which appends
+    // a SHA-1.  This can be safely ignored.
+    const size_t kLegacyJunkSize = 20;
+    if (serial_proto.size() < kLegacyJunkSize ||
+        !protobuf_.ParseFromArray(serial_proto.data(),
+                                  serial_proto.length() - kLegacyJunkSize)) {
+      LOG(ERROR) << "Failed to parse database.";
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace attestation
diff --git a/server/database_impl.h b/server/database_impl.h
new file mode 100644
index 0000000..077ec05
--- /dev/null
+++ b/server/database_impl.h
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_DATABASE_IMPL_H_
+#define ATTESTATION_SERVER_DATABASE_IMPL_H_
+
+#include "attestation/server/database.h"
+
+#include <string>
+
+#include <base/callback_forward.h>
+#include <base/files/file_path_watcher.h>
+#include <base/threading/thread_checker.h>
+
+#include "attestation/common/crypto_utility.h"
+
+namespace attestation {
+
+// An I/O abstraction to help with testing.
+class DatabaseIO {
+ public:
+  // Reads the persistent database blob.
+  virtual bool Read(std::string* data) = 0;
+  // Writes the persistent database blob.
+  virtual bool Write(const std::string& data) = 0;
+  // Watch for external changes to the database.
+  virtual void Watch(const base::Closure& callback) = 0;
+};
+
+// An implementation of Database backed by an ordinary file. Not thread safe.
+// All methods must be called on the same thread as the Initialize() call.
+class DatabaseImpl : public Database,
+                     public DatabaseIO {
+ public:
+  // Does not take ownership of pointers.
+  explicit DatabaseImpl(CryptoUtility* crypto);
+  ~DatabaseImpl() override;
+
+  // Reads and decrypts any existing database on disk synchronously. Must be
+  // called before calling other methods.
+  void Initialize();
+
+  // Database methods.
+  const AttestationDatabase& GetProtobuf() const override;
+  AttestationDatabase* GetMutableProtobuf() override;
+  bool SaveChanges() override;
+  bool Reload() override;
+
+  // DatabaseIO methods.
+  bool Read(std::string* data) override;
+  bool Write(const std::string& data) override;
+  void Watch(const base::Closure& callback) override;
+
+  // Useful for testing.
+  void set_io(DatabaseIO* io) {
+    io_ = io;
+  }
+
+ private:
+  // Encrypts |protobuf_| into |encrypted_output|. Returns true on success.
+  bool EncryptProtobuf(std::string* encrypted_output);
+
+  // Decrypts |encrypted_input| as output by EncryptProtobuf into |protobuf_|.
+  // Returns true on success.
+  bool DecryptProtobuf(const std::string& encrypted_input);
+
+  AttestationDatabase protobuf_;
+  DatabaseIO* io_;
+  CryptoUtility* crypto_;
+  std::string database_key_;
+  std::string sealed_database_key_;
+  std::unique_ptr<base::FilePathWatcher> file_watcher_;
+  base::ThreadChecker thread_checker_;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_DATABASE_IMPL_H_
diff --git a/server/database_impl_test.cc b/server/database_impl_test.cc
new file mode 100644
index 0000000..e2fef01
--- /dev/null
+++ b/server/database_impl_test.cc
@@ -0,0 +1,151 @@
+// Copyright 2015 The Chromium OS 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 <memory>
+#include <string>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "attestation/common/mock_crypto_utility.h"
+#include "attestation/server/database_impl.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::WithArgs;
+
+namespace {
+
+const char kFakeCredential[] = "1234";
+
+}  // namespace
+
+namespace attestation {
+
+class DatabaseImplTest : public testing::Test,
+                         public DatabaseIO {
+ public:
+  ~DatabaseImplTest() override = default;
+  void SetUp() override {
+    database_.reset(new DatabaseImpl(&mock_crypto_utility_));
+    database_->set_io(this);
+    InitializeFakeData();
+    database_->Initialize();
+  }
+
+  // Fake DatabaseIO::Read.
+  bool Read(std::string* data) override {
+    if (fake_persistent_data_readable_) {
+      *data = fake_persistent_data_;
+    }
+    return fake_persistent_data_readable_;
+  }
+
+  // Fake DatabaseIO::Write.
+  bool Write(const std::string& data) override {
+    if (fake_persistent_data_writable_) {
+      fake_persistent_data_ = data;
+    }
+    return fake_persistent_data_writable_;
+  }
+
+  // Fake DatabaseIO::Watch.
+  void Watch(const base::Closure& callback) override {
+    fake_watch_callback_ = callback;
+  }
+
+  // Initializes fake_persistent_data_ with a default value.
+  void InitializeFakeData() {
+    AttestationDatabase proto;
+    proto.mutable_credentials()->set_conformance_credential(kFakeCredential);
+    proto.SerializeToString(&fake_persistent_data_);
+  }
+
+ protected:
+  std::string fake_persistent_data_;
+  bool fake_persistent_data_readable_{true};
+  bool fake_persistent_data_writable_{true};
+  base::Closure fake_watch_callback_;
+  NiceMock<MockCryptoUtility> mock_crypto_utility_;
+  std::unique_ptr<DatabaseImpl> database_;
+};
+
+TEST_F(DatabaseImplTest, ReadSuccess) {
+  database_->GetMutableProtobuf()->Clear();
+  EXPECT_TRUE(database_->Reload());
+  EXPECT_EQ(std::string(kFakeCredential),
+            database_->GetProtobuf().credentials().conformance_credential());
+}
+
+TEST_F(DatabaseImplTest, ReadFailure) {
+  fake_persistent_data_readable_ = false;
+  database_->GetMutableProtobuf()->Clear();
+  EXPECT_FALSE(database_->Reload());
+  EXPECT_FALSE(database_->GetProtobuf().has_credentials());
+}
+
+TEST_F(DatabaseImplTest, DecryptFailure) {
+  EXPECT_CALL(mock_crypto_utility_, DecryptData(_, _, _))
+      .WillRepeatedly(Return(false));
+  database_->GetMutableProtobuf()->Clear();
+  EXPECT_FALSE(database_->Reload());
+  EXPECT_FALSE(database_->GetProtobuf().has_credentials());
+}
+
+TEST_F(DatabaseImplTest, WriteSuccess) {
+  database_->GetMutableProtobuf()->mutable_credentials()->
+      set_platform_credential("test");
+  std::string expected_data;
+  database_->GetProtobuf().SerializeToString(&expected_data);
+  EXPECT_TRUE(database_->SaveChanges());
+  EXPECT_EQ(expected_data, fake_persistent_data_);
+}
+
+TEST_F(DatabaseImplTest, WriteFailure) {
+  fake_persistent_data_writable_ = false;
+  database_->GetMutableProtobuf()->mutable_credentials()->
+      set_platform_credential("test");
+  EXPECT_FALSE(database_->SaveChanges());
+}
+
+TEST_F(DatabaseImplTest, EncryptFailure) {
+  EXPECT_CALL(mock_crypto_utility_, EncryptData(_, _, _, _))
+      .WillRepeatedly(Return(false));
+  database_->GetMutableProtobuf()->mutable_credentials()->
+      set_platform_credential("test");
+  EXPECT_FALSE(database_->SaveChanges());
+}
+
+TEST_F(DatabaseImplTest, IgnoreLegacyEncryptJunk) {
+  // Legacy encryption scheme appended a SHA-1 hash before encrypting.
+  fake_persistent_data_ += std::string(20, 'A');
+  EXPECT_EQ(std::string(kFakeCredential),
+            database_->GetProtobuf().credentials().conformance_credential());
+}
+
+TEST_F(DatabaseImplTest, Reload) {
+  AttestationDatabase proto;
+  proto.mutable_credentials()->set_platform_credential(kFakeCredential);
+  proto.SerializeToString(&fake_persistent_data_);
+  EXPECT_EQ(std::string(),
+            database_->GetProtobuf().credentials().platform_credential());
+  EXPECT_TRUE(database_->Reload());
+  EXPECT_EQ(std::string(kFakeCredential),
+            database_->GetProtobuf().credentials().platform_credential());
+}
+
+TEST_F(DatabaseImplTest, AutoReload) {
+  AttestationDatabase proto;
+  proto.mutable_credentials()->set_platform_credential(kFakeCredential);
+  proto.SerializeToString(&fake_persistent_data_);
+  EXPECT_EQ(std::string(),
+            database_->GetProtobuf().credentials().platform_credential());
+  fake_watch_callback_.Run();
+  EXPECT_EQ(std::string(kFakeCredential),
+            database_->GetProtobuf().credentials().platform_credential());
+}
+
+}  // namespace attestation
diff --git a/server/dbus_service.cc b/server/dbus_service.cc
new file mode 100644
index 0000000..7973ad3
--- /dev/null
+++ b/server/dbus_service.cc
@@ -0,0 +1,230 @@
+// Copyright 2014 The Chromium OS 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 "attestation/server/dbus_service.h"
+
+#include <memory>
+#include <string>
+
+#include <chromeos/bind_lambda.h>
+#include <dbus/bus.h>
+#include <dbus/object_path.h>
+
+#include "attestation/common/dbus_interface.h"
+
+using chromeos::dbus_utils::DBusMethodResponse;
+
+namespace attestation {
+
+DBusService::DBusService(const scoped_refptr<dbus::Bus>& bus,
+                         AttestationInterface* service)
+    : dbus_object_(nullptr, bus, dbus::ObjectPath(kAttestationServicePath)),
+      service_(service) {
+}
+
+void DBusService::Register(const CompletionAction& callback) {
+  chromeos::dbus_utils::DBusInterface* dbus_interface =
+      dbus_object_.AddOrGetInterface(kAttestationInterface);
+
+  dbus_interface->AddMethodHandler(kCreateGoogleAttestedKey,
+                                   base::Unretained(this),
+                                   &DBusService::HandleCreateGoogleAttestedKey);
+  dbus_interface->AddMethodHandler(kGetKeyInfo,
+                                   base::Unretained(this),
+                                   &DBusService::HandleGetKeyInfo);
+  dbus_interface->AddMethodHandler(kGetEndorsementInfo,
+                                   base::Unretained(this),
+                                   &DBusService::HandleGetEndorsementInfo);
+  dbus_interface->AddMethodHandler(kGetAttestationKeyInfo,
+                                   base::Unretained(this),
+                                   &DBusService::HandleGetAttestationKeyInfo);
+  dbus_interface->AddMethodHandler(kActivateAttestationKey,
+                                   base::Unretained(this),
+                                   &DBusService::HandleActivateAttestationKey);
+  dbus_interface->AddMethodHandler(kCreateCertifiableKey,
+                                   base::Unretained(this),
+                                   &DBusService::HandleCreateCertifiableKey);
+  dbus_interface->AddMethodHandler(kDecrypt,
+                                   base::Unretained(this),
+                                   &DBusService::HandleDecrypt);
+  dbus_interface->AddMethodHandler(kSign,
+                                   base::Unretained(this),
+                                   &DBusService::HandleSign);
+  dbus_interface->AddMethodHandler(
+      kRegisterKeyWithChapsToken,
+      base::Unretained(this),
+      &DBusService::HandleRegisterKeyWithChapsToken);
+
+  dbus_object_.RegisterAsync(callback);
+}
+
+void DBusService::HandleCreateGoogleAttestedKey(
+    std::unique_ptr<DBusMethodResponse<const CreateGoogleAttestedKeyReply&>>
+        response,
+    const CreateGoogleAttestedKeyRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const CreateGoogleAttestedKeyReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const CreateGoogleAttestedKeyReply& reply) {
+    response->Return(reply);
+  };
+  service_->CreateGoogleAttestedKey(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleGetKeyInfo(
+    std::unique_ptr<DBusMethodResponse<const GetKeyInfoReply&>> response,
+    const GetKeyInfoRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const GetKeyInfoReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const GetKeyInfoReply& reply) {
+    response->Return(reply);
+  };
+  service_->GetKeyInfo(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleGetEndorsementInfo(
+    std::unique_ptr<DBusMethodResponse<const GetEndorsementInfoReply&>>
+        response,
+    const GetEndorsementInfoRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const GetEndorsementInfoReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const GetEndorsementInfoReply& reply) {
+    response->Return(reply);
+  };
+  service_->GetEndorsementInfo(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleGetAttestationKeyInfo(
+    std::unique_ptr<DBusMethodResponse<const GetAttestationKeyInfoReply&>>
+        response,
+    const GetAttestationKeyInfoRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const GetAttestationKeyInfoReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const GetAttestationKeyInfoReply& reply) {
+    response->Return(reply);
+  };
+  service_->GetAttestationKeyInfo(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleActivateAttestationKey(
+    std::unique_ptr<DBusMethodResponse<const ActivateAttestationKeyReply&>>
+        response,
+    const ActivateAttestationKeyRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const ActivateAttestationKeyReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const ActivateAttestationKeyReply& reply) {
+    response->Return(reply);
+  };
+  service_->ActivateAttestationKey(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleCreateCertifiableKey(
+    std::unique_ptr<DBusMethodResponse<const CreateCertifiableKeyReply&>>
+        response,
+    const CreateCertifiableKeyRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const CreateCertifiableKeyReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const CreateCertifiableKeyReply& reply) {
+    response->Return(reply);
+  };
+  service_->CreateCertifiableKey(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleDecrypt(
+    std::unique_ptr<DBusMethodResponse<const DecryptReply&>> response,
+    const DecryptRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const DecryptReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const DecryptReply& reply) {
+    response->Return(reply);
+  };
+  service_->Decrypt(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleSign(
+    std::unique_ptr<DBusMethodResponse<const SignReply&>> response,
+    const SignRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const SignReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const SignReply& reply) {
+    response->Return(reply);
+  };
+  service_->Sign(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+void DBusService::HandleRegisterKeyWithChapsToken(
+    std::unique_ptr<DBusMethodResponse<const RegisterKeyWithChapsTokenReply&>>
+        response,
+    const RegisterKeyWithChapsTokenRequest& request) {
+  VLOG(1) << __func__;
+  // Convert |response| to a shared_ptr so |service_| can safely copy the
+  // callback.
+  using SharedResponsePointer = std::shared_ptr<
+      DBusMethodResponse<const RegisterKeyWithChapsTokenReply&>>;
+  // A callback that fills the reply protobuf and sends it.
+  auto callback = [](const SharedResponsePointer& response,
+                     const RegisterKeyWithChapsTokenReply& reply) {
+    response->Return(reply);
+  };
+  service_->RegisterKeyWithChapsToken(
+      request,
+      base::Bind(callback, SharedResponsePointer(std::move(response))));
+}
+
+}  // namespace attestation
diff --git a/server/dbus_service.h b/server/dbus_service.h
new file mode 100644
index 0000000..7224efa
--- /dev/null
+++ b/server/dbus_service.h
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium OS 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 ATTESTATION_SERVER_DBUS_SERVICE_H_
+#define ATTESTATION_SERVER_DBUS_SERVICE_H_
+
+#include <memory>
+
+#include <chromeos/dbus/dbus_method_response.h>
+#include <chromeos/dbus/dbus_object.h>
+#include <dbus/bus.h>
+
+#include "attestation/common/attestation_interface.h"
+
+namespace attestation {
+
+using CompletionAction =
+    chromeos::dbus_utils::AsyncEventSequencer::CompletionAction;
+
+// Handles D-Bus calls to the attestation daemon.
+class DBusService {
+ public:
+  // DBusService does not take ownership of |service|; it must remain valid for
+  // the lifetime of the DBusService instance.
+  DBusService(const scoped_refptr<dbus::Bus>& bus,
+              AttestationInterface* service);
+  virtual ~DBusService() = default;
+
+  // Connects to D-Bus system bus and exports methods.
+  void Register(const CompletionAction& callback);
+
+  // Useful for testing.
+  void set_service(AttestationInterface* service) {
+    service_ = service;
+  }
+
+ private:
+  friend class DBusServiceTest;
+
+  // Handles a CreateGoogleAttestedKey D-Bus call.
+  void HandleCreateGoogleAttestedKey(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const CreateGoogleAttestedKeyReply&>> response,
+      const CreateGoogleAttestedKeyRequest& request);
+
+  // Handles a GetKeyInfo D-Bus call.
+  void HandleGetKeyInfo(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const GetKeyInfoReply&>> response,
+      const GetKeyInfoRequest& request);
+
+  // Handles a GetEndorsementInfo D-Bus call.
+  void HandleGetEndorsementInfo(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const GetEndorsementInfoReply&>> response,
+      const GetEndorsementInfoRequest& request);
+
+  // Handles a GetAttestationKeyInfo D-Bus call.
+  void HandleGetAttestationKeyInfo(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const GetAttestationKeyInfoReply&>> response,
+      const GetAttestationKeyInfoRequest& request);
+
+  // Handles a ActivateAttestationKey D-Bus call.
+  void HandleActivateAttestationKey(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const ActivateAttestationKeyReply&>> response,
+      const ActivateAttestationKeyRequest& request);
+
+  // Handles a CreateCertifiableKey D-Bus call.
+  void HandleCreateCertifiableKey(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const CreateCertifiableKeyReply&>> response,
+      const CreateCertifiableKeyRequest& request);
+
+  // Handles a Decrypt D-Bus call.
+  void HandleDecrypt(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const DecryptReply&>> response,
+      const DecryptRequest& request);
+
+  // Handles a Sign D-Bus call.
+  void HandleSign(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const SignReply&>> response,
+      const SignRequest& request);
+
+  // Handles a RegisterKeyWithChapsToken D-Bus call.
+  void HandleRegisterKeyWithChapsToken(
+      std::unique_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const RegisterKeyWithChapsTokenReply&>> response,
+      const RegisterKeyWithChapsTokenRequest& request);
+
+  chromeos::dbus_utils::DBusObject dbus_object_;
+  AttestationInterface* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(DBusService);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_DBUS_SERVICE_H_
diff --git a/server/dbus_service_test.cc b/server/dbus_service_test.cc
new file mode 100644
index 0000000..b8c0605
--- /dev/null
+++ b/server/dbus_service_test.cc
@@ -0,0 +1,370 @@
+// Copyright 2014 The Chromium OS 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 <string>
+
+#include <chromeos/bind_lambda.h>
+#include <chromeos/dbus/dbus_object_test_helpers.h>
+#include <dbus/mock_bus.h>
+#include <dbus/mock_exported_object.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "attestation/common/dbus_interface.h"
+#include "attestation/common/mock_attestation_interface.h"
+#include "attestation/server/dbus_service.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::StrictMock;
+using testing::WithArgs;
+
+namespace attestation {
+
+class DBusServiceTest : public testing::Test {
+ public:
+  ~DBusServiceTest() override = default;
+  void SetUp() override {
+    dbus::Bus::Options options;
+    mock_bus_ = new NiceMock<dbus::MockBus>(options);
+    dbus::ObjectPath path(kAttestationServicePath);
+    mock_exported_object_ = new NiceMock<dbus::MockExportedObject>(
+        mock_bus_.get(), path);
+    ON_CALL(*mock_bus_, GetExportedObject(path))
+        .WillByDefault(Return(mock_exported_object_.get()));
+    dbus_service_.reset(new DBusService(mock_bus_, &mock_service_));
+    dbus_service_->Register(chromeos::dbus_utils::AsyncEventSequencer::
+                                GetDefaultCompletionAction());
+  }
+
+  std::unique_ptr<dbus::Response> CallMethod(dbus::MethodCall* method_call) {
+    return chromeos::dbus_utils::testing::CallMethod(
+        dbus_service_->dbus_object_, method_call);
+  }
+
+  std::unique_ptr<dbus::MethodCall> CreateMethodCall(
+      const std::string& method_name) {
+    std::unique_ptr<dbus::MethodCall> call(new dbus::MethodCall(
+        kAttestationInterface, method_name));
+    call->SetSerial(1);
+    return call;
+  }
+
+ protected:
+  scoped_refptr<dbus::MockBus> mock_bus_;
+  scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+  StrictMock<MockAttestationInterface> mock_service_;
+  std::unique_ptr<DBusService> dbus_service_;
+};
+
+TEST_F(DBusServiceTest, CreateGoogleAttestedKey) {
+  CreateGoogleAttestedKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
+  request.set_username("username");
+  request.set_origin("origin");
+  EXPECT_CALL(mock_service_, CreateGoogleAttestedKey(_, _))
+      .WillOnce(Invoke([](
+          const CreateGoogleAttestedKeyRequest& request,
+          const AttestationInterface::
+              CreateGoogleAttestedKeyCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ(KEY_TYPE_ECC, request.key_type());
+        EXPECT_EQ(KEY_USAGE_SIGN, request.key_usage());
+        EXPECT_EQ(ENTERPRISE_MACHINE_CERTIFICATE,
+                  request.certificate_profile());
+        EXPECT_EQ("username", request.username());
+        EXPECT_EQ("origin", request.origin());
+        CreateGoogleAttestedKeyReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_certificate_chain("certificate");
+        reply.set_server_error("server_error");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(
+      kCreateGoogleAttestedKey);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  CreateGoogleAttestedKeyReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("certificate", reply.certificate_chain());
+  EXPECT_EQ("server_error", reply.server_error());
+}
+
+TEST_F(DBusServiceTest, CopyableCallback) {
+  EXPECT_CALL(mock_service_, CreateGoogleAttestedKey(_, _))
+      .WillOnce(WithArgs<1>(Invoke([](const AttestationInterface::
+          CreateGoogleAttestedKeyCallback& callback) {
+        // Copy the callback, then call the original.
+        CreateGoogleAttestedKeyReply reply;
+        base::Closure copy = base::Bind(callback, reply);
+        callback.Run(reply);
+      })));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(
+      kCreateGoogleAttestedKey);
+  CreateGoogleAttestedKeyRequest request;
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  CreateGoogleAttestedKeyReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+}
+
+TEST_F(DBusServiceTest, GetKeyInfo) {
+  GetKeyInfoRequest request;
+  request.set_key_label("label");
+  request.set_username("username");
+  EXPECT_CALL(mock_service_, GetKeyInfo(_, _))
+      .WillOnce(Invoke([](
+          const GetKeyInfoRequest& request,
+          const AttestationInterface::GetKeyInfoCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ("username", request.username());
+        GetKeyInfoReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_key_type(KEY_TYPE_ECC);
+        reply.set_key_usage(KEY_USAGE_SIGN);
+        reply.set_public_key("public_key");
+        reply.set_certify_info("certify");
+        reply.set_certify_info_signature("signature");
+        reply.set_certificate("certificate");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kGetKeyInfo);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  GetKeyInfoReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ(KEY_TYPE_ECC, reply.key_type());
+  EXPECT_EQ(KEY_USAGE_SIGN, reply.key_usage());
+  EXPECT_EQ("public_key", reply.public_key());
+  EXPECT_EQ("certify", reply.certify_info());
+  EXPECT_EQ("signature", reply.certify_info_signature());
+  EXPECT_EQ("certificate", reply.certificate());
+}
+
+TEST_F(DBusServiceTest, GetEndorsementInfo) {
+  GetEndorsementInfoRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  EXPECT_CALL(mock_service_, GetEndorsementInfo(_, _))
+      .WillOnce(Invoke([](
+          const GetEndorsementInfoRequest& request,
+          const AttestationInterface::GetEndorsementInfoCallback& callback) {
+        EXPECT_EQ(KEY_TYPE_ECC, request.key_type());
+        GetEndorsementInfoReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_ek_public_key("public_key");
+        reply.set_ek_certificate("certificate");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call =
+      CreateMethodCall(kGetEndorsementInfo);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  GetEndorsementInfoReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("public_key", reply.ek_public_key());
+  EXPECT_EQ("certificate", reply.ek_certificate());
+}
+
+TEST_F(DBusServiceTest, GetAttestationKeyInfo) {
+  GetAttestationKeyInfoRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  EXPECT_CALL(mock_service_, GetAttestationKeyInfo(_, _))
+      .WillOnce(Invoke([](
+          const GetAttestationKeyInfoRequest& request,
+          const AttestationInterface::GetAttestationKeyInfoCallback& callback) {
+        EXPECT_EQ(KEY_TYPE_ECC, request.key_type());
+        GetAttestationKeyInfoReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_public_key("public_key");
+        reply.set_public_key_tpm_format("public_key_tpm_format");
+        reply.set_certificate("certificate");
+        reply.mutable_pcr0_quote()->set_quote("pcr0");
+        reply.mutable_pcr1_quote()->set_quote("pcr1");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call =
+      CreateMethodCall(kGetAttestationKeyInfo);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  GetAttestationKeyInfoReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("public_key", reply.public_key());
+  EXPECT_EQ("public_key_tpm_format", reply.public_key_tpm_format());
+  EXPECT_EQ("certificate", reply.certificate());
+  EXPECT_EQ("pcr0", reply.pcr0_quote().quote());
+  EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
+}
+
+TEST_F(DBusServiceTest, ActivateAttestationKey) {
+  ActivateAttestationKeyRequest request;
+  request.set_key_type(KEY_TYPE_ECC);
+  request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
+  request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
+  request.set_save_certificate(true);
+  EXPECT_CALL(mock_service_, ActivateAttestationKey(_, _))
+      .WillOnce(Invoke([](
+          const ActivateAttestationKeyRequest& request,
+          const AttestationInterface::ActivateAttestationKeyCallback&
+              callback) {
+        EXPECT_EQ(KEY_TYPE_ECC, request.key_type());
+        EXPECT_EQ("encrypted1",
+                  request.encrypted_certificate().asym_ca_contents());
+        EXPECT_EQ("encrypted2",
+                  request.encrypted_certificate().sym_ca_attestation());
+        EXPECT_TRUE(request.save_certificate());
+        ActivateAttestationKeyReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_certificate("certificate");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call =
+      CreateMethodCall(kActivateAttestationKey);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  ActivateAttestationKeyReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("certificate", reply.certificate());
+}
+
+TEST_F(DBusServiceTest, CreateCertifiableKey) {
+  CreateCertifiableKeyRequest request;
+  request.set_key_label("label");
+  request.set_key_type(KEY_TYPE_ECC);
+  request.set_key_usage(KEY_USAGE_SIGN);
+  request.set_username("user");
+  EXPECT_CALL(mock_service_, CreateCertifiableKey(_, _))
+      .WillOnce(Invoke([](
+          const CreateCertifiableKeyRequest& request,
+          const AttestationInterface::CreateCertifiableKeyCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ(KEY_TYPE_ECC, request.key_type());
+        EXPECT_EQ(KEY_USAGE_SIGN, request.key_usage());
+        EXPECT_EQ("user", request.username());
+        CreateCertifiableKeyReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_public_key("public_key");
+        reply.set_certify_info("certify_info");
+        reply.set_certify_info_signature("signature");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call =
+      CreateMethodCall(kCreateCertifiableKey);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  CreateCertifiableKeyReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("public_key", reply.public_key());
+  EXPECT_EQ("certify_info", reply.certify_info());
+  EXPECT_EQ("signature", reply.certify_info_signature());
+}
+
+TEST_F(DBusServiceTest, Decrypt) {
+  DecryptRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_encrypted_data("data");
+  EXPECT_CALL(mock_service_, Decrypt(_, _))
+      .WillOnce(Invoke([](
+          const DecryptRequest& request,
+          const AttestationInterface::DecryptCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ("user", request.username());
+        EXPECT_EQ("data", request.encrypted_data());
+        DecryptReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_decrypted_data("data");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kDecrypt);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  DecryptReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("data", reply.decrypted_data());
+}
+
+TEST_F(DBusServiceTest, Sign) {
+  SignRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  request.set_data_to_sign("data");
+  EXPECT_CALL(mock_service_, Sign(_, _))
+      .WillOnce(Invoke([](
+          const SignRequest& request,
+          const AttestationInterface::SignCallback& callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ("user", request.username());
+        EXPECT_EQ("data", request.data_to_sign());
+        SignReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        reply.set_signature("signature");
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(kSign);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  SignReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+  EXPECT_EQ("signature", reply.signature());
+}
+
+TEST_F(DBusServiceTest, RegisterKeyWithChapsToken) {
+  RegisterKeyWithChapsTokenRequest request;
+  request.set_key_label("label");
+  request.set_username("user");
+  EXPECT_CALL(mock_service_, RegisterKeyWithChapsToken(_, _))
+      .WillOnce(Invoke([](
+          const RegisterKeyWithChapsTokenRequest& request,
+          const AttestationInterface::RegisterKeyWithChapsTokenCallback&
+              callback) {
+        EXPECT_EQ("label", request.key_label());
+        EXPECT_EQ("user", request.username());
+        RegisterKeyWithChapsTokenReply reply;
+        reply.set_status(STATUS_SUCCESS);
+        callback.Run(reply);
+      }));
+  std::unique_ptr<dbus::MethodCall> call =
+      CreateMethodCall(kRegisterKeyWithChapsToken);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  RegisterKeyWithChapsTokenReply reply;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply));
+  EXPECT_EQ(STATUS_SUCCESS, reply.status());
+}
+
+
+}  // namespace attestation
diff --git a/server/key_store.h b/server/key_store.h
new file mode 100644
index 0000000..3ae6a87
--- /dev/null
+++ b/server/key_store.h
@@ -0,0 +1,70 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_KEY_STORE_H_
+#define ATTESTATION_SERVER_KEY_STORE_H_
+
+#include <string>
+
+#include <base/macros.h>
+
+#include "attestation/common/common.pb.h"
+
+namespace attestation {
+
+// A mock-able key storage interface.
+class KeyStore {
+ public:
+  KeyStore() {}
+  virtual ~KeyStore() {}
+
+  // Reads key data from the store for the key identified by |key_label| and by
+  // |username|. On success true is returned and |key_data| is populated.
+  virtual bool Read(const std::string& username,
+                    const std::string& key_label,
+                    std::string* key_data) = 0;
+
+  // Writes key data to the store for the key identified by |key_label| and by
+  // |username|. If such a key already exists the existing data will be
+  // overwritten.
+  virtual bool Write(const std::string& username,
+                     const std::string& key_label,
+                     const std::string& key_data) = 0;
+
+  // Deletes key data for the key identified by |key_label| and by |username|.
+  // Returns false if key data exists but could not be deleted.
+  virtual bool Delete(const std::string& username,
+                      const std::string& key_label) = 0;
+
+  // Deletes key data for all keys identified by |key_prefix| and by |username|
+  // Returns false if key data exists but could not be deleted.
+  virtual bool DeleteByPrefix(const std::string& username,
+                              const std::string& key_prefix) = 0;
+
+  // Registers a key to be associated with |username|.
+  // The provided |label| will be associated with all registered objects.
+  // |private_key_blob| holds the private key in some opaque format and
+  // |public_key_der| holds the public key in PKCS #1 RSAPublicKey format.
+  // If a non-empty |certificate| is provided it will be registered along with
+  // the key. Returns true on success.
+  virtual bool Register(const std::string& username,
+                        const std::string& label,
+                        KeyType key_type,
+                        KeyUsage key_usage,
+                        const std::string& private_key_blob,
+                        const std::string& public_key_der,
+                        const std::string& certificate) = 0;
+
+  // Registers a |certificate| that is not associated to a registered key. The
+  // certificate will be associated with |username|.
+  virtual bool RegisterCertificate(const std::string& username,
+                                   const std::string& certificate) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KeyStore);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_KEY_STORE_H_
diff --git a/server/main.cc b/server/main.cc
new file mode 100644
index 0000000..73ba426
--- /dev/null
+++ b/server/main.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 The Chromium OS 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 <sysexits.h>
+
+#include <memory>
+#include <string>
+
+#include <base/command_line.h>
+#include <chromeos/daemons/dbus_daemon.h>
+#include <chromeos/dbus/async_event_sequencer.h>
+#include <chromeos/minijail/minijail.h>
+#include <chromeos/syslog_logging.h>
+#include <chromeos/userdb_utils.h>
+
+#include "attestation/common/dbus_interface.h"
+#include "attestation/server/attestation_service.h"
+#include "attestation/server/dbus_service.h"
+
+#include <chromeos/libminijail.h>
+
+namespace {
+
+const uid_t kRootUID = 0;
+const char kAttestationUser[] = "attestation";
+const char kAttestationGroup[] = "attestation";
+const char kAttestationSeccompPath[] =
+    "/usr/share/policy/attestationd-seccomp.policy";
+
+void InitMinijailSandbox() {
+  uid_t attestation_uid;
+  gid_t attestation_gid;
+  CHECK(chromeos::userdb::GetUserInfo(kAttestationUser,
+                                      &attestation_uid,
+                                      &attestation_gid))
+      << "Error getting attestation uid and gid.";
+  CHECK_EQ(getuid(), kRootUID) << "AttestationDaemon not initialized as root.";
+  chromeos::Minijail* minijail = chromeos::Minijail::GetInstance();
+  struct minijail* jail = minijail->New();
+
+  minijail->DropRoot(jail, kAttestationUser, kAttestationGroup);
+  minijail->UseSeccompFilter(jail, kAttestationSeccompPath);
+  minijail->Enter(jail);
+  minijail->Destroy(jail);
+  CHECK_EQ(getuid(), attestation_uid)
+      << "AttestationDaemon was not able to drop to attestation user.";
+  CHECK_EQ(getgid(), attestation_gid)
+      << "AttestationDaemon was not able to drop to attestation group.";
+}
+
+}  // namespace
+
+using chromeos::dbus_utils::AsyncEventSequencer;
+
+class AttestationDaemon : public chromeos::DBusServiceDaemon {
+ public:
+  AttestationDaemon()
+      : chromeos::DBusServiceDaemon(attestation::kAttestationServiceName) {
+    attestation_service_.reset(new attestation::AttestationService);
+    // Move initialize call down to OnInit
+    CHECK(attestation_service_->Initialize());
+  }
+
+ protected:
+  int OnInit() override {
+    int result = chromeos::DBusServiceDaemon::OnInit();
+    if (result != EX_OK) {
+      LOG(ERROR) << "Error starting attestation dbus daemon.";
+      return result;
+    }
+    return EX_OK;
+  }
+
+  void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
+    dbus_service_.reset(new attestation::DBusService(
+        bus_,
+        attestation_service_.get()));
+    dbus_service_->Register(sequencer->GetHandler("Register() failed.", true));
+  }
+
+ private:
+  std::unique_ptr<attestation::AttestationInterface> attestation_service_;
+  std::unique_ptr<attestation::DBusService> dbus_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(AttestationDaemon);
+};
+
+int main(int argc, char* argv[]) {
+  base::CommandLine::Init(argc, argv);
+  chromeos::InitLog(chromeos::kLogToSyslog | chromeos::kLogToStderr);
+  AttestationDaemon daemon;
+  LOG(INFO) << "Attestation Daemon Started.";
+  InitMinijailSandbox();
+  return daemon.Run();
+}
diff --git a/server/mock_database.cc b/server/mock_database.cc
new file mode 100644
index 0000000..bfe5bce
--- /dev/null
+++ b/server/mock_database.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/mock_database.h"
+
+using testing::Return;
+using testing::ReturnRef;
+
+namespace attestation {
+
+MockDatabase::MockDatabase() {
+  ON_CALL(*this, GetProtobuf()).WillByDefault(ReturnRef(fake_));
+  ON_CALL(*this, GetMutableProtobuf()).WillByDefault(Return(&fake_));
+  ON_CALL(*this, SaveChanges()).WillByDefault(Return(true));
+  ON_CALL(*this, Reload()).WillByDefault(Return(true));
+}
+
+MockDatabase::~MockDatabase() {}
+
+}  // namespace attestation
diff --git a/server/mock_database.h b/server/mock_database.h
new file mode 100644
index 0000000..daf7ff4
--- /dev/null
+++ b/server/mock_database.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_MOCK_DATABASE_H_
+#define ATTESTATION_SERVER_MOCK_DATABASE_H_
+
+#include "attestation/server/database.h"
+
+#include <gmock/gmock.h>
+
+namespace attestation {
+
+class MockDatabase : public Database {
+ public:
+  MockDatabase();
+  ~MockDatabase() override;
+
+  MOCK_CONST_METHOD0(GetProtobuf, const AttestationDatabase&());
+  MOCK_METHOD0(GetMutableProtobuf, AttestationDatabase*());
+  MOCK_METHOD0(SaveChanges, bool());
+  MOCK_METHOD0(Reload, bool());
+
+ private:
+  AttestationDatabase fake_;
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_MOCK_DATABASE_H_
diff --git a/server/mock_key_store.cc b/server/mock_key_store.cc
new file mode 100644
index 0000000..792ebdd
--- /dev/null
+++ b/server/mock_key_store.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/mock_key_store.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace attestation {
+
+MockKeyStore::MockKeyStore() {
+  ON_CALL(*this, Read(_, _, _)).WillByDefault(Return(true));
+  ON_CALL(*this, Write(_, _, _)).WillByDefault(Return(true));
+  ON_CALL(*this, Delete(_, _)).WillByDefault(Return(true));
+  ON_CALL(*this, DeleteByPrefix(_, _)).WillByDefault(Return(true));
+  ON_CALL(*this, Register(_, _, _, _, _, _, _)).WillByDefault(Return(true));
+  ON_CALL(*this, RegisterCertificate(_, _)).WillByDefault(Return(true));
+}
+
+MockKeyStore::~MockKeyStore() {}
+
+}  // namespace attestation
diff --git a/server/mock_key_store.h b/server/mock_key_store.h
new file mode 100644
index 0000000..505fb76
--- /dev/null
+++ b/server/mock_key_store.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_MOCK_KEY_STORE_H_
+#define ATTESTATION_SERVER_MOCK_KEY_STORE_H_
+
+#include "attestation/server/key_store.h"
+
+#include <string>
+
+#include <base/macros.h>
+#include <gmock/gmock.h>
+
+namespace attestation {
+
+class MockKeyStore : public KeyStore {
+ public:
+  MockKeyStore();
+  virtual ~MockKeyStore();
+
+  MOCK_METHOD3(Read, bool(const std::string& username,
+                          const std::string& name,
+                          std::string* key_data));
+  MOCK_METHOD3(Write, bool(const std::string& username,
+                           const std::string& name,
+                           const std::string& key_data));
+  MOCK_METHOD2(Delete, bool(const std::string& username,
+                            const std::string& name));
+  MOCK_METHOD2(DeleteByPrefix, bool(const std::string& username,
+                                    const std::string& key_prefix));
+  MOCK_METHOD7(Register, bool(const std::string& username,
+                              const std::string& label,
+                              KeyType key_type,
+                              KeyUsage key_usage,
+                              const std::string& private_key_blob,
+                              const std::string& public_key_der,
+                              const std::string& certificate));
+  MOCK_METHOD2(RegisterCertificate, bool(const std::string& username,
+                                         const std::string& certificate));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockKeyStore);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_MOCK_KEY_STORE_H_
diff --git a/server/org.chromium.Attestation.conf b/server/org.chromium.Attestation.conf
new file mode 100644
index 0000000..2adae8e
--- /dev/null
+++ b/server/org.chromium.Attestation.conf
@@ -0,0 +1,15 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <policy user="attestation">
+    <allow own="org.chromium.Attestation" />
+    <allow send_destination="org.chromium.Attestation" />
+  </policy>
+  <policy context="default">
+    <allow send_destination="org.chromium.Attestation" />
+    <!-- introspection denied -->
+    <deny send_destination="org.chromium.Attestation"
+          send_interface="org.freedesktop.DBus.Introspectable" />
+  </policy>
+</busconfig>
diff --git a/server/pkcs11_key_store.cc b/server/pkcs11_key_store.cc
new file mode 100644
index 0000000..58a6cbd
--- /dev/null
+++ b/server/pkcs11_key_store.cc
@@ -0,0 +1,673 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/pkcs11_key_store.h"
+
+#include <memory>
+#include <string>
+
+#include <base/bind.h>
+#include <base/callback.h>
+#include <base/files/file_path.h>
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <base/strings/string_util.h>
+#include <chaps/isolate.h>
+#include <chaps/pkcs11/cryptoki.h>
+#include <chaps/token_manager_client.h>
+#include <chromeos/cryptohome.h>
+#include <crypto/scoped_openssl_types.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/x509.h>
+
+namespace {
+
+std::string Sha1(const std::string& input) {
+  unsigned char output[SHA_DIGEST_LENGTH];
+  SHA1(reinterpret_cast<const unsigned char*>(input.data()), input.size(),
+       output);
+  return std::string(reinterpret_cast<char*>(output), SHA_DIGEST_LENGTH);
+}
+
+}  // namespace
+
+namespace attestation {
+
+typedef crypto::ScopedOpenSSL<X509, X509_free> ScopedX509;
+
+// An arbitrary application ID to identify PKCS #11 objects.
+const char kApplicationID[] = "CrOS_d5bbc079d2497110feadfc97c40d718ae46f4658";
+
+// A helper class to scope a PKCS #11 session.
+class ScopedSession {
+ public:
+  explicit ScopedSession(CK_SLOT_ID slot) : handle_(CK_INVALID_HANDLE) {
+    CK_RV rv = C_Initialize(nullptr);
+    if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+      // This may be normal in a test environment.
+      LOG(INFO) << "PKCS #11 is not available.";
+      return;
+    }
+    CK_FLAGS flags = CKF_RW_SESSION | CKF_SERIAL_SESSION;
+    if (C_OpenSession(slot, flags, nullptr, nullptr, &handle_) != CKR_OK) {
+      LOG(ERROR) << "Failed to open PKCS #11 session.";
+      return;
+    }
+  }
+
+  ~ScopedSession() {
+    if (IsValid() && (C_CloseSession(handle_) != CKR_OK)) {
+      LOG(WARNING) << "Failed to close PKCS #11 session.";
+      handle_ = CK_INVALID_HANDLE;
+    }
+  }
+
+  CK_SESSION_HANDLE handle() const {
+    return handle_;
+  }
+
+  bool IsValid() const {
+    return (handle_ != CK_INVALID_HANDLE);
+  }
+
+ private:
+  CK_SESSION_HANDLE handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSession);
+};
+
+Pkcs11KeyStore::Pkcs11KeyStore(chaps::TokenManagerClient* token_manager)
+    : token_manager_(token_manager) {}
+
+Pkcs11KeyStore::~Pkcs11KeyStore() {}
+
+bool Pkcs11KeyStore::Read(const std::string& username,
+                          const std::string& key_name,
+                          std::string* key_data) {
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+  CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
+  if (key_handle == CK_INVALID_HANDLE) {
+    LOG(WARNING) << "Pkcs11KeyStore: Key does not exist: " << key_name;
+    return false;
+  }
+  // First get the attribute with a NULL buffer which will give us the length.
+  CK_ATTRIBUTE attribute = {CKA_VALUE, nullptr, 0};
+  if (C_GetAttributeValue(session.handle(),
+                          key_handle,
+                          &attribute, 1) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
+    return false;
+  }
+  key_data->resize(attribute.ulValueLen);
+  attribute.pValue = string_as_array(key_data);
+  if (C_GetAttributeValue(session.handle(),
+                          key_handle,
+                          &attribute, 1) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to read key data: " << key_name;
+    return false;
+  }
+  key_data->resize(attribute.ulValueLen);
+  return true;
+}
+
+bool Pkcs11KeyStore::Write(const std::string& username,
+                           const std::string& key_name,
+                           const std::string& key_data) {
+  // Delete any existing key with the same name.
+  if (!Delete(username, key_name)) {
+    return false;
+  }
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+  std::string mutable_key_name(key_name);
+  std::string mutable_key_data(key_data);
+  std::string mutable_application_id(kApplicationID);
+  // Create a new data object for the key.
+  CK_OBJECT_CLASS object_class = CKO_DATA;
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  CK_ATTRIBUTE attributes[] = {
+    {CKA_CLASS, &object_class, sizeof(object_class)},
+    {
+      CKA_LABEL,
+      string_as_array(&mutable_key_name),
+      mutable_key_name.size()
+    },
+    {
+      CKA_VALUE,
+      string_as_array(&mutable_key_data),
+      mutable_key_data.size()
+    },
+    {
+      CKA_APPLICATION,
+      string_as_array(&mutable_application_id),
+      mutable_application_id.size()
+    },
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &true_value, sizeof(true_value)},
+    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
+  };
+  CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
+  if (C_CreateObject(session.handle(),
+                     attributes,
+                     arraysize(attributes),
+                     &key_handle) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to write key data: " << key_name;
+    return false;
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::Delete(const std::string& username,
+                            const std::string& key_name) {
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+  CK_OBJECT_HANDLE key_handle = FindObject(session.handle(), key_name);
+  if (key_handle != CK_INVALID_HANDLE) {
+    if (C_DestroyObject(session.handle(), key_handle) != CKR_OK) {
+      LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::DeleteByPrefix(const std::string& username,
+                                    const std::string& key_prefix) {
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+  EnumObjectsCallback callback = base::Bind(
+      &Pkcs11KeyStore::DeleteIfMatchesPrefix,
+      base::Unretained(this),
+      session.handle(),
+      key_prefix);
+  if (!EnumObjects(session.handle(), callback)) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to delete key data.";
+    return false;
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::Register(const std::string& username,
+                              const std::string& label,
+                              KeyType key_type,
+                              KeyUsage key_usage,
+                              const std::string& private_key_blob,
+                              const std::string& public_key_der,
+                              const std::string& certificate) {
+  const CK_ATTRIBUTE_TYPE kKeyBlobAttribute = CKA_VENDOR_DEFINED + 1;
+
+  if (key_type != KEY_TYPE_RSA) {
+    LOG(ERROR) << "Pkcs11KeyStore: Only RSA supported.";
+    return false;
+  }
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+
+  // Extract the modulus from the public key.
+  const unsigned char* asn1_ptr = reinterpret_cast<const unsigned char*>(
+      public_key_der.data());
+  crypto::ScopedRSA public_key(d2i_RSAPublicKey(nullptr,
+                                                &asn1_ptr,
+                                                public_key_der.size()));
+  if (!public_key.get()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to decode public key.";
+    return false;
+  }
+  std::string modulus(BN_num_bytes(public_key.get()->n), 0);
+  int length = BN_bn2bin(public_key.get()->n, reinterpret_cast<unsigned char*>(
+      string_as_array(&modulus)));
+  if (length <= 0) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to extract public key modulus.";
+    return false;
+  }
+  modulus.resize(length);
+
+  // Construct a PKCS #11 template for the public key object.
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  CK_KEY_TYPE p11_key_type = CKK_RSA;
+  CK_OBJECT_CLASS public_key_class = CKO_PUBLIC_KEY;
+  std::string id = Sha1(modulus);
+  std::string mutable_label(label);
+  CK_ULONG modulus_bits = modulus.size() * 8;
+  CK_BBOOL sign_usage = (key_usage == KEY_USAGE_SIGN);
+  CK_BBOOL decrypt_usage = (key_usage == KEY_USAGE_DECRYPT);
+  unsigned char public_exponent[] = {1, 0, 1};
+  CK_ATTRIBUTE public_key_attributes[] = {
+    {CKA_CLASS, &public_key_class, sizeof(public_key_class)},
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_DERIVE, &false_value, sizeof(false_value)},
+    {CKA_WRAP, &false_value, sizeof(false_value)},
+    {CKA_VERIFY, &sign_usage, sizeof(sign_usage)},
+    {CKA_VERIFY_RECOVER, &false_value, sizeof(false_value)},
+    {CKA_ENCRYPT, &decrypt_usage, sizeof(decrypt_usage)},
+    {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
+    {CKA_ID, string_as_array(&id), id.size()},
+    {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
+    {CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits)},
+    {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
+    {CKA_MODULUS, string_as_array(&modulus), modulus.size()}
+  };
+
+  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
+  if (C_CreateObject(session.handle(),
+                     public_key_attributes,
+                     arraysize(public_key_attributes),
+                     &object_handle) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to create public key object.";
+    return false;
+  }
+
+  // Construct a PKCS #11 template for the private key object.
+  std::string mutable_private_key_blob(private_key_blob);
+  CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY;
+  CK_ATTRIBUTE private_key_attributes[] = {
+    {CKA_CLASS, &private_key_class, sizeof(private_key_class)},
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &true_value, sizeof(true_value)},
+    {CKA_SENSITIVE, &true_value, sizeof(true_value)},
+    {CKA_EXTRACTABLE, &false_value, sizeof(false_value)},
+    {CKA_DERIVE, &false_value, sizeof(false_value)},
+    {CKA_UNWRAP, &false_value, sizeof(false_value)},
+    {CKA_SIGN, &sign_usage, sizeof(sign_usage)},
+    {CKA_SIGN_RECOVER, &false_value, sizeof(false_value)},
+    {CKA_DECRYPT, &decrypt_usage, sizeof(decrypt_usage)},
+    {CKA_KEY_TYPE, &p11_key_type, sizeof(p11_key_type)},
+    {CKA_ID, string_as_array(&id), id.size()},
+    {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
+    {CKA_PUBLIC_EXPONENT, public_exponent, arraysize(public_exponent)},
+    {CKA_MODULUS, string_as_array(&modulus), modulus.size()},
+    {
+      kKeyBlobAttribute,
+      string_as_array(&mutable_private_key_blob),
+      mutable_private_key_blob.size()
+    }
+  };
+
+  if (C_CreateObject(session.handle(),
+                     private_key_attributes,
+                     arraysize(private_key_attributes),
+                     &object_handle) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to create private key object.";
+    return false;
+  }
+
+  if (!certificate.empty()) {
+    std::string subject;
+    std::string issuer;
+    std::string serial_number;
+    if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
+      LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
+    }
+    // Construct a PKCS #11 template for a certificate object.
+    std::string mutable_certificate = certificate;
+    CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
+    CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
+    CK_ATTRIBUTE certificate_attributes[] = {
+      {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
+      {CKA_TOKEN, &true_value, sizeof(true_value)},
+      {CKA_PRIVATE, &false_value, sizeof(false_value)},
+      {CKA_ID, string_as_array(&id), id.size()},
+      {CKA_LABEL, string_as_array(&mutable_label), mutable_label.size()},
+      {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
+      {CKA_SUBJECT, string_as_array(&subject), subject.size()},
+      {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
+      {
+        CKA_SERIAL_NUMBER,
+        string_as_array(&serial_number),
+        serial_number.size()
+      },
+      {
+        CKA_VALUE,
+        string_as_array(&mutable_certificate),
+        mutable_certificate.size()
+      }
+    };
+
+    if (C_CreateObject(session.handle(),
+                       certificate_attributes,
+                       arraysize(certificate_attributes),
+                       &object_handle) != CKR_OK) {
+      LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
+      return false;
+    }
+  }
+
+  // Close all sessions in an attempt to trigger other modules to find the new
+  // objects.
+  C_CloseAllSessions(slot);
+
+  return true;
+}
+
+bool Pkcs11KeyStore::RegisterCertificate(const std::string& username,
+                                         const std::string& certificate) {
+  CK_SLOT_ID slot;
+  if (!GetUserSlot(username, &slot)) {
+    LOG(ERROR) << "Pkcs11KeyStore: No token for user.";
+    return false;
+  }
+  ScopedSession session(slot);
+  if (!session.IsValid()) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to open token session.";
+    return false;
+  }
+
+  if (DoesCertificateExist(session.handle(), certificate)) {
+    LOG(INFO) << "Pkcs11KeyStore: Certificate already exists.";
+    return true;
+  }
+  std::string subject;
+  std::string issuer;
+  std::string serial_number;
+  if (!GetCertificateFields(certificate, &subject, &issuer, &serial_number)) {
+    LOG(WARNING) << "Pkcs11KeyStore: Failed to find certificate fields.";
+  }
+  // Construct a PKCS #11 template for a certificate object.
+  std::string mutable_certificate = certificate;
+  CK_OBJECT_CLASS certificate_class = CKO_CERTIFICATE;
+  CK_CERTIFICATE_TYPE certificate_type = CKC_X_509;
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  CK_ATTRIBUTE certificate_attributes[] = {
+    {CKA_CLASS, &certificate_class, sizeof(certificate_class)},
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &false_value, sizeof(false_value)},
+    {CKA_CERTIFICATE_TYPE, &certificate_type, sizeof(certificate_type)},
+    {CKA_SUBJECT, string_as_array(&subject), subject.size()},
+    {CKA_ISSUER, string_as_array(&issuer), issuer.size()},
+    {CKA_SERIAL_NUMBER, string_as_array(&serial_number), serial_number.size()},
+    {
+      CKA_VALUE,
+      string_as_array(&mutable_certificate),
+      mutable_certificate.size()
+    }
+  };
+  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
+  if (C_CreateObject(session.handle(),
+                     certificate_attributes,
+                     arraysize(certificate_attributes),
+                     &object_handle) != CKR_OK) {
+    LOG(ERROR) << "Pkcs11KeyStore: Failed to create certificate object.";
+    return false;
+  }
+  return true;
+}
+
+CK_OBJECT_HANDLE Pkcs11KeyStore::FindObject(CK_SESSION_HANDLE session_handle,
+                                            const std::string& key_name) {
+  // Assemble a search template.
+  std::string mutable_key_name(key_name);
+  std::string mutable_application_id(kApplicationID);
+  CK_OBJECT_CLASS object_class = CKO_DATA;
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  CK_ATTRIBUTE attributes[] = {
+    {CKA_CLASS, &object_class, sizeof(object_class)},
+    {
+      CKA_LABEL,
+      string_as_array(&mutable_key_name),
+      mutable_key_name.size()
+    },
+    {
+      CKA_APPLICATION,
+      string_as_array(&mutable_application_id),
+      mutable_application_id.size()
+    },
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &true_value, sizeof(true_value)},
+    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
+  };
+  CK_OBJECT_HANDLE key_handle = CK_INVALID_HANDLE;
+  CK_ULONG count = 0;
+  if ((C_FindObjectsInit(session_handle,
+                         attributes,
+                         arraysize(attributes)) != CKR_OK) ||
+      (C_FindObjects(session_handle, &key_handle, 1, &count) != CKR_OK) ||
+      (C_FindObjectsFinal(session_handle) != CKR_OK)) {
+    LOG(ERROR) << "Key search failed: " << key_name;
+    return CK_INVALID_HANDLE;
+  }
+  if (count == 1)
+    return key_handle;
+  return CK_INVALID_HANDLE;
+}
+
+bool Pkcs11KeyStore::GetUserSlot(const std::string& username,
+                                 CK_SLOT_ID_PTR slot) {
+  const char kChapsDaemonName[] = "chaps";
+  const char kChapsSystemToken[] = "/var/lib/chaps";
+  base::FilePath token_path = username.empty() ?
+      base::FilePath(kChapsSystemToken) :
+      chromeos::cryptohome::home::GetDaemonPath(username, kChapsDaemonName);
+  CK_RV rv;
+  rv = C_Initialize(nullptr);
+  if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+    LOG(WARNING) << __func__ << ": C_Initialize failed.";
+    return false;
+  }
+  CK_ULONG num_slots = 0;
+  rv = C_GetSlotList(CK_TRUE, nullptr, &num_slots);
+  if (rv != CKR_OK) {
+    LOG(WARNING) << __func__ << ": C_GetSlotList(nullptr) failed.";
+    return false;
+  }
+  std::unique_ptr<CK_SLOT_ID[]> slot_list(new CK_SLOT_ID[num_slots]);
+  rv = C_GetSlotList(CK_TRUE, slot_list.get(), &num_slots);
+  if (rv != CKR_OK) {
+    LOG(WARNING) << __func__ << ": C_GetSlotList failed.";
+    return false;
+  }
+  // Look through all slots for |token_path|.
+  for (CK_ULONG i = 0; i < num_slots; ++i) {
+    base::FilePath slot_path;
+    if (token_manager_->GetTokenPath(
+        chaps::IsolateCredentialManager::GetDefaultIsolateCredential(),
+        slot_list[i],
+        &slot_path) && (token_path == slot_path)) {
+      *slot = slot_list[i];
+      return true;
+    }
+  }
+  LOG(WARNING) << __func__ << ": Path not found.";
+  return false;
+}
+
+bool Pkcs11KeyStore::EnumObjects(
+    CK_SESSION_HANDLE session_handle,
+    const Pkcs11KeyStore::EnumObjectsCallback& callback) {
+  std::string mutable_application_id(kApplicationID);
+  // Assemble a search template.
+  CK_OBJECT_CLASS object_class = CKO_DATA;
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  CK_ATTRIBUTE attributes[] = {
+    {CKA_CLASS, &object_class, sizeof(object_class)},
+    {
+      CKA_APPLICATION,
+      string_as_array(&mutable_application_id),
+      mutable_application_id.size()
+    },
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &true_value, sizeof(true_value)},
+    {CKA_MODIFIABLE, &false_value, sizeof(false_value)}
+  };
+  const CK_ULONG kMaxHandles = 100;  // Arbitrary.
+  CK_OBJECT_HANDLE handles[kMaxHandles];
+  CK_ULONG count = 0;
+  if ((C_FindObjectsInit(session_handle,
+                         attributes,
+                         arraysize(attributes)) != CKR_OK) ||
+      (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK)) {
+    LOG(ERROR) << "Key search failed.";
+    return false;
+  }
+  while (count > 0) {
+    for (CK_ULONG i = 0; i < count; ++i) {
+      std::string key_name;
+      if (!GetKeyName(session_handle, handles[i], &key_name)) {
+        LOG(WARNING) << "Found key object but failed to get name.";
+        continue;
+      }
+      if (!callback.Run(key_name, handles[i]))
+        return false;
+    }
+    if (C_FindObjects(session_handle, handles, kMaxHandles, &count) != CKR_OK) {
+      LOG(ERROR) << "Key search continuation failed.";
+      return false;
+    }
+  }
+  if (C_FindObjectsFinal(session_handle) != CKR_OK) {
+    LOG(WARNING) << "Failed to finalize key search.";
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::GetKeyName(CK_SESSION_HANDLE session_handle,
+                                CK_OBJECT_HANDLE object_handle,
+                                std::string* key_name) {
+  CK_ATTRIBUTE attribute = {CKA_LABEL, nullptr, 0};
+  if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
+      CKR_OK) {
+    LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) [length] failed.";
+    return false;
+  }
+  key_name->resize(attribute.ulValueLen);
+  attribute.pValue = string_as_array(key_name);
+  if (C_GetAttributeValue(session_handle, object_handle, &attribute, 1) !=
+      CKR_OK) {
+    LOG(ERROR) << "C_GetAttributeValue(CKA_LABEL) failed.";
+    return false;
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::DeleteIfMatchesPrefix(CK_SESSION_HANDLE session_handle,
+                                           const std::string& key_prefix,
+                                           const std::string& key_name,
+                                           CK_OBJECT_HANDLE object_handle) {
+  if (base::StartsWithASCII(key_name, key_prefix, true /*case_sensitive*/)) {
+    if (C_DestroyObject(session_handle, object_handle) != CKR_OK) {
+      LOG(ERROR) << "C_DestroyObject failed.";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool Pkcs11KeyStore::GetCertificateFields(const std::string& certificate,
+                                          std::string* subject,
+                                          std::string* issuer,
+                                          std::string* serial_number) {
+  const unsigned char* asn1_ptr = reinterpret_cast<const unsigned char*>(
+      certificate.data());
+  ScopedX509 x509(d2i_X509(nullptr, &asn1_ptr, certificate.size()));
+  if (!x509.get() || !x509->cert_info || !x509->cert_info->subject) {
+    LOG(WARNING) << "Pkcs11KeyStore: Failed to decode certificate.";
+    return false;
+  }
+  unsigned char* subject_buffer = nullptr;
+  int length = i2d_X509_NAME(x509->cert_info->subject, &subject_buffer);
+  crypto::ScopedOpenSSLBytes scoped_subject_buffer(subject_buffer);
+  if (length <= 0) {
+    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate subject.";
+    return false;
+  }
+  subject->assign(reinterpret_cast<char*>(subject_buffer), length);
+
+  unsigned char* issuer_buffer = nullptr;
+  length = i2d_X509_NAME(x509->cert_info->issuer, &issuer_buffer);
+  crypto::ScopedOpenSSLBytes scoped_issuer_buffer(issuer_buffer);
+  if (length <= 0) {
+    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate issuer.";
+    return false;
+  }
+  issuer->assign(reinterpret_cast<char*>(issuer_buffer), length);
+
+  unsigned char* serial_number_buffer = nullptr;
+  length = i2d_ASN1_INTEGER(x509->cert_info->serialNumber,
+                            &serial_number_buffer);
+  crypto::ScopedOpenSSLBytes scoped_serial_number_buffer(serial_number_buffer);
+  if (length <= 0) {
+    LOG(WARNING) << "Pkcs11KeyStore: Failed to encode certificate serial "
+                    "number.";
+    return false;
+  }
+  serial_number->assign(reinterpret_cast<char*>(serial_number_buffer), length);
+  return true;
+}
+
+bool Pkcs11KeyStore::DoesCertificateExist(
+    CK_SESSION_HANDLE session_handle,
+    const std::string& certificate) {
+  CK_OBJECT_CLASS object_class = CKO_CERTIFICATE;
+  CK_BBOOL true_value = CK_TRUE;
+  CK_BBOOL false_value = CK_FALSE;
+  std::string mutable_certificate = certificate;
+  CK_ATTRIBUTE attributes[] = {
+    {CKA_CLASS, &object_class, sizeof(object_class)},
+    {CKA_TOKEN, &true_value, sizeof(true_value)},
+    {CKA_PRIVATE, &false_value, sizeof(false_value)},
+    {
+      CKA_VALUE,
+      string_as_array(&mutable_certificate),
+      mutable_certificate.size()
+    }
+  };
+  CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
+  CK_ULONG count = 0;
+  if ((C_FindObjectsInit(session_handle,
+                         attributes,
+                         arraysize(attributes)) != CKR_OK) ||
+      (C_FindObjects(session_handle, &object_handle, 1, &count) != CKR_OK) ||
+      (C_FindObjectsFinal(session_handle) != CKR_OK)) {
+    return false;
+  }
+  return (count > 0);
+}
+
+}  // namespace attestation
diff --git a/server/pkcs11_key_store.h b/server/pkcs11_key_store.h
new file mode 100644
index 0000000..5fb02cd
--- /dev/null
+++ b/server/pkcs11_key_store.h
@@ -0,0 +1,111 @@
+// Copyright 2015 The Chromium OS 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 ATTESTATION_SERVER_PKCS11_KEY_STORE_H_
+#define ATTESTATION_SERVER_PKCS11_KEY_STORE_H_
+
+#include "attestation/server/key_store.h"
+
+#include <string>
+
+#include <base/callback_forward.h>
+#include <base/macros.h>
+#include <chaps/pkcs11/cryptoki.h>
+#include <chaps/token_manager_client.h>
+
+namespace attestation {
+
+// This class uses a PKCS #11 token as storage for key data.  The key data is
+// stored in data objects with the following attributes:
+// CKA_CLASS - CKO_DATA
+// CKA_LABEL - A key name.
+// CKA_VALUE - Binary key data (opaque to this class and the PKCS #11 token).
+// CKA_APPLICATION - A constant value associated with this class.
+// CKA_TOKEN - True
+// CKA_PRIVATE - True
+// CKA_MODIFIABLE - False
+// There is no barrier between the objects created by this class and any other
+// objects residing in the same token.  In practice, this means that any
+// component with access to the PKCS #11 token also has access to read or delete
+// key data.
+class Pkcs11KeyStore : public KeyStore {
+ public:
+  // Does not take ownership of pointers.
+  explicit Pkcs11KeyStore(chaps::TokenManagerClient* token_manager);
+  ~Pkcs11KeyStore() override;
+
+  // KeyStore interface.
+  bool Read(const std::string& username,
+            const std::string& key_name,
+            std::string* key_data) override;
+  bool Write(const std::string& username,
+             const std::string& key_name,
+             const std::string& key_data) override;
+  bool Delete(const std::string& username,
+              const std::string& key_name) override;
+  bool DeleteByPrefix(const std::string& username,
+                      const std::string& key_prefix) override;
+  bool Register(const std::string& username,
+                const std::string& label,
+                KeyType key_type,
+                KeyUsage key_usage,
+                const std::string& private_key_blob,
+                const std::string& public_key_der,
+                const std::string& certificate) override;
+  bool RegisterCertificate(const std::string& username,
+                           const std::string& certificate) override;
+
+ private:
+  using EnumObjectsCallback =
+      base::Callback<bool(const std::string& key_name,
+                          CK_OBJECT_HANDLE object_handle)>;
+
+  // Searches for a PKCS #11 object for a given key name.  If one exists, the
+  // object handle is returned, otherwise CK_INVALID_HANDLE is returned.
+  CK_OBJECT_HANDLE FindObject(CK_SESSION_HANDLE session_handle,
+                              const std::string& key_name);
+
+  // Gets a slot for the given |username| if |is_user_specific| or the system
+  // slot otherwise. Returns false if no appropriate slot is found.
+  bool GetUserSlot(const std::string& username,
+                   CK_SLOT_ID_PTR slot);
+
+  // Enumerates all PKCS #11 objects associated with keys.  The |callback| is
+  // called once for each object.
+  bool EnumObjects(CK_SESSION_HANDLE session_handle,
+                   const EnumObjectsCallback& callback);
+
+  // Looks up the key name for the given |object_handle| which is associated
+  // with a key.  Returns true on success.
+  bool GetKeyName(CK_SESSION_HANDLE session_handle,
+                  CK_OBJECT_HANDLE object_handle,
+                  std::string* key_name);
+
+  // An EnumObjectsCallback for use with DeleteByPrefix.  Destroys the key
+  // object identified by |object_handle| if |key_name| matches |key_prefix|.
+  // Returns true on success.
+  bool DeleteIfMatchesPrefix(CK_SESSION_HANDLE session_handle,
+                             const std::string& key_prefix,
+                             const std::string& key_name,
+                             CK_OBJECT_HANDLE object_handle);
+
+  // Extracts the |subject|, |issuer|, and |serial_number| information from an
+  // X.509 |certificate|. Returns false if the value cannot be determined.
+  bool GetCertificateFields(const std::string& certificate,
+                            std::string* subject,
+                            std::string* issuer,
+                            std::string* serial_number);
+
+  // Returns true iff the given certificate already exists in the token.
+  bool DoesCertificateExist(CK_SESSION_HANDLE session_handle,
+                            const std::string& certificate);
+
+  chaps::TokenManagerClient* token_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(Pkcs11KeyStore);
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_SERVER_PKCS11_KEY_STORE_H_
diff --git a/server/pkcs11_key_store_test.cc b/server/pkcs11_key_store_test.cc
new file mode 100644
index 0000000..f8c9058
--- /dev/null
+++ b/server/pkcs11_key_store_test.cc
@@ -0,0 +1,586 @@
+// Copyright 2015 The Chromium OS 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 "attestation/server/pkcs11_key_store.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <chaps/attributes.h>
+#include <chaps/chaps_proxy_mock.h>
+#include <chaps/token_manager_client_mock.h>
+#include <chromeos/cryptohome.h>
+#include <chromeos/map_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+
+namespace {
+
+const uint64_t kSession = 7;  // Arbitrary non-zero value.
+const char kDefaultUser[] = "test_user";
+
+const char kValidPublicKeyHex[] =
+    "3082010A0282010100"
+    "961037BC12D2A298BEBF06B2D5F8C9B64B832A2237F8CF27D5F96407A6041A4D"
+    "AD383CB5F88E625F412E8ACD5E9D69DF0F4FA81FCE7955829A38366CBBA5A2B1"
+    "CE3B48C14B59E9F094B51F0A39155874C8DE18A0C299EBF7A88114F806BE4F25"
+    "3C29A509B10E4B19E31675AFE3B2DA77077D94F43D8CE61C205781ED04D183B4"
+    "C349F61B1956C64B5398A3A98FAFF17D1B3D9120C832763EDFC8F4137F6EFBEF"
+    "46D8F6DE03BD00E49DEF987C10BDD5B6F8758B6A855C23C982DDA14D8F0F2B74"
+    "E6DEFA7EEE5A6FC717EB0FF103CB8049F693A2C8A5039EF1F5C025DC44BD8435"
+    "E8D8375DADE00E0C0F5C196E04B8483CC98B1D5B03DCD7E0048B2AB343FFC11F"
+    "0203"
+    "010001";
+
+const char kValidCertificateHex[] =
+    "3082040f308202f7a003020102020900bd0f8fd6bf496b67300d06092a864886"
+    "f70d01010b050030819d310b3009060355040613025553311330110603550408"
+    "0c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e20"
+    "5669657731133011060355040a0c0a4368726f6d69756d4f533111300f060355"
+    "040b0c08556e6974546573743117301506035504030c0e506b637331314b6579"
+    "53746f72653120301e06092a864886f70d010901161174657374406368726f6d"
+    "69756d2e6f7267301e170d3135303231383137303132345a170d313731313133"
+    "3137303132345a30819d310b3009060355040613025553311330110603550408"
+    "0c0a43616c69666f726e69613116301406035504070c0d4d6f756e7461696e20"
+    "5669657731133011060355040a0c0a4368726f6d69756d4f533111300f060355"
+    "040b0c08556e6974546573743117301506035504030c0e506b637331314b6579"
+    "53746f72653120301e06092a864886f70d010901161174657374406368726f6d"
+    "69756d2e6f726730820122300d06092a864886f70d01010105000382010f0030"
+    "82010a0282010100a8fb9e12b1e5298b9a24fabc3901d00c32057392c763836e"
+    "0b55cff8e67d39b9b9853920fd615688b3e13c03a10cb5668187819172d1d269"
+    "70f0ff8d4371ac581f6970a0e43a1d0d61a94741a771fe86aee45ab0ca059b1f"
+    "c067f7416f08544cc4d08ec884b6d4327bb3ec0dc0789639375bd159df0efd87"
+    "1cf4d605778c7a68c96b94cf0a6c29f9a23bc027e8250084eb2dfca817b20f57"
+    "a6fe09513f884389db7b90788aea70c6e1638f24e39553ac0f859e585965c425"
+    "9ed7b9680fde3e059f254d8c9494f6ab425ede80d63366dfcb7cc311f5bc6fb0"
+    "1c27d81f4c5112d04b7614c37ba19c014916816372c773e4e44564fac34565ad"
+    "ebf38fe56c1413170203010001a350304e301d0603551d0e04160414fe13c7db"
+    "459bd2881e9113198e1f072e16cea144301f0603551d23041830168014fe13c7"
+    "db459bd2881e9113198e1f072e16cea144300c0603551d13040530030101ff30"
+    "0d06092a864886f70d01010b05000382010100a163d636ac64bd6f67eca53708"
+    "5f92abc993a40fd0c0222a56b262c29f88057a3edf9abac024756ad85d7453d8"
+    "4782e0be65d176aecfb0fbfc88ca567d17124fa190cb5ce832264360dd6daee1"
+    "e121428de28dda0b8ba117a1be3cf438efd060a3b5fc812e7eba70cec12cb609"
+    "738fc7d0912546c42b5aaadb142adce2167c7f30cd9e0049687d384334335aff"
+    "72aebd1745a0aac4be816365969347f064f36f7fdec69f970f28b87061650470"
+    "c63be8475bb23d0485985fb77c7cdd9d9fe008211a9ddd0fe68efb0b47cf629c"
+    "941d31e3c2f88e670e7e4ef1129febad000e6a16222779fbfe34641e5243ca38"
+    "74e2ad06f9585a00bec014744d3175ecc4808d";
+
+std::string HexDecode(const std::string hex) {
+  std::vector<uint8> output;
+  CHECK(base::HexStringToBytes(hex, &output));
+  return std::string(reinterpret_cast<char*>(output.data()), output.size());
+}
+
+class ScopedFakeSalt {
+ public:
+  ScopedFakeSalt() : salt_(128, 0) {
+    chromeos::cryptohome::home::SetSystemSalt(&salt_);
+  }
+  ~ScopedFakeSalt() {
+    chromeos::cryptohome::home::SetSystemSalt(nullptr);
+  }
+
+ private:
+  std::string salt_;
+};
+
+class ScopedDisableVerboseLogging {
+ public:
+  ScopedDisableVerboseLogging()
+      : original_severity_(logging::GetMinLogLevel()) {
+    logging::SetMinLogLevel(logging::LOG_INFO);
+  }
+  ~ScopedDisableVerboseLogging() {
+    logging::SetMinLogLevel(original_severity_);
+  }
+
+ private:
+  logging::LogSeverity original_severity_;
+};
+
+}  // namespace
+
+namespace attestation {
+
+typedef chaps::ChapsProxyMock Pkcs11Mock;
+
+// Implements a fake PKCS #11 object store.  Labeled data blobs can be stored
+// and later retrieved.  The mocked interface is ChapsInterface so these
+// tests must be linked with the Chaps PKCS #11 library.  The mock class itself
+// is part of the Chaps package; it is reused here to avoid duplication (see
+// chaps_proxy_mock.h).
+class KeyStoreTest : public testing::Test {
+ public:
+  KeyStoreTest()
+      : pkcs11_(false),  // Do not pre-initialize the mock PKCS #11 library.
+                         // This just controls whether the first call to
+                         // C_Initialize returns 'already initialized'.
+        next_handle_(1) {}
+  ~KeyStoreTest() override = default;
+
+  void SetUp() override {
+    std::vector<uint64_t> slot_list = {0, 1};
+    ON_CALL(pkcs11_, GetSlotList(_, _, _))
+        .WillByDefault(DoAll(SetArgumentPointee<2>(slot_list), Return(0)));
+    ON_CALL(pkcs11_, OpenSession(_, _, _, _))
+        .WillByDefault(DoAll(SetArgumentPointee<3>(kSession), Return(0)));
+    ON_CALL(pkcs11_, CloseSession(_, _))
+        .WillByDefault(Return(0));
+    ON_CALL(pkcs11_, CreateObject(_, _, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::CreateObject));
+    ON_CALL(pkcs11_, DestroyObject(_, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::DestroyObject));
+    ON_CALL(pkcs11_, GetAttributeValue(_, _, _, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::GetAttributeValue));
+    ON_CALL(pkcs11_, SetAttributeValue(_, _, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::SetAttributeValue));
+    ON_CALL(pkcs11_, FindObjectsInit(_, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::FindObjectsInit));
+    ON_CALL(pkcs11_, FindObjects(_, _, _, _))
+        .WillByDefault(Invoke(this, &KeyStoreTest::FindObjects));
+    ON_CALL(pkcs11_, FindObjectsFinal(_, _))
+        .WillByDefault(Return(0));
+    base::FilePath system_path("/var/lib/chaps");
+    ON_CALL(token_manager_, GetTokenPath(_, 0, _))
+        .WillByDefault(DoAll(SetArgumentPointee<2>(system_path), Return(true)));
+    base::FilePath user_path(chromeos::cryptohome::home::GetDaemonPath(
+        kDefaultUser, "chaps"));
+    ON_CALL(token_manager_, GetTokenPath(_, 1, _))
+        .WillByDefault(DoAll(SetArgumentPointee<2>(user_path), Return(true)));
+  }
+
+  // Stores a new labeled object, only CKA_LABEL and CKA_VALUE are relevant.
+  virtual uint32_t CreateObject(const chromeos::SecureBlob& isolate,
+                                uint64_t session_id,
+                                const std::vector<uint8_t>& attributes,
+                                uint64_t* new_object_handle) {
+    *new_object_handle = next_handle_++;
+    std::string label = GetValue(attributes, CKA_LABEL);
+    handles_[*new_object_handle] = label;
+    values_[label] = GetValue(attributes, CKA_VALUE);
+    labels_[label] = *new_object_handle;
+    return CKR_OK;
+  }
+
+  // Deletes a labeled object.
+  virtual uint32_t DestroyObject(const chromeos::SecureBlob& isolate,
+                                 uint64_t session_id,
+                                 uint64_t object_handle) {
+    std::string label = handles_[object_handle];
+    handles_.erase(object_handle);
+    values_.erase(label);
+    labels_.erase(label);
+    return CKR_OK;
+  }
+
+  // Supports reading CKA_VALUE.
+  virtual uint32_t GetAttributeValue(const chromeos::SecureBlob& isolate,
+                                     uint64_t session_id,
+                                     uint64_t object_handle,
+                                     const std::vector<uint8_t>& attributes_in,
+                                     std::vector<uint8_t>* attributes_out) {
+    std::string label = handles_[object_handle];
+    std::string value = values_[label];
+    chaps::Attributes parsed;
+    parsed.Parse(attributes_in);
+    if (parsed.num_attributes() == 1 &&
+        parsed.attributes()[0].type == CKA_LABEL)
+      value = label;
+    if (parsed.num_attributes() != 1 ||
+        (parsed.attributes()[0].type != CKA_VALUE &&
+         parsed.attributes()[0].type != CKA_LABEL) ||
+        (parsed.attributes()[0].pValue &&
+         parsed.attributes()[0].ulValueLen != value.size()))
+      return CKR_GENERAL_ERROR;
+    parsed.attributes()[0].ulValueLen = value.size();
+    if (parsed.attributes()[0].pValue)
+      memcpy(parsed.attributes()[0].pValue, value.data(), value.size());
+    parsed.Serialize(attributes_out);
+    return CKR_OK;
+  }
+
+  // Supports writing CKA_VALUE.
+  virtual uint32_t SetAttributeValue(
+      const chromeos::SecureBlob& isolate,
+      uint64_t session_id,
+      uint64_t object_handle,
+      const std::vector<uint8_t>& attributes) {
+    values_[handles_[object_handle]] = GetValue(attributes, CKA_VALUE);
+    return CKR_OK;
+  }
+
+  // Finds stored objects by CKA_LABEL or CKA_VALUE. If no CKA_LABEL or
+  // CKA_VALUE, find all objects.
+  virtual uint32_t FindObjectsInit(const chromeos::SecureBlob& isolate,
+                                   uint64_t session_id,
+                                   const std::vector<uint8_t>& attributes) {
+    std::string label = GetValue(attributes, CKA_LABEL);
+    std::string value = GetValue(attributes, CKA_VALUE);
+    found_objects_.clear();
+    if (label.empty() && value.empty()) {
+      // Find all objects.
+      found_objects_ = chromeos::GetMapKeysAsVector(handles_);
+    } else if (!label.empty() && labels_.count(label) > 0) {
+      // Find only the object with |label|.
+      found_objects_.push_back(labels_[label]);
+    } else {
+      // Find all objects with |value|.
+      for (const auto& item : values_) {
+        if (item.second == value && labels_.count(item.first) > 0) {
+          found_objects_.push_back(labels_[item.first]);
+        }
+      }
+    }
+    return CKR_OK;
+  }
+
+  // Reports a 'found' object based on find_status_.
+  virtual uint32_t FindObjects(const chromeos::SecureBlob& isolate,
+                               uint64_t session_id,
+                               uint64_t max_object_count,
+                               std::vector<uint64_t>* object_list) {
+    while (!found_objects_.empty() && object_list->size() < max_object_count) {
+      object_list->push_back(found_objects_.back());
+      found_objects_.pop_back();
+    }
+    return CKR_OK;
+  }
+
+ protected:
+  NiceMock<Pkcs11Mock> pkcs11_;
+  NiceMock<chaps::TokenManagerClientMock> token_manager_;
+
+ private:
+  // A helper to pull the value for a given attribute out of a serialized
+  // template.
+  std::string GetValue(const std::vector<uint8_t>& attributes,
+                       CK_ATTRIBUTE_TYPE type) {
+    chaps::Attributes parsed;
+    parsed.Parse(attributes);
+    CK_ATTRIBUTE_PTR array = parsed.attributes();
+    for (CK_ULONG i = 0; i < parsed.num_attributes(); ++i) {
+      if (array[i].type == type) {
+        if (!array[i].pValue)
+          return "";
+        return std::string(reinterpret_cast<char*>(array[i].pValue),
+                           array[i].ulValueLen);
+      }
+    }
+    return "";
+  }
+
+  std::map<std::string, std::string> values_;  // The fake store: label->value
+  std::map<uint64_t, std::string> handles_;    // The fake store: handle->label
+  std::map<std::string, uint64_t> labels_;     // The fake store: label->handle
+  std::vector<uint64_t> found_objects_;        // The most recent search results
+  uint64_t next_handle_;                       // Tracks handle assignment
+  ScopedFakeSalt fake_system_salt_;
+  // We want to avoid all the Chaps verbose logging.
+  ScopedDisableVerboseLogging no_verbose_logging;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyStoreTest);
+};
+
+// This test assumes that chaps in not available on the system running the test.
+// The purpose of this test is to exercise the C_Initialize failure code path.
+// Without a mock, the Chaps library will attempt to connect to the Chaps daemon
+// unsuccessfully, resulting in a C_Initialize failure.
+TEST(KeyStoreTest_NoMock, Pkcs11NotAvailable) {
+  chaps::TokenManagerClient token_manager;
+  Pkcs11KeyStore key_store(&token_manager);
+  std::string blob;
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_FALSE(key_store.Write(kDefaultUser, "test", blob));
+  EXPECT_FALSE(key_store.Read("", "test", &blob));
+  EXPECT_FALSE(key_store.Write("", "test", blob));
+}
+
+// Exercises the key store when PKCS #11 returns success.  This exercises all
+// non-error-handling code paths.
+TEST_F(KeyStoreTest, Pkcs11Success) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_EQ("test_data", blob);
+  // Try with a different key name.
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test2", &blob));
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test2", "test_data2"));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "test2", &blob));
+  EXPECT_EQ("test_data2", blob);
+  // Read the original key again.
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_EQ("test_data", blob);
+  // Replace key data.
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data3"));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_EQ("test_data3", blob);
+  // Delete key data.
+  EXPECT_TRUE(key_store.Delete(kDefaultUser, "test2"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test2", &blob));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+TEST_F(KeyStoreTest, Pkcs11Success_NoUser) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_FALSE(key_store.Read("", "test", &blob));
+  EXPECT_TRUE(key_store.Write("", "test", "test_data"));
+  EXPECT_TRUE(key_store.Read("", "test", &blob));
+  EXPECT_EQ("test_data", blob);
+  // Try with a different key name.
+  EXPECT_FALSE(key_store.Read("", "test2", &blob));
+  EXPECT_TRUE(key_store.Write("", "test2", "test_data2"));
+  EXPECT_TRUE(key_store.Read("", "test2", &blob));
+  EXPECT_EQ("test_data2", blob);
+  // Read the original key again.
+  EXPECT_TRUE(key_store.Read("", "test", &blob));
+  EXPECT_EQ("test_data", blob);
+  // Replace key data.
+  EXPECT_TRUE(key_store.Write("", "test", "test_data3"));
+  EXPECT_TRUE(key_store.Read("", "test", &blob));
+  EXPECT_EQ("test_data3", blob);
+  // Delete key data.
+  EXPECT_TRUE(key_store.Delete("", "test2"));
+  EXPECT_FALSE(key_store.Read("", "test2", &blob));
+  EXPECT_TRUE(key_store.Read("", "test", &blob));
+}
+
+// Tests the key store when PKCS #11 has no token for the given user.
+TEST_F(KeyStoreTest, TokenNotAvailable) {
+  EXPECT_CALL(token_manager_, GetTokenPath(_, _, _))
+      .WillRepeatedly(Return(false));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+  EXPECT_FALSE(key_store.Write(kDefaultUser, "test", blob));
+  EXPECT_FALSE(key_store.Read("", "test", &blob));
+  EXPECT_FALSE(key_store.Write("", "test", blob));
+}
+
+// Tests the key store when PKCS #11 fails to open a session.
+TEST_F(KeyStoreTest, NoSession) {
+  EXPECT_CALL(pkcs11_, OpenSession(_, _, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_FALSE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+// Tests the key store when PKCS #11 fails to create an object.
+TEST_F(KeyStoreTest, CreateObjectFail) {
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_FALSE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+// Tests the key store when PKCS #11 fails to read attribute values.
+TEST_F(KeyStoreTest, ReadValueFail) {
+  EXPECT_CALL(pkcs11_, GetAttributeValue(_, _, _, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+// Tests the key store when PKCS #11 fails to delete key data.
+TEST_F(KeyStoreTest, DeleteValueFail) {
+  EXPECT_CALL(pkcs11_, DestroyObject(_, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  Pkcs11KeyStore key_store(&token_manager_);
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Write(kDefaultUser, "test", "test_data2"));
+  EXPECT_FALSE(key_store.Delete(kDefaultUser, "test"));
+}
+
+// Tests the key store when PKCS #11 fails to find objects.  Tests each part of
+// the multi-part find operation individually.
+TEST_F(KeyStoreTest, FindFail) {
+  EXPECT_CALL(pkcs11_, FindObjectsInit(_, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+
+  EXPECT_CALL(pkcs11_, FindObjectsInit(_, _, _))
+      .WillRepeatedly(Return(CKR_OK));
+  EXPECT_CALL(pkcs11_, FindObjects(_, _, _, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+
+  EXPECT_CALL(pkcs11_, FindObjects(_, _, _, _))
+      .WillRepeatedly(Return(CKR_OK));
+  EXPECT_CALL(pkcs11_, FindObjectsFinal(_, _))
+      .WillRepeatedly(Return(CKR_GENERAL_ERROR));
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+// Tests the key store when PKCS #11 successfully finds zero objects.
+TEST_F(KeyStoreTest, FindNoObjects) {
+  std::vector<uint64_t> empty;
+  EXPECT_CALL(pkcs11_, FindObjects(_, _, _, _))
+      .WillRepeatedly(DoAll(SetArgumentPointee<3>(empty), Return(CKR_OK)));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string blob;
+  EXPECT_TRUE(key_store.Write(kDefaultUser, "test", "test_data"));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "test", &blob));
+}
+
+TEST_F(KeyStoreTest, RegisterKeyWithoutCertificate) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  // Try with a malformed public key.
+  EXPECT_FALSE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                  KEY_USAGE_SIGN, "private_key_blob",
+                                  "bad_pubkey", ""));
+  // Try with a well-formed public key.
+  std::string public_key_der = HexDecode(kValidPublicKeyHex);
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .Times(2)  // Public, private (no certificate).
+      .WillRepeatedly(Return(CKR_OK));
+  EXPECT_TRUE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                 KEY_USAGE_SIGN, "private_key_blob",
+                                 public_key_der, ""));
+}
+
+TEST_F(KeyStoreTest, RegisterKeyWithCertificate) {
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .Times(3)  // Public, private, and certificate.
+      .WillRepeatedly(Return(CKR_OK));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string public_key_der = HexDecode(kValidPublicKeyHex);
+  std::string certificate_der = HexDecode(kValidCertificateHex);
+  EXPECT_TRUE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                 KEY_USAGE_SIGN, "private_key_blob",
+                                 public_key_der, certificate_der));
+  // Also try with the system token.
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .Times(3)  // Public, private, and certificate.
+      .WillRepeatedly(Return(CKR_OK));
+  EXPECT_TRUE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                 KEY_USAGE_SIGN, "private_key_blob",
+                                 public_key_der, certificate_der));
+}
+
+TEST_F(KeyStoreTest, RegisterKeyWithBadCertificate) {
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .Times(3)  // Public, private, and certificate.
+      .WillRepeatedly(Return(CKR_OK));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string public_key_der = HexDecode(kValidPublicKeyHex);
+  EXPECT_TRUE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                 KEY_USAGE_SIGN, "private_key_blob",
+                                 public_key_der, "bad_certificate"));
+}
+
+TEST_F(KeyStoreTest, RegisterWithUnsupportedKeyType) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string public_key_der = HexDecode(kValidPublicKeyHex);
+  EXPECT_FALSE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_ECC,
+                                  KEY_USAGE_SIGN, "private_key_blob",
+                                  public_key_der, ""));
+}
+
+TEST_F(KeyStoreTest, RegisterDecryptionKey) {
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .WillRepeatedly(Return(CKR_OK));
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string public_key_der = HexDecode(kValidPublicKeyHex);
+  EXPECT_TRUE(key_store.Register(kDefaultUser, "test_label", KEY_TYPE_RSA,
+                                 KEY_USAGE_DECRYPT, "private_key_blob",
+                                 public_key_der, ""));
+}
+
+TEST_F(KeyStoreTest, RegisterCertificate) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string certificate_der = HexDecode(kValidCertificateHex);
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .Times(2);  // Once for valid, once for invalid.
+  // Try with a valid certificate (hit multiple times to check dup logic).
+  EXPECT_TRUE(key_store.RegisterCertificate(kDefaultUser, certificate_der));
+  EXPECT_TRUE(key_store.RegisterCertificate(kDefaultUser, certificate_der));
+  EXPECT_TRUE(key_store.RegisterCertificate(kDefaultUser, certificate_der));
+  // Try with an invalid certificate.
+  EXPECT_TRUE(key_store.RegisterCertificate(kDefaultUser, "bad_certificate"));
+}
+
+TEST_F(KeyStoreTest, RegisterCertificateError) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string certificate_der = HexDecode(kValidCertificateHex);
+  // Handle an error from PKCS #11.
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .WillOnce(Return(CKR_GENERAL_ERROR));
+  EXPECT_FALSE(key_store.RegisterCertificate(kDefaultUser, certificate_der));
+}
+
+TEST_F(KeyStoreTest, RegisterCertificateSystemToken) {
+  Pkcs11KeyStore key_store(&token_manager_);
+  std::string certificate_der = HexDecode(kValidCertificateHex);
+  // Try with the system token.
+  EXPECT_CALL(pkcs11_, CreateObject(_, _, _, _))
+      .WillOnce(Return(CKR_OK));
+  EXPECT_TRUE(key_store.RegisterCertificate(kDefaultUser, certificate_der));
+}
+
+// Tests that the DeleteByPrefix() method removes the correct objects and only
+// the correct objects.
+TEST_F(KeyStoreTest, DeleteByPrefix) {
+  Pkcs11KeyStore key_store(&token_manager_);
+
+  // Test with no keys.
+  ASSERT_TRUE(key_store.DeleteByPrefix(kDefaultUser, "prefix"));
+
+  // Test with a single matching key.
+  ASSERT_TRUE(key_store.Write(kDefaultUser, "prefix_test", "test"));
+  ASSERT_TRUE(key_store.DeleteByPrefix(kDefaultUser, "prefix"));
+  std::string blob;
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "prefix_test", &blob));
+
+  // Test with a single non-matching key.
+  ASSERT_TRUE(key_store.Write(kDefaultUser, "_prefix_", "test"));
+  ASSERT_TRUE(key_store.DeleteByPrefix(kDefaultUser, "prefix"));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "_prefix_", &blob));
+
+  // Test with an empty prefix.
+  ASSERT_TRUE(key_store.DeleteByPrefix(kDefaultUser, ""));
+  EXPECT_FALSE(key_store.Read(kDefaultUser, "_prefix_", &blob));
+
+  // Test with multiple matching and non-matching keys.
+  const int kNumKeys = 110;  // Pkcs11KeyStore max is 100 for FindObjects.
+  key_store.Write(kDefaultUser, "other1", "test");
+  for (int i = 0; i < kNumKeys; ++i) {
+    std::string key_name = std::string("prefix") + base::IntToString(i);
+    key_store.Write(kDefaultUser, key_name, std::string(key_name));
+  }
+  ASSERT_TRUE(key_store.Write(kDefaultUser, "other2", "test"));
+  ASSERT_TRUE(key_store.DeleteByPrefix(kDefaultUser, "prefix"));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "other1", &blob));
+  EXPECT_TRUE(key_store.Read(kDefaultUser, "other2", &blob));
+  for (int i = 0; i < kNumKeys; ++i) {
+    std::string key_name = std::string("prefix") + base::IntToString(i);
+    EXPECT_FALSE(key_store.Read(kDefaultUser, key_name, &blob));
+  }
+}
+
+}  // namespace attestation