blob: 448caa15d05a38b302db4e3048ebbf7038bf1f4f [file] [log] [blame]
// 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 <attestation/proto_bindings/attestation_ca.pb.h>
#include <attestation/proto_bindings/pca_agent.pb.h>
#include <base/bind.h>
#include <base/bind_helpers.h>
#include <base/callback.h>
#include <base/run_loop.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <base/synchronization/waitable_event.h>
#include <base/test/task_environment.h>
#include <brillo/data_encoding.h>
#include <brillo/errors/error.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <policy/mock_device_policy.h>
#include <policy/mock_libpolicy.h>
#if USE_TPM2
#include <trunks/tpm_utility.h>
#endif
#if USE_TPM2
extern "C" {
#include <trunks/cr50_headers/virtual_nvmem.h>
}
#endif
#include "attestation/common/mock_crypto_utility.h"
#include "attestation/common/mock_tpm_utility.h"
#include "attestation/pca_agent/client/fake_pca_agent_proxy.h"
#include "attestation/server/attestation_service.h"
#include "attestation/server/google_keys.h"
#include "attestation/server/mock_database.h"
#include "attestation/server/mock_key_store.h"
using testing::_;
using testing::AtMost;
using testing::DoAll;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;
using testing::SetArgPointee;
using testing::StrictMock;
using testing::WithArgs;
namespace attestation {
namespace {
#if USE_TPM2
constexpr TpmVersion kTpmVersionUnderTest = TPM_2_0;
#else
constexpr TpmVersion kTpmVersionUnderTest = TPM_1_2;
#endif
std::string CreateChallenge(const std::string& prefix) {
Challenge challenge;
challenge.set_prefix(prefix);
challenge.set_nonce("nonce");
challenge.set_timestamp(100500);
std::string serialized;
challenge.SerializeToString(&serialized);
return serialized;
}
std::string CreateSignedChallenge(const std::string& prefix) {
SignedData signed_data;
signed_data.set_data(CreateChallenge(prefix));
signed_data.set_signature("challenge_signature");
std::string serialized;
signed_data.SerializeToString(&serialized);
return serialized;
}
EncryptedData MockEncryptedData(std::string data) {
EncryptedData encrypted_data;
encrypted_data.set_wrapped_key("wrapped_key");
encrypted_data.set_iv("iv");
encrypted_data.set_mac("mac");
encrypted_data.set_encrypted_data(data);
encrypted_data.set_wrapping_key_id("wrapping_key_id");
return encrypted_data;
}
KeyInfo CreateChallengeKeyInfo() {
KeyInfo key_info;
key_info.set_key_type(EUK);
key_info.set_domain("domain");
key_info.set_device_id("device_id");
key_info.set_certificate("");
return key_info;
}
KeyInfo CreateMachineChallengeKeyInfoWithSPKAC(
const std::string& certified_credential_of_key_for_spkac,
const std::string& spkac) {
// Create a PEM encoding of |certified_credential_of_key_for_spkac|.
std::string pem_certificate_of_key_for_spkac =
"-----BEGIN CERTIFICATE-----\n" +
brillo::data_encoding::Base64EncodeWrapLines(
certified_credential_of_key_for_spkac) +
"-----END CERTIFICATE-----";
KeyInfo key_info;
key_info.set_key_type(EMK);
key_info.set_customer_id("customer_id");
key_info.set_device_id("device_id");
key_info.set_certificate(pem_certificate_of_key_for_spkac);
key_info.set_signed_public_key_and_challenge(spkac);
return key_info;
}
std::string GetFakeCertificateChain() {
const std::string kBeginCertificate = "-----BEGIN CERTIFICATE-----\n";
const std::string kEndCertificate = "-----END CERTIFICATE-----";
std::string pem = kBeginCertificate;
pem += brillo::data_encoding::Base64EncodeWrapLines("fake_cert");
pem += kEndCertificate + "\n" + kBeginCertificate;
pem += brillo::data_encoding::Base64EncodeWrapLines("fake_ca_cert");
pem += kEndCertificate + "\n" + kBeginCertificate;
pem += brillo::data_encoding::Base64EncodeWrapLines("fake_ca_cert2");
pem += kEndCertificate;
return pem;
}
// testing::InvokeArgument<N> does not work with base::Callback, need to use
// |ACTION_TAMPLATE| along with predefined |args| tuple.
ACTION_TEMPLATE(InvokeCallbackArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(p0)) {
std::get<k>(args).Run(p0);
}
} // namespace
class AttestationServiceBaseTest : public testing::Test {
public:
~AttestationServiceBaseTest() override = default;
void SetUp() override {
service_.reset(new AttestationService(nullptr));
service_->set_database(&mock_database_);
service_->set_crypto_utility(&mock_crypto_utility_);
service_->set_key_store(&mock_key_store_);
service_->set_tpm_utility(&mock_tpm_utility_);
service_->set_hwid("fake_hwid");
service_->set_pca_agent_proxy(&fake_pca_agent_proxy_);
mock_policy_provider_ = new StrictMock<policy::MockPolicyProvider>();
service_->set_policy_provider(mock_policy_provider_);
// Setup a fake wrapped EK certificate by default.
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[DEFAULT_ACA]
.set_wrapping_key_id("default");
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[TEST_ACA]
.set_wrapping_key_id("test");
EXPECT_CALL(mock_tpm_utility_, IsPCR0Valid()).WillRepeatedly(Return(true));
// Run out initialize task(s) to avoid any race conditions with tests that
// need to change the default setup.
CHECK(
CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
}
protected:
void Run() { run_loop_.Run(); }
void RunUntilIdle() { run_loop_.RunUntilIdle(); }
void Quit() { run_loop_.Quit(); }
base::Closure QuitClosure() { return run_loop_.QuitClosure(); }
template <typename T>
T CallAndWait(
base::OnceCallback<T(AttestationService::InitializeCompleteCallback)>
func) {
base::WaitableEvent done(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
T val = std::move(func).Run(
base::BindOnce([](base::WaitableEvent* done, bool) { done->Signal(); },
base::Unretained(&done)));
done.Wait();
return val;
}
void SetUpIdentity(int identity) {
auto* database = mock_database_.GetMutableProtobuf();
AttestationDatabase::Identity* identity_data;
if (database->identities().size() > identity) {
identity_data = database->mutable_identities()->Mutable(identity);
} else {
for (int i = database->identities().size(); i <= identity; ++i) {
identity_data = database->mutable_identities()->Add();
}
}
identity_data->set_features(IDENTITY_FEATURE_ENTERPRISE_ENROLLMENT_ID);
identity_data->mutable_identity_key()->set_identity_public_key_der(
"public_key");
identity_data->mutable_identity_binding()
->set_identity_public_key_tpm_format("public_key_tpm");
(*identity_data->mutable_pcr_quotes())[0].set_quote("pcr0");
(*identity_data->mutable_pcr_quotes())[1].set_quote("pcr1");
#if USE_TPM2
(*identity_data->mutable_nvram_quotes())[BOARD_ID].set_quote("board_id");
(*identity_data->mutable_nvram_quotes())[SN_BITS].set_quote("sn_bits");
if (service_->GetEndorsementKeyType() != KEY_TYPE_RSA) {
(*identity_data->mutable_nvram_quotes())[RSA_PUB_EK_CERT].set_quote(
"rsa_pub_ek_cert");
}
#endif
}
// Generate a unique name for a certificate from an ACA.
std::string GetCertificateName(int identity, ACAType aca_type) {
std::ostringstream stream;
stream << "certificate(" << identity << ", " << aca_type << ")";
return stream.str();
}
// Create an identity certificate if needed and sets an ACA-signed
// certificate. Once this exists, we consider that the identity has been
// enrolled with the given ACA.
void SetUpIdentityCertificate(int identity, ACAType aca_type) {
auto identity_certificate = service_->FindOrCreateIdentityCertificate(
identity, aca_type, nullptr /* cert_index */);
EXPECT_NE(nullptr, identity_certificate);
identity_certificate->set_identity_credential(
GetCertificateName(identity, aca_type));
}
CertifiedKey GenerateFakeCertifiedKey() const {
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);
return key;
}
std::string GenerateSerializedFakeCertifiedKey() const {
CertifiedKey key = GenerateFakeCertifiedKey();
return key.SerializeAsString();
}
void ExpectGetCustomerId(std::string customer_id) {
EXPECT_CALL(*mock_policy_provider_, Reload()).WillOnce(Return(true));
EXPECT_CALL(*mock_policy_provider_, device_policy_is_loaded())
.WillOnce(Return(true));
EXPECT_CALL(*mock_policy_provider_, GetDevicePolicy())
.WillOnce(ReturnRef(mock_device_policy_));
EXPECT_CALL(mock_device_policy_, GetCustomerId(_))
.WillOnce(DoAll(SetArgPointee<0>(customer_id), Return(true)));
}
// Verify Attestation CA-related data, including the default CA's identity
// credential.
void VerifyACAData(const AttestationDatabase& db,
const char* default_identity_credential) {
ASSERT_EQ(default_identity_credential ? 1 : 0,
db.identity_certificates().size());
for (int aca = 0; aca < db.identity_certificates().size(); ++aca) {
const AttestationDatabase::IdentityCertificate identity_certificate =
db.identity_certificates().at(aca);
ASSERT_EQ(0, identity_certificate.identity());
ASSERT_EQ(aca, identity_certificate.aca());
if (default_identity_credential && aca == DEFAULT_ACA) {
ASSERT_EQ(default_identity_credential,
identity_certificate.identity_credential());
} else {
ASSERT_FALSE(identity_certificate.has_identity_credential());
}
}
// All ACAs have encrypted credentials.
for (int aca = AttestationService::kDefaultACA;
aca < AttestationService::kMaxACATypeInternal; ++aca) {
AttestationService::ACATypeInternal aca_int =
static_cast<AttestationService::ACATypeInternal>(aca);
ASSERT_TRUE(db.credentials().encrypted_endorsement_credentials().count(
AttestationService::GetACAType(aca_int)));
}
}
// Verify Attestation CA-related data, including the lack of default CA's
// identity credential.
void VerifyACAData(const AttestationDatabase& db) {
VerifyACAData(db, nullptr);
}
std::string ComputeEnterpriseEnrollmentId() {
return service_->ComputeEnterpriseEnrollmentId();
}
std::string GetEnrollmentId() {
GetEnrollmentIdRequest request;
auto result = std::make_shared<GetEnrollmentIdReply>();
service_->GetEnrollmentIdTask(request, result);
if (result->status() != STATUS_SUCCESS) {
return "";
}
return result->enrollment_id();
}
NiceMock<MockCryptoUtility> mock_crypto_utility_;
NiceMock<MockDatabase> mock_database_;
NiceMock<MockKeyStore> mock_key_store_;
NiceMock<MockTpmUtility> mock_tpm_utility_;
StrictMock<policy::MockPolicyProvider>* mock_policy_provider_; // Not Owned.
StrictMock<policy::MockDevicePolicy> mock_device_policy_;
StrictMock<pca_agent::client::FakePcaAgentProxy> fake_pca_agent_proxy_{
kTpmVersionUnderTest};
std::unique_ptr<AttestationService> service_;
const int identity_ = AttestationService::kFirstIdentity;
private:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY};
base::RunLoop run_loop_;
};
TEST_F(AttestationServiceBaseTest, MigrateAttestationDatabase) {
// Simulate an older database.
auto* db = mock_database_.GetMutableProtobuf();
db->mutable_credentials()->clear_encrypted_endorsement_credentials();
db->mutable_credentials()->set_endorsement_credential("endorsement_cred");
EncryptedData default_encrypted_endorsement_credential;
default_encrypted_endorsement_credential.set_wrapped_key("default_key");
db->mutable_credentials()
->mutable_default_encrypted_endorsement_credential()
->CopyFrom(default_encrypted_endorsement_credential);
db->clear_identities();
db->clear_identity_certificates();
db->mutable_identity_binding()->set_identity_binding("identity_binding");
db->mutable_identity_binding()->set_identity_public_key_tpm_format(
"identity_public_key");
db->mutable_identity_key()->set_identity_credential("identity_cred");
db->mutable_pcr0_quote()->set_quote("pcr0_quote");
db->mutable_pcr1_quote()->set_quote("pcr1_quote");
// Persist that older database.
mock_database_.SaveChanges();
// Simulate login.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
service_->PrepareForEnrollment(base::DoNothing());
const auto& const_db = mock_database_.GetProtobuf();
// The default encrypted endorsement credential has been migrated.
// The deprecated field has not been cleared so that older code can still
// use the database.
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.encrypted_endorsement_credentials()
.at(DEFAULT_ACA)
.wrapped_key());
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.default_encrypted_endorsement_credential()
.wrapped_key());
// The default identity has data copied from the deprecated database fields.
// The deprecated fields have not been cleared so that older code can still
// use the database.
const AttestationDatabase::Identity& default_identity_data =
const_db.identities().Get(DEFAULT_ACA);
EXPECT_EQ(IDENTITY_FEATURE_ENTERPRISE_ENROLLMENT_ID,
default_identity_data.features());
EXPECT_EQ("identity_binding",
default_identity_data.identity_binding().identity_binding());
EXPECT_EQ("identity_public_key", default_identity_data.identity_binding()
.identity_public_key_tpm_format());
EXPECT_EQ("identity_binding", const_db.identity_binding().identity_binding());
EXPECT_EQ("identity_public_key",
const_db.identity_binding().identity_public_key_tpm_format());
EXPECT_EQ("pcr0_quote", default_identity_data.pcr_quotes().at(0).quote());
EXPECT_EQ("pcr0_quote", const_db.pcr0_quote().quote());
EXPECT_EQ("pcr1_quote", default_identity_data.pcr_quotes().at(1).quote());
EXPECT_EQ("pcr1_quote", const_db.pcr1_quote().quote());
// No other identity has been created.
EXPECT_EQ(1, const_db.identities().size());
// The identity credential was migrated into an identity certificate.
// As a result, identity data does not use the identity credential. The
// deprecated field has not been cleared so that older code can still
// use the database.
EXPECT_FALSE(default_identity_data.identity_key().has_identity_credential());
EXPECT_EQ("identity_cred", const_db.identity_key().identity_credential());
VerifyACAData(const_db, "identity_cred");
}
TEST_F(AttestationServiceBaseTest,
MigrateAttestationDatabaseWithCorruptedFields) {
// Simulate an older database.
auto* db = mock_database_.GetMutableProtobuf();
db->mutable_credentials()->clear_encrypted_endorsement_credentials();
db->mutable_credentials()->set_endorsement_credential("endorsement_cred");
EncryptedData default_encrypted_endorsement_credential;
default_encrypted_endorsement_credential.set_wrapped_key("default_key");
db->mutable_credentials()
->mutable_default_encrypted_endorsement_credential()
->CopyFrom(default_encrypted_endorsement_credential);
db->clear_identities();
db->clear_identity_certificates();
db->mutable_identity_binding()->set_identity_binding("identity_binding");
db->mutable_identity_binding()->set_identity_public_key_tpm_format(
"identity_public_key");
db->mutable_identity_key()->set_identity_credential("identity_cred");
// Note that we are missing a PCR0 quote.
db->mutable_pcr1_quote()->set_quote("pcr1_quote");
// Persist that older database.
mock_database_.SaveChanges();
// Simulate login.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
service_->PrepareForEnrollment(base::DoNothing());
const auto& const_db = mock_database_.GetProtobuf();
// The default encrypted endorsement credential has been migrated.
// The deprecated field has not been cleared so that older code can still
// use the database.
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.encrypted_endorsement_credentials()
.at(DEFAULT_ACA)
.wrapped_key());
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.default_encrypted_endorsement_credential()
.wrapped_key());
// The default identity could not be copied from the deprecated database.
// The deprecated fields have not been cleared so that older code can still
// use the database.
ASSERT_TRUE(const_db.identities().empty());
ASSERT_EQ("identity_binding", const_db.identity_binding().identity_binding());
ASSERT_EQ("identity_public_key",
const_db.identity_binding().identity_public_key_tpm_format());
EXPECT_EQ("pcr1_quote", const_db.pcr1_quote().quote());
// There is no identity certificate since there is no identity.
ASSERT_TRUE(const_db.identity_certificates().empty());
}
TEST_F(AttestationServiceBaseTest,
MigrateAttestationDatabaseAllEndorsementCredentials) {
// Simulate an older database.
auto* db = mock_database_.GetMutableProtobuf();
db->mutable_credentials()->clear_encrypted_endorsement_credentials();
db->mutable_credentials()->set_endorsement_credential("endorsement_cred");
EncryptedData default_encrypted_endorsement_credential;
default_encrypted_endorsement_credential.set_wrapped_key("default_key");
db->mutable_credentials()
->mutable_default_encrypted_endorsement_credential()
->CopyFrom(default_encrypted_endorsement_credential);
EncryptedData test_encrypted_endorsement_credential;
test_encrypted_endorsement_credential.set_wrapped_key("test_key");
db->mutable_credentials()
->mutable_test_encrypted_endorsement_credential()
->CopyFrom(test_encrypted_endorsement_credential);
db->clear_identities();
db->clear_identity_certificates();
db->mutable_identity_binding()->set_identity_binding("identity_binding");
db->mutable_identity_binding()->set_identity_public_key_tpm_format(
"identity_public_key");
db->mutable_identity_key()->set_identity_credential("identity_cred");
db->mutable_pcr0_quote()->set_quote("pcr0_quote");
db->mutable_pcr1_quote()->set_quote("pcr1_quote");
// Persist that older database.
mock_database_.SaveChanges();
// Simulate second login.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
service_->PrepareForEnrollment(base::DoNothing());
const auto& const_db = mock_database_.GetProtobuf();
// The encrypted endorsement credentials have both been migrated.
// The deprecated fields have not been cleared so that older code can still
// use the database.
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.encrypted_endorsement_credentials()
.at(DEFAULT_ACA)
.wrapped_key());
EXPECT_EQ(default_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.default_encrypted_endorsement_credential()
.wrapped_key());
EXPECT_EQ(test_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.encrypted_endorsement_credentials()
.at(TEST_ACA)
.wrapped_key());
EXPECT_EQ(test_encrypted_endorsement_credential.wrapped_key(),
const_db.credentials()
.test_encrypted_endorsement_credential()
.wrapped_key());
}
TEST_F(AttestationServiceBaseTest, GetEndorsementInfoNoInfo) {
EXPECT_CALL(mock_tpm_utility_, GetEndorsementPublicKey(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const GetEndorsementInfoReply& reply) {
EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status());
EXPECT_FALSE(reply.has_ek_public_key());
EXPECT_FALSE(reply.has_ek_certificate());
quit_closure.Run();
};
GetEndorsementInfoRequest request;
service_->GetEndorsementInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, GetEndorsementInfoNoCert) {
EXPECT_CALL(mock_tpm_utility_, GetEndorsementCertificate(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const GetEndorsementInfoReply& reply) {
EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status());
EXPECT_FALSE(reply.has_ek_public_key());
EXPECT_FALSE(reply.has_ek_certificate());
quit_closure.Run();
};
GetEndorsementInfoRequest request;
service_->GetEndorsementInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, 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(SetArgPointee<2>(key_bytes), Return(true)));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
GetKeyInfoRequest request;
request.set_key_label("label");
request.set_username("user");
service_->GetKeyInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, 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 = [](const base::Closure& quit_closure,
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_closure.Run();
};
GetKeyInfoRequest request;
request.set_key_label("label");
service_->GetKeyInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, GetKeyInfoNoKey) {
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const GetKeyInfoReply& reply) {
EXPECT_EQ(STATUS_INVALID_PARAMETER, reply.status());
quit_closure.Run();
};
GetKeyInfoRequest request;
request.set_key_label("label");
request.set_username("user");
service_->GetKeyInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, GetKeyInfoBadPublicKey) {
EXPECT_CALL(mock_crypto_utility_, GetRSASubjectPublicKeyInfo(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const GetKeyInfoReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
GetKeyInfoRequest request;
request.set_key_label("label");
request.set_username("user");
service_->GetKeyInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, GetEndorsementKeyTypeForExistingKey) {
AttestationDatabase* database = mock_database_.GetMutableProtobuf();
// Default key type is KEY_TYPE_RSA.
database->mutable_credentials()->set_endorsement_public_key("public_key");
database->mutable_credentials()->set_endorsement_credential("certificate");
EXPECT_EQ(service_->GetEndorsementKeyType(), KEY_TYPE_RSA);
database->mutable_credentials()->set_endorsement_key_type(KEY_TYPE_ECC);
database->mutable_credentials()->set_endorsement_public_key("public_key");
database->mutable_credentials()->set_endorsement_credential("certificate");
EXPECT_EQ(service_->GetEndorsementKeyType(), KEY_TYPE_ECC);
}
TEST_F(AttestationServiceBaseTest,
GetEndorsementKeyTypeForNewlyCreatedKeyInTpm2) {
EXPECT_CALL(mock_tpm_utility_, GetVersion()).WillRepeatedly(Return(TPM_2_0));
EXPECT_EQ(service_->GetEndorsementKeyType(), KEY_TYPE_ECC);
}
TEST_F(AttestationServiceBaseTest,
GetEndorsementKeyTypeForNewlyCreatedKeyInTpm12) {
EXPECT_CALL(mock_tpm_utility_, GetVersion()).WillRepeatedly(Return(TPM_1_2));
EXPECT_EQ(service_->GetEndorsementKeyType(), KEY_TYPE_RSA);
}
TEST_F(AttestationServiceBaseTest, GetAttestationIdentityKeyTypeInTpm2) {
EXPECT_CALL(mock_tpm_utility_, GetVersion()).WillRepeatedly(Return(TPM_2_0));
EXPECT_EQ(service_->GetAttestationIdentityKeyType(), KEY_TYPE_ECC);
}
TEST_F(AttestationServiceBaseTest, GetAttestationIdentityKeyTypeInTpm12) {
EXPECT_CALL(mock_tpm_utility_, GetVersion()).WillRepeatedly(Return(TPM_1_2));
EXPECT_EQ(service_->GetAttestationIdentityKeyType(), KEY_TYPE_RSA);
}
TEST_F(AttestationServiceBaseTest, 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 = [](const base::Closure& quit_closure,
const GetEndorsementInfoReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ("public_key", reply.ek_public_key());
EXPECT_EQ("certificate", reply.ek_certificate());
quit_closure.Run();
};
GetEndorsementInfoRequest request;
service_->GetEndorsementInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, GetEnrollmentId) {
EXPECT_CALL(mock_tpm_utility_, GetEndorsementPublicKeyModulus(_, _))
.WillRepeatedly(
DoAll(SetArgPointee<1>(std::string("ekm")), Return(true)));
brillo::SecureBlob abe_data(0xCA, 32);
service_->set_abe_data(&abe_data);
CryptoUtilityImpl crypto_utility(&mock_tpm_utility_);
service_->set_crypto_utility(&crypto_utility);
std::string enrollment_id = GetEnrollmentId();
EXPECT_EQ("635c4526dfa583362273e2987944007b09131cfa0f4e5874e7a76d55d333e3cc",
base::ToLowerASCII(
base::HexEncode(enrollment_id.data(), enrollment_id.size())));
// Cache the EID in the database.
AttestationDatabase database_pb;
database_pb.set_enrollment_id(enrollment_id);
EXPECT_CALL(mock_database_, GetProtobuf()).WillOnce(ReturnRef(database_pb));
// Change abe_data, and yet the EID remains the same.
brillo::SecureBlob abe_data_new(0x89, 32);
service_->set_abe_data(&abe_data_new);
enrollment_id = GetEnrollmentId();
EXPECT_EQ("635c4526dfa583362273e2987944007b09131cfa0f4e5874e7a76d55d333e3cc",
base::ToLowerASCII(
base::HexEncode(enrollment_id.data(), enrollment_id.size())));
}
TEST_F(AttestationServiceBaseTest, SignSimpleChallengeSuccess) {
EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _))
.WillRepeatedly(
DoAll(SetArgPointee<2>(std::string("signature")), Return(true)));
auto callback = [](const base::Closure& quit_closure,
const SignSimpleChallengeReply& 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());
EXPECT_EQ(0, signed_data.data().find("challenge"));
EXPECT_NE("challenge", signed_data.data());
quit_closure.Run();
};
SignSimpleChallengeRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_challenge("challenge");
service_->SignSimpleChallenge(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_F(AttestationServiceBaseTest, SignSimpleChallengeInternalFailure) {
EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false));
auto callback = [](const base::Closure& quit_closure,
const SignSimpleChallengeReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_challenge_response());
quit_closure.Run();
};
SignSimpleChallengeRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_challenge("challenge");
service_->SignSimpleChallenge(request, base::Bind(callback, QuitClosure()));
Run();
}
class AttestationServiceEnterpriseTest
: public AttestationServiceBaseTest,
public testing::WithParamInterface<VAType> {
public:
AttestationServiceEnterpriseTest() : va_type_(GetParam()) {}
~AttestationServiceEnterpriseTest() override = default;
protected:
VAType va_type_;
// A default GoogleKeys instance that is supposed to be the identical key
// database that |service_| uses.
GoogleKeys google_keys_;
};
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(
_, google_keys_.va_signing_key(va_type_).modulus_in_hex(), _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(
mock_crypto_utility_,
EncryptDataForGoogle(
key_info_str,
google_keys_.va_encryption_key(va_type_).modulus_in_hex(), _, _))
.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 = [](const base::Closure& quit_closure,
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_closure.Run();
};
SignEnterpriseChallengeRequest request;
request.set_va_type(va_type_);
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, QuitClosure()));
Run();
}
TEST_P(AttestationServiceEnterpriseTest,
SignEnterpriseChallengeInternalFailure) {
KeyInfo key_info = CreateChallengeKeyInfo();
std::string key_info_str;
key_info.SerializeToString(&key_info_str);
EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(_, _, _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false));
auto callback = [](const base::Closure& quit_closure,
const SignEnterpriseChallengeReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_challenge_response());
quit_closure.Run();
};
SignEnterpriseChallengeRequest request;
request.set_va_type(va_type_);
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, QuitClosure()));
Run();
}
TEST_P(AttestationServiceEnterpriseTest, SignEnterpriseChallengeBadPrefix) {
KeyInfo key_info = CreateChallengeKeyInfo();
std::string key_info_str;
key_info.SerializeToString(&key_info_str);
EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(_, _, _, _))
.WillRepeatedly(Return(true));
auto callback = [](const base::Closure& quit_closure,
const SignEnterpriseChallengeReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_challenge_response());
quit_closure.Run();
};
SignEnterpriseChallengeRequest request;
request.set_va_type(va_type_);
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("bad_prefix"));
service_->SignEnterpriseChallenge(request,
base::Bind(callback, QuitClosure()));
Run();
}
// Test that if |key_name_for_spkac| is not empty then the key associated to it
// is used for SignedPublicKeyAndChallenge.
TEST_P(AttestationServiceEnterpriseTest,
SignEnterpriseChallengeUseKeyForSPKAC) {
static const char kKeyNameForSpkac[] = "attest-ent-machine_temp_id";
static const char kKeyNameForSpkacPublicKey[] =
"attest-ent-machine_public_key";
CertifiedKey& key = *mock_database_.GetMutableProtobuf()->add_device_keys();
key.set_public_key("public_key");
key.set_key_name("label");
// Create a machine key for SPKAC
CertifiedKey& key_for_spkac =
*mock_database_.GetMutableProtobuf()->add_device_keys();
key_for_spkac.set_key_blob("key_blob");
key_for_spkac.set_public_key(kKeyNameForSpkacPublicKey);
key_for_spkac.set_key_name(kKeyNameForSpkac);
key_for_spkac.set_certified_key_credential("fake_cert_data");
KeyInfo expected_key_info =
CreateMachineChallengeKeyInfoWithSPKAC("fake_cert_data", "fake_spkac");
std::string expected_key_info_str;
expected_key_info.SerializeToString(&expected_key_info_str);
ExpectGetCustomerId("customer_id");
EXPECT_CALL(
mock_crypto_utility_,
VerifySignatureUsingHexKey(
_, google_keys_.va_signing_key(va_type_).modulus_in_hex(), _, _))
.WillOnce(Return(true));
EXPECT_CALL(
mock_crypto_utility_,
EncryptDataForGoogle(
expected_key_info_str,
google_keys_.va_encryption_key(va_type_).modulus_in_hex(), _, _))
.WillOnce(
DoAll(SetArgPointee<3>(MockEncryptedData(expected_key_info_str)),
Return(true)));
// Expect |CreateSPKAC| to be called for |key_name_for_spkac|.
EXPECT_CALL(
mock_crypto_utility_,
CreateSPKAC(key_for_spkac.key_blob(), key_for_spkac.public_key(), _, _))
.WillOnce(
DoAll(SetArgPointee<3>(std::string("fake_spkac")), Return(true)));
EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _))
.WillOnce(
DoAll(SetArgPointee<2>(std::string("signature")), Return(true)));
auto callback = [](const std::string& expected_key_info_str,
const base::Closure& quit_closure,
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()));
// This relies on the fact that the mock for EncryptDataForGoogle just
// passes the data unencrypted.
EXPECT_EQ(expected_key_info_str,
response_pb.encrypted_key_info().encrypted_data());
quit_closure.Run();
};
SignEnterpriseChallengeRequest request;
request.set_va_type(va_type_);
request.set_key_label("label");
request.set_domain("to_be_ignored");
request.set_device_id(expected_key_info.device_id());
request.set_include_signed_public_key(true);
request.set_key_name_for_spkac(kKeyNameForSpkac);
request.set_challenge(CreateSignedChallenge("EnterpriseKeyChallenge"));
service_->SignEnterpriseChallenge(
request, base::Bind(callback, expected_key_info_str, QuitClosure()));
Run();
}
INSTANTIATE_TEST_SUITE_P(VerifiedAccessType,
AttestationServiceEnterpriseTest,
::testing::Values(DEFAULT_VA, TEST_VA));
class AttestationServiceTest : public AttestationServiceBaseTest,
public testing::WithParamInterface<ACAType> {
public:
AttestationServiceTest() : aca_type_(GetParam()) {}
~AttestationServiceTest() override = default;
void SetUp() override { AttestationServiceBaseTest::SetUp(); }
protected:
std::string CreateCAEnrollResponse(bool success) {
AttestationEnrollmentResponse response_pb;
if (success) {
response_pb.set_status(OK);
response_pb.set_detail("");
response_pb.mutable_encrypted_identity_credential()->set_tpm_version(
kTpmVersionUnderTest);
response_pb.mutable_encrypted_identity_credential()->set_asym_ca_contents(
"1234");
response_pb.mutable_encrypted_identity_credential()
->set_sym_ca_attestation("5678");
response_pb.mutable_encrypted_identity_credential()->set_encrypted_seed(
"seed");
response_pb.mutable_encrypted_identity_credential()->set_credential_mac(
"mac");
response_pb.mutable_encrypted_identity_credential()
->mutable_wrapped_certificate()
->set_wrapped_key("wrapped");
} else {
response_pb.set_status(SERVER_ERROR);
response_pb.set_detail("fake_enroll_error");
}
std::string response_str;
response_pb.SerializeToString(&response_str);
return response_str;
}
std::string CreateCACertResponse(bool success, std::string message_id) {
AttestationCertificateResponse response_pb;
if (success) {
response_pb.set_status(OK);
response_pb.set_detail("");
response_pb.set_message_id(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";
} else {
response_pb.set_status(SERVER_ERROR);
response_pb.set_message_id(message_id);
response_pb.set_detail("fake_sign_error");
}
std::string response_str;
response_pb.SerializeToString(&response_str);
return response_str;
}
AttestationCertificateRequest GenerateCACertRequest() {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, DEFAULT_ACA);
base::RunLoop loop;
auto callback = [](base::RunLoop* loop,
AttestationCertificateRequest* pca_request,
const CreateCertificateRequestReply& reply) {
pca_request->ParseFromString(reply.pca_request());
loop->Quit();
};
CreateCertificateRequestRequest request;
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
AttestationCertificateRequest pca_request;
service_->CreateCertificateRequest(
request, base::Bind(callback, &loop, &pca_request));
loop.Run();
return pca_request;
}
ACAType aca_type_;
};
TEST_P(AttestationServiceTest, GetAttestationKeyInfoSuccess) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
// Set expectations on the outputs.
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const GetAttestationKeyInfoReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ("public_key", reply.public_key());
EXPECT_EQ("public_key_tpm", reply.public_key_tpm_format());
EXPECT_EQ(cert_name, reply.certificate());
EXPECT_EQ("pcr0", reply.pcr0_quote().quote());
EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
quit_closure.Run();
};
GetAttestationKeyInfoRequest request;
request.set_aca_type(aca_type_);
service_->GetAttestationKeyInfo(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, GetAttestationKeyInfoNoInfo) {
SetUpIdentityCertificate(identity_, aca_type_);
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
GetAttestationKeyInfoRequest request;
request.set_aca_type(aca_type_);
service_->GetAttestationKeyInfo(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, GetAttestationKeyInfoSomeInfo) {
SetUpIdentity(identity_);
auto* identity_data =
mock_database_.GetMutableProtobuf()->mutable_identities()->Mutable(
identity_);
identity_data->mutable_identity_key()->clear_identity_public_key_der();
identity_data->mutable_identity_binding()
->clear_identity_public_key_tpm_format();
identity_data->mutable_pcr_quotes()->erase(0);
SetUpIdentityCertificate(identity_, aca_type_);
// Set expectations on the outputs.
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
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(cert_name, reply.certificate());
EXPECT_FALSE(reply.has_pcr0_quote());
EXPECT_EQ("pcr1", reply.pcr1_quote().quote());
quit_closure.Run();
};
GetAttestationKeyInfoRequest request;
request.set_aca_type(aca_type_);
service_->GetAttestationKeyInfo(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, ActivateAttestationKeySuccess) {
SetUpIdentity(identity_);
EXPECT_CALL(mock_database_, SaveChanges()).Times(1);
const std::string cert_name = GetCertificateName(identity_, aca_type_);
if (kTpmVersionUnderTest == TPM_1_2) {
EXPECT_CALL(mock_tpm_utility_,
ActivateIdentity(_, "encrypted1", "encrypted2", _))
.WillOnce(DoAll(SetArgPointee<3>(cert_name), Return(true)));
} else {
EXPECT_CALL(
mock_tpm_utility_,
ActivateIdentityForTpm2(KEY_TYPE_ECC, _, "seed", "mac", "wrapped", _))
.WillOnce(DoAll(SetArgPointee<5>(cert_name), Return(true)));
}
// Set expectations on the outputs.
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const ActivateAttestationKeyReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(cert_name, reply.certificate());
quit_closure.Run();
};
ActivateAttestationKeyRequest request;
request.set_aca_type(aca_type_);
request.mutable_encrypted_certificate()->set_tpm_version(
kTpmVersionUnderTest);
request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
request.mutable_encrypted_certificate()->set_encrypted_seed("seed");
request.mutable_encrypted_certificate()->set_credential_mac("mac");
request.mutable_encrypted_certificate()
->mutable_wrapped_certificate()
->set_wrapped_key("wrapped");
request.set_save_certificate(true);
service_->ActivateAttestationKey(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, ActivateAttestationKeySuccessNoSave) {
SetUpIdentity(identity_);
EXPECT_CALL(mock_database_, GetMutableProtobuf()).Times(0);
EXPECT_CALL(mock_database_, SaveChanges()).Times(0);
const std::string cert_name = GetCertificateName(identity_, aca_type_);
if (kTpmVersionUnderTest == TPM_1_2) {
EXPECT_CALL(mock_tpm_utility_,
ActivateIdentity(_, "encrypted1", "encrypted2", _))
.WillOnce(DoAll(SetArgPointee<3>(cert_name), Return(true)));
} else {
EXPECT_CALL(
mock_tpm_utility_,
ActivateIdentityForTpm2(KEY_TYPE_ECC, _, "seed", "mac", "wrapped", _))
.WillOnce(DoAll(SetArgPointee<5>(cert_name), Return(true)));
}
// Set expectations on the outputs.
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const ActivateAttestationKeyReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(cert_name, reply.certificate());
quit_closure.Run();
};
ActivateAttestationKeyRequest request;
request.set_aca_type(aca_type_);
request.mutable_encrypted_certificate()->set_tpm_version(
kTpmVersionUnderTest);
request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
request.mutable_encrypted_certificate()->set_encrypted_seed("seed");
request.mutable_encrypted_certificate()->set_credential_mac("mac");
request.mutable_encrypted_certificate()
->mutable_wrapped_certificate()
->set_wrapped_key("wrapped");
service_->ActivateAttestationKey(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, ActivateAttestationKeySaveFailure) {
SetUpIdentity(identity_);
EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const ActivateAttestationKeyReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
ActivateAttestationKeyRequest request;
request.set_aca_type(aca_type_);
request.mutable_encrypted_certificate()->set_tpm_version(
kTpmVersionUnderTest);
request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
request.mutable_encrypted_certificate()->set_encrypted_seed("seed");
request.mutable_encrypted_certificate()->set_credential_mac("mac");
request.mutable_encrypted_certificate()
->mutable_wrapped_certificate()
->set_wrapped_key("wrapped");
request.set_save_certificate(true);
service_->ActivateAttestationKey(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, ActivateAttestationKeyActivateFailure) {
SetUpIdentity(identity_);
if (kTpmVersionUnderTest == TPM_1_2) {
EXPECT_CALL(mock_tpm_utility_,
ActivateIdentity(_, "encrypted1", "encrypted2", _))
.WillRepeatedly(Return(false));
} else {
EXPECT_CALL(
mock_tpm_utility_,
ActivateIdentityForTpm2(KEY_TYPE_ECC, _, "seed", "mac", "wrapped", _))
.WillRepeatedly(Return(false));
}
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const ActivateAttestationKeyReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
ActivateAttestationKeyRequest request;
request.set_aca_type(aca_type_);
request.mutable_encrypted_certificate()->set_tpm_version(
kTpmVersionUnderTest);
request.mutable_encrypted_certificate()->set_asym_ca_contents("encrypted1");
request.mutable_encrypted_certificate()->set_sym_ca_attestation("encrypted2");
request.mutable_encrypted_certificate()->set_encrypted_seed("seed");
request.mutable_encrypted_certificate()->set_credential_mac("mac");
request.mutable_encrypted_certificate()
->mutable_wrapped_certificate()
->set_wrapped_key("wrapped");
request.set_save_certificate(true);
service_->ActivateAttestationKey(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeySuccess) {
// We need an identity to create a certifiable key.
SetUpIdentity(identity_);
// Configure a fake TPM response.
EXPECT_CALL(
mock_tpm_utility_,
CreateCertifiedKey(KEY_TYPE_RSA, KEY_USAGE_SIGN, _, _, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(std::string("public_key")),
SetArgPointee<7>(std::string("certify_info")),
SetArgPointee<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 = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
request.set_username("user");
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeySuccessNoUser) {
// We need an identity to create a certifiable key.
SetUpIdentity(identity_);
// Configure a fake TPM response.
EXPECT_CALL(
mock_tpm_utility_,
CreateCertifiedKey(KEY_TYPE_RSA, KEY_USAGE_SIGN, _, _, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<5>(std::string("public_key")),
SetArgPointee<7>(std::string("certify_info")),
SetArgPointee<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 = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeyRNGFailure) {
// We need an identity to make sure it didn't fail because of that.
SetUpIdentity(identity_);
EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeyNoIdentityFailure) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeyTpmCreateFailure) {
// We need an identity to create a certifiable key.
SetUpIdentity(identity_);
EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeyDBFailure) {
// We need an identity to make sure it didn't fail because of that.
SetUpIdentity(identity_);
EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
request.set_username("username");
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertifiableKeyDBFailureNoUser) {
// We need an identity to make sure it didn't fail because of that.
SetUpIdentity(identity_);
EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
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_closure.Run();
};
CreateCertifiableKeyRequest request;
request.set_key_label("label");
request.set_key_type(KEY_TYPE_RSA);
request.set_key_usage(KEY_USAGE_SIGN);
service_->CreateCertifiableKey(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DecryptSuccess) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DecryptReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
reply.decrypted_data());
quit_closure.Run();
};
DecryptRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_encrypted_data("data");
service_->Decrypt(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DecryptSuccessNoUser) {
mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label");
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DecryptReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"),
reply.decrypted_data());
quit_closure.Run();
};
DecryptRequest request;
request.set_key_label("label");
request.set_encrypted_data("data");
service_->Decrypt(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DecryptKeyNotFound) {
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DecryptReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_decrypted_data());
quit_closure.Run();
};
DecryptRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_encrypted_data("data");
service_->Decrypt(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DecryptKeyNotFoundNoUser) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DecryptReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_decrypted_data());
quit_closure.Run();
};
DecryptRequest request;
request.set_key_label("label");
request.set_encrypted_data("data");
service_->Decrypt(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DecryptUnbindFailure) {
EXPECT_CALL(mock_tpm_utility_, Unbind(_, _, _)).WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DecryptReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_decrypted_data());
quit_closure.Run();
};
DecryptRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_encrypted_data("data");
service_->Decrypt(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, SignSuccess) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const SignReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
quit_closure.Run();
};
SignRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_data_to_sign("data");
service_->Sign(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, SignSuccessNoUser) {
mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label");
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const SignReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature());
quit_closure.Run();
};
SignRequest request;
request.set_key_label("label");
request.set_data_to_sign("data");
service_->Sign(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, SignKeyNotFound) {
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const SignReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_signature());
quit_closure.Run();
};
SignRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_data_to_sign("data");
service_->Sign(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, SignKeyNotFoundNoUser) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const SignReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_signature());
quit_closure.Run();
};
SignRequest request;
request.set_key_label("label");
request.set_data_to_sign("data");
service_->Sign(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, SignUnbindFailure) {
EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const SignReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_signature());
quit_closure.Run();
};
SignRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_data_to_sign("data");
service_->Sign(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(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(SetArgPointee<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", ""))
.Times(1);
EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _)).Times(0);
EXPECT_CALL(mock_key_store_, Delete("user", "label")).Times(1);
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(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", ""))
.Times(1);
EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _)).Times(0);
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure, Database* database,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(0, database->GetMutableProtobuf()->device_keys_size());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
service_->RegisterKeyWithChapsToken(
request, base::Bind(callback, QuitClosure(), &mock_database_));
Run();
}
TEST_P(AttestationServiceTest, RegisterSuccessWithCertificates) {
// 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(SetArgPointee<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 = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_include_certificates(true);
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, RegisterSuccessNoUserWithCertificates) {
// 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 = [](const base::Closure& quit_closure, Database* database,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(0, database->GetMutableProtobuf()->device_keys_size());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_include_certificates(true);
service_->RegisterKeyWithChapsToken(
request, base::Bind(callback, QuitClosure(), &mock_database_));
Run();
}
TEST_P(AttestationServiceTest, RegisterNoKey) {
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, RegisterNoKeyNoUser) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(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(SetArgPointee<2>(key_bytes), Return(true)));
EXPECT_CALL(mock_key_store_, Register(_, _, _, _, _, _, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(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(SetArgPointee<2>(key_bytes), Return(true)));
EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_include_certificates(true);
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(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(SetArgPointee<2>(key_bytes), Return(true)));
EXPECT_CALL(mock_key_store_, RegisterCertificate(_, _))
.WillRepeatedly(Return(false));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const RegisterKeyWithChapsTokenReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
RegisterKeyWithChapsTokenRequest request;
request.set_key_label("label");
request.set_username("user");
request.set_include_certificates(true);
service_->RegisterKeyWithChapsToken(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeysByLabelSuccess) {
// 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_, Delete("user", "label"))
.Times(1)
.WillOnce(Return(true));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
request.set_match_behavior(DeleteKeysRequest::MATCH_BEHAVIOR_EXACT);
request.set_username("user");
service_->DeleteKeys(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeyByLabelNoUserSuccess) {
// 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);
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure, Database* database,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(0, database->GetMutableProtobuf()->device_keys_size());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
request.set_match_behavior(DeleteKeysRequest::MATCH_BEHAVIOR_EXACT);
service_->DeleteKeys(request,
base::Bind(callback, QuitClosure(), &mock_database_));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeysByLabelNoKey) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
request.set_match_behavior(DeleteKeysRequest::MATCH_BEHAVIOR_EXACT);
request.set_username("user");
service_->DeleteKeys(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeyByLabelNoUserNoKey) {
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
request.set_match_behavior(DeleteKeysRequest::MATCH_BEHAVIOR_EXACT);
service_->DeleteKeys(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeysByPrefixSuccess) {
EXPECT_CALL(mock_key_store_, DeleteByPrefix("user", "label"))
.Times(1)
.WillOnce(Return(true));
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
request.set_username("user");
service_->DeleteKeys(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, DeleteKeyByPrefixNoUserSuccess) {
// Setup a key in the device_keys field.
const std::string key_labels[] = {"label1", "label2", "otherprefix"};
for (const auto& key_label : key_labels) {
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(key_label);
key.set_key_type(KEY_TYPE_RSA);
key.set_key_usage(KEY_USAGE_SIGN);
}
// Set expectations on the outputs.
auto callback = [](const base::Closure& quit_closure, Database* database,
const DeleteKeysReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_EQ(1, database->GetMutableProtobuf()->device_keys_size());
EXPECT_EQ("otherprefix",
database->GetMutableProtobuf()->device_keys()[0].key_name());
quit_closure.Run();
};
DeleteKeysRequest request;
request.set_key_label_match("label");
service_->DeleteKeys(request,
base::Bind(callback, QuitClosure(), &mock_database_));
Run();
}
TEST_P(AttestationServiceTest, PrepareForEnrollment) {
// Start with an empty database.
mock_database_.GetMutableProtobuf()->Clear();
// Schedule initialization again to make sure it runs after this point.
EXPECT_CALL(mock_tpm_utility_, GetNVDataSize(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(9487), Return(true)));
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
// One identity has been created.
EXPECT_EQ(1, mock_database_.GetProtobuf().identities().size());
const AttestationDatabase::Identity& identity_data =
mock_database_.GetProtobuf().identities().Get(0);
EXPECT_TRUE(identity_data.has_identity_binding());
EXPECT_TRUE(identity_data.has_identity_key());
EXPECT_EQ(1, identity_data.pcr_quotes().count(0));
EXPECT_EQ(1, identity_data.pcr_quotes().count(1));
#if USE_TPM2
EXPECT_EQ(1, identity_data.nvram_quotes().count(BOARD_ID));
EXPECT_EQ(1, identity_data.nvram_quotes().count(SN_BITS));
EXPECT_EQ(service_->GetEndorsementKeyType() != KEY_TYPE_RSA ? 1 : 0,
identity_data.nvram_quotes().count(RSA_PUB_EK_CERT));
#else
EXPECT_TRUE(identity_data.nvram_quotes().empty());
#endif
EXPECT_EQ(IDENTITY_FEATURE_ENTERPRISE_ENROLLMENT_ID,
identity_data.features());
// Deprecated identity-related values have not been set.
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_key());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_binding());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr0_quote());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr1_quote());
// Verify Privacy CA-related data.
VerifyACAData(mock_database_.GetProtobuf());
// These deprecated fields have not been set either.
EXPECT_TRUE(mock_database_.GetProtobuf().has_credentials());
EXPECT_FALSE(mock_database_.GetProtobuf()
.credentials()
.has_default_encrypted_endorsement_credential());
}
#if USE_TPM2
TEST_P(AttestationServiceTest,
PrepareForEnrollmentCannotQuoteOptionalNvramForRsaEK) {
auto database_pb = mock_database_.GetMutableProtobuf();
// Start with an empty database to trigger PrepareForEnrollment.
database_pb->Clear();
// Setup the database to make GetEndorsementKeyType to return specific key
// type, but will still make IsPreparedForEnrollment return false.
database_pb->mutable_credentials()->set_endorsement_key_type(KEY_TYPE_RSA);
database_pb->mutable_credentials()->set_endorsement_public_key("pubkey");
EXPECT_CALL(mock_tpm_utility_, CertifyNV(_, _, _, _, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
// One identity has been created.
EXPECT_EQ(1, mock_database_.GetProtobuf().identities().size());
const AttestationDatabase::Identity& identity_data =
mock_database_.GetProtobuf().identities().Get(0);
EXPECT_TRUE(identity_data.has_identity_binding());
EXPECT_TRUE(identity_data.has_identity_key());
EXPECT_EQ(1, identity_data.pcr_quotes().count(0));
EXPECT_EQ(1, identity_data.pcr_quotes().count(1));
EXPECT_TRUE(identity_data.nvram_quotes().empty());
EXPECT_EQ(IDENTITY_FEATURE_ENTERPRISE_ENROLLMENT_ID,
identity_data.features());
}
TEST_P(AttestationServiceTest,
PrepareForEnrollmentCannotQuoteOptionalNvramForEccEK) {
auto database_pb = mock_database_.GetMutableProtobuf();
// Start with an empty database to trigger PrepareForEnrollment.
database_pb->Clear();
// Setup the database to make GetEndorsementKeyType to return specific key
// type, but will still make IsPreparedForEnrollment return false.
database_pb->mutable_credentials()->set_endorsement_key_type(KEY_TYPE_ECC);
database_pb->mutable_credentials()->set_endorsement_public_key("pubkey");
// Assume the NV indexes doesn't exist, except RSA EK cert which is required
// when ECC EK is enabled.
EXPECT_CALL(mock_tpm_utility_, GetNVDataSize(_, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(9487), Return(true)));
EXPECT_CALL(mock_tpm_utility_, CertifyNV(_, _, _, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_tpm_utility_,
CertifyNV(trunks::kRsaEndorsementCertificateIndex, _, _, _, _))
.WillRepeatedly(Return(true));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
// One identity has been created.
EXPECT_EQ(1, mock_database_.GetProtobuf().identities().size());
const AttestationDatabase::Identity& identity_data =
mock_database_.GetProtobuf().identities().Get(0);
EXPECT_TRUE(identity_data.has_identity_binding());
EXPECT_TRUE(identity_data.has_identity_key());
EXPECT_EQ(1, identity_data.pcr_quotes().count(0));
EXPECT_EQ(1, identity_data.pcr_quotes().count(1));
EXPECT_EQ(1, identity_data.nvram_quotes().size());
EXPECT_EQ(1, identity_data.nvram_quotes().count(RSA_PUB_EK_CERT));
EXPECT_EQ(IDENTITY_FEATURE_ENTERPRISE_ENROLLMENT_ID,
identity_data.features());
}
TEST_P(AttestationServiceTest,
PrepareForEnrollmentCannotQuoteRsaEKCertForEccEK) {
auto database_pb = mock_database_.GetMutableProtobuf();
// Start with an empty database to trigger PrepareForEnrollment.
database_pb->Clear();
// Setup the database to make GetEndorsementKeyType to return specific key
// type, but will still make IsPreparedForEnrollment return false.
database_pb->mutable_credentials()->set_endorsement_key_type(KEY_TYPE_ECC);
database_pb->mutable_credentials()->set_endorsement_public_key("pubkey");
EXPECT_CALL(mock_tpm_utility_, CertifyNV(_, _, _, _, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_key());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_binding());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr0_quote());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr1_quote());
}
#endif
TEST_P(AttestationServiceTest, PrepareForEnrollmentNoPublicKey) {
// Start with an empty database.
mock_database_.GetMutableProtobuf()->Clear();
EXPECT_CALL(mock_tpm_utility_, GetEndorsementPublicKey(_, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
EXPECT_FALSE(mock_database_.GetProtobuf().has_credentials());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_key());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_binding());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr0_quote());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr1_quote());
}
TEST_P(AttestationServiceTest, PrepareForEnrollmentNoCert) {
// Start with an empty database.
mock_database_.GetMutableProtobuf()->Clear();
EXPECT_CALL(mock_tpm_utility_, GetEndorsementCertificate(_, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
EXPECT_FALSE(mock_database_.GetProtobuf().has_credentials());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_key());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_binding());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr0_quote());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr1_quote());
}
TEST_P(AttestationServiceTest, PrepareForEnrollmentFailAIK) {
// Start with an empty database.
mock_database_.GetMutableProtobuf()->Clear();
EXPECT_CALL(mock_tpm_utility_, CreateIdentity(_, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
// No identity was created.
EXPECT_EQ(0, mock_database_.GetProtobuf().identities().size());
// And no credentials were stored.
EXPECT_FALSE(mock_database_.GetProtobuf().has_credentials());
}
TEST_P(AttestationServiceTest, PrepareForEnrollmentFailQuote) {
// Start with an empty database.
mock_database_.GetMutableProtobuf()->Clear();
EXPECT_CALL(mock_tpm_utility_, QuotePCR(_, _, _, _, _))
.WillRepeatedly(Return(false));
// Schedule initialization again to make sure it runs after this point.
CHECK(CallAndWait(base::BindOnce(&AttestationService::InitializeWithCallback,
base::Unretained(service_.get()))));
EXPECT_FALSE(mock_database_.GetProtobuf().has_credentials());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_key());
EXPECT_FALSE(mock_database_.GetProtobuf().has_identity_binding());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr0_quote());
EXPECT_FALSE(mock_database_.GetProtobuf().has_pcr1_quote());
}
TEST_P(AttestationServiceTest, ComputeEnterpriseEnrollmentId) {
EXPECT_CALL(mock_tpm_utility_, GetEndorsementPublicKeyModulus(_, _))
.WillRepeatedly(
DoAll(SetArgPointee<1>(std::string("ekm")), Return(true)));
brillo::SecureBlob abe_data(0xCA, 32);
service_->set_abe_data(&abe_data);
CryptoUtilityImpl crypto_utility(&mock_tpm_utility_);
service_->set_crypto_utility(&crypto_utility);
std::string enrollment_id = ComputeEnterpriseEnrollmentId();
EXPECT_EQ("635c4526dfa583362273e2987944007b09131cfa0f4e5874e7a76d55d333e3cc",
base::ToLowerASCII(
base::HexEncode(enrollment_id.data(), enrollment_id.size())));
}
TEST_P(AttestationServiceTest, CreateCertificateRequestSuccess) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationCertificateRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ(ENTERPRISE_MACHINE_CERTIFICATE, pca_request.profile());
EXPECT_TRUE(pca_request.nvram_quotes().empty());
EXPECT_EQ(cert_name, pca_request.identity_credential());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateEnrollmentCertificateRequestSuccess) {
#if USE_TPM2
EXPECT_CALL(mock_tpm_utility_,
CertifyNV(VIRTUAL_NV_INDEX_RSU_DEV_ID, _, _, _, _))
.WillRepeatedly(DoAll(SetArgPointee<3>("rsu_device_id_quoted_data"),
SetArgPointee<4>("rsu_device_id"), Return(true)));
#endif
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationCertificateRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ(ENTERPRISE_ENROLLMENT_CERTIFICATE, pca_request.profile());
#if USE_TPM2
EXPECT_EQ(3, pca_request.nvram_quotes().size());
EXPECT_EQ("board_id", pca_request.nvram_quotes().at(BOARD_ID).quote());
EXPECT_EQ("sn_bits", pca_request.nvram_quotes().at(SN_BITS).quote());
EXPECT_EQ("rsu_device_id",
pca_request.nvram_quotes().at(RSU_DEVICE_ID).quote());
EXPECT_EQ("rsu_device_id_quoted_data",
pca_request.nvram_quotes().at(RSU_DEVICE_ID).quoted_data());
#else
EXPECT_TRUE(pca_request.nvram_quotes().empty());
#endif
EXPECT_EQ(cert_name, pca_request.identity_credential());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_ENROLLMENT_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest,
CreateEnrollmentCertificateRequestSuccessWithUnattestedRsuDeviceId) {
#if USE_TPM2
EXPECT_CALL(mock_tpm_utility_,
CertifyNV(VIRTUAL_NV_INDEX_RSU_DEV_ID, _, _, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_tpm_utility_, GetRsuDeviceId(_))
.WillRepeatedly(DoAll(SetArgPointee<0>("rsu_device_id"), Return(true)));
#endif
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationCertificateRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ(ENTERPRISE_ENROLLMENT_CERTIFICATE, pca_request.profile());
#if USE_TPM2
EXPECT_EQ(2, pca_request.nvram_quotes().size());
EXPECT_EQ("board_id", pca_request.nvram_quotes().at(BOARD_ID).quote());
EXPECT_EQ("sn_bits", pca_request.nvram_quotes().at(SN_BITS).quote());
EXPECT_EQ(pca_request.nvram_quotes().end(),
pca_request.nvram_quotes().find(RSU_DEVICE_ID));
#else
EXPECT_TRUE(pca_request.nvram_quotes().empty());
#endif
EXPECT_EQ(cert_name, pca_request.identity_credential());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_ENROLLMENT_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest,
CreateEnrollmentCertificateRequestWithoutRsuDeviceIdSuccess) {
#if USE_TPM2
EXPECT_CALL(mock_tpm_utility_,
CertifyNV(VIRTUAL_NV_INDEX_RSU_DEV_ID, _, _, _, _))
.WillRepeatedly(Return(false));
EXPECT_CALL(mock_tpm_utility_, GetRsuDeviceId(_))
.WillRepeatedly(Return(false));
#endif
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const std::string& cert_name,
const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationCertificateRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ(ENTERPRISE_ENROLLMENT_CERTIFICATE, pca_request.profile());
#if USE_TPM2
EXPECT_EQ(2, pca_request.nvram_quotes().size());
EXPECT_EQ("board_id", pca_request.nvram_quotes().at(BOARD_ID).quote());
EXPECT_EQ("sn_bits", pca_request.nvram_quotes().at(SN_BITS).quote());
EXPECT_EQ(pca_request.nvram_quotes().find(RSU_DEVICE_ID),
pca_request.nvram_quotes().cend());
#else
EXPECT_TRUE(pca_request.nvram_quotes().empty());
#endif
EXPECT_EQ(cert_name, pca_request.identity_credential());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_ENROLLMENT_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(
request, base::Bind(callback, GetCertificateName(identity_, aca_type_),
QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertificateRequestInternalFailure) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _))
.WillRepeatedly(Return(false));
auto callback = [](const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_pca_request());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateCertificateRequestNotEnrolled) {
// No identiy certificate, so not enrolled.
mock_database_.GetMutableProtobuf()->Clear();
SetUpIdentity(identity_);
auto callback = [](const base::Closure& quit_closure,
const CreateCertificateRequestReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_pca_request());
quit_closure.Run();
};
CreateCertificateRequestRequest request;
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
service_->CreateCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, FinishCertificateRequestSuccess) {
auto callback = [](const base::Closure& quit_closure,
const FinishCertificateRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_certificate());
quit_closure.Run();
};
AttestationCertificateRequest pca_request = GenerateCACertRequest();
FinishCertificateRequestRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_pca_response(
CreateCACertResponse(true, pca_request.message_id()));
service_->FinishCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, FinishCertificateRequestInternalFailure) {
EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false));
auto callback = [](const base::Closure& quit_closure,
const FinishCertificateRequestReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_certificate());
quit_closure.Run();
};
AttestationCertificateRequest pca_request = GenerateCACertRequest();
FinishCertificateRequestRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_pca_response(
CreateCACertResponse(true, pca_request.message_id()));
service_->FinishCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, FinishCertificateRequestWrongMessageId) {
auto callback = [](const base::Closure& quit_closure,
const FinishCertificateRequestReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_certificate());
quit_closure.Run();
};
// Generate some request to populate pending_requests, but ignore its fields.
GenerateCACertRequest();
FinishCertificateRequestRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_pca_response(CreateCACertResponse(true, "wrong_id"));
service_->FinishCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, FinishCertificateRequestServerFailure) {
auto callback = [](const base::Closure& quit_closure,
const FinishCertificateRequestReply& reply) {
EXPECT_NE(STATUS_SUCCESS, reply.status());
EXPECT_FALSE(reply.has_certificate());
quit_closure.Run();
};
// Generate some request to populate pending_requests, but ignore its fields.
GenerateCACertRequest();
FinishCertificateRequestRequest request;
request.set_username("user");
request.set_key_label("label");
request.set_pca_response(CreateCACertResponse(false, ""));
service_->FinishCertificateRequest(request,
base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateEnrollRequestSuccessWithoutAbeData) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const CreateEnrollRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationEnrollmentRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ("wrapped_key",
pca_request.encrypted_endorsement_credential().wrapped_key());
EXPECT_EQ("public_key_tpm", pca_request.identity_public_key());
EXPECT_EQ("pcr0", pca_request.pcr0_quote().quote());
EXPECT_EQ("pcr1", pca_request.pcr1_quote().quote());
EXPECT_FALSE(pca_request.has_enterprise_enrollment_nonce());
quit_closure.Run();
};
CreateEnrollRequestRequest request;
request.set_aca_type(aca_type_);
service_->CreateEnrollRequest(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateEnrollRequestSuccessWithEmptyAbeData) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const CreateEnrollRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationEnrollmentRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ("wrapped_key",
pca_request.encrypted_endorsement_credential().wrapped_key());
EXPECT_EQ("public_key_tpm", pca_request.identity_public_key());
EXPECT_EQ("pcr0", pca_request.pcr0_quote().quote());
EXPECT_EQ("pcr1", pca_request.pcr1_quote().quote());
EXPECT_FALSE(pca_request.has_enterprise_enrollment_nonce());
quit_closure.Run();
};
brillo::SecureBlob abe_data;
service_->set_abe_data(&abe_data);
CreateEnrollRequestRequest request;
request.set_aca_type(aca_type_);
service_->CreateEnrollRequest(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, CreateEnrollRequestSuccessWithAbeData) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const CreateEnrollRequestReply& reply) {
EXPECT_EQ(STATUS_SUCCESS, reply.status());
EXPECT_TRUE(reply.has_pca_request());
AttestationEnrollmentRequest pca_request;
EXPECT_TRUE(pca_request.ParseFromString(reply.pca_request()));
EXPECT_EQ(kTpmVersionUnderTest, pca_request.tpm_version());
EXPECT_EQ("wrapped_key",
pca_request.encrypted_endorsement_credential().wrapped_key());
EXPECT_EQ("public_key_tpm", pca_request.identity_public_key());
EXPECT_EQ("pcr0", pca_request.pcr0_quote().quote());
EXPECT_EQ("pcr1", pca_request.pcr1_quote().quote());
EXPECT_TRUE(pca_request.has_enterprise_enrollment_nonce());
// Mocked CryptoUtility->HmacSha256 returns always a zeroed buffer.
EXPECT_EQ(std::string(32, '\0'), pca_request.enterprise_enrollment_nonce());
quit_closure.Run();
};
CreateEnrollRequestRequest request;
request.set_aca_type(aca_type_);
brillo::SecureBlob abe_data(0xCA, 32);
service_->set_abe_data(&abe_data);
service_->CreateEnrollRequest(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollSuccess) {
SetUpIdentity(identity_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_SUCCESS);
quit_closure.Run();
};
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(1);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollSuccessNoop) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_SUCCESS);
quit_closure.Run();
};
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(0);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollSuccessForced) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
(*mock_database_.GetMutableProtobuf()
->mutable_credentials()
->mutable_encrypted_endorsement_credentials())[aca_type_]
.set_wrapped_key("wrapped_key");
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_SUCCESS);
quit_closure.Run();
};
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(1);
EnrollRequest request;
request.set_aca_type(aca_type_);
request.set_forced(true);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollFailureNoIdentity) {
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_UNEXPECTED_DEVICE_ERROR);
quit_closure.Run();
};
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(0);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollFailureBadPcaAgentStatus) {
SetUpIdentity(identity_);
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_UNEXPECTED_DEVICE_ERROR);
quit_closure.Run();
};
fake_pca_agent_proxy_.SetEnrollDBusError();
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(1);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollFailureBadPcaAgentResponse) {
SetUpIdentity(identity_);
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_INVALID_PARAMETER);
quit_closure.Run();
};
fake_pca_agent_proxy_.SetBadEnrollStatus(STATUS_INVALID_PARAMETER);
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(1);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, EnrollFailureBadPcaServerResponse) {
SetUpIdentity(identity_);
auto callback = [](const base::Closure& quit_closure,
const EnrollReply& reply) {
EXPECT_EQ(reply.status(), STATUS_REQUEST_DENIED_BY_CA);
quit_closure.Run();
};
fake_pca_agent_proxy_.SetBadEnrollPcaResponse();
EXPECT_CALL(fake_pca_agent_proxy_, EnrollAsync(_, _, _, _)).Times(1);
EnrollRequest request;
request.set_aca_type(aca_type_);
service_->Enroll(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, GetCertificateSuccess) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const base::Closure& quit_closure,
const GetCertificateReply& reply) {
EXPECT_EQ(reply.status(), STATUS_SUCCESS);
EXPECT_TRUE(reply.has_certificate());
quit_closure.Run();
};
GetCertificateRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
request.set_key_label("label");
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillOnce(Return(false));
EXPECT_CALL(fake_pca_agent_proxy_, GetCertificateAsync(_, _, _, _)).Times(1);
service_->GetCertificate(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, GetCertificateSuccessNoop) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const base::Closure& quit_closure,
const GetCertificateReply& reply) {
EXPECT_EQ(reply.status(), STATUS_SUCCESS);
EXPECT_TRUE(reply.has_public_key());
EXPECT_TRUE(reply.has_certificate());
quit_closure.Run();
};
GetCertificateRequest request;
request.set_aca_type(aca_type_);
request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE);
request.set_username("user");
request.set_request_origin("origin");
request.set_key_label("label");
EXPECT_CALL(mock_key_store_, Read("user", "label", _))
.WillOnce(DoAll(SetArgPointee<2>(GenerateSerializedFakeCertifiedKey()),
Return(true)));
EXPECT_CALL(fake_pca_agent_proxy_, GetCertificateAsync(_, _, _, _)).Times(0);
service_->GetCertificate(request, base::Bind(callback, QuitClosure()));
Run();
}
TEST_P(AttestationServiceTest, GetCertificateSuccessSavedBadPublicKey) {
SetUpIdentity(identity_);
SetUpIdentityCertificate(identity_, aca_type_);
auto callback = [](const base::Closure& quit_closure,
const GetCertificateReply& reply) {
EXPECT_EQ(reply.status(), STATUS_UNEXPECTED_DEVICE_ERROR);
quit_closure.Run();
};
GetCertificateRequest request;
request.set_aca_type(aca_type_);
request.