00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
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;
00177 usage = 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
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 & )
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 & )
00279 {
00280 return e_Absent;
00281 }
00282
00283
00284 H235Authenticator::ValidationResult H235Authenticator::ValidateCryptoToken(
00285 const H225_CryptoH323Token & ,
00286 const PBYTEArray & )
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
00365
00366
00367
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
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 :
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
00451
00452
00453
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 :
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;
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
00629 H235_ClearToken clearToken;
00630
00631
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
00644 PPER_Stream strm;
00645 clearToken.Encode(strm);
00646 strm.CompleteEncoding();
00647
00648
00649 PMessageDigest5 stomach;
00650 stomach.Process(strm.GetPointer(), strm.GetSize());
00651 PMessageDigest5::Code digest;
00652 stomach.Complete(digest);
00653
00654
00655 H225_CryptoH323Token * cryptoToken = new H225_CryptoH323Token;
00656 cryptoToken->SetTag(H225_CryptoH323Token::e_cryptoEPPwdHash);
00657 H225_CryptoH323Token_cryptoEPPwdHash & cryptoEPPwdHash = *cryptoToken;
00658
00659
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
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
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
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
00718 PPER_Stream strm;
00719 clearToken.Encode(strm);
00720 strm.CompleteEncoding();
00721
00722
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
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
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
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
00869 return e_InvalidTime;
00870 }
00871
00872
00873 if (lastTimestamp == clearToken.m_timeStamp &&
00874 lastRandomSequenceNumber == clearToken.m_random) {
00875
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
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
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