Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/talk/session/media/srtpfilter.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 25.1 KB
Line 
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#undef HAVE_CONFIG_H
29
30#include "talk/session/media/srtpfilter.h"
31
32#include <algorithm>
33#include <cstring>
34
35#include "talk/base/base64.h"
36#include "talk/base/logging.h"
37#include "talk/base/stringencode.h"
38#include "talk/base/timeutils.h"
39#include "talk/media/base/rtputils.h"
40
41// Enable this line to turn on SRTP debugging
42// #define SRTP_DEBUG
43
44#ifdef HAVE_SRTP
45#ifdef SRTP_RELATIVE_PATH
46#include "srtp.h"  // NOLINT
47#else
48#include "third_party/libsrtp/include/srtp.h"
49#endif  // SRTP_RELATIVE_PATH
50#ifdef _DEBUG
51extern "C" debug_module_t mod_srtp;
52extern "C" debug_module_t mod_auth;
53extern "C" debug_module_t mod_cipher;
54extern "C" debug_module_t mod_stat;
55extern "C" debug_module_t mod_alloc;
56extern "C" debug_module_t mod_aes_icm;
57extern "C" debug_module_t mod_aes_hmac;
58#endif
59#else
60// SrtpFilter needs that constant.
61#define SRTP_MASTER_KEY_LEN 30
62#endif  // HAVE_SRTP
63
64namespace cricket {
65
66const char CS_AES_CM_128_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80";
67const char CS_AES_CM_128_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32";
68const int SRTP_MASTER_KEY_BASE64_LEN = SRTP_MASTER_KEY_LEN * 4 / 3;
69const int SRTP_MASTER_KEY_KEY_LEN = 16;
70const int SRTP_MASTER_KEY_SALT_LEN = 14;
71
72#ifndef HAVE_SRTP
73
74// This helper function is used on systems that don't (yet) have SRTP,
75// to log that the functions that require it won't do anything.
76namespace {
77bool SrtpNotAvailable(const char *func) {
78  LOG(LS_ERROR) << func << ": SRTP is not available on your system.";
79  return false;
80}
81}  // anonymous namespace
82
83#endif  // !HAVE_SRTP
84
85void EnableSrtpDebugging() {
86#ifdef HAVE_SRTP
87#ifdef _DEBUG
88  debug_on(mod_srtp);
89  debug_on(mod_auth);
90  debug_on(mod_cipher);
91  debug_on(mod_stat);
92  debug_on(mod_alloc);
93  debug_on(mod_aes_icm);
94  // debug_on(mod_aes_cbc);
95  // debug_on(mod_hmac);
96#endif
97#endif  // HAVE_SRTP
98}
99
100// NOTE: This is called from ChannelManager D'tor.
101void ShutdownSrtp() {
102#ifdef HAVE_SRTP
103  // If srtp_dealloc is not executed then this will clear all existing sessions.
104  // This should be called when application is shutting down.
105  SrtpSession::Terminate();
106#endif
107}
108
109SrtpFilter::SrtpFilter()
110    : state_(ST_INIT),
111      signal_silent_time_in_ms_(0) {
112}
113
114SrtpFilter::~SrtpFilter() {
115}
116
117bool SrtpFilter::IsActive() const {
118  return state_ >= ST_ACTIVE;
119}
120
121bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params,
122                          ContentSource source) {
123  if (!ExpectOffer(source)) {
124     LOG(LS_ERROR) << "Wrong state to update SRTP offer";
125     return false;
126  }
127  return StoreParams(offer_params, source);
128}
129
130bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params,
131                           ContentSource source) {
132  return DoSetAnswer(answer_params, source, true);
133}
134
135bool SrtpFilter::SetProvisionalAnswer(
136    const std::vector<CryptoParams>& answer_params,
137    ContentSource source) {
138  return DoSetAnswer(answer_params, source, false);
139}
140
141bool SrtpFilter::SetRtpParams(const std::string& send_cs,
142                              const uint8* send_key, int send_key_len,
143                              const std::string& recv_cs,
144                              const uint8* recv_key, int recv_key_len) {
145  if (state_ == ST_ACTIVE) {
146    LOG(LS_ERROR) << "Tried to set SRTP Params when filter already active";
147    return false;
148  }
149  CreateSrtpSessions();
150  if (!send_session_->SetSend(send_cs, send_key, send_key_len))
151    return false;
152
153  if (!recv_session_->SetRecv(recv_cs, recv_key, recv_key_len))
154    return false;
155
156  state_ = ST_ACTIVE;
157
158  LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
159               << " send cipher_suite " << send_cs
160               << " recv cipher_suite " << recv_cs;
161
162  return true;
163}
164
165// This function is provided separately because DTLS-SRTP behaves
166// differently in RTP/RTCP mux and non-mux modes.
167//
168// - In the non-muxed case, RTP and RTCP are keyed with different
169//   keys (from different DTLS handshakes), and so we need a new
170//   SrtpSession.
171// - In the muxed case, they are keyed with the same keys, so
172//   this function is not needed
173bool SrtpFilter::SetRtcpParams(const std::string& send_cs,
174                               const uint8* send_key, int send_key_len,
175                               const std::string& recv_cs,
176                               const uint8* recv_key, int recv_key_len) {
177  // This can only be called once, but can be safely called after
178  // SetRtpParams
179  if (send_rtcp_session_ || recv_rtcp_session_) {
180    LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
181    return false;
182  }
183
184  send_rtcp_session_.reset(new SrtpSession());
185  SignalSrtpError.repeat(send_rtcp_session_->SignalSrtpError);
186  send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_);
187  if (!send_rtcp_session_->SetRecv(send_cs, send_key, send_key_len))
188    return false;
189
190  recv_rtcp_session_.reset(new SrtpSession());
191  SignalSrtpError.repeat(recv_rtcp_session_->SignalSrtpError);
192  recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms_);
193  if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len))
194    return false;
195
196  LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
197               << " send cipher_suite " << send_cs
198               << " recv cipher_suite " << recv_cs;
199
200  return true;
201}
202
203bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
204  if (!IsActive()) {
205    LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
206    return false;
207  }
208  return send_session_->ProtectRtp(p, in_len, max_len, out_len);
209}
210
211bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
212  if (!IsActive()) {
213    LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
214    return false;
215  }
216  if (send_rtcp_session_) {
217    return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
218  } else {
219    return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
220  }
221}
222
223bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
224  if (!IsActive()) {
225    LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
226    return false;
227  }
228  return recv_session_->UnprotectRtp(p, in_len, out_len);
229}
230
231bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
232  if (!IsActive()) {
233    LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
234    return false;
235  }
236  if (recv_rtcp_session_) {
237    return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
238  } else {
239    return recv_session_->UnprotectRtcp(p, in_len, out_len);
240  }
241}
242
243void SrtpFilter::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
244  signal_silent_time_in_ms_ = signal_silent_time_in_ms;
245  if (state_ == ST_ACTIVE) {
246    send_session_->set_signal_silent_time(signal_silent_time_in_ms);
247    recv_session_->set_signal_silent_time(signal_silent_time_in_ms);
248    if (send_rtcp_session_)
249      send_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms);
250    if (recv_rtcp_session_)
251      recv_rtcp_session_->set_signal_silent_time(signal_silent_time_in_ms);
252  }
253}
254
255bool SrtpFilter::ExpectOffer(ContentSource source) {
256  return ((state_ == ST_INIT) ||
257          (state_ == ST_ACTIVE) ||
258          (state_  == ST_SENTOFFER && source == CS_LOCAL) ||
259          (state_  == ST_SENTUPDATEDOFFER && source == CS_LOCAL) ||
260          (state_ == ST_RECEIVEDOFFER && source == CS_REMOTE) ||
261          (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_REMOTE));
262}
263
264bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
265                             ContentSource source) {
266  offer_params_ = params;
267  if (state_ == ST_INIT) {
268    state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
269  } else {  // state >= ST_ACTIVE
270    state_ =
271        (source == CS_LOCAL) ? ST_SENTUPDATEDOFFER : ST_RECEIVEDUPDATEDOFFER;
272  }
273  return true;
274}
275
276bool SrtpFilter::ExpectAnswer(ContentSource source) {
277  return ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
278          (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL) ||
279          (state_ == ST_SENTUPDATEDOFFER && source == CS_REMOTE) ||
280          (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_LOCAL) ||
281          (state_ == ST_SENTPRANSWER_NO_CRYPTO && source == CS_LOCAL) ||
282          (state_ == ST_SENTPRANSWER && source == CS_LOCAL) ||
283          (state_ == ST_RECEIVEDPRANSWER_NO_CRYPTO && source == CS_REMOTE) ||
284          (state_ == ST_RECEIVEDPRANSWER && source == CS_REMOTE));
285}
286
287bool SrtpFilter::DoSetAnswer(const std::vector<CryptoParams>& answer_params,
288                             ContentSource source,
289                             bool final) {
290  if (!ExpectAnswer(source)) {
291    LOG(LS_ERROR) << "Invalid state for SRTP answer";
292    return false;
293  }
294
295  // If the answer doesn't requests crypto complete the negotiation of an
296  // unencrypted session.
297  // Otherwise, finalize the parameters and apply them.
298  if (answer_params.empty()) {
299    if (final) {
300      return ResetParams();
301    } else {
302      // Need to wait for the final answer to decide if
303      // we should go to Active state.
304      state_ = (source == CS_LOCAL) ? ST_SENTPRANSWER_NO_CRYPTO :
305                                      ST_RECEIVEDPRANSWER_NO_CRYPTO;
306      return true;
307    }
308  }
309  CryptoParams selected_params;
310  if (!NegotiateParams(answer_params, &selected_params))
311    return false;
312  const CryptoParams& send_params =
313      (source == CS_REMOTE) ? selected_params : answer_params[0];
314  const CryptoParams& recv_params =
315      (source == CS_REMOTE) ? answer_params[0] : selected_params;
316  if (!ApplyParams(send_params, recv_params)) {
317    return false;
318  }
319
320  if (final) {
321    offer_params_.clear();
322    state_ = ST_ACTIVE;
323  } else {
324    state_ =
325        (source == CS_LOCAL) ? ST_SENTPRANSWER : ST_RECEIVEDPRANSWER;
326  }
327  return true;
328}
329
330void SrtpFilter::CreateSrtpSessions() {
331  send_session_.reset(new SrtpSession());
332  applied_send_params_ = CryptoParams();
333  recv_session_.reset(new SrtpSession());
334  applied_recv_params_ = CryptoParams();
335
336  SignalSrtpError.repeat(send_session_->SignalSrtpError);
337  SignalSrtpError.repeat(recv_session_->SignalSrtpError);
338
339  send_session_->set_signal_silent_time(signal_silent_time_in_ms_);
340  recv_session_->set_signal_silent_time(signal_silent_time_in_ms_);
341}
342
343bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params,
344                                 CryptoParams* selected_params) {
345  // We're processing an accept. We should have exactly one set of params,
346  // unless the offer didn't mention crypto, in which case we shouldn't be here.
347  bool ret = (answer_params.size() == 1U && !offer_params_.empty());
348  if (ret) {
349    // We should find a match between the answer params and the offered params.
350    std::vector<CryptoParams>::const_iterator it;
351    for (it = offer_params_.begin(); it != offer_params_.end(); ++it) {
352      if (answer_params[0].Matches(*it)) {
353        break;
354      }
355    }
356
357    if (it != offer_params_.end()) {
358      *selected_params = *it;
359    } else {
360      ret = false;
361    }
362  }
363
364  if (!ret) {
365    LOG(LS_WARNING) << "Invalid parameters in SRTP answer";
366  }
367  return ret;
368}
369
370bool SrtpFilter::ApplyParams(const CryptoParams& send_params,
371                             const CryptoParams& recv_params) {
372  // TODO(jiayl): Split this method to apply send and receive CryptoParams
373  // independently, so that we can skip one method when either send or receive
374  // CryptoParams is unchanged.
375  if (applied_send_params_.cipher_suite == send_params.cipher_suite &&
376      applied_send_params_.key_params == send_params.key_params &&
377      applied_recv_params_.cipher_suite == recv_params.cipher_suite &&
378      applied_recv_params_.key_params == recv_params.key_params) {
379    LOG(LS_INFO) << "Applying the same SRTP parameters again. No-op.";
380
381    // We do not want to reset the ROC if the keys are the same. So just return.
382    return true;
383  }
384  // TODO(juberti): Zero these buffers after use.
385  bool ret;
386  uint8 send_key[SRTP_MASTER_KEY_LEN], recv_key[SRTP_MASTER_KEY_LEN];
387  ret = (ParseKeyParams(send_params.key_params, send_key, sizeof(send_key)) &&
388         ParseKeyParams(recv_params.key_params, recv_key, sizeof(recv_key)));
389  if (ret) {
390    CreateSrtpSessions();
391    ret = (send_session_->SetSend(send_params.cipher_suite,
392                                  send_key, sizeof(send_key)) &&
393           recv_session_->SetRecv(recv_params.cipher_suite,
394                                  recv_key, sizeof(recv_key)));
395  }
396  if (ret) {
397    LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
398                 << " send cipher_suite " << send_params.cipher_suite
399                 << " recv cipher_suite " << recv_params.cipher_suite;
400    applied_send_params_ = send_params;
401    applied_recv_params_ = recv_params;
402  } else {
403    LOG(LS_WARNING) << "Failed to apply negotiated SRTP parameters";
404  }
405  return ret;
406}
407
408bool SrtpFilter::ResetParams() {
409  offer_params_.clear();
410  state_ = ST_INIT;
411  LOG(LS_INFO) << "SRTP reset to init state";
412  return true;
413}
414
415bool SrtpFilter::ParseKeyParams(const std::string& key_params,
416                                uint8* key, int len) {
417  // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
418
419  // Fail if key-method is wrong.
420  if (key_params.find("inline:") != 0) {
421    return false;
422  }
423
424  // Fail if base64 decode fails, or the key is the wrong size.
425  std::string key_b64(key_params.substr(7)), key_str;
426  if (!talk_base::Base64::Decode(key_b64, talk_base::Base64::DO_STRICT,
427                                 &key_str, NULL) ||
428      static_cast<int>(key_str.size()) != len) {
429    return false;
430  }
431
432  memcpy(key, key_str.c_str(), len);
433  return true;
434}
435
436///////////////////////////////////////////////////////////////////////////////
437// SrtpSession
438
439#ifdef HAVE_SRTP
440
441bool SrtpSession::inited_ = false;
442
443SrtpSession::SrtpSession()
444    : session_(NULL),
445      rtp_auth_tag_len_(0),
446      rtcp_auth_tag_len_(0),
447      srtp_stat_(new SrtpStat()),
448      last_send_seq_num_(-1) {
449  sessions()->push_back(this);
450  SignalSrtpError.repeat(srtp_stat_->SignalSrtpError);
451}
452
453SrtpSession::~SrtpSession() {
454  sessions()->erase(std::find(sessions()->begin(), sessions()->end(), this));
455  if (session_) {
456    srtp_dealloc(session_);
457  }
458}
459
460bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
461  return SetKey(ssrc_any_outbound, cs, key, len);
462}
463
464bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
465  return SetKey(ssrc_any_inbound, cs, key, len);
466}
467
468bool SrtpSession::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
469  if (!session_) {
470    LOG(LS_WARNING) << "Failed to protect SRTP packet: no SRTP Session";
471    return false;
472  }
473
474  int need_len = in_len + rtp_auth_tag_len_;  // NOLINT
475  if (max_len < need_len) {
476    LOG(LS_WARNING) << "Failed to protect SRTP packet: The buffer length "
477                    << max_len << " is less than the needed " << need_len;
478    return false;
479  }
480
481  *out_len = in_len;
482  int err = srtp_protect(session_, p, out_len);
483  uint32 ssrc;
484  if (GetRtpSsrc(p, in_len, &ssrc)) {
485    srtp_stat_->AddProtectRtpResult(ssrc, err);
486  }
487  int seq_num;
488  GetRtpSeqNum(p, in_len, &seq_num);
489  if (err != err_status_ok) {
490    LOG(LS_WARNING) << "Failed to protect SRTP packet, seqnum="
491                    << seq_num << ", err=" << err << ", last seqnum="
492                    << last_send_seq_num_;
493    return false;
494  }
495  last_send_seq_num_ = seq_num;
496  return true;
497}
498
499bool SrtpSession::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
500  if (!session_) {
501    LOG(LS_WARNING) << "Failed to protect SRTCP packet: no SRTP Session";
502    return false;
503  }
504
505  int need_len = in_len + sizeof(uint32) + rtcp_auth_tag_len_;  // NOLINT
506  if (max_len < need_len) {
507    LOG(LS_WARNING) << "Failed to protect SRTCP packet: The buffer length "
508                    << max_len << " is less than the needed " << need_len;
509    return false;
510  }
511
512  *out_len = in_len;
513  int err = srtp_protect_rtcp(session_, p, out_len);
514  srtp_stat_->AddProtectRtcpResult(err);
515  if (err != err_status_ok) {
516    LOG(LS_WARNING) << "Failed to protect SRTCP packet, err=" << err;
517    return false;
518  }
519  return true;
520}
521
522bool SrtpSession::UnprotectRtp(void* p, int in_len, int* out_len) {
523  if (!session_) {
524    LOG(LS_WARNING) << "Failed to unprotect SRTP packet: no SRTP Session";
525    return false;
526  }
527
528  *out_len = in_len;
529  int err = srtp_unprotect(session_, p, out_len);
530  uint32 ssrc;
531  if (GetRtpSsrc(p, in_len, &ssrc)) {
532    srtp_stat_->AddUnprotectRtpResult(ssrc, err);
533  }
534  if (err != err_status_ok) {
535    LOG(LS_WARNING) << "Failed to unprotect SRTP packet, err=" << err;
536    return false;
537  }
538  return true;
539}
540
541bool SrtpSession::UnprotectRtcp(void* p, int in_len, int* out_len) {
542  if (!session_) {
543    LOG(LS_WARNING) << "Failed to unprotect SRTCP packet: no SRTP Session";
544    return false;
545  }
546
547  *out_len = in_len;
548  int err = srtp_unprotect_rtcp(session_, p, out_len);
549  srtp_stat_->AddUnprotectRtcpResult(err);
550  if (err != err_status_ok) {
551    LOG(LS_WARNING) << "Failed to unprotect SRTCP packet, err=" << err;
552    return false;
553  }
554  return true;
555}
556
557void SrtpSession::set_signal_silent_time(uint32 signal_silent_time_in_ms) {
558  srtp_stat_->set_signal_silent_time(signal_silent_time_in_ms);
559}
560
561bool SrtpSession::SetKey(int type, const std::string& cs,
562                         const uint8* key, int len) {
563  if (session_) {
564    LOG(LS_ERROR) << "Failed to create SRTP session: "
565                  << "SRTP session already created";
566    return false;
567  }
568
569  if (!Init()) {
570    return false;
571  }
572
573  srtp_policy_t policy;
574  memset(&policy, 0, sizeof(policy));
575
576  if (cs == CS_AES_CM_128_HMAC_SHA1_80) {
577    crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
578    crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
579  } else if (cs == CS_AES_CM_128_HMAC_SHA1_32) {
580    crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);   // rtp is 32,
581    crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);  // rtcp still 80
582  } else {
583    LOG(LS_WARNING) << "Failed to create SRTP session: unsupported"
584                    << " cipher_suite " << cs.c_str();
585    return false;
586  }
587
588  if (!key || len != SRTP_MASTER_KEY_LEN) {
589    LOG(LS_WARNING) << "Failed to create SRTP session: invalid key";
590    return false;
591  }
592
593  policy.ssrc.type = static_cast<ssrc_type_t>(type);
594  policy.ssrc.value = 0;
595  policy.key = const_cast<uint8*>(key);
596  // TODO(astor) parse window size from WSH session-param
597  policy.window_size = 1024;
598  policy.allow_repeat_tx = 1;
599  policy.next = NULL;
600
601  int err = srtp_create(&session_, &policy);
602  if (err != err_status_ok) {
603    LOG(LS_ERROR) << "Failed to create SRTP session, err=" << err;
604    return false;
605  }
606
607  rtp_auth_tag_len_ = policy.rtp.auth_tag_len;
608  rtcp_auth_tag_len_ = policy.rtcp.auth_tag_len;
609  return true;
610}
611
612bool SrtpSession::Init() {
613  if (!inited_) {
614    int err;
615    err = srtp_init();
616    if (err != err_status_ok) {
617      LOG(LS_ERROR) << "Failed to init SRTP, err=" << err;
618      return false;
619    }
620
621    err = srtp_install_event_handler(&SrtpSession::HandleEventThunk);
622    if (err != err_status_ok) {
623      LOG(LS_ERROR) << "Failed to install SRTP event handler, err=" << err;
624      return false;
625    }
626
627    inited_ = true;
628  }
629
630  return true;
631}
632
633void SrtpSession::Terminate() {
634  if (inited_) {
635    int err = srtp_shutdown();
636    if (err) {
637      LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
638      return;
639    }
640    inited_ = false;
641  }
642}
643
644void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
645  switch (ev->event) {
646    case event_ssrc_collision:
647      LOG(LS_INFO) << "SRTP event: SSRC collision";
648      break;
649    case event_key_soft_limit:
650      LOG(LS_INFO) << "SRTP event: reached soft key usage limit";
651      break;
652    case event_key_hard_limit:
653      LOG(LS_INFO) << "SRTP event: reached hard key usage limit";
654      break;
655    case event_packet_index_limit:
656      LOG(LS_INFO) << "SRTP event: reached hard packet limit (2^48 packets)";
657      break;
658    default:
659      LOG(LS_INFO) << "SRTP event: unknown " << ev->event;
660      break;
661  }
662}
663
664void SrtpSession::HandleEventThunk(srtp_event_data_t* ev) {
665  for (std::list<SrtpSession*>::iterator it = sessions()->begin();
666       it != sessions()->end(); ++it) {
667    if ((*it)->session_ == ev->session) {
668      (*it)->HandleEvent(ev);
669      break;
670    }
671  }
672}
673
674std::list<SrtpSession*>* SrtpSession::sessions() {
675  LIBJINGLE_DEFINE_STATIC_LOCAL(std::list<SrtpSession*>, sessions, ());
676  return &sessions;
677}
678
679#else   // !HAVE_SRTP
680
681// On some systems, SRTP is not (yet) available.
682
683SrtpSession::SrtpSession() {
684  LOG(WARNING) << "SRTP implementation is missing.";
685}
686
687SrtpSession::~SrtpSession() {
688}
689
690bool SrtpSession::SetSend(const std::string& cs, const uint8* key, int len) {
691  return SrtpNotAvailable(__FUNCTION__);
692}
693
694bool SrtpSession::SetRecv(const std::string& cs, const uint8* key, int len) {
695  return SrtpNotAvailable(__FUNCTION__);
696}
697
698bool SrtpSession::ProtectRtp(void* data, int in_len, int max_len,
699                             int* out_len) {
700  return SrtpNotAvailable(__FUNCTION__);
701}
702
703bool SrtpSession::ProtectRtcp(void* data, int in_len, int max_len,
704                              int* out_len) {
705  return SrtpNotAvailable(__FUNCTION__);
706}
707
708bool SrtpSession::UnprotectRtp(void* data, int in_len, int* out_len) {
709  return SrtpNotAvailable(__FUNCTION__);
710}
711
712bool SrtpSession::UnprotectRtcp(void* data, int in_len, int* out_len) {
713  return SrtpNotAvailable(__FUNCTION__);
714}
715
716void SrtpSession::set_signal_silent_time(uint32 signal_silent_time) {
717  // Do nothing.
718}
719
720#endif  // HAVE_SRTP
721
722///////////////////////////////////////////////////////////////////////////////
723// SrtpStat
724
725#ifdef HAVE_SRTP
726
727SrtpStat::SrtpStat()
728    : signal_silent_time_(1000) {
729}
730
731void SrtpStat::AddProtectRtpResult(uint32 ssrc, int result) {
732  FailureKey key;
733  key.ssrc = ssrc;
734  key.mode = SrtpFilter::PROTECT;
735  switch (result) {
736    case err_status_ok:
737      key.error = SrtpFilter::ERROR_NONE;
738      break;
739    case err_status_auth_fail:
740      key.error = SrtpFilter::ERROR_AUTH;
741      break;
742    default:
743      key.error = SrtpFilter::ERROR_FAIL;
744  }
745  HandleSrtpResult(key);
746}
747
748void SrtpStat::AddUnprotectRtpResult(uint32 ssrc, int result) {
749  FailureKey key;
750  key.ssrc = ssrc;
751  key.mode = SrtpFilter::UNPROTECT;
752  switch (result) {
753    case err_status_ok:
754      key.error = SrtpFilter::ERROR_NONE;
755      break;
756    case err_status_auth_fail:
757      key.error = SrtpFilter::ERROR_AUTH;
758      break;
759    case err_status_replay_fail:
760    case err_status_replay_old:
761      key.error = SrtpFilter::ERROR_REPLAY;
762      break;
763    default:
764      key.error = SrtpFilter::ERROR_FAIL;
765  }
766  HandleSrtpResult(key);
767}
768
769void SrtpStat::AddProtectRtcpResult(int result) {
770  AddProtectRtpResult(0U, result);
771}
772
773void SrtpStat::AddUnprotectRtcpResult(int result) {
774  AddUnprotectRtpResult(0U, result);
775}
776
777void SrtpStat::HandleSrtpResult(const SrtpStat::FailureKey& key) {
778  // Handle some cases where error should be signalled right away. For other
779  // errors, trigger error for the first time seeing it.  After that, silent
780  // the same error for a certain amount of time (default 1 sec).
781  if (key.error != SrtpFilter::ERROR_NONE) {
782    // For errors, signal first time and wait for 1 sec.
783    FailureStat* stat = &(failures_[key]);
784    uint32 current_time = talk_base::Time();
785    if (stat->last_signal_time == 0 ||
786        talk_base::TimeDiff(current_time, stat->last_signal_time) >
787        static_cast<int>(signal_silent_time_)) {
788      SignalSrtpError(key.ssrc, key.mode, key.error);
789      stat->last_signal_time = current_time;
790    }
791  }
792}
793
794#else   // !HAVE_SRTP
795
796// On some systems, SRTP is not (yet) available.
797
798SrtpStat::SrtpStat()
799    : signal_silent_time_(1000) {
800  LOG(WARNING) << "SRTP implementation is missing.";
801}
802
803void SrtpStat::AddProtectRtpResult(uint32 ssrc, int result) {
804  SrtpNotAvailable(__FUNCTION__);
805}
806
807void SrtpStat::AddUnprotectRtpResult(uint32 ssrc, int result) {
808  SrtpNotAvailable(__FUNCTION__);
809}
810
811void SrtpStat::AddProtectRtcpResult(int result) {
812  SrtpNotAvailable(__FUNCTION__);
813}
814
815void SrtpStat::AddUnprotectRtcpResult(int result) {
816  SrtpNotAvailable(__FUNCTION__);
817}
818
819void SrtpStat::HandleSrtpResult(const SrtpStat::FailureKey& key) {
820  SrtpNotAvailable(__FUNCTION__);
821}
822
823#endif  // HAVE_SRTP
824
825}  // namespace cricket
Note: See TracBrowser for help on using the repository browser.