Refactor TlsServerHandshaker to use ProofSourceHandle for cert selection and signature.
Protected by FLAGS_quic_reloadable_flag_quic_tls_use_per_handshaker_proof_source.
PiperOrigin-RevId: 350572752
Change-Id: Ifb33c9554c5c91fb69bbe1606a06b913c2fbbfff
diff --git a/quic/core/crypto/proof_source.h b/quic/core/crypto/proof_source.h
index 4e36a32..cee94f2 100644
--- a/quic/core/crypto/proof_source.h
+++ b/quic/core/crypto/proof_source.h
@@ -19,6 +19,10 @@
namespace quic {
+namespace test {
+class FakeProofSourceHandle;
+} // namespace test
+
// CryptoBuffers is a RAII class to own a std::vector<CRYPTO_BUFFER*> and the
// buffers the elements point to.
struct QUIC_EXPORT_PRIVATE CryptoBuffers {
@@ -211,6 +215,97 @@
virtual TicketCrypter* GetTicketCrypter() = 0;
};
+// ProofSourceHandleCallback is an interface that contains the callbacks when
+// the operations in ProofSourceHandle completes.
+// TODO(wub): Consider deprecating ProofSource by moving all functionalities of
+// ProofSource into ProofSourceHandle.
+class QUIC_EXPORT_PRIVATE ProofSourceHandleCallback {
+ public:
+ virtual ~ProofSourceHandleCallback() = default;
+
+ // Called when a ProofSourceHandle::SelectCertificate operation completes.
+ // |ok| indicates whether the operation was successful.
+ // |is_sync| indicates whether the operation completed synchronously, i.e.
+ // whether it is completed before ProofSourceHandle::SelectCertificate
+ // returned.
+ // |chain| the certificate chain in leaf-first order.
+ //
+ // When called asynchronously(is_sync=false), this method will be responsible
+ // to continue the handshake from where it left off.
+ virtual void OnSelectCertificateDone(bool ok,
+ bool is_sync,
+ const ProofSource::Chain* chain) = 0;
+
+ // Called when a ProofSourceHandle::ComputeSignature operation completes.
+ virtual void OnComputeSignatureDone(
+ bool ok,
+ bool is_sync,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> details) = 0;
+};
+
+// ProofSourceHandle is an interface by which a TlsServerHandshaker can obtain
+// certificate chains and signatures that prove its identity.
+// The operations this interface supports are similar to those in ProofSource,
+// the main difference is that ProofSourceHandle is per-handshaker, so
+// an implementation can have states that are shared by multiple calls on the
+// same handle.
+//
+// A handle object is owned by a TlsServerHandshaker. Since there might be an
+// async operation pending when the handle destructs, an implementation must
+// ensure when such operations finish, their corresponding callback method won't
+// be invoked.
+//
+// A handle will have at most one async operation pending at a time.
+class QUIC_EXPORT_PRIVATE ProofSourceHandle {
+ public:
+ virtual ~ProofSourceHandle() = default;
+
+ // Cancel the pending operation, if any.
+ // Once called, any completion method on |callback()| won't be invoked.
+ virtual void CancelPendingOperation() = 0;
+
+ // Starts a select certificate operation. If the operation is not cancelled
+ // when it completes, callback()->OnSelectCertificateDone will be invoked.
+ //
+ // If the operation is handled synchronously:
+ // - QUIC_SUCCESS or QUIC_FAILURE will be returned.
+ // - callback()->OnSelectCertificateDone should be invoked before the function
+ // returns.
+ //
+ // If the operation is handled asynchronously:
+ // - QUIC_PENDING will be returned.
+ // - When the operation is done, callback()->OnSelectCertificateDone should be
+ // invoked.
+ virtual QuicAsyncStatus SelectCertificate(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context) = 0;
+
+ // Starts a compute signature operation. If the operation is not cancelled
+ // when it completes, callback()->OnComputeSignatureDone will be invoked.
+ //
+ // See the comments of SelectCertificate for sync vs. async operations.
+ virtual QuicAsyncStatus ComputeSignature(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size) = 0;
+
+ protected:
+ // Returns the object that will be notified when an operation completes.
+ virtual ProofSourceHandleCallback* callback() = 0;
+
+ private:
+ friend class test::FakeProofSourceHandle;
+};
+
} // namespace quic
#endif // QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h
index 41d2820..baf8ee9 100644
--- a/quic/core/quic_flags_list.h
+++ b/quic/core/quic_flags_list.h
@@ -62,6 +62,7 @@
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_false, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_testonly_default_true, true)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_early_select_cert, false)
+QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_tls_use_per_handshaker_proof_source, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_circular_deque_for_unacked_packets_v2, false)
QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_use_encryption_level_context, false)
diff --git a/quic/core/tls_server_handshaker.cc b/quic/core/tls_server_handshaker.cc
index 383ca83..8fc52f1 100644
--- a/quic/core/tls_server_handshaker.cc
+++ b/quic/core/tls_server_handshaker.cc
@@ -13,6 +13,8 @@
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "quic/core/crypto/quic_crypto_server_config.h"
#include "quic/core/crypto/transport_parameters.h"
+#include "quic/core/quic_time.h"
+#include "quic/core/quic_types.h"
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_hostname_utils.h"
@@ -21,9 +23,88 @@
namespace quic {
+TlsServerHandshaker::DefaultProofSourceHandle::DefaultProofSourceHandle(
+ TlsServerHandshaker* handshaker,
+ ProofSource* proof_source)
+ : handshaker_(handshaker), proof_source_(proof_source) {}
+
+TlsServerHandshaker::DefaultProofSourceHandle::~DefaultProofSourceHandle() {
+ CancelPendingOperation();
+}
+
+void TlsServerHandshaker::DefaultProofSourceHandle::CancelPendingOperation() {
+ QUIC_DVLOG(1) << "CancelPendingOperation. is_signature_pending="
+ << (signature_callback_ != nullptr);
+ if (signature_callback_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 3,
+ 3);
+ signature_callback_->Cancel();
+ signature_callback_ = nullptr;
+ }
+}
+
+QuicAsyncStatus
+TlsServerHandshaker::DefaultProofSourceHandle::SelectCertificate(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view /*client_hello*/,
+ const std::string& /*alpn*/,
+ const std::vector<uint8_t>& /*quic_transport_params*/,
+ const absl::optional<std::vector<uint8_t>>& /*early_data_context*/) {
+ if (!handshaker_ || !proof_source_) {
+ QUIC_BUG << "SelectCertificate called on a detached handle";
+ return QUIC_FAILURE;
+ }
+
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ proof_source_->GetCertChain(server_address, client_address, hostname);
+
+ handshaker_->OnSelectCertificateDone(
+ /*ok=*/true, /*is_sync=*/true, chain.get());
+ return handshaker_->SelectCertStatus();
+}
+
+QuicAsyncStatus TlsServerHandshaker::DefaultProofSourceHandle::ComputeSignature(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size) {
+ if (!handshaker_ || !proof_source_) {
+ QUIC_BUG << "ComputeSignature called on a detached handle";
+ return QUIC_FAILURE;
+ }
+
+ if (signature_callback_) {
+ QUIC_BUG << "ComputeSignature called while pending";
+ return QUIC_FAILURE;
+ }
+
+ signature_callback_ = new DefaultSignatureCallback(this);
+ proof_source_->ComputeTlsSignature(
+ server_address, client_address, hostname, signature_algorithm, in,
+ std::unique_ptr<DefaultSignatureCallback>(signature_callback_));
+
+ if (signature_callback_) {
+ QUIC_DVLOG(1) << "ComputeTlsSignature is pending";
+ signature_callback_->set_is_sync(false);
+ return QUIC_PENDING;
+ }
+
+ bool success = handshaker_->HasValidSignature(max_signature_size);
+ QUIC_DVLOG(1) << "ComputeTlsSignature completed synchronously. success:"
+ << success;
+ // OnComputeSignatureDone should have been called by signature_callback_->Run.
+ return success ? QUIC_SUCCESS : QUIC_FAILURE;
+}
+
TlsServerHandshaker::SignatureCallback::SignatureCallback(
TlsServerHandshaker* handshaker)
- : handshaker_(handshaker) {}
+ : handshaker_(handshaker) {
+ DCHECK(!handshaker_->use_proof_source_handle_);
+}
void TlsServerHandshaker::SignatureCallback::Run(
bool ok,
@@ -110,6 +191,9 @@
}
void TlsServerHandshaker::CancelOutstandingCallbacks() {
+ if (use_proof_source_handle_ && proof_source_handle_) {
+ proof_source_handle_->CancelPendingOperation();
+ }
if (signature_callback_) {
signature_callback_->Cancel();
signature_callback_ = nullptr;
@@ -120,6 +204,12 @@
}
}
+std::unique_ptr<ProofSourceHandle>
+TlsServerHandshaker::MaybeCreateProofSourceHandle() {
+ DCHECK(use_proof_source_handle_);
+ return std::make_unique<DefaultProofSourceHandle>(this, proof_source_);
+}
+
bool TlsServerHandshaker::GetBase64SHA256ClientChannelID(
std::string* /*output*/) const {
// Channel ID is not supported when TLS is used in QUIC.
@@ -477,6 +567,19 @@
size_t max_out,
uint16_t sig_alg,
absl::string_view in) {
+ if (use_proof_source_handle_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 2,
+ 3);
+ QuicAsyncStatus status = proof_source_handle_->ComputeSignature(
+ session()->connection()->self_address(),
+ session()->connection()->peer_address(), hostname_, sig_alg, in,
+ max_out);
+ if (status == QUIC_PENDING) {
+ set_expected_ssl_error(SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
+ }
+ return PrivateKeyComplete(out, out_len, max_out);
+ }
+
signature_callback_ = new SignatureCallback(this);
proof_source_->ComputeTlsSignature(
session()->connection()->self_address(),
@@ -496,7 +599,7 @@
if (expected_ssl_error() == SSL_ERROR_WANT_PRIVATE_KEY_OPERATION) {
return ssl_private_key_retry;
}
- if (cert_verify_sig_.size() > max_out || cert_verify_sig_.empty()) {
+ if (!HasValidSignature(max_out)) {
return ssl_private_key_failure;
}
*out_len = cert_verify_sig_.size();
@@ -506,6 +609,32 @@
return ssl_private_key_success;
}
+void TlsServerHandshaker::OnComputeSignatureDone(
+ bool ok,
+ bool is_sync,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> details) {
+ QUIC_DVLOG(1) << "OnComputeSignatureDone. ok:" << ok
+ << ", is_sync:" << is_sync
+ << ", len(signature):" << signature.size();
+ DCHECK(use_proof_source_handle_);
+ if (ok) {
+ cert_verify_sig_ = std::move(signature);
+ proof_source_details_ = std::move(details);
+ }
+ const int last_expected_ssl_error = expected_ssl_error();
+ set_expected_ssl_error(SSL_ERROR_WANT_READ);
+ if (!is_sync) {
+ DCHECK_EQ(last_expected_ssl_error, SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
+ AdvanceHandshakeFromCallback();
+ }
+}
+
+bool TlsServerHandshaker::HasValidSignature(size_t max_signature_size) const {
+ return !cert_verify_sig_.empty() &&
+ cert_verify_sig_.size() <= max_signature_size;
+}
+
size_t TlsServerHandshaker::SessionTicketMaxOverhead() {
DCHECK(proof_source_->GetTicketCrypter());
return proof_source_->GetTicketCrypter()->MaxOverhead();
@@ -579,6 +708,27 @@
QUIC_RELOADABLE_FLAG_COUNT(quic_tls_use_early_select_cert);
+ // EarlySelectCertCallback can be called twice from BoringSSL: If the first
+ // call returns ssl_select_cert_retry, when cert selection completes,
+ // SSL_do_handshake will call it again.
+ if (use_proof_source_handle_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_tls_use_per_handshaker_proof_source, 1,
+ 3);
+ if (select_cert_status_.has_value()) {
+ // This is the second call, return the result directly.
+ QUIC_DVLOG(1) << "EarlySelectCertCallback called to continue handshake, "
+ "returning directly. success:"
+ << (select_cert_status_.value() == QUIC_SUCCESS);
+ return (select_cert_status_.value() == QUIC_SUCCESS)
+ ? ssl_select_cert_success
+ : ssl_select_cert_error;
+ }
+
+ // This is the first call.
+ select_cert_status_ = QUIC_PENDING;
+ proof_source_handle_ = MaybeCreateProofSourceHandle();
+ }
+
if (!pre_shared_key_.empty()) {
// TODO(b/154162689) add PSK support to QUIC+TLS.
QUIC_BUG << "QUIC server pre-shared keys not yet supported with TLS";
@@ -599,6 +749,45 @@
QUIC_LOG(INFO) << "No hostname indicated in SNI";
}
+ if (use_proof_source_handle_) {
+ std::string error_details;
+ if (!ProcessTransportParameters(client_hello, &error_details)) {
+ CloseConnection(QUIC_HANDSHAKE_FAILED, error_details);
+ return ssl_select_cert_error;
+ }
+ OverrideQuicConfigDefaults(session()->config());
+ session()->OnConfigNegotiated();
+
+ auto set_transport_params_result = SetTransportParameters();
+ if (!set_transport_params_result.success) {
+ QUIC_LOG(ERROR) << "Failed to set transport parameters";
+ return ssl_select_cert_error;
+ }
+
+ const QuicAsyncStatus status = proof_source_handle_->SelectCertificate(
+ session()->connection()->self_address(),
+ session()->connection()->peer_address(), hostname_,
+ absl::string_view(
+ reinterpret_cast<const char*>(client_hello->client_hello),
+ client_hello->client_hello_len),
+ AlpnForVersion(session()->version()),
+ set_transport_params_result.quic_transport_params,
+ set_transport_params_result.early_data_context);
+
+ DCHECK_EQ(status, SelectCertStatus());
+
+ if (status == QUIC_PENDING) {
+ set_expected_ssl_error(SSL_ERROR_PENDING_CERTIFICATE);
+ return ssl_select_cert_retry;
+ }
+
+ if (status == QUIC_FAILURE) {
+ return ssl_select_cert_error;
+ }
+
+ return ssl_select_cert_success;
+ }
+
QuicReferenceCountedPointer<ProofSource::Chain> chain =
proof_source_->GetCertChain(session()->connection()->self_address(),
session()->connection()->peer_address(),
@@ -629,6 +818,38 @@
return ssl_select_cert_success;
}
+void TlsServerHandshaker::OnSelectCertificateDone(
+ bool ok,
+ bool is_sync,
+ const ProofSource::Chain* chain) {
+ QUIC_DVLOG(1) << "OnSelectCertificateDone. ok:" << ok
+ << ", is_sync:" << is_sync;
+ DCHECK(use_proof_source_handle_);
+
+ select_cert_status_ = QUIC_FAILURE;
+ if (ok) {
+ if (chain && !chain->certs.empty()) {
+ tls_connection_.SetCertChain(chain->ToCryptoBuffers().value);
+ select_cert_status_ = QUIC_SUCCESS;
+ } else {
+ QUIC_LOG(ERROR) << "No certs provided for host '" << hostname_ << "'";
+ }
+ }
+
+ if (!is_sync) {
+ AdvanceHandshakeFromCallback();
+ }
+}
+
+QuicAsyncStatus TlsServerHandshaker::SelectCertStatus() const {
+ if (!select_cert_status_.has_value()) {
+ QUIC_BUG << "SelectCertStatus should be called after select cert started";
+ return QUIC_PENDING;
+ }
+
+ return select_cert_status_.value();
+}
+
bool TlsServerHandshaker::ValidateHostname(const std::string& hostname) const {
if (!QuicHostnameUtils::IsValidSNI(hostname)) {
// TODO(b/151676147): Include this error string in the CONNECTION_CLOSE
diff --git a/quic/core/tls_server_handshaker.h b/quic/core/tls_server_handshaker.h
index 40db662..9b1cdae 100644
--- a/quic/core/tls_server_handshaker.h
+++ b/quic/core/tls_server_handshaker.h
@@ -15,6 +15,7 @@
#include "quic/core/proto/cached_network_parameters_proto.h"
#include "quic/core/quic_crypto_server_stream_base.h"
#include "quic/core/quic_crypto_stream.h"
+#include "quic/core/quic_types.h"
#include "quic/core/tls_handshaker.h"
#include "quic/platform/api/quic_export.h"
@@ -25,6 +26,7 @@
class QUIC_EXPORT_PRIVATE TlsServerHandshaker
: public TlsHandshaker,
public TlsServerConnection::Delegate,
+ public ProofSourceHandleCallback,
public QuicCryptoServerStreamBase {
public:
// |crypto_config| must outlive TlsServerHandshaker.
@@ -79,6 +81,12 @@
const std::vector<uint8_t>& write_secret) override;
protected:
+ // Creates a proof source handle for selecting cert and computing signature.
+ // Only called when |use_proof_source_handle_| is true.
+ virtual std::unique_ptr<ProofSourceHandle> MaybeCreateProofSourceHandle();
+
+ bool use_proof_source_handle() const { return use_proof_source_handle_; }
+
// Hook to allow the server to override parts of the QuicConfig based on SNI
// before we generate transport parameters.
virtual void OverrideQuicConfigDefaults(QuicConfig* config);
@@ -136,6 +144,26 @@
absl::string_view in) override;
TlsConnection::Delegate* ConnectionDelegate() override { return this; }
+ // The status of cert selection. Only called after cert selection started.
+ QuicAsyncStatus SelectCertStatus() const;
+ // Whether |cert_verify_sig_| contains a valid signature.
+ // NOTE: BoringSSL queries the result of a async signature operation using
+ // PrivateKeyComplete(), a successful PrivateKeyComplete() will clear the
+ // content of |cert_verify_sig_|, this function should not be called after
+ // that.
+ bool HasValidSignature(size_t max_signature_size) const;
+
+ // ProofSourceHandleCallback implementation:
+ void OnSelectCertificateDone(bool ok,
+ bool is_sync,
+ const ProofSource::Chain* chain) override;
+
+ void OnComputeSignatureDone(
+ bool ok,
+ bool is_sync,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> details) override;
+
private:
class QUIC_EXPORT_PRIVATE SignatureCallback
: public ProofSource::SignatureCallback {
@@ -165,6 +193,81 @@
TlsServerHandshaker* handshaker_;
};
+ // DefaultProofSourceHandle delegates all operations to the shared proof
+ // source.
+ class QUIC_EXPORT_PRIVATE DefaultProofSourceHandle
+ : public ProofSourceHandle {
+ public:
+ DefaultProofSourceHandle(TlsServerHandshaker* handshaker,
+ ProofSource* proof_source);
+
+ ~DefaultProofSourceHandle() override;
+
+ // Cancel the pending signature operation, if any.
+ void CancelPendingOperation() override;
+
+ // Delegates to proof_source_->GetCertChain.
+ // Returns QUIC_SUCCESS or QUIC_FAILURE. Never returns QUIC_PENDING.
+ QuicAsyncStatus SelectCertificate(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context)
+ override;
+
+ // Delegates to proof_source_->ComputeTlsSignature.
+ // Returns QUIC_SUCCESS, QUIC_FAILURE or QUIC_PENDING.
+ QuicAsyncStatus ComputeSignature(const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size) override;
+
+ protected:
+ ProofSourceHandleCallback* callback() override { return handshaker_; }
+
+ private:
+ class QUIC_EXPORT_PRIVATE DefaultSignatureCallback
+ : public ProofSource::SignatureCallback {
+ public:
+ explicit DefaultSignatureCallback(DefaultProofSourceHandle* handle)
+ : handle_(handle) {}
+
+ void Run(bool ok,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> details) override {
+ if (handle_ == nullptr) {
+ // Operation has been canceled, or Run has been called.
+ return;
+ }
+ handle_->signature_callback_ = nullptr;
+ if (handle_->handshaker_ != nullptr) {
+ handle_->handshaker_->OnComputeSignatureDone(
+ ok, is_sync_, std::move(signature), std::move(details));
+ }
+ }
+
+ // If called, Cancel causes the pending callback to be a no-op.
+ void Cancel() { handle_ = nullptr; }
+
+ void set_is_sync(bool is_sync) { is_sync_ = is_sync; }
+
+ private:
+ DefaultProofSourceHandle* handle_;
+ // Set to false if handle_->ComputeSignature returns QUIC_PENDING.
+ bool is_sync_ = true;
+ };
+
+ // Not nullptr on construction. Set to nullptr when cancelled.
+ TlsServerHandshaker* handshaker_; // Not owned.
+ ProofSource* proof_source_; // Not owned.
+ DefaultSignatureCallback* signature_callback_ = nullptr;
+ };
+
struct QUIC_NO_EXPORT SetTransportParametersResult {
bool success = false;
// Empty vector if QUIC transport params are not set successfully.
@@ -178,6 +281,7 @@
bool ProcessTransportParameters(const SSL_CLIENT_HELLO* client_hello,
std::string* error_details);
+ std::unique_ptr<ProofSourceHandle> proof_source_handle_;
ProofSource* proof_source_;
SignatureCallback* signature_callback_ = nullptr;
@@ -195,6 +299,9 @@
// indicates that the client attempted a resumption.
bool ticket_received_ = false;
+ // nullopt means select cert hasn't started.
+ absl::optional<QuicAsyncStatus> select_cert_status_;
+
std::string hostname_;
std::string cert_verify_sig_;
std::unique_ptr<ProofSource::Details> proof_source_details_;
@@ -212,6 +319,9 @@
TlsServerConnection tls_connection_;
const bool use_early_select_cert_ =
GetQuicReloadableFlag(quic_tls_use_early_select_cert);
+ const bool use_proof_source_handle_ =
+ use_early_select_cert_ &&
+ GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source);
const QuicCryptoServerConfig* crypto_config_; // Unowned.
};
diff --git a/quic/core/tls_server_handshaker_test.cc b/quic/core/tls_server_handshaker_test.cc
index 5271bb6..e650a4a 100644
--- a/quic/core/tls_server_handshaker_test.cc
+++ b/quic/core/tls_server_handshaker_test.cc
@@ -15,12 +15,14 @@
#include "quic/core/quic_utils.h"
#include "quic/core/quic_versions.h"
#include "quic/core/tls_client_handshaker.h"
+#include "quic/core/tls_server_handshaker.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/crypto_test_utils.h"
#include "quic/test_tools/failing_proof_source.h"
#include "quic/test_tools/fake_proof_source.h"
+#include "quic/test_tools/fake_proof_source_handle.h"
#include "quic/test_tools/quic_test_utils.h"
#include "quic/test_tools/simple_session_cache.h"
#include "quic/test_tools/test_ticket_crypter.h"
@@ -65,6 +67,68 @@
return params;
}
+class TestTlsServerHandshaker : public TlsServerHandshaker {
+ public:
+ TestTlsServerHandshaker(QuicSession* session,
+ const QuicCryptoServerConfig* crypto_config)
+ : TlsServerHandshaker(session, crypto_config),
+ proof_source_(crypto_config->proof_source()) {
+ ON_CALL(*this, MaybeCreateProofSourceHandle())
+ .WillByDefault(testing::Invoke(
+ this, &TestTlsServerHandshaker::RealMaybeCreateProofSourceHandle));
+ }
+
+ MOCK_METHOD(std::unique_ptr<ProofSourceHandle>,
+ MaybeCreateProofSourceHandle,
+ (),
+ (override));
+
+ void SetupProofSourceHandle(
+ FakeProofSourceHandle::Action select_cert_action,
+ FakeProofSourceHandle::Action compute_signature_action) {
+ EXPECT_CALL(*this, MaybeCreateProofSourceHandle())
+ .WillOnce(testing::Invoke(
+ [this, select_cert_action, compute_signature_action]() {
+ auto handle = std::make_unique<FakeProofSourceHandle>(
+ proof_source_, this, select_cert_action,
+ compute_signature_action);
+ fake_proof_source_handle_ = handle.get();
+ return handle;
+ }));
+ }
+
+ FakeProofSourceHandle* fake_proof_source_handle() {
+ return fake_proof_source_handle_;
+ }
+
+ private:
+ std::unique_ptr<ProofSourceHandle> RealMaybeCreateProofSourceHandle() {
+ return TlsServerHandshaker::MaybeCreateProofSourceHandle();
+ }
+
+ // Owned by TlsServerHandshaker.
+ FakeProofSourceHandle* fake_proof_source_handle_ = nullptr;
+ ProofSource* proof_source_ = nullptr;
+};
+
+class TlsServerHandshakerTestSession : public TestQuicSpdyServerSession {
+ public:
+ using TestQuicSpdyServerSession::TestQuicSpdyServerSession;
+
+ std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream(
+ const QuicCryptoServerConfig* crypto_config,
+ QuicCompressedCertsCache* /*compressed_certs_cache*/) override {
+ if (connection()->version().handshake_protocol == PROTOCOL_TLS1_3) {
+ return std::make_unique<NiceMock<TestTlsServerHandshaker>>(this,
+ crypto_config);
+ }
+
+ CHECK(false) << "Unsupported handshake protocol: "
+ << connection()->version().handshake_protocol;
+ return nullptr;
+ }
+};
+
class TlsServerHandshakerTest : public QuicTestWithParam<TestParams> {
public:
TlsServerHandshakerTest()
@@ -109,6 +173,46 @@
std::make_unique<FailingProofSource>(), KeyExchangeSource::Default());
}
+ void CreateTlsServerHandshakerTestSession(MockQuicConnectionHelper* helper,
+ MockAlarmFactory* alarm_factory) {
+ server_connection_ = new PacketSavingConnection(
+ helper, alarm_factory, Perspective::IS_SERVER,
+ ParsedVersionOfIndex(supported_versions_, 0));
+
+ TlsServerHandshakerTestSession* server_session =
+ new TlsServerHandshakerTestSession(
+ server_connection_, DefaultQuicConfig(), supported_versions_,
+ server_crypto_config_.get(), &server_compressed_certs_cache_);
+ server_session->Initialize();
+
+ // We advance the clock initially because the default time is zero and the
+ // strike register worries that we've just overflowed a uint32_t time.
+ server_connection_->AdvanceTime(QuicTime::Delta::FromSeconds(100000));
+
+ CHECK(server_session);
+ server_session_.reset(server_session);
+ }
+
+ void InitializeServerWithFakeProofSourceHandle() {
+ helpers_.push_back(std::make_unique<NiceMock<MockQuicConnectionHelper>>());
+ alarm_factories_.push_back(std::make_unique<MockAlarmFactory>());
+ CreateTlsServerHandshakerTestSession(helpers_.back().get(),
+ alarm_factories_.back().get());
+ server_handshaker_ = static_cast<NiceMock<TestTlsServerHandshaker>*>(
+ server_session_->GetMutableCryptoStream());
+ EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
+ .Times(testing::AnyNumber());
+ EXPECT_CALL(*server_session_, SelectAlpn(_))
+ .WillRepeatedly([this](const std::vector<absl::string_view>& alpns) {
+ return std::find(
+ alpns.cbegin(), alpns.cend(),
+ AlpnForVersion(server_session_->connection()->version()));
+ });
+ crypto_test_utils::SetupCryptoServerConfigForTest(
+ server_connection_->clock(), server_connection_->random_generator(),
+ server_crypto_config_.get());
+ }
+
// Initializes the crypto server stream state for testing. May be
// called multiple times.
void InitializeServer() {
@@ -122,15 +226,15 @@
&server_connection_, &server_session);
CHECK(server_session);
server_session_.reset(server_session);
+ server_handshaker_ = nullptr;
EXPECT_CALL(*server_session_->helper(), CanAcceptClientHello(_, _, _, _, _))
.Times(testing::AnyNumber());
EXPECT_CALL(*server_session_, SelectAlpn(_))
- .WillRepeatedly(
- [this](const std::vector<absl::string_view>& alpns) {
- return std::find(
- alpns.cbegin(), alpns.cend(),
- AlpnForVersion(server_session_->connection()->version()));
- });
+ .WillRepeatedly([this](const std::vector<absl::string_view>& alpns) {
+ return std::find(
+ alpns.cbegin(), alpns.cend(),
+ AlpnForVersion(server_session_->connection()->version()));
+ });
crypto_test_utils::SetupCryptoServerConfigForTest(
server_connection_->clock(), server_connection_->random_generator(),
server_crypto_config_.get());
@@ -231,8 +335,10 @@
// Server state.
PacketSavingConnection* server_connection_;
std::unique_ptr<TestQuicSpdyServerSession> server_session_;
+ // Only set when initialized with InitializeServerWithFakeProofSourceHandle.
+ NiceMock<TestTlsServerHandshaker>* server_handshaker_ = nullptr;
TestTicketCrypter* ticket_crypter_; // owned by proof_source_
- FakeProofSource* proof_source_; // owned by server_crypto_config_
+ FakeProofSource* proof_source_; // owned by server_crypto_config_
std::unique_ptr<QuicCryptoServerConfig> server_crypto_config_;
QuicCompressedCertsCache server_compressed_certs_cache_;
QuicServerId server_id_;
@@ -267,7 +373,58 @@
ExpectHandshakeSuccessful();
}
-TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) {
+TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertSuccess) {
+ if (!(GetQuicReloadableFlag(quic_tls_use_early_select_cert) &&
+ GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source))) {
+ return;
+ }
+
+ InitializeServerWithFakeProofSourceHandle();
+ server_handshaker_->SetupProofSourceHandle(
+ /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
+ /*compute_signature_action=*/FakeProofSourceHandle::Action::
+ DELEGATE_SYNC);
+
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
+
+ // Start handshake.
+ AdvanceHandshakeWithFakeClient();
+
+ ASSERT_TRUE(
+ server_handshaker_->fake_proof_source_handle()->HasPendingOperation());
+ server_handshaker_->fake_proof_source_handle()->CompletePendingOperation();
+
+ CompleteCryptoHandshake();
+
+ ExpectHandshakeSuccessful();
+}
+
+TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSelectCertFailure) {
+ if (!(GetQuicReloadableFlag(quic_tls_use_early_select_cert) &&
+ GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source))) {
+ return;
+ }
+
+ InitializeServerWithFakeProofSourceHandle();
+ server_handshaker_->SetupProofSourceHandle(
+ /*select_cert_action=*/FakeProofSourceHandle::Action::FAIL_ASYNC,
+ /*compute_signature_action=*/FakeProofSourceHandle::Action::
+ DELEGATE_SYNC);
+
+ // Start handshake.
+ AdvanceHandshakeWithFakeClient();
+
+ ASSERT_TRUE(
+ server_handshaker_->fake_proof_source_handle()->HasPendingOperation());
+ server_handshaker_->fake_proof_source_handle()->CompletePendingOperation();
+
+ // Check that the server didn't send any handshake messages, because it failed
+ // to handshake.
+ EXPECT_EQ(moved_messages_counts_.second, 0u);
+}
+
+TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncSignature) {
EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
// Enable FakeProofSource to capture call to ComputeTlsSignature and run it
@@ -285,7 +442,34 @@
ExpectHandshakeSuccessful();
}
-TEST_P(TlsServerHandshakerTest, CancelPendingProofSource) {
+TEST_P(TlsServerHandshakerTest, CancelPendingSelectCert) {
+ if (!(GetQuicReloadableFlag(quic_tls_use_early_select_cert) &&
+ GetQuicReloadableFlag(quic_tls_use_per_handshaker_proof_source))) {
+ return;
+ }
+
+ InitializeServerWithFakeProofSourceHandle();
+ server_handshaker_->SetupProofSourceHandle(
+ /*select_cert_action=*/FakeProofSourceHandle::Action::DELEGATE_ASYNC,
+ /*compute_signature_action=*/FakeProofSourceHandle::Action::
+ DELEGATE_SYNC);
+
+ EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
+ EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
+
+ // Start handshake.
+ AdvanceHandshakeWithFakeClient();
+
+ ASSERT_TRUE(
+ server_handshaker_->fake_proof_source_handle()->HasPendingOperation());
+ server_handshaker_->CancelOutstandingCallbacks();
+ ASSERT_FALSE(
+ server_handshaker_->fake_proof_source_handle()->HasPendingOperation());
+ // CompletePendingOperation should be noop.
+ server_handshaker_->fake_proof_source_handle()->CompletePendingOperation();
+}
+
+TEST_P(TlsServerHandshakerTest, CancelPendingSignature) {
EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0);
EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0);
// Enable FakeProofSource to capture call to ComputeTlsSignature and run it
diff --git a/quic/test_tools/fake_proof_source_handle.cc b/quic/test_tools/fake_proof_source_handle.cc
new file mode 100644
index 0000000..daa47b5
--- /dev/null
+++ b/quic/test_tools/fake_proof_source_handle.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2021 The Chromium 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 "quic/test_tools/fake_proof_source_handle.h"
+#include "quic/core/quic_types.h"
+#include "quic/platform/api/quic_bug_tracker.h"
+
+namespace quic {
+namespace test {
+namespace {
+
+struct QUIC_EXPORT_PRIVATE ComputeSignatureResult {
+ bool ok;
+ std::string signature;
+ std::unique_ptr<ProofSource::Details> details;
+};
+
+class QUIC_EXPORT_PRIVATE ResultSavingSignatureCallback
+ : public ProofSource::SignatureCallback {
+ public:
+ explicit ResultSavingSignatureCallback(
+ absl::optional<ComputeSignatureResult>* result)
+ : result_(result) {
+ DCHECK(!result_->has_value());
+ }
+ void Run(bool ok,
+ std::string signature,
+ std::unique_ptr<ProofSource::Details> details) override {
+ result_->emplace(
+ ComputeSignatureResult{ok, std::move(signature), std::move(details)});
+ }
+
+ private:
+ absl::optional<ComputeSignatureResult>* result_;
+};
+
+ComputeSignatureResult ComputeSignatureNow(
+ ProofSource* delegate,
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in) {
+ absl::optional<ComputeSignatureResult> result;
+ delegate->ComputeTlsSignature(
+ server_address, client_address, hostname, signature_algorithm, in,
+ std::make_unique<ResultSavingSignatureCallback>(&result));
+ CHECK(result.has_value()) << "delegate->ComputeTlsSignature must computes a "
+ "signature immediately";
+ return std::move(result.value());
+}
+} // namespace
+
+FakeProofSourceHandle::FakeProofSourceHandle(
+ ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action select_cert_action,
+ Action compute_signature_action)
+ : delegate_(delegate),
+ callback_(callback),
+ select_cert_action_(select_cert_action),
+ compute_signature_action_(compute_signature_action) {}
+
+void FakeProofSourceHandle::CancelPendingOperation() {
+ select_cert_op_.reset();
+ compute_signature_op_.reset();
+}
+
+QuicAsyncStatus FakeProofSourceHandle::SelectCertificate(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context) {
+ if (select_cert_action_ == Action::DELEGATE_ASYNC ||
+ select_cert_action_ == Action::FAIL_ASYNC) {
+ select_cert_op_.emplace(delegate_, callback_, select_cert_action_,
+ server_address, client_address, hostname,
+ client_hello, alpn, quic_transport_params,
+ early_data_context);
+ return QUIC_PENDING;
+ } else if (select_cert_action_ == Action::FAIL_SYNC) {
+ callback()->OnSelectCertificateDone(/*ok=*/false,
+ /*is_sync=*/true, nullptr);
+ return QUIC_FAILURE;
+ }
+
+ DCHECK(select_cert_action_ == Action::DELEGATE_SYNC);
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ delegate_->GetCertChain(server_address, client_address, hostname);
+
+ bool ok = chain && !chain->certs.empty();
+ callback_->OnSelectCertificateDone(ok, /*is_sync=*/true, chain.get());
+ return ok ? QUIC_SUCCESS : QUIC_FAILURE;
+}
+
+QuicAsyncStatus FakeProofSourceHandle::ComputeSignature(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size) {
+ if (compute_signature_action_ == Action::DELEGATE_ASYNC ||
+ compute_signature_action_ == Action::FAIL_ASYNC) {
+ compute_signature_op_.emplace(
+ delegate_, callback_, compute_signature_action_, server_address,
+ client_address, hostname, signature_algorithm, in, max_signature_size);
+ return QUIC_PENDING;
+ } else if (compute_signature_action_ == Action::FAIL_SYNC) {
+ callback()->OnComputeSignatureDone(/*ok=*/false, /*is_sync=*/true,
+ /*signature=*/"", /*details=*/nullptr);
+ return QUIC_FAILURE;
+ }
+
+ DCHECK(compute_signature_action_ == Action::DELEGATE_SYNC);
+ ComputeSignatureResult result =
+ ComputeSignatureNow(delegate_, server_address, client_address, hostname,
+ signature_algorithm, in);
+ callback_->OnComputeSignatureDone(
+ result.ok, /*is_sync=*/true, result.signature, std::move(result.details));
+ return result.ok ? QUIC_SUCCESS : QUIC_FAILURE;
+}
+
+ProofSourceHandleCallback* FakeProofSourceHandle::callback() {
+ return callback_;
+}
+
+bool FakeProofSourceHandle::HasPendingOperation() const {
+ int num_pending_operations = NumPendingOperations();
+ return num_pending_operations > 0;
+}
+
+void FakeProofSourceHandle::CompletePendingOperation() {
+ DCHECK_LE(NumPendingOperations(), 1);
+
+ if (select_cert_op_.has_value()) {
+ select_cert_op_->Run();
+ } else if (compute_signature_op_.has_value()) {
+ compute_signature_op_->Run();
+ }
+}
+
+int FakeProofSourceHandle::NumPendingOperations() const {
+ return static_cast<int>(select_cert_op_.has_value()) +
+ static_cast<int>(compute_signature_op_.has_value());
+}
+
+FakeProofSourceHandle::SelectCertOperation::SelectCertOperation(
+ ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action action,
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context)
+ : PendingOperation(delegate, callback, action),
+ server_address_(server_address),
+ client_address_(client_address),
+ hostname_(hostname),
+ client_hello_(client_hello),
+ alpn_(alpn),
+ quic_transport_params_(quic_transport_params),
+ early_data_context_(early_data_context) {}
+
+void FakeProofSourceHandle::SelectCertOperation::Run() {
+ if (action_ == Action::FAIL_ASYNC) {
+ callback_->OnSelectCertificateDone(/*ok=*/false,
+ /*is_sync=*/false, nullptr);
+ } else if (action_ == Action::DELEGATE_ASYNC) {
+ QuicReferenceCountedPointer<ProofSource::Chain> chain =
+ delegate_->GetCertChain(server_address_, client_address_, hostname_);
+ bool ok = chain && !chain->certs.empty();
+ callback_->OnSelectCertificateDone(ok, /*is_sync=*/false, chain.get());
+ } else {
+ QUIC_BUG << "Unexpected action: " << static_cast<int>(action_);
+ }
+}
+
+FakeProofSourceHandle::ComputeSignatureOperation::ComputeSignatureOperation(
+ ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action action,
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size)
+ : PendingOperation(delegate, callback, action),
+ server_address_(server_address),
+ client_address_(client_address),
+ hostname_(hostname),
+ signature_algorithm_(signature_algorithm),
+ in_(in),
+ max_signature_size_(max_signature_size) {}
+
+void FakeProofSourceHandle::ComputeSignatureOperation::Run() {
+ if (action_ == Action::FAIL_ASYNC) {
+ callback_->OnComputeSignatureDone(
+ /*ok=*/false, /*is_sync=*/false,
+ /*signature=*/"", /*details=*/nullptr);
+ } else if (action_ == Action::DELEGATE_ASYNC) {
+ ComputeSignatureResult result =
+ ComputeSignatureNow(delegate_, server_address_, client_address_,
+ hostname_, signature_algorithm_, in_);
+ callback_->OnComputeSignatureDone(result.ok, /*is_sync=*/false,
+ result.signature,
+ std::move(result.details));
+ } else {
+ QUIC_BUG << "Unexpected action: " << static_cast<int>(action_);
+ }
+}
+
+} // namespace test
+} // namespace quic
diff --git a/quic/test_tools/fake_proof_source_handle.h b/quic/test_tools/fake_proof_source_handle.h
new file mode 100644
index 0000000..e013b90
--- /dev/null
+++ b/quic/test_tools/fake_proof_source_handle.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2021 The Chromium 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 QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_HANDLE_H_
+#define QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_HANDLE_H_
+
+#include "quic/core/crypto/proof_source.h"
+
+namespace quic {
+namespace test {
+
+// FakeProofSourceHandle allows its behavior to be scripted for testing.
+class FakeProofSourceHandle : public ProofSourceHandle {
+ public:
+ // What would an operation return when it is called.
+ enum class Action {
+ // Delegate the operation to |delegate_| immediately.
+ DELEGATE_SYNC = 0,
+ // Handle the operation asynchronously. Delegate the operation to
+ // |delegate_| when the caller calls CompletePendingOperation().
+ DELEGATE_ASYNC,
+ // Fail the operation immediately.
+ FAIL_SYNC,
+ // Handle the operation asynchronously. Fail the operation when the caller
+ // calls CompletePendingOperation().
+ FAIL_ASYNC,
+ };
+
+ // |delegate| must do cert selection and signature synchronously.
+ FakeProofSourceHandle(ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action select_cert_action,
+ Action compute_signature_action);
+
+ ~FakeProofSourceHandle() override = default;
+
+ void CancelPendingOperation() override;
+
+ QuicAsyncStatus SelectCertificate(
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context) override;
+
+ QuicAsyncStatus ComputeSignature(const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size) override;
+
+ ProofSourceHandleCallback* callback() override;
+
+ // Whether there's a pending operation in |this|.
+ bool HasPendingOperation() const;
+ void CompletePendingOperation();
+
+ private:
+ class PendingOperation {
+ public:
+ PendingOperation(ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action action)
+ : delegate_(delegate), callback_(callback), action_(action) {}
+ virtual ~PendingOperation() = default;
+ virtual void Run() = 0;
+
+ protected:
+ ProofSource* delegate_;
+ ProofSourceHandleCallback* callback_;
+ Action action_;
+ };
+
+ class SelectCertOperation : public PendingOperation {
+ public:
+ SelectCertOperation(
+ ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action action,
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ absl::string_view client_hello,
+ const std::string& alpn,
+ const std::vector<uint8_t>& quic_transport_params,
+ const absl::optional<std::vector<uint8_t>>& early_data_context);
+
+ ~SelectCertOperation() override = default;
+
+ void Run() override;
+
+ private:
+ QuicSocketAddress server_address_;
+ QuicSocketAddress client_address_;
+ std::string hostname_;
+ std::string client_hello_;
+ std::string alpn_;
+ std::vector<uint8_t> quic_transport_params_;
+ absl::optional<std::vector<uint8_t>> early_data_context_;
+ };
+
+ class ComputeSignatureOperation : public PendingOperation {
+ public:
+ ComputeSignatureOperation(ProofSource* delegate,
+ ProofSourceHandleCallback* callback,
+ Action action,
+ const QuicSocketAddress& server_address,
+ const QuicSocketAddress& client_address,
+ const std::string& hostname,
+ uint16_t signature_algorithm,
+ absl::string_view in,
+ size_t max_signature_size);
+
+ ~ComputeSignatureOperation() override = default;
+
+ void Run() override;
+
+ private:
+ QuicSocketAddress server_address_;
+ QuicSocketAddress client_address_;
+ std::string hostname_;
+ uint16_t signature_algorithm_;
+ std::string in_;
+ size_t max_signature_size_;
+ };
+
+ private:
+ int NumPendingOperations() const;
+
+ ProofSource* delegate_;
+ ProofSourceHandleCallback* callback_;
+ // Action for the next select cert operation.
+ Action select_cert_action_ = Action::DELEGATE_SYNC;
+ // Action for the next compute signature operation.
+ Action compute_signature_action_ = Action::DELEGATE_SYNC;
+ absl::optional<SelectCertOperation> select_cert_op_;
+ absl::optional<ComputeSignatureOperation> compute_signature_op_;
+};
+
+} // namespace test
+} // namespace quic
+
+#endif // QUICHE_QUIC_TEST_TOOLS_FAKE_PROOF_SOURCE_HANDLE_H_