• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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