blob: ba49b166ae5b6536c84f7effb7fdf95d90ca64d9 [file] [log] [blame]
zstein4dde3df2017-07-07 14:26:25 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/srtpsession.h"
zstein4dde3df2017-07-07 14:26:25 -070012
13#include "third_party/libsrtp/include/srtp.h"
14#include "third_party/libsrtp/include/srtp_priv.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "media/base/rtputils.h"
16#include "pc/externalhmac.h"
17#include "rtc_base/logging.h"
18#include "rtc_base/sslstreamadapter.h"
zstein4dde3df2017-07-07 14:26:25 -070019
20namespace cricket {
21
22bool SrtpSession::inited_ = false;
23
24// This lock protects SrtpSession::inited_.
25rtc::GlobalLockPod SrtpSession::lock_;
26
27SrtpSession::SrtpSession() {}
28
29SrtpSession::~SrtpSession() {
30 if (session_) {
31 srtp_set_user_data(session_, nullptr);
32 srtp_dealloc(session_);
33 }
34}
35
36bool SrtpSession::SetSend(int cs, const uint8_t* key, size_t len) {
37 return SetKey(ssrc_any_outbound, cs, key, len);
38}
39
40bool SrtpSession::UpdateSend(int cs, const uint8_t* key, size_t len) {
41 return UpdateKey(ssrc_any_outbound, cs, key, len);
42}
43
44bool SrtpSession::SetRecv(int cs, const uint8_t* key, size_t len) {
45 return SetKey(ssrc_any_inbound, cs, key, len);
46}
47
48bool SrtpSession::UpdateRecv(int cs, const uint8_t* key, size_t len) {
49 return UpdateKey(ssrc_any_inbound, cs, key, len);
50}
51
52bool 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
80bool 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
91bool 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
114bool 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
130bool 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
146bool 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;
zstein4dde3df2017-07-07 14:26:25 -0700157 if (srtp_context && srtp_context->session_keys &&
158 srtp_context->session_keys->rtp_auth) {
159 external_hmac = reinterpret_cast<ExternalHmacContext*>(
160 srtp_context->session_keys->rtp_auth->state);
161 }
zstein4dde3df2017-07-07 14:26:25 -0700162
163 if (!external_hmac) {
164 LOG(LS_ERROR) << "Failed to get auth keys from libsrtp!.";
165 return false;
166 }
167
168 *key = external_hmac->key;
169 *key_len = external_hmac->key_length;
170 *tag_len = rtp_auth_tag_len_;
171 return true;
172}
173
174int SrtpSession::GetSrtpOverhead() const {
175 return rtp_auth_tag_len_;
176}
177
178void SrtpSession::EnableExternalAuth() {
179 RTC_DCHECK(!session_);
180 external_auth_enabled_ = true;
181}
182
183bool SrtpSession::IsExternalAuthEnabled() const {
184 return external_auth_enabled_;
185}
186
187bool SrtpSession::IsExternalAuthActive() const {
188 return external_auth_active_;
189}
190
191bool SrtpSession::GetSendStreamPacketIndex(void* p,
192 int in_len,
193 int64_t* index) {
194 RTC_DCHECK(thread_checker_.CalledOnValidThread());
195 srtp_hdr_t* hdr = reinterpret_cast<srtp_hdr_t*>(p);
196 srtp_stream_ctx_t* stream = srtp_get_stream(session_, hdr->ssrc);
197 if (!stream) {
198 return false;
199 }
200
201 // Shift packet index, put into network byte order
202 *index = static_cast<int64_t>(rtc::NetworkToHost64(
203 srtp_rdbx_get_packet_index(&stream->rtp_rdbx) << 16));
204 return true;
205}
206
207bool SrtpSession::DoSetKey(int type, int cs, const uint8_t* key, size_t len) {
208 RTC_DCHECK(thread_checker_.CalledOnValidThread());
209
210 srtp_policy_t policy;
211 memset(&policy, 0, sizeof(policy));
212 if (cs == rtc::SRTP_AES128_CM_SHA1_80) {
213 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
214 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
215 } else if (cs == rtc::SRTP_AES128_CM_SHA1_32) {
216 // RTP HMAC is shortened to 32 bits, but RTCP remains 80 bits.
217 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
218 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
219 } else if (cs == rtc::SRTP_AEAD_AES_128_GCM) {
220 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
221 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
222 } else if (cs == rtc::SRTP_AEAD_AES_256_GCM) {
223 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
224 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
225 } else {
226 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
227 << " SRTP session: unsupported cipher_suite " << cs;
228 return false;
229 }
230
231 int expected_key_len;
232 int expected_salt_len;
233 if (!rtc::GetSrtpKeyAndSaltLengths(cs, &expected_key_len,
234 &expected_salt_len)) {
235 // This should never happen.
236 LOG(LS_WARNING)
237 << "Failed to " << (session_ ? "update" : "create")
238 << " SRTP session: unsupported cipher_suite without length information"
239 << cs;
240 return false;
241 }
242
243 if (!key ||
244 len != static_cast<size_t>(expected_key_len + expected_salt_len)) {
245 LOG(LS_WARNING) << "Failed to " << (session_ ? "update" : "create")
246 << " SRTP session: invalid key";
247 return false;
248 }
249
250 policy.ssrc.type = static_cast<srtp_ssrc_type_t>(type);
251 policy.ssrc.value = 0;
252 policy.key = const_cast<uint8_t*>(key);
253 // TODO(astor) parse window size from WSH session-param
254 policy.window_size = 1024;
255 policy.allow_repeat_tx = 1;
256 // If external authentication option is enabled, supply custom auth module
257 // id EXTERNAL_HMAC_SHA1 in the policy structure.
258 // We want to set this option only for rtp packets.
259 // By default policy structure is initialized to HMAC_SHA1.
260 // Enable external HMAC authentication only for outgoing streams and only
261 // for cipher suites that support it (i.e. only non-GCM cipher suites).
262 if (type == ssrc_any_outbound && IsExternalAuthEnabled() &&
263 !rtc::IsGcmCryptoSuite(cs)) {
264 policy.rtp.auth_type = EXTERNAL_HMAC_SHA1;
265 }
266 if (!encrypted_header_extension_ids_.empty()) {
267 policy.enc_xtn_hdr = const_cast<int*>(&encrypted_header_extension_ids_[0]);
268 policy.enc_xtn_hdr_count =
269 static_cast<int>(encrypted_header_extension_ids_.size());
270 }
271 policy.next = nullptr;
272
273 if (!session_) {
274 int err = srtp_create(&session_, &policy);
275 if (err != srtp_err_status_ok) {
276 session_ = nullptr;
277 LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
278 return false;
279 }
280 srtp_set_user_data(session_, this);
281 } else {
282 int err = srtp_update(session_, &policy);
283 if (err != srtp_err_status_ok) {
284 LOG(LS_ERROR) << "Failed to update SRTP session, err=" << err;
285 return false;
286 }
287 }
288
289 rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
290 rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
291 external_auth_active_ = (policy.rtp.auth_type == EXTERNAL_HMAC_SHA1);
292 return true;
293}
294
295bool SrtpSession::SetKey(int type, int cs, const uint8_t* key, size_t len) {
296 RTC_DCHECK(thread_checker_.CalledOnValidThread());
297 if (session_) {
298 LOG(LS_ERROR) << "Failed to create SRTP session: "
299 << "SRTP session already created";
300 return false;
301 }
302
303 if (!Init()) {
304 return false;
305 }
306
307 return DoSetKey(type, cs, key, len);
308}
309
310bool SrtpSession::UpdateKey(int type, int cs, const uint8_t* key, size_t len) {
311 RTC_DCHECK(thread_checker_.CalledOnValidThread());
312 if (!session_) {
313 LOG(LS_ERROR) << "Failed to update non-existing SRTP session";
314 return false;
315 }
316
317 return DoSetKey(type, cs, key, len);
318}
319
320void SrtpSession::SetEncryptedHeaderExtensionIds(
321 const std::vector<int>& encrypted_header_extension_ids) {
322 RTC_DCHECK(thread_checker_.CalledOnValidThread());
323 encrypted_header_extension_ids_ = encrypted_header_extension_ids;
324}
325
326bool SrtpSession::Init() {
327 rtc::GlobalLockScope ls(&lock_);
328
329 if (!inited_) {
330 int err;
331 err = srtp_init();
332 if (err != srtp_err_status_ok) {
333 LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
334 return false;
335 }
336
337 err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
338 if (err != srtp_err_status_ok) {
339 LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
340 return false;
341 }
342
343 err = external_crypto_init();
344 if (err != srtp_err_status_ok) {
345 LOG(LS_ERROR) << "Failed to initialize fake auth, err=" << err;
346 return false;
347 }
348 inited_ = true;
349 }
350
351 return true;
352}
353
354void SrtpSession::Terminate() {
355 rtc::GlobalLockScope ls(&lock_);
356
357 if (inited_) {
358 int err = srtp_shutdown();
359 if (err) {
360 LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
361 return;
362 }
363 inited_ = false;
364 }
365}
366
367void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
368 RTC_DCHECK(thread_checker_.CalledOnValidThread());
369 switch (ev->event) {
370 case event_ssrc_collision:
371 LOG(LS_INFO) << "SRTP event: SSRC collision";
372 break;
373 case event_key_soft_limit:
374 LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
375 break;
376 case event_key_hard_limit:
377 LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
378 break;
379 case event_packet_index_limit:
380 LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)";
381 break;
382 default:
383 LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
384 break;
385 }
386}
387
388void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
389 // Callback will be executed from same thread that calls the "srtp_protect"
390 // and "srtp_unprotect" functions.
391 SrtpSession* session =
392 static_cast<SrtpSession*>(srtp_get_user_data(ev->session));
393 if (session) {
394 session->HandleEvent(ev);
395 }
396}
397
398} // namespace cricket