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