attestation: Support default and test Verified Access servers

BUG=b:69687094
TEST=unit tests

Change-Id: I9b4587d155099d9e5f94bfe0a881f73e2acf1a82
Reviewed-on: https://chromium-review.googlesource.com/795216
Commit-Ready: Yves Arrouye <drcrash@chromium.org>
Tested-by: Yves Arrouye <drcrash@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
diff --git a/attestation/common/interface.proto b/attestation/common/interface.proto
index 0bda784..fc024ab 100644
--- a/attestation/common/interface.proto
+++ b/attestation/common/interface.proto
@@ -37,6 +37,11 @@
   TEST_ACA = 1;
 }
 
+enum VAType {
+  DEFAULT_VA = 0;
+  TEST_VA = 1;
+}
+
 message CreateGoogleAttestedKeyRequest {
   // An arbitrary label which can be used to reference the key later.
   optional string key_label = 1;
@@ -312,6 +317,8 @@
   optional bool include_signed_public_key = 5;
   // The challenge to be signed.
   optional bytes challenge = 6;
+  // The VA server that will handle the challenge.
+  optional VAType va_type = 7;
 }
 
 message SignEnterpriseChallengeReply {
diff --git a/attestation/server/attestation_service.cc b/attestation/server/attestation_service.cc
index b7b5fe4..8dac24b 100644
--- a/attestation/server/attestation_service.cc
+++ b/attestation/server/attestation_service.cc
@@ -70,7 +70,7 @@
        " but provide the right aca_type in requests."
 #endif
 
-const char kEnterpriseSigningPublicKey[] =
+const char kDefaultEnterpriseSigningPublicKey[] =
     "bf7fefa3a661437b26aed0801db64d7ba8b58875c351d3bdc9f653847d4a67b3"
     "b67479327724d56aa0f71a3f57c2290fdc1ff05df80589715e381dfbbda2c4ac"
     "114c30d0a73c5b7b2e22178d26d8b65860aa8dd65e1b3d61a07c81de87c1e7e4"
@@ -79,8 +79,7 @@
     "69c292c6d9f6f52522333b84ddf9471ffe00f01bf2de5faa1621f967f49e158b"
     "f2b305360f886826cc6fdbef11a12b2d6002d70d8d1e8f40e0901ff94c203cb2"
     "01a36a0bd6e83955f14b494f4f2f17c0c826657b85c25ffb8a73599721fa17ab";
-
-const char kEnterpriseEncryptionPublicKey[] =
+const char kDefaultEnterpriseEncryptionPublicKey[] =
     "edba5e723da811e41636f792c7a77aef633fbf39b542aa537c93c93eaba7a3b1"
     "0bc3e484388c13d625ef5573358ec9e7fbeb6baaaa87ca87d93fb61bf5760e29"
     "6813c435763ed2c81f631e26e3ff1a670261cdc3c39a4640b6bbf4ead3d6587b"
@@ -89,13 +88,30 @@
     "eb08318611d44daf6044f8527687dc7ce5319b51eae6ab12bee6bd16e59c499e"
     "fa53d80232ae886c7ee9ad8bc1cbd6e4ac55cb8fa515671f7e7ad66e98769f52"
     "c3c309f98bf08a3b8fbb0166e97906151b46402217e65c5d01ddac8514340e8b";
-
-// This value is opaque; it is proprietary to the system managing the private
-// key.  In this case the value has been supplied by the enterprise server
-// maintainers.
-const char kEnterpriseEncryptionPublicKeyID[] =
+const char kDefaultEnterpriseEncryptionPublicKeyID[] =
     "\x00\x4a\xe2\xdc\xae";
 
+const char kTestEnterpriseSigningPublicKey[] =
+    "baab3e277518c65b1b98290bb55061df9a50b9f32a4b0ff61c7c61c51e966fcd"
+    "c891799a39ee0b7278f204a2b45a7e615080ff8f69f668e05adcf3486b319f80"
+    "f9da814d9b86b16a3e68b4ce514ab5591112838a68dc3bfdcc4043a5aa8de52c"
+    "ae936847a271971ecaa188172692c13f3b0321239c90559f3b7ba91e66d38ef4"
+    "db4c75104ac5f2f15e55a463c49753a88e56906b1725fd3f0c1372beb16d4904"
+    "752c74452b0c9f757ee12877a859dd0666cafaccbfc33fe67d98a89a2c12ef52"
+    "5e4b16ea8972577dbfc567c2625a3eee6bcaa6cb4939b941f57236d1d57243f8"
+    "c9766938269a8034d82fbd44044d2ee6a5c7275589afc3790b60280c0689900f";
+const char kTestEnterpriseEncryptionPublicKey[] =
+    "c0c116e7ded8d7c1e577f9c8fb0d267c3c5c3e3b6800abb0309c248eaa5cd9bf"
+    "91945132e4bb0111711356a388b756788e20bc1ecc9261ea9bcae8369cfd050e"
+    "d8dc00b50fbe36d2c1c8a9b335f2e11096be76bebce8b5dcb0dc39ac0fd963b0"
+    "51474f794d4289cc0c52d0bab451b9e69a43ecd3a84330b0b2de4365c038ffce"
+    "ec0f1999d789615849c2f3c29d1d9ed42ccb7f330d5b56f40fb7cc6556190c3b"
+    "698c20d83fb341a442fd69701fe0bdc41bdcf8056ccbc8d9b4275e8e43ec6b63"
+    "c1ae70d52838dfa90a9cd9e7b6bd88ed3abf4fab444347104e30e635f4f296ac"
+    "4c91939103e317d0eca5f36c48102e967f176a19a42220f3cf14634b6773be07";
+const char kTestEnterpriseEncryptionPublicKeyID[] =
+    "\x00\xef\x22\x0f\xb0";
+
 const size_t kNonceSize = 20;  // As per TPM_NONCE definition.
 const int kNumTemporalValues = 5;
 
@@ -1903,11 +1919,34 @@
   }
 }
 
+const char *AttestationService::GetEnterpriseSigningHexKey(VAType va_type)
+    const {
+  return va_type == TEST_VA ? kTestEnterpriseSigningPublicKey :
+      kDefaultEnterpriseSigningPublicKey;
+}
+
+const char *AttestationService::GetEnterpriseEncryptionHexKey(VAType va_type)
+    const {
+  return va_type == TEST_VA ? kTestEnterpriseEncryptionPublicKey :
+      kDefaultEnterpriseEncryptionPublicKey;
+}
+
+std::string AttestationService::GetEnterpriseEncryptionPublicKeyID(
+    VAType va_type) const {
+  return std::string(va_type == TEST_VA ?
+      kTestEnterpriseEncryptionPublicKeyID :
+      kDefaultEnterpriseEncryptionPublicKeyID,
+      arraysize(va_type == TEST_VA ?
+          kTestEnterpriseEncryptionPublicKeyID :
+          kDefaultEnterpriseEncryptionPublicKeyID) - 1);
+}
+
 bool AttestationService::ValidateEnterpriseChallenge(
+    VAType va_type,
     const SignedData& signed_challenge) {
   const char kExpectedChallengePrefix[] = "EnterpriseKeyChallenge";
   if (!crypto_utility_->VerifySignatureUsingHexKey(
-      kEnterpriseSigningPublicKey,
+      GetEnterpriseSigningHexKey(va_type),
       signed_challenge.data(),
       signed_challenge.signature())) {
     LOG(ERROR) << __func__ << ": Failed to verify challenge signature.";
@@ -1926,6 +1965,7 @@
 }
 
 bool AttestationService::EncryptEnterpriseKeyInfo(
+    VAType va_type,
     const KeyInfo& key_info,
     EncryptedData* encrypted_data) {
   std::string serialized;
@@ -1933,12 +1973,9 @@
     LOG(ERROR) << "Failed to serialize key info.";
     return false;
   }
-  std::string enterprise_key_id(
-      kEnterpriseEncryptionPublicKeyID,
-      arraysize(kEnterpriseEncryptionPublicKeyID) - 1);
   return crypto_utility_->EncryptDataForGoogle(
-             serialized, kEnterpriseEncryptionPublicKey,
-             enterprise_key_id, encrypted_data);
+             serialized, GetEnterpriseEncryptionHexKey(va_type),
+             GetEnterpriseEncryptionPublicKeyID(va_type), encrypted_data);
 }
 
 void AttestationService::SignEnterpriseChallenge(
@@ -1970,7 +2007,7 @@
     result->set_status(STATUS_INVALID_PARAMETER);
     return;
   }
-  if (!ValidateEnterpriseChallenge(signed_challenge)) {
+  if (!ValidateEnterpriseChallenge(request.va_type(), signed_challenge)) {
     LOG(ERROR) << __func__ << ": Invalid challenge.";
     result->set_status(STATUS_INVALID_PARAMETER);
     return;
@@ -2007,7 +2044,8 @@
   ChallengeResponse response_pb;
   *response_pb.mutable_challenge() = signed_challenge;
   response_pb.set_nonce(nonce);
-  if (!EncryptEnterpriseKeyInfo(key_info,
+  if (!EncryptEnterpriseKeyInfo(request.va_type(),
+                                key_info,
                                 response_pb.mutable_encrypted_key_info())) {
     LOG(ERROR) << __func__ << ": Failed to encrypt KeyInfo.";
     result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR);
diff --git a/attestation/server/attestation_service.h b/attestation/server/attestation_service.h
index 50822b4..41b3766 100644
--- a/attestation/server/attestation_service.h
+++ b/attestation/server/attestation_service.h
@@ -29,6 +29,7 @@
 #include <brillo/bind_lambda.h>
 #include <brillo/http/http_transport.h>
 #include <brillo/secure_blob.h>
+#include <gtest/gtest_prod.h>
 
 #include "attestation/common/attestation_ca.pb.h"
 #include "attestation/common/crypto_utility.h"
@@ -431,12 +432,23 @@
   // for enrollment.
   bool IsVerifiedMode() const;
 
+  // Gets the enterprise signing key for |va_type| servers.
+  const char* GetEnterpriseSigningHexKey(VAType va_type) const;
+
+  // Gets the enterprise encryption key for |va_type| servers.
+  const char *GetEnterpriseEncryptionHexKey(VAType va_type) const;
+
+  // Gets the enterprise encryption key identifier for |va_type| servers.
+  std::string GetEnterpriseEncryptionPublicKeyID(VAType va_type) const;
+
   // Validates incoming enterprise challenge data.
-  bool ValidateEnterpriseChallenge(const SignedData& signed_challenge);
+  bool ValidateEnterpriseChallenge(VAType va_type,
+                                   const SignedData& signed_challenge);
 
   // Encrypts a KeyInfo protobuf as required for an enterprise challenge
   // response.
-  bool EncryptEnterpriseKeyInfo(const KeyInfo& key_info,
+  bool EncryptEnterpriseKeyInfo(VAType va_type,
+                                const KeyInfo& key_info,
                                 EncryptedData* encrypted_data);
 
   // Signs data using the provided key. On success, returns true and fills
@@ -503,6 +515,10 @@
 
   base::WeakPtr<AttestationService> GetWeakPtr();
 
+  FRIEND_TEST_ALL_PREFIXES(AttestationServiceEnterpriseTest,
+                           SignEnterpriseChallengeSuccess);
+  FRIEND_TEST(AttestationServiceTest, SignEnterpriseChallengeSuccess);
+
   // Other than initialization and destruction, these are used only by the
   // worker thread.
   CryptoUtility* crypto_utility_{nullptr};
diff --git a/attestation/server/attestation_service_test.cc b/attestation/server/attestation_service_test.cc
index 360b5f3..3232a8c 100644
--- a/attestation/server/attestation_service_test.cc
+++ b/attestation/server/attestation_service_test.cc
@@ -1849,14 +1849,70 @@
   Run();
 }
 
+class AttestationServiceEnterpriseTest
+  : public AttestationServiceTest,
+    public testing::WithParamInterface<VAType> {};
+
+TEST_P(AttestationServiceEnterpriseTest, SignEnterpriseChallengeSuccess) {
+  KeyInfo key_info = CreateChallengeKeyInfo();
+  std::string key_info_str;
+  key_info.SerializeToString(&key_info_str);
+  EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(
+      service_->GetEnterpriseSigningHexKey(GetParam()), _, _))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(mock_crypto_utility_,
+              EncryptDataForGoogle(key_info_str,
+                  service_->GetEnterpriseEncryptionHexKey(GetParam()), _, _))
+      .WillRepeatedly(
+          DoAll(SetArgPointee<3>(MockEncryptedData(key_info_str)),
+                Return(true)));
+  EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _))
+      .WillRepeatedly(DoAll(SetArgPointee<2>(std::string("signature")),
+                      Return(true)));
+  auto callback = [this](const SignEnterpriseChallengeReply& reply) {
+    EXPECT_EQ(STATUS_SUCCESS, reply.status());
+    EXPECT_TRUE(reply.has_challenge_response());
+    SignedData signed_data;
+    EXPECT_TRUE(signed_data.ParseFromString(reply.challenge_response()));
+    EXPECT_EQ("signature", signed_data.signature());
+    ChallengeResponse response_pb;
+    EXPECT_TRUE(response_pb.ParseFromString(signed_data.data()));
+    EXPECT_EQ(CreateChallenge("EnterpriseKeyChallenge"),
+              response_pb.challenge().data());
+    KeyInfo key_info = CreateChallengeKeyInfo();
+    std::string key_info_str;
+    key_info.SerializeToString(&key_info_str);
+    EXPECT_EQ(key_info_str,
+              response_pb.encrypted_key_info().encrypted_data());
+    Quit();
+  };
+  SignEnterpriseChallengeRequest request;
+  request.set_va_type(GetParam());
+  request.set_username("user");
+  request.set_key_label("label");
+  request.set_domain(key_info.domain());
+  request.set_device_id(key_info.device_id());
+  request.set_include_signed_public_key(false);
+  request.set_challenge(CreateSignedChallenge("EnterpriseKeyChallenge"));
+  service_->SignEnterpriseChallenge(request, base::Bind(callback));
+  Run();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    VerifiedAccessType,
+    AttestationServiceEnterpriseTest,
+    ::testing::Values(DEFAULT_VA, TEST_VA));
+
 TEST_F(AttestationServiceTest, SignEnterpriseChallengeSuccess) {
   KeyInfo key_info = CreateChallengeKeyInfo();
   std::string key_info_str;
   key_info.SerializeToString(&key_info_str);
-  EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(_, _, _))
+  EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(
+      service_->GetEnterpriseSigningHexKey(DEFAULT_VA), _, _))
       .WillRepeatedly(Return(true));
   EXPECT_CALL(mock_crypto_utility_,
-              EncryptDataForGoogle(key_info_str, _, _, _))
+              EncryptDataForGoogle(key_info_str,
+                  service_->GetEnterpriseEncryptionHexKey(DEFAULT_VA), _, _))
       .WillRepeatedly(
           DoAll(SetArgPointee<3>(MockEncryptedData(key_info_str)),
                 Return(true)));