/* * Copyright 2016 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/p2p/quic/quictransportchannel.h" #include #include #include #include #include "webrtc/base/common.h" #include "webrtc/base/gunit.h" #include "webrtc/base/sslidentity.h" #include "webrtc/p2p/base/faketransportcontroller.h" using cricket::ConnectionRole; using cricket::IceRole; using cricket::QuicTransportChannel; using cricket::ReliableQuicStream; using cricket::TransportChannel; using cricket::TransportDescription; // Timeout in milliseconds for asynchronous operations in unit tests. static const int kTimeoutMs = 1000; // Export keying material parameters. static const char kExporterLabel[] = "label"; static const uint8_t kExporterContext[] = "context"; static const size_t kExporterContextLength = sizeof(kExporterContext); static const size_t kOutputKeyLength = 20; // Packet size for SRTP. static const size_t kPacketSize = 100; // Indicates ICE channel has no write error. static const int kNoWriteError = 0; // ICE parameters. static const char kIceUfrag[] = "TESTICEUFRAG0001"; static const char kIcePwd[] = "TESTICEPWD00000000000001"; // QUIC packet parameters. static const net::IPAddress kIpAddress(0, 0, 0, 0); static const net::IPEndPoint kIpEndpoint(kIpAddress, 0); // Detects incoming RTP packets. static bool IsRtpLeadByte(uint8_t b) { return (b & 0xC0) == 0x80; } // Maps SSL role to ICE connection role. The peer with a client role is assumed // to be the one who initiates the connection. static ConnectionRole SslRoleToConnectionRole(rtc::SSLRole ssl_role) { return (ssl_role == rtc::SSL_CLIENT) ? cricket::CONNECTIONROLE_ACTIVE : cricket::CONNECTIONROLE_PASSIVE; } // Allows cricket::FakeTransportChannel to simulate write blocked // and write error states. // TODO(mikescarlett): Add this functionality to cricket::FakeTransportChannel. class FailableTransportChannel : public cricket::FakeTransportChannel { public: FailableTransportChannel(const std::string& name, int component) : cricket::FakeTransportChannel(name, component), error_(kNoWriteError) {} int GetError() override { return error_; } void SetError(int error) { error_ = error; } int SendPacket(const char* data, size_t len, const rtc::PacketOptions& options, int flags) override { if (error_ == kNoWriteError) { return cricket::FakeTransportChannel::SendPacket(data, len, options, flags); } return -1; } private: int error_; }; // Peer who establishes a handshake using a QuicTransportChannel, which wraps // a FailableTransportChannel to simulate network connectivity and ICE // negotiation. class QuicTestPeer : public sigslot::has_slots<> { public: explicit QuicTestPeer(const std::string& name) : name_(name), bytes_sent_(0), ice_channel_(new FailableTransportChannel(name_, 0)), quic_channel_(ice_channel_), incoming_stream_count_(0) { quic_channel_.SignalReadPacket.connect( this, &QuicTestPeer::OnTransportChannelReadPacket); quic_channel_.SignalIncomingStream.connect(this, &QuicTestPeer::OnIncomingStream); quic_channel_.SignalClosed.connect(this, &QuicTestPeer::OnClosed); ice_channel_->SetAsync(true); rtc::scoped_refptr local_cert = rtc::RTCCertificate::Create(std::unique_ptr( rtc::SSLIdentity::Generate(name_, rtc::KT_DEFAULT))); quic_channel_.SetLocalCertificate(local_cert); local_fingerprint_.reset(CreateFingerprint(local_cert.get())); } // Connects |ice_channel_| to that of the other peer. void Connect(QuicTestPeer* other_peer) { ice_channel_->Connect(); other_peer->ice_channel_->Connect(); ice_channel_->SetDestination(other_peer->ice_channel_); } // Disconnects |ice_channel_|. void Disconnect() { ice_channel_->SetDestination(nullptr); } // Generates ICE credentials and passes them to |quic_channel_|. void SetIceParameters(IceRole local_ice_role, ConnectionRole local_connection_role, ConnectionRole remote_connection_role, rtc::SSLFingerprint* remote_fingerprint) { quic_channel_.SetIceRole(local_ice_role); quic_channel_.SetIceTiebreaker( (local_ice_role == cricket::ICEROLE_CONTROLLING) ? 1 : 2); TransportDescription local_desc( std::vector(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL, local_connection_role, local_fingerprint_.get()); TransportDescription remote_desc( std::vector(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL, remote_connection_role, remote_fingerprint); quic_channel_.SetIceCredentials(local_desc.ice_ufrag, local_desc.ice_pwd); quic_channel_.SetRemoteIceCredentials(remote_desc.ice_ufrag, remote_desc.ice_pwd); } // Creates fingerprint from certificate. rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { std::string digest_algorithm; bool get_digest_algorithm = cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); if (!get_digest_algorithm || digest_algorithm.empty()) { return nullptr; } std::unique_ptr fingerprint( rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); if (digest_algorithm != rtc::DIGEST_SHA_256) { return nullptr; } return fingerprint.release(); } // Sends SRTP packet to the other peer via |quic_channel_|. int SendSrtpPacket() { char packet[kPacketSize]; packet[0] = 0x80; // Make the packet header look like RTP. int rv = quic_channel_.SendPacket( &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS); bytes_sent_ += rv; return rv; } // Sends a non-SRTP packet with the PF_SRTP_BYPASS flag via |quic_channel_|. int SendInvalidSrtpPacket() { char packet[kPacketSize]; // Fill the packet with 0 to form an invalid SRTP packet. memset(packet, 0, kPacketSize); return quic_channel_.SendPacket( &packet[0], kPacketSize, rtc::PacketOptions(), cricket::PF_SRTP_BYPASS); } // Sends an RTP packet to the other peer via |quic_channel_|, without the SRTP // bypass flag. int SendRtpPacket() { char packet[kPacketSize]; packet[0] = 0x80; // Make the packet header look like RTP. return quic_channel_.SendPacket(&packet[0], kPacketSize, rtc::PacketOptions(), 0); } void ClearBytesSent() { bytes_sent_ = 0; } void ClearBytesReceived() { bytes_received_ = 0; } void SetWriteError(int error) { ice_channel_->SetError(error); } size_t bytes_received() const { return bytes_received_; } size_t bytes_sent() const { return bytes_sent_; } FailableTransportChannel* ice_channel() { return ice_channel_; } QuicTransportChannel* quic_channel() { return &quic_channel_; } std::unique_ptr& local_fingerprint() { return local_fingerprint_; } ReliableQuicStream* incoming_quic_stream() { return incoming_quic_stream_; } size_t incoming_stream_count() const { return incoming_stream_count_; } bool signal_closed_emitted() const { return signal_closed_emitted_; } private: // QuicTransportChannel callbacks. void OnTransportChannelReadPacket(TransportChannel* channel, const char* data, size_t size, const rtc::PacketTime& packet_time, int flags) { bytes_received_ += size; // Only SRTP packets should have the bypass flag set. int expected_flags = IsRtpLeadByte(data[0]) ? cricket::PF_SRTP_BYPASS : 0; ASSERT_EQ(expected_flags, flags); } void OnIncomingStream(ReliableQuicStream* stream) { incoming_quic_stream_ = stream; ++incoming_stream_count_; } void OnClosed() { signal_closed_emitted_ = true; } std::string name_; // Channel name. size_t bytes_sent_; // Bytes sent by QUIC channel. size_t bytes_received_; // Bytes received by QUIC channel. FailableTransportChannel* ice_channel_; // Simulates an ICE channel. QuicTransportChannel quic_channel_; // QUIC channel to test. std::unique_ptr local_fingerprint_; ReliableQuicStream* incoming_quic_stream_ = nullptr; size_t incoming_stream_count_; bool signal_closed_emitted_ = false; }; class QuicTransportChannelTest : public testing::Test { public: QuicTransportChannelTest() : peer1_("P1"), peer2_("P2") {} // Performs negotiation before QUIC handshake, then connects the fake // transport channels of each peer. As a side effect, the QUIC channels // start sending handshake messages. |peer1_| has a client role and |peer2_| // has server role in the QUIC handshake. void Connect() { SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER); peer1_.Connect(&peer2_); } // Disconnects the fake transport channels. void Disconnect() { peer1_.Disconnect(); peer2_.Disconnect(); } // Sets up ICE parameters and exchanges fingerprints before QUIC handshake. void SetIceAndCryptoParameters(rtc::SSLRole peer1_ssl_role, rtc::SSLRole peer2_ssl_role) { peer1_.quic_channel()->SetSslRole(peer1_ssl_role); peer2_.quic_channel()->SetSslRole(peer2_ssl_role); std::unique_ptr& peer1_fingerprint = peer1_.local_fingerprint(); std::unique_ptr& peer2_fingerprint = peer2_.local_fingerprint(); peer1_.quic_channel()->SetRemoteFingerprint( peer2_fingerprint->algorithm, reinterpret_cast(peer2_fingerprint->digest.data()), peer2_fingerprint->digest.size()); peer2_.quic_channel()->SetRemoteFingerprint( peer1_fingerprint->algorithm, reinterpret_cast(peer1_fingerprint->digest.data()), peer1_fingerprint->digest.size()); ConnectionRole peer1_connection_role = SslRoleToConnectionRole(peer1_ssl_role); ConnectionRole peer2_connection_role = SslRoleToConnectionRole(peer2_ssl_role); peer1_.SetIceParameters(cricket::ICEROLE_CONTROLLED, peer1_connection_role, peer2_connection_role, peer2_fingerprint.get()); peer2_.SetIceParameters(cricket::ICEROLE_CONTROLLING, peer2_connection_role, peer1_connection_role, peer1_fingerprint.get()); } // Checks if QUIC handshake is done. bool quic_connected() { return peer1_.quic_channel()->quic_state() == cricket::QUIC_TRANSPORT_CONNECTED && peer2_.quic_channel()->quic_state() == cricket::QUIC_TRANSPORT_CONNECTED; } // Checks if QUIC channels are writable. bool quic_writable() { return peer1_.quic_channel()->writable() && peer2_.quic_channel()->writable(); } protected: // QUIC peer with a client role, who initiates the QUIC handshake. QuicTestPeer peer1_; // QUIC peer with a server role, who responds to the client peer. QuicTestPeer peer2_; }; // Test that the QUIC channel passes ICE parameters to the underlying ICE // channel. TEST_F(QuicTransportChannelTest, ChannelSetupIce) { SetIceAndCryptoParameters(rtc::SSL_CLIENT, rtc::SSL_SERVER); FailableTransportChannel* channel1 = peer1_.ice_channel(); FailableTransportChannel* channel2 = peer2_.ice_channel(); EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole()); EXPECT_EQ(2u, channel1->IceTiebreaker()); EXPECT_EQ(kIceUfrag, channel1->ice_ufrag()); EXPECT_EQ(kIcePwd, channel1->ice_pwd()); EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole()); EXPECT_EQ(1u, channel2->IceTiebreaker()); } // Test that export keying material generates identical keys for both peers // after the QUIC handshake. TEST_F(QuicTransportChannelTest, ExportKeyingMaterial) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); uint8_t key1[kOutputKeyLength]; uint8_t key2[kOutputKeyLength]; bool from_success = peer1_.quic_channel()->ExportKeyingMaterial( kExporterLabel, kExporterContext, kExporterContextLength, true, key1, kOutputKeyLength); ASSERT_TRUE(from_success); bool to_success = peer2_.quic_channel()->ExportKeyingMaterial( kExporterLabel, kExporterContext, kExporterContextLength, true, key2, kOutputKeyLength); ASSERT_TRUE(to_success); EXPECT_EQ(0, memcmp(key1, key2, sizeof(key1))); } // Test that the QUIC channel is not writable before the QUIC handshake. TEST_F(QuicTransportChannelTest, NotWritableBeforeHandshake) { Connect(); EXPECT_FALSE(quic_writable()); Disconnect(); EXPECT_FALSE(quic_writable()); Connect(); EXPECT_FALSE(quic_writable()); } // Test that once handshake begins, QUIC is not writable until its completion. TEST_F(QuicTransportChannelTest, QuicHandshake) { Connect(); EXPECT_FALSE(quic_writable()); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); EXPECT_TRUE(quic_writable()); } // Test that Non-SRTP data is not sent using SendPacket(), regardless of QUIC // channel state. TEST_F(QuicTransportChannelTest, TransferNonSrtp) { // Send data before ICE channel is connected. peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); ASSERT_EQ(-1, peer1_.SendRtpPacket()); EXPECT_EQ(0u, peer1_.bytes_sent()); // Send data after ICE channel is connected, before QUIC handshake. Connect(); peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); ASSERT_EQ(-1, peer1_.SendRtpPacket()); EXPECT_EQ(0u, peer1_.bytes_sent()); // Send data after QUIC handshake. ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); ASSERT_EQ(-1, peer1_.SendRtpPacket()); EXPECT_EQ(0u, peer1_.bytes_sent()); } // Test that SRTP data is always be sent, regardless of QUIC channel state, when // the ICE channel is connected. TEST_F(QuicTransportChannelTest, TransferSrtp) { // Send data after ICE channel is connected, before QUIC handshake. Connect(); peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); ASSERT_EQ(kPacketSize, static_cast(peer1_.SendSrtpPacket())); EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs); EXPECT_EQ(kPacketSize, peer1_.bytes_sent()); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); // Send data after QUIC handshake. peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); ASSERT_EQ(kPacketSize, static_cast(peer1_.SendSrtpPacket())); EXPECT_EQ_WAIT(kPacketSize, peer2_.bytes_received(), kTimeoutMs); EXPECT_EQ(kPacketSize, peer1_.bytes_sent()); } // Test that invalid SRTP (non-SRTP data with // PF_SRTP_BYPASS flag) fails to send with return value -1. TEST_F(QuicTransportChannelTest, TransferInvalidSrtp) { peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket()); EXPECT_EQ(0u, peer2_.bytes_received()); Connect(); peer1_.ClearBytesSent(); peer2_.ClearBytesReceived(); EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket()); EXPECT_EQ(0u, peer2_.bytes_received()); } // Test that QuicTransportChannel::WritePacket blocks when the ICE // channel is not writable, and otherwise succeeds. TEST_F(QuicTransportChannelTest, QuicWritePacket) { peer1_.ice_channel()->Connect(); peer2_.ice_channel()->Connect(); peer1_.ice_channel()->SetDestination(peer2_.ice_channel()); std::string packet = "FAKEQUICPACKET"; // QUIC should be write blocked when the ICE channel is not writable. peer1_.ice_channel()->SetWritable(false); EXPECT_TRUE(peer1_.quic_channel()->IsWriteBlocked()); net::WriteResult write_blocked_result = peer1_.quic_channel()->WritePacket( packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_blocked_result.status); EXPECT_EQ(EWOULDBLOCK, write_blocked_result.error_code); // QUIC should ignore errors when the ICE channel is writable. peer1_.ice_channel()->SetWritable(true); EXPECT_FALSE(peer1_.quic_channel()->IsWriteBlocked()); peer1_.SetWriteError(EWOULDBLOCK); net::WriteResult ignore_error_result = peer1_.quic_channel()->WritePacket( packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); EXPECT_EQ(net::WRITE_STATUS_OK, ignore_error_result.status); EXPECT_EQ(0, ignore_error_result.bytes_written); peer1_.SetWriteError(kNoWriteError); net::WriteResult no_error_result = peer1_.quic_channel()->WritePacket( packet.data(), packet.size(), kIpAddress, kIpEndpoint, nullptr); EXPECT_EQ(net::WRITE_STATUS_OK, no_error_result.status); EXPECT_EQ(static_cast(packet.size()), no_error_result.bytes_written); } // Test that SSL roles can be reversed before QUIC handshake. TEST_F(QuicTransportChannelTest, QuicRoleReversalBeforeQuic) { EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); } // Test that SSL roles cannot be reversed after the QUIC handshake. SetSslRole // returns true if the current SSL role equals the proposed SSL role. TEST_F(QuicTransportChannelTest, QuicRoleReversalAfterQuic) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); EXPECT_FALSE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); EXPECT_FALSE(peer2_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); EXPECT_TRUE(peer2_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); } // Set the SSL role, then test that GetSslRole returns the same value. TEST_F(QuicTransportChannelTest, SetGetSslRole) { ASSERT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); std::unique_ptr role(new rtc::SSLRole()); ASSERT_TRUE(peer1_.quic_channel()->GetSslRole(role.get())); EXPECT_EQ(rtc::SSL_SERVER, *role); } // Test that after the QUIC handshake is complete, the QUIC handshake remains // confirmed even if the ICE channel reconnects. TEST_F(QuicTransportChannelTest, HandshakeConfirmedAfterReconnect) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); Disconnect(); EXPECT_TRUE(quic_connected()); Connect(); EXPECT_TRUE(quic_connected()); } // Test that if the ICE channel becomes receiving after the QUIC channel is // connected, then the QUIC channel becomes receiving. TEST_F(QuicTransportChannelTest, IceReceivingAfterConnected) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); ASSERT_FALSE(peer1_.ice_channel()->receiving()); EXPECT_FALSE(peer1_.quic_channel()->receiving()); peer1_.ice_channel()->SetReceiving(true); EXPECT_TRUE(peer1_.quic_channel()->receiving()); } // Test that if the ICE channel becomes receiving before the QUIC channel is // connected, then the QUIC channel becomes receiving. TEST_F(QuicTransportChannelTest, IceReceivingBeforeConnected) { Connect(); peer1_.ice_channel()->SetReceiving(true); ASSERT_TRUE(peer1_.ice_channel()->receiving()); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); EXPECT_TRUE(peer1_.quic_channel()->receiving()); } // Test that when peer 1 creates an outgoing stream, peer 2 creates an incoming // QUIC stream with the same ID and fires OnIncomingStream. TEST_F(QuicTransportChannelTest, CreateOutgoingAndIncomingQuicStream) { Connect(); EXPECT_EQ(nullptr, peer1_.quic_channel()->CreateQuicStream()); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); ReliableQuicStream* stream = peer1_.quic_channel()->CreateQuicStream(); ASSERT_NE(nullptr, stream); stream->Write("Hi", 2); EXPECT_TRUE_WAIT(peer2_.incoming_quic_stream() != nullptr, kTimeoutMs); EXPECT_EQ(stream->id(), peer2_.incoming_quic_stream()->id()); } // Test that if the QuicTransportChannel is unwritable, then all outgoing QUIC // streams can send data once the QuicTransprotChannel becomes writable again. TEST_F(QuicTransportChannelTest, OutgoingQuicStreamSendsDataAfterReconnect) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); ReliableQuicStream* stream1 = peer1_.quic_channel()->CreateQuicStream(); ASSERT_NE(nullptr, stream1); ReliableQuicStream* stream2 = peer1_.quic_channel()->CreateQuicStream(); ASSERT_NE(nullptr, stream2); peer1_.ice_channel()->SetWritable(false); stream1->Write("First", 5); EXPECT_EQ(5u, stream1->queued_data_bytes()); stream2->Write("Second", 6); EXPECT_EQ(6u, stream2->queued_data_bytes()); EXPECT_EQ(0u, peer2_.incoming_stream_count()); peer1_.ice_channel()->SetWritable(true); EXPECT_EQ_WAIT(0u, stream1->queued_data_bytes(), kTimeoutMs); EXPECT_EQ_WAIT(0u, stream2->queued_data_bytes(), kTimeoutMs); EXPECT_EQ_WAIT(2u, peer2_.incoming_stream_count(), kTimeoutMs); } // Test that SignalClosed is emitted when the QuicConnection closes. TEST_F(QuicTransportChannelTest, SignalClosedEmitted) { Connect(); ASSERT_TRUE_WAIT(quic_connected(), kTimeoutMs); ASSERT_FALSE(peer1_.signal_closed_emitted()); ReliableQuicStream* stream = peer1_.quic_channel()->CreateQuicStream(); ASSERT_NE(nullptr, stream); stream->CloseConnectionWithDetails(net::QuicErrorCode::QUIC_NO_ERROR, "Closing QUIC for testing"); EXPECT_TRUE(peer1_.signal_closed_emitted()); EXPECT_TRUE_WAIT(peer2_.signal_closed_emitted(), kTimeoutMs); }