attestation: Make the attestation interface asynchronous.

Also moves to the D-Bus asynchronous methods for proxy / object.

BUG=brillo:737
TEST=build, unit tests, manually ran 'attestation_client'

Change-Id: I7cf60edcb5bf7fa112592e5f129a2dcd6334ae22
Reviewed-on: https://chromium-review.googlesource.com/264932
Reviewed-by: Alex Vakulenko <[email protected]>
Commit-Queue: Darren Krahn <[email protected]>
Tested-by: Darren Krahn <[email protected]>
diff --git a/attestation.gyp b/attestation.gyp
index 84a1916..b37cdee 100644
--- a/attestation.gyp
+++ b/attestation.gyp
@@ -103,6 +103,7 @@
           'sources': [
             'attestation_testrunner.cc',
             'client/dbus_proxy_test.cc',
+            'server/dbus_service_test.cc',
           ],
           'dependencies': [
             'client_library',
diff --git a/client/dbus_proxy.cc b/client/dbus_proxy.cc
index 5a4d64a..9f507a2 100644
--- a/client/dbus_proxy.cc
+++ b/client/dbus_proxy.cc
@@ -4,10 +4,19 @@
 
 #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() {}
@@ -27,37 +36,34 @@
   return (object_proxy_ != nullptr);
 }
 
-AttestationStatus DBusProxy::CreateGoogleAttestedKey(
+void DBusProxy::CreateGoogleAttestedKey(
     const std::string& key_label,
     KeyType key_type,
     KeyUsage key_usage,
     CertificateProfile certificate_profile,
-    std::string* server_error_details,
-    std::string* certificate) {
+    const base::Callback<CreateGoogleAttestedKeyCallback>& callback) {
   attestation::CreateGoogleAttestedKeyRequest request;
   request.set_key_label(key_label);
   request.set_key_type(key_type);
   request.set_key_usage(key_usage);
   request.set_certificate_profile(certificate_profile);
-  auto response = chromeos::dbus_utils::CallMethodAndBlock(
+  auto on_success = [callback](
+      const attestation::CreateGoogleAttestedKeyReply& reply) {
+    callback.Run(reply.status(),
+                 reply.certificate_chain(),
+                 reply.server_error());
+  };
+  auto on_error = [callback](chromeos::Error* error) {
+    callback.Run(NOT_AVAILABLE, std::string(), std::string());
+  };
+  chromeos::dbus_utils::CallMethodWithTimeout(
+      kDBusTimeoutMS,
       object_proxy_,
       attestation::kAttestationInterface,
       attestation::kCreateGoogleAttestedKey,
-      nullptr /* error */,
+      base::Bind(on_success),
+      base::Bind(on_error),
       request);
-  if (!response) {
-    return NOT_AVAILABLE;
-  }
-  attestation::CreateGoogleAttestedKeyReply reply;
-  if (!chromeos::dbus_utils::ExtractMethodCallResults(
-      response.get(),
-      nullptr /* error */,
-      &reply)) {
-    return UNEXPECTED_DEVICE_ERROR;
-  }
-  *certificate = reply.certificate();
-  *server_error_details = reply.server_error();
-  return reply.status();
 }
 
 }  // namespace attestation
diff --git a/client/dbus_proxy.h b/client/dbus_proxy.h
index 1847273..7d3d135 100644
--- a/client/dbus_proxy.h
+++ b/client/dbus_proxy.h
@@ -28,13 +28,12 @@
 
   // AttestationInterface methods.
   bool Initialize() override;
-  AttestationStatus CreateGoogleAttestedKey(
+  void CreateGoogleAttestedKey(
       const std::string& key_label,
       KeyType key_type,
       KeyUsage key_usage,
       CertificateProfile certificate_profile,
-      std::string* server_error_details,
-      std::string* certificate) override;
+      const base::Callback<CreateGoogleAttestedKeyCallback>& callback) override;
 
   // Useful for testing.
   void set_object_proxy(dbus::ObjectProxy* object_proxy) {
diff --git a/client/dbus_proxy_test.cc b/client/dbus_proxy_test.cc
index c86862e..bc1920a 100644
--- a/client/dbus_proxy_test.cc
+++ b/client/dbus_proxy_test.cc
@@ -4,6 +4,7 @@
 
 #include <string>
 
+#include <chromeos/bind_lambda.h>
 #include <dbus/mock_object_proxy.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -31,7 +32,9 @@
 };
 
 TEST_F(DBusProxyTest, CreateGoogleAttestedKeySuccess) {
-  auto fake_dbus_call = [](dbus::MethodCall* method_call) -> dbus::Response* {
+  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;
@@ -47,21 +50,26 @@
     dbus::MessageWriter writer(response.get());
     CreateGoogleAttestedKeyReply reply_proto;
     reply_proto.set_status(SUCCESS);
-    reply_proto.set_certificate("certificate");
+    reply_proto.set_certificate_chain("certificate");
     reply_proto.set_server_error("server_error");
     writer.AppendProtoAsArrayOfBytes(reply_proto);
-    return response.release();
+    response_callback.Run(response.release());
   };
   EXPECT_CALL(*mock_object_proxy_,
-              MockCallMethodAndBlockWithErrorDetails(_, _, _))
-      .WillOnce(WithArgs<0>(Invoke(fake_dbus_call)));
-  std::string certificate;
-  std::string server_error;
-  EXPECT_EQ(SUCCESS, proxy_.CreateGoogleAttestedKey(
-      "label", KEY_TYPE_ECC, KEY_USAGE_SIGN, ENTERPRISE_MACHINE_CERTIFICATE,
-      &server_error, &certificate));
-  EXPECT_EQ("certificate", certificate);
-  EXPECT_EQ("server_error", server_error);
+              CallMethodWithErrorCallback(_, _, _, _))
+      .WillOnce(WithArgs<0, 2>(Invoke(fake_dbus_call)));
+
+  // Set expectations on the outputs.
+  auto callback = [](AttestationStatus status,
+                     const std::string& certificate,
+                     const std::string& server_error) {
+    EXPECT_EQ(SUCCESS, status);
+    EXPECT_EQ("certificate", certificate);
+    EXPECT_EQ("server_error", server_error);
+  };
+  proxy_.CreateGoogleAttestedKey("label", KEY_TYPE_ECC, KEY_USAGE_SIGN,
+                                 ENTERPRISE_MACHINE_CERTIFICATE,
+                                 base::Bind(callback));
 }
 
 }  // namespace attestation
diff --git a/client/main.cc b/client/main.cc
index 1fae5a1..b97e9a6 100644
--- a/client/main.cc
+++ b/client/main.cc
@@ -2,35 +2,114 @@
 // 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/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/interface.pb.h"
 
-int main(int argc, char* argv[]) {
-  std::unique_ptr<attestation::AttestationInterface> attestation(
-      new attestation::DBusProxy());
-  if (!attestation->Initialize()) {
-    printf("Failed to initialize.\n");
-  }
-  std::string certificate;
-  std::string server_error_details;
-  attestation::AttestationStatus status = attestation->CreateGoogleAttestedKey(
-    "test_key",
-    attestation::KEY_TYPE_RSA,
-    attestation::KEY_USAGE_SIGN,
-    attestation::ENTERPRISE_MACHINE_CERTIFICATE,
-    &certificate,
-    &server_error_details);
-  if (status == attestation::SUCCESS) {
-    printf("Success!\n");
-  } else {
-    printf("Error occurred: %d.\n", status);
-    if (!server_error_details.empty()) {
-      printf("Server error details: %s\n", server_error_details.c_str());
+namespace attestation {
+
+const char kCreateCommand[] = "create";
+const char kUsage[] = R"(
+Usage: attestation_client <command> [<args>]
+Commands:
+  create - Creates a Google-attested key (this is the default command).
+)";
+
+// 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;
   }
-  return status;
+
+  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;
+    auto args = base::CommandLine::ForCurrentProcess()->GetArgs();
+    if (args.empty() || args.front() == kCreateCommand) {
+      task = base::Bind(&ClientLoop::CallCreateGoogleAttestedKey,
+                        weak_factory_.GetWeakPtr());
+    } else {
+      return EX_USAGE;
+    }
+    base::MessageLoop::current()->PostTask(FROM_HERE, task);
+    return EX_OK;
+  }
+
+  void HandleCreateGoogleAttestedKeyReply(
+      attestation::AttestationStatus status,
+      const std::string& certificate,
+      const std::string& server_error_details) {
+    if (status == attestation::SUCCESS) {
+      printf("Success!\n");
+    } else {
+      printf("Error occurred: %d.\n", status);
+      if (!server_error_details.empty()) {
+        printf("Server error details: %s\n", server_error_details.c_str());
+      }
+    }
+    Quit();
+  }
+
+  void CallCreateGoogleAttestedKey() {
+    attestation_->CreateGoogleAttestedKey(
+        "test_key",
+        attestation::KEY_TYPE_RSA,
+        attestation::KEY_USAGE_SIGN,
+        attestation::ENTERPRISE_MACHINE_CERTIFICATE,
+        base::Bind(&ClientLoop::HandleCreateGoogleAttestedKeyReply,
+                   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_interface.h b/common/attestation_interface.h
index b153899..89b6d87 100644
--- a/common/attestation_interface.h
+++ b/common/attestation_interface.h
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include <base/callback_forward.h>
+
 #include "attestation/common/attestation_ca.pb.h"
 #include "attestation/common/export.h"
 #include "attestation/common/interface.pb.h"
@@ -18,7 +20,7 @@
 //   [APP] -> AttestationInterface -> [IPC] -> AttestationInterface
 class ATTESTATION_EXPORT AttestationInterface {
  public:
-  virtual ~AttestationInterface() {}
+  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
@@ -26,18 +28,25 @@
   virtual bool Initialize() = 0;
 
   // Creates a key certified by the Google Attestation CA which corresponds to
-  // the give |key_label|, |key_type|, and |key_usage|. The certificate issued
-  // by the CA will correspond to |certificate_profile|. On success,
-  // |certificate| will contain the DER-encoded X.509 certificate issued by the
-  // CA. If the CA refuses to issue a certificate, REQUEST_DENIED_BY_CA is
-  // returned and |server_error_details| contains a message from the CA.
-  virtual AttestationStatus CreateGoogleAttestedKey(
+  // the given |key_label|, |key_type|, and |key_usage|. The certificate issued
+  // by the CA will correspond to |certificate_profile|. On success, |status|
+  // will be SUCCESS and |certificate_chain| will contain 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.
+  // If the CA refuses to issue a certificate, |status| will be
+  // REQUEST_DENIED_BY_CA and |server_error_details| will contain an error
+  // message from the CA.
+  using CreateGoogleAttestedKeyCallback =
+      void(AttestationStatus status,
+           const std::string& certificate_chain,
+           const std::string& server_error_details);
+  virtual void CreateGoogleAttestedKey(
       const std::string& key_label,
       KeyType key_type,
       KeyUsage key_usage,
       CertificateProfile certificate_profile,
-      std::string* certificate,
-      std::string* server_error_details) = 0;
+      const base::Callback<CreateGoogleAttestedKeyCallback>& callback) = 0;
 };
 
 }  // namespace attestation
diff --git a/common/interface.proto b/common/interface.proto
index f81e3ff..ef7af4e 100644
--- a/common/interface.proto
+++ b/common/interface.proto
@@ -44,6 +44,9 @@
   // More information about a server-side error. This only exists
   // if status=REQUEST_DENIED_BY_CA.
   optional string server_error = 2;
-  // The X.509/DER certificate issued by the Google Attestation CA.
-  optional bytes certificate = 3;
+  // 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;
 }
diff --git a/common/mock_attestation_interface.h b/common/mock_attestation_interface.h
new file mode 100644
index 0000000..2dcca1f
--- /dev/null
+++ b/common/mock_attestation_interface.h
@@ -0,0 +1,33 @@
+// 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_METHOD5(CreateGoogleAttestedKey, void(
+      const std::string&,
+      KeyType,
+      KeyUsage,
+      CertificateProfile,
+      const base::Callback<CreateGoogleAttestedKeyCallback>&));
+};
+
+}  // namespace attestation
+
+#endif  // ATTESTATION_COMMON_MOCK_ATTESTATION_INTERFACE_H_
+
diff --git a/server/attestation_service.cc b/server/attestation_service.cc
index 9565a13..dfddea8 100644
--- a/server/attestation_service.cc
+++ b/server/attestation_service.cc
@@ -4,20 +4,22 @@
 
 #include "attestation/server/attestation_service.h"
 
+#include <base/callback.h>
+
 namespace attestation {
 
 bool AttestationService::Initialize() {
+  LOG(INFO) << "Attestation service started.";
   return true;
 }
 
-AttestationStatus AttestationService::CreateGoogleAttestedKey(
+void AttestationService::CreateGoogleAttestedKey(
     const std::string& key_label,
     KeyType key_type,
     KeyUsage key_usage,
     CertificateProfile certificate_profile,
-    std::string* server_error_details,
-    std::string* certificate) {
-  return NOT_AVAILABLE;
+    const base::Callback<CreateGoogleAttestedKeyCallback>& callback) {
+  callback.Run(NOT_AVAILABLE, std::string(), std::string());
 }
 
 }  // namespace attestation
diff --git a/server/attestation_service.h b/server/attestation_service.h
index a869db2..0e835b8 100644
--- a/server/attestation_service.h
+++ b/server/attestation_service.h
@@ -11,7 +11,7 @@
 
 namespace attestation {
 
-// An implementation of AttestationInterface that actually implements it.
+// An implementation of AttestationInterface for the core attestation service.
 // Usage:
 //   std::unique_ptr<AttestationInterface> attestation =
 //       new AttestationService();
@@ -24,13 +24,12 @@
 
   // AttestationInterface methods.
   bool Initialize() override;
-  AttestationStatus CreateGoogleAttestedKey(
+  void CreateGoogleAttestedKey(
       const std::string& key_label,
       KeyType key_type,
       KeyUsage key_usage,
       CertificateProfile certificate_profile,
-      std::string* server_error_details,
-      std::string* certificate) override;
+      const base::Callback<CreateGoogleAttestedKeyCallback>& callback) override;
 };
 
 }  // namespace attestation
diff --git a/server/dbus_service.cc b/server/dbus_service.cc
index 29e8e82..919ac7b 100644
--- a/server/dbus_service.cc
+++ b/server/dbus_service.cc
@@ -6,11 +6,14 @@
 
 #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,
@@ -23,7 +26,7 @@
   chromeos::dbus_utils::DBusInterface* dbus_interface =
       dbus_object_.AddOrGetInterface(kAttestationInterface);
 
-  dbus_interface->AddSimpleMethodHandler(
+  dbus_interface->AddMethodHandler(
       kCreateGoogleAttestedKey,
       base::Unretained(this),
       &DBusService::HandleCreateGoogleAttestedKey);
@@ -31,26 +34,34 @@
   dbus_object_.RegisterAsync(callback);
 }
 
-CreateGoogleAttestedKeyReply DBusService::HandleCreateGoogleAttestedKey(
-    CreateGoogleAttestedKeyRequest request) {
+void DBusService::HandleCreateGoogleAttestedKey(
+    scoped_ptr<DBusMethodResponse<const CreateGoogleAttestedKeyReply&>>
+        response,
+    const CreateGoogleAttestedKeyRequest& request) {
   VLOG(1) << __func__;
-  std::string certificate;
-  std::string server_error_details;
-  AttestationStatus status = service_->CreateGoogleAttestedKey(
-    request.key_label(),
-    request.key_type(),
-    request.key_usage(),
-    request.certificate_profile(),
-    &certificate,
-    &server_error_details);
-  CreateGoogleAttestedKeyReply reply;
-  reply.set_status(status);
-  if (status == SUCCESS) {
-    reply.set_certificate(certificate);
-  } else if (status == REQUEST_DENIED_BY_CA) {
-    reply.set_server_error(server_error_details);
-  }
-  return reply;
+  // A callback that fills the reply protobuf and sends it.
+  // CAUTION: This callback takes ownership of |response|.
+  auto callback = [](
+      scoped_ptr<DBusMethodResponse<const CreateGoogleAttestedKeyReply&>>
+          response,
+      AttestationStatus status,
+      const std::string& certificate_chain,
+      const std::string& server_error_details) {
+    CreateGoogleAttestedKeyReply reply;
+    reply.set_status(status);
+    if (status == SUCCESS) {
+      reply.set_certificate_chain(certificate_chain);
+    } else if (status == REQUEST_DENIED_BY_CA) {
+      reply.set_server_error(server_error_details);
+    }
+    response->Return(reply);
+  };
+  service_->CreateGoogleAttestedKey(request.key_label(),
+                                    request.key_type(),
+                                    request.key_usage(),
+                                    request.certificate_profile(),
+                                    base::Bind(callback,
+                                               base::Passed(&response)));
 }
 
 }  // namespace attestation
diff --git a/server/dbus_service.h b/server/dbus_service.h
index 12c8ab5..e880c16 100644
--- a/server/dbus_service.h
+++ b/server/dbus_service.h
@@ -6,6 +6,7 @@
 #define ATTESTATION_SERVER_DBUS_SERVICE_H_
 
 #include <base/memory/scoped_ptr.h>
+#include <chromeos/dbus/dbus_method_response.h>
 #include <chromeos/dbus/dbus_object.h>
 #include <dbus/bus.h>
 
@@ -16,7 +17,7 @@
 using CompletionAction =
     chromeos::dbus_utils::AsyncEventSequencer::CompletionAction;
 
-// Main class within the attestation daemon that ties other classes together.
+// Handles D-Bus calls to the attestation daemon.
 class DBusService {
  public:
   // DBusService does not take ownership of |service|; it must remain valid for
@@ -28,10 +29,19 @@
   // 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.
-  CreateGoogleAttestedKeyReply HandleCreateGoogleAttestedKey(
-      CreateGoogleAttestedKeyRequest request);
+  void HandleCreateGoogleAttestedKey(
+      scoped_ptr<chromeos::dbus_utils::DBusMethodResponse<
+          const CreateGoogleAttestedKeyReply&>> response,
+      const CreateGoogleAttestedKeyRequest& request);
 
   chromeos::dbus_utils::DBusObject dbus_object_;
   AttestationInterface* service_;
diff --git a/server/dbus_service_test.cc b/server/dbus_service_test.cc
new file mode 100644
index 0000000..c440f5a
--- /dev/null
+++ b/server/dbus_service_test.cc
@@ -0,0 +1,108 @@
+// 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, CreateGoogleAttestedKeySuccess) {
+  EXPECT_CALL(mock_service_, CreateGoogleAttestedKey(
+      "label", KEY_TYPE_ECC, KEY_USAGE_SIGN, ENTERPRISE_MACHINE_CERTIFICATE, _))
+      .WillOnce(WithArgs<4>(Invoke([](const base::Callback<
+          AttestationInterface::CreateGoogleAttestedKeyCallback>& callback) {
+        callback.Run(SUCCESS, "certificate", "server_error");
+      })));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(
+      kCreateGoogleAttestedKey);
+  CreateGoogleAttestedKeyRequest request_proto;
+  request_proto.set_key_label("label");
+  request_proto.set_key_type(KEY_TYPE_ECC);
+  request_proto.set_key_usage(KEY_USAGE_SIGN);
+  request_proto.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request_proto);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  CreateGoogleAttestedKeyReply reply_proto;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply_proto));
+  EXPECT_EQ(SUCCESS, reply_proto.status());
+  EXPECT_EQ("certificate", reply_proto.certificate_chain());
+  EXPECT_EQ("", reply_proto.server_error());
+}
+
+TEST_F(DBusServiceTest, CreateGoogleAttestedKeyServerError) {
+  EXPECT_CALL(mock_service_, CreateGoogleAttestedKey(_, _, _, _, _))
+      .WillOnce(WithArgs<4>(Invoke([](const base::Callback<
+          AttestationInterface::CreateGoogleAttestedKeyCallback>& callback) {
+        callback.Run(REQUEST_DENIED_BY_CA, "certificate", "server_error");
+      })));
+  std::unique_ptr<dbus::MethodCall> call = CreateMethodCall(
+      kCreateGoogleAttestedKey);
+  CreateGoogleAttestedKeyRequest request_proto;
+  dbus::MessageWriter writer(call.get());
+  writer.AppendProtoAsArrayOfBytes(request_proto);
+  auto response = CallMethod(call.get());
+  dbus::MessageReader reader(response.get());
+  CreateGoogleAttestedKeyReply reply_proto;
+  EXPECT_TRUE(reader.PopArrayOfBytesAsProto(&reply_proto));
+  EXPECT_EQ(REQUEST_DENIED_BY_CA, reply_proto.status());
+  EXPECT_EQ("", reply_proto.certificate_chain());
+  EXPECT_EQ("server_error", reply_proto.server_error());
+}
+
+}  // namespace attestation