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     RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
170   }
171 }
172 
SetupRtcpDtlsSrtp()173 void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
174   // Return if the DTLS-SRTP is active because the encrypted header extension
175   // IDs don't need to be updated for RTCP and the crypto params don't need to
176   // be reset.
177   if (IsSrtpActive()) {
178     return;
179   }
180 
181   std::vector<int> send_extension_ids;
182   std::vector<int> recv_extension_ids;
183   if (send_extension_ids_) {
184     send_extension_ids = *send_extension_ids_;
185   }
186   if (recv_extension_ids_) {
187     recv_extension_ids = *recv_extension_ids_;
188   }
189 
190   int selected_crypto_suite;
191   rtc::ZeroOnFreeBuffer<unsigned char> rtcp_send_key;
192   rtc::ZeroOnFreeBuffer<unsigned char> rtcp_recv_key;
193   if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
194                      &rtcp_send_key, &rtcp_recv_key) ||
195       !SetRtcpParams(selected_crypto_suite, &rtcp_send_key[0],
196                      static_cast<int>(rtcp_send_key.size()), send_extension_ids,
197                      selected_crypto_suite, &rtcp_recv_key[0],
198                      static_cast<int>(rtcp_recv_key.size()),
199                      recv_extension_ids)) {
200     RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
201   }
202 }
203 
ExtractParams(cricket::DtlsTransportInternal * dtls_transport,int * selected_crypto_suite,rtc::ZeroOnFreeBuffer<unsigned char> * send_key,rtc::ZeroOnFreeBuffer<unsigned char> * recv_key)204 bool DtlsSrtpTransport::ExtractParams(
205     cricket::DtlsTransportInternal* dtls_transport,
206     int* selected_crypto_suite,
207     rtc::ZeroOnFreeBuffer<unsigned char>* send_key,
208     rtc::ZeroOnFreeBuffer<unsigned char>* recv_key) {
209   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)
231   rtc::ZeroOnFreeBuffer<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
232 
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
243   rtc::ZeroOnFreeBuffer<unsigned char> client_write_key(key_len + salt_len);
244   rtc::ZeroOnFreeBuffer<unsigned char> server_write_key(key_len + salt_len);
245   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;
255   if (!dtls_transport->GetDtlsRole(&role)) {
256     RTC_LOG(LS_WARNING) << "Failed to get the DTLS role.";
257     return false;
258   }
259 
260   if (role == rtc::SSL_SERVER) {
261     *send_key = std::move(server_write_key);
262     *recv_key = std::move(client_write_key);
263   } else {
264     *send_key = std::move(client_write_key);
265     *recv_key = std::move(server_write_key);
266   }
267   return true;
268 }
269 
SetDtlsTransport(cricket::DtlsTransportInternal * new_dtls_transport,cricket::DtlsTransportInternal ** old_dtls_transport)270 void DtlsSrtpTransport::SetDtlsTransport(
271     cricket::DtlsTransportInternal* new_dtls_transport,
272     cricket::DtlsTransportInternal** old_dtls_transport) {
273   if (*old_dtls_transport == new_dtls_transport) {
274     return;
275   }
276 
277   if (*old_dtls_transport) {
278     (*old_dtls_transport)->UnsubscribeDtlsState(this);
279   }
280 
281   *old_dtls_transport = new_dtls_transport;
282 
283   if (new_dtls_transport) {
284     new_dtls_transport->SubscribeDtlsState(
285         this, [this](cricket::DtlsTransportInternal* transport,
286                      cricket::DtlsTransportState state) {
287           OnDtlsState(transport, state);
288         });
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,cricket::DtlsTransportState state)302 void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
303                                     cricket::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 != cricket::DTLS_TRANSPORT_CONNECTED) {
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