1 /*
2  * h235chan.cxx
3  *
4  * H.235 Secure RTP channel class.
5  *
6  * h323plus library
7  *
8  * Copyright (c) 2011 Spranto Australia Pty Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.1 (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  * Alternatively, the contents of this file may be used under the terms
16  * of the General Public License (the  "GNU License"), in which case the
17  * provisions of GNU License are applicable instead of those
18  * above. If you wish to allow use of your version of this file only
19  * under the terms of the GNU License and not to allow others to use
20  * your version of this file under the MPL, indicate your decision by
21  * deleting the provisions above and replace them with the notice and
22  * other provisions required by the GNU License. If you do not delete
23  * the provisions above, a recipient may use your version of this file
24  * under either the MPL or the GNU License."
25  *
26  * Software distributed under the License is distributed on an "AS IS"
27  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
28  * the License for the specific language governing rights and limitations
29  * under the License.
30  *
31  *
32  * The Initial Developer of the Original Code is ISVO (Asia) Pte. Ltd.
33  *
34  *
35  * Contributor(s): ______________________________________.
36  *
37  * $Id$
38  *
39  */
40 
41 #include <ptlib.h>
42 #include "openh323buildopts.h"
43 
44 #ifdef H323_H235
45 
46 #include "h235/h235chan.h"
47 #include <h323rtp.h>
48 #include <h323con.h>
49 
50 #ifdef H323_H235_AES256
51 const char * STR_AES256 = "AES256";
52 #endif
53 const char * STR_AES192 = "AES192";
54 const char * STR_AES128 = "AES128";
55 
CipherString(const PString & m_algorithmOID)56 PString CipherString(const PString & m_algorithmOID)
57 {
58     if (m_algorithmOID == "2.16.840.1.101.3.4.1.2") {
59         return STR_AES128;
60     } else if (m_algorithmOID == "2.16.840.1.101.3.4.1.22") {
61         return STR_AES192;
62 #ifdef H323_H235_AES256
63     } else if (m_algorithmOID == "2.16.840.1.101.3.4.1.42") {
64         return STR_AES256;
65 #endif
66     }
67     return "Unknown";
68 }
69 
H323SecureRTPChannel(H323Connection & conn,const H323Capability & cap,Directions direction,RTP_Session & r)70 H323SecureRTPChannel::H323SecureRTPChannel(H323Connection & conn,
71                                  const H323Capability & cap,
72                                  Directions direction,
73                                  RTP_Session & r
74                                  )
75     : H323_RTPChannel(conn,cap,direction, r), m_algorithm(cap.GetEncryptionAlgorithm()),
76       m_encryption((H235Capabilities*)conn.GetLocalCapabilitiesRef(), cap.GetEncryptionAlgorithm()),
77       m_payload(RTP_DataFrame::IllegalPayloadType)
78 {
79 }
80 
~H323SecureRTPChannel()81 H323SecureRTPChannel::~H323SecureRTPChannel()
82 {
83     delete capability;
84     capability = NULL;
85 }
86 
CleanUpOnTermination()87 void H323SecureRTPChannel::CleanUpOnTermination()
88 {
89   if (terminating)
90     return;
91 
92   return H323_RTPChannel::CleanUpOnTermination();
93 }
94 
BuildEncryptionSync(H245_EncryptionSync & sync,const H323Channel & chan,const H235Session & session)95 void BuildEncryptionSync(H245_EncryptionSync & sync, const H323Channel & chan, const H235Session & session)
96 {
97     sync.m_synchFlag = chan.GetRTPPayloadType();
98 
99     PBYTEArray encryptedMediaKey;
100     PRemoveConst(H235Session, &session)->EncodeMediaKey(encryptedMediaKey);
101     H235_H235Key h235key;
102     h235key.SetTag(H235_H235Key::e_secureSharedSecret);
103     H235_V3KeySyncMaterial & v3data = h235key;
104     v3data.IncludeOptionalField(H235_V3KeySyncMaterial::e_algorithmOID);
105     v3data.m_algorithmOID = session.GetAlgorithmOID();
106     v3data.IncludeOptionalField(H235_V3KeySyncMaterial::e_encryptedSessionKey);
107     v3data.m_encryptedSessionKey = encryptedMediaKey;
108 
109     sync.m_h235Key.EncodeSubType(h235key);
110 }
111 
112 
ReadEncryptionSync(const H245_EncryptionSync & sync,H323Channel & chan,H235Session & session)113 PBoolean ReadEncryptionSync(const H245_EncryptionSync & sync, H323Channel & chan, H235Session & session)
114 {
115     H235_H235Key h235key;
116 
117     if (sync.m_h235Key.DecodeSubType(h235key)) {
118         chan.SetDynamicRTPPayloadType(sync.m_synchFlag);
119 
120         switch (h235key.GetTag()) {
121             case H235_H235Key::e_secureChannel:
122                 PTRACE(4,"H235Key\tSecureChannel not supported");
123                 return false;
124             case H235_H235Key::e_secureChannelExt:
125                 PTRACE(4,"H235Key\tSecureChannelExt not supported");
126                 return false;
127             case H235_H235Key::e_sharedSecret:
128                 PTRACE(4,"H235Key\tShared Secret not supported");
129                 return false;
130             case H235_H235Key::e_certProtectedKey:
131                 PTRACE(4,"H235Key\tProtected Key not supported");
132                 return false;
133             case H235_H235Key::e_secureSharedSecret:
134                 {
135                     const H235_V3KeySyncMaterial & v3data = h235key;
136                     if (!v3data.HasOptionalField(H235_V3KeySyncMaterial::e_algorithmOID)) {
137                         // the algo is required, but is really redundant
138                         PTRACE(3, "H235\tWarning: No algo set in encryptionSync");
139                     }
140                     if (v3data.HasOptionalField(H235_V3KeySyncMaterial::e_encryptedSessionKey)) {
141                       PBYTEArray mediaKey = v3data.m_encryptedSessionKey;
142                       return session.DecodeMediaKey(mediaKey);
143                     }
144                 }
145         }
146     }
147     return false;
148 }
149 
150 
OnSendingPDU(H245_OpenLogicalChannel & open) const151 PBoolean H323SecureRTPChannel::OnSendingPDU(H245_OpenLogicalChannel & open) const
152 {
153   PTRACE(4, "H235RTP\tOnSendingPDU");
154 
155   if (H323_RealTimeChannel::OnSendingPDU(open)) {
156        if (connection.IsH245Master()) {
157             if (PRemoveConst(H235Session, &m_encryption)->CreateSession(true)) {
158                 open.IncludeOptionalField(H245_OpenLogicalChannel::e_encryptionSync);
159                 BuildEncryptionSync(open.m_encryptionSync,*this, m_encryption);
160             }
161         }
162         connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
163        return true;
164   }
165   return false;
166 }
167 
168 
OnSendOpenAck(const H245_OpenLogicalChannel & open,H245_OpenLogicalChannelAck & ack) const169 void H323SecureRTPChannel::OnSendOpenAck(const H245_OpenLogicalChannel & open,
170                                          H245_OpenLogicalChannelAck & ack) const
171 {
172   PTRACE(4, "H235RTP\tOnSendOpenAck");
173 
174   H323_RealTimeChannel::OnSendOpenAck(open,ack);
175 
176   if (connection.IsH245Master()) {
177         if (PRemoveConst(H235Session, &m_encryption)->CreateSession(true)) {
178             ack.IncludeOptionalField(H245_OpenLogicalChannelAck::e_encryptionSync);
179             BuildEncryptionSync(ack.m_encryptionSync,*this, m_encryption);
180             connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
181         }
182   }
183 
184 }
185 
186 
OnReceivedPDU(const H245_OpenLogicalChannel & open,unsigned & errorCode)187 PBoolean H323SecureRTPChannel::OnReceivedPDU(const H245_OpenLogicalChannel & open,
188                                          unsigned & errorCode)
189 {
190    PTRACE(4, "H235RTP\tOnRecievedPDU");
191 
192    if (!H323_RealTimeChannel::OnReceivedPDU(open,errorCode))
193        return false;
194 
195    if (open.HasOptionalField(H245_OpenLogicalChannel::e_encryptionSync)) {
196        if (m_encryption.CreateSession(false)) {
197            connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
198            return ReadEncryptionSync(open.m_encryptionSync,*this, m_encryption);
199        }
200    }
201    return true;
202 }
203 
204 
OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)205 PBoolean H323SecureRTPChannel::OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)
206 {
207   PTRACE(3, "H235RTP\tOnReceiveOpenAck");
208 
209   if (!H323_RealTimeChannel::OnReceivedAckPDU(ack))
210       return false;
211 
212   if (ack.HasOptionalField(H245_OpenLogicalChannelAck::e_encryptionSync)) {
213       if (m_encryption.CreateSession(false)) {
214             connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
215             return ReadEncryptionSync(ack.m_encryptionSync,*this, m_encryption);
216       }
217   }
218   return true;
219 }
220 
OnSendingPDU(H245_H2250LogicalChannelParameters & param) const221 PBoolean H323SecureRTPChannel::OnSendingPDU(H245_H2250LogicalChannelParameters & param) const
222 {
223   return rtpCallbacks.OnSendingPDU(*this, param);
224 }
225 
226 
OnSendOpenAck(H245_H2250LogicalChannelAckParameters & param) const227 void H323SecureRTPChannel::OnSendOpenAck(H245_H2250LogicalChannelAckParameters & param) const
228 {
229   rtpCallbacks.OnSendingAckPDU(*this, param);
230 }
231 
232 
OnReceivedPDU(const H245_H2250LogicalChannelParameters & param,unsigned & errorCode)233 PBoolean H323SecureRTPChannel::OnReceivedPDU(const H245_H2250LogicalChannelParameters & param,
234                                              unsigned & errorCode)
235 {
236   return rtpCallbacks.OnReceivedPDU(*this, param, errorCode);
237 }
238 
239 
OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)240 PBoolean H323SecureRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters & param)
241 {
242   return rtpCallbacks.OnReceivedAckPDU(*this, param);
243 }
244 
245 
ReadFrame(DWORD & rtpTimestamp,RTP_DataFrame & frame)246 PBoolean H323SecureRTPChannel::ReadFrame(DWORD & rtpTimestamp, RTP_DataFrame & frame)
247 {
248     if (rtpSession.ReadBufferedData(rtpTimestamp, frame)) {
249         if (m_encryption.IsInitialised() && frame.GetPayloadSize() > 0)
250            return m_encryption.ReadFrameInPlace(frame);
251         else
252            return true;
253 	} else
254 		return false;
255 }
256 
257 
WriteFrame(RTP_DataFrame & frame)258 PBoolean H323SecureRTPChannel::WriteFrame(RTP_DataFrame & frame)
259 {
260     if (!rtpSession.PreWriteData(frame))
261         return false;
262 
263     if (m_encryption.IsInitialised()) {
264         if (m_encryption.WriteFrameInPlace(frame))
265             return rtpSession.WriteData(frame);
266         else
267             return true;
268     }
269     return rtpSession.WriteData(frame);
270 }
271 
GetRTPPayloadType() const272 RTP_DataFrame::PayloadTypes H323SecureRTPChannel::GetRTPPayloadType() const
273 {
274     if (m_payload == RTP_DataFrame::IllegalPayloadType) {
275         int baseType = H323_RealTimeChannel::GetRTPPayloadType();
276         int tempPayload = 0;
277         if (baseType >= RTP_DataFrame::DynamicBase)
278             tempPayload = baseType;
279         else
280             tempPayload = 120 + capability->GetMainType();
281 
282       PRemoveConst(H323SecureRTPChannel, this)->SetDynamicRTPPayloadType(tempPayload);
283     }
284     return (RTP_DataFrame::PayloadTypes)m_payload;
285 }
286 
SetDynamicRTPPayloadType(int newType)287 PBoolean H323SecureRTPChannel::SetDynamicRTPPayloadType(int newType)
288 {
289     if (m_payload == newType)
290         return true;
291 
292     if (m_payload != RTP_DataFrame::IllegalPayloadType) {
293         PTRACE(1,"WARNING: Change Payload " << GetSessionID() << " " <<
294                  (GetDirection() == IsReceiver ? "Receive" : "Transmit") <<
295                   " to " << newType << " from " << m_payload);
296     }
297 
298     m_payload = newType;
299     return true;
300 }
301 
302 ////////////////////////////////////////////////////////////////////////////////////
303 
H323SecureChannel(H323Connection & conn,const H323Capability & cap,H323Channel * channel)304 H323SecureChannel::H323SecureChannel(H323Connection & conn, const H323Capability & cap, H323Channel * channel)
305 : H323Channel(conn,cap), m_baseChannel(channel), m_algorithm(cap.GetEncryptionAlgorithm()),
306   m_encryption((H235Capabilities*)conn.GetLocalCapabilitiesRef(), cap.GetEncryptionAlgorithm()),
307   m_payload(RTP_DataFrame::IllegalPayloadType)
308 {
309     m_baseChannel->ReplaceCapability(cap);
310     m_baseChannel->SetAssociatedChannel(this);
311 }
312 
~H323SecureChannel()313 H323SecureChannel::~H323SecureChannel()
314 {
315     if (m_baseChannel)
316         delete m_baseChannel;
317 }
318 
GetDirection() const319 H323Channel::Directions H323SecureChannel::GetDirection() const
320 {
321     if (m_baseChannel)
322         return m_baseChannel->GetDirection();
323     else
324         return H323Channel::IsBidirectional;
325 }
326 
SetInitialBandwidth()327 PBoolean H323SecureChannel::SetInitialBandwidth()
328 {
329     return (m_baseChannel && m_baseChannel->SetInitialBandwidth());
330 }
331 
SetNumber(const H323ChannelNumber & num)332 void H323SecureChannel::SetNumber(const H323ChannelNumber & num)
333 {
334     number = num;
335     if (m_baseChannel)
336         m_baseChannel->SetNumber(num);
337 }
338 
GetSessionID() const339 unsigned H323SecureChannel::GetSessionID() const
340 {
341     if (m_baseChannel)
342         return m_baseChannel->GetSessionID();
343     else
344         return 0;
345 }
346 
GetRTPPayloadType() const347 RTP_DataFrame::PayloadTypes H323SecureChannel::GetRTPPayloadType() const
348 {
349     if (m_baseChannel)
350         return m_baseChannel->GetRTPPayloadType();
351     else
352         return RTP_DataFrame::IllegalPayloadType;
353 }
354 
355 
Receive()356 void H323SecureChannel::Receive()
357 {
358     if (m_baseChannel)
359         m_baseChannel->Receive();
360 }
361 
Transmit()362 void H323SecureChannel::Transmit()
363 {
364     if (m_baseChannel)
365         m_baseChannel->Transmit();
366 }
367 
368 
Open()369 PBoolean H323SecureChannel::Open()
370 {
371     return (m_baseChannel && m_baseChannel->Open());
372 }
373 
Start()374 PBoolean H323SecureChannel::Start()
375 {
376     return (m_baseChannel && m_baseChannel->Start());
377 }
378 
CleanUpOnTermination()379 void H323SecureChannel::CleanUpOnTermination()
380 {
381     if (terminating)
382         return;
383 
384     if (m_baseChannel)
385         m_baseChannel->CleanUpOnTermination();
386 }
387 
OnSendingPDU(H245_OpenLogicalChannel & open) const388 PBoolean H323SecureChannel::OnSendingPDU(H245_OpenLogicalChannel & open) const
389 {
390   PTRACE(4, "H235Chan\tOnSendingPDU");
391 
392   if (m_baseChannel && m_baseChannel->OnSendingPDU(open)) {
393        if (connection.IsH245Master()) {
394             if (PRemoveConst(H235Session, &m_encryption)->CreateSession(true)) {
395                 open.IncludeOptionalField(H245_OpenLogicalChannel::e_encryptionSync);
396                 BuildEncryptionSync(open.m_encryptionSync,*this, m_encryption);
397             }
398         }
399        connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
400        return true;
401   }
402   return false;
403 }
404 
OnSendOpenAck(const H245_OpenLogicalChannel & open,H245_OpenLogicalChannelAck & ack) const405 void H323SecureChannel::OnSendOpenAck(const H245_OpenLogicalChannel & open, H245_OpenLogicalChannelAck & ack) const
406 {
407   PTRACE(4, "H235Chan\tOnSendOpenAck");
408 
409   if (m_baseChannel)
410       m_baseChannel->OnSendOpenAck(open,ack);
411 
412   if (connection.IsH245Master() && PRemoveConst(H235Session, &m_encryption)->CreateSession(true)) {
413         ack.IncludeOptionalField(H245_OpenLogicalChannelAck::e_encryptionSync);
414         BuildEncryptionSync(ack.m_encryptionSync,*this, m_encryption);
415         connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
416   } else
417         ack.RemoveOptionalField(H245_OpenLogicalChannelAck::e_encryptionSync);
418 }
419 
OnReceivedPDU(const H245_OpenLogicalChannel & open,unsigned & errorCode)420 PBoolean H323SecureChannel::OnReceivedPDU(const H245_OpenLogicalChannel & open, unsigned & errorCode)
421 {
422    PTRACE(4, "H235Chan\tOnRecievedPDU");
423 
424   if (m_baseChannel && !m_baseChannel->OnReceivedPDU(open,errorCode))
425        return false;
426 
427    if (open.HasOptionalField(H245_OpenLogicalChannel::e_encryptionSync)) {
428        if (m_encryption.CreateSession(false)) {
429            connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
430            return ReadEncryptionSync(open.m_encryptionSync,*this, m_encryption);
431        }
432    }
433    return true;
434 }
435 
OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)436 PBoolean H323SecureChannel::OnReceivedAckPDU(const H245_OpenLogicalChannelAck & ack)
437 {
438   PTRACE(3, "H235Chan\tOnReceiveOpenAck");
439 
440   if (m_baseChannel && !m_baseChannel->OnReceivedAckPDU(ack))
441       return false;
442 
443   if (ack.HasOptionalField(H245_OpenLogicalChannelAck::e_encryptionSync)) {
444       if (m_encryption.CreateSession(false)) {
445             connection.OnMediaEncryption(GetSessionID(), GetDirection(), CipherString(m_algorithm));
446             return ReadEncryptionSync(ack.m_encryptionSync,*this, m_encryption);
447       }
448   }
449   return true;
450 }
451 
ReadFrame(RTP_DataFrame & frame)452 PBoolean H323SecureChannel::ReadFrame(RTP_DataFrame & frame)
453 {
454     if (m_encryption.IsInitialised() && frame.GetPayloadSize() > 0)
455        return m_encryption.ReadFrameInPlace(frame);
456     else
457        return true;
458 }
459 
WriteFrame(RTP_DataFrame & frame)460 PBoolean H323SecureChannel::WriteFrame(RTP_DataFrame & frame)
461 {
462    if (m_encryption.IsInitialised())
463        return m_encryption.WriteFrameInPlace(frame);
464    else
465        return true;
466 }
467 
468 #endif   // H323_H235
469 
470 
471