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
62extern "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
69namespace cricket {
70
71const std::string& CS_DEFAULT = CS_AES_CM_128_HMAC_SHA1_80;
72const std::string CS_AES_CM_128_HMAC_SHA1_80 = "AES_CM_128_HMAC_SHA1_80";
73const std::string CS_AES_CM_128_HMAC_SHA1_32 = "AES_CM_128_HMAC_SHA1_32";
74const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3;
75
76SrtpFilter::SrtpFilter() : state_(ST_INIT) {
77}
78
79SrtpFilter::~SrtpFilter() {
80}
81
82bool SrtpFilter::IsActive() const {
83  return (state_ == ST_ACTIVE);
84}
85
86bool 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
97bool 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
123bool 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
131bool 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
139bool 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
147bool 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
156bool 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
163bool 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
190bool 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
215bool SrtpFilter::ResetParams() {
216  offer_params_.clear();
217  state_ = ST_INIT;
218  LOG(LS_INFO) << "SRTP reset to init state";
219  return true;
220}
221
222bool 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
248bool SrtpSession::inited_ = false;
249std::list<SrtpSession*> SrtpSession::sessions_;
250
251SrtpSession::SrtpSession()
252    : session_(NULL), rtp_auth_tag_len_(0), rtcp_auth_tag_len_(0) {
253  sessions_.push_back(this);
254}
255
256SrtpSession::~SrtpSession() {
257  sessions_.erase(std::find(sessions_.begin(), sessions_.end(), this));
258  if (session_) {
259    srtp_dealloc(session_);
260  }
261}
262
263bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
264  return SetKey(ssrc_any_outbound, cs, key, len);
265}
266
267bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
268  return SetKey(ssrc_any_inbound, cs, key, len);
269}
270
271bool 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
293bool 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
315bool 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
330bool 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
345bool 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
396bool 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
420void 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
440void 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
452namespace {
453bool SrtpNotAvailable(const char *func) {
454  LOG(LS_ERROR) << func << ": SRTP is not available on your system.";
455  return false;
456}
457}  // anonymous namespace
458
459SrtpSession::SrtpSession() {
460  LOG(WARNING) << "SRTP implementation is missing.";
461}
462
463SrtpSession::~SrtpSession() {
464}
465
466bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
467  return SrtpNotAvailable(__FUNCTION__);
468}
469
470bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
471  return SrtpNotAvailable(__FUNCTION__);
472}
473
474bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len,
475                             int* out_len) {
476  return SrtpNotAvailable(__FUNCTION__);
477}
478
479bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len,
480                              int* out_len) {
481  return SrtpNotAvailable(__FUNCTION__);
482}
483
484bool SrtpSession::UnprotectRtp(void* data, int in_len, int* out_len) {
485  return SrtpNotAvailable(__FUNCTION__);
486}
487
488bool SrtpSession::UnprotectRtcp(void* data, int in_len, int* out_len) {
489  return SrtpNotAvailable(__FUNCTION__);
490}
491
492#endif  // HAVE_SRTP
493}  // namespace cricket
494