blob: dacbcb411ddd06376b34d30f20077760f096a5b4 [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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/dtls_srtp_transport.h"
Zhi Huangf2d7beb2017-11-20 14:35:11 -080012
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Zhi Huangf2d7beb2017-11-20 14:35:11 -080015#include <string>
16#include <utility>
17
Yves Gerey3e707812018-11-28 16:47:49 +010018#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/ssl_stream_adapter.h"
Zhi Huangf2d7beb2017-11-20 14:35:11 -080021
22namespace {
23// Value specified in RFC 5764.
24static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
25} // namespace
26
27namespace webrtc {
28
Zhi Huang365381f2018-04-13 16:44:34 -070029DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled)
30 : SrtpTransport(rtcp_mux_enabled) {}
Zhi Huangf2d7beb2017-11-20 14:35:11 -080031
32void DtlsSrtpTransport::SetDtlsTransports(
33 cricket::DtlsTransportInternal* rtp_dtls_transport,
34 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
35 // Transport names should be the same.
36 if (rtp_dtls_transport && rtcp_dtls_transport) {
37 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
38 rtcp_dtls_transport->transport_name());
39 }
40
41 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
42 // DtlsTransport changes and wait until the DTLS handshake is complete to set
43 // the newly negotiated parameters.
Zhi Huangb57e1692018-06-12 11:41:11 -070044 // If |active_reset_srtp_params_| is true, intentionally reset the SRTP
45 // parameter even though the DtlsTransport may not change.
46 if (IsSrtpActive() && (rtp_dtls_transport != rtp_dtls_transport_ ||
47 active_reset_srtp_params_)) {
Zhi Huang365381f2018-04-13 16:44:34 -070048 ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080049 }
50
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080051 const std::string transport_name =
52 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
Zhi Huangf2d7beb2017-11-20 14:35:11 -080053
Taylor Brandstetter53e43b32018-04-19 14:44:12 -070054 if (rtcp_dtls_transport && rtcp_dtls_transport != rtcp_dtls_transport_) {
55 // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
56 // allowed according to the BUNDLE spec.
57 RTC_CHECK(!(IsSrtpActive()))
58 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
59 "should never happen.";
60 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080061
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080062 RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
63 << " transport " << rtcp_dtls_transport;
64 SetRtcpDtlsTransport(rtcp_dtls_transport);
65 SetRtcpPacketTransport(rtcp_dtls_transport);
66
67 RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
68 << " transport " << rtp_dtls_transport;
Zhi Huangf2d7beb2017-11-20 14:35:11 -080069 SetRtpDtlsTransport(rtp_dtls_transport);
70 SetRtpPacketTransport(rtp_dtls_transport);
71
Zhi Huang365381f2018-04-13 16:44:34 -070072 MaybeSetupDtlsSrtp();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080073}
74
75void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
Zhi Huang365381f2018-04-13 16:44:34 -070076 SrtpTransport::SetRtcpMuxEnabled(enable);
Zhi Huangf2d7beb2017-11-20 14:35:11 -080077 if (enable) {
Zhi Huang365381f2018-04-13 16:44:34 -070078 MaybeSetupDtlsSrtp();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080079 }
80}
81
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080082void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -080083 const std::vector<int>& send_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080084 if (send_extension_ids_ == send_extension_ids) {
85 return;
86 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080087 send_extension_ids_.emplace(send_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080088 if (DtlsHandshakeCompleted()) {
89 // Reset the crypto parameters to update the send extension IDs.
90 SetupRtpDtlsSrtp();
91 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080092}
93
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080094void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -080095 const std::vector<int>& recv_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080096 if (recv_extension_ids_ == recv_extension_ids) {
97 return;
98 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080099 recv_extension_ids_.emplace(recv_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800100 if (DtlsHandshakeCompleted()) {
101 // Reset the crypto parameters to update the receive extension IDs.
102 SetupRtpDtlsSrtp();
103 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800104}
105
106bool DtlsSrtpTransport::IsDtlsActive() {
107 auto rtcp_dtls_transport =
108 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
109 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
110 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
111}
112
113bool DtlsSrtpTransport::IsDtlsConnected() {
114 auto rtcp_dtls_transport =
115 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
116 return (rtp_dtls_transport_ &&
117 rtp_dtls_transport_->dtls_state() ==
118 cricket::DTLS_TRANSPORT_CONNECTED &&
119 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
120 cricket::DTLS_TRANSPORT_CONNECTED));
121}
122
123bool DtlsSrtpTransport::IsDtlsWritable() {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800124 auto rtcp_packet_transport =
Zhi Huang365381f2018-04-13 16:44:34 -0700125 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
126 return rtp_dtls_transport_ && rtp_dtls_transport_->writable() &&
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800127 (!rtcp_packet_transport || rtcp_packet_transport->writable());
128}
129
130bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
131 return IsDtlsActive() && IsDtlsConnected();
132}
133
134void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
Zhi Huang365381f2018-04-13 16:44:34 -0700135 if (IsSrtpActive() || !IsDtlsWritable()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800136 return;
137 }
138
139 SetupRtpDtlsSrtp();
140
141 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
142 SetupRtcpDtlsSrtp();
143 }
144}
145
146void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
147 // Use an empty encrypted header extension ID vector if not set. This could
148 // happen when the DTLS handshake is completed before processing the
149 // Offer/Answer which contains the encrypted header extension IDs.
150 std::vector<int> send_extension_ids;
151 std::vector<int> recv_extension_ids;
152 if (send_extension_ids_) {
153 send_extension_ids = *send_extension_ids_;
154 }
155 if (recv_extension_ids_) {
156 recv_extension_ids = *recv_extension_ids_;
157 }
158
159 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100160 rtc::ZeroOnFreeBuffer<unsigned char> send_key;
161 rtc::ZeroOnFreeBuffer<unsigned char> recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800162
163 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
164 &recv_key) ||
Zhi Huang365381f2018-04-13 16:44:34 -0700165 !SetRtpParams(selected_crypto_suite, &send_key[0],
166 static_cast<int>(send_key.size()), send_extension_ids,
167 selected_crypto_suite, &recv_key[0],
168 static_cast<int>(recv_key.size()), recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800169 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
170 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
171 }
172}
173
174void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
175 // Return if the DTLS-SRTP is active because the encrypted header extension
176 // IDs don't need to be updated for RTCP and the crypto params don't need to
177 // be reset.
Zhi Huange830e682018-03-30 10:48:35 -0700178 if (IsSrtpActive()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800179 return;
180 }
181
182 std::vector<int> send_extension_ids;
183 std::vector<int> recv_extension_ids;
184 if (send_extension_ids_) {
185 send_extension_ids = *send_extension_ids_;
186 }
187 if (recv_extension_ids_) {
188 recv_extension_ids = *recv_extension_ids_;
189 }
190
191 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100192 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
193 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800194 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
195 &rtcp_send_key, &rtcp_recv_key) ||
Zhi Huang365381f2018-04-13 16:44:34 -0700196 !SetRtcpParams(selected_crypto_suite, &rtcp_send_key[0],
197 static_cast<int>(rtcp_send_key.size()), send_extension_ids,
198 selected_crypto_suite, &rtcp_recv_key[0],
199 static_cast<int>(rtcp_recv_key.size()),
200 recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800201 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
202 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
203 }
204}
205
206bool DtlsSrtpTransport::ExtractParams(
207 cricket::DtlsTransportInternal* dtls_transport,
208 int* selected_crypto_suite,
Joachim Bauch5b32f232018-03-07 20:02:26 +0100209 rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
210 rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800211 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
212 return false;
213 }
214
215 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
216 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
217 return false;
218 }
219
220 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
221 << dtls_transport->transport_name();
222
223 int key_len;
224 int salt_len;
225 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
226 &salt_len)) {
227 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
228 << selected_crypto_suite;
229 return false;
230 }
231
232 // OK, we're now doing DTLS (RFC 5764)
Joachim Bauch5b32f232018-03-07 20:02:26 +0100233 rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800234
235 // RFC 5705 exporter using the RFC 5764 parameters
236 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
237 false, &dtls_buffer[0],
238 dtls_buffer.size())) {
239 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
240 RTC_NOTREACHED(); // This should never happen
241 return false;
242 }
243
244 // Sync up the keys with the DTLS-SRTP interface
Joachim Bauch5b32f232018-03-07 20:02:26 +0100245 rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
246 rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800247 size_t offset = 0;
248 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
249 offset += key_len;
250 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
251 offset += key_len;
252 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
253 offset += salt_len;
254 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
255
256 rtc::SSLRole role;
Zhi Huange818b6e2018-02-22 15:26:27 -0800257 if (!dtls_transport->GetDtlsRole(&role)) {
258 RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800259 return false;
260 }
261
262 if (role == rtc::SSL_SERVER) {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100263 *send_key = std::move(server_write_key);
264 *recv_key = std::move(client_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800265 } else {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100266 *send_key = std::move(client_write_key);
267 *recv_key = std::move(server_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800268 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800269 return true;
270}
271
272void DtlsSrtpTransport::SetDtlsTransport(
273 cricket::DtlsTransportInternal* new_dtls_transport,
274 cricket::DtlsTransportInternal** old_dtls_transport) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800275 if (*old_dtls_transport == new_dtls_transport) {
276 return;
277 }
278
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800279 if (*old_dtls_transport) {
280 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800281 }
282
283 *old_dtls_transport = new_dtls_transport;
284
285 if (new_dtls_transport) {
286 new_dtls_transport->SignalDtlsState.connect(
287 this, &DtlsSrtpTransport::OnDtlsState);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800288 }
289}
290
291void DtlsSrtpTransport::SetRtpDtlsTransport(
292 cricket::DtlsTransportInternal* rtp_dtls_transport) {
293 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
294}
295
296void DtlsSrtpTransport::SetRtcpDtlsTransport(
297 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
298 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
299}
300
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800301void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
302 cricket::DtlsTransportState state) {
303 RTC_DCHECK(transport == rtp_dtls_transport_ ||
304 transport == rtcp_dtls_transport_);
305
Jonas Olsson635474e2018-10-18 15:58:17 +0200306 SignalDtlsStateChange();
307
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800308 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
Zhi Huang365381f2018-04-13 16:44:34 -0700309 ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800310 return;
311 }
312
313 MaybeSetupDtlsSrtp();
314}
315
Zhi Huang365381f2018-04-13 16:44:34 -0700316void DtlsSrtpTransport::OnWritableState(
317 rtc::PacketTransportInternal* packet_transport) {
318 MaybeSetupDtlsSrtp();
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000319}
320
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800321} // namespace webrtc