blob: 2835d34a4677654972b54b7f6033a1f420396333 [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 Huang365381f2018-04-13 16:44:34 -070027DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled)
28 : SrtpTransport(rtcp_mux_enabled) {}
Zhi Huangf2d7beb2017-11-20 14:35:11 -080029
30void DtlsSrtpTransport::SetDtlsTransports(
31 cricket::DtlsTransportInternal* rtp_dtls_transport,
32 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
33 // Transport names should be the same.
34 if (rtp_dtls_transport && rtcp_dtls_transport) {
35 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
36 rtcp_dtls_transport->transport_name());
37 }
38
39 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
40 // DtlsTransport changes and wait until the DTLS handshake is complete to set
41 // the newly negotiated parameters.
Zhi Huangb57e1692018-06-12 11:41:11 -070042 // If |active_reset_srtp_params_| is true, intentionally reset the SRTP
43 // parameter even though the DtlsTransport may not change.
44 if (IsSrtpActive() && (rtp_dtls_transport != rtp_dtls_transport_ ||
45 active_reset_srtp_params_)) {
Zhi Huang365381f2018-04-13 16:44:34 -070046 ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080047 }
48
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080049 const std::string transport_name =
50 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
Zhi Huangf2d7beb2017-11-20 14:35:11 -080051
Taylor Brandstetter53e43b32018-04-19 14:44:12 -070052 if (rtcp_dtls_transport && rtcp_dtls_transport != rtcp_dtls_transport_) {
53 // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
54 // allowed according to the BUNDLE spec.
55 RTC_CHECK(!(IsSrtpActive()))
56 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
57 "should never happen.";
58 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080059
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080060 RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
61 << " transport " << rtcp_dtls_transport;
62 SetRtcpDtlsTransport(rtcp_dtls_transport);
63 SetRtcpPacketTransport(rtcp_dtls_transport);
64
65 RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
66 << " transport " << rtp_dtls_transport;
Zhi Huangf2d7beb2017-11-20 14:35:11 -080067 SetRtpDtlsTransport(rtp_dtls_transport);
68 SetRtpPacketTransport(rtp_dtls_transport);
69
Zhi Huang365381f2018-04-13 16:44:34 -070070 MaybeSetupDtlsSrtp();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080071}
72
73void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
Zhi Huang365381f2018-04-13 16:44:34 -070074 SrtpTransport::SetRtcpMuxEnabled(enable);
Zhi Huangf2d7beb2017-11-20 14:35:11 -080075 if (enable) {
Zhi Huang365381f2018-04-13 16:44:34 -070076 MaybeSetupDtlsSrtp();
Zhi Huangf2d7beb2017-11-20 14:35:11 -080077 }
78}
79
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080080void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -080081 const std::vector<int>& send_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080082 if (send_extension_ids_ == send_extension_ids) {
83 return;
84 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080085 send_extension_ids_.emplace(send_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080086 if (DtlsHandshakeCompleted()) {
87 // Reset the crypto parameters to update the send extension IDs.
88 SetupRtpDtlsSrtp();
89 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080090}
91
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080092void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 14:35:11 -080093 const std::vector<int>& recv_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080094 if (recv_extension_ids_ == recv_extension_ids) {
95 return;
96 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -080097 recv_extension_ids_.emplace(recv_extension_ids);
Zhi Huangcd3fc5d2017-11-29 10:41:57 -080098 if (DtlsHandshakeCompleted()) {
99 // Reset the crypto parameters to update the receive extension IDs.
100 SetupRtpDtlsSrtp();
101 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800102}
103
104bool DtlsSrtpTransport::IsDtlsActive() {
105 auto rtcp_dtls_transport =
106 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
107 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
108 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
109}
110
111bool DtlsSrtpTransport::IsDtlsConnected() {
112 auto rtcp_dtls_transport =
113 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
114 return (rtp_dtls_transport_ &&
115 rtp_dtls_transport_->dtls_state() ==
116 cricket::DTLS_TRANSPORT_CONNECTED &&
117 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
118 cricket::DTLS_TRANSPORT_CONNECTED));
119}
120
121bool DtlsSrtpTransport::IsDtlsWritable() {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800122 auto rtcp_packet_transport =
Zhi Huang365381f2018-04-13 16:44:34 -0700123 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
124 return rtp_dtls_transport_ && rtp_dtls_transport_->writable() &&
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800125 (!rtcp_packet_transport || rtcp_packet_transport->writable());
126}
127
128bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
129 return IsDtlsActive() && IsDtlsConnected();
130}
131
132void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
Zhi Huang365381f2018-04-13 16:44:34 -0700133 if (IsSrtpActive() || !IsDtlsWritable()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800134 return;
135 }
136
137 SetupRtpDtlsSrtp();
138
139 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
140 SetupRtcpDtlsSrtp();
141 }
142}
143
144void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
145 // Use an empty encrypted header extension ID vector if not set. This could
146 // happen when the DTLS handshake is completed before processing the
147 // Offer/Answer which contains the encrypted header extension IDs.
148 std::vector<int> send_extension_ids;
149 std::vector<int> recv_extension_ids;
150 if (send_extension_ids_) {
151 send_extension_ids = *send_extension_ids_;
152 }
153 if (recv_extension_ids_) {
154 recv_extension_ids = *recv_extension_ids_;
155 }
156
157 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100158 rtc::ZeroOnFreeBuffer<unsigned char> send_key;
159 rtc::ZeroOnFreeBuffer<unsigned char> recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800160
161 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
162 &recv_key) ||
Zhi Huang365381f2018-04-13 16:44:34 -0700163 !SetRtpParams(selected_crypto_suite, &send_key[0],
164 static_cast<int>(send_key.size()), send_extension_ids,
165 selected_crypto_suite, &recv_key[0],
166 static_cast<int>(recv_key.size()), recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800167 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
168 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
169 }
170}
171
172void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
173 // Return if the DTLS-SRTP is active because the encrypted header extension
174 // IDs don't need to be updated for RTCP and the crypto params don't need to
175 // be reset.
Zhi Huange830e682018-03-30 10:48:35 -0700176 if (IsSrtpActive()) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800177 return;
178 }
179
180 std::vector<int> send_extension_ids;
181 std::vector<int> recv_extension_ids;
182 if (send_extension_ids_) {
183 send_extension_ids = *send_extension_ids_;
184 }
185 if (recv_extension_ids_) {
186 recv_extension_ids = *recv_extension_ids_;
187 }
188
189 int selected_crypto_suite;
Joachim Bauch5b32f232018-03-07 20:02:26 +0100190 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
191 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800192 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
193 &rtcp_send_key, &rtcp_recv_key) ||
Zhi Huang365381f2018-04-13 16:44:34 -0700194 !SetRtcpParams(selected_crypto_suite, &rtcp_send_key[0],
195 static_cast<int>(rtcp_send_key.size()), send_extension_ids,
196 selected_crypto_suite, &rtcp_recv_key[0],
197 static_cast<int>(rtcp_recv_key.size()),
198 recv_extension_ids)) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800199 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
200 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
201 }
202}
203
204bool DtlsSrtpTransport::ExtractParams(
205 cricket::DtlsTransportInternal* dtls_transport,
206 int* selected_crypto_suite,
Joachim Bauch5b32f232018-03-07 20:02:26 +0100207 rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
208 rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800209 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
210 return false;
211 }
212
213 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
214 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
215 return false;
216 }
217
218 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
219 << dtls_transport->transport_name();
220
221 int key_len;
222 int salt_len;
223 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
224 &salt_len)) {
225 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
226 << selected_crypto_suite;
227 return false;
228 }
229
230 // OK, we're now doing DTLS (RFC 5764)
Joachim Bauch5b32f232018-03-07 20:02:26 +0100231 rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800232
233 // RFC 5705 exporter using the RFC 5764 parameters
234 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
235 false, &dtls_buffer[0],
236 dtls_buffer.size())) {
237 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
238 RTC_NOTREACHED(); // This should never happen
239 return false;
240 }
241
242 // Sync up the keys with the DTLS-SRTP interface
Joachim Bauch5b32f232018-03-07 20:02:26 +0100243 rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
244 rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800245 size_t offset = 0;
246 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
247 offset += key_len;
248 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
249 offset += key_len;
250 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
251 offset += salt_len;
252 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
253
254 rtc::SSLRole role;
Zhi Huange818b6e2018-02-22 15:26:27 -0800255 if (!dtls_transport->GetDtlsRole(&role)) {
256 RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800257 return false;
258 }
259
260 if (role == rtc::SSL_SERVER) {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100261 *send_key = std::move(server_write_key);
262 *recv_key = std::move(client_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800263 } else {
Joachim Bauch5b32f232018-03-07 20:02:26 +0100264 *send_key = std::move(client_write_key);
265 *recv_key = std::move(server_write_key);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800266 }
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800267 return true;
268}
269
270void DtlsSrtpTransport::SetDtlsTransport(
271 cricket::DtlsTransportInternal* new_dtls_transport,
272 cricket::DtlsTransportInternal** old_dtls_transport) {
Zhi Huangcd3fc5d2017-11-29 10:41:57 -0800273 if (*old_dtls_transport == new_dtls_transport) {
274 return;
275 }
276
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800277 if (*old_dtls_transport) {
278 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800279 }
280
281 *old_dtls_transport = new_dtls_transport;
282
283 if (new_dtls_transport) {
284 new_dtls_transport->SignalDtlsState.connect(
285 this, &DtlsSrtpTransport::OnDtlsState);
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800286 }
287}
288
289void DtlsSrtpTransport::SetRtpDtlsTransport(
290 cricket::DtlsTransportInternal* rtp_dtls_transport) {
291 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
292}
293
294void DtlsSrtpTransport::SetRtcpDtlsTransport(
295 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
296 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
297}
298
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800299void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
300 cricket::DtlsTransportState state) {
301 RTC_DCHECK(transport == rtp_dtls_transport_ ||
302 transport == rtcp_dtls_transport_);
303
Jonas Olsson635474e2018-10-18 15:58:17 +0200304 SignalDtlsStateChange();
305
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800306 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
Zhi Huang365381f2018-04-13 16:44:34 -0700307 ResetParams();
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800308 return;
309 }
310
311 MaybeSetupDtlsSrtp();
312}
313
Zhi Huang365381f2018-04-13 16:44:34 -0700314void DtlsSrtpTransport::OnWritableState(
315 rtc::PacketTransportInternal* packet_transport) {
316 MaybeSetupDtlsSrtp();
Zhi Huang95e7dbb2018-03-29 00:08:03 +0000317}
318
Zhi Huangf2d7beb2017-11-20 14:35:11 -0800319} // namespace webrtc