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