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 "api/dtls_transport_interface.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/ssl_stream_adapter.h"
22
23 namespace {
24 // Value specified in RFC 5764.
25 static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
26 } // namespace
27
28 namespace webrtc {
29
DtlsSrtpTransport(bool rtcp_mux_enabled,const FieldTrialsView & field_trials)30 DtlsSrtpTransport::DtlsSrtpTransport(bool rtcp_mux_enabled,
31 const FieldTrialsView& field_trials)
32 : SrtpTransport(rtcp_mux_enabled, field_trials) {}
33
SetDtlsTransports(cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)34 void DtlsSrtpTransport::SetDtlsTransports(
35 cricket::DtlsTransportInternal* rtp_dtls_transport,
36 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
37 // Transport names should be the same.
38 if (rtp_dtls_transport && rtcp_dtls_transport) {
39 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
40 rtcp_dtls_transport->transport_name());
41 }
42
43 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
44 // DtlsTransport changes and wait until the DTLS handshake is complete to set
45 // the newly negotiated parameters.
46 // If `active_reset_srtp_params_` is true, intentionally reset the SRTP
47 // parameter even though the DtlsTransport may not change.
48 if (IsSrtpActive() && (rtp_dtls_transport != rtp_dtls_transport_ ||
49 active_reset_srtp_params_)) {
50 ResetParams();
51 }
52
53 const std::string transport_name =
54 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
55
56 if (rtcp_dtls_transport && rtcp_dtls_transport != rtcp_dtls_transport_) {
57 // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
58 // allowed according to the BUNDLE spec.
59 RTC_CHECK(!(IsSrtpActive()))
60 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
61 "should never happen.";
62 }
63
64 RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
65 << " transport " << rtcp_dtls_transport;
66 SetRtcpDtlsTransport(rtcp_dtls_transport);
67 SetRtcpPacketTransport(rtcp_dtls_transport);
68
69 RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
70 << " transport " << rtp_dtls_transport;
71 SetRtpDtlsTransport(rtp_dtls_transport);
72 SetRtpPacketTransport(rtp_dtls_transport);
73
74 MaybeSetupDtlsSrtp();
75 }
76
SetRtcpMuxEnabled(bool enable)77 void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
78 SrtpTransport::SetRtcpMuxEnabled(enable);
79 if (enable) {
80 MaybeSetupDtlsSrtp();
81 }
82 }
83
UpdateSendEncryptedHeaderExtensionIds(const std::vector<int> & send_extension_ids)84 void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
85 const std::vector<int>& send_extension_ids) {
86 if (send_extension_ids_ == send_extension_ids) {
87 return;
88 }
89 send_extension_ids_.emplace(send_extension_ids);
90 if (DtlsHandshakeCompleted()) {
91 // Reset the crypto parameters to update the send extension IDs.
92 SetupRtpDtlsSrtp();
93 }
94 }
95
UpdateRecvEncryptedHeaderExtensionIds(const std::vector<int> & recv_extension_ids)96 void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
97 const std::vector<int>& recv_extension_ids) {
98 if (recv_extension_ids_ == recv_extension_ids) {
99 return;
100 }
101 recv_extension_ids_.emplace(recv_extension_ids);
102 if (DtlsHandshakeCompleted()) {
103 // Reset the crypto parameters to update the receive extension IDs.
104 SetupRtpDtlsSrtp();
105 }
106 }
107
IsDtlsActive()108 bool DtlsSrtpTransport::IsDtlsActive() {
109 auto rtcp_dtls_transport =
110 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
111 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
112 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
113 }
114
IsDtlsConnected()115 bool DtlsSrtpTransport::IsDtlsConnected() {
116 auto rtcp_dtls_transport =
117 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
118 return (rtp_dtls_transport_ &&
119 rtp_dtls_transport_->dtls_state() == DtlsTransportState::kConnected &&
120 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
121 DtlsTransportState::kConnected));
122 }
123
IsDtlsWritable()124 bool DtlsSrtpTransport::IsDtlsWritable() {
125 auto rtcp_packet_transport =
126 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
127 return rtp_dtls_transport_ && rtp_dtls_transport_->writable() &&
128 (!rtcp_packet_transport || rtcp_packet_transport->writable());
129 }
130
DtlsHandshakeCompleted()131 bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
132 return IsDtlsActive() && IsDtlsConnected();
133 }
134
MaybeSetupDtlsSrtp()135 void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
136 if (IsSrtpActive() || !IsDtlsWritable()) {
137 return;
138 }
139
140 SetupRtpDtlsSrtp();
141
142 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
143 SetupRtcpDtlsSrtp();
144 }
145 }
146
SetupRtpDtlsSrtp()147 void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
148 // Use an empty encrypted header extension ID vector if not set. This could
149 // happen when the DTLS handshake is completed before processing the
150 // Offer/Answer which contains the encrypted header extension IDs.
151 std::vector<int> send_extension_ids;
152 std::vector<int> recv_extension_ids;
153 if (send_extension_ids_) {
154 send_extension_ids = *send_extension_ids_;
155 }
156 if (recv_extension_ids_) {
157 recv_extension_ids = *recv_extension_ids_;
158 }
159
160 int selected_crypto_suite;
161 rtc::ZeroOnFreeBuffer<unsigned char> send_key;
162 rtc::ZeroOnFreeBuffer<unsigned char> recv_key;
163
164 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
165 &recv_key) ||
166 !SetRtpParams(selected_crypto_suite, &send_key[0],
167 static_cast<int>(send_key.size()), send_extension_ids,
168 selected_crypto_suite, &recv_key[0],
169 static_cast<int>(recv_key.size()), recv_extension_ids)) {
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 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
202 }
203 }
204
ExtractParams(cricket::DtlsTransportInternal * dtls_transport,int * selected_crypto_suite,rtc::ZeroOnFreeBuffer<unsigned char> * send_key,rtc::ZeroOnFreeBuffer<unsigned char> * recv_key)205 bool DtlsSrtpTransport::ExtractParams(
206 cricket::DtlsTransportInternal* dtls_transport,
207 int* selected_crypto_suite,
208 rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
209 rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
210 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
211 return false;
212 }
213
214 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
215 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
216 return false;
217 }
218
219 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
220 << dtls_transport->transport_name();
221
222 int key_len;
223 int salt_len;
224 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
225 &salt_len)) {
226 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
227 << selected_crypto_suite;
228 return false;
229 }
230
231 // OK, we're now doing DTLS (RFC 5764)
232 rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
233
234 // RFC 5705 exporter using the RFC 5764 parameters
235 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
236 false, &dtls_buffer[0],
237 dtls_buffer.size())) {
238 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
239 RTC_DCHECK_NOTREACHED(); // This should never happen
240 return false;
241 }
242
243 // Sync up the keys with the DTLS-SRTP interface
244 rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
245 rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
246 size_t offset = 0;
247 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
248 offset += key_len;
249 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
250 offset += key_len;
251 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
252 offset += salt_len;
253 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
254
255 rtc::SSLRole role;
256 if (!dtls_transport->GetDtlsRole(&role)) {
257 RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
258 return false;
259 }
260
261 if (role == rtc::SSL_SERVER) {
262 *send_key = std::move(server_write_key);
263 *recv_key = std::move(client_write_key);
264 } else {
265 *send_key = std::move(client_write_key);
266 *recv_key = std::move(server_write_key);
267 }
268 return true;
269 }
270
SetDtlsTransport(cricket::DtlsTransportInternal * new_dtls_transport,cricket::DtlsTransportInternal ** old_dtls_transport)271 void DtlsSrtpTransport::SetDtlsTransport(
272 cricket::DtlsTransportInternal* new_dtls_transport,
273 cricket::DtlsTransportInternal** old_dtls_transport) {
274 if (*old_dtls_transport == new_dtls_transport) {
275 return;
276 }
277
278 if (*old_dtls_transport) {
279 (*old_dtls_transport)->UnsubscribeDtlsTransportState(this);
280 }
281
282 *old_dtls_transport = new_dtls_transport;
283
284 if (new_dtls_transport) {
285 new_dtls_transport->SubscribeDtlsTransportState(
286 this,
287 [this](cricket::DtlsTransportInternal* transport,
288 DtlsTransportState state) { OnDtlsState(transport, state); });
289 }
290 }
291
SetRtpDtlsTransport(cricket::DtlsTransportInternal * rtp_dtls_transport)292 void DtlsSrtpTransport::SetRtpDtlsTransport(
293 cricket::DtlsTransportInternal* rtp_dtls_transport) {
294 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
295 }
296
SetRtcpDtlsTransport(cricket::DtlsTransportInternal * rtcp_dtls_transport)297 void DtlsSrtpTransport::SetRtcpDtlsTransport(
298 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
299 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
300 }
301
OnDtlsState(cricket::DtlsTransportInternal * transport,DtlsTransportState state)302 void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
303 DtlsTransportState state) {
304 RTC_DCHECK(transport == rtp_dtls_transport_ ||
305 transport == rtcp_dtls_transport_);
306
307 if (on_dtls_state_change_) {
308 on_dtls_state_change_();
309 }
310
311 if (state != DtlsTransportState::kConnected) {
312 ResetParams();
313 return;
314 }
315
316 MaybeSetupDtlsSrtp();
317 }
318
OnWritableState(rtc::PacketTransportInternal * packet_transport)319 void DtlsSrtpTransport::OnWritableState(
320 rtc::PacketTransportInternal* packet_transport) {
321 MaybeSetupDtlsSrtp();
322 }
323
SetOnDtlsStateChange(std::function<void (void)> callback)324 void DtlsSrtpTransport::SetOnDtlsStateChange(
325 std::function<void(void)> callback) {
326 on_dtls_state_change_ = std::move(callback);
327 }
328 } // namespace webrtc
329