Chromium Code Reviews| Index: net/quic/quartc/quartc_session.cc |
| diff --git a/net/quic/quartc/quartc_session.cc b/net/quic/quartc/quartc_session.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..74ec9ce9ae67ce6b532b31919d8c0f37e2d250b9 |
| --- /dev/null |
| +++ b/net/quic/quartc/quartc_session.cc |
| @@ -0,0 +1,296 @@ |
| +// Copyright (c) 2016 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 "net/quic/quartc/quartc_session.h" |
| + |
| +#include "base/rand_util.h" |
| + |
| +namespace { |
| + |
| +// Default priority for incoming QUIC streams. |
| +// TODO(zhihuang): Determine if this value is correct. |
| +static const net::SpdyPriority kDefaultPriority = 3; |
| + |
| +// Arbitrary server port number for net::QuicCryptoClientConfig. |
| +const int kQuicServerPort = 0; |
| + |
| +// Length of HKDF input keying material, equal to its number of bytes. |
| +// https://tools.ietf.org/html/rfc5869#section-2.2. |
| +// TODO(zhihuang): Verify that input keying material length is correct. |
| +const size_t kInputKeyingMaterialLength = 32; |
| + |
| +// Used by QuicCryptoServerConfig to provide dummy proof credentials. |
| +// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. |
| +class DummyProofSource : public net::ProofSource { |
| + public: |
| + DummyProofSource() {} |
| + ~DummyProofSource() override {} |
| + |
| + // ProofSource override. |
| + bool GetProof(const net::IPAddress& server_ip, |
| + const std::string& hostname, |
| + const std::string& server_config, |
| + net::QuicVersion quic_version, |
| + base::StringPiece chlo_hash, |
| + scoped_refptr<net::ProofSource::Chain>* out_chain, |
| + std::string* out_signature, |
| + std::string* out_leaf_cert_sct) override { |
| + std::vector<std::string> certs; |
| + certs.push_back("Dummy cert"); |
| + *out_chain = new ProofSource::Chain(certs); |
| + *out_signature = "Dummy signature"; |
| + *out_leaf_cert_sct = "Dummy timestamp"; |
| + return true; |
| + } |
| + |
| + void GetProof(const net::IPAddress& server_ip, |
| + const std::string& hostname, |
| + const std::string& server_config, |
| + net::QuicVersion quic_version, |
| + base::StringPiece chlo_hash, |
| + std::unique_ptr<Callback> callback) override {} |
| +}; |
| + |
| +// Used by QuicCryptoClientConfig to ignore the peer's credentials |
| +// and establish an insecure QUIC connection. |
| +// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. |
| +class InsecureProofVerifier : public net::ProofVerifier { |
| + public: |
| + InsecureProofVerifier() {} |
| + ~InsecureProofVerifier() override {} |
| + |
| + // ProofVerifier override. |
| + net::QuicAsyncStatus VerifyProof( |
| + const std::string& hostname, |
| + const uint16_t port, |
| + const std::string& server_config, |
| + net::QuicVersion quic_version, |
| + base::StringPiece chlo_hash, |
| + const std::vector<std::string>& certs, |
| + const std::string& cert_sct, |
| + const std::string& signature, |
| + const net::ProofVerifyContext* context, |
| + std::string* error_details, |
| + std::unique_ptr<net::ProofVerifyDetails>* verify_details, |
| + std::unique_ptr<net::ProofVerifierCallback> callback) override { |
| + return net::QUIC_SUCCESS; |
| + } |
| + |
| + net::QuicAsyncStatus VerifyCertChain( |
| + const std::string& hostname, |
| + const std::vector<std::string>& certs, |
| + const net::ProofVerifyContext* context, |
| + std::string* error_details, |
| + std::unique_ptr<net::ProofVerifyDetails>* details, |
| + std::unique_ptr<net::ProofVerifierCallback> callback) override { |
| + return net::QUIC_SUCCESS; |
| + } |
| +}; |
| +} |
| + |
| +namespace net { |
| + |
| +QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject( |
| + QuicConnectionId connection_id) const { |
| + return 0; |
| +} |
| + |
| +bool QuartcCryptoServerStreamHelper::CanAcceptClientHello( |
| + const CryptoHandshakeMessage& message, |
| + const IPEndPoint& self_address, |
| + std::string* error_details) const { |
| + return true; |
| +} |
| + |
| +void QuartcSessionTransportDelegate::OnCanWrite() { |
| + OnQuartcCanWrite(); |
| +} |
| + |
| +QuartcSession::QuartcSession( |
| + std::unique_ptr<QuicConnection> connection, |
| + const QuicConfig& config, |
| + const std::string& remote_fingerprint_value, |
| + Perspective perspective, |
| + QuartcSessionInterface::Transport* session_transport) |
| + : QuicSession(connection.get(), config), |
| + remote_fingerprint_value_(remote_fingerprint_value), |
| + perspective_(perspective), |
| + connection_(std::move(connection)), |
| + session_transport_(session_transport) { |
| + // Initialization with default crypto configuration. |
| + if (perspective_ == Perspective::IS_CLIENT) { |
| + std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier); |
| + quic_crypto_client_config_.reset( |
| + new QuicCryptoClientConfig(std::move(proof_verifier))); |
| + } else { |
| + std::unique_ptr<ProofSource> proof_source(new DummyProofSource); |
| + std::string source_address_token_secret = |
| + base::RandBytesAsString(kInputKeyingMaterialLength); |
| + quic_crypto_server_config_.reset(new QuicCryptoServerConfig( |
| + source_address_token_secret, helper_.GetRandomGenerator(), |
| + std::move(proof_source))); |
| + // Provide server with serialized config string to prove ownership. |
| + QuicCryptoServerConfig::ConfigOptions options; |
| + quic_crypto_server_config_->AddDefaultConfig(helper_.GetRandomGenerator(), |
| + helper_.GetClock(), options); |
| + } |
| + // Set the delegate for the |session_transport_|. |
| + DCHECK(session_transport_); |
| + session_transport_->SetDelegate(this); |
| +} |
| + |
| +QuartcSession::~QuartcSession() {} |
| + |
| +QuicCryptoStream* QuartcSession::GetCryptoStream() { |
| + return crypto_stream_.get(); |
| +} |
| + |
| +QuartcStream* QuartcSession::CreateOutgoingDynamicStream( |
| + SpdyPriority priority) { |
| + return CreateDataStream(GetNextOutgoingStreamId(), priority); |
| +} |
| + |
| +void QuartcSession::OnCryptoHandshakeEvent(CryptoHandshakeEvent event) { |
| + QuicSession::OnCryptoHandshakeEvent(event); |
| + if (event == HANDSHAKE_CONFIRMED) { |
| + DCHECK(IsEncryptionEstablished()); |
| + DCHECK(IsCryptoHandshakeConfirmed()); |
| + |
| + DCHECK(session_delegate_); |
| + session_delegate_->OnCryptoHandshakeComplete(); |
| + } |
| +} |
| + |
| +void QuartcSession::CloseStream(QuicStreamId stream_id) { |
| + if (IsClosedStream(stream_id)) { |
| + // When CloseStream has been called recursively (via |
| + // ReliableQuicStream::OnClose), the stream is already closed so return. |
| + return; |
| + } |
| + write_blocked_streams()->UnregisterStream(stream_id); |
| + QuicSession::CloseStream(stream_id); |
| +} |
| + |
| +void QuartcSession::OnConnectionClosed(QuicErrorCode error, |
| + const std::string& error_details, |
| + ConnectionCloseSource source) { |
| + QuicSession::OnConnectionClosed(error, error_details, source); |
| + DCHECK(session_delegate_); |
| + session_delegate_->OnConnectionClosed( |
| + error, source == ConnectionCloseSource::FROM_PEER); |
| +} |
| + |
| +void QuartcSession::StartCryptoHandshake() { |
| + if (perspective_ == Perspective::IS_CLIENT) { |
| + QuicServerId server_id(remote_fingerprint_value_, kQuicServerPort); |
| + QuicCryptoClientStream* crypto_stream = |
| + new QuicCryptoClientStream(server_id, this, new ProofVerifyContext(), |
| + quic_crypto_client_config_.get(), this); |
| + crypto_stream_.reset(crypto_stream); |
| + QuicSession::Initialize(); |
| + crypto_stream->CryptoConnect(); |
| + } else { |
| + quic_compressed_certs_cache_.reset(new QuicCompressedCertsCache( |
| + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)); |
| + bool use_stateless_rejects_if_peer_supported = false; |
| + QuicCryptoServerStream* crypto_stream = new QuicCryptoServerStream( |
| + quic_crypto_server_config_.get(), quic_compressed_certs_cache_.get(), |
| + use_stateless_rejects_if_peer_supported, this, &stream_helper_); |
| + crypto_stream_.reset(crypto_stream); |
| + QuicSession::Initialize(); |
| + } |
| +} |
| + |
| +bool QuartcSession::ExportKeyingMaterial(const std::string& label, |
| + const uint8_t* context, |
| + size_t context_len, |
| + bool used_context, |
| + uint8_t* result, |
| + size_t result_len) { |
| + std::string quic_context(reinterpret_cast<const char*>(context), context_len); |
| + std::string quic_result; |
| + bool success = crypto_stream_->ExportKeyingMaterial(label, quic_context, |
| + result_len, &quic_result); |
| + quic_result.copy(reinterpret_cast<char*>(result), result_len); |
| + DCHECK(quic_result.length() == result_len); |
| + return success; |
| +} |
| + |
| +QuartcStreamInterface* QuartcSession::CreateOutgoingStream( |
| + const OutgoingStreamParameters& param) { |
| + // The |param| is for forward-compatibility. Not used for now. |
| + return CreateOutgoingDynamicStream(kDefaultPriority); |
| +} |
| + |
| +void QuartcSession::OnQuartcCanWrite() { |
| + connection()->OnCanWrite(); |
| +} |
| + |
| +void QuartcSession::SetDelegate( |
| + QuartcSessionInterface::Delegate* session_delegate) { |
| + if (session_delegate_) { |
| + DVLOG(1) << "The delegate for the session has already been set."; |
| + return; |
| + } |
| + session_delegate_ = session_delegate; |
| + DCHECK(session_delegate_); |
| +} |
| + |
| +// Decrypts an incoming QUIC packet to a data stream. |
|
pthatcher2
2016/10/05 22:12:06
I don't think this comment is needed.
zhihuang1
2016/10/13 06:22:40
Done.
|
| +bool QuartcSession::OnReceived(const char* data, size_t data_len) { |
| + QuicReceivedPacket packet(data, data_len, clock_.Now()); |
| + ProcessUdpPacket(connection()->self_address(), connection()->peer_address(), |
| + packet); |
| + return true; |
| +} |
| + |
| +void QuartcSession::OnProofValid( |
| + const QuicCryptoClientConfig::CachedState& cached) { |
| + // TODO(zhihuang): Handle the proof verification. |
| +} |
| + |
| +void QuartcSession::OnProofVerifyDetailsAvailable( |
| + const ProofVerifyDetails& verify_details) { |
| + // TODO(zhihuang): Handle the proof verification. |
| +} |
| + |
| +void QuartcSession::SetClientCryptoConfig( |
| + QuicCryptoClientConfig* client_config) { |
| + quic_crypto_client_config_.reset(client_config); |
| +} |
| + |
| +void QuartcSession::SetServerCryptoConfig( |
| + QuicCryptoServerConfig* server_config) { |
| + quic_crypto_server_config_.reset(server_config); |
| +} |
| + |
| +ReliableQuicStream* QuartcSession::CreateIncomingDynamicStream( |
| + QuicStreamId id) { |
| + QuartcStream* stream = CreateDataStream(id, kDefaultPriority); |
| + if (stream) { |
| + DCHECK(session_delegate_); |
| + session_delegate_->OnIncomingStream(stream); |
| + } |
| + return stream; |
| +} |
| + |
| +QuartcStream* QuartcSession::CreateDataStream(QuicStreamId id, |
| + SpdyPriority priority) { |
| + if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) { |
| + // Encryption not active so no stream created |
| + return nullptr; |
| + } |
| + QuartcStream* stream = new QuartcStream(id, this); |
| + if (stream) { |
| + // Make QuicSession take ownership of the stream. |
| + ActivateStream(stream); |
| + // Register the stream to the QuicWriteBlockedList. |priority| is clamped |
| + // between 0 and 7, with 0 being the highest priority and 7 the lowest |
| + // priority. |
| + write_blocked_streams()->RegisterStream(stream->id(), priority); |
| + } |
| + return stream; |
| +} |
| + |
| +} // namespace net |