blob: f40c96f925c7e852dc3b70c7fd3f65d27fb24caa [file] [log] [blame]
Zhi Huangf2d7beb2017-11-20 14:35:11 -08001/*
2 * Copyright 2017 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
11#include "pc/dtlssrtptransport.h"
12
13#include <memory>
14#include <string>
15#include <utility>
16
17#include "media/base/rtputils.h"
18#include "rtc_base/sslstreamadapter.h"
19
20namespace {
21// Value specified in RFC 5764.
22static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
23} // namespace
24
25namespace webrtc {
26
Zhi Huang95e7dbb2018-03-29 00:08:03 +000027DtlsSrtpTransport::DtlsSrtpTransport(
28 std::unique_ptr<webrtc::SrtpTransport> srtp_transport)
29 : RtpTransportInternalAdapter(srtp_transport.get()) {
30 srtp_transport_ = std::move(srtp_transport);
31 RTC_DCHECK(srtp_transport_);
32 srtp_transport_->SignalPacketReceived.connect(
33 this, &DtlsSrtpTransport::OnPacketReceived);
34 srtp_transport_->SignalReadyToSend.connect(this,
35 &DtlsSrtpTransport::OnReadyToSend);
36 srtp_transport_->SignalNetworkRouteChanged.connect(
37 this, &DtlsSrtpTransport::OnNetworkRouteChanged);
38 srtp_transport_->SignalWritableState.connect(
39 this, &DtlsSrtpTransport::OnWritableState);
40 srtp_transport_->SignalSentPacket.connect(this,
41 &DtlsSrtpTransport::OnSentPacket);
42}
Zhi Huangf2d7beb2017-11-20 14:35:11 -080043
44void DtlsSrtpTransport::SetDtlsTransports(
45 cricket::DtlsTransportInternal* rtp_dtls_transport,
46 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
47 // Transport names should be the same.
48 if (rtp_dtls_transport && rtcp_dtls_transport) {
49 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
50 rtcp_dtls_transport->transport_name());
51 }
52
53 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
54 // DtlsTransport changes and wait until the DTLS handshake is complete to set
55 // the newly negotiated parameters.
Zhi Huange830e682018-03-30 10:48:35 -070056 if (IsSrtpActive()) {
Zhi Huang95e7dbb2018-03-29 00:08:03 +000057 srtp_transport_->ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080058 }
59
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080060 const std::string transport_name =
61 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
Zhi Huangf2d7beb2017-11-20 14:35:11 -080062
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080063 // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
64 // allowed according to the BUNDLE spec.
Zhi Huange830e682018-03-30 10:48:35 -070065 RTC_CHECK(!(IsSrtpActive()))
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080066 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
Jonas Olsson45cc8902018-02-13 10:37:07 +010067 "should never happen.";
Zhi Huangf2d7beb2017-11-20 14:35:11 -080068
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080069 RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
70 << " transport " << rtcp_dtls_transport;
71 SetRtcpDtlsTransport(rtcp_dtls_transport);
72 SetRtcpPacketTransport(rtcp_dtls_transport);
73
74 RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
75 << " transport " << rtp_dtls_transport;
Zhi Huangf2d7beb2017-11-20 14:35:11 -080076 SetRtpDtlsTransport(rtp_dtls_transport);
77 SetRtpPacketTransport(rtp_dtls_transport);
78
79 UpdateWritableStateAndMaybeSetupDtlsSrtp();
80}
81
82void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
Zhi Huang95e7dbb2018-03-29 00:08:03 +000083 srtp_transport_->SetRtcpMuxEnabled(enable);
Zhi Huangf2d7beb2017-11-20 14:35:11 -080084 if (enable) {
85 UpdateWritableStateAndMaybeSetupDtlsSrtp();
86 }
87}
88
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080089void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -080090 const std::vector<int>& send_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080091 if (send_extension_ids_ == send_extension_ids) {
92 return;
93 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080094 send_extension_ids_.emplace(send_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080095 if (DtlsHandshakeCompleted()) {
96 // Reset the crypto parameters to update the send extension IDs.
97 SetupRtpDtlsSrtp();
98 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080099}
100
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800101void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800102 const std::vector<int>& recv_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800103 if (recv_extension_ids_ == recv_extension_ids) {
104 return;
105 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800106 recv_extension_ids_.emplace(recv_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800107 if (DtlsHandshakeCompleted()) {
108 // Reset the crypto parameters to update the receive extension IDs.
109 SetupRtpDtlsSrtp();
110 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800111}
112
113bool DtlsSrtpTransport::IsDtlsActive() {
114 auto rtcp_dtls_transport =
115 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
116 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
117 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
118}
119
120bool DtlsSrtpTransport::IsDtlsConnected() {
121 auto rtcp_dtls_transport =
122 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
123 return (rtp_dtls_transport_ &&
124 rtp_dtls_transport_->dtls_state() ==
125 cricket::DTLS_TRANSPORT_CONNECTED &&
126 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
127 cricket::DTLS_TRANSPORT_CONNECTED));
128}
129
130bool DtlsSrtpTransport::IsDtlsWritable() {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000131 auto rtp_packet_transport = srtp_transport_->rtp_packet_transport();
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800132 auto rtcp_packet_transport =
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000133 rtcp_mux_enabled() ? nullptr : srtp_transport_->rtcp_packet_transport();
134 return rtp_packet_transport && rtp_packet_transport->writable() &&
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800135 (!rtcp_packet_transport || rtcp_packet_transport->writable());
136}
137
138bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
139 return IsDtlsActive() && IsDtlsConnected();
140}
141
142void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
Zhi Huange830e682018-03-30 10:48:35 -0700143 if (IsSrtpActive() || !DtlsHandshakeCompleted()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800144 return;
145 }
146
147 SetupRtpDtlsSrtp();
148
149 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
150 SetupRtcpDtlsSrtp();
151 }
152}
153
154void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
155 // Use an empty encrypted header extension ID vector if not set. This could
156 // happen when the DTLS handshake is completed before processing the
157 // Offer/Answer which contains the encrypted header extension IDs.
158 std::vector<int> send_extension_ids;
159 std::vector<int> recv_extension_ids;
160 if (send_extension_ids_) {
161 send_extension_ids = *send_extension_ids_;
162 }
163 if (recv_extension_ids_) {
164 recv_extension_ids = *recv_extension_ids_;
165 }
166
167 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100168 rtc::ZeroOnFreeBuffer<unsigned char> send_key;
169 rtc::ZeroOnFreeBuffer<unsigned char> recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800170
171 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
172 &recv_key) ||
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000173 !srtp_transport_->SetRtpParams(
174 selected_crypto_suite, &send_key[0],
175 static_cast<int>(send_key.size()), send_extension_ids,
176 selected_crypto_suite, &recv_key[0],
177 static_cast<int>(recv_key.size()), recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800178 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
179 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
180 }
181}
182
183void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
184 // Return if the DTLS-SRTP is active because the encrypted header extension
185 // IDs don't need to be updated for RTCP and the crypto params don't need to
186 // be reset.
Zhi Huange830e682018-03-30 10:48:35 -0700187 if (IsSrtpActive()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800188 return;
189 }
190
191 std::vector<int> send_extension_ids;
192 std::vector<int> recv_extension_ids;
193 if (send_extension_ids_) {
194 send_extension_ids = *send_extension_ids_;
195 }
196 if (recv_extension_ids_) {
197 recv_extension_ids = *recv_extension_ids_;
198 }
199
200 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100201 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
202 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800203 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
204 &rtcp_send_key, &rtcp_recv_key) ||
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000205 !srtp_transport_->SetRtcpParams(
206 selected_crypto_suite, &rtcp_send_key[0],
207 static_cast<int>(rtcp_send_key.size()), send_extension_ids,
208 selected_crypto_suite, &rtcp_recv_key[0],
209 static_cast<int>(rtcp_recv_key.size()), recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800210 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
211 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
212 }
213}
214
215bool DtlsSrtpTransport::ExtractParams(
216 cricket::DtlsTransportInternal* dtls_transport,
217 int* selected_crypto_suite,
Joachim Bauch5b32f232018-03-07 20:02:26 +0100218 rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
219 rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800220 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
221 return false;
222 }
223
224 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
225 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
226 return false;
227 }
228
229 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
230 << dtls_transport->transport_name();
231
232 int key_len;
233 int salt_len;
234 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
235 &salt_len)) {
236 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
237 << selected_crypto_suite;
238 return false;
239 }
240
241 // OK, we're now doing DTLS (RFC 5764)
Joachim Bauch5b32f232018-03-07 20:02:26 +0100242 rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800243
244 // RFC 5705 exporter using the RFC 5764 parameters
245 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
246 false, &dtls_buffer[0],
247 dtls_buffer.size())) {
248 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
249 RTC_NOTREACHED(); // This should never happen
250 return false;
251 }
252
253 // Sync up the keys with the DTLS-SRTP interface
Joachim Bauch5b32f232018-03-07 20:02:26 +0100254 rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
255 rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800256 size_t offset = 0;
257 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
258 offset += key_len;
259 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
260 offset += key_len;
261 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
262 offset += salt_len;
263 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
264
265 rtc::SSLRole role;
Zhi Huange818b6e2018-02-22 15:26:27 -0800266 if (!dtls_transport->GetDtlsRole(&role)) {
267 RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800268 return false;
269 }
270
271 if (role == rtc::SSL_SERVER) {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100272 *send_key = std::move(server_write_key);
273 *recv_key = std::move(client_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800274 } else {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100275 *send_key = std::move(client_write_key);
276 *recv_key = std::move(server_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800277 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800278 return true;
279}
280
281void DtlsSrtpTransport::SetDtlsTransport(
282 cricket::DtlsTransportInternal* new_dtls_transport,
283 cricket::DtlsTransportInternal** old_dtls_transport) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800284 if (*old_dtls_transport == new_dtls_transport) {
285 return;
286 }
287
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800288 if (*old_dtls_transport) {
289 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800290 }
291
292 *old_dtls_transport = new_dtls_transport;
293
294 if (new_dtls_transport) {
295 new_dtls_transport->SignalDtlsState.connect(
296 this, &DtlsSrtpTransport::OnDtlsState);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800297 }
298}
299
300void DtlsSrtpTransport::SetRtpDtlsTransport(
301 cricket::DtlsTransportInternal* rtp_dtls_transport) {
302 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
303}
304
305void DtlsSrtpTransport::SetRtcpDtlsTransport(
306 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
307 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
308}
309
310void DtlsSrtpTransport::UpdateWritableStateAndMaybeSetupDtlsSrtp() {
311 bool writable = IsDtlsWritable();
312 SetWritable(writable);
313 if (writable) {
314 MaybeSetupDtlsSrtp();
315 }
316}
317
318void DtlsSrtpTransport::SetWritable(bool writable) {
319 // Only fire the signal if the writable state changes.
320 if (writable_ != writable) {
321 writable_ = writable;
322 SignalWritableState(writable_);
323 }
324}
325
326void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
327 cricket::DtlsTransportState state) {
328 RTC_DCHECK(transport == rtp_dtls_transport_ ||
329 transport == rtcp_dtls_transport_);
330
331 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000332 srtp_transport_->ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800333 return;
334 }
335
336 MaybeSetupDtlsSrtp();
337}
338
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000339void DtlsSrtpTransport::OnWritableState(bool writable) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800340 SetWritable(writable);
341 if (writable) {
342 MaybeSetupDtlsSrtp();
343 }
344}
345
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000346void DtlsSrtpTransport::OnSentPacket(const rtc::SentPacket& sent_packet) {
347 SignalSentPacket(sent_packet);
348}
349
350void DtlsSrtpTransport::OnPacketReceived(bool rtcp,
351 rtc::CopyOnWriteBuffer* packet,
352 const rtc::PacketTime& packet_time) {
353 SignalPacketReceived(rtcp, packet, packet_time);
354}
355
356void DtlsSrtpTransport::OnReadyToSend(bool ready) {
357 SignalReadyToSend(ready);
358}
359
360void DtlsSrtpTransport::OnNetworkRouteChanged(
361 rtc::Optional<rtc::NetworkRoute> network_route) {
362 SignalNetworkRouteChanged(network_route);
363}
364
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800365} // namespace webrtc