cryptohome: cert provision apis provide ek public key query.

It is meant to replace cryptohome client in ap-daemons.

BUG=b:173470557
TEST=hwsec.CertProvision

Change-Id: I559ad1cefbd6b17ca8eb4d83a4512755ae799025
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2587118
Reviewed-by: Yi Chou <yich@google.com>
Tested-by: Leo Lai <cylai@google.com>
Commit-Queue: Leo Lai <cylai@google.com>
diff --git a/cryptohome/cert/cert_provision.cc b/cryptohome/cert/cert_provision.cc
index ec825f3..a833a8d 100644
--- a/cryptohome/cert/cert_provision.cc
+++ b/cryptohome/cert/cert_provision.cc
@@ -307,4 +307,22 @@
   return Status::Success;
 }
 
+Status GetEndorsementPublicKey(std::string* ek_public_key) {
+  auto proxy = AttestationProxyFactory::Create();
+  // By design, the factory must return a valid object.
+  CHECK(proxy);
+  ::attestation::GetEndorsementInfoReply reply;
+  brillo::ErrorPtr error;
+  if (!proxy->GetEndorsementInfo(attestation::GetEndorsementInfoRequest(),
+                                 &reply, &error)) {
+    return ReportAndReturn(Status::DBusError, error->GetMessage());
+  }
+  if (reply.status() != ::attestation::STATUS_SUCCESS) {
+    return ReportAndReturn(Status::AttestationError,
+                           "Failed to get endorsement info");
+  }
+  *ek_public_key = reply.ek_public_key();
+  return Status::Success;
+}
+
 }  // namespace cert_provision
diff --git a/cryptohome/cert/cert_provision_client.cc b/cryptohome/cert/cert_provision_client.cc
index 58e1b19..500b32f 100644
--- a/cryptohome/cert/cert_provision_client.cc
+++ b/cryptohome/cert/cert_provision_client.cc
@@ -35,6 +35,8 @@
   printf("  --sign --label=<label> --in=<file_in> [--out=<file_out>]\n");
   printf("         --mechanism=<mechanism>\n");
   printf("  where mechanism: sha1_rsa, sha256_rsa, sha256_rsa_pss\n");
+  printf("  Get endorsement public key:'\n");
+  printf("  --get_ek_public_key\n");
 }
 
 int main(int argc, char** argv) {
@@ -174,6 +176,18 @@
     } else {
       puts(base::HexEncode(sig.data(), sig.size()).c_str());
     }
+  } else if (cl->HasSwitch("get_ek_public_key")) {
+    std::string ek_public_key;
+    sts = cert_provision::GetEndorsementPublicKey(&ek_public_key);
+    if (sts != cert_provision::Status::Success) {
+      LOG(ERROR) << "Getting EK returned " << static_cast<int>(sts);
+      return 3;
+    }
+    if (ek_public_key.empty()) {
+      LOG(ERROR) << "Empty endorsement public key";
+      return 1;
+    }
+    puts(base::HexEncode(ek_public_key.data(), ek_public_key.size()).c_str());
   }
   return 0;
 }
diff --git a/cryptohome/cert/cert_provision_unittest.cc b/cryptohome/cert/cert_provision_unittest.cc
index 757228f..c7bb9ed 100644
--- a/cryptohome/cert/cert_provision_unittest.cc
+++ b/cryptohome/cert/cert_provision_unittest.cc
@@ -41,9 +41,10 @@
 namespace {
 
 // Some arbitrary certificate label used for testing.
-const char kCertLabel[] = "test";
-const char kWrongLabel[] = "some wrong label";
-const char kFakeErrorMessage[] = "fake error message";
+constexpr char kCertLabel[] = "test";
+constexpr char kWrongLabel[] = "some wrong label";
+constexpr char kFakeErrorMessage[] = "fake error message";
+constexpr char kFakeEndorsementPublicKey[] = "fake public ek";
 
 const char kBegCertificate[] = "-----BEGIN CERTIFICATE-----";
 const char kEndCertificate[] = "-----END CERTIFICATE-----";
@@ -71,18 +72,21 @@
 class RecordingAttestationProxy : public org::chromium::AttestationProxyMock {
  public:
   struct ReplySource {
+    attestation::GetEndorsementInfoReply get_endorsement_info_reply;
     attestation::GetStatusReply get_status_reply;
     attestation::EnrollReply enroll_reply;
     attestation::GetCertificateReply get_cert_reply;
     attestation::RegisterKeyWithChapsTokenReply register_key_reply;
   };
   struct ErrorSource {
+    brillo::ErrorPtr get_endorsement_info_error;
     brillo::ErrorPtr get_status_error;
     brillo::ErrorPtr enroll_error;
     brillo::ErrorPtr get_cert_error;
     brillo::ErrorPtr register_key_error;
   };
   struct RequestSink {
+    attestation::GetEndorsementInfoRequest get_endorsement_info_request;
     attestation::GetStatusRequest get_status_request;
     attestation::EnrollRequest enroll_request;
     attestation::GetCertificateRequest get_cert_request;
@@ -96,6 +100,9 @@
       : reply_source_(reply_source),
         error_source_(error_source),
         request_sink_(request_sink) {
+    ON_CALL(*this, GetEndorsementInfo(_, _, _, _))
+        .WillByDefault(
+            Invoke(this, &RecordingAttestationProxy::HandleGetEndorsementInfo));
     ON_CALL(*this, GetStatus(_, _, _, _))
         .WillByDefault(
             Invoke(this, &RecordingAttestationProxy::HandleGetStatus));
@@ -109,6 +116,19 @@
             this, &RecordingAttestationProxy::HandleRegisterKeyWithChapsToken));
   }
 
+  bool HandleGetEndorsementInfo(
+      const attestation::GetEndorsementInfoRequest& request,
+      attestation::GetEndorsementInfoReply* reply,
+      brillo::ErrorPtr* error,
+      int /*timeout_ms*/) {
+    if (error_source_->get_endorsement_info_error) {
+      *error = std::move(error_source_->get_endorsement_info_error);
+      return false;
+    }
+    request_sink_->get_endorsement_info_request = request;
+    *reply = reply_source_->get_endorsement_info_reply;
+    return true;
+  }
   bool HandleGetStatus(const attestation::GetStatusRequest& request,
                        attestation::GetStatusReply* reply,
                        brillo::ErrorPtr* error,
@@ -826,4 +846,27 @@
   EXPECT_EQ(exepcted_error_message, progress_.back().message);
 }
 
+TEST_F(CertProvisionTest, GetEndorsementPublicKeySuccess) {
+  attestation_proxy_factory_.get_reply_source()
+      ->get_endorsement_info_reply.set_ek_public_key(kFakeEndorsementPublicKey);
+  EXPECT_CALL(*attestation_proxy_factory_.get_mock_proxy(),
+              GetEndorsementInfo(_, _, _, _));
+  std::string endorsment_public_key;
+  EXPECT_EQ(Status::Success, GetEndorsementPublicKey(&endorsment_public_key));
+  EXPECT_EQ(endorsment_public_key, kFakeEndorsementPublicKey);
+}
+
+TEST_F(CertProvisionTest, GetEndorsementPublicKeyDBusError) {
+  brillo::Error::AddTo(&attestation_proxy_factory_.get_error_source()
+                            ->get_endorsement_info_error,
+                       FROM_HERE, "", "", kFakeErrorMessage);
+  const std::string exepcted_error_message =
+      attestation_proxy_factory_.get_error_source()
+          ->get_endorsement_info_error->GetMessage();
+  EXPECT_CALL(*attestation_proxy_factory_.get_mock_proxy(),
+              GetEndorsementInfo(_, _, _, _));
+  std::string endorsment_public_key;
+  EXPECT_NE(Status::Success, GetEndorsementPublicKey(&endorsment_public_key));
+}
+
 }  // namespace cert_provision
diff --git a/cryptohome/cert_provision.h b/cryptohome/cert_provision.h
index a3553cd..27ec743 100644
--- a/cryptohome/cert_provision.h
+++ b/cryptohome/cert_provision.h
@@ -157,6 +157,10 @@
                                   const std::string& data,
                                   std::string* signature);
 
+// Gets endorsement public key of the TPM.
+CERT_PROVISION_EXPORT Status
+GetEndorsementPublicKey(std::string* ek_public_key);
+
 }  // namespace cert_provision
 
 #endif  // CRYPTOHOME_CERT_PROVISION_H_