henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2011 The WebRTC Project Authors. All rights reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Jonas Olsson | a4d8737 | 2019-07-05 17:08:33 | [diff] [blame] | 11 | #include "p2p/base/dtls_transport.h" |
| 12 | |
zhihuang | ca6d3b6 | 2017-08-24 01:05:50 | [diff] [blame] | 13 | #include <algorithm> |
jbauch | 555604a | 2016-04-26 10:13:22 | [diff] [blame] | 14 | #include <memory> |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 15 | #include <set> |
Harald Alvestrand | 00dfe93 | 2018-11-22 10:34:47 | [diff] [blame] | 16 | #include <utility> |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 17 | |
Ali Tofigh | de2ac5a | 2022-06-30 09:58:26 | [diff] [blame] | 18 | #include "absl/strings/string_view.h" |
Mirko Bonadei | 9f6808b | 2021-05-21 18:46:09 | [diff] [blame] | 19 | #include "api/dtls_transport_interface.h" |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 20 | #include "p2p/base/fake_ice_transport.h" |
| 21 | #include "p2p/base/packet_transport_internal.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 22 | #include "rtc_base/checks.h" |
| 23 | #include "rtc_base/dscp.h" |
| 24 | #include "rtc_base/gunit.h" |
| 25 | #include "rtc_base/helpers.h" |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 26 | #include "rtc_base/rtc_certificate.h" |
| 27 | #include "rtc_base/ssl_adapter.h" |
| 28 | #include "rtc_base/ssl_identity.h" |
| 29 | #include "rtc_base/ssl_stream_adapter.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 30 | |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 31 | #define MAYBE_SKIP_TEST(feature) \ |
| 32 | if (!(rtc::SSLStreamAdapter::feature())) { \ |
| 33 | RTC_LOG(LS_INFO) << #feature " feature disabled... skipping"; \ |
| 34 | return; \ |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 35 | } |
| 36 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 37 | namespace cricket { |
| 38 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 39 | static const size_t kPacketNumOffset = 8; |
| 40 | static const size_t kPacketHeaderLen = 12; |
stefan | c1aeaf0 | 2015-10-15 14:26:07 | [diff] [blame] | 41 | static const int kFakePacketId = 0x1234; |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 42 | static const int kTimeout = 10000; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 43 | |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 44 | static bool IsRtpLeadByte(uint8_t b) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 45 | return ((b & 0xC0) == 0x80); |
| 46 | } |
| 47 | |
Artem Titov | 2dbb4c9 | 2021-07-26 13:12:41 | [diff] [blame] | 48 | // `modify_digest` is used to set modified fingerprints that are meant to fail |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 49 | // validation. |
| 50 | void SetRemoteFingerprintFromCert( |
| 51 | DtlsTransport* transport, |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 52 | const rtc::scoped_refptr<rtc::RTCCertificate>& cert, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 53 | bool modify_digest = false) { |
Steve Anton | 4905edb | 2018-10-16 02:27:44 | [diff] [blame] | 54 | std::unique_ptr<rtc::SSLFingerprint> fingerprint = |
| 55 | rtc::SSLFingerprint::CreateFromCertificate(*cert); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 56 | if (modify_digest) { |
Danil Chapovalov | e15dc58 | 2021-01-07 14:24:05 | [diff] [blame] | 57 | ++fingerprint->digest.MutableData()[0]; |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 58 | } |
Philipp Hancke | 4a3b5cc | 2022-08-18 12:48:21 | [diff] [blame] | 59 | |
| 60 | // Even if digest is verified to be incorrect, should fail asynchronously. |
| 61 | EXPECT_TRUE( |
| 62 | transport |
| 63 | ->SetRemoteParameters( |
| 64 | fingerprint->algorithm, |
| 65 | reinterpret_cast<const uint8_t*>(fingerprint->digest.data()), |
| 66 | fingerprint->digest.size(), absl::nullopt) |
| 67 | .ok()); |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 68 | } |
| 69 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 70 | class DtlsTestClient : public sigslot::has_slots<> { |
| 71 | public: |
Ali Tofigh | de2ac5a | 2022-06-30 09:58:26 | [diff] [blame] | 72 | explicit DtlsTestClient(absl::string_view name) : name_(name) {} |
Henrik Boström | d828198 | 2015-08-27 08:12:24 | [diff] [blame] | 73 | void CreateCertificate(rtc::KeyType key_type) { |
kwiberg | 0eb15ed | 2015-12-17 11:04:15 | [diff] [blame] | 74 | certificate_ = |
Harald Alvestrand | 8515d5a | 2020-03-20 21:51:32 | [diff] [blame] | 75 | rtc::RTCCertificate::Create(rtc::SSLIdentity::Create(name_, key_type)); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 76 | } |
Henrik Boström | d828198 | 2015-08-27 08:12:24 | [diff] [blame] | 77 | const rtc::scoped_refptr<rtc::RTCCertificate>& certificate() { |
| 78 | return certificate_; |
| 79 | } |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 80 | void SetupMaxProtocolVersion(rtc::SSLProtocolVersion version) { |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 81 | ssl_max_version_ = version; |
| 82 | } |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 83 | // Set up fake ICE transport and real DTLS transport under test. |
| 84 | void SetupTransports(IceRole role, int async_delay_ms = 0) { |
Bjorn A Mellem | 0c1c1b4 | 2019-05-30 00:34:13 | [diff] [blame] | 85 | fake_ice_transport_.reset(new FakeIceTransport("fake", 0)); |
| 86 | fake_ice_transport_->SetAsync(true); |
| 87 | fake_ice_transport_->SetAsyncDelay(async_delay_ms); |
| 88 | fake_ice_transport_->SetIceRole(role); |
| 89 | fake_ice_transport_->SetIceTiebreaker((role == ICEROLE_CONTROLLING) ? 1 |
| 90 | : 2); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 91 | // Hook the raw packets so that we can verify they are encrypted. |
Bjorn A Mellem | 0c1c1b4 | 2019-05-30 00:34:13 | [diff] [blame] | 92 | fake_ice_transport_->SignalReadPacket.connect( |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 93 | this, &DtlsTestClient::OnFakeIceTransportReadPacket); |
deadbeef | 49f34fd | 2016-12-07 00:22:06 | [diff] [blame] | 94 | |
Tommi | 653bab6 | 2021-04-03 15:53:54 | [diff] [blame] | 95 | dtls_transport_ = std::make_unique<DtlsTransport>( |
| 96 | fake_ice_transport_.get(), webrtc::CryptoOptions(), |
| 97 | /*event_log=*/nullptr, ssl_max_version_); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 98 | // Note: Certificate may be null here if testing passthrough. |
| 99 | dtls_transport_->SetLocalCertificate(certificate_); |
| 100 | dtls_transport_->SignalWritableState.connect( |
| 101 | this, &DtlsTestClient::OnTransportWritableState); |
| 102 | dtls_transport_->SignalReadPacket.connect( |
| 103 | this, &DtlsTestClient::OnTransportReadPacket); |
| 104 | dtls_transport_->SignalSentPacket.connect( |
| 105 | this, &DtlsTestClient::OnTransportSentPacket); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 106 | } |
| 107 | |
Harald Alvestrand | 00dfe93 | 2018-11-22 10:34:47 | [diff] [blame] | 108 | FakeIceTransport* fake_ice_transport() { |
| 109 | return static_cast<FakeIceTransport*>(dtls_transport_->ice_transport()); |
| 110 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 111 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 112 | DtlsTransport* dtls_transport() { return dtls_transport_.get(); } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 113 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 114 | // Simulate fake ICE transports connecting. |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 115 | bool Connect(DtlsTestClient* peer, bool asymmetric) { |
Harald Alvestrand | 00dfe93 | 2018-11-22 10:34:47 | [diff] [blame] | 116 | fake_ice_transport()->SetDestination(peer->fake_ice_transport(), |
| 117 | asymmetric); |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 118 | return true; |
| 119 | } |
| 120 | |
| 121 | int received_dtls_client_hellos() const { |
| 122 | return received_dtls_client_hellos_; |
| 123 | } |
| 124 | |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 125 | int received_dtls_server_hellos() const { |
| 126 | return received_dtls_server_hellos_; |
| 127 | } |
| 128 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 129 | void CheckRole(rtc::SSLRole role) { |
| 130 | if (role == rtc::SSL_CLIENT) { |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 131 | ASSERT_EQ(0, received_dtls_client_hellos_); |
| 132 | ASSERT_GT(received_dtls_server_hellos_, 0); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 133 | } else { |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 134 | ASSERT_GT(received_dtls_client_hellos_, 0); |
| 135 | ASSERT_EQ(0, received_dtls_server_hellos_); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 136 | } |
| 137 | } |
| 138 | |
Guo-wei Shieh | 521ed7b | 2015-11-19 03:41:53 | [diff] [blame] | 139 | void CheckSrtp(int expected_crypto_suite) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 140 | int crypto_suite; |
| 141 | bool rv = dtls_transport_->GetSrtpCryptoSuite(&crypto_suite); |
| 142 | if (dtls_transport_->IsDtlsActive() && expected_crypto_suite) { |
| 143 | ASSERT_TRUE(rv); |
| 144 | ASSERT_EQ(crypto_suite, expected_crypto_suite); |
| 145 | } else { |
| 146 | ASSERT_FALSE(rv); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 147 | } |
| 148 | } |
| 149 | |
torbjorng | 43166b8 | 2016-03-11 08:06:47 | [diff] [blame] | 150 | void CheckSsl() { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 151 | int cipher; |
| 152 | bool rv = dtls_transport_->GetSslCipherSuite(&cipher); |
| 153 | if (dtls_transport_->IsDtlsActive()) { |
| 154 | ASSERT_TRUE(rv); |
| 155 | EXPECT_TRUE( |
| 156 | rtc::SSLStreamAdapter::IsAcceptableCipher(cipher, rtc::KT_DEFAULT)); |
| 157 | } else { |
| 158 | ASSERT_FALSE(rv); |
pthatcher@webrtc.org | 3ee4fe5 | 2015-02-11 22:34:36 | [diff] [blame] | 159 | } |
| 160 | } |
| 161 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 162 | void SendPackets(size_t size, size_t count, bool srtp) { |
jbauch | 555604a | 2016-04-26 10:13:22 | [diff] [blame] | 163 | std::unique_ptr<char[]> packet(new char[size]); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 164 | size_t sent = 0; |
| 165 | do { |
| 166 | // Fill the packet with a known value and a sequence number to check |
| 167 | // against, and make sure that it doesn't look like DTLS. |
| 168 | memset(packet.get(), sent & 0xff, size); |
| 169 | packet[0] = (srtp) ? 0x80 : 0x00; |
| 170 | rtc::SetBE32(packet.get() + kPacketNumOffset, |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 171 | static_cast<uint32_t>(sent)); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 172 | |
| 173 | // Only set the bypass flag if we've activated DTLS. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 174 | int flags = (certificate_ && srtp) ? PF_SRTP_BYPASS : 0; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 175 | rtc::PacketOptions packet_options; |
stefan | c1aeaf0 | 2015-10-15 14:26:07 | [diff] [blame] | 176 | packet_options.packet_id = kFakePacketId; |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 177 | int rv = dtls_transport_->SendPacket(packet.get(), size, packet_options, |
| 178 | flags); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 179 | ASSERT_GT(rv, 0); |
| 180 | ASSERT_EQ(size, static_cast<size_t>(rv)); |
| 181 | ++sent; |
| 182 | } while (sent < count); |
| 183 | } |
| 184 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 185 | int SendInvalidSrtpPacket(size_t size) { |
jbauch | 555604a | 2016-04-26 10:13:22 | [diff] [blame] | 186 | std::unique_ptr<char[]> packet(new char[size]); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 187 | // Fill the packet with 0 to form an invalid SRTP packet. |
| 188 | memset(packet.get(), 0, size); |
| 189 | |
| 190 | rtc::PacketOptions packet_options; |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 191 | return dtls_transport_->SendPacket(packet.get(), size, packet_options, |
| 192 | PF_SRTP_BYPASS); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 193 | } |
| 194 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 195 | void ExpectPackets(size_t size) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 196 | packet_size_ = size; |
| 197 | received_.clear(); |
| 198 | } |
| 199 | |
zhihuang | ca6d3b6 | 2017-08-24 01:05:50 | [diff] [blame] | 200 | size_t NumPacketsReceived() { return received_.size(); } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 201 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 202 | // Inverse of SendPackets. |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 203 | bool VerifyPacket(const char* data, size_t size, uint32_t* out_num) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 204 | if (size != packet_size_ || |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 205 | (data[0] != 0 && static_cast<uint8_t>(data[0]) != 0x80)) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 206 | return false; |
| 207 | } |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 208 | uint32_t packet_num = rtc::GetBE32(data + kPacketNumOffset); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 209 | for (size_t i = kPacketHeaderLen; i < size; ++i) { |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 210 | if (static_cast<uint8_t>(data[i]) != (packet_num & 0xff)) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 211 | return false; |
| 212 | } |
| 213 | } |
| 214 | if (out_num) { |
| 215 | *out_num = packet_num; |
| 216 | } |
| 217 | return true; |
| 218 | } |
| 219 | bool VerifyEncryptedPacket(const char* data, size_t size) { |
| 220 | // This is an encrypted data packet; let's make sure it's mostly random; |
| 221 | // less than 10% of the bytes should be equal to the cleartext packet. |
| 222 | if (size <= packet_size_) { |
| 223 | return false; |
| 224 | } |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 225 | uint32_t packet_num = rtc::GetBE32(data + kPacketNumOffset); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 226 | int num_matches = 0; |
| 227 | for (size_t i = kPacketNumOffset; i < size; ++i) { |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 228 | if (static_cast<uint8_t>(data[i]) == (packet_num & 0xff)) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 229 | ++num_matches; |
| 230 | } |
| 231 | } |
| 232 | return (num_matches < ((static_cast<int>(size) - 5) / 10)); |
| 233 | } |
| 234 | |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 235 | // Transport callbacks |
| 236 | void OnTransportWritableState(rtc::PacketTransportInternal* transport) { |
| 237 | RTC_LOG(LS_INFO) << name_ << ": Transport '" << transport->transport_name() |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 238 | << "' is writable"; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 239 | } |
| 240 | |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 241 | void OnTransportReadPacket(rtc::PacketTransportInternal* transport, |
| 242 | const char* data, |
| 243 | size_t size, |
Niels Möller | e693381 | 2018-11-05 12:01:41 | [diff] [blame] | 244 | const int64_t& /* packet_time_us */, |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 245 | int flags) { |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 246 | uint32_t packet_num = 0; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 247 | ASSERT_TRUE(VerifyPacket(data, size, &packet_num)); |
| 248 | received_.insert(packet_num); |
| 249 | // Only DTLS-SRTP packets should have the bypass flag set. |
deadbeef | cbecd35 | 2015-09-23 18:50:27 | [diff] [blame] | 250 | int expected_flags = |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 251 | (certificate_ && IsRtpLeadByte(data[0])) ? PF_SRTP_BYPASS : 0; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 252 | ASSERT_EQ(expected_flags, flags); |
| 253 | } |
| 254 | |
Zhi Huang | 942bc2e | 2017-11-13 21:26:07 | [diff] [blame] | 255 | void OnTransportSentPacket(rtc::PacketTransportInternal* transport, |
| 256 | const rtc::SentPacket& sent_packet) { |
stefan | c1aeaf0 | 2015-10-15 14:26:07 | [diff] [blame] | 257 | sent_packet_ = sent_packet; |
| 258 | } |
| 259 | |
| 260 | rtc::SentPacket sent_packet() const { return sent_packet_; } |
| 261 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 262 | // Hook into the raw packet stream to make sure DTLS packets are encrypted. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 263 | void OnFakeIceTransportReadPacket(rtc::PacketTransportInternal* transport, |
| 264 | const char* data, |
| 265 | size_t size, |
Niels Möller | e693381 | 2018-11-05 12:01:41 | [diff] [blame] | 266 | const int64_t& /* packet_time_us */, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 267 | int flags) { |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 268 | // Flags shouldn't be set on the underlying Transport packets. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 269 | ASSERT_EQ(0, flags); |
| 270 | |
| 271 | // Look at the handshake packets to see what role we played. |
| 272 | // Check that non-handshake packets are DTLS data or SRTP bypass. |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 273 | if (data[0] == 22 && size > 17) { |
| 274 | if (data[13] == 1) { |
| 275 | ++received_dtls_client_hellos_; |
| 276 | } else if (data[13] == 2) { |
| 277 | ++received_dtls_server_hellos_; |
| 278 | } |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 279 | } else if (dtls_transport_->IsDtlsActive() && |
| 280 | !(data[0] >= 20 && data[0] <= 22)) { |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 281 | ASSERT_TRUE(data[0] == 23 || IsRtpLeadByte(data[0])); |
| 282 | if (data[0] == 23) { |
| 283 | ASSERT_TRUE(VerifyEncryptedPacket(data, size)); |
| 284 | } else if (IsRtpLeadByte(data[0])) { |
| 285 | ASSERT_TRUE(VerifyPacket(data, size, NULL)); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 286 | } |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | private: |
| 291 | std::string name_; |
Henrik Boström | d828198 | 2015-08-27 08:12:24 | [diff] [blame] | 292 | rtc::scoped_refptr<rtc::RTCCertificate> certificate_; |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 293 | std::unique_ptr<FakeIceTransport> fake_ice_transport_; |
| 294 | std::unique_ptr<DtlsTransport> dtls_transport_; |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 295 | size_t packet_size_ = 0u; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 296 | std::set<int> received_; |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 297 | rtc::SSLProtocolVersion ssl_max_version_ = rtc::SSL_PROTOCOL_DTLS_12; |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 298 | int received_dtls_client_hellos_ = 0; |
| 299 | int received_dtls_server_hellos_ = 0; |
stefan | c1aeaf0 | 2015-10-15 14:26:07 | [diff] [blame] | 300 | rtc::SentPacket sent_packet_; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 301 | }; |
| 302 | |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 303 | // Base class for DtlsTransportTest and DtlsEventOrderingTest, which |
Mirko Bonadei | 6a489f2 | 2019-04-09 13:11:12 | [diff] [blame] | 304 | // inherit from different variants of ::testing::Test. |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 305 | // |
Artem Titov | 2dbb4c9 | 2021-07-26 13:12:41 | [diff] [blame] | 306 | // Note that this test always uses a FakeClock, due to the `fake_clock_` member |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 307 | // variable. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 308 | class DtlsTransportTestBase { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 309 | public: |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 310 | DtlsTransportTestBase() : client1_("P1"), client2_("P2"), use_dtls_(false) {} |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 311 | |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 312 | void SetMaxProtocolVersions(rtc::SSLProtocolVersion c1, |
| 313 | rtc::SSLProtocolVersion c2) { |
| 314 | client1_.SetupMaxProtocolVersion(c1); |
| 315 | client2_.SetupMaxProtocolVersion(c2); |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 316 | } |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 317 | // If not called, DtlsTransport will be used in SRTP bypass mode. |
| 318 | void PrepareDtls(rtc::KeyType key_type) { |
| 319 | client1_.CreateCertificate(key_type); |
| 320 | client2_.CreateCertificate(key_type); |
| 321 | use_dtls_ = true; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 322 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 323 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 324 | // This test negotiates DTLS parameters before the underlying transports are |
| 325 | // writable. DtlsEventOrderingTest is responsible for exercising differerent |
| 326 | // orderings. |
| 327 | bool Connect(bool client1_server = true) { |
| 328 | Negotiate(client1_server); |
| 329 | EXPECT_TRUE(client1_.Connect(&client2_, false)); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 330 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 331 | EXPECT_TRUE_SIMULATED_WAIT(client1_.dtls_transport()->writable() && |
| 332 | client2_.dtls_transport()->writable(), |
zhihuang | b2cdd93 | 2017-01-20 00:54:25 | [diff] [blame] | 333 | kTimeout, fake_clock_); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 334 | if (!client1_.dtls_transport()->writable() || |
| 335 | !client2_.dtls_transport()->writable()) |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 336 | return false; |
| 337 | |
| 338 | // Check that we used the right roles. |
| 339 | if (use_dtls_) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 340 | client1_.CheckRole(client1_server ? rtc::SSL_SERVER : rtc::SSL_CLIENT); |
| 341 | client2_.CheckRole(client1_server ? rtc::SSL_CLIENT : rtc::SSL_SERVER); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 342 | } |
| 343 | |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 344 | if (use_dtls_) { |
| 345 | // Check that we negotiated the right ciphers. Since GCM ciphers are not |
Mirko Bonadei | 7750d80 | 2021-07-26 15:27:42 | [diff] [blame] | 346 | // negotiated by default, we should end up with kSrtpAes128CmSha1_80. |
| 347 | client1_.CheckSrtp(rtc::kSrtpAes128CmSha1_80); |
| 348 | client2_.CheckSrtp(rtc::kSrtpAes128CmSha1_80); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 349 | } else { |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 350 | // If DTLS isn't actually being used, GetSrtpCryptoSuite should return |
| 351 | // false. |
Mirko Bonadei | 7750d80 | 2021-07-26 15:27:42 | [diff] [blame] | 352 | client1_.CheckSrtp(rtc::kSrtpInvalidCryptoSuite); |
| 353 | client2_.CheckSrtp(rtc::kSrtpInvalidCryptoSuite); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 354 | } |
torbjorng | 43166b8 | 2016-03-11 08:06:47 | [diff] [blame] | 355 | |
| 356 | client1_.CheckSsl(); |
| 357 | client2_.CheckSsl(); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 358 | |
| 359 | return true; |
| 360 | } |
| 361 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 362 | void Negotiate(bool client1_server = true) { |
| 363 | client1_.SetupTransports(ICEROLE_CONTROLLING); |
| 364 | client2_.SetupTransports(ICEROLE_CONTROLLED); |
Zhi Huang | e818b6e | 2018-02-22 23:26:27 | [diff] [blame] | 365 | client1_.dtls_transport()->SetDtlsRole(client1_server ? rtc::SSL_SERVER |
| 366 | : rtc::SSL_CLIENT); |
| 367 | client2_.dtls_transport()->SetDtlsRole(client1_server ? rtc::SSL_CLIENT |
| 368 | : rtc::SSL_SERVER); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 369 | if (client2_.certificate()) { |
| 370 | SetRemoteFingerprintFromCert(client1_.dtls_transport(), |
| 371 | client2_.certificate()); |
| 372 | } |
| 373 | if (client1_.certificate()) { |
| 374 | SetRemoteFingerprintFromCert(client2_.dtls_transport(), |
| 375 | client1_.certificate()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 376 | } |
| 377 | } |
| 378 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 379 | void TestTransfer(size_t size, size_t count, bool srtp) { |
Mirko Bonadei | 675513b | 2017-11-09 10:09:25 | [diff] [blame] | 380 | RTC_LOG(LS_INFO) << "Expect packets, size=" << size; |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 381 | client2_.ExpectPackets(size); |
| 382 | client1_.SendPackets(size, count, srtp); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 383 | EXPECT_EQ_SIMULATED_WAIT(count, client2_.NumPacketsReceived(), kTimeout, |
| 384 | fake_clock_); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 385 | } |
| 386 | |
| 387 | protected: |
Niels Möller | 83830f3 | 2022-05-20 07:12:57 | [diff] [blame] | 388 | rtc::AutoThread main_thread_; |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 389 | rtc::ScopedFakeClock fake_clock_; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 390 | DtlsTestClient client1_; |
| 391 | DtlsTestClient client2_; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 392 | bool use_dtls_; |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 393 | rtc::SSLProtocolVersion ssl_expected_version_; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 394 | }; |
| 395 | |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 396 | class DtlsTransportTest : public DtlsTransportTestBase, |
| 397 | public ::testing::Test {}; |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 398 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 399 | // Connect without DTLS, and transfer RTP data. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 400 | TEST_F(DtlsTransportTest, TestTransferRtp) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 401 | ASSERT_TRUE(Connect()); |
| 402 | TestTransfer(1000, 100, /*srtp=*/false); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 403 | } |
| 404 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 405 | // Test that the SignalSentPacket signal is wired up. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 406 | TEST_F(DtlsTransportTest, TestSignalSentPacket) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 407 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 408 | // Sanity check default value (-1). |
| 409 | ASSERT_EQ(client1_.sent_packet().send_time_ms, -1); |
| 410 | TestTransfer(1000, 100, false); |
| 411 | // Check that we get the expected fake packet ID, and a time of 0 from the |
| 412 | // fake clock. |
stefan | c1aeaf0 | 2015-10-15 14:26:07 | [diff] [blame] | 413 | EXPECT_EQ(kFakePacketId, client1_.sent_packet().packet_id); |
| 414 | EXPECT_GE(client1_.sent_packet().send_time_ms, 0); |
| 415 | } |
| 416 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 417 | // Connect without DTLS, and transfer SRTP data. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 418 | TEST_F(DtlsTransportTest, TestTransferSrtp) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 419 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 420 | TestTransfer(1000, 100, /*srtp=*/true); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 421 | } |
| 422 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 423 | // Connect with DTLS, and transfer data over DTLS. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 424 | TEST_F(DtlsTransportTest, TestTransferDtls) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 425 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 426 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 427 | TestTransfer(1000, 100, /*srtp=*/false); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 428 | } |
| 429 | |
jbauch | 7d0a77ee | 2017-07-07 20:44:07 | [diff] [blame] | 430 | // Connect with DTLS, combine multiple DTLS records into one packet. |
| 431 | // Our DTLS implementation doesn't do this, but other implementations may; |
| 432 | // see https://tools.ietf.org/html/rfc6347#section-4.1.1. |
| 433 | // This has caused interoperability problems with ORTCLib in the past. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 434 | TEST_F(DtlsTransportTest, TestTransferDtlsCombineRecords) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 435 | PrepareDtls(rtc::KT_DEFAULT); |
jbauch | 7d0a77ee | 2017-07-07 20:44:07 | [diff] [blame] | 436 | ASSERT_TRUE(Connect()); |
| 437 | // Our DTLS implementation always sends one record per packet, so to simulate |
| 438 | // an endpoint that sends multiple records per packet, we configure the fake |
| 439 | // ICE transport to combine every two consecutive packets into a single |
| 440 | // packet. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 441 | FakeIceTransport* transport = client1_.fake_ice_transport(); |
jbauch | 7d0a77ee | 2017-07-07 20:44:07 | [diff] [blame] | 442 | transport->combine_outgoing_packets(true); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 443 | TestTransfer(500, 100, /*srtp=*/false); |
jbauch | 7d0a77ee | 2017-07-07 20:44:07 | [diff] [blame] | 444 | } |
| 445 | |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 446 | class DtlsTransportVersionTest |
| 447 | : public DtlsTransportTestBase, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 448 | public ::testing::TestWithParam< |
| 449 | ::testing::tuple<rtc::SSLProtocolVersion, rtc::SSLProtocolVersion>> { |
| 450 | }; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 451 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 452 | // Test that an acceptable cipher suite is negotiated when different versions |
| 453 | // of DTLS are supported. Note that it's IsAcceptableCipher that does the actual |
| 454 | // work. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 455 | TEST_P(DtlsTransportVersionTest, TestCipherSuiteNegotiation) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 456 | PrepareDtls(rtc::KT_DEFAULT); |
| 457 | SetMaxProtocolVersions(::testing::get<0>(GetParam()), |
| 458 | ::testing::get<1>(GetParam())); |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 459 | ASSERT_TRUE(Connect()); |
| 460 | } |
| 461 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 462 | // Will test every combination of 1.0/1.2 on the client and server. |
Mirko Bonadei | c84f661 | 2019-01-31 11:20:57 | [diff] [blame] | 463 | INSTANTIATE_TEST_SUITE_P( |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 464 | TestCipherSuiteNegotiation, |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 465 | DtlsTransportVersionTest, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 466 | ::testing::Combine(::testing::Values(rtc::SSL_PROTOCOL_DTLS_10, |
| 467 | rtc::SSL_PROTOCOL_DTLS_12), |
| 468 | ::testing::Values(rtc::SSL_PROTOCOL_DTLS_10, |
| 469 | rtc::SSL_PROTOCOL_DTLS_12))); |
Joachim Bauch | 831c558 | 2015-05-20 10:48:41 | [diff] [blame] | 470 | |
deadbeef | 7914b8c | 2017-04-21 10:23:33 | [diff] [blame] | 471 | // Connect with DTLS, negotiating DTLS-SRTP, and transfer SRTP using bypass. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 472 | TEST_F(DtlsTransportTest, TestTransferDtlsSrtp) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 473 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 474 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 475 | TestTransfer(1000, 100, /*srtp=*/true); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 476 | } |
| 477 | |
| 478 | // Connect with DTLS-SRTP, transfer an invalid SRTP packet, and expects -1 |
| 479 | // returned. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 480 | TEST_F(DtlsTransportTest, TestTransferDtlsInvalidSrtpPacket) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 481 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 482 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 483 | EXPECT_EQ(-1, client1_.SendInvalidSrtpPacket(100)); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 484 | } |
| 485 | |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 486 | // Create a single transport with DTLS, and send normal data and SRTP data on |
| 487 | // it. |
| 488 | TEST_F(DtlsTransportTest, TestTransferDtlsSrtpDemux) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 489 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 490 | ASSERT_TRUE(Connect()); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 491 | TestTransfer(1000, 100, /*srtp=*/false); |
| 492 | TestTransfer(1000, 100, /*srtp=*/true); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 493 | } |
| 494 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 495 | // Test transferring when the "answerer" has the server role. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 496 | TEST_F(DtlsTransportTest, TestTransferDtlsSrtpAnswererIsPassive) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 497 | PrepareDtls(rtc::KT_DEFAULT); |
| 498 | ASSERT_TRUE(Connect(/*client1_server=*/false)); |
| 499 | TestTransfer(1000, 100, /*srtp=*/true); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 500 | } |
| 501 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 502 | // Test that renegotiation (setting same role and fingerprint again) can be |
| 503 | // started before the clients become connected in the first negotiation. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 504 | TEST_F(DtlsTransportTest, TestRenegotiateBeforeConnect) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 505 | PrepareDtls(rtc::KT_DEFAULT); |
| 506 | // Note: This is doing the same thing Connect normally does, minus some |
| 507 | // additional checks not relevant for this test. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 508 | Negotiate(); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 509 | Negotiate(); |
| 510 | EXPECT_TRUE(client1_.Connect(&client2_, false)); |
| 511 | EXPECT_TRUE_SIMULATED_WAIT(client1_.dtls_transport()->writable() && |
| 512 | client2_.dtls_transport()->writable(), |
zhihuang | b2cdd93 | 2017-01-20 00:54:25 | [diff] [blame] | 513 | kTimeout, fake_clock_); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 514 | TestTransfer(1000, 100, true); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 515 | } |
| 516 | |
| 517 | // Test Certificates state after negotiation but before connection. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 518 | TEST_F(DtlsTransportTest, TestCertificatesBeforeConnect) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 519 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 520 | Negotiate(); |
| 521 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 522 | // After negotiation, each side has a distinct local certificate, but still no |
| 523 | // remote certificate, because connection has not yet occurred. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 524 | auto certificate1 = client1_.dtls_transport()->GetLocalCertificate(); |
| 525 | auto certificate2 = client2_.dtls_transport()->GetLocalCertificate(); |
Benjamin Wright | 6c6c9df | 2018-10-25 08:16:26 | [diff] [blame] | 526 | ASSERT_NE(certificate1->GetSSLCertificate().ToPEMString(), |
| 527 | certificate2->GetSSLCertificate().ToPEMString()); |
Taylor Brandstetter | c392866 | 2018-02-23 21:04:51 | [diff] [blame] | 528 | ASSERT_FALSE(client1_.dtls_transport()->GetRemoteSSLCertChain()); |
| 529 | ASSERT_FALSE(client2_.dtls_transport()->GetRemoteSSLCertChain()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 530 | } |
| 531 | |
| 532 | // Test Certificates state after connection. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 533 | TEST_F(DtlsTransportTest, TestCertificatesAfterConnect) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 534 | PrepareDtls(rtc::KT_DEFAULT); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 535 | ASSERT_TRUE(Connect()); |
| 536 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 537 | // After connection, each side has a distinct local certificate. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 538 | auto certificate1 = client1_.dtls_transport()->GetLocalCertificate(); |
| 539 | auto certificate2 = client2_.dtls_transport()->GetLocalCertificate(); |
Benjamin Wright | 6c6c9df | 2018-10-25 08:16:26 | [diff] [blame] | 540 | ASSERT_NE(certificate1->GetSSLCertificate().ToPEMString(), |
| 541 | certificate2->GetSSLCertificate().ToPEMString()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 542 | |
| 543 | // Each side's remote certificate is the other side's local certificate. |
Taylor Brandstetter | c392866 | 2018-02-23 21:04:51 | [diff] [blame] | 544 | std::unique_ptr<rtc::SSLCertChain> remote_cert1 = |
| 545 | client1_.dtls_transport()->GetRemoteSSLCertChain(); |
kwiberg | b4d01c4 | 2016-04-06 12:15:06 | [diff] [blame] | 546 | ASSERT_TRUE(remote_cert1); |
Taylor Brandstetter | c392866 | 2018-02-23 21:04:51 | [diff] [blame] | 547 | ASSERT_EQ(1u, remote_cert1->GetSize()); |
| 548 | ASSERT_EQ(remote_cert1->Get(0).ToPEMString(), |
Benjamin Wright | 6c6c9df | 2018-10-25 08:16:26 | [diff] [blame] | 549 | certificate2->GetSSLCertificate().ToPEMString()); |
Taylor Brandstetter | c392866 | 2018-02-23 21:04:51 | [diff] [blame] | 550 | std::unique_ptr<rtc::SSLCertChain> remote_cert2 = |
| 551 | client2_.dtls_transport()->GetRemoteSSLCertChain(); |
kwiberg | b4d01c4 | 2016-04-06 12:15:06 | [diff] [blame] | 552 | ASSERT_TRUE(remote_cert2); |
Taylor Brandstetter | c392866 | 2018-02-23 21:04:51 | [diff] [blame] | 553 | ASSERT_EQ(1u, remote_cert2->GetSize()); |
| 554 | ASSERT_EQ(remote_cert2->Get(0).ToPEMString(), |
Benjamin Wright | 6c6c9df | 2018-10-25 08:16:26 | [diff] [blame] | 555 | certificate1->GetSSLCertificate().ToPEMString()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 556 | } |
deadbeef | e84cd2e | 2016-05-05 00:16:34 | [diff] [blame] | 557 | |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 558 | // Test that packets are retransmitted according to the expected schedule. |
| 559 | // Each time a timeout occurs, the retransmission timer should be doubled up to |
| 560 | // 60 seconds. The timer defaults to 1 second, but for WebRTC we should be |
| 561 | // initializing it to 50ms. |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 562 | TEST_F(DtlsTransportTest, TestRetransmissionSchedule) { |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 563 | // We can only change the retransmission schedule with a recently-added |
| 564 | // BoringSSL API. Skip the test if not built with BoringSSL. |
| 565 | MAYBE_SKIP_TEST(IsBoringSsl); |
| 566 | |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 567 | PrepareDtls(rtc::KT_DEFAULT); |
| 568 | // Exchange fingerprints and set SSL roles. |
| 569 | Negotiate(); |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 570 | |
| 571 | // Make client2_ writable, but not client1_. |
| 572 | // This means client1_ will send DTLS client hellos but get no response. |
| 573 | EXPECT_TRUE(client2_.Connect(&client1_, true)); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 574 | EXPECT_TRUE_SIMULATED_WAIT(client2_.fake_ice_transport()->writable(), |
| 575 | kTimeout, fake_clock_); |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 576 | |
| 577 | // Wait for the first client hello to be sent. |
| 578 | EXPECT_EQ_WAIT(1, client1_.received_dtls_client_hellos(), kTimeout); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 579 | EXPECT_FALSE(client1_.fake_ice_transport()->writable()); |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 580 | |
| 581 | static int timeout_schedule_ms[] = {50, 100, 200, 400, 800, 1600, |
| 582 | 3200, 6400, 12800, 25600, 51200, 60000}; |
| 583 | |
| 584 | int expected_hellos = 1; |
| 585 | for (size_t i = 0; |
| 586 | i < (sizeof(timeout_schedule_ms) / sizeof(timeout_schedule_ms[0])); |
| 587 | ++i) { |
| 588 | // For each expected retransmission time, advance the fake clock a |
| 589 | // millisecond before the expected time and verify that no unexpected |
| 590 | // retransmissions were sent. Then advance it the final millisecond and |
| 591 | // verify that the expected retransmission was sent. |
Danil Chapovalov | 0c626af | 2020-02-10 10:16:00 | [diff] [blame] | 592 | fake_clock_.AdvanceTime( |
| 593 | webrtc::TimeDelta::Millis(timeout_schedule_ms[i] - 1)); |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 594 | EXPECT_EQ(expected_hellos, client1_.received_dtls_client_hellos()); |
Danil Chapovalov | 0c626af | 2020-02-10 10:16:00 | [diff] [blame] | 595 | fake_clock_.AdvanceTime(webrtc::TimeDelta::Millis(1)); |
Taylor Brandstetter | 4f0dfbd | 2016-06-16 00:15:23 | [diff] [blame] | 596 | EXPECT_EQ(++expected_hellos, client1_.received_dtls_client_hellos()); |
| 597 | } |
| 598 | } |
deadbeef | 367efdc | 2016-07-13 19:10:17 | [diff] [blame] | 599 | |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 600 | // The following events can occur in many different orders: |
| 601 | // 1. Caller receives remote fingerprint. |
| 602 | // 2. Caller is writable. |
| 603 | // 3. Caller receives ClientHello. |
| 604 | // 4. DTLS handshake finishes. |
| 605 | // |
| 606 | // The tests below cover all causally consistent permutations of these events; |
| 607 | // the caller must be writable and receive a ClientHello before the handshake |
| 608 | // finishes, but otherwise any ordering is possible. |
| 609 | // |
| 610 | // For each permutation, the test verifies that a connection is established and |
| 611 | // fingerprint verified without any DTLS packet needing to be retransmitted. |
| 612 | // |
| 613 | // Each permutation is also tested with valid and invalid fingerprints, |
| 614 | // ensuring that the handshake fails with an invalid fingerprint. |
| 615 | enum DtlsTransportEvent { |
| 616 | CALLER_RECEIVES_FINGERPRINT, |
| 617 | CALLER_WRITABLE, |
| 618 | CALLER_RECEIVES_CLIENTHELLO, |
| 619 | HANDSHAKE_FINISHES |
| 620 | }; |
| 621 | |
| 622 | class DtlsEventOrderingTest |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 623 | : public DtlsTransportTestBase, |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 624 | public ::testing::TestWithParam< |
| 625 | ::testing::tuple<std::vector<DtlsTransportEvent>, bool>> { |
| 626 | protected: |
Artem Titov | 2dbb4c9 | 2021-07-26 13:12:41 | [diff] [blame] | 627 | // If `valid_fingerprint` is false, the caller will receive a fingerprint |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 628 | // that doesn't match the callee's certificate, so the handshake should fail. |
| 629 | void TestEventOrdering(const std::vector<DtlsTransportEvent>& events, |
| 630 | bool valid_fingerprint) { |
| 631 | // Pre-setup: Set local certificate on both caller and callee, and |
| 632 | // remote fingerprint on callee, but neither is writable and the caller |
| 633 | // doesn't have the callee's fingerprint. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 634 | PrepareDtls(rtc::KT_DEFAULT); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 635 | // Simulate packets being sent and arriving asynchronously. |
| 636 | // Otherwise the entire DTLS handshake would occur in one clock tick, and |
| 637 | // we couldn't inject method calls in the middle of it. |
| 638 | int simulated_delay_ms = 10; |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 639 | client1_.SetupTransports(ICEROLE_CONTROLLING, simulated_delay_ms); |
| 640 | client2_.SetupTransports(ICEROLE_CONTROLLED, simulated_delay_ms); |
| 641 | // Similar to how NegotiateOrdering works. |
Zhi Huang | e818b6e | 2018-02-22 23:26:27 | [diff] [blame] | 642 | client1_.dtls_transport()->SetDtlsRole(rtc::SSL_SERVER); |
| 643 | client2_.dtls_transport()->SetDtlsRole(rtc::SSL_CLIENT); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 644 | SetRemoteFingerprintFromCert(client2_.dtls_transport(), |
| 645 | client1_.certificate()); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 646 | |
| 647 | for (DtlsTransportEvent e : events) { |
| 648 | switch (e) { |
| 649 | case CALLER_RECEIVES_FINGERPRINT: |
| 650 | if (valid_fingerprint) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 651 | SetRemoteFingerprintFromCert(client1_.dtls_transport(), |
| 652 | client2_.certificate()); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 653 | } else { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 654 | SetRemoteFingerprintFromCert(client1_.dtls_transport(), |
| 655 | client2_.certificate(), |
| 656 | true /*modify_digest*/); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 657 | } |
| 658 | break; |
| 659 | case CALLER_WRITABLE: |
| 660 | EXPECT_TRUE(client1_.Connect(&client2_, true)); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 661 | EXPECT_TRUE_SIMULATED_WAIT(client1_.fake_ice_transport()->writable(), |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 662 | kTimeout, fake_clock_); |
| 663 | break; |
| 664 | case CALLER_RECEIVES_CLIENTHELLO: |
| 665 | // Sanity check that a ClientHello hasn't already been received. |
| 666 | EXPECT_EQ(0, client1_.received_dtls_client_hellos()); |
| 667 | // Making client2_ writable will cause it to send the ClientHello. |
| 668 | EXPECT_TRUE(client2_.Connect(&client1_, true)); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 669 | EXPECT_TRUE_SIMULATED_WAIT(client2_.fake_ice_transport()->writable(), |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 670 | kTimeout, fake_clock_); |
| 671 | EXPECT_EQ_SIMULATED_WAIT(1, client1_.received_dtls_client_hellos(), |
| 672 | kTimeout, fake_clock_); |
| 673 | break; |
| 674 | case HANDSHAKE_FINISHES: |
| 675 | // Sanity check that the handshake hasn't already finished. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 676 | EXPECT_FALSE(client1_.dtls_transport()->IsDtlsConnected() || |
| 677 | client1_.dtls_transport()->dtls_state() == |
Mirko Bonadei | 9f6808b | 2021-05-21 18:46:09 | [diff] [blame] | 678 | webrtc::DtlsTransportState::kFailed); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 679 | EXPECT_TRUE_SIMULATED_WAIT( |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 680 | client1_.dtls_transport()->IsDtlsConnected() || |
| 681 | client1_.dtls_transport()->dtls_state() == |
Mirko Bonadei | 9f6808b | 2021-05-21 18:46:09 | [diff] [blame] | 682 | webrtc::DtlsTransportState::kFailed, |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 683 | kTimeout, fake_clock_); |
| 684 | break; |
| 685 | } |
| 686 | } |
| 687 | |
Mirko Bonadei | 9f6808b | 2021-05-21 18:46:09 | [diff] [blame] | 688 | webrtc::DtlsTransportState expected_final_state = |
| 689 | valid_fingerprint ? webrtc::DtlsTransportState::kConnected |
| 690 | : webrtc::DtlsTransportState::kFailed; |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 691 | EXPECT_EQ_SIMULATED_WAIT(expected_final_state, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 692 | client1_.dtls_transport()->dtls_state(), kTimeout, |
| 693 | fake_clock_); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 694 | EXPECT_EQ_SIMULATED_WAIT(expected_final_state, |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 695 | client2_.dtls_transport()->dtls_state(), kTimeout, |
| 696 | fake_clock_); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 697 | |
Zhi Huang | 70b820f | 2018-01-27 22:16:15 | [diff] [blame] | 698 | // Transports should be writable iff there was a valid fingerprint. |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 699 | EXPECT_EQ(valid_fingerprint, client1_.dtls_transport()->writable()); |
| 700 | EXPECT_EQ(valid_fingerprint, client2_.dtls_transport()->writable()); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 701 | |
| 702 | // Check that no hello needed to be retransmitted. |
| 703 | EXPECT_EQ(1, client1_.received_dtls_client_hellos()); |
| 704 | EXPECT_EQ(1, client2_.received_dtls_server_hellos()); |
| 705 | |
| 706 | if (valid_fingerprint) { |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 707 | TestTransfer(1000, 100, false); |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 708 | } |
| 709 | } |
| 710 | }; |
| 711 | |
| 712 | TEST_P(DtlsEventOrderingTest, TestEventOrdering) { |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 713 | TestEventOrdering(::testing::get<0>(GetParam()), |
| 714 | ::testing::get<1>(GetParam())); |
| 715 | } |
| 716 | |
Mirko Bonadei | c84f661 | 2019-01-31 11:20:57 | [diff] [blame] | 717 | INSTANTIATE_TEST_SUITE_P( |
deadbeef | 89824f6 | 2016-09-30 18:55:43 | [diff] [blame] | 718 | TestEventOrdering, |
| 719 | DtlsEventOrderingTest, |
| 720 | ::testing::Combine( |
| 721 | ::testing::Values( |
| 722 | std::vector<DtlsTransportEvent>{ |
| 723 | CALLER_RECEIVES_FINGERPRINT, CALLER_WRITABLE, |
| 724 | CALLER_RECEIVES_CLIENTHELLO, HANDSHAKE_FINISHES}, |
| 725 | std::vector<DtlsTransportEvent>{ |
| 726 | CALLER_WRITABLE, CALLER_RECEIVES_FINGERPRINT, |
| 727 | CALLER_RECEIVES_CLIENTHELLO, HANDSHAKE_FINISHES}, |
| 728 | std::vector<DtlsTransportEvent>{ |
| 729 | CALLER_WRITABLE, CALLER_RECEIVES_CLIENTHELLO, |
| 730 | CALLER_RECEIVES_FINGERPRINT, HANDSHAKE_FINISHES}, |
| 731 | std::vector<DtlsTransportEvent>{ |
| 732 | CALLER_WRITABLE, CALLER_RECEIVES_CLIENTHELLO, |
| 733 | HANDSHAKE_FINISHES, CALLER_RECEIVES_FINGERPRINT}, |
| 734 | std::vector<DtlsTransportEvent>{ |
| 735 | CALLER_RECEIVES_FINGERPRINT, CALLER_RECEIVES_CLIENTHELLO, |
| 736 | CALLER_WRITABLE, HANDSHAKE_FINISHES}, |
| 737 | std::vector<DtlsTransportEvent>{ |
| 738 | CALLER_RECEIVES_CLIENTHELLO, CALLER_RECEIVES_FINGERPRINT, |
| 739 | CALLER_WRITABLE, HANDSHAKE_FINISHES}, |
| 740 | std::vector<DtlsTransportEvent>{ |
| 741 | CALLER_RECEIVES_CLIENTHELLO, CALLER_WRITABLE, |
| 742 | CALLER_RECEIVES_FINGERPRINT, HANDSHAKE_FINISHES}, |
| 743 | std::vector<DtlsTransportEvent>{CALLER_RECEIVES_CLIENTHELLO, |
| 744 | CALLER_WRITABLE, HANDSHAKE_FINISHES, |
| 745 | CALLER_RECEIVES_FINGERPRINT}), |
| 746 | ::testing::Bool())); |
Taylor Brandstetter | 74cefe1 | 2017-12-14 23:38:57 | [diff] [blame] | 747 | |
| 748 | } // namespace cricket |