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