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