• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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