|
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 "logging.h" |
|
8 #include "SrtpFlow.h" |
|
9 |
|
10 #include "srtp.h" |
|
11 #include "ssl.h" |
|
12 #include "sslproto.h" |
|
13 |
|
14 #include "mozilla/RefPtr.h" |
|
15 |
|
16 // Logging context |
|
17 using namespace mozilla; |
|
18 MOZ_MTLOG_MODULE("mediapipeline") |
|
19 |
|
20 namespace mozilla { |
|
21 |
|
22 bool SrtpFlow::initialized; // Static |
|
23 |
|
24 SrtpFlow::~SrtpFlow() { |
|
25 if (session_) { |
|
26 srtp_dealloc(session_); |
|
27 } |
|
28 } |
|
29 |
|
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; |
|
37 |
|
38 RefPtr<SrtpFlow> flow = new SrtpFlow(); |
|
39 |
|
40 if (!key) { |
|
41 MOZ_MTLOG(ML_ERROR, "Null SRTP key specified"); |
|
42 return nullptr; |
|
43 } |
|
44 |
|
45 if (key_len != SRTP_TOTAL_KEY_LENGTH) { |
|
46 MOZ_MTLOG(ML_ERROR, "Invalid SRTP key length"); |
|
47 return nullptr; |
|
48 } |
|
49 |
|
50 srtp_policy_t policy; |
|
51 memset(&policy, 0, sizeof(srtp_policy_t)); |
|
52 |
|
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; |
|
82 |
|
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 } |
|
89 |
|
90 return flow; |
|
91 } |
|
92 |
|
93 |
|
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 } |
|
101 |
|
102 if (in_len < 0) { |
|
103 MOZ_MTLOG(ML_ERROR, "Input length is negative"); |
|
104 return NS_ERROR_ILLEGAL_VALUE; |
|
105 } |
|
106 |
|
107 if (max_len < 0) { |
|
108 MOZ_MTLOG(ML_ERROR, "Max output length is negative"); |
|
109 return NS_ERROR_ILLEGAL_VALUE; |
|
110 } |
|
111 |
|
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 } |
|
125 |
|
126 return NS_OK; |
|
127 } |
|
128 |
|
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; |
|
134 |
|
135 int len = in_len; |
|
136 err_status_t r = srtp_protect(session_, in, &len); |
|
137 |
|
138 if (r != err_status_ok) { |
|
139 MOZ_MTLOG(ML_ERROR, "Error protecting SRTP packet"); |
|
140 return NS_ERROR_FAILURE; |
|
141 } |
|
142 |
|
143 MOZ_ASSERT(len <= max_len); |
|
144 *out_len = len; |
|
145 |
|
146 |
|
147 MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTP packet of len " |
|
148 << *out_len); |
|
149 |
|
150 return NS_OK; |
|
151 } |
|
152 |
|
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; |
|
158 |
|
159 int len = in_len; |
|
160 err_status_t r = srtp_unprotect(session_, in, &len); |
|
161 |
|
162 if (r != err_status_ok) { |
|
163 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTP packet error=" << (int)r); |
|
164 return NS_ERROR_FAILURE; |
|
165 } |
|
166 |
|
167 MOZ_ASSERT(len <= max_len); |
|
168 *out_len = len; |
|
169 |
|
170 MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTP packet of len " |
|
171 << *out_len); |
|
172 |
|
173 return NS_OK; |
|
174 } |
|
175 |
|
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; |
|
181 |
|
182 int len = in_len; |
|
183 err_status_t r = srtp_protect_rtcp(session_, in, &len); |
|
184 |
|
185 if (r != err_status_ok) { |
|
186 MOZ_MTLOG(ML_ERROR, "Error protecting SRTCP packet"); |
|
187 return NS_ERROR_FAILURE; |
|
188 } |
|
189 |
|
190 MOZ_ASSERT(len <= max_len); |
|
191 *out_len = len; |
|
192 |
|
193 MOZ_MTLOG(ML_DEBUG, "Successfully protected an SRTCP packet of len " |
|
194 << *out_len); |
|
195 |
|
196 return NS_OK; |
|
197 } |
|
198 |
|
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; |
|
204 |
|
205 int len = in_len; |
|
206 err_status_t r = srtp_unprotect_rtcp(session_, in, &len); |
|
207 |
|
208 if (r != err_status_ok) { |
|
209 MOZ_MTLOG(ML_ERROR, "Error unprotecting SRTCP packet error=" << (int)r); |
|
210 return NS_ERROR_FAILURE; |
|
211 } |
|
212 |
|
213 MOZ_ASSERT(len <= max_len); |
|
214 *out_len = len; |
|
215 |
|
216 MOZ_MTLOG(ML_DEBUG, "Successfully unprotected an SRTCP packet of len " |
|
217 << *out_len); |
|
218 |
|
219 return NS_OK; |
|
220 } |
|
221 |
|
222 // Statics |
|
223 void SrtpFlow::srtp_event_handler(srtp_event_data_t *data) { |
|
224 // TODO(ekr@rtfm.com): Implement this |
|
225 MOZ_CRASH(); |
|
226 } |
|
227 |
|
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 } |
|
236 |
|
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 } |
|
243 |
|
244 initialized = true; |
|
245 } |
|
246 |
|
247 return NS_OK; |
|
248 } |
|
249 |
|
250 } // end of namespace |
|
251 |