blob: bc5d3aa9002f0ececaf2e866352ae603dfc8f484 [file] [log] [blame]
Zhi Huangf2d7beb2017-11-20 22:35:111/*
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/dtlssrtptransport.h"
12
13#include <memory>
14#include <string>
15#include <utility>
16
17#include "media/base/rtputils.h"
18#include "rtc_base/sslstreamadapter.h"
19
20namespace {
21// Value specified in RFC 5764.
22static const char kDtlsSrtpExporterLabel[] = "EXTRACTOR-dtls_srtp";
23} // namespace
24
25namespace webrtc {
26
27DtlsSrtpTransport::DtlsSrtpTransport(
28 std::unique_ptr<webrtc::SrtpTransport> srtp_transport)
29 : RtpTransportInternalAdapter(srtp_transport.get()) {
30 srtp_transport_ = std::move(srtp_transport);
31 RTC_DCHECK(srtp_transport_);
32 srtp_transport_->SignalPacketReceived.connect(
33 this, &DtlsSrtpTransport::OnPacketReceived);
34 srtp_transport_->SignalReadyToSend.connect(this,
35 &DtlsSrtpTransport::OnReadyToSend);
Zhi Huangcd3fc5d2017-11-29 18:41:5736 srtp_transport_->SignalWritableState.connect(
37 this, &DtlsSrtpTransport::OnWritableState);
38 srtp_transport_->SignalSentPacket.connect(this,
39 &DtlsSrtpTransport::OnSentPacket);
Zhi Huangf2d7beb2017-11-20 22:35:1140}
41
42void DtlsSrtpTransport::SetDtlsTransports(
43 cricket::DtlsTransportInternal* rtp_dtls_transport,
44 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
45 // Transport names should be the same.
46 if (rtp_dtls_transport && rtcp_dtls_transport) {
47 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
48 rtcp_dtls_transport->transport_name());
49 }
50
51 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
52 // DtlsTransport changes and wait until the DTLS handshake is complete to set
53 // the newly negotiated parameters.
54 if (IsActive()) {
55 srtp_transport_->ResetParams();
56 }
57
Zhi Huangcd3fc5d2017-11-29 18:41:5758 const std::string transport_name =
59 rtp_dtls_transport ? rtp_dtls_transport->transport_name() : "null";
Zhi Huangf2d7beb2017-11-20 22:35:1160
Zhi Huangcd3fc5d2017-11-29 18:41:5761 // This would only be possible if using BUNDLE but not rtcp-mux, which isn't
62 // allowed according to the BUNDLE spec.
63 RTC_CHECK(!(IsActive()))
64 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
65 << "should never happen.";
Zhi Huangf2d7beb2017-11-20 22:35:1166
Zhi Huangcd3fc5d2017-11-29 18:41:5767 RTC_LOG(LS_INFO) << "Setting RTCP Transport on " << transport_name
68 << " transport " << rtcp_dtls_transport;
69 SetRtcpDtlsTransport(rtcp_dtls_transport);
70 SetRtcpPacketTransport(rtcp_dtls_transport);
71
72 RTC_LOG(LS_INFO) << "Setting RTP Transport on " << transport_name
73 << " transport " << rtp_dtls_transport;
Zhi Huangf2d7beb2017-11-20 22:35:1174 SetRtpDtlsTransport(rtp_dtls_transport);
75 SetRtpPacketTransport(rtp_dtls_transport);
76
77 UpdateWritableStateAndMaybeSetupDtlsSrtp();
78}
79
80void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
81 srtp_transport_->SetRtcpMuxEnabled(enable);
82 if (enable) {
83 UpdateWritableStateAndMaybeSetupDtlsSrtp();
84 }
85}
86
Zhi Huangcd3fc5d2017-11-29 18:41:5787void DtlsSrtpTransport::UpdateSendEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 22:35:1188 const std::vector<int>& send_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 18:41:5789 if (send_extension_ids_ == send_extension_ids) {
90 return;
91 }
Zhi Huangf2d7beb2017-11-20 22:35:1192 send_extension_ids_.emplace(send_extension_ids);
Zhi Huangcd3fc5d2017-11-29 18:41:5793 if (DtlsHandshakeCompleted()) {
94 // Reset the crypto parameters to update the send extension IDs.
95 SetupRtpDtlsSrtp();
96 }
Zhi Huangf2d7beb2017-11-20 22:35:1197}
98
Zhi Huangcd3fc5d2017-11-29 18:41:5799void DtlsSrtpTransport::UpdateRecvEncryptedHeaderExtensionIds(
Zhi Huangf2d7beb2017-11-20 22:35:11100 const std::vector<int>& recv_extension_ids) {
Zhi Huangcd3fc5d2017-11-29 18:41:57101 if (recv_extension_ids_ == recv_extension_ids) {
102 return;
103 }
Zhi Huangf2d7beb2017-11-20 22:35:11104 recv_extension_ids_.emplace(recv_extension_ids);
Zhi Huangcd3fc5d2017-11-29 18:41:57105 if (DtlsHandshakeCompleted()) {
106 // Reset the crypto parameters to update the receive extension IDs.
107 SetupRtpDtlsSrtp();
108 }
Zhi Huangf2d7beb2017-11-20 22:35:11109}
110
111bool DtlsSrtpTransport::IsDtlsActive() {
112 auto rtcp_dtls_transport =
113 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
114 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
115 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
116}
117
118bool DtlsSrtpTransport::IsDtlsConnected() {
119 auto rtcp_dtls_transport =
120 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
121 return (rtp_dtls_transport_ &&
122 rtp_dtls_transport_->dtls_state() ==
123 cricket::DTLS_TRANSPORT_CONNECTED &&
124 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
125 cricket::DTLS_TRANSPORT_CONNECTED));
126}
127
128bool DtlsSrtpTransport::IsDtlsWritable() {
129 auto rtp_packet_transport = srtp_transport_->rtp_packet_transport();
130 auto rtcp_packet_transport =
131 rtcp_mux_enabled() ? nullptr : srtp_transport_->rtcp_packet_transport();
132 return rtp_packet_transport && rtp_packet_transport->writable() &&
133 (!rtcp_packet_transport || rtcp_packet_transport->writable());
134}
135
136bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
137 return IsDtlsActive() && IsDtlsConnected();
138}
139
140void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
141 if (IsActive() || !DtlsHandshakeCompleted()) {
142 return;
143 }
144
145 SetupRtpDtlsSrtp();
146
147 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
148 SetupRtcpDtlsSrtp();
149 }
150}
151
152void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
153 // Use an empty encrypted header extension ID vector if not set. This could
154 // happen when the DTLS handshake is completed before processing the
155 // Offer/Answer which contains the encrypted header extension IDs.
156 std::vector<int> send_extension_ids;
157 std::vector<int> recv_extension_ids;
158 if (send_extension_ids_) {
159 send_extension_ids = *send_extension_ids_;
160 }
161 if (recv_extension_ids_) {
162 recv_extension_ids = *recv_extension_ids_;
163 }
164
165 int selected_crypto_suite;
166 std::vector<unsigned char> send_key;
167 std::vector<unsigned char> recv_key;
168
169 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
170 &recv_key) ||
171 !srtp_transport_->SetRtpParams(
172 selected_crypto_suite, &send_key[0],
173 static_cast<int>(send_key.size()), send_extension_ids,
174 selected_crypto_suite, &recv_key[0],
175 static_cast<int>(recv_key.size()), recv_extension_ids)) {
176 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
177 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
178 }
179}
180
181void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
182 // Return if the DTLS-SRTP is active because the encrypted header extension
183 // IDs don't need to be updated for RTCP and the crypto params don't need to
184 // be reset.
185 if (IsActive()) {
186 return;
187 }
188
189 std::vector<int> send_extension_ids;
190 std::vector<int> recv_extension_ids;
191 if (send_extension_ids_) {
192 send_extension_ids = *send_extension_ids_;
193 }
194 if (recv_extension_ids_) {
195 recv_extension_ids = *recv_extension_ids_;
196 }
197
198 int selected_crypto_suite;
199 std::vector<unsigned char> rtcp_send_key;
200 std::vector<unsigned char> rtcp_recv_key;
201 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
202 &rtcp_send_key, &rtcp_recv_key) ||
203 !srtp_transport_->SetRtcpParams(
204 selected_crypto_suite, &rtcp_send_key[0],
205 static_cast<int>(rtcp_send_key.size()), send_extension_ids,
206 selected_crypto_suite, &rtcp_recv_key[0],
207 static_cast<int>(rtcp_recv_key.size()), recv_extension_ids)) {
208 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
209 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
210 }
211}
212
213bool DtlsSrtpTransport::ExtractParams(
214 cricket::DtlsTransportInternal* dtls_transport,
215 int* selected_crypto_suite,
216 std::vector<unsigned char>* send_key,
217 std::vector<unsigned char>* recv_key) {
218 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
219 return false;
220 }
221
222 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
223 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
224 return false;
225 }
226
227 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
228 << dtls_transport->transport_name();
229
230 int key_len;
231 int salt_len;
232 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
233 &salt_len)) {
234 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
235 << selected_crypto_suite;
236 return false;
237 }
238
239 // OK, we're now doing DTLS (RFC 5764)
240 std::vector<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
241
242 // RFC 5705 exporter using the RFC 5764 parameters
243 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
244 false, &dtls_buffer[0],
245 dtls_buffer.size())) {
246 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
247 RTC_NOTREACHED(); // This should never happen
248 return false;
249 }
250
251 // Sync up the keys with the DTLS-SRTP interface
252 std::vector<unsigned char> client_write_key(key_len + salt_len);
253 std::vector<unsigned char> server_write_key(key_len + salt_len);
254 size_t offset = 0;
255 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
256 offset += key_len;
257 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
258 offset += key_len;
259 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
260 offset += salt_len;
261 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
262
263 rtc::SSLRole role;
264 if (!dtls_transport->GetSslRole(&role)) {
265 RTC_LOG(LS_WARNING) << "GetSslRole failed";
266 return false;
267 }
268
269 if (role == rtc::SSL_SERVER) {
270 *send_key = server_write_key;
271 *recv_key = client_write_key;
272 } else {
273 *send_key = client_write_key;
274 *recv_key = server_write_key;
275 }
276
277 return true;
278}
279
280void DtlsSrtpTransport::SetDtlsTransport(
281 cricket::DtlsTransportInternal* new_dtls_transport,
282 cricket::DtlsTransportInternal** old_dtls_transport) {
Zhi Huangcd3fc5d2017-11-29 18:41:57283 if (*old_dtls_transport == new_dtls_transport) {
284 return;
285 }
286
Zhi Huangf2d7beb2017-11-20 22:35:11287 if (*old_dtls_transport) {
288 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
Zhi Huangf2d7beb2017-11-20 22:35:11289 }
290
291 *old_dtls_transport = new_dtls_transport;
292
293 if (new_dtls_transport) {
294 new_dtls_transport->SignalDtlsState.connect(
295 this, &DtlsSrtpTransport::OnDtlsState);
Zhi Huangf2d7beb2017-11-20 22:35:11296 }
297}
298
299void DtlsSrtpTransport::SetRtpDtlsTransport(
300 cricket::DtlsTransportInternal* rtp_dtls_transport) {
301 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
302}
303
304void DtlsSrtpTransport::SetRtcpDtlsTransport(
305 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
306 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
307}
308
309void DtlsSrtpTransport::UpdateWritableStateAndMaybeSetupDtlsSrtp() {
310 bool writable = IsDtlsWritable();
311 SetWritable(writable);
312 if (writable) {
313 MaybeSetupDtlsSrtp();
314 }
315}
316
317void DtlsSrtpTransport::SetWritable(bool writable) {
318 // Only fire the signal if the writable state changes.
319 if (writable_ != writable) {
320 writable_ = writable;
321 SignalWritableState(writable_);
322 }
323}
324
325void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
326 cricket::DtlsTransportState state) {
327 RTC_DCHECK(transport == rtp_dtls_transport_ ||
328 transport == rtcp_dtls_transport_);
329
330 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
331 srtp_transport_->ResetParams();
332 return;
333 }
334
335 MaybeSetupDtlsSrtp();
336}
337
Zhi Huangcd3fc5d2017-11-29 18:41:57338void DtlsSrtpTransport::OnWritableState(bool writable) {
339 SetWritable(writable);
340 if (writable) {
341 MaybeSetupDtlsSrtp();
342 }
343}
344
345void DtlsSrtpTransport::OnSentPacket(const rtc::SentPacket& sent_packet) {
346 SignalSentPacket(sent_packet);
Zhi Huangf2d7beb2017-11-20 22:35:11347}
348
349void DtlsSrtpTransport::OnPacketReceived(bool rtcp,
350 rtc::CopyOnWriteBuffer* packet,
351 const rtc::PacketTime& packet_time) {
352 SignalPacketReceived(rtcp, packet, packet_time);
353}
354
355void DtlsSrtpTransport::OnReadyToSend(bool ready) {
356 SignalReadyToSend(ready);
357}
358
359} // namespace webrtc