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