1 /*
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/dtls_srtp_transport.h"
12
13 #include <string.h>
14
15 #include <string>
16 #include <utility>
17
18 #include "rtc_base/checks.h"
19 #include "rtc_base/logging.h"
20 #include "rtc_base/ssl_stream_adapter.h"
21
22 namespace {
23 // Value specified in RFC 5764.
24 static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
25 } // namespace
26
27 namespace webrtc {
28
DtlsSrtpTransport(bool rtcp_mux_enabled)29 DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled)
30 : SrtpTransport(rtcp_mux_enabled) {}
31
SetDtlsTransports(cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)32 void 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.
44 // 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_)) {
48 ResetParams();
49 }
50
51 const std::string transport_name =
52 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
53
54 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 }
61
62 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;
69 SetRtpDtlsTransport(rtp_dtls_transport);
70 SetRtpPacketTransport(rtp_dtls_transport);
71
72 MaybeSetupDtlsSrtp();
73 }
74
SetRtcpMuxEnabled(bool enable)75 void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
76 SrtpTransport::SetRtcpMuxEnabled(enable);
77 if (enable) {
78 MaybeSetupDtlsSrtp();
79 }
80 }
81
UpdateSendEncryptedHeaderExtensionIds(const std::vector<int> & send_extension_ids)82 void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
83 const std::vector<int>& send_extension_ids) {
84 if (send_extension_ids_ == send_extension_ids) {
85 return;
86 }
87 send_extension_ids_.emplace(send_extension_ids);
88 if (DtlsHandshakeCompleted()) {
89 // Reset the crypto parameters to update the send extension IDs.
90 SetupRtpDtlsSrtp();
91 }
92 }
93
UpdateRecvEncryptedHeaderExtensionIds(const std::vector<int> & recv_extension_ids)94 void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
95 const std::vector<int>& recv_extension_ids) {
96 if (recv_extension_ids_ == recv_extension_ids) {
97 return;
98 }
99 recv_extension_ids_.emplace(recv_extension_ids);
100 if (DtlsHandshakeCompleted()) {
101 // Reset the crypto parameters to update the receive extension IDs.
102 SetupRtpDtlsSrtp();
103 }
104 }
105
IsDtlsActive()106 bool 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
IsDtlsConnected()113 bool 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
IsDtlsWritable()123 bool DtlsSrtpTransport::IsDtlsWritable() {
124 auto rtcp_packet_transport =
125 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
126 return rtp_dtls_transport_ && rtp_dtls_transport_->writable() &&
127 (!rtcp_packet_transport || rtcp_packet_transport->writable());
128 }
129
DtlsHandshakeCompleted()130 bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
131 return IsDtlsActive() && IsDtlsConnected();
132 }
133
MaybeSetupDtlsSrtp()134 void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
135 if (IsSrtpActive() || !IsDtlsWritable()) {
136 return;
137 }
138
139 SetupRtpDtlsSrtp();
140
141 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
142 SetupRtcpDtlsSrtp();
143 }
144 }
145
SetupRtpDtlsSrtp()146 void 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;
160 rtc::ZeroOnFreeBuffer<unsigned char> send_key;
161 rtc::ZeroOnFreeBuffer<unsigned char> recv_key;
162
163 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
164 &recv_key) ||
165 !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)) {
169 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
170 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
171 }
172 }
173
SetupRtcpDtlsSrtp()174 void 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.
178 if (IsSrtpActive()) {
179 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;
192 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
193 rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
194 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
195 &rtcp_send_key, &rtcp_recv_key) ||
196 !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)) {
201 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
202 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
203 }
204 }
205
ExtractParams(cricket::DtlsTransportInternal * dtls_transport,int * selected_crypto_suite,rtc::ZeroOnFreeBuffer<unsigned char> * send_key,rtc::ZeroOnFreeBuffer<unsigned char> * recv_key)206 bool DtlsSrtpTransport::ExtractParams(
207 cricket::DtlsTransportInternal* dtls_transport,
208 int* selected_crypto_suite,
209 rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
210 rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
211 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)
233 rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
234
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
245 rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
246 rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
247 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;
257 if (!dtls_transport->GetDtlsRole(&role)) {
258 RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
259 return false;
260 }
261
262 if (role == rtc::SSL_SERVER) {
263 *send_key = std::move(server_write_key);
264 *recv_key = std::move(client_write_key);
265 } else {
266 *send_key = std::move(client_write_key);
267 *recv_key = std::move(server_write_key);
268 }
269 return true;
270 }
271
SetDtlsTransport(cricket::DtlsTransportInternal * new_dtls_transport,cricket::DtlsTransportInternal ** old_dtls_transport)272 void DtlsSrtpTransport::SetDtlsTransport(
273 cricket::DtlsTransportInternal* new_dtls_transport,
274 cricket::DtlsTransportInternal** old_dtls_transport) {
275 if (*old_dtls_transport == new_dtls_transport) {
276 return;
277 }
278
279 if (*old_dtls_transport) {
280 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
281 }
282
283 *old_dtls_transport = new_dtls_transport;
284
285 if (new_dtls_transport) {
286 new_dtls_transport->SignalDtlsState.connect(
287 this, &DtlsSrtpTransport::OnDtlsState);
288 }
289 }
290
SetRtpDtlsTransport(cricket::DtlsTransportInternal * rtp_dtls_transport)291 void DtlsSrtpTransport::SetRtpDtlsTransport(
292 cricket::DtlsTransportInternal* rtp_dtls_transport) {
293 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
294 }
295
SetRtcpDtlsTransport(cricket::DtlsTransportInternal * rtcp_dtls_transport)296 void DtlsSrtpTransport::SetRtcpDtlsTransport(
297 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
298 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
299 }
300
OnDtlsState(cricket::DtlsTransportInternal * transport,cricket::DtlsTransportState state)301 void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
302 cricket::DtlsTransportState state) {
303 RTC_DCHECK(transport == rtp_dtls_transport_ ||
304 transport == rtcp_dtls_transport_);
305
306 SignalDtlsStateChange();
307
308 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
309 ResetParams();
310 return;
311 }
312
313 MaybeSetupDtlsSrtp();
314 }
315
OnWritableState(rtc::PacketTransportInternal * packet_transport)316 void DtlsSrtpTransport::OnWritableState(
317 rtc::PacketTransportInternal* packet_transport) {
318 MaybeSetupDtlsSrtp();
319 }
320
321 } // namespace webrtc
322