Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(524)

Side by Side Diff: webrtc/pc/srtpsession.cc

Issue 2976443002: Move SrtpSession and tests to their own files. (Closed)
Patch Set: Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/pc/srtpsession.h ('k') | webrtc/pc/srtpsession_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "webrtc/pc/srtpsession.h"
12
13 #include "third_party/libsrtp/include/srtp.h"
14 #include "third_party/libsrtp/include/srtp_priv.h"
15 #include "webrtc/media/base/rtputils.h"
16 #include "webrtc/pc/externalhmac.h"
17 #include "webrtc/rtc_base/logging.h"
18 #include "webrtc/rtc_base/sslstreamadapter.h"
19
20 namespace cricket {
21
22 bool SrtpSession::inited_ = false;
23
24 // This lock protects SrtpSession::inited_.
25 rtc::GlobalLockPod SrtpSession::lock_;
26
27 SrtpSession::SrtpSession() {}
28
29 SrtpSession::~SrtpSession() {
30 if (session_) {
31 srtp_set_user_data(session_, nullptr);
32 srtp_dealloc(session_);
33 }
34 }
35
36 bool SrtpSession::SetSend(int cs, const uint8_t* key, size_t len) {
37 return SetKey(ssrc_any_outbound, cs, key, len);
38 }
39
40 bool SrtpSession::UpdateSend(int cs, const uint8_t* key, size_t len) {
41 return UpdateKey(ssrc_any_outbound, cs, key, len);
42 }
43
44 bool SrtpSession::SetRecv(int cs, const uint8_t* key, size_t len) {
45 return SetKey(ssrc_any_inbound, cs, key, len);
46 }
47
48 bool SrtpSession::UpdateRecv(int cs, const uint8_t* key, size_t len) {
49 return UpdateKey(ssrc_any_inbound, cs, key, len);
50 }
51
52 bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
53 RTC_DCHECK(thread_checker_.CalledOnValidThread());
54 if (!session_) {
55 LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
56 return false;
57 }
58
59 int need_len = in_len + rtp_auth_tag_len_; // NOLINT
60 if (max_len < need_len) {
61 LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
62 << max_len << " is less than the needed " << need_len;
63 return false;
64 }
65
66 *out_len = in_len;
67 int err = srtp_protect(session_, p, out_len);
68 int seq_num;
69 GetRtpSeqNum(p, in_len, &seq_num);
70 if (err != srtp_err_status_ok) {
71 LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum=" << seq_num
72 << ", err=" << err
73 << ", last seqnum=" << last_send_seq_num_;
74 return false;
75 }
76 last_send_seq_num_ = seq_num;
77 return true;
78 }
79
80 bool SrtpSession::ProtectRtp(void* p,
81 int in_len,
82 int max_len,
83 int* out_len,
84 int64_t* index) {
85 if (!ProtectRtp(p, in_len, max_len, out_len)) {
86 return false;
87 }
88 return (index) ? GetSendStreamPacketIndex(p, in_len, index) : true;
89 }
90
91 bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
92 RTC_DCHECK(thread_checker_.CalledOnValidThread());
93 if (!session_) {
94 LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
95 return false;
96 }
97
98 int need_len = in_len + sizeof(uint32_t) + rtcp_auth_tag_len_; // NOLINT
99 if (max_len < need_len) {
100 LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
101 << max_len << " is less than the needed " << need_len;
102 return false;
103 }
104
105 *out_len = in_len;
106 int err = srtp_protect_rtcp(session_, p, out_len);
107 if (err != srtp_err_status_ok) {
108 LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err;
109 return false;
110 }
111 return true;
112 }
113
114 bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
115 RTC_DCHECK(thread_checker_.CalledOnValidThread());
116 if (!session_) {
117 LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
118 return false;
119 }
120
121 *out_len = in_len;
122 int err = srtp_unprotect(session_, p, out_len);
123 if (err != srtp_err_status_ok) {
124 LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err;
125 return false;
126 }
127 return true;
128 }
129
130 bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
131 RTC_DCHECK(thread_checker_.CalledOnValidThread());
132 if (!session_) {
133 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
134 return false;
135 }
136
137 *out_len = in_len;
138 int err = srtp_unprotect_rtcp(session_, p, out_len);
139 if (err != srtp_err_status_ok) {
140 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
141 return false;
142 }
143 return true;
144 }
145
146 bool SrtpSession::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) {
147 RTC_DCHECK(thread_checker_.CalledOnValidThread());
148 RTC_DCHECK(IsExternalAuthActive());
149 if (!IsExternalAuthActive()) {
150 return false;
151 }
152
153 ExternalHmacContext* external_hmac = nullptr;
154 // stream_template will be the reference context for other streams.
155 // Let's use it for getting the keys.
156 srtp_stream_ctx_t* srtp_context = session_->stream_template;
157 #if defined(SRTP_MAX_MKI_LEN)
158 // libsrtp 2.1.0
159 if (srtp_context && srtp_context->session_keys &&
160 srtp_context->session_keys->rtp_auth) {
161 external_hmac = reinterpret_cast<ExternalHmacContext*>(
162 srtp_context->session_keys->rtp_auth->state);
163 }
164 #else
165 // libsrtp 2.0.0
166 // TODO(jbauch): Remove after switching to libsrtp 2.1.0
167 if (srtp_context && srtp_context->rtp_auth) {
168 external_hmac =
169 reinterpret_cast<ExternalHmacContext*>(srtp_context->rtp_auth->state);
170 }
171 #endif
172
173 if (!external_hmac) {
174 LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!.";
175 return false;
176 }
177
178 *key = external_hmac->key;
179 *key_len = external_hmac->key_length;
180 *tag_len = rtp_auth_tag_len_;
181 return true;
182 }
183
184 int SrtpSession::GetSrtpOverhead() const {
185 return rtp_auth_tag_len_;
186 }
187
188 void SrtpSession::EnableExternalAuth() {
189 RTC_DCHECK(!session_);
190 external_auth_enabled_ = true;
191 }
192
193 bool SrtpSession::IsExternalAuthEnabled() const {
194 return external_auth_enabled_;
195 }
196
197 bool SrtpSession::IsExternalAuthActive() const {
198 return external_auth_active_;
199 }
200
201 bool SrtpSession::GetSendStreamPacketIndex(void* p,
202 int in_len,
203 int64_t* index) {
204 RTC_DCHECK(thread_checker_.CalledOnValidThread());
205 srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p);
206 srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc);
207 if (!stream) {
208 return false;
209 }
210
211 // Shift packet index, put into network byte order
212 *index = static_cast<int64_t>(rtc::NetworkToHost64(
213 srtp_rdbx_get_packet_index(&stream->rtp_rdbx) << 16));
214 return true;
215 }
216
217 bool SrtpSession::DoSetKey(int type, int cs, const uint8_t* key, size_t len) {
218 RTC_DCHECK(thread_checker_.CalledOnValidThread());
219
220 srtp_policy_t policy;
221 memset(&policy, 0, sizeof(policy));
222 if (cs == rtc::SRTP_AES128_CM_SHA1_80) {
223 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
224 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
225 } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) {
226 // RTP HMAC is shortened to 32 bits, but RTCP remains 80 bits.
227 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
228 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
229 } else if (cs == rtc::SRTP_AEAD_AES_128_GCM) {
230 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
231 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
232 } else if (cs == rtc::SRTP_AEAD_AES_256_GCM) {
233 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
234 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
235 } else {
236 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
237 << " SRTP session: unsupported cipher_suite " << cs;
238 return false;
239 }
240
241 int expected_key_len;
242 int expected_salt_len;
243 if (!rtc::GetSrtpKeyAndSaltLengths(cs, &expected_key_len,
244 &expected_salt_len)) {
245 // This should never happen.
246 LOG(LS_WARNING)
247 << "Failed to " << (session_ ? "update" : "create")
248 << " SRTP session: unsupported cipher_suite without length information"
249 << cs;
250 return false;
251 }
252
253 if (!key ||
254 len != static_cast<size_t>(expected_key_len + expected_salt_len)) {
255 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
256 << " SRTP session: invalid key";
257 return false;
258 }
259
260 policy.ssrc.type = static_cast<srtp_ssrc_type_t>(type);
261 policy.ssrc.value = 0;
262 policy.key = const_cast<uint8_t*>(key);
263 // TODO(astor) parse window size from WSH session-param
264 policy.window_size = 1024;
265 policy.allow_repeat_tx = 1;
266 // If external authentication option is enabled, supply custom auth module
267 // id EXTERNAL_HMAC_SHA1 in the policy structure.
268 // We want to set this option only for rtp packets.
269 // By default policy structure is initialized to HMAC_SHA1.
270 // Enable external HMAC authentication only for outgoing streams and only
271 // for cipher suites that support it (i.e. only non-GCM cipher suites).
272 if (type == ssrc_any_outbound && IsExternalAuthEnabled() &&
273 !rtc::IsGcmCryptoSuite(cs)) {
274 policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
275 }
276 if (!encrypted_header_extension_ids_.empty()) {
277 policy.enc_xtn_hdr = const_cast<int*>(&encrypted_header_extension_ids_[0]);
278 policy.enc_xtn_hdr_count =
279 static_cast<int>(encrypted_header_extension_ids_.size());
280 }
281 policy.next = nullptr;
282
283 if (!session_) {
284 int err = srtp_create(&session_, &policy);
285 if (err != srtp_err_status_ok) {
286 session_ = nullptr;
287 LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
288 return false;
289 }
290 srtp_set_user_data(session_, this);
291 } else {
292 int err = srtp_update(session_, &policy);
293 if (err != srtp_err_status_ok) {
294 LOG(LS_ERROR) << "Failed to update SRTP session, err=" << err;
295 return false;
296 }
297 }
298
299 rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
300 rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
301 external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1);
302 return true;
303 }
304
305 bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) {
306 RTC_DCHECK(thread_checker_.CalledOnValidThread());
307 if (session_) {
308 LOG(LS_ERROR) << "Failed to create SRTP session: "
309 << "SRTP session already created";
310 return false;
311 }
312
313 if (!Init()) {
314 return false;
315 }
316
317 return DoSetKey(type, cs, key, len);
318 }
319
320 bool SrtpSession::UpdateKey(int type, int cs, const uint8_t* key, size_t len) {
321 RTC_DCHECK(thread_checker_.CalledOnValidThread());
322 if (!session_) {
323 LOG(LS_ERROR) << "Failed to update non-existing SRTP session";
324 return false;
325 }
326
327 return DoSetKey(type, cs, key, len);
328 }
329
330 void SrtpSession::SetEncryptedHeaderExtensionIds(
331 const std::vector<int>& encrypted_header_extension_ids) {
332 RTC_DCHECK(thread_checker_.CalledOnValidThread());
333 encrypted_header_extension_ids_ = encrypted_header_extension_ids;
334 }
335
336 bool SrtpSession::Init() {
337 rtc::GlobalLockScope ls(&lock_);
338
339 if (!inited_) {
340 int err;
341 err = srtp_init();
342 if (err != srtp_err_status_ok) {
343 LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
344 return false;
345 }
346
347 err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
348 if (err != srtp_err_status_ok) {
349 LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
350 return false;
351 }
352
353 err = external_crypto_init();
354 if (err != srtp_err_status_ok) {
355 LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err;
356 return false;
357 }
358 inited_ = true;
359 }
360
361 return true;
362 }
363
364 void SrtpSession::Terminate() {
365 rtc::GlobalLockScope ls(&lock_);
366
367 if (inited_) {
368 int err = srtp_shutdown();
369 if (err) {
370 LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
371 return;
372 }
373 inited_ = false;
374 }
375 }
376
377 void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
378 RTC_DCHECK(thread_checker_.CalledOnValidThread());
379 switch (ev->event) {
380 case event_ssrc_collision:
381 LOG(LS_INFO) << "SRTP event: SSRC collision";
382 break;
383 case event_key_soft_limit:
384 LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
385 break;
386 case event_key_hard_limit:
387 LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
388 break;
389 case event_packet_index_limit:
390 LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)";
391 break;
392 default:
393 LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
394 break;
395 }
396 }
397
398 void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
399 // Callback will be executed from same thread that calls the "srtp_protect"
400 // and "srtp_unprotect" functions.
401 SrtpSession* session =
402 static_cast<SrtpSession*>(srtp_get_user_data(ev->session));
403 if (session) {
404 session->HandleEvent(ev);
405 }
406 }
407
408 } // namespace cricket
OLDNEW
« no previous file with comments | « webrtc/pc/srtpsession.h ('k') | webrtc/pc/srtpsession_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698