Implemented asynchronous attestation calls.

BUG=chromium-os:36561
TEST=Ran unit tests
     Ran platform_Attestation
     Ran platform_Attestation after modifying to use --async

Change-Id: Ibb83b40b3328fbd31ba7632c7f762a52843d0769
Reviewed-on: https://gerrit.chromium.org/gerrit/38780
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Commit-Ready: Darren Krahn <dkrahn@chromium.org>
Tested-by: Darren Krahn <dkrahn@chromium.org>
diff --git a/attestation_task.cc b/attestation_task.cc
new file mode 100644
index 0000000..a88d434
--- /dev/null
+++ b/attestation_task.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 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.
+//
+// Asynchronous attestation tasks.
+
+#include "attestation_task.h"
+
+#include "attestation.h"
+
+namespace cryptohome {
+
+AttestationTask::AttestationTask(AttestationTaskObserver* observer,
+                                 Attestation* attestation)
+    : MountTask(observer, NULL, UsernamePasskey()),
+      attestation_(attestation) {
+}
+
+AttestationTask::~AttestationTask() {}
+
+CreateEnrollRequestTask::CreateEnrollRequestTask(
+    AttestationTaskObserver* observer,
+    Attestation* attestation)
+    : AttestationTask(observer, attestation) {
+}
+
+CreateEnrollRequestTask::~CreateEnrollRequestTask() {}
+
+void CreateEnrollRequestTask::Run() {
+  result()->set_return_status(FALSE);
+  if (attestation_) {
+    SecureBlob pca_request;
+    bool status = attestation_->CreateEnrollRequest(&pca_request);
+    result()->set_return_status(status);
+    result()->set_return_data(pca_request);
+  }
+  Notify();
+}
+
+EnrollTask::EnrollTask(AttestationTaskObserver* observer,
+                       Attestation* attestation,
+                       const SecureBlob& pca_response)
+    : AttestationTask(observer, attestation),
+      pca_response_(pca_response) {
+}
+
+EnrollTask::~EnrollTask() {}
+
+void EnrollTask::Run() {
+  result()->set_return_status(FALSE);
+  if (attestation_) {
+    bool status = attestation_->Enroll(pca_response_);
+    result()->set_return_status(status);
+  }
+  Notify();
+}
+
+CreateCertRequestTask::CreateCertRequestTask(AttestationTaskObserver* observer,
+                                             Attestation* attestation,
+                                             bool is_cert_for_owner)
+    : AttestationTask(observer, attestation),
+      is_cert_for_owner_(is_cert_for_owner) {
+}
+
+CreateCertRequestTask::~CreateCertRequestTask() {}
+
+void CreateCertRequestTask::Run() {
+  result()->set_return_status(FALSE);
+  if (attestation_) {
+    SecureBlob pca_request;
+    bool status = attestation_->CreateCertRequest(is_cert_for_owner_,
+                                                  &pca_request);
+    result()->set_return_status(status);
+    result()->set_return_data(pca_request);
+  }
+  Notify();
+}
+
+FinishCertRequestTask::FinishCertRequestTask(AttestationTaskObserver* observer,
+                                             Attestation* attestation,
+                                             const SecureBlob& pca_response)
+    : AttestationTask(observer, attestation),
+      pca_response_(pca_response) {
+}
+
+FinishCertRequestTask::~FinishCertRequestTask() {}
+
+void FinishCertRequestTask::Run() {
+  result()->set_return_status(FALSE);
+  if (attestation_) {
+    SecureBlob cert;
+    bool status = attestation_->FinishCertRequest(pca_response_, &cert);
+    result()->set_return_status(status);
+    result()->set_return_data(cert);
+  }
+  Notify();
+}
+
+}  // namespace cryptohome
diff --git a/attestation_task.h b/attestation_task.h
new file mode 100644
index 0000000..fc1bdc7
--- /dev/null
+++ b/attestation_task.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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.
+//
+// Asynchronous attestation tasks.
+
+#include "mount_task.h"
+
+namespace cryptohome {
+
+class Attestation;
+
+typedef MountTaskObserver AttestationTaskObserver;
+
+// This class represents an attestation task.  Inherit MountTask to reuse basic
+// async code, especially the sequence counter.
+class AttestationTask : public MountTask {
+ public:
+  AttestationTask(AttestationTaskObserver* observer, Attestation* attestation);
+  virtual ~AttestationTask();
+
+ protected:
+  // The Attestation instance which will do the actual work.
+  Attestation* attestation_;
+};
+
+class CreateEnrollRequestTask : public AttestationTask {
+ public:
+  CreateEnrollRequestTask(AttestationTaskObserver* observer,
+                          Attestation* attestation);
+  virtual ~CreateEnrollRequestTask();
+
+  virtual void Run();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CreateEnrollRequestTask);
+};
+
+class EnrollTask : public AttestationTask {
+ public:
+  EnrollTask(AttestationTaskObserver* observer,
+             Attestation* attestation,
+             const SecureBlob& pca_response);
+  virtual ~EnrollTask();
+
+  virtual void Run();
+
+ private:
+  SecureBlob pca_response_;
+
+  DISALLOW_COPY_AND_ASSIGN(EnrollTask);
+};
+
+class CreateCertRequestTask : public AttestationTask {
+ public:
+  CreateCertRequestTask(AttestationTaskObserver* observer,
+                        Attestation* attestation,
+                        bool is_cert_for_owner);
+  virtual ~CreateCertRequestTask();
+
+  virtual void Run();
+
+ private:
+  bool is_cert_for_owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(CreateCertRequestTask);
+};
+
+class FinishCertRequestTask : public AttestationTask {
+ public:
+  FinishCertRequestTask(AttestationTaskObserver* observer,
+                        Attestation* attestation,
+                        const SecureBlob& pca_response);
+  virtual ~FinishCertRequestTask();
+
+  virtual void Run();
+
+ private:
+  SecureBlob pca_response_;
+
+  DISALLOW_COPY_AND_ASSIGN(FinishCertRequestTask);
+};
+
+}  // namespace cryptohome
diff --git a/mount_task.h b/mount_task.h
index e5efdb3..675a7fb 100644
--- a/mount_task.h
+++ b/mount_task.h
@@ -37,6 +37,8 @@
 #include "pkcs11_init.h"
 #include "username_passkey.h"
 
+using chromeos::SecureBlob;
+
 namespace cryptohome {
 
 extern const char* kMountTaskResultEventType;
@@ -72,6 +74,7 @@
       : sequence_id_(rhs.sequence_id_),
         return_status_(rhs.return_status_),
         return_code_(rhs.return_code_),
+        return_data_(rhs.return_data_),
         event_name_(rhs.event_name_),
         mount_(rhs.mount_),
         pkcs11_init_(rhs.pkcs11_init_),
@@ -133,10 +136,21 @@
     guest_ = value;
   }
 
+  SecureBlob return_data() const {
+    return return_data_;
+  }
+
+  void set_return_data(const SecureBlob& data) {
+    return_data_.clear_contents();
+    return_data_ = data;
+  }
+
   MountTaskResult& operator=(const MountTaskResult& rhs) {
     sequence_id_ = rhs.sequence_id_;
     return_status_ = rhs.return_status_;
     return_code_ = rhs.return_code_;
+    return_data_.clear_contents();
+    return_data_ = rhs.return_data_;
     event_name_ = rhs.event_name_;
     mount_ = rhs.mount_;
     pkcs11_init_ = rhs.pkcs11_init_;
@@ -152,6 +166,7 @@
   int sequence_id_;
   bool return_status_;
   MountError return_code_;
+  SecureBlob return_data_;
   const char* event_name_;
   Mount* mount_;
   bool pkcs11_init_;
diff --git a/service.cc b/service.cc
index abb3cc3..7aba369 100644
--- a/service.cc
+++ b/service.cc
@@ -26,6 +26,7 @@
 #include <string>
 #include <vector>
 
+#include "attestation_task.h"
 #include "cryptohome_event_source.h"
 #include "crypto.h"
 #include "install_attributes.h"
@@ -430,8 +431,26 @@
 void Service::NotifyEvent(CryptohomeEventBase* event) {
   if (!strcmp(event->GetEventName(), kMountTaskResultEventType)) {
     MountTaskResult* result = static_cast<MountTaskResult*>(event);
-    g_signal_emit(cryptohome_, async_complete_signal_, 0, result->sequence_id(),
-                  result->return_status(), result->return_code());
+    if (result->return_data().size() == 0) {
+      g_signal_emit(cryptohome_,
+                    async_complete_signal_,
+                    0,
+                    result->sequence_id(),
+                    result->return_status(),
+                    result->return_code());
+    } else {
+      chromeos::glib::ScopedArray tmp_array(g_array_new(FALSE, FALSE, 1));
+      g_array_append_vals(tmp_array.get(),
+                          result->return_data().data(),
+                          result->return_data().size());
+      g_signal_emit(cryptohome_,
+                    async_data_complete_signal_,
+                    0,
+                    result->sequence_id(),
+                    result->return_status(),
+                    tmp_array.get());
+      chromeos::SecureMemset(tmp_array.get()->data, 0, tmp_array.get()->len);
+    }
     if (result->pkcs11_init()) {
       LOG(INFO) << "An asynchronous mount request with sequence id: "
                 << result->sequence_id()
@@ -1036,9 +1055,15 @@
 
 gboolean Service::AsyncTpmAttestationCreateEnrollRequest(gint* OUT_async_id,
                                                          GError** error) {
-  // TODO(dkrahn): Implement.
-  g_set_error(error, 0, 0, "Not implemented");
-  return FALSE;
+  AttestationTaskObserver* observer =
+      new MountTaskObserverBridge(NULL, &event_source_);
+  scoped_refptr<CreateEnrollRequestTask> task =
+      new CreateEnrollRequestTask(observer, tpm_init_->get_attestation());
+  *OUT_async_id = task->sequence_id();
+  mount_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&CreateEnrollRequestTask::Run, task.get()));
+  return TRUE;
 }
 
 gboolean Service::TpmAttestationEnroll(GArray* pca_response,
@@ -1058,9 +1083,16 @@
 gboolean Service::AsyncTpmAttestationEnroll(GArray* pca_response,
                                             gint* OUT_async_id,
                                             GError** error) {
-  // TODO(dkrahn): Implement.
-  g_set_error(error, 0, 0, "Not implemented");
-  return FALSE;
+  chromeos::SecureBlob blob(pca_response->data, pca_response->len);
+  AttestationTaskObserver* observer =
+      new MountTaskObserverBridge(NULL, &event_source_);
+  scoped_refptr<EnrollTask> task =
+      new EnrollTask(observer, tpm_init_->get_attestation(), blob);
+  *OUT_async_id = task->sequence_id();
+  mount_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&EnrollTask::Run, task.get()));
+  return TRUE;
 }
 
 gboolean Service::TpmAttestationCreateCertRequest(gboolean is_cert_for_owner,
@@ -1082,9 +1114,17 @@
     gboolean is_cert_for_owner,
     gint* OUT_async_id,
     GError** error) {
-  // TODO(dkrahn): Implement.
-  g_set_error(error, 0, 0, "Not implemented");
-  return FALSE;
+  AttestationTaskObserver* observer =
+      new MountTaskObserverBridge(NULL, &event_source_);
+  scoped_refptr<CreateCertRequestTask> task =
+      new CreateCertRequestTask(observer,
+                                tpm_init_->get_attestation(),
+                                is_cert_for_owner);
+  *OUT_async_id = task->sequence_id();
+  mount_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&CreateCertRequestTask::Run, task.get()));
+  return TRUE;
 }
 
 gboolean Service::TpmAttestationFinishCertRequest(GArray* pca_response,
@@ -1109,9 +1149,16 @@
 gboolean Service::AsyncTpmAttestationFinishCertRequest(GArray* pca_response,
                                                        gint* OUT_async_id,
                                                        GError** error) {
-  // TODO(dkrahn): Implement.
-  g_set_error(error, 0, 0, "Not implemented");
-  return FALSE;
+  chromeos::SecureBlob blob(pca_response->data, pca_response->len);
+  AttestationTaskObserver* observer =
+      new MountTaskObserverBridge(NULL, &event_source_);
+  scoped_refptr<FinishCertRequestTask> task =
+      new FinishCertRequestTask(observer, tpm_init_->get_attestation(), blob);
+  *OUT_async_id = task->sequence_id();
+  mount_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&FinishCertRequestTask::Run, task.get()));
+  return TRUE;
 }
 
 gboolean Service::TpmIsAttestationEnrolled(gboolean* OUT_is_enrolled,