xref: /aosp_15_r20/external/webrtc/pc/dtls_srtp_transport.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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