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 #include <ptlib.h>
00111
00112 #if P_SSL
00113
00114 #include <openssl/sha.h>
00115
00116 #include "h235auth.h"
00117 #include "h323pdu.h"
00118
00119 namespace PWLibStupidLinkerHacks {
00120 int h235AuthProcedure1Loader;
00121 };
00122
00123 #ifdef _MSC_VER
00124 #pragma comment(lib, P_SSL_LIB1)
00125 #pragma comment(lib, P_SSL_LIB2)
00126 #endif
00127
00128
00129 #define REPLY_BUFFER_SIZE 1024
00130
00131
00132 static const char OID_A[] = "0.0.8.235.0.2.1";
00133 static const char OID_T[] = "0.0.8.235.0.2.5";
00134 static const char OID_U[] = "0.0.8.235.0.2.6";
00135
00136 #define OID_VERSION_OFFSET 5
00137
00138
00139 #define HASH_SIZE 12
00140
00141 static const BYTE SearchPattern[HASH_SIZE] = {
00142 't', 'W', 'e', 'l', 'V', 'e', '~', 'b', 'y', 't', 'e', 'S'
00143 };
00144
00145 #ifndef SHA_DIGESTSIZE
00146 #define SHA_DIGESTSIZE 20
00147 #endif
00148
00149 #ifndef SHA_BLOCKSIZE
00150 #define SHA_BLOCKSIZE 64
00151 #endif
00152
00153
00154 #define new PNEW
00155
00156
00158
00159
00160 #if 0
00161 static void pr_sha(FILE* fp, char* s, int t)
00162 {
00163 int i ;
00164
00165 fprintf(fp, "0x") ;
00166 for (i = 0 ; i < t ; i++)
00167 fprintf(fp, "%02x", s[i]) ;
00168 fprintf(fp, "0x") ;
00169 }
00170 #endif
00171
00172 static void truncate(unsigned char* d1,
00173 char* d2,
00174 int len)
00175 {
00176 int i ;
00177 for (i = 0 ; i < len ; i++) d2[i] = d1[i];
00178 }
00179
00180
00181 static void hmac_sha (const unsigned char* k,
00182 int lk,
00183 const unsigned char* d,
00184 int ld,
00185 char* out,
00186 int t)
00187 {
00188 SHA_CTX ictx, octx ;
00189 unsigned char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
00190 unsigned char key[SHA_DIGESTSIZE] ;
00191 char buf[SHA_BLOCKSIZE] ;
00192 int i ;
00193
00194 if (lk > SHA_BLOCKSIZE) {
00195
00196 SHA_CTX tctx ;
00197
00198 SHA1_Init(&tctx) ;
00199 SHA1_Update(&tctx, k, lk) ;
00200 SHA1_Final(key, &tctx) ;
00201
00202 k = key ;
00203 lk = SHA_DIGESTSIZE ;
00204 }
00205
00206
00207
00208 SHA1_Init(&ictx) ;
00209
00210
00211 for (i = 0 ; i < lk ; ++i) buf[i] = (char)(k[i] ^ 0x36);
00212 for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36;
00213
00214 SHA1_Update(&ictx, buf, SHA_BLOCKSIZE) ;
00215 SHA1_Update(&ictx, d, ld) ;
00216
00217 SHA1_Final(isha, &ictx) ;
00218
00219
00220
00221 SHA1_Init(&octx) ;
00222
00223
00224
00225 for (i = 0 ; i < lk ; ++i) buf[i] = (char)(k[i] ^ 0x5C);
00226 for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C;
00227
00228 SHA1_Update(&octx, buf, SHA_BLOCKSIZE) ;
00229 SHA1_Update(&octx, isha, SHA_DIGESTSIZE) ;
00230
00231 SHA1_Final(osha, &octx) ;
00232
00233
00234 t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ;
00235 truncate(osha, out, t) ;
00236
00237 }
00238
00239
00241
00242 static PFactory<H235Authenticator>::Worker<H2351_Authenticator> factoryH2351_Authenticator("H2351_Authenticator");
00243
00244 H2351_Authenticator::H2351_Authenticator()
00245 {
00246 usage = AnyApplication;
00247 }
00248
00249
00250 PObject * H2351_Authenticator::Clone() const
00251 {
00252 H2351_Authenticator * auth = new H2351_Authenticator(*this);
00253
00254
00255 auth->lastRandomSequenceNumber = 0;
00256 auth->lastTimestamp = 0;
00257
00258 return auth;
00259 }
00260
00261
00262 const char * H2351_Authenticator::GetName() const
00263 {
00264 return "H.235.1";
00265 }
00266
00267
00268 H225_CryptoH323Token * H2351_Authenticator::CreateCryptoToken()
00269 {
00270 if (!IsActive())
00271 return NULL;
00272
00273 H225_CryptoH323Token * cryptoToken = new H225_CryptoH323Token;
00274
00275
00276 cryptoToken->SetTag(H225_CryptoH323Token::e_nestedcryptoToken);
00277 H235_CryptoToken & nestedCryptoToken = *cryptoToken;
00278
00279
00280 nestedCryptoToken.SetTag(H235_CryptoToken::e_cryptoHashedToken);
00281 H235_CryptoToken_cryptoHashedToken & cryptoHashedToken = nestedCryptoToken;
00282
00283
00284 cryptoHashedToken.m_tokenOID = OID_A;
00285
00286
00287 H235_ClearToken & clearToken = cryptoHashedToken.m_hashedVals;
00288
00289
00290 clearToken.m_tokenOID = OID_T;
00291
00292 if (!remoteId) {
00293 clearToken.IncludeOptionalField(H235_ClearToken::e_generalID);
00294 clearToken.m_generalID = remoteId;
00295 }
00296
00297 if (!localId) {
00298 clearToken.IncludeOptionalField(H235_ClearToken::e_sendersID);
00299 clearToken.m_sendersID = localId;
00300 }
00301
00302 clearToken.IncludeOptionalField(H235_ClearToken::e_timeStamp);
00303 clearToken.m_timeStamp = (int)PTime().GetTimeInSeconds();
00304
00305 clearToken.IncludeOptionalField(H235_ClearToken::e_random);
00306 clearToken.m_random = ++sentRandomSequenceNumber;
00307
00308
00309 H235_HASHED<H235_EncodedGeneralToken> & encodedToken = cryptoHashedToken.m_token;
00310
00311
00312 encodedToken.m_algorithmOID = OID_U;
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 encodedToken.m_hash.SetData(HASH_SIZE*8, SearchPattern);
00323 return cryptoToken;
00324 }
00325
00326
00327 BOOL H2351_Authenticator::Finalise(PBYTEArray & rawPDU)
00328 {
00329 if (!IsActive())
00330 return FALSE;
00331
00332
00333
00334 int foundat = -1;
00335 for (PINDEX i = 0; i <= rawPDU.GetSize() - HASH_SIZE; i++) {
00336 if (memcmp(&rawPDU[i], SearchPattern, HASH_SIZE) == 0) {
00337 foundat = i;
00338 break;
00339 }
00340 }
00341
00342 if (foundat == -1) {
00343
00344 PTRACE(2, "H235RAS\tPDU not prepared for H2351_Authenticator");
00345 return FALSE;
00346 }
00347
00348
00349 memset(&rawPDU[foundat], 0, HASH_SIZE);
00350
00351
00352
00353
00354
00355
00356
00357
00358 char key[HASH_SIZE];
00359
00361 unsigned char secretkey[20];
00362
00363 SHA1((unsigned char *)password.GetPointer(), password.GetSize()-1, secretkey);
00364
00365 hmac_sha(secretkey, 20, rawPDU.GetPointer(), rawPDU.GetSize(), key, HASH_SIZE);
00366
00367 memcpy(&rawPDU[foundat], key, HASH_SIZE);
00368
00369 PTRACE(4, "H235RAS\tH2351_Authenticator hashing completed: \"" << password << '"');
00370 return TRUE;
00371 }
00372
00373
00374 static BOOL CheckOID(const PASN_ObjectId & oid1, const PASN_ObjectId & oid2)
00375 {
00376 if (oid1.GetSize() != oid2.GetSize())
00377 return FALSE;
00378
00379 PINDEX i;
00380 for (i = 0; i < OID_VERSION_OFFSET; i++) {
00381 if (oid1[i] != oid2[i])
00382 return FALSE;
00383 }
00384
00385 for (i++; i < oid1.GetSize(); i++) {
00386 if (oid1[i] != oid2[i])
00387 return FALSE;
00388 }
00389
00390 return TRUE;
00391 }
00392
00393
00394 H235Authenticator::ValidationResult H2351_Authenticator::ValidateCryptoToken(
00395 const H225_CryptoH323Token & cryptoToken,
00396 const PBYTEArray & rawPDU)
00397 {
00398
00399 if (cryptoToken.GetTag() != H225_CryptoH323Token::e_nestedcryptoToken) {
00400 PTRACE(4, "H235\tNo nested crypto token!");
00401 return e_Absent;
00402 }
00403
00404 const H235_CryptoToken & crNested = cryptoToken;
00405 if (crNested.GetTag() != H235_CryptoToken::e_cryptoHashedToken) {
00406 PTRACE(4, "H235\tNo crypto hash token!");
00407 return e_Absent;
00408 }
00409
00410 const H235_CryptoToken_cryptoHashedToken & crHashed = crNested;
00411
00412
00413
00414
00415 if (!CheckOID(crHashed.m_tokenOID, OID_A)) {
00416 PTRACE(2, "H235RAS\tH2351_Authenticator requires all fields are hashed, got OID " << crHashed.m_tokenOID);
00417 return e_Absent;
00418 }
00419
00420
00421 if (!CheckOID(crHashed.m_hashedVals.m_tokenOID, OID_T)) {
00422 PTRACE(2, "H235RAS\tH2351_Authenticator requires ClearToken, got OID " << crHashed.m_hashedVals.m_tokenOID);
00423 return e_Absent;
00424 }
00425
00426
00427 if (!CheckOID(crHashed.m_token.m_algorithmOID, OID_U)) {
00428 PTRACE(2, "H235RAS\tH2351_Authenticator requires HMAC-SHA1-96, got OID " << crHashed.m_token.m_algorithmOID);
00429 return e_Absent;
00430 }
00431
00432
00433 PTime now;
00434 int deltaTime = now.GetTimeInSeconds() - crHashed.m_hashedVals.m_timeStamp;
00435 if (PABS(deltaTime) > timestampGracePeriod) {
00436 PTRACE(1, "H235RAS\tInvalid timestamp ABS(" << now.GetTimeInSeconds() << '-'
00437 << (int)crHashed.m_hashedVals.m_timeStamp << ") > " << timestampGracePeriod);
00438
00439 return e_InvalidTime;
00440 }
00441
00442
00443 if (lastTimestamp == crHashed.m_hashedVals.m_timeStamp &&
00444 lastRandomSequenceNumber == crHashed.m_hashedVals.m_random) {
00445
00446 PTRACE(1, "H235RAS\tConsecutive messages with the same random and timestamp");
00447 return e_ReplyAttack;
00448 }
00449
00450 #ifndef DISABLE_CALLAUTH
00451
00452 if (connection != NULL) {
00453
00454 if (!crHashed.m_hashedVals.HasOptionalField(H235_ClearToken::e_sendersID)) {
00455 PTRACE(1, "H235RAS\tH2351_Authenticator requires senders ID.");
00456 return e_Error;
00457 }
00458
00459 localId = crHashed.m_hashedVals.m_sendersID.GetValue();
00460 remoteId = PString::Empty();
00461 if (!connection->OnCallAuthentication(localId,password)) {
00462 PTRACE(1, "H235EP\tH2351_Authenticator Authentication Fail UserName \""
00463 << localId << "\", not Authorised. \"");
00464 return e_BadPassword;
00465 }
00466 } else {
00467 #endif
00468
00469 if (!localId && crHashed.m_tokenOID[OID_VERSION_OFFSET] > 1) {
00470 if (!crHashed.m_hashedVals.HasOptionalField(H235_ClearToken::e_generalID)) {
00471 PTRACE(1, "H235RAS\tH2351_Authenticator requires general ID.");
00472 return e_Error;
00473 }
00474
00475 if (crHashed.m_hashedVals.m_generalID.GetValue() != localId) {
00476 PTRACE(1, "H235RAS\tGeneral ID is \"" << crHashed.m_hashedVals.m_generalID.GetValue()
00477 << "\", should be \"" << localId << '"');
00478 return e_Error;
00479 }
00480 }
00481 #ifndef DISABLE_CALLAUTH
00482 }
00483 #endif
00484
00485 if (!remoteId) {
00486 if (!crHashed.m_hashedVals.HasOptionalField(H235_ClearToken::e_sendersID)) {
00487 PTRACE(1, "H235RAS\tH2351_Authenticator requires senders ID.");
00488 return e_Error;
00489 }
00490
00491 if (crHashed.m_hashedVals.m_sendersID.GetValue() != remoteId) {
00492 PTRACE(1, "H235RAS\tSenders ID is \"" << crHashed.m_hashedVals.m_sendersID.GetValue()
00493 << "\", should be \"" << remoteId << '"');
00494 return e_Error;
00495 }
00496 }
00497
00498
00499
00500
00501
00502
00503
00504 BYTE RV[HASH_SIZE];
00505
00506 if (crHashed.m_token.m_hash.GetSize() != HASH_SIZE*8) {
00507 PTRACE(2, "H235RAS\tH2351_Authenticator requires a hash!");
00508 return e_Error;
00509 }
00510
00511 const unsigned char *data = crHashed.m_token.m_hash.GetDataPointer();
00512 memcpy(RV, data, HASH_SIZE);
00513
00514 unsigned char secretkey[20];
00515 SHA1((unsigned char *)password.GetPointer(), password.GetSize()-1, secretkey);
00516
00517
00518
00519
00520
00521
00522
00523 PINDEX foundat = 0;
00524 bool found = false;
00525
00526 const BYTE * asnPtr = rawPDU;
00527 PINDEX asnLen = rawPDU.GetSize();
00528 while (foundat < asnLen - HASH_SIZE) {
00529 for (PINDEX i = foundat; i <= asnLen - HASH_SIZE; i++) {
00530 if (memcmp(asnPtr+i, data, HASH_SIZE) == 0) {
00531 foundat = i;
00532 found = true;
00533 break;
00534 }
00535 }
00536
00537 if (!found) {
00538 if (foundat != 0)
00539 break;
00540
00541 PTRACE(2, "H235RAS\tH2351_Authenticator could not locate embedded hash!");
00542 return e_Error;
00543 }
00544
00545 found = false;
00546
00547 memset((BYTE *)asnPtr+foundat, 0, HASH_SIZE);
00548
00549
00550
00551
00552
00553
00554
00555 char key[HASH_SIZE];
00556 hmac_sha(secretkey, 20, asnPtr, asnLen, key, HASH_SIZE);
00557
00558
00559
00560
00561
00562
00563 if (memcmp(key, RV, HASH_SIZE) == 0) {
00564
00565 lastRandomSequenceNumber = crHashed.m_hashedVals.m_random;
00566 lastTimestamp = crHashed.m_hashedVals.m_timeStamp;
00567
00568 return e_OK;
00569 }
00570
00571
00572 memcpy((BYTE *)asnPtr+foundat, data, HASH_SIZE);
00573 foundat++;
00574 }
00575
00576 PTRACE(1, "H235RAS\tH2351_Authenticator hash does not match.");
00577 return e_BadPassword;
00578 }
00579
00580
00581 BOOL H2351_Authenticator::IsCapability(const H235_AuthenticationMechanism & mechansim,
00582 const PASN_ObjectId & algorithmOID)
00583 {
00584 return mechansim.GetTag() == H235_AuthenticationMechanism::e_pwdHash &&
00585 algorithmOID.AsString() == OID_U;
00586 }
00587
00588
00589 BOOL H2351_Authenticator::SetCapability(H225_ArrayOf_AuthenticationMechanism & mechanisms,
00590 H225_ArrayOf_PASN_ObjectId & algorithmOIDs)
00591 {
00592 return AddCapability(H235_AuthenticationMechanism::e_pwdHash, OID_U, mechanisms, algorithmOIDs);
00593 }
00594
00595 BOOL H2351_Authenticator::IsSecuredPDU(unsigned rasPDU, BOOL received) const
00596 {
00597 switch (rasPDU) {
00598 case H225_RasMessage::e_registrationRequest :
00599 case H225_RasMessage::e_admissionRequest :
00600 return received ? !remoteId.IsEmpty() : !localId.IsEmpty();
00601
00602 default :
00603 return FALSE;
00604 }
00605 }
00606
00607 BOOL H2351_Authenticator::IsSecuredSignalPDU(unsigned signalPDU, BOOL received) const
00608 {
00609 switch (signalPDU) {
00610 case H225_H323_UU_PDU_h323_message_body::e_setup:
00611 return received ? !remoteId.IsEmpty() : !localId.IsEmpty();
00612
00613 default :
00614 return FALSE;
00615 }
00616 }
00617
00618 BOOL H2351_Authenticator::UseGkAndEpIdentifiers() const
00619 {
00620 return TRUE;
00621 }
00622
00623
00624 #endif // P_SSL
00625
00626