1 /*
2 * libjingle
3 * Copyright 2009, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 // talk's config.h, generated from mac_config_dot_h for OSX, conflicts with the
29 // one included by the libsrtp headers. Don't use it. Instead, we keep HAVE_SRTP
30 // and LOGGING defined in config.h.
31 #undef HAVE_CONFIG_H
32
33 #ifdef OSX
34 // TODO: For the XCode build, we force SRTP (b/2500074)
35 #ifndef HAVE_SRTP
36 #define HAVE_SRTP 1
37 #endif // HAVE_SRTP
38 // If LOGGING is not defined, define it to 1 (b/3245816)
39 #ifndef LOGGING
40 #define LOGGING 1
41 #endif // HAVE_SRTP
42 #endif
43
44 #include "talk/session/phone/srtpfilter.h"
45
46 #include <algorithm>
47 #include <cstring>
48
49 #include "talk/base/base64.h"
50 #include "talk/base/logging.h"
51
52 // Enable this line to turn on SRTP debugging
53 // #define SRTP_DEBUG
54
55 #ifdef HAVE_SRTP
56 #ifdef SRTP_RELATIVE_PATH
57 #include "srtp.h" // NOLINT
58 #else
59 #include "third_party/libsrtp/include/srtp.h"
60 #endif // SRTP_RELATIVE_PATH
61 #ifdef _DEBUG
62 extern "C" debug_module_t mod_srtp;
63 #endif
64 #else
65 // SrtpFilter needs that constant.
66 #define SRTP_MASTER_KEY_LEN 30
67 #endif // HAVE_SRTP
68
69 namespace cricket {
70
71 const std::string& CS_DEFAULT = CS_AES_CM_128_HMAC_SHA1_80;
72 const std::string CS_AES_CM_128_HMAC_SHA1_80 = "AES_CM_128_HMAC_SHA1_80";
73 const std::string CS_AES_CM_128_HMAC_SHA1_32 = "AES_CM_128_HMAC_SHA1_32";
74 const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3;
75
SrtpFilter()76 SrtpFilter::SrtpFilter() : state_(ST_INIT) {
77 }
78
~SrtpFilter()79 SrtpFilter::~SrtpFilter() {
80 }
81
IsActive() const82 bool SrtpFilter::IsActive() const {
83 return (state_ == ST_ACTIVE);
84 }
85
SetOffer(const std::vector<CryptoParams> & offer_params,ContentSource source)86 bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params,
87 ContentSource source) {
88 bool ret = false;
89 if (state_ == ST_INIT) {
90 ret = StoreParams(offer_params, source);
91 } else {
92 LOG(LS_ERROR) << "Invalid state for SRTP offer";
93 }
94 return ret;
95 }
96
SetAnswer(const std::vector<CryptoParams> & answer_params,ContentSource source)97 bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params,
98 ContentSource source) {
99 bool ret = false;
100 if ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
101 (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL)) {
102 // If the answer requests crypto, finalize the parameters and apply them.
103 // Otherwise, complete the negotiation of a unencrypted session.
104 if (!answer_params.empty()) {
105 CryptoParams selected_params;
106 ret = NegotiateParams(answer_params, &selected_params);
107 if (ret) {
108 if (state_ == ST_SENTOFFER) {
109 ret = ApplyParams(selected_params, answer_params[0]);
110 } else { // ST_RECEIVEDOFFER
111 ret = ApplyParams(answer_params[0], selected_params);
112 }
113 }
114 } else {
115 ret = ResetParams();
116 }
117 } else {
118 LOG(LS_ERROR) << "Invalid state for SRTP answer";
119 }
120 return ret;
121 }
122
ProtectRtp(void * p,int in_len,int max_len,int * out_len)123 bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
124 if (!IsActive()) {
125 LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
126 return false;
127 }
128 return send_session_.ProtectRtp(p, in_len, max_len, out_len);
129 }
130
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)131 bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
132 if (!IsActive()) {
133 LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
134 return false;
135 }
136 return send_session_.ProtectRtcp(p, in_len, max_len, out_len);
137 }
138
UnprotectRtp(void * p,int in_len,int * out_len)139 bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
140 if (!IsActive()) {
141 LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
142 return false;
143 }
144 return recv_session_.UnprotectRtp(p, in_len, out_len);
145 }
146
UnprotectRtcp(void * p,int in_len,int * out_len)147 bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
148 if (!IsActive()) {
149 LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
150 return false;
151 }
152 return recv_session_.UnprotectRtcp(p, in_len, out_len);
153 }
154
155
StoreParams(const std::vector<CryptoParams> & params,ContentSource source)156 bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
157 ContentSource source) {
158 offer_params_ = params;
159 state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
160 return true;
161 }
162
NegotiateParams(const std::vector<CryptoParams> & answer_params,CryptoParams * selected_params)163 bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params,
164 CryptoParams* selected_params) {
165 // We're processing an accept. We should have exactly one set of params,
166 // unless the offer didn't mention crypto, in which case we shouldn't be here.
167 bool ret = (answer_params.size() == 1U && !offer_params_.empty());
168 if (ret) {
169 // We should find a match between the answer params and the offered params.
170 std::vector<CryptoParams>::const_iterator it;
171 for (it = offer_params_.begin(); it != offer_params_.end(); ++it) {
172 if (answer_params[0].Matches(*it)) {
173 break;
174 }
175 }
176
177 if (it != offer_params_.end()) {
178 *selected_params = *it;
179 } else {
180 ret = false;
181 }
182 }
183
184 if (!ret) {
185 LOG(LS_WARNING) << "Invalid parameters in SRTP answer";
186 }
187 return ret;
188 }
189
ApplyParams(const CryptoParams & send_params,const CryptoParams & recv_params)190 bool SrtpFilter::ApplyParams(const CryptoParams& send_params,
191 const CryptoParams& recv_params) {
192 // TODO: Zero these buffers after use.
193 bool ret;
194 uint8 send_key[SRTP_MASTER_KEY_LEN], recv_key[SRTP_MASTER_KEY_LEN];
195 ret = (ParseKeyParams(send_params.key_params, send_key, sizeof(send_key)) &&
196 ParseKeyParams(recv_params.key_params, recv_key, sizeof(recv_key)));
197 if (ret) {
198 ret = (send_session_.SetSend(send_params.cipher_suite,
199 send_key, sizeof(send_key)) &&
200 recv_session_.SetRecv(recv_params.cipher_suite,
201 recv_key, sizeof(recv_key)));
202 }
203 if (ret) {
204 offer_params_.clear();
205 state_ = ST_ACTIVE;
206 LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
207 << " send cipher_suite " << send_params.cipher_suite
208 << " recv cipher_suite " << recv_params.cipher_suite;
209 } else {
210 LOG(LS_WARNING) << "Failed to apply negotiated SRTP parameters";
211 }
212 return ret;
213 }
214
ResetParams()215 bool SrtpFilter::ResetParams() {
216 offer_params_.clear();
217 state_ = ST_INIT;
218 LOG(LS_INFO) << "SRTP reset to init state";
219 return true;
220 }
221
ParseKeyParams(const std::string & key_params,uint8 * key,int len)222 bool SrtpFilter::ParseKeyParams(const std::string& key_params,
223 uint8* key, int len) {
224 // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
225
226 // Fail if key-method is wrong.
227 if (key_params.find("inline:") != 0) {
228 return false;
229 }
230
231 // Fail if base64 decode fails, or the key is the wrong size.
232 std::string key_b64(key_params.substr(7)), key_str;
233 if (!talk_base::Base64::Decode(key_b64, talk_base::Base64::DO_STRICT,
234 &key_str, NULL) ||
235 static_cast<int>(key_str.size()) != len) {
236 return false;
237 }
238
239 memcpy(key, key_str.c_str(), len);
240 return true;
241 }
242
243 ///////////////////////////////////////////////////////////////////////////////
244 // SrtpSession
245
246 #ifdef HAVE_SRTP
247
248 bool SrtpSession::inited_ = false;
249 std::list<SrtpSession*> SrtpSession::sessions_;
250
SrtpSession()251 SrtpSession::SrtpSession()
252 : session_(NULL), rtp_auth_tag_len_(0), rtcp_auth_tag_len_(0) {
253 sessions_.push_back(this);
254 }
255
~SrtpSession()256 SrtpSession::~SrtpSession() {
257 sessions_.erase(std::find(sessions_.begin(), sessions_.end(), this));
258 if (session_) {
259 srtp_dealloc(session_);
260 }
261 }
262
SetSend(const std::string & cs,const uint8 * key,int len)263 bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
264 return SetKey(ssrc_any_outbound, cs, key, len);
265 }
266
SetRecv(const std::string & cs,const uint8 * key,int len)267 bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
268 return SetKey(ssrc_any_inbound, cs, key, len);
269 }
270
ProtectRtp(void * p,int in_len,int max_len,int * out_len)271 bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
272 if (!session_) {
273 LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
274 return false;
275 }
276
277 int need_len = in_len + rtp_auth_tag_len_; // NOLINT
278 if (max_len < need_len) {
279 LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
280 << max_len << " is less than the needed " << need_len;
281 return false;
282 }
283
284 *out_len = in_len;
285 int err = srtp_protect(session_, p, out_len);
286 if (err != err_status_ok) {
287 LOG(LS_WARNING) << "Failed to protect SRTP packet, err=" << err;
288 return false;
289 }
290 return true;
291 }
292
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)293 bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
294 if (!session_) {
295 LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
296 return false;
297 }
298
299 int need_len = in_len + sizeof(uint32) + rtcp_auth_tag_len_; // NOLINT
300 if (max_len < need_len) {
301 LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
302 << max_len << " is less than the needed " << need_len;
303 return false;
304 }
305
306 *out_len = in_len;
307 int err = srtp_protect_rtcp(session_, p, out_len);
308 if (err != err_status_ok) {
309 LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err;
310 return false;
311 }
312 return true;
313 }
314
UnprotectRtp(void * p,int in_len,int * out_len)315 bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
316 if (!session_) {
317 LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
318 return false;
319 }
320
321 *out_len = in_len;
322 int err = srtp_unprotect(session_, p, out_len);
323 if (err != err_status_ok) {
324 LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err;
325 return false;
326 }
327 return true;
328 }
329
UnprotectRtcp(void * p,int in_len,int * out_len)330 bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
331 if (!session_) {
332 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
333 return false;
334 }
335
336 *out_len = in_len;
337 int err = srtp_unprotect_rtcp(session_, p, out_len);
338 if (err != err_status_ok) {
339 LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
340 return false;
341 }
342 return true;
343 }
344
SetKey(int type,const std::string & cs,const uint8 * key,int len)345 bool SrtpSession::SetKey(int type, const std::string& cs,
346 const uint8* key, int len) {
347 if (session_) {
348 LOG(LS_ERROR) << "Failed to create SRTP session: "
349 << "SRTP session already created";
350 return false;
351 }
352
353 if (!Init()) {
354 return false;
355 }
356
357 srtp_policy_t policy;
358 memset(&policy, 0, sizeof(policy));
359
360 if (cs == CS_AES_CM_128_HMAC_SHA1_80) {
361 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
362 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
363 } else if (cs == CS_AES_CM_128_HMAC_SHA1_32) {
364 crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32,
365 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80
366 } else {
367 LOG(LS_WARNING) << "Failed to create SRTP session: unsupported"
368 << " cipher_suite " << cs.c_str();
369 return false;
370 }
371
372 if (!key || len != SRTP_MASTER_KEY_LEN) {
373 LOG(LS_WARNING) << "Failed to create SRTP session: invalid key";
374 return false;
375 }
376
377 policy.ssrc.type = static_cast<ssrc_type_t>(type);
378 policy.ssrc.value = 0;
379 policy.key = const_cast<uint8*>(key);
380 // TODO parse window size from WSH session-param
381 policy.window_size = 1024;
382 policy.allow_repeat_tx = 1;
383 policy.next = NULL;
384
385 int err = srtp_create(&session_, &policy);
386 if (err != err_status_ok) {
387 LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
388 return false;
389 }
390
391 rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
392 rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
393 return true;
394 }
395
Init()396 bool SrtpSession::Init() {
397 if (!inited_) {
398 int err;
399 #ifdef DEBUG_SRTP
400 debug_on(mod_srtp);
401 #endif
402 err = srtp_init();
403 if (err != err_status_ok) {
404 LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
405 return false;
406 }
407
408 err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
409 if (err != err_status_ok) {
410 LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
411 return false;
412 }
413
414 inited_ = true;
415 }
416
417 return true;
418 }
419
HandleEvent(const srtp_event_data_t * ev)420 void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
421 switch (ev->event) {
422 case event_ssrc_collision:
423 LOG(LS_INFO) << "SRTP event: SSRC collision";
424 break;
425 case event_key_soft_limit:
426 LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
427 break;
428 case event_key_hard_limit:
429 LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
430 break;
431 case event_packet_index_limit:
432 LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)";
433 break;
434 default:
435 LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
436 break;
437 }
438 }
439
HandleEventThunk(srtp_event_data_t * ev)440 void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
441 for (std::list<SrtpSession*>::iterator it = sessions_.begin();
442 it != sessions_.end(); ++it) {
443 if ((*it)->session_ == ev->session) {
444 (*it)->HandleEvent(ev);
445 break;
446 }
447 }
448 }
449
450 #else // !HAVE_SRTP
451
452 namespace {
SrtpNotAvailable(const char * func)453 bool SrtpNotAvailable(const char *func) {
454 LOG(LS_ERROR) << func << ": SRTP is not available on your system.";
455 return false;
456 }
457 } // anonymous namespace
458
SrtpSession()459 SrtpSession::SrtpSession() {
460 LOG(WARNING) << "SRTP implementation is missing.";
461 }
462
~SrtpSession()463 SrtpSession::~SrtpSession() {
464 }
465
SetSend(const std::string & cs,const uint8 * key,int len)466 bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
467 return SrtpNotAvailable(__FUNCTION__);
468 }
469
SetRecv(const std::string & cs,const uint8 * key,int len)470 bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
471 return SrtpNotAvailable(__FUNCTION__);
472 }
473
ProtectRtp(void * data,int in_len,int max_len,int * out_len)474 bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len,
475 int* out_len) {
476 return SrtpNotAvailable(__FUNCTION__);
477 }
478
ProtectRtcp(void * data,int in_len,int max_len,int * out_len)479 bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len,
480 int* out_len) {
481 return SrtpNotAvailable(__FUNCTION__);
482 }
483
UnprotectRtp(void * data,int in_len,int * out_len)484 bool SrtpSession::UnprotectRtp(void* data, int in_len, int* out_len) {
485 return SrtpNotAvailable(__FUNCTION__);
486 }
487
UnprotectRtcp(void * data,int in_len,int * out_len)488 bool SrtpSession::UnprotectRtcp(void* data, int in_len, int* out_len) {
489 return SrtpNotAvailable(__FUNCTION__);
490 }
491
492 #endif // HAVE_SRTP
493 } // namespace cricket
494