Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

SSLv2.cc

Go to the documentation of this file.
00001 // $Id: SSLv2.cc,v 1.2 2004/03/21 14:57:40 vern Exp $
00002 
00003 #include "SSLv2.h"
00004 #include "SSLv3.h"
00005 
00006 // --- Initalization of static variables --------------------------------------
00007 
00008 uint SSLv2_Interpreter::totalConnections = 0;
00009 uint SSLv2_Interpreter::analyzedConnections = 0;
00010 uint SSLv2_Interpreter::openedConnections = 0;
00011 uint SSLv2_Interpreter::failedConnections = 0;
00012 uint SSLv2_Interpreter::weirdConnections = 0;
00013 uint SSLv2_Interpreter::totalRecords = 0;
00014 uint SSLv2_Interpreter::clientHelloRecords = 0;
00015 uint SSLv2_Interpreter::serverHelloRecords = 0;
00016 uint SSLv2_Interpreter::clientMasterKeyRecords = 0;
00017 uint SSLv2_Interpreter::errorRecords = 0;
00018 
00019 
00020 // --- SSLv2_Interpreter -------------------------------------------------------
00021 
00027 SSLv2_Interpreter::SSLv2_Interpreter(SSL_ConnectionProxy* proxy)
00028 : SSL_Interpreter(proxy)
00029         {
00030         ++totalConnections;
00031         records = 0;
00032         bAnalyzedCounted = false;
00033         connState = START;
00034 
00035         pServerCipherSpecs = 0;
00036         pClientCipherSpecs = 0;
00037         bClientWantsCachedSession = false;
00038         usedCipherSpec = (SSLv2_CipherSpec) 0;
00039 
00040         pConnectionId = 0;
00041         pChallenge = 0;
00042         pSessionId = 0;
00043         pMasterClearKey = 0;
00044         pMasterEncryptedKey = 0;
00045         pClientReadKey = 0;
00046         pServerReadKey = 0;
00047         }
00048 
00052 SSLv2_Interpreter::~SSLv2_Interpreter()
00053         {
00054         if ( connState != CLIENT_MASTERKEY_SEEN &&
00055              connState != CACHED_SESSION &&
00056              connState != START &&      // we only complain if we saw some data
00057              connState != ERROR_SEEN )
00058                 ++failedConnections;
00059 
00060         if ( connState != CLIENT_MASTERKEY_SEEN && connState != CACHED_SESSION )
00061                 ++weirdConnections;
00062 
00063         delete pServerCipherSpecs;
00064         delete pClientCipherSpecs;
00065         delete pConnectionId;
00066         delete pChallenge;
00067         delete pSessionId;
00068         delete pMasterClearKey;
00069         delete pMasterEncryptedKey;
00070         delete pClientReadKey;
00071         delete pServerReadKey;
00072         }
00073 
00077 void SSLv2_Interpreter::BuildInterpreterEndpoints()
00078         {
00079         orig = new SSLv2_Endpoint(this, 1);
00080         resp = new SSLv2_Endpoint(this, 0);
00081         }
00082 
00086 void SSLv2_Interpreter::printStats()
00087         {
00088         printf("SSLv2:\n");
00089         printf("totalConnections    = %u\n", totalConnections);
00090         printf("analyzedConnections = %u\n", analyzedConnections);
00091         printf("openedConnections   = %u\n", openedConnections);
00092         printf("failedConnections   = %u\n", failedConnections);
00093         printf("weirdConnections   = %u\n", weirdConnections);
00094 
00095         printf("totalRecords            = %u\n", totalRecords);
00096         printf("clientHelloRecords      = %u\n", clientHelloRecords);
00097         printf("serverHelloRecords      = %u\n", serverHelloRecords);
00098         printf("clientMasterKeyRecords  = %u\n", clientMasterKeyRecords);
00099         printf("errorRecords            = %u\n", errorRecords);
00100 
00101         printf("SSL_RecordBuilder::maxAllocCount     = %u\n", SSL_RecordBuilder::maxAllocCount);
00102         printf("SSL_RecordBuilder::maxFragmentCount  = %u\n", SSL_RecordBuilder::maxFragmentCount);
00103         printf("SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders);
00104         }
00105 
00109 SSLv2_States SSLv2_Interpreter::ConnState()
00110         {
00111         return connState;
00112         }
00113 
00124 void SSLv2_Interpreter::NewSSLRecord(SSL_InterpreterEndpoint* s,
00125                                         int length, u_char* data)
00126         {
00127         ++records;
00128         ++totalRecords;
00129 
00130         if ( ! bAnalyzedCounted )
00131                 {
00132                 ++analyzedConnections;
00133                 bAnalyzedCounted = true;
00134                 }
00135 
00136         // We should see a maximum of 4 cleartext records.
00137         if ( records == 5 )
00138                 { // so this should never happen
00139                 Weird("SSLv2: Saw more than 4 records, skipping connection...");
00140                 proxy->SetSkip(1);
00141                 return;
00142                 }
00143 
00144         // SSLv2 record header analysis
00145         uint32 recordLength = 0; // data length of SSLv2 record
00146         bool isEscape = false;
00147         uint8 padding = 0;
00148         u_char* contents;
00149 
00150         if ( (data[0] & 0x80) > 0 )
00151                 { // we have a two-byte record header
00152                 recordLength = ((data[0] & 0x7f) << 8) | data[1];
00153                 contents = data + 2;
00154                 if (  recordLength + 2 != uint32(length)  )
00155                         {
00156                         // This should never happen, otherwise
00157                         // we have a bug in the SSL_RecordBuilder.
00158                         Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
00159                         connState = ERROR_REQUIRED;
00160                         proxy->SetSkip(1);
00161                         return;
00162                         }
00163                 }
00164         else
00165                 { // We have a three-byte record header.
00166                 recordLength = ((data[0] & 0x3f) << 8) | data[1];
00167                 isEscape = (data[0] & 0x40) != 0;
00168                 padding = data[2];
00169                 contents = data + 3;
00170                 if ( recordLength + 3 != uint32(length) )
00171                         {
00172                         // This should never happen, otherwise
00173                         // we have a bug in the SSL_RecordBuilder.
00174                         Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
00175                         connState = ERROR_REQUIRED;
00176                         proxy->SetSkip(1);
00177                         return;
00178                         }
00179 
00180                 if ( padding == 0 && ! isEscape )
00181                         Weird("SSLv2: 3 Byte record header, but no escape, no padding!");
00182                 }
00183 
00184         if ( recordLength == 0 )
00185                 {
00186                 Weird("SSLv2: Record length is zero (no record data)!");
00187                 return;
00188                 }
00189 
00190         if ( isEscape )
00191                 Weird("SSLv2: Record has escape bit set (security escape)!");
00192 
00193         if  ( padding > 0 && connState != CACHED_SESSION &&
00194               connState != CLIENT_MASTERKEY_SEEN )
00195                 Weird("SSLv2 record with padding > 0 in cleartext!");
00196 
00197         // MISSING:
00198         // A final consistency check is done when a block cipher is used
00199         // and the protocol is using encryption. The amount of data present
00200         // in a record (RECORD-LENGTH))must be a multiple of the cipher's
00201         // block size.  If the received record is not a multiple of the
00202         // cipher's block size then the record is considered damaged, and it
00203         // is to be treated as if an "I/O Error" had occurred (i.e. an
00204         // unrecoverable error is asserted and the connection is closed).
00205 
00206         switch ( connState ) {
00207         case START:
00208                 // Only CLIENT-HELLLOs allowed here.
00209                 if ( contents[0] != SSLv2_MT_CLIENT_HELLO )
00210                         {
00211                         Weird("SSLv2: First packet is not a CLIENT-HELLO!");
00212                         analyzeRecord(s, recordLength, contents);
00213                         connState = ERROR_REQUIRED;
00214                         }
00215                 else
00216                         connState = ClientHelloRecord(s, recordLength, contents);
00217                 break;
00218 
00219         case CLIENT_HELLO_SEEN:
00220                 // Only SERVER-HELLOs or ERRORs allowed here.
00221                 if ( contents[0] == SSLv2_MT_SERVER_HELLO )
00222                         connState = ServerHelloRecord(s, recordLength, contents);
00223                 else if ( contents[0] == SSLv2_MT_ERROR )
00224                         connState = ErrorRecord(s, recordLength, contents);
00225                 else
00226                         {
00227                         Weird("SSLv2: State violation in CLIENT_HELLO_SEEN!");
00228                         analyzeRecord(s, recordLength, contents);
00229                         connState = ERROR_REQUIRED;
00230                         }
00231                 break;
00232 
00233         case NEW_SESSION:
00234                 // We expect a client master key.
00235                 if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY )
00236                         connState = ClientMasterKeyRecord(s, recordLength, contents);
00237                 else if ( contents[0] == SSLv2_MT_ERROR )
00238                         connState = ErrorRecord(s, recordLength, contents);
00239                 else
00240                         {
00241                         Weird("SSLv2: State violation in NEW_SESSION or encrypted record!");
00242                         analyzeRecord(s, recordLength, contents);
00243                         connState = ERROR_REQUIRED;
00244                         }
00245 
00246                 delete pServerCipherSpecs;
00247                 pServerCipherSpecs = 0;
00248                 break;
00249 
00250         case CACHED_SESSION:
00251                 delete pServerCipherSpecs;
00252                 pServerCipherSpecs = 0;
00253                 // No break here.
00254 
00255         case CLIENT_MASTERKEY_SEEN:
00256                 // If no error record, no further analysis.
00257                 if ( contents[0] == SSLv2_MT_ERROR &&
00258                      recordLength == SSLv2_ERROR_RECORD_SIZE )
00259                         connState = ErrorRecord(s, recordLength, contents);
00260                 else
00261                         {
00262                         // So we finished the cleartext handshake.
00263                         // Skip all further data.
00264 
00265                         proxy->SetSkip(1);
00266                         ++openedConnections;
00267                         }
00268                 break;
00269 
00270         case ERROR_REQUIRED:
00271                 if ( contents[0] == SSLv2_MT_ERROR )
00272                         connState = ErrorRecord(s, recordLength, contents);
00273                 else
00274                         {
00275                         // We lost tracking: this should not happen.
00276                         Weird("SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!");
00277                         analyzeRecord(s, recordLength, contents);
00278                         connState = ERROR_REQUIRED;
00279                         }
00280                 break;
00281 
00282         case ERROR_SEEN:
00283                 // We don't have recoverable errors in cleartext phase,
00284                 // so we shouldn't see anymore packets.
00285                 Weird("SSLv2: Traffic after error record!");
00286                 analyzeRecord(s, recordLength, contents);
00287                 break;
00288 
00289         default:
00290                 internal_error("SSLv2: unknown state");
00291                 break;
00292         }
00293         }
00294 
00304 void SSLv2_Interpreter::analyzeRecord(SSL_InterpreterEndpoint* s,
00305                                         int length, u_char* data)
00306         {
00307         switch ( data[0] ) {
00308         case SSLv2_MT_ERROR:
00309                 ErrorRecord(s, length, data);
00310                 break;
00311 
00312         case SSLv2_MT_CLIENT_HELLO:
00313                 ClientHelloRecord(s, length, data);
00314                 break;
00315 
00316         case SSLv2_MT_CLIENT_MASTER_KEY:
00317                 ClientMasterKeyRecord(s, length, data);
00318                 break;
00319 
00320         case SSLv2_MT_SERVER_HELLO:
00321                 ServerHelloRecord(s, length, data);
00322                 break;
00323 
00324         case SSLv2_MT_CLIENT_FINISHED:
00325         case SSLv2_MT_SERVER_VERIFY:
00326         case SSLv2_MT_SERVER_FINISHED:
00327         case SSLv2_MT_REQUEST_CERTIFICATE:
00328         case SSLv2_MT_CLIENT_CERTIFICATE:
00329                 Weird("SSLv2: Encrypted record type seems to be in cleartext");
00330                 break;
00331 
00332         default:
00333                 // Unknown record type.
00334                 Weird("SSLv2: Unknown record type or encrypted record");
00335                 break;
00336         }
00337         }
00338 
00348 SSLv2_States SSLv2_Interpreter::ClientHelloRecord(SSL_InterpreterEndpoint* s,
00349                                         int recordLength, u_char* recordData)
00350         {
00351         // This method gets the record's data (without the header).
00352         ++clientHelloRecords;
00353 
00354         if ( s != orig )
00355                 Weird("SSLv2: CLIENT-HELLO record from server!");
00356 
00357         // There should not be any pending data in the SSLv2 reassembler,
00358         // because the client should wait for a server response.
00359         if ( ((SSLv2_Endpoint*) s)->isDataPending() )
00360                 Weird("SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!");
00361 
00362         // Client hello minimum header size check.
00363         if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE )
00364                 {
00365                 Weird("SSLv2: CLIENT-HELLO is too small!");
00366                 return ERROR_REQUIRED;
00367                 }
00368 
00369         // Extract the data of the client hello header.
00370         SSLv2_ClientHelloHeader ch;
00371         ch.clientVersion = uint16(recordData[1] << 8) | recordData[2];
00372         ch.cipherSpecLength = uint16(recordData[3] << 8) | recordData[4];
00373         ch.sessionIdLength = uint16(recordData[5] << 8) | recordData[6];
00374         ch.challengeLength = uint16(recordData[7] << 8) | recordData[8];
00375 
00376         if ( ch.clientVersion != SSL_ConnectionProxy::SSLv20 &&
00377              ch.clientVersion != SSL_ConnectionProxy::SSLv30 &&
00378              ch.clientVersion != SSL_ConnectionProxy::SSLv31 )
00379                 {
00380                 Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO");
00381                 return ERROR_REQUIRED;
00382                 }
00383 
00384         if ( ch.challengeLength + ch.cipherSpecLength + ch.sessionIdLength +
00385              SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength )
00386                 {
00387                 Weird("SSLv2: Size inconsistency in CLIENT-HELLO");
00388                 return ERROR_REQUIRED;
00389                 }
00390 
00391         // The CIPHER-SPECS-LENGTH must be > 0 and a multiple of 3.
00392         if ( ch.cipherSpecLength == 0 || ch.cipherSpecLength % 3 != 0 )
00393                 {
00394                 Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO.");
00395                 return ERROR_REQUIRED;
00396                 }
00397 
00398         // The SESSION-ID-LENGTH must either be zero or 16.
00399         if ( ch.sessionIdLength != 0 && ch.sessionIdLength != 16 )
00400                 Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO.");
00401 
00402         if ( (ch.challengeLength < 16) || (ch.challengeLength > 32))
00403                 Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO.");
00404 
00405         u_char* ptr = recordData;
00406         ptr += SSLv2_CLIENT_HELLO_HEADER_SIZE + ch.cipherSpecLength;
00407 
00408         pSessionId = new SSL_DataBlock(ptr, ch.sessionIdLength);
00409 
00410         // If decrypting, store the challenge.
00411         if ( ssl_store_key_material && ch.challengeLength <= 32 )
00412                 pChallenge = new SSL_DataBlock(ptr, ch.challengeLength);
00413 
00414         bClientWantsCachedSession = ch.sessionIdLength != 0;
00415 
00416         TableVal* currentCipherSuites =
00417                 analyzeCiphers(s, ch.cipherSpecLength,
00418                         recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE);
00419 
00420         fire_ssl_conn_attempt(ch.clientVersion, currentCipherSuites);
00421 
00422         return CLIENT_HELLO_SEEN;
00423         }
00424 
00434 SSLv2_States SSLv2_Interpreter::ServerHelloRecord(SSL_InterpreterEndpoint* s,
00435                                         int recordLength, u_char* recordData)
00436         {
00437         ++serverHelloRecords;
00438         TableVal* currentCipherSuites = NULL;
00439 
00440         if ( s != resp )
00441                 Weird("SSLv2: SERVER-HELLO from client!");
00442 
00443         if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE )
00444                 {
00445                 Weird("SSLv2: SERVER-HELLO is too small!");
00446                 return ERROR_REQUIRED;
00447                 }
00448 
00449         // Extract the data of the client hello header.
00450         SSLv2_ServerHelloHeader sh;
00451         sh.sessionIdHit = recordData[1];
00452         sh.certificateType = recordData[2];
00453         sh.serverVersion = uint16(recordData[3] << 8) | recordData[4];
00454         sh.certificateLength = uint16(recordData[5] << 8) | recordData[6];
00455         sh.cipherSpecLength = uint16(recordData[7] << 8) | recordData[8];
00456         sh.connectionIdLength = uint16(recordData[9] << 8) | recordData[10];
00457 
00458         if ( sh.serverVersion != SSL_ConnectionProxy::SSLv20 )
00459                 {
00460                 Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO");
00461                 return ERROR_REQUIRED;
00462                 }
00463 
00464         if ( sh.certificateLength + sh.cipherSpecLength +
00465              sh.connectionIdLength +
00466              SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength )
00467                 {
00468                 Weird("SSLv2: Size inconsistency in SERVER-HELLO");
00469                 return ERROR_REQUIRED;
00470                 }
00471 
00472         // The length of the CONNECTION-ID must be between 16 and 32 bytes.
00473         if ( sh.connectionIdLength < 16 || sh.connectionIdLength > 32 )
00474                 Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO");
00475 
00476         // If decrypting, store the connection ID.
00477         if ( ssl_store_key_material && sh.connectionIdLength <= 32 )
00478                 {
00479                 u_char* ptr = recordData;
00480 
00481                 ptr += SSLv2_SERVER_HELLO_HEADER_SIZE + sh.cipherSpecLength +
00482                        sh.certificateLength;
00483 
00484                 pConnectionId = new SSL_DataBlock(ptr, sh.connectionIdLength);
00485                 }
00486 
00487         if  (sh.sessionIdHit == 0 )
00488                 {
00489                 // Generating reusing-connection event.
00490                 EventHandlerPtr event = ssl_session_insertion;
00491 
00492                 if ( event )
00493                         {
00494                         TableVal* sessionIDTable = new TableVal(SSL_sessionID);
00495                         u_char* ptr = recordData;
00496                         ptr += SSLv2_SERVER_HELLO_HEADER_SIZE +
00497                                 sh.certificateLength + sh.cipherSpecLength;
00498 
00499                         for ( int i = 0; i < sh.connectionIdLength; i += 4 )
00500                                 {
00501                                 uint32 temp =
00502                                         (((ptr[i] << 24) |
00503                                           ptr[i + 1] << 16) |
00504                                          ptr[i + 2] << 8) | ptr[i + 3];
00505                                 sessionIDTable->Assign(
00506                                         new Val(i / 4, TYPE_COUNT),
00507                                         new Val(temp, TYPE_COUNT));
00508                                 }
00509 
00510                         val_list* vl = new val_list;
00511                         vl->append(proxy->BuildConnVal());
00512                         vl->append(sessionIDTable);
00513 
00514                         proxy->ConnectionEvent(ssl_session_insertion, vl);
00515                         }
00516                 }
00517 
00518         SSLv2_States nextState;
00519 
00520         if ( sh.sessionIdHit != 0 )
00521                 { // we're using a cached session
00522 
00523                 // There should not be any pending data in the SSLv2
00524                 // reassembler, because the server should wait for a
00525                 // client response.
00526                 if ( ((SSLv2_Endpoint*) s)->isDataPending() )
00527                         {
00528                         // But turns out some SSL Implementations do this
00529                         // when using a cached session.
00530                         }
00531 
00532                 // Consistency check for SESSION-ID-HIT.
00533                 if ( ! bClientWantsCachedSession )
00534                         Weird("SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!");
00535 
00536                 // If the SESSION-ID-HIT flag is non-zero then the
00537                 // CERTIFICATE-TYPE, CERTIFICATE-LENGTH and
00538                 // CIPHER-SPECS-LENGTH fields will be zero.
00539                 if ( sh.certificateType != 0 || sh.certificateLength != 0 ||
00540                      sh.cipherSpecLength != 0 )
00541                         Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO");
00542 
00543                 // Generate reusing-connection event.
00544                 if ( pSessionId )
00545                         {
00546                         fire_ssl_conn_reused(pSessionId);
00547                         delete pSessionId;
00548                         pSessionId = 0;
00549                         }
00550 
00551                 nextState = CACHED_SESSION;
00552                 }
00553         else
00554                 { // we're starting a new session
00555 
00556                 // There should not be any pending data in the SSLv2
00557                 // reassembler, because the server should wait for
00558                 // a client response.
00559                 if ( ((SSLv2_Endpoint*) s)->isDataPending() )
00560                         Weird("SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!");
00561 
00562                 // TODO: check certificate length ???
00563                 if ( sh.certificateLength == 0 )
00564                         Weird("SSLv2: No certificate in SERVER-HELLO!");
00565 
00566                 // The CIPHER-SPECS-LENGTH must be > zero and a multiple of 3.
00567                 if ( sh.cipherSpecLength == 0 )
00568                         Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!");
00569 
00570                 if ( sh.cipherSpecLength % 3 != 0 )
00571                         {
00572                         Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO");
00573                         return ERROR_REQUIRED;
00574                         }
00575 
00576                 u_char* ptr = recordData;
00577                 ptr += sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE;
00578                 currentCipherSuites = analyzeCiphers(s, sh.cipherSpecLength, ptr);
00579 
00580                 nextState = NEW_SESSION;
00581                 }
00582 
00583         // Check if at least one cipher is supported by the client.
00584         if ( pClientCipherSpecs && pServerCipherSpecs )
00585                 {
00586                 bool bFound = false;
00587                 for ( int i = 0; i < pClientCipherSpecs->len; i += 3 )
00588                         {
00589                         for ( int j = 0; j < pServerCipherSpecs->len; j += 3 )
00590                                 {
00591                                 if ( memcmp(pClientCipherSpecs + i,
00592                                             pServerCipherSpecs + j, 3) == 0 )
00593                                         {
00594                                         bFound = true;
00595                                         i = pClientCipherSpecs->len;
00596                                         break;
00597                                         }
00598                                 }
00599                         }
00600 
00601                 if ( ! bFound )
00602                         {
00603                         Weird("SSLv2: Client's and server's CIPHER-SPECS don't match!");
00604                         nextState = ERROR_REQUIRED;
00605                         }
00606 
00607                 delete pClientCipherSpecs;
00608                 pClientCipherSpecs = 0;
00609                 }
00610 
00611         // Certificate analysis.
00612         if ( sh.certificateLength > 0 && ssl_analyze_certificates != 0 )
00613                 {
00614                 analyzeCertificate(s, recordData + SSLv2_SERVER_HELLO_HEADER_SIZE,
00615                         sh.certificateLength, sh.certificateType, false);
00616                 }
00617 
00618         if ( nextState == NEW_SESSION )
00619                 // generate server-reply event
00620                 fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
00621 
00622         else if ( nextState == CACHED_SESSION )
00623                 { // generate server-reply event
00624                 fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
00625                 // Generate a connection-established event with a dummy
00626                 // cipher suite, since we can't remember session information
00627                 // (yet).
00628                 // Note: A new session identifier is sent encrypted in SSLv2!
00629                 fire_ssl_conn_established(sh.serverVersion, 0xABCD);
00630                 }
00631 
00632         return nextState;
00633         }
00634 
00644 SSLv2_States SSLv2_Interpreter::
00645 	ClientMasterKeyRecord(SSL_InterpreterEndpoint* s, int recordLength,
00646                                 u_char* recordData)
00647         {
00648         ++clientMasterKeyRecords;
00649         SSLv2_States nextState = CLIENT_MASTERKEY_SEEN;
00650 
00651         if ( s != orig )
00652                 Weird("SSLv2: CLIENT-MASTER-KEY from server!");
00653 
00654         if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE )
00655                 {
00656                 Weird("SSLv2: CLIENT-MASTER-KEY is too small!");
00657                 return ERROR_REQUIRED;
00658                 }
00659 
00660         // Extract the data of the client master key header.
00661         SSLv2_ClientMasterKeyHeader cmk;
00662         cmk.cipherKind =
00663                 ((recordData[1] << 16) | recordData[2] << 8) | recordData[3];
00664         cmk.clearKeyLength = uint16(recordData[4] << 8) | recordData[5];
00665         cmk.encryptedKeyLength = uint16(recordData[6] << 8) | recordData[7];
00666         cmk.keyArgLength = uint16(recordData[8] << 8) | recordData[9];
00667 
00668         if ( cmk.clearKeyLength + cmk.encryptedKeyLength + cmk.keyArgLength +
00669              SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength )
00670                 {
00671                 Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY");
00672                 return ERROR_REQUIRED;
00673                 }
00674 
00675         // Check if cipher is supported by the server.
00676         if ( pServerCipherSpecs )
00677                 {
00678                 bool bFound = false;
00679                 for ( int i = 0; i < pServerCipherSpecs->len; i += 3 )
00680                         {
00681                         uint32 cipherSpec =
00682                                 ((pServerCipherSpecs->data[i] << 16) |
00683                                  pServerCipherSpecs->data[i+1] << 8) |
00684                                 pServerCipherSpecs->data[i+2];
00685 
00686                         if ( cmk.cipherKind == cipherSpec )
00687                                 {
00688                                 bFound = true;
00689                                 break;
00690                                 }
00691                         }
00692 
00693                 if ( ! bFound )
00694                         {
00695                         Weird("SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!");
00696                         nextState = ERROR_REQUIRED;
00697                         }
00698                 else
00699                         nextState = CLIENT_MASTERKEY_SEEN;
00700 
00701                 delete pServerCipherSpecs;
00702                 pServerCipherSpecs = 0;
00703                 }
00704 
00705         // TODO: check if cipher has been advertised before.
00706 
00707         SSL_CipherSpec* pCipherSpecTemp = 0;
00708 
00709         HashKey h(cmk.cipherKind);
00710         pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
00711         if ( ! pCipherSpecTemp || ! (pCipherSpecTemp->flags & SSL_FLAG_SSLv20) )
00712                 Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!");
00713         else
00714                 { // check for conistency of clearKeyLength
00715                 if ( cmk.clearKeyLength * 8 != pCipherSpecTemp->clearKeySize )
00716                         {
00717                         Weird("SSLv2: Inconsistency of clearKeyLength in CLIENT-MASTER-KEY!");
00718                         // nextState = ERROR_REQUIRED;
00719                         }
00720 
00721                 // TODO: check for consistency of encryptedKeyLength.
00722                 // TODO: check for consistency of keyArgLength.
00723 //              switch ( cmk.cipherKind )
00724 //                      {
00725 //                      case SSL_CK_RC4_128_WITH_MD5:
00726 //                      case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
00727 //                              if ( cmk.keyArgLength != 0 )
00728 //                                      {
00729 //                                      Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
00730 //                                      //nextState = ERROR_REQUIRED;
00731 //                                      }
00732 //                      break;
00733 //                      case SSL_CK_DES_64_CBC_WITH_MD5:
00734 //                      case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
00735 //                      case SSL_CK_RC2_128_CBC_WITH_MD5:
00736 //                              case SSL_CK_IDEA_128_CBC_WITH_MD5:
00737 //                      case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
00738 //                              if ( cmk.keyArgLength != 8 )
00739 //                                      {
00740 //                                      Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
00741 //                                      }
00742 //                      break;
00743 //                      }
00744                 }
00745 
00746         // Remember the used cipher spec.
00747         usedCipherSpec = SSLv2_CipherSpec(cmk.cipherKind);
00748 
00749         // If decrypting, store the clear key part of the master key.
00750         if ( ssl_store_key_material /* && cmk.clearKeyLength == 11 */ )
00751                 {
00752                 pMasterClearKey =
00753                         new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE), cmk.clearKeyLength);
00754 
00755                 pMasterEncryptedKey =
00756                         new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE + cmk.clearKeyLength ), cmk.encryptedKeyLength);
00757                 }
00758 
00759         if ( nextState == CLIENT_MASTERKEY_SEEN )
00760                 fire_ssl_conn_established(SSL_ConnectionProxy::SSLv20,
00761                                                 cmk.cipherKind);
00762 
00763         return nextState;
00764         }
00765 
00766 
00776 SSLv2_States SSLv2_Interpreter::ErrorRecord(SSL_InterpreterEndpoint* s,
00777                                         int recordLength, u_char* recordData)
00778         {
00779         ++errorRecords;
00780 
00781         if ( unsigned(recordLength) != SSLv2_ERROR_RECORD_SIZE )
00782                 {
00783                 Weird("SSLv2: Size mismatch in Error Record!");
00784                 return ERROR_REQUIRED;
00785                 }
00786 
00787         SSLv2_ErrorRecord er;
00788         er.errorCode = (recordData[1] << 8) | recordData[2];
00789         SSL3x_AlertLevel al = SSL3x_AlertLevel(255);
00790 
00791         switch ( er.errorCode ) {
00792         case SSLv2_PE_NO_CIPHER:
00793                 // The client doesn't support a cipher which the server
00794                 // supports.  Only from client to server and not recoverable!
00795                 al = SSL3x_ALERT_LEVEL_FATAL;
00796                 break;
00797 
00798         case SSLv2_PE_NO_CERTIFICATE:
00799                 if ( s == orig )
00800                         // from client to server: not recoverable
00801                         al = SSL3x_ALERT_LEVEL_FATAL;
00802                 else
00803                         // from server to client: recoverable
00804                         al = SSL3x_ALERT_LEVEL_WARNING;
00805                 break;
00806 
00807         case SSLv2_PE_BAD_CERTIFICATE:
00808                 if ( s == orig )
00809                         // from client to server: not recoverable
00810                         al = SSL3x_ALERT_LEVEL_FATAL;
00811                 else
00812                         // from server to client: recoverable
00813                         al = SSL3x_ALERT_LEVEL_WARNING;
00814                 break;
00815 
00816         case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
00817                 if ( s == orig )
00818                         // from client to server: not recoverable
00819                         al = SSL3x_ALERT_LEVEL_FATAL;
00820                 else
00821                         // from server to client: recoverable
00822                         al = SSL3x_ALERT_LEVEL_WARNING;
00823                 break;
00824 
00825         default:
00826                 al = SSL3x_ALERT_LEVEL_FATAL;
00827                 break;
00828         }
00829 
00830         fire_ssl_conn_alert(SSL_ConnectionProxy::SSLv20, al, er.errorCode);
00831 
00832         return ERROR_SEEN;
00833         }
00834 
00845 TableVal* SSLv2_Interpreter::analyzeCiphers(SSL_InterpreterEndpoint* s,
00846                                                 int length, u_char* data)
00847         {
00848         if ( length > MAX_CIPHERSPEC_SIZE )
00849                 {
00850                 if ( s == orig )
00851                         Weird("SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE");
00852                 else
00853                         Weird("SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE");
00854                 }
00855         else
00856                 { // cipher specs are not too big
00857                 if ( ssl_compare_cipherspecs )
00858                         { // store cipher specs for state analysis
00859                         if ( s == resp )
00860                                 pServerCipherSpecs =
00861                                         new SSL_DataBlock(data, length);
00862                         else
00863                                 pClientCipherSpecs =
00864                                         new SSL_DataBlock(data, length);
00865                         }
00866                 }
00867 
00868         u_char* pCipher = data;
00869         bool bExtractCipherSuite = false;
00870         TableVal* pCipherTable = 0;
00871 
00872         // We only extract the cipher suite when the corresponding
00873         // ssl events are defined (otherwise we do work for nothing
00874         // and suffer a memory leak).
00875         // FIXME: This check needs to be done only once!
00876         if ( (s == orig && ssl_conn_attempt) ||
00877              (s == resp && ssl_conn_server_reply) )
00878                 {
00879                 pCipherTable = new TableVal(cipher_suites_list);
00880                 bExtractCipherSuite = true;
00881                 }
00882 
00883         for ( int i = 0; i < length; i += 3 )
00884                 {
00885                 SSL_CipherSpec* pCurrentCipherSpec;
00886                 uint32 cipherSpecID =
00887                         ((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2];
00888 
00889                 // Check for unknown cipher specs.
00890                 HashKey h(cipherSpecID);
00891                 pCurrentCipherSpec =
00892                         (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
00893 
00894                 if ( ! pCurrentCipherSpec )
00895                         {
00896                         if ( s == orig )
00897                                 Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!");
00898                         else
00899                                 Weird("SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!");
00900                         }
00901 
00902                 if ( bExtractCipherSuite )
00903                         {
00904                         pCipherTable->Assign(new Val(i / 3, TYPE_COUNT),
00905                                         new Val(cipherSpecID, TYPE_COUNT));
00906                         }
00907 
00908                 pCipher += 3;
00909                 }
00910 
00911         return pCipherTable;
00912         }
00913 
00914 // --- SSLv2_EndPoint ---------------------------------------------------------
00915 
00923 SSLv2_Endpoint::SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig)
00924 : SSL_InterpreterEndpoint(interpreter, is_orig)
00925         {
00926         sentRecords = 0;
00927         }
00928 
00932 SSLv2_Endpoint::~SSLv2_Endpoint()
00933         {
00934         }
00935 
00945 void SSLv2_Endpoint::Deliver(double t, int seq, int len, u_char* data)
00946         {
00947         ++((SSLv2_Endpoint*)peer)->sentRecords;
00948 
00949         ((SSLv2_Interpreter*)interpreter)->NewSSLRecord(this, len, data);
00950         }

Generated on Sat May 1 15:26:24 2004 for bro_docs.8a82 by doxygen 1.3.6