blob: e37a5707ba5fd1377d17fd79c718553f016be62c [file] [log] [blame]
// Copyright (c) 2012 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_CORE_QUIC_CRYPTO_CLIENT_STREAM_H_
#define QUICHE_QUIC_CORE_QUIC_CRYPTO_CLIENT_STREAM_H_
#include <cstdint>
#include <memory>
#include <string>
#include "quic/core/crypto/proof_verifier.h"
#include "quic/core/crypto/quic_crypto_client_config.h"
#include "quic/core/proto/cached_network_parameters_proto.h"
#include "quic/core/quic_config.h"
#include "quic/core/quic_crypto_handshaker.h"
#include "quic/core/quic_crypto_stream.h"
#include "quic/core/quic_server_id.h"
#include "quic/core/quic_session.h"
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_export.h"
namespace quic {
namespace test {
class QuicCryptoClientStreamPeer;
} // namespace test
class TlsClientHandshaker;
class QUIC_EXPORT_PRIVATE QuicCryptoClientStreamBase : public QuicCryptoStream {
public:
explicit QuicCryptoClientStreamBase(QuicSession* session);
~QuicCryptoClientStreamBase() override {}
// Performs a crypto handshake with the server. Returns true if the connection
// is still connected.
virtual bool CryptoConnect() = 0;
// DEPRECATED: Use IsResumption, EarlyDataAccepted, and/or
// ReceivedInchoateReject instead.
//
// num_sent_client_hellos returns the number of client hello messages that
// have been sent. If the handshake has completed then this is one greater
// than the number of round-trips needed for the handshake.
virtual int num_sent_client_hellos() const = 0;
// Returns true if the handshake performed was a resumption instead of a full
// handshake. Resumption only makes sense for TLS handshakes - there is no
// concept of resumption for QUIC crypto even though it supports a 0-RTT
// handshake. This function only returns valid results once the handshake is
// complete.
virtual bool IsResumption() const = 0;
// Returns true if early data (0-RTT) was accepted in the connection.
virtual bool EarlyDataAccepted() const = 0;
// Returns true if the client received an inchoate REJ during the handshake,
// extending the handshake by one round trip. This only applies for QUIC
// crypto handshakes. The equivalent feature in IETF QUIC is a Retry packet,
// but that is handled at the connection layer instead of the crypto layer.
virtual bool ReceivedInchoateReject() const = 0;
// The number of server config update messages received by the
// client. Does not count update messages that were received prior
// to handshake confirmation.
virtual int num_scup_messages_received() const = 0;
bool ExportKeyingMaterial(absl::string_view /*label*/,
absl::string_view /*context*/,
size_t /*result_len*/,
std::string* /*result*/) override {
QUICHE_NOTREACHED();
return false;
}
std::string GetAddressToken(
const CachedNetworkParameters* /*cached_network_params*/) const override {
QUICHE_DCHECK(false);
return "";
}
bool ValidateAddressToken(absl::string_view /*token*/) const override {
QUICHE_DCHECK(false);
return false;
}
const CachedNetworkParameters* PreviousCachedNetworkParams() const override {
QUICHE_DCHECK(false);
return nullptr;
}
void SetPreviousCachedNetworkParams(
CachedNetworkParameters /*cached_network_params*/) override {
QUICHE_DCHECK(false);
}
};
class QUIC_EXPORT_PRIVATE QuicCryptoClientStream
: public QuicCryptoClientStreamBase {
public:
// kMaxClientHellos is the maximum number of times that we'll send a client
// hello. The value 4 accounts for:
// * One failure due to an incorrect or missing source-address token.
// * One failure due the server's certificate chain being unavailible and
// the server being unwilling to send it without a valid source-address
// token.
// * One failure due to the ServerConfig private key being located on a
// remote oracle which has become unavailable, forcing the server to send
// the client a fallback ServerConfig.
static const int kMaxClientHellos = 4;
// QuicCryptoClientStream creates a HandshakerInterface at construction time
// based on the QuicTransportVersion of the connection. Different
// HandshakerInterfaces provide implementations of different crypto handshake
// protocols. Currently QUIC crypto is the only protocol implemented; a future
// HandshakerInterface will use TLS as the handshake protocol.
// QuicCryptoClientStream delegates all of its public methods to its
// HandshakerInterface.
//
// This setup of the crypto stream delegating its implementation to the
// handshaker results in the handshaker reading and writing bytes on the
// crypto stream, instead of the handshaker passing the stream bytes to send.
class QUIC_EXPORT_PRIVATE HandshakerInterface {
public:
virtual ~HandshakerInterface() {}
// Performs a crypto handshake with the server. Returns true if the
// connection is still connected.
virtual bool CryptoConnect() = 0;
// DEPRECATED: Use IsResumption, EarlyDataAccepted, and/or
// ReceivedInchoateReject instead.
//
// num_sent_client_hellos returns the number of client hello messages that
// have been sent. If the handshake has completed then this is one greater
// than the number of round-trips needed for the handshake.
virtual int num_sent_client_hellos() const = 0;
// Returns true if the handshake performed was a resumption instead of a
// full handshake. Resumption only makes sense for TLS handshakes - there is
// no concept of resumption for QUIC crypto even though it supports a 0-RTT
// handshake. This function only returns valid results once the handshake is
// complete.
virtual bool IsResumption() const = 0;
// Returns true if early data (0-RTT) was accepted in the connection.
virtual bool EarlyDataAccepted() const = 0;
// Returns the ssl_early_data_reason_t describing why 0-RTT was accepted or
// rejected.
virtual ssl_early_data_reason_t EarlyDataReason() const = 0;
// Returns true if the client received an inchoate REJ during the handshake,
// extending the handshake by one round trip. This only applies for QUIC
// crypto handshakes. The equivalent feature in IETF QUIC is a Retry packet,
// but that is handled at the connection layer instead of the crypto layer.
virtual bool ReceivedInchoateReject() const = 0;
// The number of server config update messages received by the
// client. Does not count update messages that were received prior
// to handshake confirmation.
virtual int num_scup_messages_received() const = 0;
virtual std::string chlo_hash() const = 0;
// Returns true once any encrypter (initial/0RTT or final/1RTT) has been set
// for the connection.
virtual bool encryption_established() const = 0;
// Returns true once 1RTT keys are available.
virtual bool one_rtt_keys_available() const = 0;
// Returns the parameters negotiated in the crypto handshake.
virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const = 0;
// Used by QuicCryptoStream to parse data received on this stream.
virtual CryptoMessageParser* crypto_message_parser() = 0;
// Used by QuicCryptoStream to know how much unprocessed data can be
// buffered at each encryption level.
virtual size_t BufferSizeLimitForLevel(EncryptionLevel level) const = 0;
// Returns whether the implementation supports key update.
virtual bool KeyUpdateSupportedLocally() const = 0;
// Called to generate a decrypter for the next key phase. Each call should
// generate the key for phase n+1.
virtual std::unique_ptr<QuicDecrypter>
AdvanceKeysAndCreateCurrentOneRttDecrypter() = 0;
// Called to generate an encrypter for the same key phase of the last
// decrypter returned by AdvanceKeysAndCreateCurrentOneRttDecrypter().
virtual std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() = 0;
// Returns current handshake state.
virtual HandshakeState GetHandshakeState() const = 0;
// Called when a 1RTT packet has been acknowledged.
virtual void OnOneRttPacketAcknowledged() = 0;
// Called when a packet of ENCRYPTION_HANDSHAKE gets sent.
virtual void OnHandshakePacketSent() = 0;
// Called when connection gets closed.
virtual void OnConnectionClosed(QuicErrorCode error,
ConnectionCloseSource source) = 0;
// Called when handshake done has been received.
virtual void OnHandshakeDoneReceived() = 0;
// Called when new token has been received.
virtual void OnNewTokenReceived(absl::string_view token) = 0;
// Called when application state is received.
virtual void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) = 0;
// Called to obtain keying material export of length |result_len| with the
// given |label| and |context|. Returns false on failure.
virtual bool ExportKeyingMaterial(absl::string_view label,
absl::string_view context,
size_t result_len,
std::string* result) = 0;
};
// ProofHandler is an interface that handles callbacks from the crypto
// stream when the client has proof verification details of the server.
class QUIC_EXPORT_PRIVATE ProofHandler {
public:
virtual ~ProofHandler() {}
// Called when the proof in |cached| is marked valid. If this is a secure
// QUIC session, then this will happen only after the proof verifier
// completes.
virtual void OnProofValid(
const QuicCryptoClientConfig::CachedState& cached) = 0;
// Called when proof verification details become available, either because
// proof verification is complete, or when cached details are used. This
// will only be called for secure QUIC connections.
virtual void OnProofVerifyDetailsAvailable(
const ProofVerifyDetails& verify_details) = 0;
};
QuicCryptoClientStream(const QuicServerId& server_id,
QuicSession* session,
std::unique_ptr<ProofVerifyContext> verify_context,
QuicCryptoClientConfig* crypto_config,
ProofHandler* proof_handler,
bool has_application_state);
QuicCryptoClientStream(const QuicCryptoClientStream&) = delete;
QuicCryptoClientStream& operator=(const QuicCryptoClientStream&) = delete;
~QuicCryptoClientStream() override;
// From QuicCryptoClientStreamBase
bool CryptoConnect() override;
int num_sent_client_hellos() const override;
bool IsResumption() const override;
bool EarlyDataAccepted() const override;
ssl_early_data_reason_t EarlyDataReason() const override;
bool ReceivedInchoateReject() const override;
int num_scup_messages_received() const override;
// From QuicCryptoStream
bool encryption_established() const override;
bool one_rtt_keys_available() const override;
const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
const override;
CryptoMessageParser* crypto_message_parser() override;
void OnPacketDecrypted(EncryptionLevel /*level*/) override {}
void OnOneRttPacketAcknowledged() override;
void OnHandshakePacketSent() override;
void OnConnectionClosed(QuicErrorCode error,
ConnectionCloseSource source) override;
void OnHandshakeDoneReceived() override;
void OnNewTokenReceived(absl::string_view token) override;
HandshakeState GetHandshakeState() const override;
void SetServerApplicationStateForResumption(
std::unique_ptr<ApplicationState> application_state) override;
size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
bool KeyUpdateSupportedLocally() const override;
std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
override;
std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override;
SSL* GetSsl() const override;
bool ExportKeyingMaterial(absl::string_view label, absl::string_view context,
size_t result_len, std::string* result) override;
std::string chlo_hash() const;
protected:
void set_handshaker(std::unique_ptr<HandshakerInterface> handshaker) {
handshaker_ = std::move(handshaker);
}
private:
friend class test::QuicCryptoClientStreamPeer;
std::unique_ptr<HandshakerInterface> handshaker_;
// Points to |handshaker_| if it uses TLS1.3. Otherwise, nullptr.
// TODO(danzh) change the type of |handshaker_| to TlsClientHandshaker after
// deprecating Google QUIC.
TlsClientHandshaker* tls_handshaker_{nullptr};
};
} // namespace quic
#endif // QUICHE_QUIC_CORE_QUIC_CRYPTO_CLIENT_STREAM_H_