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