1 /*
2 * srtp.cxx
3 *
4 * SRTP protocol handler
5 *
6 * OPAL Library
7 *
8 * Copyright (C) 2006 Post Increment
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is OPAL Library.
21 *
22 * The Initial Developer of the Original Code is Post Increment
23 * Portions of this code were written with the assistance of funding from
24 * US Joint Forces Command Joint Concept Development & Experimentation (J9)
25 * http://www.jfcom.mil/about/abt_j9.htm
26 *
27 * Contributor(s): ______________________________________.
28 *
29 * $Revision: 22444 $
30 * $Author: rjongbloed $
31 * $Date: 2009-04-20 18:49:06 -0500 (Mon, 20 Apr 2009) $
32 */
33
34 #include <ptlib.h>
35
36 #ifdef __GNUC__
37 #pragma implementation "srtp.h"
38 #endif
39
40 #include <opal/buildopts.h>
41
42 #if OPAL_SRTP
43
44 #include <rtp/srtp.h>
45 #include <opal/connection.h>
46 #include <h323/h323caps.h>
47 #include <h323/h235auth.h>
48
49
50 class PNatMethod;
51
52
53 // default key = 2687012454
54
55
56 ////////////////////////////////////////////////////////////////////
57 //
58 // this class implements SRTP over UDP
59 //
60
OpalSRTP_UDP(const Params & params)61 OpalSRTP_UDP::OpalSRTP_UDP(const Params & params)
62 : SecureRTP_UDP(params)
63 {
64 }
65
66
67 /////////////////////////////////////////////////////////////////////////////////////
68 //
69 // SRTP implementation using Cisco libSRTP
70 // See http://srtp.sourceforge.net/srtp.html
71 //
72
73 ////////////////////////////////////////////////////////////////////
74 //
75 // implement SRTP via libSRTP
76 //
77
78
79 #ifdef LIBSRTP_LIBRARY
80 #pragma comment(lib, LIBSRTP_LIBRARY)
81 #endif
82
83 #ifdef _WIN32
84 #pragma warning(disable:4244)
85 #pragma warning(disable:4505)
86 #endif
87
88 extern "C" {
89 #include "srtp/srtp.h"
90 };
91
92 ///////////////////////////////////////////////////////
93
94 class LibSRTPSecurityMode_Base : public OpalSRTPSecurityMode
95 {
96 PCLASSINFO(LibSRTPSecurityMode_Base, OpalSRTPSecurityMode);
97 public:
98 RTP_UDP * CreateRTPSession(
99 OpalRTPConnection & connection, ///< Connection creating session (may be needed by secure connections)
100 const RTP_Session::Params & options ///< Parameters to construct with session.
101 );
102
SetOutgoingKey(const KeySalt & key)103 PBoolean SetOutgoingKey(const KeySalt & key) { outgoingKey = key; return PTrue; }
GetOutgoingKey(KeySalt & key) const104 PBoolean GetOutgoingKey(KeySalt & key) const { key = outgoingKey; return PTrue; }
105 PBoolean SetOutgoingSSRC(DWORD ssrc);
106 PBoolean GetOutgoingSSRC(DWORD & ssrc) const;
107
SetIncomingKey(const KeySalt & key)108 PBoolean SetIncomingKey(const KeySalt & key) { incomingKey = key; return PTrue; }
GetIncomingKey(KeySalt & key) const109 PBoolean GetIncomingKey(KeySalt & key) const { key = incomingKey; return PTrue; } ;
110 PBoolean SetIncomingSSRC(DWORD ssrc);
111 PBoolean GetIncomingSSRC(DWORD & ssrc) const;
112
113 PBoolean Open();
114
115 srtp_t inboundSession;
116 srtp_t outboundSession;
117
118 protected:
119 void Init();
120 KeySalt incomingKey;
121 KeySalt outgoingKey;
122 srtp_policy_t inboundPolicy;
123 srtp_policy_t outboundPolicy;
124
125 private:
126 static PBoolean inited;
127 static PMutex initMutex;
128 };
129
130 PBoolean LibSRTPSecurityMode_Base::inited = PFalse;
131 PMutex LibSRTPSecurityMode_Base::initMutex;
132
Init()133 void LibSRTPSecurityMode_Base::Init()
134 {
135 {
136 PWaitAndSignal m(initMutex);
137 if (!inited) {
138 srtp_init();
139 inited = PTrue;
140 }
141 }
142 inboundPolicy.ssrc.type = ssrc_any_inbound;
143 inboundPolicy.next = NULL;
144 outboundPolicy.ssrc.type = ssrc_any_outbound;
145 outboundPolicy.next = NULL;
146
147 crypto_get_random(outgoingKey.key.GetPointer(SRTP_MASTER_KEY_LEN), SRTP_MASTER_KEY_LEN);
148 }
149
150
CreateRTPSession(OpalRTPConnection &,const RTP_Session::Params & options)151 RTP_UDP * LibSRTPSecurityMode_Base::CreateRTPSession(OpalRTPConnection & /*connection*/,
152 const RTP_Session::Params & options)
153 {
154 LibSRTP_UDP * session = new LibSRTP_UDP(options);
155 session->SetSecurityMode(this);
156 return session;
157 }
158
SetIncomingSSRC(DWORD ssrc)159 PBoolean LibSRTPSecurityMode_Base::SetIncomingSSRC(DWORD ssrc)
160 {
161 inboundPolicy.ssrc.type = ssrc_specific;
162 inboundPolicy.ssrc.value = ssrc;
163 return PTrue;
164 }
165
SetOutgoingSSRC(DWORD ssrc)166 PBoolean LibSRTPSecurityMode_Base::SetOutgoingSSRC(DWORD ssrc)
167 {
168 outboundPolicy.ssrc.type = ssrc_specific;
169 outboundPolicy.ssrc.value = ssrc;
170
171 return PTrue;
172 }
173
GetOutgoingSSRC(DWORD & ssrc) const174 PBoolean LibSRTPSecurityMode_Base::GetOutgoingSSRC(DWORD & ssrc) const
175 {
176 if (outboundPolicy.ssrc.type != ssrc_specific)
177 return PFalse;
178 ssrc = outboundPolicy.ssrc.value;
179 return PTrue;
180 }
181
GetIncomingSSRC(DWORD & ssrc) const182 PBoolean LibSRTPSecurityMode_Base::GetIncomingSSRC(DWORD & ssrc) const
183 {
184 if (inboundPolicy.ssrc.type != ssrc_specific)
185 return PFalse;
186
187 ssrc = inboundPolicy.ssrc.value;
188 return PTrue;
189 }
190
Open()191 PBoolean LibSRTPSecurityMode_Base::Open()
192 {
193 outboundPolicy.key = outgoingKey.key.GetPointer();
194 err_status_t err = srtp_create(&outboundSession, &outboundPolicy);
195 if (err != ::err_status_ok)
196 return PFalse;
197
198 inboundPolicy.key = incomingKey.key.GetPointer();
199 err = srtp_create(&inboundSession, &inboundPolicy);
200 if (err != ::err_status_ok)
201 return PFalse;
202
203 return PTrue;
204 }
205
206
207 #define DECLARE_LIBSRTP_CRYPTO_ALG(name, policy_fn) \
208 class LibSRTPSecurityMode_##name : public LibSRTPSecurityMode_Base \
209 { \
210 public: \
211 LibSRTPSecurityMode_##name() \
212 { \
213 policy_fn(&inboundPolicy.rtp); \
214 policy_fn(&inboundPolicy.rtcp); \
215 policy_fn(&outboundPolicy.rtp); \
216 policy_fn(&outboundPolicy.rtcp); \
217 Init(); \
218 } \
219 }; \
220 PFACTORY_CREATE(PFactory<OpalSecurityMode>, LibSRTPSecurityMode_##name, "SRTP|" #name, false)
221
222 DECLARE_LIBSRTP_CRYPTO_ALG(AES_CM_128_HMAC_SHA1_80, crypto_policy_set_aes_cm_128_hmac_sha1_80);
223 DECLARE_LIBSRTP_CRYPTO_ALG(AES_CM_128_HMAC_SHA1_32, crypto_policy_set_aes_cm_128_hmac_sha1_32);
224 DECLARE_LIBSRTP_CRYPTO_ALG(AES_CM_128_NULL_AUTH, crypto_policy_set_aes_cm_128_null_auth);
225 DECLARE_LIBSRTP_CRYPTO_ALG(NULL_CIPHER_HMAC_SHA1_80, crypto_policy_set_null_cipher_hmac_sha1_80);
226
227 DECLARE_LIBSRTP_CRYPTO_ALG(STRONGHOLD, crypto_policy_set_aes_cm_128_hmac_sha1_80);
228
229 ///////////////////////////////////////////////////////
230
LibSRTP_UDP(const Params & params)231 LibSRTP_UDP::LibSRTP_UDP(const Params & params)
232 : OpalSRTP_UDP(params)
233 {
234 }
235
~LibSRTP_UDP()236 LibSRTP_UDP::~LibSRTP_UDP()
237 {
238 }
239
Open(PIPSocket::Address localAddress,WORD portBase,WORD portMax,BYTE ipTypeOfService,PNatMethod * nat,RTP_QOS * rtpqos)240 PBoolean LibSRTP_UDP::Open(
241 PIPSocket::Address localAddress, ///< Local interface to bind to
242 WORD portBase, ///< Base of ports to search
243 WORD portMax, ///< end of ports to search (inclusive)
244 BYTE ipTypeOfService, ///< Type of Service byte
245 PNatMethod * nat, ///< NAT method to use createing sockets (or NULL if no STUN)
246 RTP_QOS * rtpqos ///< QOS spec (or NULL if no QoS)
247 )
248 {
249 LibSRTPSecurityMode_Base * srtp = (LibSRTPSecurityMode_Base *)securityParms;
250 if (srtp == NULL)
251 return PFalse;
252
253 // get the inbound and outbound SSRC from the SRTP parms and into the RTP session
254 srtp->GetOutgoingSSRC(syncSourceOut);
255 srtp->GetIncomingSSRC(syncSourceIn);
256
257 return OpalSRTP_UDP::Open(localAddress, portBase, portMax, ipTypeOfService, nat, rtpqos);
258 }
259
260
OnSendData(RTP_DataFrame & frame)261 RTP_UDP::SendReceiveStatus LibSRTP_UDP::OnSendData(RTP_DataFrame & frame)
262 {
263 SendReceiveStatus stat = RTP_UDP::OnSendData(frame);
264 if (stat != e_ProcessPacket)
265 return stat;
266
267 LibSRTPSecurityMode_Base * srtp = (LibSRTPSecurityMode_Base *)securityParms;
268
269 int len = frame.GetHeaderSize() + frame.GetPayloadSize();
270 frame.SetPayloadSize(len + SRTP_MAX_TRAILER_LEN);
271 err_status_t err = ::srtp_protect(srtp->outboundSession, frame.GetPointer(), &len);
272 if (err != err_status_ok)
273 return RTP_Session::e_IgnorePacket;
274 frame.SetPayloadSize(len - frame.GetHeaderSize());
275 return e_ProcessPacket;
276 }
277
OnReceiveData(RTP_DataFrame & frame)278 RTP_UDP::SendReceiveStatus LibSRTP_UDP::OnReceiveData(RTP_DataFrame & frame)
279 {
280 LibSRTPSecurityMode_Base * srtp = (LibSRTPSecurityMode_Base *)securityParms;
281
282 int len = frame.GetHeaderSize() + frame.GetPayloadSize();
283 err_status_t err = ::srtp_unprotect(srtp->inboundSession, frame.GetPointer(), &len);
284 if (err != err_status_ok)
285 return RTP_Session::e_IgnorePacket;
286 frame.SetPayloadSize(len - frame.GetHeaderSize());
287
288 return RTP_UDP::OnReceiveData(frame);
289 }
290
OnSendControl(RTP_ControlFrame & frame,PINDEX & transmittedLen)291 RTP_UDP::SendReceiveStatus LibSRTP_UDP::OnSendControl(RTP_ControlFrame & frame, PINDEX & transmittedLen)
292 {
293 SendReceiveStatus stat = RTP_UDP::OnSendControl(frame, transmittedLen);
294 if (stat != e_ProcessPacket)
295 return stat;
296
297 frame.SetMinSize(transmittedLen + SRTP_MAX_TRAILER_LEN);
298 int len = transmittedLen;
299
300 LibSRTPSecurityMode_Base * srtp = (LibSRTPSecurityMode_Base *)securityParms;
301
302 err_status_t err = ::srtp_protect_rtcp(srtp->outboundSession, frame.GetPointer(), &len);
303 if (err != err_status_ok)
304 return RTP_Session::e_IgnorePacket;
305 transmittedLen = len;
306
307 return e_ProcessPacket;
308 }
309
OnReceiveControl(RTP_ControlFrame & frame)310 RTP_UDP::SendReceiveStatus LibSRTP_UDP::OnReceiveControl(RTP_ControlFrame & frame)
311 {
312 LibSRTPSecurityMode_Base * srtp = (LibSRTPSecurityMode_Base *)securityParms;
313
314 int len = frame.GetSize();
315 err_status_t err = ::srtp_unprotect_rtcp(srtp->inboundSession, frame.GetPointer(), &len);
316 if (err != err_status_ok)
317 return RTP_Session::e_IgnorePacket;
318 frame.SetSize(len);
319
320 return RTP_UDP::OnReceiveControl(frame);
321 }
322
323 ///////////////////////////////////////////////////////
324
325 #endif // OPAL_SRTP
326