| // 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_); |
| |