1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "pc/srtp_transport.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <string.h>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/match.h"
20*d9f75844SAndroid Build Coastguard Worker #include "media/base/rtp_utils.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_util.h"
22*d9f75844SAndroid Build Coastguard Worker #include "pc/rtp_transport.h"
23*d9f75844SAndroid Build Coastguard Worker #include "pc/srtp_session.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/async_packet_socket.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/copy_on_write_buffer.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/ssl_stream_adapter.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/third_party/base64/base64.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/zero_memory.h"
33*d9f75844SAndroid Build Coastguard Worker
34*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
35*d9f75844SAndroid Build Coastguard Worker
SrtpTransport(bool rtcp_mux_enabled,const FieldTrialsView & field_trials)36*d9f75844SAndroid Build Coastguard Worker SrtpTransport::SrtpTransport(bool rtcp_mux_enabled,
37*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView& field_trials)
38*d9f75844SAndroid Build Coastguard Worker : RtpTransport(rtcp_mux_enabled), field_trials_(field_trials) {}
39*d9f75844SAndroid Build Coastguard Worker
SetSrtpSendKey(const cricket::CryptoParams & params)40*d9f75844SAndroid Build Coastguard Worker RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) {
41*d9f75844SAndroid Build Coastguard Worker if (send_params_) {
42*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(
43*d9f75844SAndroid Build Coastguard Worker webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
44*d9f75844SAndroid Build Coastguard Worker "Setting the SRTP send key twice is currently unsupported.");
45*d9f75844SAndroid Build Coastguard Worker }
46*d9f75844SAndroid Build Coastguard Worker if (recv_params_ && recv_params_->cipher_suite != params.cipher_suite) {
47*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(
48*d9f75844SAndroid Build Coastguard Worker webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
49*d9f75844SAndroid Build Coastguard Worker "The send key and receive key must have the same cipher suite.");
50*d9f75844SAndroid Build Coastguard Worker }
51*d9f75844SAndroid Build Coastguard Worker
52*d9f75844SAndroid Build Coastguard Worker send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
53*d9f75844SAndroid Build Coastguard Worker if (*send_cipher_suite_ == rtc::kSrtpInvalidCryptoSuite) {
54*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
55*d9f75844SAndroid Build Coastguard Worker "Invalid SRTP crypto suite");
56*d9f75844SAndroid Build Coastguard Worker }
57*d9f75844SAndroid Build Coastguard Worker
58*d9f75844SAndroid Build Coastguard Worker int send_key_len, send_salt_len;
59*d9f75844SAndroid Build Coastguard Worker if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
60*d9f75844SAndroid Build Coastguard Worker &send_salt_len)) {
61*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
62*d9f75844SAndroid Build Coastguard Worker "Could not get lengths for crypto suite(s):"
63*d9f75844SAndroid Build Coastguard Worker " send cipher_suite ");
64*d9f75844SAndroid Build Coastguard Worker }
65*d9f75844SAndroid Build Coastguard Worker
66*d9f75844SAndroid Build Coastguard Worker send_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(send_key_len + send_salt_len);
67*d9f75844SAndroid Build Coastguard Worker if (!ParseKeyParams(params.key_params, send_key_.data(), send_key_.size())) {
68*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
69*d9f75844SAndroid Build Coastguard Worker "Failed to parse the crypto key params");
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker
72*d9f75844SAndroid Build Coastguard Worker if (!MaybeSetKeyParams()) {
73*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
74*d9f75844SAndroid Build Coastguard Worker "Failed to set the crypto key params");
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker send_params_ = params;
77*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
78*d9f75844SAndroid Build Coastguard Worker }
79*d9f75844SAndroid Build Coastguard Worker
SetSrtpReceiveKey(const cricket::CryptoParams & params)80*d9f75844SAndroid Build Coastguard Worker RTCError SrtpTransport::SetSrtpReceiveKey(const cricket::CryptoParams& params) {
81*d9f75844SAndroid Build Coastguard Worker if (recv_params_) {
82*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(
83*d9f75844SAndroid Build Coastguard Worker webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
84*d9f75844SAndroid Build Coastguard Worker "Setting the SRTP send key twice is currently unsupported.");
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker if (send_params_ && send_params_->cipher_suite != params.cipher_suite) {
87*d9f75844SAndroid Build Coastguard Worker LOG_AND_RETURN_ERROR(
88*d9f75844SAndroid Build Coastguard Worker webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
89*d9f75844SAndroid Build Coastguard Worker "The send key and receive key must have the same cipher suite.");
90*d9f75844SAndroid Build Coastguard Worker }
91*d9f75844SAndroid Build Coastguard Worker
92*d9f75844SAndroid Build Coastguard Worker recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
93*d9f75844SAndroid Build Coastguard Worker if (*recv_cipher_suite_ == rtc::kSrtpInvalidCryptoSuite) {
94*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
95*d9f75844SAndroid Build Coastguard Worker "Invalid SRTP crypto suite");
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker
98*d9f75844SAndroid Build Coastguard Worker int recv_key_len, recv_salt_len;
99*d9f75844SAndroid Build Coastguard Worker if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
100*d9f75844SAndroid Build Coastguard Worker &recv_salt_len)) {
101*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
102*d9f75844SAndroid Build Coastguard Worker "Could not get lengths for crypto suite(s):"
103*d9f75844SAndroid Build Coastguard Worker " recv cipher_suite ");
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker
106*d9f75844SAndroid Build Coastguard Worker recv_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(recv_key_len + recv_salt_len);
107*d9f75844SAndroid Build Coastguard Worker if (!ParseKeyParams(params.key_params, recv_key_.data(), recv_key_.size())) {
108*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
109*d9f75844SAndroid Build Coastguard Worker "Failed to parse the crypto key params");
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker
112*d9f75844SAndroid Build Coastguard Worker if (!MaybeSetKeyParams()) {
113*d9f75844SAndroid Build Coastguard Worker return RTCError(RTCErrorType::INVALID_PARAMETER,
114*d9f75844SAndroid Build Coastguard Worker "Failed to set the crypto key params");
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker recv_params_ = params;
117*d9f75844SAndroid Build Coastguard Worker return RTCError::OK();
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker
SendRtpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)120*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
121*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options,
122*d9f75844SAndroid Build Coastguard Worker int flags) {
123*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
124*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
125*d9f75844SAndroid Build Coastguard Worker << "Failed to send the packet because SRTP transport is inactive.";
126*d9f75844SAndroid Build Coastguard Worker return false;
127*d9f75844SAndroid Build Coastguard Worker }
128*d9f75844SAndroid Build Coastguard Worker rtc::PacketOptions updated_options = options;
129*d9f75844SAndroid Build Coastguard Worker TRACE_EVENT0("webrtc", "SRTP Encode");
130*d9f75844SAndroid Build Coastguard Worker bool res;
131*d9f75844SAndroid Build Coastguard Worker uint8_t* data = packet->MutableData();
132*d9f75844SAndroid Build Coastguard Worker int len = rtc::checked_cast<int>(packet->size());
133*d9f75844SAndroid Build Coastguard Worker // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
134*d9f75844SAndroid Build Coastguard Worker // inside libsrtp for a RTP packet. A external HMAC module will be writing
135*d9f75844SAndroid Build Coastguard Worker // a fake HMAC value. This is ONLY done for a RTP packet.
136*d9f75844SAndroid Build Coastguard Worker // Socket layer will update rtp sendtime extension header if present in
137*d9f75844SAndroid Build Coastguard Worker // packet with current time before updating the HMAC.
138*d9f75844SAndroid Build Coastguard Worker #if !defined(ENABLE_EXTERNAL_AUTH)
139*d9f75844SAndroid Build Coastguard Worker res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
140*d9f75844SAndroid Build Coastguard Worker #else
141*d9f75844SAndroid Build Coastguard Worker if (!IsExternalAuthActive()) {
142*d9f75844SAndroid Build Coastguard Worker res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
143*d9f75844SAndroid Build Coastguard Worker } else {
144*d9f75844SAndroid Build Coastguard Worker updated_options.packet_time_params.rtp_sendtime_extension_id =
145*d9f75844SAndroid Build Coastguard Worker rtp_abs_sendtime_extn_id_;
146*d9f75844SAndroid Build Coastguard Worker res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
147*d9f75844SAndroid Build Coastguard Worker &updated_options.packet_time_params.srtp_packet_index);
148*d9f75844SAndroid Build Coastguard Worker // If protection succeeds, let's get auth params from srtp.
149*d9f75844SAndroid Build Coastguard Worker if (res) {
150*d9f75844SAndroid Build Coastguard Worker uint8_t* auth_key = nullptr;
151*d9f75844SAndroid Build Coastguard Worker int key_len = 0;
152*d9f75844SAndroid Build Coastguard Worker res = GetRtpAuthParams(
153*d9f75844SAndroid Build Coastguard Worker &auth_key, &key_len,
154*d9f75844SAndroid Build Coastguard Worker &updated_options.packet_time_params.srtp_auth_tag_len);
155*d9f75844SAndroid Build Coastguard Worker if (res) {
156*d9f75844SAndroid Build Coastguard Worker updated_options.packet_time_params.srtp_auth_key.resize(key_len);
157*d9f75844SAndroid Build Coastguard Worker updated_options.packet_time_params.srtp_auth_key.assign(
158*d9f75844SAndroid Build Coastguard Worker auth_key, auth_key + key_len);
159*d9f75844SAndroid Build Coastguard Worker }
160*d9f75844SAndroid Build Coastguard Worker }
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker #endif
163*d9f75844SAndroid Build Coastguard Worker if (!res) {
164*d9f75844SAndroid Build Coastguard Worker uint16_t seq_num = ParseRtpSequenceNumber(*packet);
165*d9f75844SAndroid Build Coastguard Worker uint32_t ssrc = ParseRtpSsrc(*packet);
166*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
167*d9f75844SAndroid Build Coastguard Worker << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
168*d9f75844SAndroid Build Coastguard Worker return false;
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker
171*d9f75844SAndroid Build Coastguard Worker // Update the length of the packet now that we've added the auth tag.
172*d9f75844SAndroid Build Coastguard Worker packet->SetSize(len);
173*d9f75844SAndroid Build Coastguard Worker return SendPacket(/*rtcp=*/false, packet, updated_options, flags);
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker
SendRtcpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)176*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
177*d9f75844SAndroid Build Coastguard Worker const rtc::PacketOptions& options,
178*d9f75844SAndroid Build Coastguard Worker int flags) {
179*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
180*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
181*d9f75844SAndroid Build Coastguard Worker << "Failed to send the packet because SRTP transport is inactive.";
182*d9f75844SAndroid Build Coastguard Worker return false;
183*d9f75844SAndroid Build Coastguard Worker }
184*d9f75844SAndroid Build Coastguard Worker
185*d9f75844SAndroid Build Coastguard Worker TRACE_EVENT0("webrtc", "SRTP Encode");
186*d9f75844SAndroid Build Coastguard Worker uint8_t* data = packet->MutableData();
187*d9f75844SAndroid Build Coastguard Worker int len = rtc::checked_cast<int>(packet->size());
188*d9f75844SAndroid Build Coastguard Worker if (!ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len)) {
189*d9f75844SAndroid Build Coastguard Worker int type = -1;
190*d9f75844SAndroid Build Coastguard Worker cricket::GetRtcpType(data, len, &type);
191*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
192*d9f75844SAndroid Build Coastguard Worker << ", type=" << type;
193*d9f75844SAndroid Build Coastguard Worker return false;
194*d9f75844SAndroid Build Coastguard Worker }
195*d9f75844SAndroid Build Coastguard Worker // Update the length of the packet now that we've added the auth tag.
196*d9f75844SAndroid Build Coastguard Worker packet->SetSize(len);
197*d9f75844SAndroid Build Coastguard Worker
198*d9f75844SAndroid Build Coastguard Worker return SendPacket(/*rtcp=*/true, packet, options, flags);
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker
OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)201*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,
202*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
203*d9f75844SAndroid Build Coastguard Worker TRACE_EVENT0("webrtc", "SrtpTransport::OnRtpPacketReceived");
204*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
205*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
206*d9f75844SAndroid Build Coastguard Worker << "Inactive SRTP transport received an RTP packet. Drop it.";
207*d9f75844SAndroid Build Coastguard Worker return;
208*d9f75844SAndroid Build Coastguard Worker }
209*d9f75844SAndroid Build Coastguard Worker char* data = packet.MutableData<char>();
210*d9f75844SAndroid Build Coastguard Worker int len = rtc::checked_cast<int>(packet.size());
211*d9f75844SAndroid Build Coastguard Worker if (!UnprotectRtp(data, len, &len)) {
212*d9f75844SAndroid Build Coastguard Worker // Limit the error logging to avoid excessive logs when there are lots of
213*d9f75844SAndroid Build Coastguard Worker // bad packets.
214*d9f75844SAndroid Build Coastguard Worker const int kFailureLogThrottleCount = 100;
215*d9f75844SAndroid Build Coastguard Worker if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
216*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
217*d9f75844SAndroid Build Coastguard Worker << ", seqnum=" << ParseRtpSequenceNumber(packet)
218*d9f75844SAndroid Build Coastguard Worker << ", SSRC=" << ParseRtpSsrc(packet)
219*d9f75844SAndroid Build Coastguard Worker << ", previous failure count: "
220*d9f75844SAndroid Build Coastguard Worker << decryption_failure_count_;
221*d9f75844SAndroid Build Coastguard Worker }
222*d9f75844SAndroid Build Coastguard Worker ++decryption_failure_count_;
223*d9f75844SAndroid Build Coastguard Worker return;
224*d9f75844SAndroid Build Coastguard Worker }
225*d9f75844SAndroid Build Coastguard Worker packet.SetSize(len);
226*d9f75844SAndroid Build Coastguard Worker DemuxPacket(std::move(packet), packet_time_us);
227*d9f75844SAndroid Build Coastguard Worker }
228*d9f75844SAndroid Build Coastguard Worker
OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)229*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,
230*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_us) {
231*d9f75844SAndroid Build Coastguard Worker TRACE_EVENT0("webrtc", "SrtpTransport::OnRtcpPacketReceived");
232*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
233*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
234*d9f75844SAndroid Build Coastguard Worker << "Inactive SRTP transport received an RTCP packet. Drop it.";
235*d9f75844SAndroid Build Coastguard Worker return;
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker char* data = packet.MutableData<char>();
238*d9f75844SAndroid Build Coastguard Worker int len = rtc::checked_cast<int>(packet.size());
239*d9f75844SAndroid Build Coastguard Worker if (!UnprotectRtcp(data, len, &len)) {
240*d9f75844SAndroid Build Coastguard Worker int type = -1;
241*d9f75844SAndroid Build Coastguard Worker cricket::GetRtcpType(data, len, &type);
242*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
243*d9f75844SAndroid Build Coastguard Worker << ", type=" << type;
244*d9f75844SAndroid Build Coastguard Worker return;
245*d9f75844SAndroid Build Coastguard Worker }
246*d9f75844SAndroid Build Coastguard Worker packet.SetSize(len);
247*d9f75844SAndroid Build Coastguard Worker SignalRtcpPacketReceived(&packet, packet_time_us);
248*d9f75844SAndroid Build Coastguard Worker }
249*d9f75844SAndroid Build Coastguard Worker
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)250*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnNetworkRouteChanged(
251*d9f75844SAndroid Build Coastguard Worker absl::optional<rtc::NetworkRoute> network_route) {
252*d9f75844SAndroid Build Coastguard Worker // Only append the SRTP overhead when there is a selected network route.
253*d9f75844SAndroid Build Coastguard Worker if (network_route) {
254*d9f75844SAndroid Build Coastguard Worker int srtp_overhead = 0;
255*d9f75844SAndroid Build Coastguard Worker if (IsSrtpActive()) {
256*d9f75844SAndroid Build Coastguard Worker GetSrtpOverhead(&srtp_overhead);
257*d9f75844SAndroid Build Coastguard Worker }
258*d9f75844SAndroid Build Coastguard Worker network_route->packet_overhead += srtp_overhead;
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker SignalNetworkRouteChanged(network_route);
261*d9f75844SAndroid Build Coastguard Worker }
262*d9f75844SAndroid Build Coastguard Worker
OnWritableState(rtc::PacketTransportInternal * packet_transport)263*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnWritableState(
264*d9f75844SAndroid Build Coastguard Worker rtc::PacketTransportInternal* packet_transport) {
265*d9f75844SAndroid Build Coastguard Worker SignalWritableState(IsWritable(/*rtcp=*/false) && IsWritable(/*rtcp=*/true));
266*d9f75844SAndroid Build Coastguard Worker }
267*d9f75844SAndroid Build Coastguard Worker
SetRtpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)268*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SetRtpParams(int send_cs,
269*d9f75844SAndroid Build Coastguard Worker const uint8_t* send_key,
270*d9f75844SAndroid Build Coastguard Worker int send_key_len,
271*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& send_extension_ids,
272*d9f75844SAndroid Build Coastguard Worker int recv_cs,
273*d9f75844SAndroid Build Coastguard Worker const uint8_t* recv_key,
274*d9f75844SAndroid Build Coastguard Worker int recv_key_len,
275*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& recv_extension_ids) {
276*d9f75844SAndroid Build Coastguard Worker // If parameters are being set for the first time, we should create new SRTP
277*d9f75844SAndroid Build Coastguard Worker // sessions and call "SetSend/SetRecv". Otherwise we should call
278*d9f75844SAndroid Build Coastguard Worker // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
279*d9f75844SAndroid Build Coastguard Worker // call "srtp_update".
280*d9f75844SAndroid Build Coastguard Worker bool new_sessions = false;
281*d9f75844SAndroid Build Coastguard Worker if (!send_session_) {
282*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!recv_session_);
283*d9f75844SAndroid Build Coastguard Worker CreateSrtpSessions();
284*d9f75844SAndroid Build Coastguard Worker new_sessions = true;
285*d9f75844SAndroid Build Coastguard Worker }
286*d9f75844SAndroid Build Coastguard Worker bool ret = new_sessions
287*d9f75844SAndroid Build Coastguard Worker ? send_session_->SetSend(send_cs, send_key, send_key_len,
288*d9f75844SAndroid Build Coastguard Worker send_extension_ids)
289*d9f75844SAndroid Build Coastguard Worker : send_session_->UpdateSend(send_cs, send_key, send_key_len,
290*d9f75844SAndroid Build Coastguard Worker send_extension_ids);
291*d9f75844SAndroid Build Coastguard Worker if (!ret) {
292*d9f75844SAndroid Build Coastguard Worker ResetParams();
293*d9f75844SAndroid Build Coastguard Worker return false;
294*d9f75844SAndroid Build Coastguard Worker }
295*d9f75844SAndroid Build Coastguard Worker
296*d9f75844SAndroid Build Coastguard Worker ret = new_sessions ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len,
297*d9f75844SAndroid Build Coastguard Worker recv_extension_ids)
298*d9f75844SAndroid Build Coastguard Worker : recv_session_->UpdateRecv(
299*d9f75844SAndroid Build Coastguard Worker recv_cs, recv_key, recv_key_len, recv_extension_ids);
300*d9f75844SAndroid Build Coastguard Worker if (!ret) {
301*d9f75844SAndroid Build Coastguard Worker ResetParams();
302*d9f75844SAndroid Build Coastguard Worker return false;
303*d9f75844SAndroid Build Coastguard Worker }
304*d9f75844SAndroid Build Coastguard Worker
305*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
306*d9f75844SAndroid Build Coastguard Worker << " with negotiated parameters: send cipher_suite "
307*d9f75844SAndroid Build Coastguard Worker << send_cs << " recv cipher_suite " << recv_cs;
308*d9f75844SAndroid Build Coastguard Worker MaybeUpdateWritableState();
309*d9f75844SAndroid Build Coastguard Worker return true;
310*d9f75844SAndroid Build Coastguard Worker }
311*d9f75844SAndroid Build Coastguard Worker
SetRtcpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)312*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SetRtcpParams(int send_cs,
313*d9f75844SAndroid Build Coastguard Worker const uint8_t* send_key,
314*d9f75844SAndroid Build Coastguard Worker int send_key_len,
315*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& send_extension_ids,
316*d9f75844SAndroid Build Coastguard Worker int recv_cs,
317*d9f75844SAndroid Build Coastguard Worker const uint8_t* recv_key,
318*d9f75844SAndroid Build Coastguard Worker int recv_key_len,
319*d9f75844SAndroid Build Coastguard Worker const std::vector<int>& recv_extension_ids) {
320*d9f75844SAndroid Build Coastguard Worker // This can only be called once, but can be safely called after
321*d9f75844SAndroid Build Coastguard Worker // SetRtpParams
322*d9f75844SAndroid Build Coastguard Worker if (send_rtcp_session_ || recv_rtcp_session_) {
323*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
324*d9f75844SAndroid Build Coastguard Worker return false;
325*d9f75844SAndroid Build Coastguard Worker }
326*d9f75844SAndroid Build Coastguard Worker
327*d9f75844SAndroid Build Coastguard Worker send_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
328*d9f75844SAndroid Build Coastguard Worker if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len,
329*d9f75844SAndroid Build Coastguard Worker send_extension_ids)) {
330*d9f75844SAndroid Build Coastguard Worker return false;
331*d9f75844SAndroid Build Coastguard Worker }
332*d9f75844SAndroid Build Coastguard Worker
333*d9f75844SAndroid Build Coastguard Worker recv_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
334*d9f75844SAndroid Build Coastguard Worker if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len,
335*d9f75844SAndroid Build Coastguard Worker recv_extension_ids)) {
336*d9f75844SAndroid Build Coastguard Worker return false;
337*d9f75844SAndroid Build Coastguard Worker }
338*d9f75844SAndroid Build Coastguard Worker
339*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
340*d9f75844SAndroid Build Coastguard Worker " send cipher_suite "
341*d9f75844SAndroid Build Coastguard Worker << send_cs << " recv cipher_suite " << recv_cs;
342*d9f75844SAndroid Build Coastguard Worker MaybeUpdateWritableState();
343*d9f75844SAndroid Build Coastguard Worker return true;
344*d9f75844SAndroid Build Coastguard Worker }
345*d9f75844SAndroid Build Coastguard Worker
IsSrtpActive() const346*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsSrtpActive() const {
347*d9f75844SAndroid Build Coastguard Worker return send_session_ && recv_session_;
348*d9f75844SAndroid Build Coastguard Worker }
349*d9f75844SAndroid Build Coastguard Worker
IsWritable(bool rtcp) const350*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsWritable(bool rtcp) const {
351*d9f75844SAndroid Build Coastguard Worker return IsSrtpActive() && RtpTransport::IsWritable(rtcp);
352*d9f75844SAndroid Build Coastguard Worker }
353*d9f75844SAndroid Build Coastguard Worker
ResetParams()354*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::ResetParams() {
355*d9f75844SAndroid Build Coastguard Worker send_session_ = nullptr;
356*d9f75844SAndroid Build Coastguard Worker recv_session_ = nullptr;
357*d9f75844SAndroid Build Coastguard Worker send_rtcp_session_ = nullptr;
358*d9f75844SAndroid Build Coastguard Worker recv_rtcp_session_ = nullptr;
359*d9f75844SAndroid Build Coastguard Worker MaybeUpdateWritableState();
360*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
361*d9f75844SAndroid Build Coastguard Worker }
362*d9f75844SAndroid Build Coastguard Worker
CreateSrtpSessions()363*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::CreateSrtpSessions() {
364*d9f75844SAndroid Build Coastguard Worker send_session_.reset(new cricket::SrtpSession(field_trials_));
365*d9f75844SAndroid Build Coastguard Worker recv_session_.reset(new cricket::SrtpSession(field_trials_));
366*d9f75844SAndroid Build Coastguard Worker if (external_auth_enabled_) {
367*d9f75844SAndroid Build Coastguard Worker send_session_->EnableExternalAuth();
368*d9f75844SAndroid Build Coastguard Worker }
369*d9f75844SAndroid Build Coastguard Worker }
370*d9f75844SAndroid Build Coastguard Worker
ProtectRtp(void * p,int in_len,int max_len,int * out_len)371*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
372*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
373*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
374*d9f75844SAndroid Build Coastguard Worker return false;
375*d9f75844SAndroid Build Coastguard Worker }
376*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
377*d9f75844SAndroid Build Coastguard Worker return send_session_->ProtectRtp(p, in_len, max_len, out_len);
378*d9f75844SAndroid Build Coastguard Worker }
379*d9f75844SAndroid Build Coastguard Worker
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)380*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtp(void* p,
381*d9f75844SAndroid Build Coastguard Worker int in_len,
382*d9f75844SAndroid Build Coastguard Worker int max_len,
383*d9f75844SAndroid Build Coastguard Worker int* out_len,
384*d9f75844SAndroid Build Coastguard Worker int64_t* index) {
385*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
386*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
387*d9f75844SAndroid Build Coastguard Worker return false;
388*d9f75844SAndroid Build Coastguard Worker }
389*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
390*d9f75844SAndroid Build Coastguard Worker return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
391*d9f75844SAndroid Build Coastguard Worker }
392*d9f75844SAndroid Build Coastguard Worker
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)393*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtcp(void* p,
394*d9f75844SAndroid Build Coastguard Worker int in_len,
395*d9f75844SAndroid Build Coastguard Worker int max_len,
396*d9f75844SAndroid Build Coastguard Worker int* out_len) {
397*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
398*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
399*d9f75844SAndroid Build Coastguard Worker return false;
400*d9f75844SAndroid Build Coastguard Worker }
401*d9f75844SAndroid Build Coastguard Worker if (send_rtcp_session_) {
402*d9f75844SAndroid Build Coastguard Worker return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
403*d9f75844SAndroid Build Coastguard Worker } else {
404*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
405*d9f75844SAndroid Build Coastguard Worker return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
406*d9f75844SAndroid Build Coastguard Worker }
407*d9f75844SAndroid Build Coastguard Worker }
408*d9f75844SAndroid Build Coastguard Worker
UnprotectRtp(void * p,int in_len,int * out_len)409*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
410*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
411*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
412*d9f75844SAndroid Build Coastguard Worker return false;
413*d9f75844SAndroid Build Coastguard Worker }
414*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(recv_session_);
415*d9f75844SAndroid Build Coastguard Worker return recv_session_->UnprotectRtp(p, in_len, out_len);
416*d9f75844SAndroid Build Coastguard Worker }
417*d9f75844SAndroid Build Coastguard Worker
UnprotectRtcp(void * p,int in_len,int * out_len)418*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
419*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
420*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
421*d9f75844SAndroid Build Coastguard Worker return false;
422*d9f75844SAndroid Build Coastguard Worker }
423*d9f75844SAndroid Build Coastguard Worker if (recv_rtcp_session_) {
424*d9f75844SAndroid Build Coastguard Worker return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
425*d9f75844SAndroid Build Coastguard Worker } else {
426*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(recv_session_);
427*d9f75844SAndroid Build Coastguard Worker return recv_session_->UnprotectRtcp(p, in_len, out_len);
428*d9f75844SAndroid Build Coastguard Worker }
429*d9f75844SAndroid Build Coastguard Worker }
430*d9f75844SAndroid Build Coastguard Worker
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)431*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
432*d9f75844SAndroid Build Coastguard Worker int* key_len,
433*d9f75844SAndroid Build Coastguard Worker int* tag_len) {
434*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
435*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
436*d9f75844SAndroid Build Coastguard Worker return false;
437*d9f75844SAndroid Build Coastguard Worker }
438*d9f75844SAndroid Build Coastguard Worker
439*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
440*d9f75844SAndroid Build Coastguard Worker return send_session_->GetRtpAuthParams(key, key_len, tag_len);
441*d9f75844SAndroid Build Coastguard Worker }
442*d9f75844SAndroid Build Coastguard Worker
GetSrtpOverhead(int * srtp_overhead) const443*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
444*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
445*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
446*d9f75844SAndroid Build Coastguard Worker return false;
447*d9f75844SAndroid Build Coastguard Worker }
448*d9f75844SAndroid Build Coastguard Worker
449*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
450*d9f75844SAndroid Build Coastguard Worker *srtp_overhead = send_session_->GetSrtpOverhead();
451*d9f75844SAndroid Build Coastguard Worker return true;
452*d9f75844SAndroid Build Coastguard Worker }
453*d9f75844SAndroid Build Coastguard Worker
EnableExternalAuth()454*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::EnableExternalAuth() {
455*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!IsSrtpActive());
456*d9f75844SAndroid Build Coastguard Worker external_auth_enabled_ = true;
457*d9f75844SAndroid Build Coastguard Worker }
458*d9f75844SAndroid Build Coastguard Worker
IsExternalAuthEnabled() const459*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsExternalAuthEnabled() const {
460*d9f75844SAndroid Build Coastguard Worker return external_auth_enabled_;
461*d9f75844SAndroid Build Coastguard Worker }
462*d9f75844SAndroid Build Coastguard Worker
IsExternalAuthActive() const463*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsExternalAuthActive() const {
464*d9f75844SAndroid Build Coastguard Worker if (!IsSrtpActive()) {
465*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
466*d9f75844SAndroid Build Coastguard Worker << "Failed to check IsExternalAuthActive: SRTP not active";
467*d9f75844SAndroid Build Coastguard Worker return false;
468*d9f75844SAndroid Build Coastguard Worker }
469*d9f75844SAndroid Build Coastguard Worker
470*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(send_session_);
471*d9f75844SAndroid Build Coastguard Worker return send_session_->IsExternalAuthActive();
472*d9f75844SAndroid Build Coastguard Worker }
473*d9f75844SAndroid Build Coastguard Worker
MaybeSetKeyParams()474*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::MaybeSetKeyParams() {
475*d9f75844SAndroid Build Coastguard Worker if (!send_cipher_suite_ || !recv_cipher_suite_) {
476*d9f75844SAndroid Build Coastguard Worker return true;
477*d9f75844SAndroid Build Coastguard Worker }
478*d9f75844SAndroid Build Coastguard Worker
479*d9f75844SAndroid Build Coastguard Worker return SetRtpParams(*send_cipher_suite_, send_key_.data(),
480*d9f75844SAndroid Build Coastguard Worker static_cast<int>(send_key_.size()), std::vector<int>(),
481*d9f75844SAndroid Build Coastguard Worker *recv_cipher_suite_, recv_key_.data(),
482*d9f75844SAndroid Build Coastguard Worker static_cast<int>(recv_key_.size()), std::vector<int>());
483*d9f75844SAndroid Build Coastguard Worker }
484*d9f75844SAndroid Build Coastguard Worker
ParseKeyParams(const std::string & key_params,uint8_t * key,size_t len)485*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ParseKeyParams(const std::string& key_params,
486*d9f75844SAndroid Build Coastguard Worker uint8_t* key,
487*d9f75844SAndroid Build Coastguard Worker size_t len) {
488*d9f75844SAndroid Build Coastguard Worker // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
489*d9f75844SAndroid Build Coastguard Worker
490*d9f75844SAndroid Build Coastguard Worker // Fail if key-method is wrong.
491*d9f75844SAndroid Build Coastguard Worker if (!absl::StartsWith(key_params, "inline:")) {
492*d9f75844SAndroid Build Coastguard Worker return false;
493*d9f75844SAndroid Build Coastguard Worker }
494*d9f75844SAndroid Build Coastguard Worker
495*d9f75844SAndroid Build Coastguard Worker // Fail if base64 decode fails, or the key is the wrong size.
496*d9f75844SAndroid Build Coastguard Worker std::string key_b64(key_params.substr(7)), key_str;
497*d9f75844SAndroid Build Coastguard Worker if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
498*d9f75844SAndroid Build Coastguard Worker nullptr) ||
499*d9f75844SAndroid Build Coastguard Worker key_str.size() != len) {
500*d9f75844SAndroid Build Coastguard Worker return false;
501*d9f75844SAndroid Build Coastguard Worker }
502*d9f75844SAndroid Build Coastguard Worker
503*d9f75844SAndroid Build Coastguard Worker memcpy(key, key_str.c_str(), len);
504*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing
505*d9f75844SAndroid Build Coastguard Worker // sensitive data.
506*d9f75844SAndroid Build Coastguard Worker rtc::ExplicitZeroMemory(&key_str[0], key_str.size());
507*d9f75844SAndroid Build Coastguard Worker return true;
508*d9f75844SAndroid Build Coastguard Worker }
509*d9f75844SAndroid Build Coastguard Worker
MaybeUpdateWritableState()510*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::MaybeUpdateWritableState() {
511*d9f75844SAndroid Build Coastguard Worker bool writable = IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/false);
512*d9f75844SAndroid Build Coastguard Worker // Only fire the signal if the writable state changes.
513*d9f75844SAndroid Build Coastguard Worker if (writable_ != writable) {
514*d9f75844SAndroid Build Coastguard Worker writable_ = writable;
515*d9f75844SAndroid Build Coastguard Worker SignalWritableState(writable_);
516*d9f75844SAndroid Build Coastguard Worker }
517*d9f75844SAndroid Build Coastguard Worker }
518*d9f75844SAndroid Build Coastguard Worker
519*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
520