1 /*
2  * h235caps.cxx
3  *
4  * H.235 Capability wrapper 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 
42 
43 #include <ptlib.h>
44 #include "openh323buildopts.h"
45 
46 #ifdef H323_H235
47 
48 #include "h235/h235caps.h"
49 #include "h235/h235chan.h"
50 #include "h235/h235support.h"
51 #include "h323.h"
52 
53 /////////////////////////////////////////////////////////////////////////////
54 
H235SecurityCapability(H323Capabilities * capabilities,unsigned capabilityNo)55 H235SecurityCapability::H235SecurityCapability(H323Capabilities * capabilities, unsigned capabilityNo)
56 : m_capabilities(capabilities), m_capNumber(capabilityNo)
57 {
58   GetMediaFormat();
59 }
60 
~H235SecurityCapability()61 H235SecurityCapability::~H235SecurityCapability()
62 {
63   m_capList.RemoveAll();
64 }
65 
Clone() const66 PObject * H235SecurityCapability::Clone() const
67 {
68   return new H235SecurityCapability(*this);
69 }
70 
GetMainType() const71 H323Capability::MainTypes H235SecurityCapability::GetMainType() const
72 {
73   return e_Security;
74 }
75 
GetSubType() const76 unsigned H235SecurityCapability::GetSubType()  const
77 {
78     return m_capNumber;
79 }
80 
GetFormatName() const81 PString H235SecurityCapability::GetFormatName() const
82 {
83     PStringStream name;
84     name << "SecCapability [" << m_capNumber << "]";
85     return name;
86 }
87 
CreateChannel(H323Connection &,H323Channel::Directions,unsigned,const H245_H2250LogicalChannelParameters *) const88 H323Channel * H235SecurityCapability::CreateChannel(H323Connection &,
89                                                       H323Channel::Directions,
90                                                       unsigned,
91                                                       const H245_H2250LogicalChannelParameters *) const
92 {
93   PTRACE(1, "Codec\tCannot create Security channel");
94   return NULL;
95 }
96 
CreateCodec(H323Codec::Direction) const97 H323Codec * H235SecurityCapability::CreateCodec(H323Codec::Direction) const
98 {
99   PTRACE(1, "Codec\tCannot create security codec");
100   return NULL;
101 }
102 
GetAlgorithmCount()103 PINDEX H235SecurityCapability::GetAlgorithmCount()
104 {
105    return m_capList.GetSize();
106 }
107 
GetAlgorithm()108 PString H235SecurityCapability::GetAlgorithm()
109 {
110    if (m_capList.GetSize() > 0)
111       return m_capList[0];
112    else
113       return PString();
114 }
115 
OnSendingPDU(H245_EncryptionAuthenticationAndIntegrity & encAuth,H323Capability::CommandType type) const116 PBoolean H235SecurityCapability::OnSendingPDU(H245_EncryptionAuthenticationAndIntegrity & encAuth, H323Capability::CommandType type) const
117 {
118   if (m_capList.GetSize() == 0)
119       return false;
120 
121   encAuth.IncludeOptionalField(H245_EncryptionAuthenticationAndIntegrity::e_encryptionCapability);
122 
123   H245_EncryptionCapability & enc = encAuth.m_encryptionCapability;
124 
125   if (type == e_OLC) {  // only the 1st (preferred) Algorithm.
126       enc.SetSize(1);
127       H245_MediaEncryptionAlgorithm & alg = enc[0];
128       alg.SetTag(H245_MediaEncryptionAlgorithm::e_algorithm);
129       PASN_ObjectId & id = alg;
130       id.SetValue(m_capList[0]);
131       return true;
132   } else if (type == e_TCS) {  // all the supported Algorithms
133       enc.SetSize(m_capList.GetSize());
134       for (PINDEX i=0; i < m_capList.GetSize(); ++i) {
135           H245_MediaEncryptionAlgorithm & alg = enc[i];
136           alg.SetTag(H245_MediaEncryptionAlgorithm::e_algorithm);
137           PASN_ObjectId & id = alg;
138           id.SetValue(m_capList[i]);
139       }
140       return true;
141   } else
142       return false;
143 }
144 
OnSendingPDU(H245_Capability & pdu) const145 PBoolean H235SecurityCapability::OnSendingPDU(H245_Capability & pdu) const
146 {
147   if (m_capList.GetSize() == 0)
148       return false;
149 
150   pdu.SetTag(H245_Capability::e_h235SecurityCapability);
151   H245_H235SecurityCapability & sec = pdu;
152 
153   if (!OnSendingPDU(sec.m_encryptionAuthenticationAndIntegrity))
154       return false;
155 
156   H245_CapabilityTableEntryNumber & capNo = sec.m_mediaCapability;
157   capNo = m_capNumber;
158 
159   return TRUE;
160 }
161 
OnSendingPDU(H245_DataType &) const162 PBoolean H235SecurityCapability::OnSendingPDU(H245_DataType &) const
163 {
164   PTRACE(1, "Codec\tCannot have Security Capability in DataType. Capability " << m_capNumber);
165   return FALSE;
166 }
167 
OnSendingPDU(H245_ModeElement &) const168 PBoolean H235SecurityCapability::OnSendingPDU(H245_ModeElement &) const
169 {
170   PTRACE(1, "Codec\tCannot have Security Capability in ModeElement");
171   return FALSE;
172 }
173 
OnReceivedPDU(const H245_Capability & pdu)174 PBoolean H235SecurityCapability::OnReceivedPDU(const H245_Capability & pdu)
175 {
176 
177   if (pdu.GetTag() != H245_Capability::e_h235SecurityCapability)
178       return false;
179 
180   const H245_H235SecurityCapability & sec = pdu;
181   if (!OnReceivedPDU(sec.m_encryptionAuthenticationAndIntegrity,e_TCS))
182       return false;
183 
184   const H245_CapabilityTableEntryNumber & capNo = sec.m_mediaCapability;
185   PRemoveConst(H235SecurityCapability, this)->SetAssociatedCapability(capNo);
186   return true;
187 }
188 
OnReceivedPDU(const H245_DataType &,PBoolean)189 PBoolean H235SecurityCapability::OnReceivedPDU(const H245_DataType &, PBoolean)
190 {
191   PTRACE(1, "Codec\tCannot have Security Capability in DataType. Capability " << m_capNumber);
192   return FALSE;
193 }
194 
SetAssociatedCapability(unsigned capNumber)195 void H235SecurityCapability::SetAssociatedCapability(unsigned capNumber)
196 {
197     m_capNumber = capNumber;
198 }
199 
MergeAlgorithms(const PStringArray & remote)200 PBoolean H235SecurityCapability::MergeAlgorithms(const PStringArray & remote)
201 {
202     PStringArray toKeep;
203     for (PINDEX i=0; i< m_capList.GetSize(); ++i) {
204        for (PINDEX j=0; j< remote.GetSize(); ++j) {
205            if (m_capList[i] == remote[j]) {
206                toKeep.AppendString(m_capList[i]);
207                break;
208            }
209        }
210     }
211     m_capList.SetSize(0);
212     m_capList = toKeep;
213 
214     if (m_capList.GetSize() > 0) {
215         if (m_capabilities) {
216             H323Capability * cap = m_capabilities->FindCapability(m_capNumber);
217             if (cap)
218                 cap->SetEncryptionAlgorithm(m_capList[0]);
219         }
220         return true;
221     }
222     return false;
223 }
224 
OnReceivedPDU(const H245_EncryptionAuthenticationAndIntegrity & encAuth,H323Capability::CommandType type) const225 PBoolean H235SecurityCapability::OnReceivedPDU(const H245_EncryptionAuthenticationAndIntegrity & encAuth,
226                                                H323Capability::CommandType type) const
227 {
228     if (!encAuth.HasOptionalField(H245_EncryptionAuthenticationAndIntegrity::e_encryptionCapability))
229             return false;
230 
231     const H245_EncryptionCapability & enc = encAuth.m_encryptionCapability;
232     if (type == e_OLC) {
233         if (m_capList.GetSize()==0 && enc.GetSize() > 0) {
234             PTRACE(4,"H235\tLOGIC ERROR No Agreed algorithms loaded!");
235         }
236         return true;
237     }
238 
239     PStringArray other;
240       for (PINDEX i=0; i < enc.GetSize(); ++i) {
241           const H245_MediaEncryptionAlgorithm & alg = enc[i];
242           if (alg.GetTag() == H245_MediaEncryptionAlgorithm::e_algorithm) {
243                   const PASN_ObjectId & id = alg;
244                   other.AppendString(id.AsString());
245           }
246       }
247 
248     return PRemoveConst(H235SecurityCapability, this)->MergeAlgorithms(other);
249 }
250 
GetDefaultSessionID() const251 unsigned H235SecurityCapability::GetDefaultSessionID() const
252 {
253   return OpalMediaFormat::NonRTPSessionID;
254 }
255 
IsUsable(const H323Connection & connection) const256 PBoolean H235SecurityCapability::IsUsable(const H323Connection & connection) const
257 {
258    const H235Capabilities & caps = (const H235Capabilities &)connection.GetLocalCapabilities();
259    return caps.GetAlgorithms(m_capList);
260 }
261 
262 /////////////////////////////////////////////////////////////////////////////
263 
H323SecureRealTimeCapability(H323Capability * childCapability,H323Capabilities * capabilities,unsigned secNo,PBoolean active)264 H323SecureRealTimeCapability::H323SecureRealTimeCapability(H323Capability * childCapability, H323Capabilities * capabilities, unsigned secNo, PBoolean active)
265                 : ChildCapability(childCapability), chtype(H235ChNew), m_active(active),
266                   m_capabilities(capabilities), m_secNo(secNo),  nrtpqos(NULL)
267 {
268     assignedCapabilityNumber = ChildCapability->GetCapabilityNumber();
269 }
270 
271 
H323SecureRealTimeCapability(RTP_QOS * _rtpqos,H323Capability * childCapability)272 H323SecureRealTimeCapability::H323SecureRealTimeCapability(RTP_QOS * _rtpqos,H323Capability * childCapability)
273                 : ChildCapability(childCapability), chtype(H235ChNew), m_active(false),
274                   m_capabilities(NULL), m_secNo(0), nrtpqos(_rtpqos)
275 {
276 }
277 
~H323SecureRealTimeCapability()278 H323SecureRealTimeCapability::~H323SecureRealTimeCapability()
279 {
280     delete ChildCapability;
281 }
282 
283 
AttachQoS(RTP_QOS * _rtpqos)284 void H323SecureRealTimeCapability::AttachQoS(RTP_QOS * _rtpqos)
285 {
286 #ifdef P_QOS
287       delete nrtpqos;
288       nrtpqos = _rtpqos;
289 #endif
290 }
291 
SetAssociatedCapability(unsigned _secNo)292 void H323SecureRealTimeCapability::SetAssociatedCapability(unsigned _secNo)
293 {
294     m_secNo = _secNo;
295 }
296 
CreateChannel(H323Connection & connection,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters * param) const297 H323Channel * H323SecureRealTimeCapability::CreateChannel(H323Connection & connection,
298                                                     H323Channel::Directions dir,
299                                                     unsigned sessionID,
300                                  const H245_H2250LogicalChannelParameters * param) const
301 {
302 
303   // create a standard RTP channel if we don't have a DH token
304   H235Capabilities * caps = dynamic_cast<H235Capabilities*>(connection.GetLocalCapabilitiesRef());
305   if (!caps || !caps->GetDiffieHellMan())
306     return connection.CreateRealTimeLogicalChannel(*ChildCapability, dir, sessionID, param, nrtpqos);
307 
308   // Support for encrypted external RTP Channel
309   H323Channel * extRTPChannel = connection.CreateRealTimeLogicalChannel(*this, dir, sessionID, param, nrtpqos);
310   if (extRTPChannel)
311       return extRTPChannel;
312 
313   RTP_Session * session = NULL;              // Session
314   if (
315 #ifdef H323_H46026
316      connection.H46026IsMediaTunneled() ||
317 #endif
318      !param || !param->HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel)) {
319     // Make a fake transport address from the connection so gets initialised with
320     // the transport type (IP, IPX, multicast etc).
321     H245_TransportAddress addr;
322     connection.GetControlChannel().SetUpTransportPDU(addr, H323Transport::UseLocalTSAP);
323     session = connection.UseSession(sessionID, addr, dir, nrtpqos);
324   } else {
325     session = connection.UseSession(param->m_sessionID, param->m_mediaControlChannel, dir, nrtpqos);
326   }
327 
328   if (!session)
329     return NULL;
330 
331   return new H323SecureRTPChannel(connection, *this, dir, *session);
332 }
333 
GetCapabilityNumber() const334 unsigned H323SecureRealTimeCapability::GetCapabilityNumber() const
335 {
336     return ChildCapability->GetCapabilityNumber();
337 };
338 
SetCapabilityNumber(unsigned num)339 void H323SecureRealTimeCapability::SetCapabilityNumber(unsigned num)
340 {
341     assignedCapabilityNumber = num;
342     ChildCapability->SetCapabilityNumber(num);
343 }
344 
SetCapabilityList(H323Capabilities * capabilities)345 void H323SecureRealTimeCapability::SetCapabilityList(H323Capabilities * capabilities)
346 {
347     m_capabilities = capabilities;
348 }
349 
SetEncryptionActive(PBoolean active)350 void H323SecureRealTimeCapability::SetEncryptionActive(PBoolean active)
351 {
352     m_active = active;
353 }
354 
IsEncryptionActive() const355 PBoolean H323SecureRealTimeCapability::IsEncryptionActive() const
356 {
357     return m_active;
358 }
359 
SetEncryptionAlgorithm(const PString & alg)360 void H323SecureRealTimeCapability::SetEncryptionAlgorithm(const PString & alg)
361 {
362     m_algorithm = alg;
363 }
364 
GetEncryptionAlgorithm() const365 const PString & H323SecureRealTimeCapability::GetEncryptionAlgorithm() const
366 {
367    return m_algorithm;
368 }
369 
GetMediaFormat() const370 const OpalMediaFormat & H323SecureRealTimeCapability::GetMediaFormat() const
371 {
372    return ChildCapability->GetMediaFormat();
373 }
374 
GetWritableMediaFormat()375 OpalMediaFormat & H323SecureRealTimeCapability::GetWritableMediaFormat()
376 {
377    return ChildCapability->GetWritableMediaFormat();
378 }
379 
380 /////////////////////////////////////////////////////////////////////////////
381 
H323SecureCapability(H323Capability & childCapability,H235ChType Ch,H323Capabilities * capabilities,unsigned secNo,PBoolean active)382 H323SecureCapability::H323SecureCapability(H323Capability & childCapability,
383                                                      H235ChType Ch,
384                                                      H323Capabilities * capabilities,
385                                                      unsigned secNo,
386                                                      PBoolean active
387                                                      )
388    : H323SecureRealTimeCapability((H323Capability *)childCapability.Clone(), capabilities, secNo, active)
389 {
390     chtype = Ch;
391 }
392 
GetMainType() const393 H323Capability::MainTypes H323SecureCapability::GetMainType() const
394 {
395     return ChildCapability->GetMainType();
396 }
397 
398 
Clone() const399 PObject * H323SecureCapability::Clone() const
400 {
401     PTRACE(4, "H235RTP\tCloning Capability: " << GetFormatName());
402 
403     H235ChType ch = H235ChNew;
404 
405     switch (chtype) {
406     case H235ChNew:
407            ch = H235ChClone;
408         break;
409     case H235ChClone:
410            ch = H235Channel;
411         break;
412     case H235Channel:
413            ch = H235Channel;
414         break;
415     }
416 
417   return new H323SecureCapability(*ChildCapability, ch, m_capabilities, m_secNo, m_active);
418 }
419 
IsMatch(const PASN_Choice & subTypePDU) const420 PBoolean H323SecureCapability::IsMatch(const PASN_Choice & subTypePDU) const
421 {
422 
423     if (PIsDescendant(&subTypePDU, H245_AudioCapability) &&
424        ChildCapability->GetMainType() == H323Capability::e_Audio) {
425           const H245_AudioCapability & audio = (const H245_AudioCapability &)subTypePDU;
426           return ChildCapability->IsMatch(audio);
427     }
428 
429     if (PIsDescendant(&subTypePDU, H245_VideoCapability) &&
430        ChildCapability->GetMainType() == H323Capability::e_Video) {
431           const H245_VideoCapability & video = (const H245_VideoCapability &)subTypePDU;
432           return ChildCapability->IsMatch(video);
433     }
434 
435     if (PIsDescendant(&subTypePDU, H245_DataApplicationCapability_application) &&
436        ChildCapability->GetMainType() == H323Capability::e_Data) {
437           const H245_DataApplicationCapability_application & data =
438                          (const H245_DataApplicationCapability_application &)subTypePDU;
439           return ChildCapability->IsMatch(data);
440     }
441 
442     if (PIsDescendant(&subTypePDU, H245_H235Media_mediaType)) {
443           const H245_H235Media_mediaType & data =
444                           (const H245_H235Media_mediaType &)subTypePDU;
445           return IsSubMatch(data);
446     }
447     return false;
448 }
449 
450 
IsSubMatch(const PASN_Choice & subTypePDU) const451 PBoolean H323SecureCapability::IsSubMatch(const PASN_Choice & subTypePDU) const
452 {
453     const H245_H235Media_mediaType & dataType = (const H245_H235Media_mediaType &)subTypePDU;
454     if (dataType.GetTag() == H245_H235Media_mediaType::e_audioData &&
455        ChildCapability->GetMainType() == H323Capability::e_Audio) {
456           const H245_AudioCapability & audio = dataType;
457           return ChildCapability->IsMatch(audio);
458     }
459 
460     if (dataType.GetTag() == H245_H235Media_mediaType::e_videoData &&
461        ChildCapability->GetMainType() == H323Capability::e_Video) {
462           const H245_VideoCapability & video = dataType;
463           return ChildCapability->IsMatch(video);
464     }
465 
466     return false;
467 }
468 
Compare(const PObject & obj) const469 PObject::Comparison H323SecureCapability::Compare(const PObject & obj) const
470 {
471   if (!PIsDescendant(&obj, H323SecureCapability))
472     return LessThan;
473 
474   Comparison result = H323Capability::Compare(obj);
475   if (result != EqualTo)
476     return result;
477 
478   const H323SecureCapability & other = (const H323SecureCapability &)obj;
479 
480   return ChildCapability->Compare(*(other.GetChildCapability()));
481 }
482 
GetDefaultSessionID() const483 unsigned H323SecureCapability::GetDefaultSessionID() const
484 {
485     return ChildCapability->GetDefaultSessionID();
486 }
487 
488 ////////////////////////////////////////////////////////////////////////
489 // PDU Sending
490 
OnSendingPDU(H245_ModeElement & mode) const491 PBoolean H323SecureCapability::OnSendingPDU(H245_ModeElement & mode) const
492 {
493     switch (ChildCapability->GetMainType()) {
494         case H323Capability::e_Audio:
495             return ((H323AudioCapability *)ChildCapability)->OnSendingPDU(mode);
496         case H323Capability::e_Video:
497 #ifdef H323_VIDEO
498             return ((H323VideoCapability *)ChildCapability)->OnSendingPDU(mode);
499 #endif // H323_VIDEO
500         case H323Capability::e_Data:
501         default:
502             return false;
503     }
504 }
505 
OnSendingPDU(H245_DataType & dataType) const506 PBoolean H323SecureCapability::OnSendingPDU(H245_DataType & dataType) const
507 {
508     // find the matching H235SecurityCapability to get the agreed algorithms
509     // if not found or no matching algorithm then assume no encryption.
510     H235SecurityCapability * secCap = NULL;
511     if (m_capabilities) {
512         secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
513         if (secCap && secCap->GetAlgorithmCount() > 0) {
514            (PRemoveConst(H323SecureCapability,this))->SetEncryptionActive(true);
515            (PRemoveConst(H323SecureCapability,this))->SetEncryptionAlgorithm(secCap->GetAlgorithm());
516         }
517     }
518 
519     if (!IsEncryptionActive()) {
520         unsigned txFramesInPacket =0;
521         switch (ChildCapability->GetMainType()) {
522             case H323Capability::e_Audio:
523                 dataType.SetTag(H245_DataType::e_audioData);
524                 txFramesInPacket = ((H323AudioCapability *)ChildCapability)->GetTxFramesInPacket();
525                 return ((H323AudioCapability *)ChildCapability)->OnSendingPDU((H245_AudioCapability &)dataType, txFramesInPacket, e_OLC);
526             case H323Capability::e_Video:
527 #ifdef H323_VIDEO
528                 dataType.SetTag(H245_DataType::e_videoData);
529                 return ((H323VideoCapability *)ChildCapability)->OnSendingPDU((H245_VideoCapability &)dataType, e_OLC);
530 #endif // H323_VIDEO
531             case H323Capability::e_Data:
532             default:
533                 break;
534         }
535         return false;
536     }
537 
538     dataType.SetTag(H245_DataType::e_h235Media);
539     H245_H235Media & h235Media = dataType;
540     // Load the algorithm
541     if (secCap)
542       secCap->OnSendingPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC);
543 
544     H245_H235Media_mediaType & cType = h235Media.m_mediaType;
545     unsigned txFramesInPacket =0;
546     switch (ChildCapability->GetMainType()) {
547         case H323Capability::e_Audio:
548             cType.SetTag(H245_H235Media_mediaType::e_audioData);
549             txFramesInPacket = ((H323AudioCapability *)ChildCapability)->GetTxFramesInPacket();
550             return ((H323AudioCapability *)ChildCapability)->OnSendingPDU((H245_AudioCapability &)cType, txFramesInPacket, e_OLC);
551         case H323Capability::e_Video:
552 #ifdef H323_VIDEO
553             cType.SetTag(H245_H235Media_mediaType::e_videoData);
554             return ((H323VideoCapability *)ChildCapability)->OnSendingPDU((H245_VideoCapability &)cType, e_OLC);
555 #endif // H323_VIDEO
556         case H323Capability::e_Data:
557         default:
558             break;
559     }
560     return false;
561 }
562 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)563 PBoolean H323SecureCapability::OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)
564 {
565     if (dataType.GetTag() != H245_DataType::e_h235Media)
566         return ChildCapability->OnReceivedPDU(dataType, receiver);
567 
568     const H245_H235Media & h235Media = dataType;
569 
570     if (m_capabilities) {
571         H235SecurityCapability * secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
572         if (!secCap || !secCap->OnReceivedPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC)) {
573             PTRACE(4,"H235\tFailed to locate security capability " << m_secNo);
574             return false;
575         }
576         if (secCap && secCap->GetAlgorithmCount() > 0) {
577             SetEncryptionAlgorithm(secCap->GetAlgorithm());
578             SetEncryptionActive(true);
579         }
580     }
581 
582     const H245_H235Media_mediaType & mediaType = h235Media.m_mediaType;
583 
584     switch (ChildCapability->GetMainType()) {
585         case H323Capability::e_Audio:
586             if (mediaType.GetTag() == H245_H235Media_mediaType::e_audioData) {
587                unsigned packetSize = (receiver) ?
588                    ChildCapability->GetRxFramesInPacket() : ChildCapability->GetTxFramesInPacket();
589                return ((H323AudioCapability *)ChildCapability)->OnReceivedPDU((const H245_AudioCapability &)mediaType, packetSize, e_OLC);
590             }
591             break;
592 
593         case H323Capability::e_Video:
594 #ifdef H323_VIDEO
595             if (mediaType.GetTag() == H245_H235Media_mediaType::e_videoData)
596                return ((H323VideoCapability *)ChildCapability)->OnReceivedPDU((const H245_VideoCapability &)mediaType, e_OLC);
597             break;
598 #endif // H323_VIDEO
599 
600         case H323Capability::e_Data:
601         default:
602             break;
603     }
604 
605     return false;
606 }
607 
608 //////////////////////////////////////////////////////////////////////////////
609 // Child Capability Intercept
610 
OnSendingPDU(H245_Capability & pdu) const611 PBoolean H323SecureCapability::OnSendingPDU(H245_Capability & pdu) const
612 {
613     switch (ChildCapability->GetMainType()) {
614         case H323Capability::e_Audio:
615             return ((H323AudioCapability *)ChildCapability)->OnSendingPDU(pdu);
616         case H323Capability::e_Video:
617 #ifdef H323_VIDEO
618             return ((H323VideoCapability *)ChildCapability)->OnSendingPDU(pdu);
619 #endif // H323_VIDEO
620         case H323Capability::e_Data:
621         case H323Capability::e_UserInput:
622         case H323Capability::e_ExtendVideo:
623         default:
624             return false;
625     }
626 }
627 
OnReceivedPDU(const H245_Capability & pdu)628 PBoolean H323SecureCapability::OnReceivedPDU(const H245_Capability & pdu)
629 {
630     switch (ChildCapability->GetMainType()) {
631         case H323Capability::e_Audio:
632             return ((H323AudioCapability *)ChildCapability)->OnReceivedPDU(pdu);
633         case H323Capability::e_Video:
634 #ifdef H323_VIDEO
635             return ((H323VideoCapability *)ChildCapability)->OnReceivedPDU(pdu);
636 #endif // H323_VIDEO
637         case H323Capability::e_Data:
638         case H323Capability::e_UserInput:
639         case H323Capability::e_ExtendVideo:
640         default:
641             return false;
642     }
643 }
644 
645 
GetFormatName() const646 PString H323SecureCapability::GetFormatName() const
647 {
648   return ChildCapability->GetFormatName() + (m_active ? " #" : "");
649 }
650 
GetSubType() const651 unsigned H323SecureCapability::GetSubType() const
652 {
653   return ChildCapability->GetSubType();
654 }
655 
GetIdentifier() const656 PString H323SecureCapability::GetIdentifier() const
657 {
658   return ChildCapability->GetIdentifier();
659 }
660 
CreateCodec(H323Codec::Direction direction) const661 H323Codec * H323SecureCapability::CreateCodec(H323Codec::Direction direction) const
662 {
663     return ChildCapability->CreateCodec(direction);
664 }
665 
666 
667 /////////////////////////////////////////////////////////////////////////////
668 // For extended
669 
H323SecureExtendedCapability(H323Capability * childCapability,enum H235ChType Ch,H323Capabilities * capabilities,unsigned secNo,PBoolean active)670 H323SecureExtendedCapability::H323SecureExtendedCapability(H323Capability * childCapability, enum H235ChType Ch, H323Capabilities * capabilities, unsigned secNo, PBoolean active)
671                 : H323ExtendedVideoCapability(""),
672                   ChildCapability(childCapability), chtype(Ch), m_active(active),
673                   m_capabilities(capabilities), m_secNo(secNo),  nrtpqos(NULL)
674 {
675     assignedCapabilityNumber = ChildCapability->GetCapabilityNumber();
676 }
677 
678 
H323SecureExtendedCapability(RTP_QOS * _rtpqos,H323Capability * childCapability)679 H323SecureExtendedCapability::H323SecureExtendedCapability(RTP_QOS * _rtpqos,H323Capability * childCapability)
680                 : H323ExtendedVideoCapability(""),
681                   ChildCapability(childCapability), chtype(H235ChNew), m_active(false),
682                   m_capabilities(NULL), m_secNo(0), nrtpqos(_rtpqos)
683 {
684 }
685 
~H323SecureExtendedCapability()686 H323SecureExtendedCapability::~H323SecureExtendedCapability()
687 {
688     delete ChildCapability;
689 }
690 
691 
AttachQoS(RTP_QOS * _rtpqos)692 void H323SecureExtendedCapability::AttachQoS(RTP_QOS * _rtpqos)
693 {
694 #ifdef P_QOS
695       delete nrtpqos;
696       nrtpqos = _rtpqos;
697 #endif
698 }
699 
SetAssociatedCapability(unsigned _secNo)700 void H323SecureExtendedCapability::SetAssociatedCapability(unsigned _secNo)
701 {
702     m_secNo = _secNo;
703 }
704 
CreateChannel(H323Connection & connection,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters * param) const705 H323Channel * H323SecureExtendedCapability::CreateChannel(H323Connection & connection,
706                                                     H323Channel::Directions dir,
707                                                     unsigned sessionID,
708                                  const H245_H2250LogicalChannelParameters * param) const
709 {
710 
711   // create a standard RTP channel if we don't have a DH token
712   H235Capabilities * caps = dynamic_cast<H235Capabilities*>(connection.GetLocalCapabilitiesRef());
713   if (!caps || !caps->GetDiffieHellMan())
714     return connection.CreateRealTimeLogicalChannel(*ChildCapability, dir, sessionID, param, nrtpqos);
715 
716   // Support for encrypted external RTP Channel
717   H323Channel * extRTPChannel = connection.CreateRealTimeLogicalChannel(*this, dir, sessionID, param, nrtpqos);
718   if (extRTPChannel)
719       return extRTPChannel;
720 
721   RTP_Session * session = NULL;              // Session
722   if (
723 #ifdef H323_H46026
724      connection.H46026IsMediaTunneled() ||
725 #endif
726      !param || !param->HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel)) {
727     // Make a fake transport address from the connection so gets initialised with
728     // the transport type (IP, IPX, multicast etc).
729     H245_TransportAddress addr;
730     connection.GetControlChannel().SetUpTransportPDU(addr, H323Transport::UseLocalTSAP);
731     session = connection.UseSession(sessionID, addr, dir, nrtpqos);
732   } else {
733     session = connection.UseSession(param->m_sessionID, param->m_mediaControlChannel, dir, nrtpqos);
734   }
735 
736   if (!session)
737     return NULL;
738 
739   return new H323SecureRTPChannel(connection, *this, dir, *session);
740 }
741 
GetCapabilityNumber() const742 unsigned H323SecureExtendedCapability::GetCapabilityNumber() const
743 {
744     return ChildCapability->GetCapabilityNumber();
745 };
746 
SetCapabilityNumber(unsigned num)747 void H323SecureExtendedCapability::SetCapabilityNumber(unsigned num)
748 {
749     assignedCapabilityNumber = num;
750     ChildCapability->SetCapabilityNumber(num);
751 }
752 
SetCapabilityList(H323Capabilities * capabilities)753 void H323SecureExtendedCapability::SetCapabilityList(H323Capabilities * capabilities)
754 {
755     m_capabilities = capabilities;
756 }
757 
SetEncryptionActive(PBoolean active)758 void H323SecureExtendedCapability::SetEncryptionActive(PBoolean active)
759 {
760     m_active = active;
761 }
762 
IsEncryptionActive() const763 PBoolean H323SecureExtendedCapability::IsEncryptionActive() const
764 {
765     return m_active;
766 }
767 
SetEncryptionAlgorithm(const PString & alg)768 void H323SecureExtendedCapability::SetEncryptionAlgorithm(const PString & alg)
769 {
770     m_algorithm = alg;
771 }
772 
GetEncryptionAlgorithm() const773 const PString & H323SecureExtendedCapability::GetEncryptionAlgorithm() const
774 {
775    return m_algorithm;
776 }
777 
GetMediaFormat() const778 const OpalMediaFormat & H323SecureExtendedCapability::GetMediaFormat() const
779 {
780    return ChildCapability->GetMediaFormat();
781 }
782 
GetWritableMediaFormat()783 OpalMediaFormat & H323SecureExtendedCapability::GetWritableMediaFormat()
784 {
785    return ChildCapability->GetWritableMediaFormat();
786 }
787 
GetMainType() const788 H323Capability::MainTypes H323SecureExtendedCapability::GetMainType() const
789 {
790     return ChildCapability->GetMainType();
791 }
792 
Clone() const793 PObject * H323SecureExtendedCapability::Clone() const
794 {
795     PTRACE(3, "H235ExtRTP\tCloning Capability: " << GetFormatName());
796 
797     H235ChType ch = H235ChNew;
798 
799     switch (chtype) {
800     case H235ChNew:
801            ch = H235ChClone;
802         break;
803     case H235ChClone:
804            ch = H235Channel;
805         break;
806     case H235Channel:
807            ch = H235Channel;
808         break;
809     }
810 
811   return new H323SecureExtendedCapability((H323Capability *)ChildCapability->Clone(), ch, m_capabilities, m_secNo, m_active);
812 }
813 
IsMatch(const PASN_Choice & subTypePDU) const814 PBoolean H323SecureExtendedCapability::IsMatch(const PASN_Choice & subTypePDU) const
815 {
816     if (PIsDescendant(&subTypePDU, H245_VideoCapability) &&
817        ChildCapability->GetMainType() == H323Capability::e_Video) {
818           const H245_VideoCapability & video = (const H245_VideoCapability &)subTypePDU;
819           return ChildCapability->IsMatch(video);
820     }
821 
822     if (PIsDescendant(&subTypePDU, H245_H235Media_mediaType)) {
823           const H245_H235Media_mediaType & data =
824                           (const H245_H235Media_mediaType &)subTypePDU;
825           return IsSubMatch(data);
826     }
827     return false;
828 }
829 
830 
IsSubMatch(const PASN_Choice & subTypePDU) const831 PBoolean H323SecureExtendedCapability::IsSubMatch(const PASN_Choice & subTypePDU) const
832 {
833     const H245_H235Media_mediaType & dataType = (const H245_H235Media_mediaType &)subTypePDU;
834 
835     if (dataType.GetTag() == H245_H235Media_mediaType::e_videoData &&
836        ChildCapability->GetMainType() == H323Capability::e_Video) {
837           const H245_VideoCapability & video = dataType;
838           return ChildCapability->IsMatch(video);
839     }
840 
841     return false;
842 }
843 
Compare(const PObject & obj) const844 PObject::Comparison H323SecureExtendedCapability::Compare(const PObject & obj) const
845 {
846   if (!PIsDescendant(&obj, H323SecureExtendedCapability))
847     return LessThan;
848 
849   Comparison result = H323Capability::Compare(obj);
850   if (result != EqualTo)
851     return result;
852 
853   const H323SecureExtendedCapability & other = (const H323SecureExtendedCapability &)obj;
854 
855   return ChildCapability->Compare(*(other.GetChildCapability()));
856 }
857 
GetDefaultSessionID() const858 unsigned H323SecureExtendedCapability::GetDefaultSessionID() const
859 {
860     return ChildCapability->GetDefaultSessionID();
861 }
862 
863 ////////////////////////////////////////////////////////////////////////
864 // PDU Sending
865 
OnSendingPDU(H245_ModeElement & mode) const866 PBoolean H323SecureExtendedCapability::OnSendingPDU(H245_ModeElement & mode) const
867 {
868     switch (ChildCapability->GetMainType()) {
869         case H323Capability::e_Video:
870 #ifdef H323_VIDEO
871             return ((H323ExtendedVideoCapability *)ChildCapability)->OnSendingPDU(mode);
872 #endif // H323_VIDEO
873         case H323Capability::e_Audio:
874         case H323Capability::e_Data:
875         default:
876             return false;
877     }
878 }
879 
OnSendingPDU(H245_DataType & dataType) const880 PBoolean H323SecureExtendedCapability::OnSendingPDU(H245_DataType & dataType) const
881 {
882     // find the matching H235SecurityCapability to get the agreed algorithms
883     // if not found or no matching algorithm then assume no encryption.
884     H235SecurityCapability * secCap = NULL;
885     if (m_capabilities) {
886         secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
887         if (secCap && secCap->GetAlgorithmCount() > 0) {
888            (PRemoveConst(H323SecureExtendedCapability,this))->SetEncryptionActive(true);
889            (PRemoveConst(H323SecureExtendedCapability,this))->SetEncryptionAlgorithm(secCap->GetAlgorithm());
890         }
891     }
892 
893     if (!IsEncryptionActive()) {
894         switch (ChildCapability->GetMainType()) {
895             case H323Capability::e_Video:
896 #ifdef H323_VIDEO
897                 dataType.SetTag(H245_DataType::e_videoData);
898                 return ((H323CodecExtendedVideoCapability *)ChildCapability)->OnSendingPDU((H245_VideoCapability &)dataType, e_OLC);
899 #endif // H323_VIDEO
900             case H323Capability::e_Audio:
901             case H323Capability::e_Data:
902             default:
903                 break;
904         }
905         return false;
906     }
907 
908     dataType.SetTag(H245_DataType::e_h235Media);
909     H245_H235Media & h235Media = dataType;
910     // Load the algorithm
911     if (secCap)
912       secCap->OnSendingPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC);
913 
914     H245_H235Media_mediaType & cType = h235Media.m_mediaType;
915     switch (ChildCapability->GetMainType()) {
916         case H323Capability::e_Video:
917 #ifdef H323_VIDEO
918             cType.SetTag(H245_H235Media_mediaType::e_videoData);
919             return ((H323CodecExtendedVideoCapability *)ChildCapability)->OnSendingPDU((H245_VideoCapability &)cType, e_OLC);
920 #endif // H323_VIDEO
921         case H323Capability::e_Audio:
922         case H323Capability::e_Data:
923         default:
924             break;
925     }
926     return false;
927 }
928 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)929 PBoolean H323SecureExtendedCapability::OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)
930 {
931     if (dataType.GetTag() != H245_DataType::e_h235Media)
932         return ChildCapability->OnReceivedPDU(dataType, receiver);
933 
934     const H245_H235Media & h235Media = dataType;
935 
936     if (m_capabilities) {
937         H235SecurityCapability * secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
938         if (!secCap || !secCap->OnReceivedPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC)) {
939             PTRACE(4,"H235\tFailed to locate security capability " << m_secNo);
940             return false;
941         }
942         if (secCap && secCap->GetAlgorithmCount() > 0) {
943             SetEncryptionAlgorithm(secCap->GetAlgorithm());
944             SetEncryptionActive(true);
945         }
946     }
947 
948     const H245_H235Media_mediaType & mediaType = h235Media.m_mediaType;
949 
950     switch (ChildCapability->GetMainType()) {
951         case H323Capability::e_Video:
952 #ifdef H323_VIDEO
953             if (mediaType.GetTag() == H245_H235Media_mediaType::e_videoData)
954                return ((H323CodecExtendedVideoCapability *)ChildCapability)->OnReceivedPDU((const H245_VideoCapability &)mediaType);
955             break;
956 #endif // H323_VIDEO
957 
958         case H323Capability::e_Audio:
959         case H323Capability::e_Data:
960         default:
961             break;
962     }
963     return false;
964 }
965 
966 //////////////////////////////////////////////////////////////////////////////
967 // Child Capability Intercept
968 
OnSendingPDU(H245_Capability & pdu) const969 PBoolean H323SecureExtendedCapability::OnSendingPDU(H245_Capability & pdu) const
970 {
971     switch (ChildCapability->GetMainType()) {
972         case H323Capability::e_Video:
973 #ifdef H323_VIDEO
974             return ((H323CodecExtendedVideoCapability *)ChildCapability)->OnSendingPDU(pdu);
975 #endif // H323_VIDEO
976         case H323Capability::e_Audio:
977         case H323Capability::e_Data:
978         case H323Capability::e_UserInput:
979         case H323Capability::e_ExtendVideo:
980         default:
981             return false;
982     }
983 }
984 
OnReceivedPDU(const H245_Capability & pdu)985 PBoolean H323SecureExtendedCapability::OnReceivedPDU(const H245_Capability & pdu)
986 {
987     switch (ChildCapability->GetMainType()) {
988         case H323Capability::e_Video:
989 #ifdef H323_VIDEO
990             return ((H323CodecExtendedVideoCapability *)ChildCapability)->OnReceivedPDU(pdu);
991 #endif // H323_VIDEO
992         case H323Capability::e_Audio:
993         case H323Capability::e_Data:
994         case H323Capability::e_UserInput:
995         case H323Capability::e_ExtendVideo:
996         default:
997             return false;
998     }
999 }
1000 
1001 
GetFormatName() const1002 PString H323SecureExtendedCapability::GetFormatName() const
1003 {
1004   return ChildCapability->GetFormatName() + (m_active ? " #" : "");
1005 }
1006 
GetSubType() const1007 unsigned H323SecureExtendedCapability::GetSubType() const
1008 {
1009   return ChildCapability->GetSubType();
1010 }
1011 
GetIdentifier() const1012 PString H323SecureExtendedCapability::GetIdentifier() const
1013 {
1014   return ChildCapability->GetIdentifier();
1015 }
1016 
CreateCodec(H323Codec::Direction direction) const1017 H323Codec * H323SecureExtendedCapability::CreateCodec(H323Codec::Direction direction) const
1018 {
1019     return ChildCapability->CreateCodec(direction);
1020 }
1021 
GetCapabilities() const1022 const H323Capabilities & H323SecureExtendedCapability::GetCapabilities() const
1023 {
1024     H323ExtendedVideoCapability* extCap = dynamic_cast<H323ExtendedVideoCapability*>(ChildCapability);
1025     if (extCap)
1026         return extCap->GetCapabilities();
1027     else
1028         return extCapabilities;
1029 }
1030 
1031 /////////////////////////////////////////////////////////////////////////////
1032 
1033 
H323SecureDataCapability(H323Capability & childCapability,enum H235ChType Ch,H323Capabilities * capabilities,unsigned secNo,PBoolean active)1034 H323SecureDataCapability::H323SecureDataCapability(H323Capability & childCapability, enum H235ChType Ch, H323Capabilities * capabilities,
1035                            unsigned secNo, PBoolean active )
1036 : ChildCapability((H323Capability *)childCapability.Clone()), chtype(Ch), m_active(active), m_capabilities(capabilities),
1037   m_secNo(secNo), m_algorithm(PString())
1038 {
1039     assignedCapabilityNumber = childCapability.GetCapabilityNumber();
1040 }
1041 
~H323SecureDataCapability()1042 H323SecureDataCapability::~H323SecureDataCapability()
1043 {
1044     delete ChildCapability;
1045 }
1046 
SetAssociatedCapability(unsigned _secNo)1047 void H323SecureDataCapability::SetAssociatedCapability(unsigned _secNo)
1048 {
1049     m_secNo = _secNo;
1050 }
1051 
1052 
Compare(const PObject & obj) const1053 PObject::Comparison H323SecureDataCapability::Compare(const PObject & obj) const
1054 {
1055   if (!PIsDescendant(&obj, H323SecureDataCapability))
1056     return LessThan;
1057 
1058   Comparison result = H323Capability::Compare(obj);
1059   if (result != EqualTo)
1060     return result;
1061 
1062   const H323SecureDataCapability & other = (const H323SecureDataCapability &)obj;
1063 
1064   return ChildCapability->Compare(*(other.GetChildCapability()));
1065 }
1066 
Clone() const1067 PObject * H323SecureDataCapability::Clone() const
1068 {
1069     PTRACE(4, "H235Data\tCloning Capability: " << GetFormatName());
1070 
1071     H235ChType ch = H235ChNew;
1072     switch (chtype) {
1073     case H235ChNew:
1074            ch = H235ChClone;
1075         break;
1076     case H235ChClone:
1077            ch = H235Channel;
1078         break;
1079     case H235Channel:
1080            ch = H235Channel;
1081         break;
1082     }
1083     return new H323SecureDataCapability(*ChildCapability, ch, m_capabilities, m_secNo, m_active);
1084 }
1085 
1086 
GetSubType() const1087 unsigned H323SecureDataCapability::GetSubType() const
1088 {
1089   return ChildCapability->GetSubType();
1090 }
1091 
1092 
GetFormatName() const1093 PString H323SecureDataCapability::GetFormatName() const
1094 {
1095   return ChildCapability->GetFormatName() + (m_active ? " #" : "");
1096 }
1097 
1098 
IsMatch(const PASN_Choice & subTypePDU) const1099 PBoolean H323SecureDataCapability::IsMatch(const PASN_Choice & subTypePDU) const
1100 {
1101     if (PIsDescendant(&subTypePDU, H245_DataApplicationCapability_application) &&
1102        ChildCapability->GetMainType() == H323Capability::e_Data) {
1103           const H245_DataApplicationCapability_application & data =
1104                          (const H245_DataApplicationCapability_application &)subTypePDU;
1105           return ChildCapability->IsMatch(data);
1106     }
1107 
1108     if (PIsDescendant(&subTypePDU, H245_H235Media_mediaType)) {
1109           const H245_H235Media_mediaType & data =
1110                           (const H245_H235Media_mediaType &)subTypePDU;
1111           return IsSubMatch(data);
1112     }
1113     return false;
1114 }
1115 
IsSubMatch(const PASN_Choice & subTypePDU) const1116 PBoolean H323SecureDataCapability::IsSubMatch(const PASN_Choice & subTypePDU) const
1117 {
1118     const H245_H235Media_mediaType & dataType = (const H245_H235Media_mediaType &)subTypePDU;
1119 
1120     if (dataType.GetTag() == H245_H235Media_mediaType::e_data &&
1121        ChildCapability->GetMainType() == H323Capability::e_Data) {
1122           const H245_DataApplicationCapability & data = dataType;
1123           return ChildCapability->IsMatch(data.m_application);
1124     }
1125     return false;
1126 }
1127 
SetEncryptionActive(PBoolean active)1128 void H323SecureDataCapability::SetEncryptionActive(PBoolean active)
1129 {
1130     m_active = active;
1131 }
1132 
IsEncryptionActive() const1133 PBoolean H323SecureDataCapability::IsEncryptionActive() const
1134 {
1135     return m_active;
1136 }
1137 
SetEncryptionAlgorithm(const PString & alg)1138 void H323SecureDataCapability::SetEncryptionAlgorithm(const PString & alg)
1139 {
1140     m_algorithm = alg;
1141 }
1142 
GetEncryptionAlgorithm() const1143 const PString & H323SecureDataCapability::GetEncryptionAlgorithm() const
1144 {
1145    return m_algorithm;
1146 }
1147 
CreateChannel(H323Connection & connection,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters * param) const1148 H323Channel * H323SecureDataCapability::CreateChannel(H323Connection & connection,
1149                                       H323Channel::Directions dir,
1150                                       unsigned sessionID,
1151                                       const H245_H2250LogicalChannelParameters * param) const
1152 {
1153 
1154     H235Capabilities * caps = dynamic_cast<H235Capabilities*>(connection.GetLocalCapabilitiesRef());
1155     if (!caps || !caps->GetDiffieHellMan())
1156         return ChildCapability->CreateChannel(connection, dir, sessionID, param);
1157 
1158     // We create the primary channel with a clone of the child
1159     // then delete the clone and replace the clone with this one
1160     // via ReplaceCapability() in the constructor of H323SecureChannel
1161     return new H323SecureChannel(connection, *this, ((H323Capability *)ChildCapability->Clone())->CreateChannel(connection, dir, sessionID, param));
1162 }
1163 
OnSendingPDU(H245_Capability & pdu) const1164 PBoolean H323SecureDataCapability::OnSendingPDU(H245_Capability & pdu) const
1165 {
1166    return ((H323DataCapability *)ChildCapability)->OnSendingPDU(pdu);
1167 }
1168 
OnReceivedPDU(const H245_Capability & pdu)1169 PBoolean H323SecureDataCapability::OnReceivedPDU(const H245_Capability & pdu)
1170 {
1171    return ((H323DataCapability *)ChildCapability)->OnReceivedPDU(pdu);
1172 }
1173 
OnSendingPDU(H245_ModeElement & mode) const1174 PBoolean H323SecureDataCapability::OnSendingPDU(H245_ModeElement & mode) const
1175 {
1176    return ((H323DataCapability *)ChildCapability)->OnSendingPDU(mode);
1177 }
1178 
OnSendingPDU(H245_DataType & dataType) const1179 PBoolean H323SecureDataCapability::OnSendingPDU(H245_DataType & dataType) const
1180 {
1181     // find the matching H235SecurityCapability to get the agreed algorithms
1182     // if not found or no matching algorithm then assume no encryption.
1183     H235SecurityCapability * secCap = NULL;
1184     if (m_capabilities) {
1185         secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
1186         if (secCap && secCap->GetAlgorithmCount() > 0) {
1187            (PRemoveConst(H323SecureDataCapability,this))->SetEncryptionActive(true);
1188            (PRemoveConst(H323SecureDataCapability,this))->SetEncryptionAlgorithm(secCap->GetAlgorithm());
1189         }
1190     }
1191 
1192     if (!IsEncryptionActive())
1193         return ((H323DataCapability *)ChildCapability)->OnSendingPDU(dataType);
1194 
1195     dataType.SetTag(H245_DataType::e_h235Media);
1196     H245_H235Media & h235Media = dataType;
1197     // Load the algorithm
1198     if (secCap)
1199       secCap->OnSendingPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC);
1200 
1201     H245_H235Media_mediaType & cType = h235Media.m_mediaType;
1202     cType.SetTag(H245_H235Media_mediaType::e_data);
1203     return ((H323DataCapability *)ChildCapability)->OnSendingPDU((H245_DataApplicationCapability &)cType, e_OLC);
1204 }
1205 
1206 
OnReceivedPDU(const H245_DataType & dataType,PBoolean receiver)1207 PBoolean H323SecureDataCapability::OnReceivedPDU(const H245_DataType & dataType, PBoolean receiver)
1208 {
1209     if (dataType.GetTag() != H245_DataType::e_h235Media)
1210         return ChildCapability->OnReceivedPDU(dataType, receiver);
1211 
1212     const H245_H235Media & h235Media = dataType;
1213     if (m_capabilities) {
1214         H235SecurityCapability * secCap = (H235SecurityCapability *)m_capabilities->FindCapability(m_secNo);
1215         if (!secCap || !secCap->OnReceivedPDU(h235Media.m_encryptionAuthenticationAndIntegrity, e_OLC)) {
1216             PTRACE(4,"H235\tFailed to locate security capability " << m_secNo);
1217             return false;
1218         }
1219         if (secCap && secCap->GetAlgorithmCount() > 0) {
1220             SetEncryptionAlgorithm(secCap->GetAlgorithm());
1221             SetEncryptionActive(true);
1222         }
1223     }
1224     const H245_H235Media_mediaType & mediaType = h235Media.m_mediaType;
1225     if (mediaType.GetTag() == H245_H235Media_mediaType::e_data)
1226         return ((H323DataCapability *)ChildCapability)->OnReceivedPDU((const H245_DataApplicationCapability &)mediaType, e_OLC);
1227     else
1228         return false;
1229 }
1230 
1231 
OnSendingPDU(H245_DataMode & pdu) const1232 PBoolean H323SecureDataCapability::OnSendingPDU(H245_DataMode & pdu) const
1233 {
1234     return ((H323DataCapability *)ChildCapability)->OnSendingPDU(pdu);
1235 }
1236 
1237 
1238 /////////////////////////////////////////////////////////////////////////////
1239 
GetH235Codecs()1240 static PStringArray & GetH235Codecs()
1241 {
1242   static const char * defaultCodecs[] = { "all" };
1243   static PStringArray codecs(
1244           sizeof(defaultCodecs)/sizeof(defaultCodecs[0]),
1245           defaultCodecs
1246   );
1247   return codecs;
1248 }
1249 
GetH235CodecsMutex()1250 static PMutex & GetH235CodecsMutex()
1251 {
1252   static PMutex mutex;
1253   return mutex;
1254 }
1255 
1256 /////////////////////////////////////////////////////////////////////////////
1257 
H235Capabilities()1258 H235Capabilities::H235Capabilities()
1259 : m_DHkey(NULL), m_h245Master(false)
1260 {
1261     m_algorithms.SetSize(0);
1262 }
1263 
H235Capabilities(const H323Capabilities & original)1264 H235Capabilities::H235Capabilities(const H323Capabilities & original)
1265 : m_DHkey(NULL), m_h245Master(false)
1266 {
1267   m_algorithms.SetSize(0);
1268   const H323CapabilitiesSet rset = original.GetSet();
1269 
1270   for (PINDEX i = 0; i < original.GetSize(); i++) {
1271     unsigned capabilityNumber = original[i].GetCapabilityNumber();
1272     PINDEX outer=0,middle=0,inner=0;
1273     for (outer = 0; outer < rset.GetSize(); outer++) {
1274         for (middle = 0; middle < rset[outer].GetSize(); middle++) {
1275           for (inner = 0; inner < rset[outer][middle].GetSize(); inner++) {
1276               if (rset[outer][middle][inner].GetCapabilityNumber() == capabilityNumber) {
1277                  WrapCapability(outer, middle, original[i]);
1278                  break;
1279               }
1280           }
1281           if (rset[outer][middle].GetSize() == 0) {
1282              WrapCapability(outer, middle, original[i]);
1283              break;
1284           }
1285         }
1286         if (rset[outer].GetSize() == 0) {
1287            WrapCapability(outer, middle, original[i]);
1288            break;
1289         }
1290     }
1291   }
1292 }
1293 
H235Capabilities(const H323Connection & connection,const H245_TerminalCapabilitySet & pdu)1294 H235Capabilities::H235Capabilities(const H323Connection & connection, const H245_TerminalCapabilitySet & pdu)
1295  : H323Capabilities(connection, pdu), m_DHkey(NULL), m_h245Master(false)
1296 {
1297    const H235Capabilities & localCapabilities = (const H235Capabilities &)connection.GetLocalCapabilities();
1298    PRemoveConst(H235Capabilities,&localCapabilities)->GetDHKeyPair(m_algorithms, m_DHkey, m_h245Master);
1299 }
1300 
SetCapabilityNumber(const H323CapabilitiesList & table,unsigned newCapabilityNumber)1301 static unsigned SetCapabilityNumber(const H323CapabilitiesList & table,
1302                                       unsigned newCapabilityNumber)
1303 {
1304   // Assign a unique number to the codec, check if the user wants a specific
1305   // value and start with that.
1306   if (newCapabilityNumber == 0)
1307     newCapabilityNumber = 1;
1308 
1309   PINDEX i = 0;
1310   while (i < table.GetSize()) {
1311     if (table[i].GetCapabilityNumber() != newCapabilityNumber)
1312       i++;
1313     else {
1314       // If it already in use, increment it
1315       newCapabilityNumber++;
1316       i = 0;
1317     }
1318   }
1319 
1320   return newCapabilityNumber;
1321 }
1322 
AddSecure(PINDEX descriptorNum,PINDEX simultaneous,H323Capability * capability)1323 void H235Capabilities::AddSecure(PINDEX descriptorNum, PINDEX simultaneous, H323Capability * capability)
1324 {
1325     if (capability == NULL)
1326         return;
1327 
1328     if (!PIsDescendant(capability,H323SecureCapability) &&
1329         !PIsDescendant(capability,H323SecureExtendedCapability) &&
1330         !PIsDescendant(capability,H323SecureDataCapability) &&
1331         !PIsDescendant(capability,H235SecurityCapability))
1332             return;
1333 
1334     // See if already added, confuses things if you add the same instance twice
1335     if (table.GetObjectsIndex(capability) != P_MAX_INDEX)
1336         return;
1337 
1338     // Create the secure capability wrapper
1339     unsigned capNumber = SetCapabilityNumber(table, capability->GetCapabilityNumber());
1340     unsigned secNumber = 100+capNumber;
1341 
1342     capability->SetCapabilityNumber(capNumber);
1343     SetCapability(descriptorNum, simultaneous, capability);
1344 
1345     // Create the security capability
1346     H235SecurityCapability * secCap = new H235SecurityCapability(this, capNumber);
1347     secCap->SetCapabilityNumber(secNumber);
1348     SetCapability(descriptorNum, simultaneous, secCap);
1349 
1350     capability->SetCapabilityList(this);
1351     capability->SetAssociatedCapability(secNumber);
1352 
1353     PTRACE(3, "H323\tAdded Secure Capability: " << *capability);
1354 }
1355 
CopySecure(PINDEX descriptorNum,PINDEX simultaneous,const H323Capability & capability)1356 H323Capability * H235Capabilities::CopySecure(PINDEX descriptorNum, PINDEX simultaneous, const H323Capability & capability)
1357 {
1358   if (!PIsDescendant(&capability,H323SecureCapability) &&
1359       !PIsDescendant(&capability,H323SecureExtendedCapability) &&
1360       !PIsDescendant(&capability,H323SecureDataCapability) &&
1361       !PIsDescendant(&capability,H235SecurityCapability))
1362       return NULL;
1363 
1364   if (PIsDescendant(&capability,H235SecurityCapability)) {
1365      H235SecurityCapability * newCapability = (H235SecurityCapability *)capability.Clone();
1366      newCapability->SetCapabilityNumber(capability.GetCapabilityNumber());
1367      table.Append(newCapability);
1368      SetCapability(descriptorNum, simultaneous, newCapability);
1369      return newCapability;
1370   } else {
1371      H323Capability * newCapability = (H323Capability *)capability.Clone();
1372      newCapability->SetCapabilityNumber(capability.GetCapabilityNumber());
1373      newCapability->SetCapabilityList(this);
1374      SetCapability(descriptorNum, simultaneous, newCapability);
1375      PTRACE(3, "H323\tCopied Secure Capability: " << *newCapability);
1376      return newCapability;
1377   }
1378 }
1379 
WrapCapability(PINDEX descriptorNum,PINDEX simultaneous,H323Capability & capability)1380 void H235Capabilities::WrapCapability(PINDEX descriptorNum, PINDEX simultaneous, H323Capability & capability)
1381 {
1382     if (PIsDescendant(&capability,H323SecureCapability) ||
1383         PIsDescendant(&capability,H323SecureExtendedCapability) ||
1384         PIsDescendant(&capability,H323SecureDataCapability) ||
1385         PIsDescendant(&capability,H235SecurityCapability)) {
1386           CopySecure(descriptorNum, simultaneous, capability);
1387           return;
1388     }
1389 
1390     if (!IsH235Codec(capability.GetFormatName())) {
1391         SetCapability(descriptorNum, simultaneous, (H323Capability *)capability.Clone());
1392         return;
1393     }
1394 
1395     switch (capability.GetDefaultSessionID()) {
1396         case OpalMediaFormat::DefaultAudioSessionID:
1397         case OpalMediaFormat::DefaultVideoSessionID:
1398             AddSecure(descriptorNum, simultaneous, new H323SecureCapability(capability, H235ChNew,this));
1399             break;
1400         case OpalMediaFormat::DefaultExtVideoSessionID:
1401             AddSecure(descriptorNum, simultaneous, new H323SecureExtendedCapability((H323Capability *)capability.Clone(), H235ChNew,this));
1402             break;
1403         case OpalMediaFormat::DefaultDataSessionID:
1404             AddSecure(descriptorNum, simultaneous, new H323SecureDataCapability(capability, H235ChNew,this));
1405             break;
1406         case OpalMediaFormat::NonRTPSessionID:
1407         //case OpalMediaFormat::DefaultDataSessionID:
1408         //case OpalMediaFormat::DefaultExtVideoSessionID:
1409         case OpalMediaFormat::DefaultFileSessionID:
1410         default:
1411             SetCapability(descriptorNum, simultaneous, (H323Capability *)capability.Clone());
1412             break;
1413     }
1414 }
1415 
MatchWildcard(const PCaselessString & str,const PStringArray & wildcard)1416 static PBoolean MatchWildcard(const PCaselessString & str, const PStringArray & wildcard)
1417 {
1418   PINDEX last = 0;
1419   for (PINDEX i = 0; i < wildcard.GetSize(); i++) {
1420     if (wildcard[i].IsEmpty())
1421       last = str.GetLength();
1422     else {
1423       PINDEX next = str.Find(wildcard[i], last);
1424       if (next == P_MAX_INDEX)
1425         return FALSE;
1426       last = next + wildcard[i].GetLength();
1427     }
1428   }
1429 
1430   return TRUE;
1431 }
1432 
AddAllCapabilities(PINDEX descriptorNum,PINDEX simultaneous,const PString & name)1433 PINDEX H235Capabilities::AddAllCapabilities(PINDEX descriptorNum,
1434                                             PINDEX simultaneous,
1435                                             const PString & name)
1436 {
1437   PINDEX reply = descriptorNum == P_MAX_INDEX ? P_MAX_INDEX : simultaneous;
1438 
1439   PStringArray wildcard = name.Tokenise('*', FALSE);
1440 
1441   H323CapabilityFactory::KeyList_T stdCaps = H323CapabilityFactory::GetKeyList();
1442 
1443   for (unsigned session = OpalMediaFormat::FirstSessionID; session <= OpalMediaFormat::LastSessionID; session++) {
1444     for (H323CapabilityFactory::KeyList_T::const_iterator r = stdCaps.begin(); r != stdCaps.end(); ++r) {
1445       PString capName(*r);
1446       if (MatchWildcard(capName, wildcard) && (FindCapability(capName) == NULL)) {
1447         OpalMediaFormat mediaFormat(capName);
1448         if (!mediaFormat.IsValid() && (capName.Right(4) == "{sw}") && capName.GetLength() > 4)
1449           mediaFormat = OpalMediaFormat(capName.Left(capName.GetLength()-4));
1450         if (mediaFormat.IsValid() && mediaFormat.GetDefaultSessionID() == session) {
1451           // add the capability
1452           H323Capability * capability = H323Capability::Create(capName);
1453           H323Capability * newCapability = NULL;
1454           PINDEX num=0;
1455             switch (session) {
1456                 case OpalMediaFormat::DefaultAudioSessionID:
1457                 case OpalMediaFormat::DefaultVideoSessionID:
1458                     newCapability = new H323SecureCapability(*capability, H235ChNew, this);
1459                     // TODO: assigning to num twice doesn't make sense
1460                     num = SetCapability(descriptorNum, simultaneous, newCapability);
1461                     num = SetCapability(descriptorNum, simultaneous,
1462                                         new H235SecurityCapability(this, newCapability->GetCapabilityNumber()));
1463                     break;
1464                 case OpalMediaFormat::DefaultDataSessionID:
1465                     newCapability = new H323SecureDataCapability(*capability, H235ChNew, this);
1466                     // TODO: assigning to num twice doesn't make sense
1467                     num = SetCapability(descriptorNum, simultaneous, newCapability);
1468                     num = SetCapability(descriptorNum, simultaneous,
1469                                         new H235SecurityCapability(this, newCapability->GetCapabilityNumber()));
1470                     break;
1471                 case OpalMediaFormat::DefaultExtVideoSessionID:
1472                     newCapability = new H323SecureExtendedCapability((H323Capability *)capability->Clone(), H235ChNew, this);
1473                     // TODO: assigning to num twice doesn't make sense
1474                     num = SetCapability(descriptorNum, simultaneous, newCapability);
1475                     num = SetCapability(descriptorNum, simultaneous,
1476                                         new H235SecurityCapability(this, newCapability->GetCapabilityNumber()));
1477                     break;
1478                 case OpalMediaFormat::DefaultFileSessionID:
1479                 default:
1480                     num = SetCapability(descriptorNum, simultaneous, capability);
1481                     break;
1482             }
1483 
1484             if (descriptorNum == P_MAX_INDEX) {
1485                 reply = num;
1486                 descriptorNum = num;
1487                 simultaneous = P_MAX_INDEX;
1488             }
1489             else if (simultaneous == P_MAX_INDEX) {
1490                 if (reply == P_MAX_INDEX)
1491                   reply = num;
1492                 simultaneous = num;
1493             }
1494         }
1495       }
1496     }
1497     simultaneous = P_MAX_INDEX;
1498   }
1499 
1500   return reply;
1501 }
1502 
SetDHKeyPair(const PStringList & keyOIDs,H235_DiffieHellman * key,PBoolean isMaster)1503 void H235Capabilities::SetDHKeyPair(const PStringList & keyOIDs, H235_DiffieHellman * key, PBoolean isMaster)
1504 {
1505     m_algorithms.SetSize(0);
1506     for (PINDEX i=0; i < keyOIDs.GetSize(); ++i)
1507          m_algorithms.AppendString(keyOIDs[i]);
1508 
1509      m_DHkey = key;
1510      m_h245Master = isMaster;
1511 
1512      PTRACE(2,"H235\tDiffieHellman selected. Key " << (isMaster ? "Master" : "Slave"));
1513 
1514 }
1515 
GetDHKeyPair(PStringList & keyOIDs,H235_DiffieHellman * & key,PBoolean & isMaster)1516 void H235Capabilities::GetDHKeyPair(PStringList & keyOIDs, H235_DiffieHellman * & key, PBoolean & isMaster)
1517 {
1518     for (PINDEX i=0; i < m_algorithms.GetSize(); ++i)
1519          keyOIDs.AppendString(m_algorithms[i]);
1520 
1521     if (m_DHkey)
1522          key = m_DHkey;
1523 
1524      isMaster = m_h245Master;
1525 }
1526 
GetAlgorithms(const PStringList & algorithms) const1527 PBoolean H235Capabilities::GetAlgorithms(const PStringList & algorithms) const
1528 {
1529     PStringList * m_localAlgorithms = PRemoveConst(PStringList,&algorithms);
1530     m_localAlgorithms->SetSize(0);
1531     for (PINDEX i=0; i < m_algorithms.GetSize(); ++i)
1532          m_localAlgorithms->AppendString(m_algorithms[i]);
1533 
1534     return (algorithms.GetSize() > 0);
1535 }
1536 
SetH235Codecs(const PStringArray & servers)1537 void H235Capabilities::SetH235Codecs(const PStringArray & servers)
1538 {
1539      PWaitAndSignal m(GetH235CodecsMutex());
1540      GetH235Codecs() = servers;
1541 }
1542 
IsH235Codec(const PString & name)1543 PBoolean H235Capabilities::IsH235Codec(const PString & name)
1544 {
1545     PStringArray codecs = GetH235Codecs();
1546 
1547     if ((codecs.GetSize() == 0) || (codecs[0] *= "all"))
1548         return true;
1549 
1550     for (PINDEX i=0; i<codecs.GetSize(); ++i) {
1551         if (name.Find(codecs[i]) != P_MAX_INDEX)
1552             return true;
1553     }
1554     return false;
1555 }
1556 
1557 #endif
1558 
1559