|  | // 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) { | 
|  | QUICHE_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)); | 
|  | QUICHE_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, | 
|  | QuicDelayedSSLConfig dealyed_ssl_config) | 
|  | : delegate_(delegate), | 
|  | callback_(callback), | 
|  | select_cert_action_(select_cert_action), | 
|  | compute_signature_action_(compute_signature_action), | 
|  | dealyed_ssl_config_(dealyed_ssl_config) {} | 
|  |  | 
|  | void FakeProofSourceHandle::CloseHandle() { | 
|  | select_cert_op_.reset(); | 
|  | compute_signature_op_.reset(); | 
|  | closed_ = true; | 
|  | } | 
|  |  | 
|  | QuicAsyncStatus FakeProofSourceHandle::SelectCertificate( | 
|  | const QuicSocketAddress& server_address, | 
|  | const QuicSocketAddress& client_address, | 
|  | absl::string_view ssl_capabilities, | 
|  | const std::string& hostname, | 
|  | absl::string_view client_hello, | 
|  | const std::string& alpn, | 
|  | absl::optional<std::string> alps, | 
|  | const std::vector<uint8_t>& quic_transport_params, | 
|  | const absl::optional<std::vector<uint8_t>>& early_data_context, | 
|  | const QuicSSLConfig& ssl_config) { | 
|  | if (select_cert_action_ != Action::FAIL_SYNC_DO_NOT_CHECK_CLOSED) { | 
|  | QUICHE_CHECK(!closed_); | 
|  | } | 
|  | all_select_cert_args_.push_back(SelectCertArgs( | 
|  | server_address, client_address, ssl_capabilities, hostname, client_hello, | 
|  | alpn, alps, quic_transport_params, early_data_context, ssl_config)); | 
|  |  | 
|  | if (select_cert_action_ == Action::DELEGATE_ASYNC || | 
|  | select_cert_action_ == Action::FAIL_ASYNC) { | 
|  | select_cert_op_.emplace(delegate_, callback_, select_cert_action_, | 
|  | all_select_cert_args_.back(), dealyed_ssl_config_); | 
|  | return QUIC_PENDING; | 
|  | } else if (select_cert_action_ == Action::FAIL_SYNC || | 
|  | select_cert_action_ == Action::FAIL_SYNC_DO_NOT_CHECK_CLOSED) { | 
|  | callback()->OnSelectCertificateDone( | 
|  | /*ok=*/false, | 
|  | /*is_sync=*/true, nullptr, /*handshake_hints=*/absl::string_view(), | 
|  | /*ticket_encryption_key=*/absl::string_view(), | 
|  | /*cert_matched_sni=*/false, dealyed_ssl_config_); | 
|  | return QUIC_FAILURE; | 
|  | } | 
|  |  | 
|  | QUICHE_DCHECK(select_cert_action_ == Action::DELEGATE_SYNC); | 
|  | bool cert_matched_sni; | 
|  | QuicReferenceCountedPointer<ProofSource::Chain> chain = | 
|  | delegate_->GetCertChain(server_address, client_address, hostname, | 
|  | &cert_matched_sni); | 
|  |  | 
|  | bool ok = chain && !chain->certs.empty(); | 
|  | callback_->OnSelectCertificateDone( | 
|  | ok, /*is_sync=*/true, chain.get(), | 
|  | /*handshake_hints=*/absl::string_view(), | 
|  | /*ticket_encryption_key=*/absl::string_view(), | 
|  | /*cert_matched_sni=*/cert_matched_sni, dealyed_ssl_config_); | 
|  | 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::FAIL_SYNC_DO_NOT_CHECK_CLOSED) { | 
|  | QUICHE_CHECK(!closed_); | 
|  | } | 
|  | all_compute_signature_args_.push_back( | 
|  | ComputeSignatureArgs(server_address, client_address, hostname, | 
|  | signature_algorithm, in, 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_, | 
|  | all_compute_signature_args_.back()); | 
|  | return QUIC_PENDING; | 
|  | } else if (compute_signature_action_ == Action::FAIL_SYNC || | 
|  | compute_signature_action_ == | 
|  | Action::FAIL_SYNC_DO_NOT_CHECK_CLOSED) { | 
|  | callback()->OnComputeSignatureDone(/*ok=*/false, /*is_sync=*/true, | 
|  | /*signature=*/"", /*details=*/nullptr); | 
|  | return QUIC_FAILURE; | 
|  | } | 
|  |  | 
|  | QUICHE_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() { | 
|  | QUICHE_DCHECK_LE(NumPendingOperations(), 1); | 
|  |  | 
|  | if (select_cert_op_.has_value()) { | 
|  | select_cert_op_->Run(); | 
|  | select_cert_op_.reset(); | 
|  | } else if (compute_signature_op_.has_value()) { | 
|  | compute_signature_op_->Run(); | 
|  | compute_signature_op_.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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, | 
|  | SelectCertArgs args, QuicDelayedSSLConfig dealyed_ssl_config) | 
|  | : PendingOperation(delegate, callback, action), | 
|  | args_(std::move(args)), | 
|  | dealyed_ssl_config_(dealyed_ssl_config) {} | 
|  |  | 
|  | void FakeProofSourceHandle::SelectCertOperation::Run() { | 
|  | if (action_ == Action::FAIL_ASYNC) { | 
|  | callback_->OnSelectCertificateDone( | 
|  | /*ok=*/false, | 
|  | /*is_sync=*/false, nullptr, | 
|  | /*handshake_hints=*/absl::string_view(), | 
|  | /*ticket_encryption_key=*/absl::string_view(), | 
|  | /*cert_matched_sni=*/false, dealyed_ssl_config_); | 
|  | } else if (action_ == Action::DELEGATE_ASYNC) { | 
|  | bool cert_matched_sni; | 
|  | QuicReferenceCountedPointer<ProofSource::Chain> chain = | 
|  | delegate_->GetCertChain(args_.server_address, args_.client_address, | 
|  | args_.hostname, &cert_matched_sni); | 
|  | bool ok = chain && !chain->certs.empty(); | 
|  | callback_->OnSelectCertificateDone( | 
|  | ok, /*is_sync=*/false, chain.get(), | 
|  | /*handshake_hints=*/absl::string_view(), | 
|  | /*ticket_encryption_key=*/absl::string_view(), | 
|  | /*cert_matched_sni=*/cert_matched_sni, dealyed_ssl_config_); | 
|  | } else { | 
|  | QUIC_BUG(quic_bug_10139_1) | 
|  | << "Unexpected action: " << static_cast<int>(action_); | 
|  | } | 
|  | } | 
|  |  | 
|  | FakeProofSourceHandle::ComputeSignatureOperation::ComputeSignatureOperation( | 
|  | ProofSource* delegate, | 
|  | ProofSourceHandleCallback* callback, | 
|  | Action action, | 
|  | ComputeSignatureArgs args) | 
|  | : PendingOperation(delegate, callback, action), args_(std::move(args)) {} | 
|  |  | 
|  | 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_, args_.server_address, args_.client_address, args_.hostname, | 
|  | args_.signature_algorithm, args_.in); | 
|  | callback_->OnComputeSignatureDone(result.ok, /*is_sync=*/false, | 
|  | result.signature, | 
|  | std::move(result.details)); | 
|  | } else { | 
|  | QUIC_BUG(quic_bug_10139_2) | 
|  | << "Unexpected action: " << static_cast<int>(action_); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace quic |