blob: d2d77ae512216ad96d988fc2dae078f35ecf48b5 [file] [log] [blame] [edit]
// Copyright 2020 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.
#ifndef ATTESTATION_PCA_AGENT_CLIENT_FAKE_PCA_AGENT_PROXY_H_
#define ATTESTATION_PCA_AGENT_CLIENT_FAKE_PCA_AGENT_PROXY_H_
#include <string>
#include <utility>
#include <attestation/pca_agent/dbus-proxy-mocks.h>
#include <attestation/proto_bindings/pca_agent.pb.h>
#include <base/optional.h>
#include <base/threading/thread_task_runner_handle.h>
#include <base/time/time.h>
namespace attestation {
namespace pca_agent {
namespace client {
// This class supports faking 4 conditions:
// 1) no any failure (default behavior),
// 2) dbus connection error (injected by |Set***DBusError|.
// 3) bad pca_agentd returned status (injected by |SetBad***Status|.
// 4) bad pca response from server (injected by |SetBad***PcaResponse|.
// Also,it supports the dbus response delay (injected by |Set***CallbackDelay|.
//
// Note that after any error injection, any other follow-up error injections are
// not considered as normal usecase; also, this class doesn't support the reset
// of any error injection because we don't have such usecase yet.
class FakePcaAgentProxy : public org::chromium::PcaAgentProxyMock {
public:
explicit FakePcaAgentProxy(TpmVersion tpm_version)
: tpm_version_(tpm_version) {
using testing::_;
using testing::Invoke;
ON_CALL(*this, EnrollAsync(_, _, _, _))
.WillByDefault(Invoke(this, &FakePcaAgentProxy::FakeEnrollAsync));
ON_CALL(*this, GetCertificateAsync(_, _, _, _))
.WillByDefault(
Invoke(this, &FakePcaAgentProxy::FakeGetCertificateAsync));
}
// Error/delay injections. More information can be found in the doc of this
// class.
void SetEnrollDBusError() { enroll_config_.success = false; }
void SetBadEnrollStatus(AttestationStatus status) {
ASSERT_NE(status, STATUS_SUCCESS);
enroll_config_.status = status;
}
void SetBadEnrollPcaResponse() {
enroll_config_.is_good_pca_response = false;
}
void SetEnrollCallbackDelay(const base::TimeDelta& t) {
enroll_config_.delay = t;
}
void SetGetCertificateDBusError() { get_certificate_config_.success = false; }
void SetBadGetCertificateStatus(AttestationStatus status) {
ASSERT_NE(status, STATUS_SUCCESS);
get_certificate_config_.status = status;
}
void SetBadGetCertificatePcaResponse() {
get_certificate_config_.is_good_pca_response = false;
}
void SetGetCertificateCallbackDelay(const base::TimeDelta& t) {
get_certificate_config_.delay = t;
}
private:
const TpmVersion tpm_version_;
// Internal configuration data; see fields for details.
struct Config {
// Success of dbus call. If |false|, then all other error flags below are
// ineffective.
bool success{true};
// Returned status from |pca_agentd|. If |false|, |is_good_pca_response| is
// ineffective.
AttestationStatus status{STATUS_SUCCESS};
// If the PCA response is good.
bool is_good_pca_response{true};
// Delay the task is posted with.
base::TimeDelta delay{base::TimeDelta::FromMilliseconds(0)};
};
// Respective configurations for enrollment and certification.
Config enroll_config_;
Config get_certificate_config_;
// Respective the expected replies.
EnrollReply enroll_reply_;
GetCertificateReply get_certificate_reply_;
// Error returned when dbus error.
brillo::ErrorPtr dummy_error_{
brillo::Error::Create(base::Location(), "", "", "")};
template <class ReplyType, class SuccessCallbackType, class ErrorCallbackType>
void PostTask(const Config& config,
const ReplyType& reply,
SuccessCallbackType on_success,
ErrorCallbackType on_error) {
auto task = config.success
? base::BindOnce(std::move(on_success), reply)
: base::BindOnce(std::move(on_error), dummy_error_.get());
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, std::move(task), config.delay);
}
void FakeEnrollAsync(
const EnrollRequest& request,
base::OnceCallback<void(const EnrollReply&)> success_callback,
base::OnceCallback<void(brillo::Error*)> error_callback,
int /*timeout_ms*/) {
enroll_reply_.set_status(enroll_config_.status);
if (enroll_config_.status == STATUS_SUCCESS) {
enroll_reply_.set_response(
CreateCAEnrollResponse(enroll_config_.is_good_pca_response));
}
PostTask(enroll_config_, enroll_reply_, std::move(success_callback),
std::move(error_callback));
}
void FakeGetCertificateAsync(
const GetCertificateRequest& request,
base::OnceCallback<void(const GetCertificateReply&)> success_callback,
base::OnceCallback<void(brillo::Error*)> error_callback,
int /*timeout_ms*/) {
get_certificate_reply_.set_status(get_certificate_config_.status);
if (get_certificate_config_.status == STATUS_SUCCESS) {
AttestationCertificateRequest pca_request;
ASSERT_TRUE(pca_request.ParseFromString(request.request()));
get_certificate_reply_.set_response(
CreateCACertResponse(get_certificate_config_.is_good_pca_response,
pca_request.message_id()));
}
PostTask(get_certificate_config_, get_certificate_reply_,
std::move(success_callback), std::move(error_callback));
}
// Creates a fake enroll response.
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(
tpm_version_);
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;
}
// Creates a fake certificate response corresponding to the request with
// |message_id|.
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;
}
};
} // namespace client
} // namespace pca_agent
} // namespace attestation
#endif // ATTESTATION_PCA_AGENT_CLIENT_FAKE_PCA_AGENT_PROXY_H_