SrtpFlow.cpp (7443B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 // Original author: ekr@rtfm.com 6 7 #include "SrtpFlow.h" 8 9 #include "logging.h" 10 #include "mozilla/RefPtr.h" 11 #include "srtp.h" 12 #include "transportlayerdtls.h" 13 14 using namespace mozilla; 15 16 namespace mozilla { 17 18 MOZ_MTLOG_MODULE("mtransport") 19 bool SrtpFlow::initialized; // Static 20 21 SrtpFlow::~SrtpFlow() { 22 if (session_) { 23 srtp_dealloc(session_); 24 } 25 } 26 27 unsigned int SrtpFlow::KeySize(int cipher_suite) { 28 srtp_profile_t profile = static_cast<srtp_profile_t>(cipher_suite); 29 return srtp_profile_get_master_key_length(profile); 30 } 31 32 unsigned int SrtpFlow::SaltSize(int cipher_suite) { 33 srtp_profile_t profile = static_cast<srtp_profile_t>(cipher_suite); 34 return srtp_profile_get_master_salt_length(profile); 35 } 36 37 RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite, bool inbound, 38 const void* key, size_t key_len) { 39 nsresult res = Init(); 40 if (!NS_SUCCEEDED(res)) return nullptr; 41 42 RefPtr<SrtpFlow> flow = new SrtpFlow(); 43 44 if (!key) { 45 MOZ_MTLOG(ML_ERROR, "Null SRTP key specified"); 46 return nullptr; 47 } 48 49 if ((key_len > SRTP_MAX_KEY_LENGTH) || (key_len < SRTP_MIN_KEY_LENGTH)) { 50 MOZ_ASSERT(false, "Invalid SRTP key length"); 51 return nullptr; 52 } 53 54 srtp_policy_t policy; 55 memset(&policy, 0, sizeof(srtp_policy_t)); 56 57 // Note that we set the same cipher suite for RTP and RTCP 58 // since any flow can only have one cipher suite with DTLS-SRTP 59 switch (cipher_suite) { 60 case kDtlsSrtpAeadAes256Gcm: 61 MOZ_MTLOG(ML_DEBUG, "Setting SRTP cipher suite SRTP_AEAD_AES_256_GCM"); 62 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp); 63 srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp); 64 break; 65 case kDtlsSrtpAeadAes128Gcm: 66 MOZ_MTLOG(ML_DEBUG, "Setting SRTP cipher suite SRTP_AEAD_AES_128_GCM"); 67 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp); 68 srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp); 69 break; 70 case kDtlsSrtpAes128CmHmacSha1_80: 71 MOZ_MTLOG(ML_DEBUG, 72 "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80"); 73 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); 74 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); 75 break; 76 case kDtlsSrtpAes128CmHmacSha1_32: 77 MOZ_MTLOG(ML_DEBUG, 78 "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32"); 79 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); 80 srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80( 81 &policy.rtcp); // 80-bit per RFC 5764 82 break; // S 4.1.2. 83 default: 84 MOZ_MTLOG(ML_ERROR, "Request to set unknown SRTP cipher suite"); 85 return nullptr; 86 } 87 // This key is copied into the srtp_t object, so we don't 88 // need to keep it. 89 policy.key = 90 const_cast<unsigned char*>(static_cast<const unsigned char*>(key)); 91 policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound; 92 policy.ssrc.value = 0; 93 policy.window_size = 94 1024; // Use the Chrome value. Needs to be revisited. Default is 128 95 policy.allow_repeat_tx = 1; // Use Chrome value; needed for NACK mode to work 96 policy.next = nullptr; 97 98 // Now make the session 99 srtp_err_status_t r = srtp_create(&flow->session_, &policy); 100 if (r != srtp_err_status_ok) { 101 MOZ_MTLOG(ML_ERROR, "Error creating srtp session"); 102 return nullptr; 103 } 104 105 return flow; 106 } 107 108 nsresult SrtpFlow::CheckInputs(bool protect, void* in, int in_len, int max_len, 109 int* out_len) { 110 MOZ_ASSERT(in); 111 if (!in) { 112 MOZ_MTLOG(ML_ERROR, "NULL input value"); 113 return NS_ERROR_NULL_POINTER; 114 } 115 116 if (in_len < 0) { 117 MOZ_MTLOG(ML_ERROR, "Input length is negative"); 118 return NS_ERROR_ILLEGAL_VALUE; 119 } 120 121 if (max_len < 0) { 122 MOZ_MTLOG(ML_ERROR, "Max output length is negative"); 123 return NS_ERROR_ILLEGAL_VALUE; 124 } 125 126 if (protect) { 127 if ((max_len < SRTP_MAX_EXPANSION) || 128 ((max_len - SRTP_MAX_EXPANSION) < in_len)) { 129 MOZ_MTLOG(ML_ERROR, "Output too short"); 130 return NS_ERROR_ILLEGAL_VALUE; 131 } 132 } else { 133 if (in_len > max_len) { 134 MOZ_MTLOG(ML_ERROR, "Output too short"); 135 return NS_ERROR_ILLEGAL_VALUE; 136 } 137 } 138 139 return NS_OK; 140 } 141 142 nsresult SrtpFlow::ProtectRtp(void* in, int in_len, int max_len, int* out_len) { 143 nsresult res = CheckInputs(true, in, in_len, max_len, out_len); 144 if (NS_FAILED(res)) return res; 145 146 int len = in_len; 147 srtp_err_status_t r = srtp_protect(session_, in, &len); 148 149 if (r != srtp_err_status_ok) { 150 MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet"); 151 return NS_ERROR_FAILURE; 152 } 153 154 MOZ_ASSERT(len <= max_len); 155 *out_len = len; 156 157 MOZ_MTLOG(ML_DEBUG, 158 "Successfully protected an SRTP packet of len " << *out_len); 159 160 return NS_OK; 161 } 162 163 nsresult SrtpFlow::UnprotectRtp(void* in, int in_len, int max_len, 164 int* out_len) { 165 nsresult res = CheckInputs(false, in, in_len, max_len, out_len); 166 if (NS_FAILED(res)) return res; 167 168 int len = in_len; 169 srtp_err_status_t r = srtp_unprotect(session_, in, &len); 170 171 if (r != srtp_err_status_ok) { 172 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r); 173 return NS_ERROR_FAILURE; 174 } 175 176 MOZ_ASSERT(len <= max_len); 177 *out_len = len; 178 179 MOZ_MTLOG(ML_DEBUG, 180 "Successfully unprotected an SRTP packet of len " << *out_len); 181 182 return NS_OK; 183 } 184 185 nsresult SrtpFlow::ProtectRtcp(void* in, int in_len, int max_len, 186 int* out_len) { 187 nsresult res = CheckInputs(true, in, in_len, max_len, out_len); 188 if (NS_FAILED(res)) return res; 189 190 int len = in_len; 191 srtp_err_status_t r = srtp_protect_rtcp(session_, in, &len); 192 193 if (r != srtp_err_status_ok) { 194 MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet"); 195 return NS_ERROR_FAILURE; 196 } 197 198 MOZ_ASSERT(len <= max_len); 199 *out_len = len; 200 201 MOZ_MTLOG(ML_DEBUG, 202 "Successfully protected an SRTCP packet of len " << *out_len); 203 204 return NS_OK; 205 } 206 207 nsresult SrtpFlow::UnprotectRtcp(void* in, int in_len, int max_len, 208 int* out_len) { 209 nsresult res = CheckInputs(false, in, in_len, max_len, out_len); 210 if (NS_FAILED(res)) return res; 211 212 int len = in_len; 213 srtp_err_status_t r = srtp_unprotect_rtcp(session_, in, &len); 214 215 if (r != srtp_err_status_ok) { 216 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r); 217 return NS_ERROR_FAILURE; 218 } 219 220 MOZ_ASSERT(len <= max_len); 221 *out_len = len; 222 223 MOZ_MTLOG(ML_DEBUG, 224 "Successfully unprotected an SRTCP packet of len " << *out_len); 225 226 return NS_OK; 227 } 228 229 // Statics 230 void SrtpFlow::srtp_event_handler(srtp_event_data_t* data) { 231 // TODO(ekr@rtfm.com): Implement this 232 MOZ_CRASH(); 233 } 234 235 nsresult SrtpFlow::Init() { 236 if (!initialized) { 237 srtp_err_status_t r = srtp_init(); 238 if (r != srtp_err_status_ok) { 239 MOZ_MTLOG(ML_ERROR, "Could not initialize SRTP"); 240 MOZ_ASSERT(PR_FALSE); 241 return NS_ERROR_FAILURE; 242 } 243 244 r = srtp_install_event_handler(&SrtpFlow::srtp_event_handler); 245 if (r != srtp_err_status_ok) { 246 MOZ_MTLOG(ML_ERROR, "Could not install SRTP event handler"); 247 MOZ_ASSERT(PR_FALSE); 248 return NS_ERROR_FAILURE; 249 } 250 251 initialized = true; 252 } 253 254 return NS_OK; 255 } 256 257 } // namespace mozilla