blob: 1c2d21f42997b24130468cf387bb34c5b03b7178 [file] [log] [blame]
Zhi Huangf2d7beb2017-11-20 14:35:11 -08001/*
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);
36}
37
38void DtlsSrtpTransport::SetDtlsTransports(
39 cricket::DtlsTransportInternal* rtp_dtls_transport,
40 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
41 // Transport names should be the same.
42 if (rtp_dtls_transport && rtcp_dtls_transport) {
43 RTC_DCHECK(rtp_dtls_transport->transport_name() ==
44 rtcp_dtls_transport->transport_name());
45 }
46
47 // When using DTLS-SRTP, we must reset the SrtpTransport every time the
48 // DtlsTransport changes and wait until the DTLS handshake is complete to set
49 // the newly negotiated parameters.
50 if (IsActive()) {
51 srtp_transport_->ResetParams();
52 }
53
54 if (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(!(IsActive()))
58 << "Setting RTCP for DTLS/SRTP after the DTLS is active "
59 << "should never happen.";
60
61 RTC_LOG(LS_INFO) << "Setting RTCP Transport on "
62 << rtcp_dtls_transport->transport_name() << " transport "
63 << rtcp_dtls_transport;
64 SetRtcpDtlsTransport(rtcp_dtls_transport);
65 SetRtcpPacketTransport(rtcp_dtls_transport);
66 }
67
68 RTC_LOG(LS_INFO) << "Setting RTP Transport on "
69 << rtp_dtls_transport->transport_name() << " transport "
70 << rtp_dtls_transport;
71 SetRtpDtlsTransport(rtp_dtls_transport);
72 SetRtpPacketTransport(rtp_dtls_transport);
73
74 UpdateWritableStateAndMaybeSetupDtlsSrtp();
75}
76
77void DtlsSrtpTransport::SetRtcpMuxEnabled(bool enable) {
78 srtp_transport_->SetRtcpMuxEnabled(enable);
79 if (enable) {
80 UpdateWritableStateAndMaybeSetupDtlsSrtp();
81 }
82}
83
84void DtlsSrtpTransport::SetSendEncryptedHeaderExtensionIds(
85 const std::vector<int>& send_extension_ids) {
86 send_extension_ids_.emplace(send_extension_ids);
87 // Reset the crypto parameters to update the send_extension IDs.
88 SetupRtpDtlsSrtp();
89}
90
91void DtlsSrtpTransport::SetRecvEncryptedHeaderExtensionIds(
92 const std::vector<int>& recv_extension_ids) {
93 recv_extension_ids_.emplace(recv_extension_ids);
94 // Reset the crypto parameters to update the send_extension IDs.
95 SetupRtpDtlsSrtp();
96}
97
98bool DtlsSrtpTransport::IsDtlsActive() {
99 auto rtcp_dtls_transport =
100 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
101 return (rtp_dtls_transport_ && rtp_dtls_transport_->IsDtlsActive() &&
102 (!rtcp_dtls_transport || rtcp_dtls_transport->IsDtlsActive()));
103}
104
105bool DtlsSrtpTransport::IsDtlsConnected() {
106 auto rtcp_dtls_transport =
107 rtcp_mux_enabled() ? nullptr : rtcp_dtls_transport_;
108 return (rtp_dtls_transport_ &&
109 rtp_dtls_transport_->dtls_state() ==
110 cricket::DTLS_TRANSPORT_CONNECTED &&
111 (!rtcp_dtls_transport || rtcp_dtls_transport->dtls_state() ==
112 cricket::DTLS_TRANSPORT_CONNECTED));
113}
114
115bool DtlsSrtpTransport::IsDtlsWritable() {
116 auto rtp_packet_transport = srtp_transport_->rtp_packet_transport();
117 auto rtcp_packet_transport =
118 rtcp_mux_enabled() ? nullptr : srtp_transport_->rtcp_packet_transport();
119 return rtp_packet_transport && rtp_packet_transport->writable() &&
120 (!rtcp_packet_transport || rtcp_packet_transport->writable());
121}
122
123bool DtlsSrtpTransport::DtlsHandshakeCompleted() {
124 return IsDtlsActive() && IsDtlsConnected();
125}
126
127void DtlsSrtpTransport::MaybeSetupDtlsSrtp() {
128 if (IsActive() || !DtlsHandshakeCompleted()) {
129 return;
130 }
131
132 SetupRtpDtlsSrtp();
133
134 if (!rtcp_mux_enabled() && rtcp_dtls_transport_) {
135 SetupRtcpDtlsSrtp();
136 }
137}
138
139void DtlsSrtpTransport::SetupRtpDtlsSrtp() {
140 // Use an empty encrypted header extension ID vector if not set. This could
141 // happen when the DTLS handshake is completed before processing the
142 // Offer/Answer which contains the encrypted header extension IDs.
143 std::vector<int> send_extension_ids;
144 std::vector<int> recv_extension_ids;
145 if (send_extension_ids_) {
146 send_extension_ids = *send_extension_ids_;
147 }
148 if (recv_extension_ids_) {
149 recv_extension_ids = *recv_extension_ids_;
150 }
151
152 int selected_crypto_suite;
153 std::vector<unsigned char> send_key;
154 std::vector<unsigned char> recv_key;
155
156 if (!ExtractParams(rtp_dtls_transport_, &selected_crypto_suite, &send_key,
157 &recv_key) ||
158 !srtp_transport_->SetRtpParams(
159 selected_crypto_suite, &send_key[0],
160 static_cast<int>(send_key.size()), send_extension_ids,
161 selected_crypto_suite, &recv_key[0],
162 static_cast<int>(recv_key.size()), recv_extension_ids)) {
163 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/false);
164 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTP failed";
165 }
166}
167
168void DtlsSrtpTransport::SetupRtcpDtlsSrtp() {
169 // Return if the DTLS-SRTP is active because the encrypted header extension
170 // IDs don't need to be updated for RTCP and the crypto params don't need to
171 // be reset.
172 if (IsActive()) {
173 return;
174 }
175
176 std::vector<int> send_extension_ids;
177 std::vector<int> recv_extension_ids;
178 if (send_extension_ids_) {
179 send_extension_ids = *send_extension_ids_;
180 }
181 if (recv_extension_ids_) {
182 recv_extension_ids = *recv_extension_ids_;
183 }
184
185 int selected_crypto_suite;
186 std::vector<unsigned char> rtcp_send_key;
187 std::vector<unsigned char> rtcp_recv_key;
188 if (!ExtractParams(rtcp_dtls_transport_, &selected_crypto_suite,
189 &rtcp_send_key, &rtcp_recv_key) ||
190 !srtp_transport_->SetRtcpParams(
191 selected_crypto_suite, &rtcp_send_key[0],
192 static_cast<int>(rtcp_send_key.size()), send_extension_ids,
193 selected_crypto_suite, &rtcp_recv_key[0],
194 static_cast<int>(rtcp_recv_key.size()), recv_extension_ids)) {
195 SignalDtlsSrtpSetupFailure(this, /*rtcp=*/true);
196 RTC_LOG(LS_WARNING) << "DTLS-SRTP key installation for RTCP failed";
197 }
198}
199
200bool DtlsSrtpTransport::ExtractParams(
201 cricket::DtlsTransportInternal* dtls_transport,
202 int* selected_crypto_suite,
203 std::vector<unsigned char>* send_key,
204 std::vector<unsigned char>* recv_key) {
205 if (!dtls_transport || !dtls_transport->IsDtlsActive()) {
206 return false;
207 }
208
209 if (!dtls_transport->GetSrtpCryptoSuite(selected_crypto_suite)) {
210 RTC_LOG(LS_ERROR) << "No DTLS-SRTP selected crypto suite";
211 return false;
212 }
213
214 RTC_LOG(LS_INFO) << "Extracting keys from transport: "
215 << dtls_transport->transport_name();
216
217 int key_len;
218 int salt_len;
219 if (!rtc::GetSrtpKeyAndSaltLengths((*selected_crypto_suite), &key_len,
220 &salt_len)) {
221 RTC_LOG(LS_ERROR) << "Unknown DTLS-SRTP crypto suite"
222 << selected_crypto_suite;
223 return false;
224 }
225
226 // OK, we're now doing DTLS (RFC 5764)
227 std::vector<unsigned char> dtls_buffer(key_len * 2 + salt_len * 2);
228
229 // RFC 5705 exporter using the RFC 5764 parameters
230 if (!dtls_transport->ExportKeyingMaterial(kDtlsSrtpExporterLabel, NULL, 0,
231 false, &dtls_buffer[0],
232 dtls_buffer.size())) {
233 RTC_LOG(LS_WARNING) << "DTLS-SRTP key export failed";
234 RTC_NOTREACHED(); // This should never happen
235 return false;
236 }
237
238 // Sync up the keys with the DTLS-SRTP interface
239 std::vector<unsigned char> client_write_key(key_len + salt_len);
240 std::vector<unsigned char> server_write_key(key_len + salt_len);
241 size_t offset = 0;
242 memcpy(&client_write_key[0], &dtls_buffer[offset], key_len);
243 offset += key_len;
244 memcpy(&server_write_key[0], &dtls_buffer[offset], key_len);
245 offset += key_len;
246 memcpy(&client_write_key[key_len], &dtls_buffer[offset], salt_len);
247 offset += salt_len;
248 memcpy(&server_write_key[key_len], &dtls_buffer[offset], salt_len);
249
250 rtc::SSLRole role;
251 if (!dtls_transport->GetSslRole(&role)) {
252 RTC_LOG(LS_WARNING) << "GetSslRole failed";
253 return false;
254 }
255
256 if (role == rtc::SSL_SERVER) {
257 *send_key = server_write_key;
258 *recv_key = client_write_key;
259 } else {
260 *send_key = client_write_key;
261 *recv_key = server_write_key;
262 }
263
264 return true;
265}
266
267void DtlsSrtpTransport::SetDtlsTransport(
268 cricket::DtlsTransportInternal* new_dtls_transport,
269 cricket::DtlsTransportInternal** old_dtls_transport) {
270 if (*old_dtls_transport) {
271 (*old_dtls_transport)->SignalDtlsState.disconnect(this);
272 (*old_dtls_transport)->SignalWritableState.disconnect(this);
273 }
274
275 *old_dtls_transport = new_dtls_transport;
276
277 if (new_dtls_transport) {
278 new_dtls_transport->SignalDtlsState.connect(
279 this, &DtlsSrtpTransport::OnDtlsState);
280 new_dtls_transport->SignalWritableState.connect(
281 this, &DtlsSrtpTransport::OnWritableState);
282 }
283}
284
285void DtlsSrtpTransport::SetRtpDtlsTransport(
286 cricket::DtlsTransportInternal* rtp_dtls_transport) {
287 SetDtlsTransport(rtp_dtls_transport, &rtp_dtls_transport_);
288}
289
290void DtlsSrtpTransport::SetRtcpDtlsTransport(
291 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
292 SetDtlsTransport(rtcp_dtls_transport, &rtcp_dtls_transport_);
293}
294
295void DtlsSrtpTransport::UpdateWritableStateAndMaybeSetupDtlsSrtp() {
296 bool writable = IsDtlsWritable();
297 SetWritable(writable);
298 if (writable) {
299 MaybeSetupDtlsSrtp();
300 }
301}
302
303void DtlsSrtpTransport::SetWritable(bool writable) {
304 // Only fire the signal if the writable state changes.
305 if (writable_ != writable) {
306 writable_ = writable;
307 SignalWritableState(writable_);
308 }
309}
310
311void DtlsSrtpTransport::OnDtlsState(cricket::DtlsTransportInternal* transport,
312 cricket::DtlsTransportState state) {
313 RTC_DCHECK(transport == rtp_dtls_transport_ ||
314 transport == rtcp_dtls_transport_);
315
316 if (state != cricket::DTLS_TRANSPORT_CONNECTED) {
317 srtp_transport_->ResetParams();
318 return;
319 }
320
321 MaybeSetupDtlsSrtp();
322}
323
324void DtlsSrtpTransport::OnWritableState(
325 rtc::PacketTransportInternal* transport) {
326 RTC_DCHECK(transport == srtp_transport_->rtp_packet_transport() ||
327 transport == srtp_transport_->rtcp_packet_transport());
328 UpdateWritableStateAndMaybeSetupDtlsSrtp();
329}
330
331void DtlsSrtpTransport::OnPacketReceived(bool rtcp,
332 rtc::CopyOnWriteBuffer* packet,
333 const rtc::PacketTime& packet_time) {
334 SignalPacketReceived(rtcp, packet, packet_time);
335}
336
337void DtlsSrtpTransport::OnReadyToSend(bool ready) {
338 SignalReadyToSend(ready);
339}
340
341} // namespace webrtc