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.
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/. */
5 // Original author: ekr@rtfm.com
7 #include "logging.h"
8 #include "SrtpFlow.h"
10 #include "srtp.h"
11 #include "ssl.h"
12 #include "sslproto.h"
14 #include "mozilla/RefPtr.h"
16 // Logging context
17 using namespace mozilla;
18 MOZ_MTLOG_MODULE("mediapipeline")
20 namespace mozilla {
22 bool SrtpFlow::initialized; // Static
24 SrtpFlow::~SrtpFlow() {
25 if (session_) {
26 srtp_dealloc(session_);
27 }
28 }
30 RefPtr<SrtpFlow> SrtpFlow::Create(int cipher_suite,
31 bool inbound,
32 const void *key,
33 size_t key_len) {
34 nsresult res = Init();
35 if (!NS_SUCCEEDED(res))
36 return nullptr;
38 RefPtr<SrtpFlow> flow = new SrtpFlow();
40 if (!key) {
41 MOZ_MTLOG(ML_ERROR, "Null SRTP key specified");
42 return nullptr;
43 }
45 if (key_len != SRTP_TOTAL_KEY_LENGTH) {
46 MOZ_MTLOG(ML_ERROR, "Invalid SRTP key length");
47 return nullptr;
48 }
50 srtp_policy_t policy;
51 memset(&policy, 0, sizeof(srtp_policy_t));
53 // Note that we set the same cipher suite for RTP and RTCP
54 // since any flow can only have one cipher suite with DTLS-SRTP
55 switch (cipher_suite) {
56 case SRTP_AES128_CM_HMAC_SHA1_80:
57 MOZ_MTLOG(ML_DEBUG,
58 "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_80");
59 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
60 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
61 break;
62 case SRTP_AES128_CM_HMAC_SHA1_32:
63 MOZ_MTLOG(ML_DEBUG,
64 "Setting SRTP cipher suite SRTP_AES128_CM_HMAC_SHA1_32");
65 crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
66 crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // 80-bit per RFC 5764
67 break; // S 4.1.2.
68 default:
69 MOZ_MTLOG(ML_ERROR, "Request to set unknown SRTP cipher suite");
70 return nullptr;
71 }
72 // This key is copied into the srtp_t object, so we don't
73 // need to keep it.
74 policy.key = const_cast<unsigned char *>(
75 static_cast<const unsigned char *>(key));
76 policy.ssrc.type = inbound ? ssrc_any_inbound : ssrc_any_outbound;
77 policy.ssrc.value = 0;
78 policy.ekt = nullptr;
79 policy.window_size = 1024; // Use the Chrome value. Needs to be revisited. Default is 128
80 policy.allow_repeat_tx = 1; // Use Chrome value; needed for NACK mode to work
81 policy.next = nullptr;
83 // Now make the session
84 err_status_t r = srtp_create(&flow->session_, &policy);
85 if (r != err_status_ok) {
86 MOZ_MTLOG(ML_ERROR, "Error creating srtp session");
87 return nullptr;
88 }
90 return flow;
91 }
94 nsresult SrtpFlow::CheckInputs(bool protect, void *in, int in_len,
95 int max_len, int *out_len) {
96 MOZ_ASSERT(in);
97 if (!in) {
98 MOZ_MTLOG(ML_ERROR, "NULL input value");
99 return NS_ERROR_NULL_POINTER;
100 }
102 if (in_len < 0) {
103 MOZ_MTLOG(ML_ERROR, "Input length is negative");
104 return NS_ERROR_ILLEGAL_VALUE;
105 }
107 if (max_len < 0) {
108 MOZ_MTLOG(ML_ERROR, "Max output length is negative");
109 return NS_ERROR_ILLEGAL_VALUE;
110 }
112 if (protect) {
113 if ((max_len < SRTP_MAX_EXPANSION) ||
114 ((max_len - SRTP_MAX_EXPANSION) < in_len)) {
115 MOZ_MTLOG(ML_ERROR, "Output too short");
116 return NS_ERROR_ILLEGAL_VALUE;
117 }
118 }
119 else {
120 if (in_len > max_len) {
121 MOZ_MTLOG(ML_ERROR, "Output too short");
122 return NS_ERROR_ILLEGAL_VALUE;
123 }
124 }
126 return NS_OK;
127 }
129 nsresult SrtpFlow::ProtectRtp(void *in, int in_len,
130 int max_len, int *out_len) {
131 nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
132 if (NS_FAILED(res))
133 return res;
135 int len = in_len;
136 err_status_t r = srtp_protect(session_, in, &len);
138 if (r != err_status_ok) {
139 MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet");
140 return NS_ERROR_FAILURE;
141 }
143 MOZ_ASSERT(len <= max_len);
144 *out_len = len;
147 MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTP packet of len "
148 << *out_len);
150 return NS_OK;
151 }
153 nsresult SrtpFlow::UnprotectRtp(void *in, int in_len,
154 int max_len, int *out_len) {
155 nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
156 if (NS_FAILED(res))
157 return res;
159 int len = in_len;
160 err_status_t r = srtp_unprotect(session_, in, &len);
162 if (r != err_status_ok) {
163 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r);
164 return NS_ERROR_FAILURE;
165 }
167 MOZ_ASSERT(len <= max_len);
168 *out_len = len;
170 MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTP packet of len "
171 << *out_len);
173 return NS_OK;
174 }
176 nsresult SrtpFlow::ProtectRtcp(void *in, int in_len,
177 int max_len, int *out_len) {
178 nsresult res = CheckInputs(true, in, in_len, max_len, out_len);
179 if (NS_FAILED(res))
180 return res;
182 int len = in_len;
183 err_status_t r = srtp_protect_rtcp(session_, in, &len);
185 if (r != err_status_ok) {
186 MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet");
187 return NS_ERROR_FAILURE;
188 }
190 MOZ_ASSERT(len <= max_len);
191 *out_len = len;
193 MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTCP packet of len "
194 << *out_len);
196 return NS_OK;
197 }
199 nsresult SrtpFlow::UnprotectRtcp(void *in, int in_len,
200 int max_len, int *out_len) {
201 nsresult res = CheckInputs(false, in, in_len, max_len, out_len);
202 if (NS_FAILED(res))
203 return res;
205 int len = in_len;
206 err_status_t r = srtp_unprotect_rtcp(session_, in, &len);
208 if (r != err_status_ok) {
209 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r);
210 return NS_ERROR_FAILURE;
211 }
213 MOZ_ASSERT(len <= max_len);
214 *out_len = len;
216 MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTCP packet of len "
217 << *out_len);
219 return NS_OK;
220 }
222 // Statics
223 void SrtpFlow::srtp_event_handler(srtp_event_data_t *data) {
224 // TODO(ekr@rtfm.com): Implement this
225 MOZ_CRASH();
226 }
228 nsresult SrtpFlow::Init() {
229 if (!initialized) {
230 err_status_t r = srtp_init();
231 if (r != err_status_ok) {
232 MOZ_MTLOG(ML_ERROR, "Could not initialize SRTP");
233 MOZ_ASSERT(PR_FALSE);
234 return NS_ERROR_FAILURE;
235 }
237 r = srtp_install_event_handler(&SrtpFlow::srtp_event_handler);
238 if (r != err_status_ok) {
239 MOZ_MTLOG(ML_ERROR, "Could not install SRTP event handler");
240 MOZ_ASSERT(PR_FALSE);
241 return NS_ERROR_FAILURE;
242 }
244 initialized = true;
245 }
247 return NS_OK;
248 }
250 } // end of namespace