| // |
| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #include <string> |
| |
| #include <base/bind.h> |
| #include <base/callback.h> |
| #include <base/message_loop/message_loop.h> |
| #include <base/run_loop.h> |
| #include <brillo/bind_lambda.h> |
| #include <brillo/data_encoding.h> |
| #include <brillo/http/http_transport_fake.h> |
| #include <brillo/mime_utils.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "attestation/common/attestation_ca.pb.h" |
| #include "attestation/common/mock_crypto_utility.h" |
| #include "attestation/common/mock_tpm_utility.h" |
| #include "attestation/server/attestation_service.h" |
| #include "attestation/server/mock_database.h" |
| #include "attestation/server/mock_key_store.h" |
| |
| using brillo::http::fake::ServerRequest; |
| using brillo::http::fake::ServerResponse; |
| using testing::_; |
| using testing::DoAll; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::ReturnRef; |
| using testing::SetArgPointee; |
| |
| namespace attestation { |
| |
| // MessageLoopIdleEvent: waits for the moment when the message loop becomes |
| // idle. Note: it is still possible that there are deferred tasks. |
| // |
| // Posts the task to the message loop that checks the following: |
| // If there are tasks in the incoming queue, the loop is not idle, so re-post |
| // the task. |
| // If there are no tasks in the incoming queue, it's still possible that there |
| // are other tasks in the work queue already picked for processing after this |
| // task. So, in this case, re-post once again, and check the number of |
| // tasks between now and the next invocation of this task. If only 1 (this |
| // task only), the task runner is idle. |
| class MessageLoopIdleEvent : public base::MessageLoop::TaskObserver { |
| public: |
| MessageLoopIdleEvent(base::MessageLoop* message_loop) |
| : event_(true /* manual_reset */, false /* initially_signalled */), |
| observer_added_(false), |
| tasks_processed_(0), |
| was_idle_(false), |
| message_loop_(message_loop) { |
| PostTask(); |
| } |
| ~MessageLoopIdleEvent() { |
| } |
| // Observer callbacks: WillProcessTask and DidProcessTask. |
| // Count the number of run tasks in WillProcessTask. |
| void WillProcessTask(const base::PendingTask& pending_task) { |
| tasks_processed_++; |
| } |
| void DidProcessTask(const base::PendingTask& pending_task) { } |
| // The task we put on the message loop. |
| void RunTask() { |
| // We need to add observer in RunTask, since it can only |
| // be done by the thread that runs MessageLoop |
| if (!observer_added_) { |
| message_loop_->AddTaskObserver(this); |
| observer_added_ = true; |
| } |
| bool is_idle = (tasks_processed_ <= 1) && |
| message_loop_->IsIdleForTesting(); |
| if (was_idle_ && is_idle) { |
| // We need to remove observer in RunTask, since it can only |
| // be done by the thread that runs MessageLoop |
| if (observer_added_) { |
| message_loop_->RemoveTaskObserver(this); |
| observer_added_ = false; |
| } |
| event_.Signal(); |
| return; |
| } |
| was_idle_ = is_idle; |
| tasks_processed_ = 0; |
| PostTask(); |
| } |
| // Waits until the message loop becomes idle. |
| void Wait() { |
| event_.Wait(); |
| } |
| |
| private: |
| void PostTask() { |
| auto task = base::Bind(&MessageLoopIdleEvent::RunTask, |
| base::Unretained(this)); |
| message_loop_->PostTask(FROM_HERE, task); |
| } |
| |
| // Event to signal when we detect that the message loop is idle. |
| base::WaitableEvent event_; |
| // Was observer added to the mount loop? |
| bool observer_added_; |
| // Number of tasks run between previous invocation and now (including this). |
| int tasks_processed_; |
| // Did the loop appear idle during the previous task invocation? |
| bool was_idle_; |
| // MessageLoop we are waiting for. |
| base::MessageLoop* message_loop_; |
| }; |
| |
| class AttestationServiceTest : public testing::Test { |
| public: |
| enum FakeCAState { |
| kSuccess, // Valid successful response. |
| kCommandFailure, // Valid error response. |
| kHttpFailure, // Responds with an HTTP error. |
| kBadMessageID, // Valid successful response but a message ID mismatch. |
| }; |
| |
| #ifndef USE_TPM2 |
| const TpmVersion kTpmVersionUnderTest = TPM_1_2; |
| #else |
| const TpmVersion kTpmVersionUnderTest = TPM_2_0; |
| #endif |
| |
| ~AttestationServiceTest() override = default; |
| |
| void SetUp() override { |
| service_.reset(new AttestationService(nullptr)); |
| service_->set_database(&mock_database_); |
| service_->set_crypto_utility(&mock_crypto_utility_); |
| fake_http_transport_ = std::make_shared<brillo::http::fake::Transport>(); |
| service_->set_http_transport(fake_http_transport_); |
| service_->set_key_store(&mock_key_store_); |
| service_->set_tpm_utility(&mock_tpm_utility_); |
| service_->set_hwid("fake_hwid"); |
| // Setup a fake wrapped EK certificate by default. |
| mock_database_.GetMutableProtobuf() |
| ->mutable_credentials() |
| ->mutable_default_encrypted_endorsement_credential() |
| ->set_wrapping_key_id("default"); |
| // Setup a fake Attestation CA for success by default. |
| SetupFakeCAEnroll(kSuccess); |
| SetupFakeCASign(kSuccess); |
| CHECK(service_->Initialize()); |
| // Run out initialize task(s) to avoid any race conditions with tests that |
| // need to change the default setup. |
| WaitUntilIdleForTesting(); |
| } |
| |
| protected: |
| void SetupFakeCAEnroll(FakeCAState state) { |
| fake_http_transport_->AddHandler( |
| service_->GetACAWebOrigin(DEFAULT_ACA) + "/enroll", |
| brillo::http::request_type::kPost, |
| base::Bind(&AttestationServiceTest::FakeCAEnroll, |
| base::Unretained(this), state)); |
| } |
| |
| void SetupFakeCASign(FakeCAState state) { |
| fake_http_transport_->AddHandler( |
| service_->GetACAWebOrigin(DEFAULT_ACA) + "/sign", |
| brillo::http::request_type::kPost, |
| base::Bind(&AttestationServiceTest::FakeCASign, base::Unretained(this), |
| state)); |
| } |
| |
| 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; |
| } |
| |
| CreateGoogleAttestedKeyRequest GetCreateRequest() { |
| CreateGoogleAttestedKeyRequest request; |
| request.set_key_label("label"); |
| request.set_key_type(KEY_TYPE_RSA); |
| request.set_key_usage(KEY_USAGE_SIGN); |
| request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE); |
| request.set_username("user"); |
| request.set_origin("origin"); |
| return request; |
| } |
| |
| 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_detail("fake_sign_error"); |
| } |
| std::string response_str; |
| response_pb.SerializeToString(&response_str); |
| return response_str; |
| } |
| |
| AttestationCertificateRequest GenerateCACertRequest() { |
| // Populate identity credential |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_identity_key()->set_identity_credential("cert"); |
| 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); |
| request.set_username("user"); |
| request.set_request_origin("origin"); |
| AttestationCertificateRequest pca_request; |
| service_->CreateCertificateRequest( |
| request, base::Bind(callback, &loop, &pca_request)); |
| loop.Run(); |
| return pca_request; |
| } |
| |
| 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; |
| } |
| |
| void Run() { run_loop_.Run(); } |
| |
| void RunUntilIdle() { run_loop_.RunUntilIdle(); } |
| |
| void Quit() { run_loop_.Quit(); } |
| |
| void WaitUntilIdleForTesting() { |
| MessageLoopIdleEvent idle_event(service_->worker_thread_->message_loop()); |
| idle_event.Wait(); |
| } |
| |
| std::shared_ptr<brillo::http::fake::Transport> fake_http_transport_; |
| NiceMock<MockCryptoUtility> mock_crypto_utility_; |
| NiceMock<MockDatabase> mock_database_; |
| NiceMock<MockKeyStore> mock_key_store_; |
| NiceMock<MockTpmUtility> mock_tpm_utility_; |
| std::unique_ptr<AttestationService> service_; |
| |
| private: |
| void FakeCAEnroll(FakeCAState state, |
| const ServerRequest& request, |
| ServerResponse* response) { |
| AttestationEnrollmentRequest request_pb; |
| EXPECT_TRUE(request_pb.ParseFromString(request.GetDataAsString())); |
| if (state == kHttpFailure) { |
| response->ReplyText(brillo::http::status_code::NotFound, std::string(), |
| brillo::mime::application::kOctet_stream); |
| return; |
| } |
| std::string response_str; |
| if (state == kCommandFailure) { |
| response_str = CreateCAEnrollResponse(false); |
| } else if (state == kSuccess) { |
| response_str = CreateCAEnrollResponse(true); |
| } else { |
| NOTREACHED(); |
| } |
| response->ReplyText(brillo::http::status_code::Ok, response_str, |
| brillo::mime::application::kOctet_stream); |
| } |
| |
| void FakeCASign(FakeCAState state, |
| const ServerRequest& request, |
| ServerResponse* response) { |
| AttestationCertificateRequest request_pb; |
| EXPECT_TRUE(request_pb.ParseFromString(request.GetDataAsString())); |
| if (state == kHttpFailure) { |
| response->ReplyText(brillo::http::status_code::NotFound, std::string(), |
| brillo::mime::application::kOctet_stream); |
| return; |
| } |
| std::string response_str; |
| if (state == kCommandFailure) { |
| response_str = CreateCACertResponse(false, ""); |
| } else if (state == kSuccess) { |
| response_str = CreateCACertResponse(true, request_pb.message_id()); |
| } else if (state == kBadMessageID) { |
| response_str = CreateCACertResponse(true, ""); |
| } |
| response->ReplyText(brillo::http::status_code::Ok, response_str, |
| brillo::mime::application::kOctet_stream); |
| } |
| |
| base::MessageLoop message_loop_; |
| base::RunLoop run_loop_; |
| }; |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeySuccess) { |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(GetFakeCertificateChain(), reply.certificate_chain()); |
| EXPECT_FALSE(reply.has_server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeySuccessNoUser) { |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(GetFakeCertificateChain(), reply.certificate_chain()); |
| EXPECT_FALSE(reply.has_server_error()); |
| Quit(); |
| }; |
| CreateGoogleAttestedKeyRequest request = GetCreateRequest(); |
| request.clear_username(); |
| service_->CreateGoogleAttestedKey(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithEnrollHttpError) { |
| SetupFakeCAEnroll(kHttpFailure); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_CA_NOT_AVAILABLE, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithSignHttpError) { |
| SetupFakeCASign(kHttpFailure); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_CA_NOT_AVAILABLE, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithCAEnrollFailure) { |
| SetupFakeCAEnroll(kCommandFailure); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_REQUEST_DENIED_BY_CA, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("fake_enroll_error", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithCASignFailure) { |
| SetupFakeCASign(kCommandFailure); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_EQ(STATUS_REQUEST_DENIED_BY_CA, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("fake_sign_error", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithBadCAMessageID) { |
| SetupFakeCASign(kBadMessageID); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithNoEKCertificate) { |
| // Remove the default credential setup. |
| mock_database_.GetMutableProtobuf()->clear_credentials(); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithRNGFailure) { |
| EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithRNGFailure2) { |
| // This flow consumes at least two nonces. |
| EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _)) |
| .WillOnce(Return(true)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithDBFailure) { |
| EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithDBFailureNoUser) { |
| EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| CreateGoogleAttestedKeyRequest request = GetCreateRequest(); |
| request.clear_username(); |
| service_->CreateGoogleAttestedKey(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithKeyWriteFailure) { |
| EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmNotReady) { |
| EXPECT_CALL(mock_tpm_utility_, IsTpmReady()).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmActivateFailure) { |
| EXPECT_CALL(mock_tpm_utility_, ActivateIdentity(_, _, _, _, _, _)) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(mock_tpm_utility_, ActivateIdentityForTpm2(_, _, _, _, _, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyWithTpmCreateFailure) { |
| EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const CreateGoogleAttestedKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate_chain()); |
| EXPECT_EQ("", reply.server_error()); |
| Quit(); |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyAndCancel) { |
| // Set expectations on the outputs. |
| int callback_count = 0; |
| auto callback = [&callback_count](const CreateGoogleAttestedKeyReply& reply) { |
| callback_count++; |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| // Bring down the service, which should cancel any callbacks. |
| service_.reset(); |
| EXPECT_EQ(0, callback_count); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateGoogleAttestedKeyAndCancel2) { |
| // Set expectations on the outputs. |
| int callback_count = 0; |
| auto callback = [&callback_count](const CreateGoogleAttestedKeyReply& reply) { |
| callback_count++; |
| }; |
| service_->CreateGoogleAttestedKey(GetCreateRequest(), base::Bind(callback)); |
| // Give threads a chance to run. |
| base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); |
| // Bring down the service, which should cancel any callbacks. |
| service_.reset(); |
| // Pump the loop to make sure no callbacks were posted. |
| RunUntilIdle(); |
| EXPECT_EQ(0, callback_count); |
| } |
| |
| TEST_F(AttestationServiceTest, 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 = [this](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(); |
| }; |
| GetKeyInfoRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->GetKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, 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 = [this](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(); |
| }; |
| GetKeyInfoRequest request; |
| request.set_key_label("label"); |
| service_->GetKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetKeyInfoNoKey) { |
| EXPECT_CALL(mock_key_store_, Read("user", "label", _)) |
| .WillRepeatedly(Return(false)); |
| |
| // Set expectations on the outputs. |
| auto callback = [this](const GetKeyInfoReply& reply) { |
| EXPECT_EQ(STATUS_INVALID_PARAMETER, reply.status()); |
| Quit(); |
| }; |
| GetKeyInfoRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->GetKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetKeyInfoBadPublicKey) { |
| EXPECT_CALL(mock_crypto_utility_, GetRSASubjectPublicKeyInfo(_, _)) |
| .WillRepeatedly(Return(false)); |
| |
| // Set expectations on the outputs. |
| auto callback = [this](const GetKeyInfoReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| GetKeyInfoRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->GetKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, 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 = [this](const GetEndorsementInfoReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ("public_key", reply.ek_public_key()); |
| EXPECT_EQ("certificate", reply.ek_certificate()); |
| Quit(); |
| }; |
| GetEndorsementInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetEndorsementInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetEndorsementInfoNoInfo) { |
| EXPECT_CALL(mock_tpm_utility_, GetEndorsementPublicKey(_, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const GetEndorsementInfoReply& reply) { |
| EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status()); |
| EXPECT_FALSE(reply.has_ek_public_key()); |
| EXPECT_FALSE(reply.has_ek_certificate()); |
| Quit(); |
| }; |
| GetEndorsementInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetEndorsementInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetEndorsementInfoNoCert) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_credentials()->set_endorsement_public_key("public_key"); |
| // Set expectations on the outputs. |
| auto callback = [this](const GetEndorsementInfoReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ("public_key", reply.ek_public_key()); |
| EXPECT_FALSE(reply.has_ek_certificate()); |
| Quit(); |
| }; |
| GetEndorsementInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetEndorsementInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetAttestationKeyInfoSuccess) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_identity_key()->set_identity_public_key("public_key"); |
| database->mutable_identity_key()->set_identity_credential("certificate"); |
| database->mutable_pcr0_quote()->set_quote("pcr0"); |
| database->mutable_pcr1_quote()->set_quote("pcr1"); |
| database->mutable_identity_binding()->set_identity_public_key("public_key2"); |
| // Set expectations on the outputs. |
| auto callback = [this](const GetAttestationKeyInfoReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ("public_key", reply.public_key()); |
| EXPECT_EQ("public_key2", reply.public_key_tpm_format()); |
| EXPECT_EQ("certificate", reply.certificate()); |
| EXPECT_EQ("pcr0", reply.pcr0_quote().quote()); |
| EXPECT_EQ("pcr1", reply.pcr1_quote().quote()); |
| Quit(); |
| }; |
| GetAttestationKeyInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetAttestationKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetAttestationKeyInfoNoInfo) { |
| // Set expectations on the outputs. |
| auto callback = [this](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(); |
| }; |
| GetAttestationKeyInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetAttestationKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, GetAttestationKeyInfoSomeInfo) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_identity_key()->set_identity_credential("certificate"); |
| database->mutable_pcr1_quote()->set_quote("pcr1"); |
| // Set expectations on the outputs. |
| auto callback = [this](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("certificate", reply.certificate()); |
| EXPECT_FALSE(reply.has_pcr0_quote()); |
| EXPECT_EQ("pcr1", reply.pcr1_quote().quote()); |
| Quit(); |
| }; |
| GetAttestationKeyInfoRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| service_->GetAttestationKeyInfo(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, ActivateAttestationKeySuccess) { |
| EXPECT_CALL(mock_database_, SaveChanges()).Times(1); |
| if (kTpmVersionUnderTest == TPM_1_2) { |
| EXPECT_CALL(mock_tpm_utility_, |
| ActivateIdentity(_, _, _, "encrypted1", "encrypted2", _)) |
| .WillOnce(DoAll(SetArgPointee<5>(std::string("certificate")), |
| Return(true))); |
| } else { |
| EXPECT_CALL( |
| mock_tpm_utility_, |
| ActivateIdentityForTpm2(KEY_TYPE_RSA, _, "seed", "mac", "wrapped", _)) |
| .WillOnce(DoAll(SetArgPointee<5>(std::string("certificate")), |
| Return(true))); |
| } |
| // Set expectations on the outputs. |
| auto callback = [this](const ActivateAttestationKeyReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ("certificate", reply.certificate()); |
| Quit(); |
| }; |
| ActivateAttestationKeyRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, ActivateAttestationKeySuccessNoSave) { |
| EXPECT_CALL(mock_database_, GetMutableProtobuf()).Times(0); |
| EXPECT_CALL(mock_database_, SaveChanges()).Times(0); |
| if (kTpmVersionUnderTest == TPM_1_2) { |
| EXPECT_CALL(mock_tpm_utility_, |
| ActivateIdentity(_, _, _, "encrypted1", "encrypted2", _)) |
| .WillOnce(DoAll(SetArgPointee<5>(std::string("certificate")), |
| Return(true))); |
| } else { |
| EXPECT_CALL( |
| mock_tpm_utility_, |
| ActivateIdentityForTpm2(KEY_TYPE_RSA, _, "seed", "mac", "wrapped", _)) |
| .WillOnce(DoAll(SetArgPointee<5>(std::string("certificate")), |
| Return(true))); |
| } |
| // Set expectations on the outputs. |
| auto callback = [this](const ActivateAttestationKeyReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ("certificate", reply.certificate()); |
| Quit(); |
| }; |
| ActivateAttestationKeyRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| 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(false); |
| service_->ActivateAttestationKey(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, ActivateAttestationKeySaveFailure) { |
| EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const ActivateAttestationKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| ActivateAttestationKeyRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, ActivateAttestationKeyActivateFailure) { |
| EXPECT_CALL(mock_tpm_utility_, |
| ActivateIdentity(_, _, _, "encrypted1", "encrypted2", _)) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL( |
| mock_tpm_utility_, |
| ActivateIdentityForTpm2(KEY_TYPE_RSA, _, "seed", "mac", "wrapped", _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const ActivateAttestationKeyReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| ActivateAttestationKeyRequest request; |
| request.set_key_type(KEY_TYPE_RSA); |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeySuccess) { |
| // 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 = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeySuccessNoUser) { |
| // 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 = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeyRNGFailure) { |
| EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeyTpmCreateFailure) { |
| EXPECT_CALL(mock_tpm_utility_, CreateCertifiedKey(_, _, _, _, _, _, _, _, _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeyDBFailure) { |
| EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertifiableKeyDBFailureNoUser) { |
| EXPECT_CALL(mock_database_, SaveChanges()).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](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(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, DecryptSuccess) { |
| // Set expectations on the outputs. |
| auto callback = [this](const DecryptReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"), |
| reply.decrypted_data()); |
| Quit(); |
| }; |
| DecryptRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_encrypted_data("data"); |
| service_->Decrypt(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, DecryptSuccessNoUser) { |
| mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label"); |
| // Set expectations on the outputs. |
| auto callback = [this](const DecryptReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(MockTpmUtility::Transform("Unbind", "data"), |
| reply.decrypted_data()); |
| Quit(); |
| }; |
| DecryptRequest request; |
| request.set_key_label("label"); |
| request.set_encrypted_data("data"); |
| service_->Decrypt(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, DecryptKeyNotFound) { |
| EXPECT_CALL(mock_key_store_, Read("user", "label", _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const DecryptReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_decrypted_data()); |
| Quit(); |
| }; |
| DecryptRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_encrypted_data("data"); |
| service_->Decrypt(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, DecryptKeyNotFoundNoUser) { |
| // Set expectations on the outputs. |
| auto callback = [this](const DecryptReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_decrypted_data()); |
| Quit(); |
| }; |
| DecryptRequest request; |
| request.set_key_label("label"); |
| request.set_encrypted_data("data"); |
| service_->Decrypt(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, DecryptUnbindFailure) { |
| EXPECT_CALL(mock_tpm_utility_, Unbind(_, _, _)).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const DecryptReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_decrypted_data()); |
| Quit(); |
| }; |
| DecryptRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_encrypted_data("data"); |
| service_->Decrypt(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignSuccess) { |
| // Set expectations on the outputs. |
| auto callback = [this](const SignReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature()); |
| Quit(); |
| }; |
| SignRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_data_to_sign("data"); |
| service_->Sign(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignSuccessNoUser) { |
| mock_database_.GetMutableProtobuf()->add_device_keys()->set_key_name("label"); |
| // Set expectations on the outputs. |
| auto callback = [this](const SignReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(MockTpmUtility::Transform("Sign", "data"), reply.signature()); |
| Quit(); |
| }; |
| SignRequest request; |
| request.set_key_label("label"); |
| request.set_data_to_sign("data"); |
| service_->Sign(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignKeyNotFound) { |
| EXPECT_CALL(mock_key_store_, Read("user", "label", _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const SignReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_signature()); |
| Quit(); |
| }; |
| SignRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_data_to_sign("data"); |
| service_->Sign(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignKeyNotFoundNoUser) { |
| // Set expectations on the outputs. |
| auto callback = [this](const SignReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_signature()); |
| Quit(); |
| }; |
| SignRequest request; |
| request.set_key_label("label"); |
| request.set_data_to_sign("data"); |
| service_->Sign(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignUnbindFailure) { |
| EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)).WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const SignReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_signature()); |
| Quit(); |
| }; |
| SignRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_data_to_sign("data"); |
| service_->Sign(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(0, mock_database_.GetMutableProtobuf()->device_keys_size()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_include_certificates(true); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_EQ(0, mock_database_.GetMutableProtobuf()->device_keys_size()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_include_certificates(true); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, RegisterNoKey) { |
| EXPECT_CALL(mock_key_store_, Read("user", "label", _)) |
| .WillRepeatedly(Return(false)); |
| // Set expectations on the outputs. |
| auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, RegisterNoKeyNoUser) { |
| // Set expectations on the outputs. |
| auto callback = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_include_certificates(true); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(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 = [this](const RegisterKeyWithChapsTokenReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| RegisterKeyWithChapsTokenRequest request; |
| request.set_key_label("label"); |
| request.set_username("user"); |
| request.set_include_certificates(true); |
| service_->RegisterKeyWithChapsToken(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, PrepareForEnrollment) { |
| // Start with an empty database. |
| mock_database_.GetMutableProtobuf()->Clear(); |
| // Schedule initialization again to make sure it runs after this point. |
| CHECK(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| EXPECT_TRUE(mock_database_.GetProtobuf().has_credentials()); |
| EXPECT_TRUE(mock_database_.GetProtobuf().has_identity_key()); |
| EXPECT_TRUE(mock_database_.GetProtobuf().has_identity_binding()); |
| EXPECT_TRUE(mock_database_.GetProtobuf().has_pcr0_quote()); |
| EXPECT_TRUE(mock_database_.GetProtobuf().has_pcr1_quote()); |
| } |
| |
| TEST_F(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(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| 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_F(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(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| 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_F(AttestationServiceTest, PrepareForEnrollmentFailAIK) { |
| // Start with an empty database. |
| mock_database_.GetMutableProtobuf()->Clear(); |
| EXPECT_CALL(mock_tpm_utility_, CreateRestrictedKey(_, _, _, _)) |
| .WillRepeatedly(Return(false)); |
| // Schedule initialization again to make sure it runs after this point. |
| CHECK(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| 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_F(AttestationServiceTest, PrepareForEnrollmentBadAIK) { |
| // Start with an empty database. |
| mock_database_.GetMutableProtobuf()->Clear(); |
| EXPECT_CALL(mock_tpm_utility_, GetRSAPublicKeyFromTpmPublicKey(_, _)) |
| .WillRepeatedly(Return(false)); |
| // Schedule initialization again to make sure it runs after this point. |
| CHECK(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| 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_F(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(service_->Initialize()); |
| WaitUntilIdleForTesting(); |
| 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_F(AttestationServiceTest, CreateEnrollRequestSuccessWithoutAbeData) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_credentials() |
| ->mutable_default_encrypted_endorsement_credential() |
| ->set_wrapped_key("wrapped_key"); |
| database->mutable_identity_binding()->set_identity_public_key("public_key"); |
| database->mutable_pcr0_quote()->set_quote("pcr0"); |
| database->mutable_pcr1_quote()->set_quote("pcr1"); |
| auto callback = [this](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", 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(); |
| }; |
| CreateEnrollRequestRequest request; |
| service_->CreateEnrollRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateEnrollRequestSuccessWithEmptyAbeData) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_credentials() |
| ->mutable_default_encrypted_endorsement_credential() |
| ->set_wrapped_key("wrapped_key"); |
| database->mutable_identity_binding()->set_identity_public_key("public_key"); |
| database->mutable_pcr0_quote()->set_quote("pcr0"); |
| database->mutable_pcr1_quote()->set_quote("pcr1"); |
| auto callback = [this](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", 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(); |
| }; |
| brillo::SecureBlob abe_data; |
| service_->set_abe_data(&abe_data); |
| CreateEnrollRequestRequest request; |
| service_->CreateEnrollRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateEnrollRequestSuccessWithAbeData) { |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_credentials() |
| ->mutable_default_encrypted_endorsement_credential() |
| ->set_wrapped_key("wrapped_key"); |
| database->mutable_identity_binding()->set_identity_public_key("public_key"); |
| database->mutable_pcr0_quote()->set_quote("pcr0"); |
| database->mutable_pcr1_quote()->set_quote("pcr1"); |
| auto callback = [this](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", 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(); |
| }; |
| |
| CreateEnrollRequestRequest request; |
| brillo::SecureBlob abe_data(0xCA, 32); |
| service_->set_abe_data(&abe_data); |
| service_->CreateEnrollRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateEnrollRequestNotReady) { |
| // Empty database - not prepared for enrollment |
| mock_database_.GetMutableProtobuf()->Clear(); |
| auto callback = [this](const CreateEnrollRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_pca_request()); |
| Quit(); |
| }; |
| CreateEnrollRequestRequest request; |
| service_->CreateEnrollRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishEnrollSuccess) { |
| auto callback = [this](const FinishEnrollReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| FinishEnrollRequest request; |
| request.set_pca_response(CreateCAEnrollResponse(true)); |
| service_->FinishEnroll(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishEnrollFailure) { |
| auto callback = [this](const FinishEnrollReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| Quit(); |
| }; |
| FinishEnrollRequest request; |
| request.set_pca_response(CreateCAEnrollResponse(false)); |
| service_->FinishEnroll(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertificateRequestSuccess) { |
| // Populate identity credential |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_identity_key()->set_identity_credential("cert"); |
| auto callback = [this](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_EQ("cert", pca_request.identity_credential()); |
| Quit(); |
| }; |
| CreateCertificateRequestRequest request; |
| request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE); |
| request.set_username("user"); |
| request.set_request_origin("origin"); |
| service_->CreateCertificateRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertificateRequestInternalFailure) { |
| // Populate identity credential |
| AttestationDatabase* database = mock_database_.GetMutableProtobuf(); |
| database->mutable_identity_key()->set_identity_credential("cert"); |
| EXPECT_CALL(mock_crypto_utility_, GetRandom(_, _)) |
| .WillRepeatedly(Return(false)); |
| auto callback = [this](const CreateCertificateRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_pca_request()); |
| Quit(); |
| }; |
| CreateCertificateRequestRequest request; |
| request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE); |
| request.set_username("user"); |
| request.set_request_origin("origin"); |
| service_->CreateCertificateRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, CreateCertificateRequestNotEnrolled) { |
| // Empty database - not enrolled |
| mock_database_.GetMutableProtobuf()->Clear(); |
| auto callback = [this](const CreateCertificateRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_pca_request()); |
| Quit(); |
| }; |
| CreateCertificateRequestRequest request; |
| request.set_certificate_profile(ENTERPRISE_MACHINE_CERTIFICATE); |
| request.set_username("user"); |
| request.set_request_origin("origin"); |
| service_->CreateCertificateRequest(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishCertificateRequestSuccess) { |
| auto callback = [this](const FinishCertificateRequestReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_TRUE(reply.has_certificate()); |
| Quit(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishCertificateRequestInternalFailure) { |
| EXPECT_CALL(mock_key_store_, Write(_, _, _)).WillRepeatedly(Return(false)); |
| auto callback = [this](const FinishCertificateRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate()); |
| Quit(); |
| }; |
| 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishCertificateRequestWrongMessageId) { |
| auto callback = [this](const FinishCertificateRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate()); |
| Quit(); |
| }; |
| // 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, FinishCertificateRequestServerFailure) { |
| auto callback = [this](const FinishCertificateRequestReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_certificate()); |
| Quit(); |
| }; |
| // 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)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignSimpleChallengeSuccess) { |
| EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<2>(std::string("signature")), |
| Return(true))); |
| auto callback = [this](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(); |
| }; |
| SignSimpleChallengeRequest request; |
| request.set_username("user"); |
| request.set_key_label("label"); |
| request.set_challenge("challenge"); |
| service_->SignSimpleChallenge(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignSimpleChallengeInternalFailure) { |
| EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)) |
| .WillRepeatedly(Return(false)); |
| auto callback = [this](const SignSimpleChallengeReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_challenge_response()); |
| Quit(); |
| }; |
| SignSimpleChallengeRequest request; |
| request.set_username("user"); |
| request.set_key_label("label"); |
| request.set_challenge("challenge"); |
| service_->SignSimpleChallenge(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, SignEnterpriseChallengeSuccess) { |
| KeyInfo key_info = CreateChallengeKeyInfo(); |
| std::string key_info_str; |
| key_info.SerializeToString(&key_info_str); |
| EXPECT_CALL(mock_crypto_utility_, VerifySignatureUsingHexKey(_, _, _)) |
| .WillRepeatedly(Return(true)); |
| EXPECT_CALL(mock_crypto_utility_, |
| EncryptDataForGoogle(key_info_str, _, _, _)) |
| .WillRepeatedly( |
| DoAll(SetArgPointee<3>(MockEncryptedData(key_info_str)), |
| Return(true))); |
| EXPECT_CALL(mock_tpm_utility_, Sign(_, _, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<2>(std::string("signature")), |
| Return(true))); |
| auto callback = [this](const SignEnterpriseChallengeReply& reply) { |
| EXPECT_EQ(STATUS_SUCCESS, reply.status()); |
| EXPECT_TRUE(reply.has_challenge_response()); |
| SignedData signed_data; |
| EXPECT_TRUE(signed_data.ParseFromString(reply.challenge_response())); |
| EXPECT_EQ("signature", signed_data.signature()); |
| ChallengeResponse response_pb; |
| EXPECT_TRUE(response_pb.ParseFromString(signed_data.data())); |
| EXPECT_EQ(CreateChallenge("EnterpriseKeyChallenge"), |
| response_pb.challenge().data()); |
| KeyInfo key_info = CreateChallengeKeyInfo(); |
| std::string key_info_str; |
| key_info.SerializeToString(&key_info_str); |
| EXPECT_EQ(key_info_str, |
| response_pb.encrypted_key_info().encrypted_data()); |
| Quit(); |
| }; |
| SignEnterpriseChallengeRequest request; |
| request.set_username("user"); |
| request.set_key_label("label"); |
| request.set_domain(key_info.domain()); |
| request.set_device_id(key_info.device_id()); |
| request.set_include_signed_public_key(false); |
| request.set_challenge(CreateSignedChallenge("EnterpriseKeyChallenge")); |
| service_->SignEnterpriseChallenge(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, 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 = [this](const SignEnterpriseChallengeReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_challenge_response()); |
| Quit(); |
| }; |
| SignEnterpriseChallengeRequest request; |
| request.set_username("user"); |
| request.set_key_label("label"); |
| request.set_domain(key_info.domain()); |
| request.set_device_id(key_info.device_id()); |
| request.set_include_signed_public_key(false); |
| request.set_challenge(CreateSignedChallenge("EnterpriseKeyChallenge")); |
| service_->SignEnterpriseChallenge(request, base::Bind(callback)); |
| Run(); |
| } |
| |
| TEST_F(AttestationServiceTest, 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 = [this](const SignEnterpriseChallengeReply& reply) { |
| EXPECT_NE(STATUS_SUCCESS, reply.status()); |
| EXPECT_FALSE(reply.has_challenge_response()); |
| Quit(); |
| }; |
| SignEnterpriseChallengeRequest request; |
| 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)); |
| Run(); |
| } |
| |
| } // namespace attestation |