D:/Storage/CVS_Head/h323plus/src/h235auth.cxx

00001 /*
00002  * h235auth.cxx
00003  *
00004  * H.235 security PDU's
00005  *
00006  * Open H323 Library
00007  *
00008  * Copyright (c) 1998-2001 Equivalence Pty. Ltd.
00009  *
00010  * The contents of this file are subject to the Mozilla Public License
00011  * Version 1.0 (the "License"); you may not use this file except in
00012  * compliance with the License. You may obtain a copy of the License at
00013  * http://www.mozilla.org/MPL/
00014  *
00015  * Software distributed under the License is distributed on an "AS IS"
00016  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00017  * the License for the specific language governing rights and limitations
00018  * under the License.
00019  *
00020  * The Original Code is Open H323 Library.
00021  *
00022  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
00023  *
00024  * Contributor(s): __________________________________
00025  *
00026  * $Log: h235auth.cxx,v $
00027  * Revision 1.1  2007/08/06 20:51:05  shorne
00028  * First commit of h323plus
00029  *
00030  * Revision 1.31.2.3  2007/07/19 19:56:10  shorne
00031  * added missiing secure signal PDU check
00032  *
00033  * Revision 1.31.2.2  2007/05/23 07:02:38  shorne
00034  * Removed VS 2005 compile warning
00035  *
00036  * Revision 1.31.2.1  2006/12/23 19:08:02  shorne
00037  * Plugin video codecs & sundry
00038  *
00039  * Revision 1.31  2006/02/13 11:24:23  csoutheren
00040  * Fixed problem with H235 authenticator factory not being populated
00041  *
00042  * Revision 1.30  2006/01/26 03:25:55  shorne
00043  * Caller Authentication added
00044  *
00045  * Revision 1.29  2005/02/03 02:46:07  csoutheren
00046  * Altered authentication functions to only update state information if authentication
00047  *  is correct. Thanks to Michal Zygmuntowicz
00048  *
00049  * Revision 1.28  2005/01/04 08:08:45  csoutheren
00050  * More changes to implement the new configuration methodology, and also to
00051  * attack the global static problem
00052  *
00053  * Revision 1.27  2004/11/21 12:59:07  csoutheren
00054  * Fixed cut and paste error affecting H235 authentication
00055  *
00056  * Revision 1.26  2004/11/20 22:00:49  csoutheren
00057  * Added hacks for linker problem
00058  *
00059  * Revision 1.25  2004/11/12 06:04:44  csoutheren
00060  * Changed H235Authentiators to use PFactory
00061  *
00062  * Revision 1.24  2003/04/30 00:28:54  robertj
00063  * Redesigned the alternate credentials in ARQ system as old implementation
00064  *   was fraught with concurrency issues, most importantly it can cause false
00065  *   detection of replay attacks taking out an endpoint completely.
00066  *
00067  * Revision 1.23  2003/04/01 04:47:55  robertj
00068  * Abstracted H.225 RAS transaction processing (RIP and secondary thread) in
00069  *   server environment for use by H.501 peer elements.
00070  *
00071  * Revision 1.22  2003/02/25 06:48:19  robertj
00072  * More work on PDU transaction abstraction.
00073  *
00074  * Revision 1.21  2003/02/12 07:40:36  robertj
00075  * Added more logging for authentication errors in validation.
00076  * Fixed problem with possible negative numbers in CAT random field.
00077  *
00078  * Revision 1.20  2003/02/11 04:44:13  robertj
00079  * Fixed use of asymmetrical authentication schemes such as MD5.
00080  *
00081  * Revision 1.19  2003/02/03 02:55:08  robertj
00082  * Fixed problem with pasing through other tokens transparently.
00083  *
00084  * Revision 1.18  2003/02/02 11:46:32  robertj
00085  * Fixed CAT selection in GRQ authentication mechanisms.
00086  *
00087  * Revision 1.17  2003/02/01 13:31:22  robertj
00088  * Changes to support CAT authentication in RAS.
00089  *
00090  * Revision 1.16  2003/01/08 04:40:34  robertj
00091  * Added more debug tracing for H.235 authenticators.
00092  *
00093  * Revision 1.15  2002/11/11 07:04:22  robertj
00094  * Fixed typo in trace.
00095  *
00096  * Revision 1.14  2002/11/05 00:04:21  robertj
00097  * Returned code back to including trailing NULL in BMPString after
00098  *   PString::AsUCS2() implementation changes.
00099  *
00100  * Revision 1.13  2002/10/31 07:11:16  robertj
00101  * Added UTF-8/UCS-2 conversion functions to PString.
00102  *
00103  * Revision 1.12  2002/08/13 05:11:03  robertj
00104  * Removed redundent code.
00105  *
00106  * Revision 1.11  2002/08/05 10:03:47  robertj
00107  * Cosmetic changes to normalise the usage of pragma interface/implementation.
00108  *
00109  * Revision 1.10  2002/08/05 05:17:41  robertj
00110  * Fairly major modifications to support different authentication credentials
00111  *   in ARQ to the logged in ones on RRQ. For both client and server.
00112  * Various other H.235 authentication bugs and anomalies fixed on the way.
00113  *
00114  * Revision 1.9  2002/06/24 00:11:21  robertj
00115  * Clarified error message during GRQ authentication.
00116  *
00117  * Revision 1.8  2002/05/17 03:40:09  robertj
00118  * Fixed problems with H.235 authentication on RAS for server and client.
00119  *
00120  * Revision 1.7  2001/09/21 04:55:27  robertj
00121  * Removed redundant code, thanks Chih-Wei Huang
00122  *
00123  * Revision 1.6  2001/09/14 00:13:39  robertj
00124  * Fixed problem with some athenticators needing extra conditions to be
00125  *   "active", so make IsActive() virtual and add localId to H235AuthSimpleMD5
00126  *
00127  * Revision 1.5  2001/09/13 01:15:20  robertj
00128  * Added flag to H235Authenticator to determine if gkid and epid is to be
00129  *   automatically set as the crypto token remote id and local id.
00130  *
00131  * Revision 1.4  2001/08/14 04:26:46  robertj
00132  * Completed the Cisco compatible MD5 authentications, thanks Wolfgang Platzer.
00133  *
00134  * Revision 1.3  2001/08/13 10:03:54  robertj
00135  * Fixed problem if do not have a localId when doing MD5 authentication.
00136  *
00137  * Revision 1.2  2001/08/10 13:49:35  robertj
00138  * Fixed alpha Linux warning.
00139  *
00140  * Revision 1.1  2001/08/10 11:03:52  robertj
00141  * Major changes to H.235 support in RAS to support server.
00142  *
00143  */
00144 
00145 #include <ptlib.h>
00146 
00147 #ifdef __GNUC__
00148 #pragma implementation "h235auth.h"
00149 #endif
00150 
00151 #if defined(_WIN32) && (_MSC_VER > 1300)
00152   #pragma warning(disable:4244) // warning about possible loss of data
00153 #endif
00154 
00155 #include "h235auth.h"
00156 
00157 #include "h323pdu.h"
00158 #include <ptclib/random.h>
00159 #include <ptclib/cypher.h>
00160 
00161 
00162 #define new PNEW
00163 
00164 namespace PWLibStupidLinkerHacks {
00165   int h235AuthLoader;
00166 };
00167 
00169 
00170 H235Authenticator::H235Authenticator()
00171 {
00172   enabled = TRUE;
00173   sentRandomSequenceNumber = PRandom::Number()&INT_MAX;
00174   lastRandomSequenceNumber = 0;
00175   lastTimestamp = 0;
00176   timestampGracePeriod = 2*60*60+10; // 2 hours 10 seconds to allow for DST adjustments
00177   usage = GKAdmission;               // Set Default Application to GKAdmission
00178   connection = NULL;
00179 }
00180 
00181 
00182 void H235Authenticator::PrintOn(ostream & strm) const
00183 {
00184   PWaitAndSignal m(mutex);
00185 
00186   strm << GetName() << '<';
00187   if (IsActive())
00188     strm << "active";
00189   else if (!enabled)
00190     strm << "disabled";
00191   else if (password.IsEmpty())
00192     strm << "no-pwd";
00193   else
00194     strm << "inactive";
00195   strm << '>';
00196 }
00197 
00198 
00199 BOOL H235Authenticator::PrepareTokens(PASN_Array & clearTokens,
00200                                       PASN_Array & cryptoTokens)
00201 {
00202   PWaitAndSignal m(mutex);
00203 
00204   if (!IsActive())
00205     return FALSE;
00206 
00207   H235_ClearToken * clearToken = CreateClearToken();
00208   if (clearToken != NULL) {
00209     // Check if already have a token of thsi type and overwrite it
00210     for (PINDEX i = 0; i < clearTokens.GetSize(); i++) {
00211       H235_ClearToken & oldToken = (H235_ClearToken &)clearTokens[i];
00212       if (clearToken->m_tokenOID == oldToken.m_tokenOID) {
00213         oldToken = *clearToken;
00214         delete clearToken;
00215         clearToken = NULL;
00216         break;
00217       }
00218     }
00219 
00220     if (clearToken != NULL)
00221       clearTokens.Append(clearToken);
00222   }
00223 
00224   H225_CryptoH323Token * cryptoToken = CreateCryptoToken();
00225   if (cryptoToken != NULL)
00226     cryptoTokens.Append(cryptoToken);
00227 
00228   return TRUE;
00229 }
00230 
00231 
00232 H235_ClearToken * H235Authenticator::CreateClearToken()
00233 {
00234   return NULL;
00235 }
00236 
00237 
00238 H225_CryptoH323Token * H235Authenticator::CreateCryptoToken()
00239 {
00240   return NULL;
00241 }
00242 
00243 
00244 BOOL H235Authenticator::Finalise(PBYTEArray & /*rawPDU*/)
00245 {
00246   return TRUE;
00247 }
00248 
00249 
00250 H235Authenticator::ValidationResult H235Authenticator::ValidateTokens(
00251                                         const PASN_Array & clearTokens,
00252                                         const PASN_Array & cryptoTokens,
00253                                         const PBYTEArray & rawPDU)
00254 {
00255   PWaitAndSignal m(mutex);
00256 
00257   if (!IsActive())
00258     return e_Disabled;
00259 
00260   PINDEX i;
00261   for (i = 0; i < clearTokens.GetSize(); i++) {
00262     ValidationResult s = ValidateClearToken((H235_ClearToken &)clearTokens[i]);
00263     if (s != e_Absent)
00264       return s;
00265   }
00266 
00267   for (i = 0; i < cryptoTokens.GetSize(); i++) {
00268     ValidationResult s = ValidateCryptoToken((H225_CryptoH323Token &)cryptoTokens[i], rawPDU);
00269     if (s != e_Absent)
00270       return s;
00271   }
00272 
00273   return e_Absent;
00274 }
00275 
00276 
00277 H235Authenticator::ValidationResult H235Authenticator::ValidateClearToken(
00278                                                  const H235_ClearToken & /*clearToken*/)
00279 {
00280   return e_Absent;
00281 }
00282 
00283 
00284 H235Authenticator::ValidationResult H235Authenticator::ValidateCryptoToken(
00285                                             const H225_CryptoH323Token & /*cryptoToken*/,
00286                                             const PBYTEArray & /*rawPDU*/)
00287 {
00288   return e_Absent;
00289 }
00290 
00291 
00292 BOOL H235Authenticator::UseGkAndEpIdentifiers() const
00293 {
00294   return FALSE;
00295 }
00296 
00297 
00298 BOOL H235Authenticator::IsSecuredPDU(unsigned, BOOL) const
00299 {
00300   return TRUE;
00301 }
00302 
00303 BOOL H235Authenticator::IsSecuredSignalPDU(unsigned, BOOL) const
00304 {
00305   return FALSE;
00306 }
00307 
00308 BOOL H235Authenticator::IsActive() const
00309 {
00310   return enabled && !password;
00311 }
00312 
00313 
00314 BOOL H235Authenticator::AddCapability(unsigned mechanism,
00315                                       const PString & oid,
00316                                       H225_ArrayOf_AuthenticationMechanism & mechanisms,
00317                                       H225_ArrayOf_PASN_ObjectId & algorithmOIDs)
00318 {
00319   PWaitAndSignal m(mutex);
00320 
00321   if (!IsActive()) {
00322     PTRACE(2, "RAS\tAuthenticator " << *this
00323             << " not active during SetCapability negotiation");
00324     return FALSE;
00325   }
00326 
00327   PINDEX i;
00328   PINDEX size = mechanisms.GetSize();
00329   for (i = 0; i < size; i++) {
00330     if (mechanisms[i].GetTag() == mechanism)
00331       break;
00332   }
00333   if (i >= size) {
00334     mechanisms.SetSize(size+1);
00335     mechanisms[size].SetTag(mechanism);
00336   }
00337 
00338   size = algorithmOIDs.GetSize();
00339   for (i = 0; i < size; i++) {
00340     if (algorithmOIDs[i] == oid)
00341       break;
00342   }
00343   if (i >= size) {
00344     algorithmOIDs.SetSize(size+1);
00345     algorithmOIDs[size] = oid;
00346   }
00347 
00348   return TRUE;
00349 }
00350 
00351 void H235Authenticator::SetConnection(H323Connection * con)
00352 {
00353         connection = con;
00354 }
00355 
00357 
00358 void H235Authenticators::PreparePDU(H323TransactionPDU & pdu,
00359                                     PASN_Array & clearTokens,
00360                                     unsigned clearOptionalField,
00361                                     PASN_Array & cryptoTokens,
00362                                     unsigned cryptoOptionalField) const
00363 {
00364   // Clean out any crypto tokens in case this is a retry message
00365   // and we are regenerating the tokens due to possible timestamp
00366   // issues. We don't do this for clear tokens which may be used by
00367   // other endpoints and should be passed through unchanged.
00368   cryptoTokens.RemoveAll();
00369 
00370   for (PINDEX i = 0; i < GetSize(); i++) {
00371     H235Authenticator & authenticator = (*this)[i];
00372     if (authenticator.IsSecuredPDU(pdu.GetChoice().GetTag(), FALSE) &&
00373         authenticator.PrepareTokens(clearTokens, cryptoTokens)) {
00374       PTRACE(4, "H235RAS\tPrepared PDU with authenticator " << authenticator);
00375     }
00376   }
00377 
00378   PASN_Sequence & subPDU = (PASN_Sequence &)pdu.GetChoice().GetObject();
00379   if (clearTokens.GetSize() > 0)
00380     subPDU.IncludeOptionalField(clearOptionalField);
00381 
00382   if (cryptoTokens.GetSize() > 0)
00383     subPDU.IncludeOptionalField(cryptoOptionalField);
00384 }
00385 
00386 
00387 H235Authenticator::ValidationResult
00388        H235Authenticators::ValidatePDU(const H323TransactionPDU & pdu,
00389                                        const PASN_Array & clearTokens,
00390                                        unsigned clearOptionalField,
00391                                        const PASN_Array & cryptoTokens,
00392                                        unsigned cryptoOptionalField,
00393                                        const PBYTEArray & rawPDU) const
00394 {
00395   BOOL noneActive = TRUE;
00396   PINDEX i;
00397   for (i = 0; i < GetSize(); i++) {
00398     H235Authenticator & authenticator = (*this)[i];
00399     if (authenticator.IsActive() && authenticator.IsSecuredPDU(pdu.GetChoice().GetTag(), TRUE)) {
00400       noneActive = FALSE;
00401       break;
00402     }
00403   }
00404 
00405   if (noneActive)
00406     return H235Authenticator::e_OK;
00407 
00408   //do not accept non secure RAS Messages
00409   const PASN_Sequence & subPDU = (const PASN_Sequence &)pdu.GetChoice().GetObject();
00410   if (!subPDU.HasOptionalField(clearOptionalField) &&
00411       !subPDU.HasOptionalField(cryptoOptionalField)) {
00412     PTRACE(2, "H235RAS\tReceived unsecured RAS message (no crypto tokens),"
00413               " need one of:\n" << setfill(',') << *this << setfill(' '));
00414     return H235Authenticator::e_Absent;
00415   }
00416 
00417   for (i = 0; i < GetSize(); i++) {
00418     H235Authenticator & authenticator = (*this)[i];
00419     if (authenticator.IsSecuredPDU(pdu.GetChoice().GetTag(), TRUE)) {
00420       H235Authenticator::ValidationResult result = authenticator.ValidateTokens(clearTokens, cryptoTokens, rawPDU);
00421       switch (result) {
00422         case H235Authenticator::e_OK :
00423           PTRACE(4, "H235RAS\tAuthenticator " << authenticator << " succeeded");
00424           return H235Authenticator::e_OK;
00425 
00426         case H235Authenticator::e_Absent :
00427           PTRACE(4, "H235RAS\tAuthenticator " << authenticator << " absent from PDU");
00428           authenticator.Disable();
00429           break;
00430 
00431         case H235Authenticator::e_Disabled :
00432           PTRACE(4, "H235RAS\tAuthenticator " << authenticator << " disabled");
00433           break;
00434 
00435         default : // Various other failure modes
00436           PTRACE(4, "H235RAS\tAuthenticator " << authenticator << " failed: " << (int)result);
00437           return result;
00438       }
00439     }
00440   }
00441 
00442   return H235Authenticator::e_Absent;
00443 }
00444 
00445 
00446 void H235Authenticators::PrepareSignalPDU(unsigned code,
00447                                     PASN_Array & clearTokens,
00448                                     PASN_Array & cryptoTokens) const
00449 {
00450   // Clean out any crypto tokens in case this is a retry message
00451   // and we are regenerating the tokens due to possible timestamp
00452   // issues. We don't do this for clear tokens which may be used by
00453   // other endpoints and should be passed through unchanged.
00454   cryptoTokens.RemoveAll();
00455 
00456   for (PINDEX i = 0; i < GetSize(); i++) {
00457     H235Authenticator & authenticator = (*this)[i];
00458      if (authenticator.IsSecuredSignalPDU(code, FALSE) &&
00459                         authenticator.PrepareTokens(clearTokens, cryptoTokens)) {
00460       PTRACE(4, "H235EP\tPrepared SignalPDU with authenticator " << authenticator);
00461            }
00462   }
00463 }
00464 
00465 
00466 H235Authenticator::ValidationResult
00467        H235Authenticators::ValidateSignalPDU(unsigned code,
00468                                                                                         const PASN_Array & clearTokens,
00469                                                                                         const PASN_Array & cryptoTokens,
00470                                                                                         const PBYTEArray & rawPDU) const
00471 {
00472 
00473   H235Authenticator::ValidationResult finalresult = H235Authenticator::e_Absent;
00474  
00475   for (PINDEX i = 0; i < GetSize(); i++) {
00476     H235Authenticator & authenticator = (*this)[i];
00477     if (authenticator.IsSecuredSignalPDU(code, TRUE)) {
00478 
00479                 H235Authenticator::ValidationResult result = authenticator.ValidateTokens(clearTokens, cryptoTokens, rawPDU);
00480                   switch (result) {
00481                         case H235Authenticator::e_OK :
00482                           PTRACE(4, "H235EP\tAuthenticator " << authenticator << " succeeded");
00483                           finalresult = result;
00484                           break;
00485 
00486                         case H235Authenticator::e_Absent :
00487                           PTRACE(4, "H235EP\tAuthenticator " << authenticator << " absent from PDU");
00488                           authenticator.Disable();
00489                           break;
00490 
00491                         case H235Authenticator::e_Disabled :
00492                           PTRACE(4, "H235EP\tAuthenticator " << authenticator << " disabled");
00493                           break;
00494 
00495                         default : // Various other failure modes
00496                           PTRACE(4, "H235EP\tAuthenticator " << authenticator << " failed: " << (int)result);
00497                             if (finalresult != H235Authenticator::e_OK) 
00498                                                                         finalresult = result;
00499                           break;
00500                   }     
00501 
00502     } else {
00503                 authenticator.Disable();
00504         }
00505 
00506   }
00507 
00508   return finalresult;
00509 }
00510 
00512 
00513 BOOL H235AuthenticatorList::HasUserName(PString UserName) const
00514 {
00515         for (PINDEX i = 0; i < GetSize(); i++) {
00516         H235AuthenticatorInfo & info = (*this)[i];
00517                         if (UserName == info.UserName)
00518                                 return TRUE;
00519         }
00520     return FALSE;
00521 }
00522 
00523 void H235AuthenticatorList::LoadPassword(PString UserName, PString & pass) const
00524 {
00525         for (PINDEX i = 0; i < GetSize(); i++) {
00526         H235AuthenticatorInfo & info = (*this)[i];
00527                 if (UserName == info.UserName) {
00528                         if (info.isHashed) {
00529                                 pass = PasswordDecrypt(info.Password);
00530                         } else 
00531                                 pass = info.Password;
00532                 }
00533         }
00534 }
00535 
00536 void H235AuthenticatorList::Add(PString username, PString password, BOOL isHashed)
00537 {
00538   H235AuthenticatorInfo * info = new H235AuthenticatorInfo(username,password,isHashed);
00539 
00540   (*this).Append(info);
00541 
00542 }
00543 
00544 #define AuthenticatorListHashKey  "H235Authenticator"
00545 
00546 PString H235AuthenticatorList::PasswordEncrypt(const PString &clear) const
00547 {
00548 
00549 int keyFilled = 0;
00550 
00551 const PString key = AuthenticatorListHashKey;
00552         
00553         PTEACypher::Key thekey;
00554         memset(&thekey, keyFilled, sizeof(PTEACypher::Key));
00555         memcpy(&thekey, const_cast<PString &>(key).GetPointer(), min(sizeof(PTEACypher::Key), size_t(key.GetLength())));
00556         PTEACypher cypher(thekey);
00557         return cypher.Encode(clear);    
00558 }
00559 
00560 PString H235AuthenticatorList::PasswordDecrypt(const PString &encrypt) const
00561 {
00562 
00563 int keyFilled = 0;
00564 
00565 const PString key = AuthenticatorListHashKey;
00566 
00567         PTEACypher::Key thekey;
00568         memset(&thekey, keyFilled, sizeof(PTEACypher::Key));
00569         memcpy(&thekey, const_cast<PString &>(key).GetPointer(), min(sizeof(PTEACypher::Key), size_t(key.GetLength())));
00570         PTEACypher cypher(thekey);
00571         return cypher.Decode(encrypt);  
00572 }
00573 
00575 H235AuthenticatorInfo::H235AuthenticatorInfo(PString username,PString password,BOOL ishashed)
00576         : UserName(username), Password(password), isHashed(ishashed)
00577 {
00578 }
00579 
00580 H235AuthenticatorInfo::H235AuthenticatorInfo(PSSLCertificate * cert)
00581         : Certificate(cert)
00582 {
00583 }
00585 
00586 static PFactory<H235Authenticator>::Worker<H235AuthSimpleMD5> factoryH235AuthSimpleMD5("SimpleMD5");
00587 
00588 static const char OID_MD5[] = "1.2.840.113549.2.5";
00589 
00590 H235AuthSimpleMD5::H235AuthSimpleMD5()
00591 {
00592         usage = AnyApplication; // Can be used either for GKAdmission or EPAuthenticstion
00593 }
00594 
00595 
00596 PObject * H235AuthSimpleMD5::Clone() const
00597 {
00598   return new H235AuthSimpleMD5(*this);
00599 }
00600 
00601 
00602 const char * H235AuthSimpleMD5::GetName() const
00603 {
00604   return "MD5";
00605 }
00606 
00607 
00608 static PWORDArray GetUCS2plusNULL(const PString & str)
00609 {
00610   PWORDArray ucs2 = str.AsUCS2();
00611   PINDEX len = ucs2.GetSize();
00612   if (len > 0 && ucs2[len-1] != 0)
00613     ucs2.SetSize(len+1);
00614   return ucs2;
00615 }
00616 
00617 
00618 H225_CryptoH323Token * H235AuthSimpleMD5::CreateCryptoToken()
00619 {
00620   if (!IsActive())
00621     return NULL;
00622 
00623   if (localId.IsEmpty()) {
00624     PTRACE(2, "H235RAS\tH235AuthSimpleMD5 requires local ID for encoding.");
00625     return NULL;
00626   }
00627 
00628   // Cisco compatible hash calculation
00629   H235_ClearToken clearToken;
00630 
00631   // fill the PwdCertToken to calculate the hash
00632   clearToken.m_tokenOID = "0.0";
00633 
00634   clearToken.IncludeOptionalField(H235_ClearToken::e_generalID);
00635   clearToken.m_generalID = GetUCS2plusNULL(localId);
00636 
00637   clearToken.IncludeOptionalField(H235_ClearToken::e_password);
00638   clearToken.m_password = GetUCS2plusNULL(password);
00639 
00640   clearToken.IncludeOptionalField(H235_ClearToken::e_timeStamp);
00641   clearToken.m_timeStamp = (int)time(NULL);
00642 
00643   // Encode it into PER
00644   PPER_Stream strm;
00645   clearToken.Encode(strm);
00646   strm.CompleteEncoding();
00647 
00648   // Generate an MD5 of the clear tokens PER encoding.
00649   PMessageDigest5 stomach;
00650   stomach.Process(strm.GetPointer(), strm.GetSize());
00651   PMessageDigest5::Code digest;
00652   stomach.Complete(digest);
00653 
00654   // Create the H.225 crypto token
00655   H225_CryptoH323Token * cryptoToken = new H225_CryptoH323Token;
00656   cryptoToken->SetTag(H225_CryptoH323Token::e_cryptoEPPwdHash);
00657   H225_CryptoH323Token_cryptoEPPwdHash & cryptoEPPwdHash = *cryptoToken;
00658 
00659   // Set the token data that actually goes over the wire
00660   H323SetAliasAddress(localId, cryptoEPPwdHash.m_alias);
00661 
00662   cryptoEPPwdHash.m_timeStamp = clearToken.m_timeStamp;
00663   cryptoEPPwdHash.m_token.m_algorithmOID = OID_MD5;
00664   cryptoEPPwdHash.m_token.m_hash.SetData(sizeof(digest)*8, (const BYTE *)&digest);
00665 
00666   return cryptoToken;
00667 }
00668 
00669 
00670 H235Authenticator::ValidationResult H235AuthSimpleMD5::ValidateCryptoToken(
00671                                              const H225_CryptoH323Token & cryptoToken,
00672                                              const PBYTEArray &)
00673 {
00674   if (!IsActive())
00675     return e_Disabled;
00676 
00677   // verify the token is of correct type
00678   if (cryptoToken.GetTag() != H225_CryptoH323Token::e_cryptoEPPwdHash)
00679     return e_Absent;
00680 
00681   const H225_CryptoH323Token_cryptoEPPwdHash & cryptoEPPwdHash = cryptoToken;
00682 
00683   PString alias = H323GetAliasAddressString(cryptoEPPwdHash.m_alias);
00684 
00685 #ifndef DISABLE_CALLAUTH
00686   // If has connection then EP Authenticator so CallBack to Check SenderID and Set Password
00687   if (connection != NULL) { 
00688          if (!connection->OnCallAuthentication(alias,password)) {
00689                 PTRACE(1, "H235EP\tH235AuthSimpleMD5 Authentication Fail UserName \"" << alias 
00690                            << "\", not Authorised. \"");
00691                 return e_BadPassword;
00692          }
00693   } else {
00694 #endif
00695      if (!remoteId && alias != remoteId) {
00696         PTRACE(1, "H235RAS\tH235AuthSimpleMD5 alias is \"" << alias
00697            << "\", should be \"" << remoteId << '"');
00698          return e_Error;
00699      }
00700 #ifndef DISABLE_CALLAUTH
00701   }
00702 #endif
00703 
00704   // Build the clear token
00705   H235_ClearToken clearToken;
00706   clearToken.m_tokenOID = "0.0";
00707 
00708   clearToken.IncludeOptionalField(H235_ClearToken::e_generalID);
00709   clearToken.m_generalID = GetUCS2plusNULL(alias);
00710 
00711   clearToken.IncludeOptionalField(H235_ClearToken::e_password);
00712   clearToken.m_password = GetUCS2plusNULL(password);
00713 
00714   clearToken.IncludeOptionalField(H235_ClearToken::e_timeStamp);
00715   clearToken.m_timeStamp = cryptoEPPwdHash.m_timeStamp;
00716 
00717   // Encode it into PER
00718   PPER_Stream strm;
00719   clearToken.Encode(strm);
00720   strm.CompleteEncoding();
00721 
00722   // Generate an MD5 of the clear tokens PER encoding.
00723   PMessageDigest5 stomach;
00724   stomach.Process(strm.GetPointer(), strm.GetSize());
00725   PMessageDigest5::Code digest;
00726   stomach.Complete(digest);
00727 
00728   if (cryptoEPPwdHash.m_token.m_hash.GetSize() == sizeof(digest)*8 &&
00729       memcmp(cryptoEPPwdHash.m_token.m_hash.GetDataPointer(), &digest, sizeof(digest)) == 0)
00730     return e_OK;
00731 
00732   PTRACE(1, "H235RAS\tH235AuthSimpleMD5 digest does not match.");
00733   return e_BadPassword;
00734 }
00735 
00736 
00737 BOOL H235AuthSimpleMD5::IsCapability(const H235_AuthenticationMechanism & mechanism,
00738                                      const PASN_ObjectId & algorithmOID)
00739 {
00740   return mechanism.GetTag() == H235_AuthenticationMechanism::e_pwdHash &&
00741          algorithmOID.AsString() == OID_MD5;
00742 }
00743 
00744 
00745 BOOL H235AuthSimpleMD5::SetCapability(H225_ArrayOf_AuthenticationMechanism & mechanisms,
00746                                       H225_ArrayOf_PASN_ObjectId & algorithmOIDs)
00747 {
00748   return AddCapability(H235_AuthenticationMechanism::e_pwdHash, OID_MD5, mechanisms, algorithmOIDs);
00749 }
00750 
00751 
00752 BOOL H235AuthSimpleMD5::IsSecuredPDU(unsigned rasPDU, BOOL received) const
00753 {
00754   switch (rasPDU) {
00755     case H225_RasMessage::e_registrationRequest :
00756     case H225_RasMessage::e_unregistrationRequest :
00757     case H225_RasMessage::e_admissionRequest :
00758     case H225_RasMessage::e_disengageRequest :
00759     case H225_RasMessage::e_bandwidthRequest :
00760     case H225_RasMessage::e_infoRequestResponse :
00761       return received ? !remoteId.IsEmpty() : !localId.IsEmpty();
00762 
00763     default :
00764       return FALSE;
00765   }
00766 }
00767 
00768 BOOL H235AuthSimpleMD5::IsSecuredSignalPDU(unsigned signalPDU, BOOL received) const
00769 {
00770   switch (signalPDU) {
00771     case H225_H323_UU_PDU_h323_message_body::e_setup:       
00772       return received ? !remoteId.IsEmpty() : !localId.IsEmpty();
00773 
00774     default :
00775       return FALSE;
00776   }
00777 }
00778 
00779 
00781 
00782 static PFactory<H235Authenticator>::Worker<H235AuthCAT> factoryH235AuthCAT("SimpleCAT");
00783 
00784 static const char OID_CAT[] = "1.2.840.113548.10.1.2.1";
00785 
00786 H235AuthCAT::H235AuthCAT()
00787 {
00788         usage = GKAdmission;             
00789 }
00790 
00791 
00792 PObject * H235AuthCAT::Clone() const
00793 {
00794   return new H235AuthCAT(*this);
00795 }
00796 
00797 
00798 const char * H235AuthCAT::GetName() const
00799 {
00800   return "CAT";
00801 }
00802 
00803 
00804 H235_ClearToken * H235AuthCAT::CreateClearToken()
00805 {
00806   if (!IsActive())
00807     return NULL;
00808 
00809   if (localId.IsEmpty()) {
00810     PTRACE(2, "H235RAS\tH235AuthCAT requires local ID for encoding.");
00811     return NULL;
00812   }
00813 
00814   H235_ClearToken * clearToken = new H235_ClearToken;
00815 
00816   // Cisco compatible hash calculation
00817   clearToken->m_tokenOID = OID_CAT;
00818 
00819   clearToken->IncludeOptionalField(H235_ClearToken::e_generalID);
00820   clearToken->m_generalID = GetUCS2plusNULL(localId);
00821 
00822   clearToken->IncludeOptionalField(H235_ClearToken::e_timeStamp);
00823   clearToken->m_timeStamp = (int)time(NULL);
00824   PUInt32b timeStamp = (DWORD)clearToken->m_timeStamp;
00825 
00826   clearToken->IncludeOptionalField(H235_ClearToken::e_random);
00827   BYTE random = (BYTE)++sentRandomSequenceNumber;
00828   clearToken->m_random = (unsigned)random;
00829 
00830   // Generate an MD5 of the clear tokens PER encoding.
00831   PMessageDigest5 stomach;
00832   stomach.Process(&random, 1);
00833   stomach.Process(password);
00834   stomach.Process(&timeStamp, 4);
00835   PMessageDigest5::Code digest;
00836   stomach.Complete(digest);
00837 
00838   clearToken->IncludeOptionalField(H235_ClearToken::e_challenge);
00839   clearToken->m_challenge.SetValue((const BYTE *)&digest, sizeof(digest));
00840 
00841   return clearToken;
00842 }
00843 
00844 
00845 H235Authenticator::ValidationResult
00846         H235AuthCAT::ValidateClearToken(const H235_ClearToken & clearToken)
00847 {
00848   if (!IsActive())
00849     return e_Disabled;
00850 
00851   if (clearToken.m_tokenOID != OID_CAT)
00852     return e_Absent;
00853 
00854   if (!clearToken.HasOptionalField(H235_ClearToken::e_generalID) ||
00855       !clearToken.HasOptionalField(H235_ClearToken::e_timeStamp) ||
00856       !clearToken.HasOptionalField(H235_ClearToken::e_random) ||
00857       !clearToken.HasOptionalField(H235_ClearToken::e_challenge)) {
00858     PTRACE(2, "H235RAS\tCAT requires generalID, timeStamp, random and challenge fields");
00859     return e_Error;
00860   }
00861 
00862   //first verify the timestamp
00863   PTime now;
00864   int deltaTime = now.GetTimeInSeconds() - clearToken.m_timeStamp;
00865   if (PABS(deltaTime) > timestampGracePeriod) {
00866     PTRACE(1, "H235RAS\tInvalid timestamp ABS(" << now.GetTimeInSeconds() << '-' 
00867            << (int)clearToken.m_timeStamp << ") > " << timestampGracePeriod);
00868     //the time has elapsed
00869     return e_InvalidTime;
00870   }
00871 
00872   //verify the randomnumber
00873   if (lastTimestamp == clearToken.m_timeStamp &&
00874       lastRandomSequenceNumber == clearToken.m_random) {
00875     //a message with this timespamp and the same random number was already verified
00876     PTRACE(1, "H235RAS\tConsecutive messages with the same random and timestamp");
00877     return e_ReplyAttack;
00878   }
00879 
00880   if (!remoteId && clearToken.m_generalID.GetValue() != remoteId) {
00881     PTRACE(1, "H235RAS\tGeneral ID is \"" << clearToken.m_generalID.GetValue()
00882            << "\", should be \"" << remoteId << '"');
00883     return e_Error;
00884   }
00885 
00886   int randomInt = clearToken.m_random;
00887   if (randomInt < -127 || randomInt > 255) {
00888     PTRACE(2, "H235RAS\tCAT requires single byte random field, got " << randomInt);
00889     return e_Error;
00890   }
00891 
00892   PUInt32b timeStamp = (DWORD)clearToken.m_timeStamp;
00893   BYTE randomByte = (BYTE)randomInt;
00894 
00895   // Generate an MD5 of the clear tokens PER encoding.
00896   PMessageDigest5 stomach;
00897   stomach.Process(&randomByte, 1);
00898   stomach.Process(password);
00899   stomach.Process(&timeStamp, 4);
00900   PMessageDigest5::Code digest;
00901   stomach.Complete(digest);
00902 
00903   if (clearToken.m_challenge.GetValue().GetSize() != sizeof(digest)) {
00904     PTRACE(2, "H235RAS\tCAT requires 16 byte challenge field");
00905     return e_Error;
00906   }
00907 
00908   if (memcmp((const BYTE *)clearToken.m_challenge.GetValue(), &digest, sizeof(digest)) == 0) {
00909 
00910     // save the values for the next call
00911     lastRandomSequenceNumber = clearToken.m_random;
00912     lastTimestamp = clearToken.m_timeStamp;
00913   
00914     return e_OK;
00915   }
00916 
00917   PTRACE(2, "H235RAS\tCAT hash does not match");
00918   return e_BadPassword;
00919 }
00920 
00921 
00922 BOOL H235AuthCAT::IsCapability(const H235_AuthenticationMechanism & mechanism,
00923                                      const PASN_ObjectId & algorithmOID)
00924 {
00925   if (mechanism.GetTag() != H235_AuthenticationMechanism::e_authenticationBES ||
00926          algorithmOID.AsString() != OID_CAT)
00927     return FALSE;
00928 
00929   const H235_AuthenticationBES & bes = mechanism;
00930   return bes.GetTag() == H235_AuthenticationBES::e_radius;
00931 }
00932 
00933 
00934 BOOL H235AuthCAT::SetCapability(H225_ArrayOf_AuthenticationMechanism & mechanisms,
00935                                 H225_ArrayOf_PASN_ObjectId & algorithmOIDs)
00936 {
00937   if (!AddCapability(H235_AuthenticationMechanism::e_authenticationBES, OID_CAT,
00938                      mechanisms, algorithmOIDs))
00939     return FALSE;
00940 
00941   H235_AuthenticationBES & bes = mechanisms[mechanisms.GetSize()-1];
00942   bes.SetTag(H235_AuthenticationBES::e_radius);
00943   return TRUE;
00944 }
00945 
00946 
00947 BOOL H235AuthCAT::IsSecuredPDU(unsigned rasPDU, BOOL received) const
00948 {
00949   switch (rasPDU) {
00950     case H225_RasMessage::e_registrationRequest :
00951     case H225_RasMessage::e_admissionRequest :
00952       return received ? !remoteId.IsEmpty() : !localId.IsEmpty();
00953 
00954     default :
00955       return FALSE;
00956   }
00957 }
00958 
00959 

Generated on Thu Oct 25 13:42:53 2007 for h323plus by  doxygen 1.5.2