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..002085e2ae50c706db75a81ec285be8fcd7896e1 |
--- /dev/null |
+++ b/net/quic/quartc/quartc_session.cc |
@@ -0,0 +1,288 @@ |
+// 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; |
+} |
+ |
+QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection, |
+ const QuicConfig& config, |
+ const std::string& remote_fingerprint_value, |
+ Perspective perspective, |
+ QuicConnectionHelperInterface* helper) |
+ : QuicSession(connection.get(), config), |
+ remote_fingerprint_value_(remote_fingerprint_value), |
+ perspective_(perspective), |
+ connection_(std::move(connection)), |
+ helper_(helper) { |
+ // 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); |
+ } |
+} |
+ |
+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::SetDelegate( |
+ QuartcSessionInterface::Delegate* session_delegate) { |
+ if (session_delegate_) { |
+ LOG(WARNING) << "The delegate for the session has already been set."; |
+ } |
+ session_delegate_ = session_delegate; |
+ DCHECK(session_delegate_); |
+} |
+ |
+void QuartcSession::OnTransportCanWrite() { |
+ if (HasDataToWrite()) { |
+ connection()->OnCanWrite(); |
+ } |
+} |
+ |
+bool QuartcSession::OnTransportReceived(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 |