zeek/src/SSLv3.cc
Robin Sommer bf76811776 Merge remote branch 'remotes/origin/topic/robin/work'
* remotes/origin/topic/robin/work:
  *Now* this passes the test suite.
  Fixes to SSL/TLS analyzer
  Added new TLS ciphers
  Removing some apparently unnecessary lines.
  A few smaller tweaks.
  Prepared the old analyzer for extracting SSL extensions.
  Fixed bug in do_split implementation.
  Removed an accidental debugging printf.
  Readded the other changes to remove CheckString calls from strings.bif.
  Fixed the problem with do_split function which caused it to bail 1 separator early.
  Modification from rmkml to support SSL extensions.
  Updated SSL analyzer and Bro script with lots of new ciphers.
2011-02-08 20:25:13 -08:00

1471 lines
40 KiB
C++
Raw Blame History

// $Id: SSLv3.cc 5988 2008-07-19 07:02:12Z vern $
#include "SSLv3.h"
#include "SSLCiphers.h"
// --- Initalization of static variables --------------------------------------
bool SSLv3_Interpreter::bInited = false;
uint SSLv3_Interpreter::totalConnections = 0;
uint SSLv3_Interpreter::openedConnections = 0;
uint SSLv3_Interpreter::totalRecords = 0;
uint SSLv3_Interpreter::handshakeRecords = 0;
uint SSLv3_Interpreter::clientHelloRecords = 0;
uint SSLv3_Interpreter::serverHelloRecords = 0;
uint SSLv3_Interpreter::alertRecords = 0;
uint SSLv3_Interpreter::changeCipherRecords = 0;
// ---SSLv3_Interpreter--------------------------------------------------------
// Initialize static:
SSLv3_Automaton SSLv3_Interpreter::sslAutomaton(SSL3_1_NUM_STATES,
SSL3_1_NUM_TRANS, SSL3_1_STATE_ERROR);
SSLv3_Interpreter::SSLv3_Interpreter(SSLProxy_Analyzer* proxy)
: SSL_Interpreter(proxy)
{
pCipherSuite = 0;
cipherSuiteIdentifier = 0;
pClientCipherSpecs = 0;
clientSessionID = 0;
serverSessionID = 0;
clientRandom = 0;
serverRandom = 0;
serverRSApars = 0;
serverDHPars = 0;
encryptedPreSecret = 0;
clientDHpublic = 0;
// keyXAlgorithm = SSL_KEY_EXCHANGE_NULL;
change_cipher_client_seen = false;
change_cipher_server_seen = false;
fin_client_seen = false;
fin_server_seen = false;
helloRequestValid = true;
if ( ! bInited )
{
BuildAutomaton();
// BuildCipherDict();
bInited = true;
}
currentState = SSL3_1_STATE_INIT;
++totalConnections;
}
SSLv3_Interpreter::~SSLv3_Interpreter()
{
delete pClientCipherSpecs;
delete clientSessionID;
delete serverSessionID;
if ( ssl_store_key_material )
{
if ( clientRandom )
delete clientRandom->random_bytes;
delete clientRandom;
if ( serverRandom )
delete serverRandom->random_bytes;
delete serverRandom;
delete serverRSApars;
delete serverDHPars;
delete encryptedPreSecret;
delete clientDHpublic;
}
}
void SSLv3_Interpreter::BuildInterpreterEndpoints()
{
orig = new SSLv3_Endpoint(this, 1);
resp = new SSLv3_Endpoint(this, 0);
}
void SSLv3_Interpreter::BuildAutomaton()
{
sslAutomaton.addTrans(SSL3_1_STATE_INIT, SSL3_1_TRANS_SERVER_HELLO_REQ,
SSL3_1_STATE_SERVER_HELLO_REQ_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_REQ_SENT,
SSL3_1_TRANS_CLIENT_HELLO, SSL3_1_STATE_CLIENT_HELLO_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_INIT, SSL3_1_TRANS_CLIENT_HELLO,
SSL3_1_STATE_CLIENT_HELLO_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_HELLO_SENT,
SSL3_1_TRANS_SERVER_HELLO, SSL3_1_STATE_SERVER_HELLO_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT,
SSL3_1_TRANS_SERVER_CERT, SSL3_1_STATE_SERVER_CERT_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT,
SSL3_1_TRANS_SERVER_KEY_EXCHANGE,
SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT);
// Server key-exchange and/or server requests cert from client.
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT,
SSL3_1_TRANS_SERVER_KEY_EXCHANGE,
SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT,
SSL3_1_TRANS_SERVER_HELLO_DONE,
SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT,
SSL3_1_TRANS_SERVER_CERT_REQ,
SSL3_1_STATE_SERVER_CERT_REQ_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT,
SSL3_1_TRANS_SERVER_CERT_REQ,
SSL3_1_STATE_SERVER_CERT_REQ_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_REQ_SENT,
SSL3_1_TRANS_SERVER_HELLO_DONE,
SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B,
SSL3_1_TRANS_CLIENT_CERT, SSL3_1_STATE_CLIENT_CERT_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_SENT,
SSL3_1_TRANS_CLIENT_KEY_EXCHANGE,
SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B,
SSL3_1_TRANS_CLIENT_CERT_VERIFY,
SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_CLIENT_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_CLIENT_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_A,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_HS_FIN_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_SERVER_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_SERVER_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_A,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_HS_FIN_A);
// Server hello done after server cert sent.
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT,
SSL3_1_TRANS_SERVER_HELLO_DONE,
SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A,
SSL3_1_TRANS_CLIENT_KEY_EXCHANGE,
SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_CLIENT_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_SERVER_FIN_SENT_A);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_A,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_HS_FIN_A);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_A,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_HS_FIN_A);
// When reestablishing a session:
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_CLIENT_FIN_SENT_B);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_SERVER_FIN_SENT_B);
sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_B,
SSL3_1_TRANS_SERVER_FIN, SSL3_1_STATE_HS_FIN_B);
sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_B,
SSL3_1_TRANS_CLIENT_FIN, SSL3_1_STATE_HS_FIN_B);
sslAutomaton.setStartState(SSL3_1_STATE_INIT);
}
void SSLv3_Interpreter::printStats()
{
printf( "SSLv3x:\n" );
printf( "Note: Because handshake messages may be coalesced into a \n");
printf( " single SSLv3x record, the number of total messages for SSLv3x plus \n");
printf( " the number of total records seen for SSLv3 won't match \n");
printf( " SSLProxy_Analyzer::totalRecords! \n");
printf( "total connections = %u\n", totalConnections );
printf( "opened connections (complete handshake) = %u\n", openedConnections );
printf( "total messages seen = %u\n", totalRecords );
printf( "handshake messages seen = %u\n", handshakeRecords );
printf( "alert records seen = %u\n", alertRecords );
printf( "change cipher records seen = %u\n", changeCipherRecords );
printf( "client hello messages seen = %u\n", clientHelloRecords );
printf( "server hello messages seen = %u\n", serverHelloRecords );
}
int SSLv3_Interpreter::HandshakeType2Trans(int type)
{
switch ( SSL3_1_HandshakeType(type) ) {
case SSL3_1_HELLO_REQUEST: return SSL3_1_TRANS_SERVER_HELLO_REQ;
case SSL3_1_CLIENT_HELLO: return SSL3_1_TRANS_CLIENT_HELLO;
case SSL3_1_SERVER_HELLO: return SSL3_1_TRANS_SERVER_HELLO;
case SSL3_1_CERTIFICATE:
// Client- and server certificate handshake records lead
// to the same transition in the SSL automaton
// (see SSLDefines.h)
return SSL3_1_TRANS_SERVER_CERT;
case SSL3_1_SERVER_KEY_EXCHANGE: return SSL3_1_TRANS_SERVER_KEY_EXCHANGE;
case SSL3_1_CERTIFICATE_REQUEST: return SSL3_1_TRANS_SERVER_CERT_REQ;
case SSL3_1_SERVER_HELLO_DONE: return SSL3_1_TRANS_SERVER_HELLO_DONE;
case SSL3_1_CERTIFICATE_VERIFY: return SSL3_1_TRANS_CLIENT_CERT_VERIFY;
case SSL3_1_CLIENT_KEY_EXCHANGE: return SSL3_1_TRANS_CLIENT_KEY_EXCHANGE;
case SSL3_1_FINISHED:
// Client- and server certificate handshake records lead
// to the same transition in the SSL automaton
// (see SSLDefines.h)
return SSL3_1_TRANS_CLIENT_FIN;
default:
return -1;
}
}
void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_HandshakeRecord* rec)
{
++SSLv3_Interpreter::totalRecords;
++SSLv3_Interpreter::handshakeRecords;
TableVal* currentCipherSuites = 0;
// First: consistency checks.
// Special treatment for finished messages, because they are
// already encrypted (encrypted handshake message).
if ( (change_cipher_client_seen && (rec->endp)->IsOrig() &&
! fin_client_seen) ||
(change_cipher_server_seen && ! rec->endp->IsOrig() &&
! fin_server_seen) )
{
// no checks can be performed due encryption...
}
else
{
SSL3_1_HandshakeType ht = SSL3_1_HandshakeType(rec->type);
switch ( ht ) {
case SSL3_1_HELLO_REQUEST:
if ( rec->length != 0 )
Weird("SSLv3x: Hello request too long!");
if ( ! helloRequestValid )
Weird("SSLv3x: Received hello request during handshake!");
// There should only be sent one hello request at a
// time.
helloRequestValid = false;
break;
case SSL3_1_CLIENT_HELLO:
{
++SSLv3_Interpreter::clientHelloRecords;
// During the handshaking phase, we don't want any
// more hello requests.
helloRequestValid = false;
if ( rec->checkClientHello() == 0 )
return;
const u_char* pTemp = rec->data;
uint8 sessionIDLength = uint8(pTemp[38]);
clientSessionID =
new SSL_DataBlock((pTemp + 39), sessionIDLength);
uint16 cipherSuiteLength =
uint16(pTemp[39 + sessionIDLength] << 8 ) |
pTemp[40 + sessionIDLength];
currentCipherSuites =
analyzeCiphers(rec->endp, cipherSuiteLength,
rec->data + 41 + sessionIDLength,
rec->sslVersion);
if ( ssl_store_key_material )
{
clientRandom = new SSLv3x_Random();
clientRandom->random_bytes = 0;
clientRandom->gmt_unix_time =
uint32(((pTemp[6] << 24) |
pTemp[7] << 16) |
pTemp[8] << 8) | pTemp[9];
clientRandom->random_bytes =
new SSL_DataBlock(pTemp + 10, 28);
}
break;
}
case SSL3_1_SERVER_HELLO:
{
++SSLv3_Interpreter::serverHelloRecords;
if ( rec->checkServerHello() == 0)
return;
const u_char* pTemp = rec->data;
uint8 sessionIDLength = uint8(pTemp[38]);
serverSessionID =
new SSL_DataBlock(pTemp + 39, sessionIDLength);
currentCipherSuites =
analyzeCiphers(rec->endp, 2,
rec->data + 39 + sessionIDLength,
rec->sslVersion);
// Check whether the cipher suite the server choose
// was included in the cipher suites the client
// anounced.
if ( pClientCipherSpecs && pCipherSuite )
{
bool bFound = false;
uint16 tempClientCipher;
for ( int i = 0; i < pClientCipherSpecs->len;
i += 2 )
{
tempClientCipher =
(pClientCipherSpecs->data[i] << 8) |
pClientCipherSpecs->data[i+1];
if ( tempClientCipher ==
pCipherSuite->identifier )
{
bFound = true;
i = pClientCipherSpecs->len;
}
}
if ( ! bFound )
Weird("SSLv3x: Server choosed cipher spec that client didn't anounce!");
delete pClientCipherSpecs;
pClientCipherSpecs = 0;
}
if ( ssl_store_key_material )
{
serverRandom = new SSLv3x_Random();
serverRandom->gmt_unix_time =
uint32(((pTemp[6] << 8) |
pTemp[7] << 8) |
pTemp[8] << 8) | pTemp[9];
serverRandom->random_bytes =
new SSL_DataBlock(pTemp + 10, 28);
}
// Insert session injection into here.
if ( ! ssl_session_insertion )
break; // in place of below
TableVal* sessionIDTable =
serverSessionID ?
MakeSessionID(serverSessionID->data,
serverSessionID->len) :
MakeSessionID(0, 0);
val_list* vl = new val_list;
vl->append(proxy->BuildConnVal());
vl->append(sessionIDTable);
proxy->ConnectionEvent(ssl_session_insertion, vl);
break;
}
case SSL3_1_CERTIFICATE:
{
const u_char* pData = rec->data;
uint32 certListLength =
uint32((pData[4] << 16) |
pData[5] << 8) | pData[6];
// Sum of all cert sizes has to match
// certListLength.
uint tempLength = 0;
uint certCount = 0;
while ( tempLength < certListLength )
{
if ( tempLength + 3 <= certListLength )
{
++certCount;
uint32 certLength =
uint32((pData[tempLength + 7] << 16) | pData[tempLength + 8] << 8) | pData[tempLength + 9];
tempLength += certLength + 3;
}
else
{
Weird("SSLv3x: Corrupt length field in certificate list!");
return;
}
}
if ( tempLength > certListLength )
{
Weird("SSLv3x: sum of size of certificates doesn't match size of certificate chain");
return;
}
SSL_InterpreterEndpoint* pEp =
(SSL_InterpreterEndpoint*) rec->endp;
if ( certCount == 0 )
{
// we don't have a certificate, but this is valid
// according to RFC2246
if ( rec->endp->IsOrig() )
{
Weird("SSLv3x: Client certificate is missing!");
break;
}
else
{
Weird("SSLv3x: Server certificate is missing!");
break;
}
}
if ( certCount > 1 )
{ // we have a chain
analyzeCertificate(pEp,
rec->data + 7,
certListLength, 1, true);
}
else
{
// We have a single certificate.
// FIXME.
analyzeCertificate(pEp,
rec->data + 10,
certListLength-3, 1, false);
}
break;
}
case SSL3_1_SERVER_KEY_EXCHANGE:
{
/*
switch (cipherSuite)
{
// It would be necessary to have the RSA key length
// out of the server's certificate. If the cipher suite
// is EXPORT, than a RSA key length larger than 512 bits
// is not allowed for encryption and thus, the server needs
// to send a key-exchange-message in order to negotiate the
// pre-master secret (see rfc 2246 page 39)
case TLS_RSA_WITH_NULL_MD5:
case TLS_RSA_WITH_NULL_SHA:
// case TLS_RSA_EXPORT_WITH_RC4_40_MD5: //see comment above
case TLS_RSA_WITH_RC4_128_MD5:
case TLS_RSA_WITH_RC4_128_SHA:
// case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: //see comment above
case TLS_RSA_WITH_IDEA_CBC_SHA:
// case TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: //see comment above
case TLS_RSA_WITH_DES_CBC_SHA:
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
case TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
case TLS_DH_DSS_WITH_DES_CBC_SHA:
case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
case TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
case TLS_DH_RSA_WITH_DES_CBC_SHA:
case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
{
Weird("SSLv3x: Sending server-key-exchange not allowed for this cipher suite!");
return;
break;
}
default:
break;
}
*/
if ( ! pCipherSuite )
// If we have an unknown CIPHER-SPEC,
// we can't do our weird checks.
break;
SSL_KeyExchangeAlgorithm keyXAlgorithm =
pCipherSuite->keyExchangeAlgorithm;
if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS ||
keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA )
{
Weird("SSLv3x: Sending server-key-exchange not allowed for this cipher suite!");
return;
}
// FIXME: check where DHE_RSA etc. belongs to
const u_char* pTemp = rec->data;
if ( ssl_store_key_material )
{
if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
keyXAlgorithm == SSL_KEY_EXCHANGE_RSA_EXPORT1024 )
{ // some weird checks
if ( rec->length < 2 )
{
Weird("SSLv3x: server-key-exchange empty!");
return;
}
uint16 modulusLength = uint16(pTemp[4] << 8 ) | pTemp[5];
if ( modulusLength + 4 > rec->length )
{
Weird("SSLv3x: Corrupt length fields in server-key-exchange!");
break;
}
uint16 exponentLength = uint16(pTemp[6 + modulusLength] << 8 ) | pTemp[7 + modulusLength];
if ( modulusLength + exponentLength + 4 > rec->length )
{
Weird("SSLv3x: Corrupt length fields in server-key-exchange!");
return;
}
serverRSApars =
new SSLv3x_ServerRSAParams;
serverRSApars->rsa_modulus =
new SSL_DataBlock(pTemp + 6, modulusLength);
serverRSApars->rsa_exponent =
new SSL_DataBlock( pTemp + 8 + modulusLength, exponentLength);
}
else
{
if ( keyXAlgorithm == SSL_KEY_EXCHANGE_DH || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_anon || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_anon_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024 )
{
if ( rec->length < 2 )
{
Weird("SSLv3x: server-key-exchange empty!");
return;
}
uint16 dh_pLength = (uint16) (pTemp[4] << 8 ) | pTemp[5];
if ( dh_pLength + 4 > rec->length )
{
Weird("SSLv3x: Corrupt length fields in server-key-exchange!");
break;
}
uint16 dh_gLength = uint16(pTemp[6 + dh_pLength] << 8 ) | pTemp[7 + dh_pLength];
uint16 dh_YsLength = uint16(pTemp[8 + dh_pLength + dh_gLength] << 8 ) | pTemp[9 + dh_pLength + dh_gLength];
if ( dh_pLength + dh_gLength + dh_YsLength + 6 > rec->length )
{
Weird("SSLv3x: Corrupt length fields in server-key-exchange!");
printf("xxx %u > %u \n", (dh_pLength + dh_gLength + dh_YsLength + 6), rec->length);
return;
}
serverDHPars = new SSLv3x_ServerDHParams;
serverDHPars->dh_p = new SSL_DataBlock(pTemp + 6 , dh_pLength);
serverDHPars->dh_g = new SSL_DataBlock(pTemp + 8 + dh_pLength, dh_gLength);
serverDHPars->dh_Ys = new SSL_DataBlock(pTemp + 10 + dh_pLength + dh_gLength, dh_YsLength);
}
}
}
break;
}
case SSL3_1_CERTIFICATE_REQUEST:
{
// Only if server not anonymous
/*
switch (cipherSuite)
{
case TLS_NULL_WITH_NULL_NULL:
case TLS_DH_anon_EXPORT_WITH_RC4_40_MD5:
case TLS_DH_anon_WITH_RC4_128_MD5:
case TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
case TLS_DH_anon_WITH_DES_CBC_SHA:
case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
{
Weird("SSLv3x: Sending certificate-request not allowed for anonymous servers!");
break;
}
default:
{
break;
}
}
*/
if ( ! pCipherSuite )
{
// if we have an unknown CIPHER-SPEC,
// we can't do our weird checks.
break;
}
if ( pCipherSuite->keyExchangeAlgorithm == SSL_KEY_EXCHANGE_DH_anon || pCipherSuite->keyExchangeAlgorithm == SSL_KEY_EXCHANGE_DH_anon_EXPORT )
Weird("SSLv3x: Sending certificate-request not allowed for anonymous servers!");
// FIXME: Insert weird checks!
break;
}
case SSL3_1_SERVER_HELLO_DONE:
{
if ( rec->length != 0 )
Weird("SSLv3x: Server hello too long!");
break;
}
case SSL3_1_CLIENT_KEY_EXCHANGE:
{
if ( ! pCipherSuite )
// if we have an unknown CIPHER-SPEC,
// we can't do our weird checks
break;
const u_char* pTemp = rec->data;
if ( ssl_store_key_material )
{
SSL_KeyExchangeAlgorithm keyXAlgorithm =
pCipherSuite->keyExchangeAlgorithm;
if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA )
{
encryptedPreSecret =
new SSLv3x_EncryptedPremasterSecret;
encryptedPreSecret->encryptedSecret =
new SSL_DataBlock( pTemp + 4, rec->length);
}
else
{
if ( keyXAlgorithm == SSL_KEY_EXCHANGE_DH || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_anon || keyXAlgorithm == SSL_KEY_EXCHANGE_DH_anon_EXPORT || keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024 )
{
if ( rec->length < 2 )
{
// This can happen (see RFC 2246, p. 45).
return;
}
uint16 DHpublicLength =
uint16(pTemp[4] << 8) | pTemp[5];
if ( DHpublicLength + 2 < rec->length )
{
Weird("SSLv3x:<3A>Corrupt length fields in client-key-exchange!");
return;
}
clientDHpublic = new SSLv3x_ClientDHPublic;
clientDHpublic->dh_Yc = new SSL_DataBlock(pTemp + 6, DHpublicLength);
}
}
}
break;
}
case SSL3_1_CERTIFICATE_VERIFY:
{
// FIXME: Insert Weird checks!
break;
}
case SSL3_1_FINISHED:
{
// We won't get here, because finished messages
// are already encrypted, so we can't get
// the content type of this handshake-message...
break;
}
default:
{
if ( currentState == SSL3_1_STATE_SERVER_FIN_SENT_A ||
currentState == SSL3_1_STATE_CLIENT_FIN_SENT_B )
{
Weird("SSLv3x: Handshake message (unknown type) after finished message!");
return;
}
else
{
Weird("SSLv3x: Invalid HandshakeType! Maybe finished message without predecessing change-cipher-message!");
return; }
}
}
}
int oldState = currentState;
bool alreadySwitchedState = false;
// First: Special handling of finished messages. They must be
// sent immediately after a change cipher message - already encrypted.
// from client?
if ( rec->endp->IsOrig() && change_cipher_client_seen )
{
if ( ! fin_client_seen )
{
// This must be a (valid) client finished.
// We assume it to be one, because the predecessing
// message was a change cipher.
fin_client_seen = true;
change_cipher_client_seen = false;
alreadySwitchedState = true;
currentState = sslAutomaton.getNextState(currentState,
SSL3_1_TRANS_CLIENT_FIN);
}
else
{
// We already saw a client finished (should not be
// possible).
Weird("SSLv3x: Already received client finished message!");
currentState = sslAutomaton.getNextState(currentState,
SSL3_1_TRANS_CLIENT_FIN);
fin_client_seen = true;
change_cipher_client_seen = false;
alreadySwitchedState = true;
}
}
// from server
else if ( ! rec->endp->IsOrig() && change_cipher_server_seen )
{
if ( ! fin_server_seen )
{
// This must be a (valid) server finished.
// We assume it to be one, because the predecessing
// message was a change cipher.
fin_server_seen = true;
change_cipher_server_seen = false;
alreadySwitchedState = true;
currentState = sslAutomaton.getNextState(currentState,
SSL3_1_TRANS_SERVER_FIN);
}
else
{
// We already saw a server-finished (should not be
// possible).
Weird("SSLv3x: Already received server finished message!");
currentState = sslAutomaton.getNextState(currentState,
SSL3_1_TRANS_SERVER_FIN);
alreadySwitchedState = true;
fin_server_seen = true;
change_cipher_server_seen = false;
}
}
if ( ! alreadySwitchedState )
{
// Check whether we are already finished with the
// handshaking process...
switch ( currentState ) {
case SSL3_1_STATE_HS_FIN_A:
case SSL3_1_STATE_HS_FIN_B:
Weird("SSLv3x: Received handshake message after finishing handshake!");
break;
default:
// It's a "normal" handshake message...
currentState = sslAutomaton.getNextState(currentState,
HandshakeType2Trans(rec->type));
break;
}
}
if ( currentState == SSL3_1_STATE_ERROR )
{
// proxy->SetSkip(1);
}
// Only if we changed the currentState, we need to call GenerateEvents
// because event generation in GenerateEvents() is based on
// currentState.
if ( oldState != currentState )
GenerateEvents(rec, currentCipherSuites);
else
Unref(currentCipherSuites);
}
void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_AlertRecord* rec)
{
++SSLv3_Interpreter::totalRecords;
++SSLv3_Interpreter::alertRecords;
// First: consistency-checks.
// Only if handshake not already finished.
// Otherwise alerts may be encrypted, so we could do nothing...
if ( currentState == SSL3_1_STATE_SERVER_FIN_SENT_A ||
currentState == SSL3_1_STATE_CLIENT_FIN_SENT_B ||
currentState == SSL3_1_STATE_CLIENT_FIN_SENT_A ||
currentState == SSL3_1_STATE_SERVER_FIN_SENT_B ||
currentState == SSL3_1_STATE_HS_FIN_A ||
currentState == SSL3_1_STATE_HS_FIN_B ||
change_cipher_client_seen || change_cipher_server_seen )
return;
if ( rec->level != SSL3x_ALERT_LEVEL_WARNING &&
rec->level != SSL3x_ALERT_LEVEL_FATAL )
Weird("SSLv3x: Unknown ssl alert level");
SSL3_1_AlertDescription ad = SSL3_1_AlertDescription(rec->description);
switch ( ad ) {
case SSL3_1_CLOSE_NOTIFY:
case SSL3_1_UNEXPECTED_MESSAGE:
case SSL3_1_BAD_RECORD_MAC:
case SSL3_1_DECRYPTION_FAILED:
case SSL3_1_RECORD_OVERFLOW:
case SSL3_1_DECOMPRESSION_FAILURE:
case SSL3_1_HANDSHAKE_FAILURE:
break;
case SSL3_0_NO_CERTIFICATE:
// This may happen ONLY in SSLv3.0 when the server sends
// a certificate request but the client has none.
if ( rec->sslVersion == SSLProxy_Analyzer::SSLv30 )
currentState = SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A;
else
Weird("SSLv3x: No certificate alert not defined for SSL 3.1!");
break;
case SSL3_1_BAD_CERTIFICATE:
case SSL3_1_UNSUPPORTED_CERTIFICATE:
case SSL3_1_CERTIFICATE_REVOKED:
case SSL3_1_CERTIFICATE_EXPIRED:
case SSL3_1_CERTIFICATE_UNKNOWN:
case SSL3_1_ILLEGAL_PARAMETER:
case SSL3_1_UNKNOWN_CA:
case SSL3_1_ACCESS_DENIED:
case SSL3_1_DECODE_ERROR:
case SSL3_1_DECRYPT_ERROR:
case SSL3_1_EXPORT_RESTRICTION:
case SSL3_1_PROTOCOL_VERSION:
case SSL3_1_INSUFFICIENT_SECURITY:
case SSL3_1_INTERNAL_ERROR:
case SSL3_1_USER_CANCELED:
case SSL3_1_NO_RENEGOTIATION:
break;
default:
Weird(" SSLv3x: Unknown ssl alert description!" );
break;
}
if ( rec->level == 2 )
// Fatal alert!
currentState = SSL3_1_STATE_INIT;
if ( rec->level == 1 && ad == SSL3_1_CLOSE_NOTIFY )
currentState = SSL3_1_STATE_INIT;
fire_ssl_conn_alert(rec->sslVersion, rec->level, rec->description);
}
void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_ChangeCipherRecord* rec)
{
++SSLv3_Interpreter::totalRecords;
++SSLv3_Interpreter::changeCipherRecords;
if ( rec->type != 1 )
Weird("SSLv3x: Unknown change cipher type!");
if ( rec->recordLength != 1 )
Weird("SSLv3x: Change cipher message too long!");
// After receiving a change cipher spec message, the next message sent
// MUST be a finished message. So we set the appropriate flag:
// change_cipher_client/server_seen.
if ( rec->endp->IsOrig())
{
if ( change_cipher_client_seen )
Weird("SSLv3x: Received multiple change cipher message from client!");
change_cipher_client_seen = true;
fin_client_seen = false;
}
else
{
if ( change_cipher_server_seen )
Weird("SSLv3x: Received multiple change cipher message from server!");
change_cipher_server_seen = true;
fin_server_seen = false;
}
if ( currentState == SSL3_1_STATE_ERROR )
{
// proxy->SetSkip(1);
}
// We don't need a GenerateEvents here, because we didn't change
// the currentState of the SSL automaton. (Event generation
// in GenerateEvents() is done based on currentState.)
// GenerateEvents(rec);
}
void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_ApplicationRecord* rec)
{
++SSLv3_Interpreter::totalRecords;
if ( currentState == SSL3_1_STATE_HS_FIN_A ||
currentState == SSL3_1_STATE_HS_FIN_B )
// O.K., sending application data is valid
// this was the last record we analyzed...
proxy->SetSkip(1);
else
{
// Sending application data now is not valid, so the SSL
// connection is probably already established and we
// didn't get the handshake.
Weird("SSLv3_data_without_full_handshake");
currentState = SSL3_1_STATE_ERROR;
GenerateEvents(rec, 0);
}
}
TableVal* SSLv3_Interpreter::analyzeCiphers(const SSLv3_Endpoint* s, int length,
const u_char* data, uint16 version)
{
int is_orig = (SSL_InterpreterEndpoint*) s == orig;
const u_char* pCipher = data;
SSL_CipherSpec* pCipherSuiteTemp = 0;
uint16 cipherSuite;
for ( int i = 0; i < length; i += 2 )
{
cipherSuite = uint16(pCipher[0+i] << 8) | pCipher[1+i];
HashKey h(static_cast<bro_uint_t>(cipherSuite));
pCipherSuiteTemp =
(SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
if ( ! pCipherSuiteTemp )
{
if ( is_orig )
proxy->Weird("SSLv3x: Unknown CIPHER-SPEC in CLIENT-HELLO");
else
proxy->Weird("SSLv3x: Unknown CIPHER-SPEC in SERVER-HELLO");
}
}
// Store server's cipher specs.
if ( ! is_orig )
{
pCipherSuite = pCipherSuiteTemp;
if ( ! pCipherSuite )
{
// Special case: we store the identifier directly
// for unknown cipher-specs.
cipherSuiteIdentifier =
uint16(pCipher[0] << 8) | pCipher[1];
}
}
if ( ssl_compare_cipherspecs && length <= ssl_max_cipherspec_size )
{
// Store cipher specs for analysis: was the choosen
// server cipher suite announced by the client?
if ( is_orig )
{
pClientCipherSpecs =
new SSL_DataBlock(data, length);
}
}
if ( (! is_orig && ssl_conn_server_reply) ||
(is_orig && ssl_conn_attempt) )
{
TableVal* pCipherTable = new TableVal(cipher_suites_list);
for ( int i = 0; i < length; i += 2 )
{
uint32 cipherSpec = (pCipher[0] << 8) | pCipher[1];
Val* index = new Val(cipherSpec, TYPE_COUNT);
pCipherTable->Assign(index, 0);
Unref(index);
pCipher += 2;
}
return pCipherTable;
}
else
return 0;
}
void SSLv3_Interpreter::GenerateEvents(SSLv3_Record* rec, TableVal* curCipherSuites)
{
if ( curCipherSuites &&
currentState != SSL3_1_STATE_CLIENT_HELLO_SENT &&
currentState != SSL3_1_STATE_SERVER_HELLO_SENT )
// Unref here, since the events won't do so in this case.
Unref(curCipherSuites);
switch ( currentState ) {
case SSL3_1_STATE_CLIENT_HELLO_SENT:
fire_ssl_conn_attempt(rec->sslVersion, curCipherSuites);
break;
case SSL3_1_STATE_SERVER_HELLO_SENT:
fire_ssl_conn_server_reply(rec->sslVersion, curCipherSuites);
break;
case SSL3_1_STATE_HS_FIN_A:
case SSL3_1_STATE_HS_FIN_B:
++SSLv3_Interpreter::openedConnections;
fire_ssl_conn_established(rec->sslVersion,
pCipherSuite ?
pCipherSuite->identifier : 0);
// We finished handshake. Skip all further data.
proxy->SetSkip(1);
helloRequestValid = true;
break;
case SSL3_1_STATE_SERVER_FIN_SENT_B:
// First, check for session-ID match.
if ( clientSessionID && serverSessionID &&
memcmp(clientSessionID->data, serverSessionID->data,
clientSessionID->len) != 0 )
Weird("SSLv3x: Reusing session but session ID mismatch!");
fire_ssl_conn_reused(serverSessionID);
break;
case SSL3_1_STATE_ERROR:
Weird("unexpected_SSLv3_record");
proxy->SetSkip(1);
}
}
void SSLv3_Interpreter::SetState(int i)
{
if ( i >= 0 && i < SSL3_1_NUM_STATES )
currentState = i;
}
// ---SSLv3_Endpoint--------------------------------------------------------------
SSLv3_Endpoint::SSLv3_Endpoint(SSL_Interpreter* interpreter, int is_orig)
: SSL_InterpreterEndpoint(interpreter, is_orig)
{
sslVersion = 0;
}
SSLv3_Endpoint::~SSLv3_Endpoint()
{
}
void SSLv3_Endpoint::Deliver(int len, const u_char* data)
{
if ( SSL3_1_LENGTHOFFSET + sizeof(uint16) <= unsigned(len) )
{
currentMessage_length =
uint16(data[SSL3_1_LENGTHOFFSET] << 8) |
data[SSL3_1_LENGTHOFFSET+1];
// ### where does this magic number come from?
if ( currentMessage_length > 18432 )
interpreter->Weird("SSLv3x: Message length too long!");
}
else
{
interpreter->Weird("SSLv3x: Could not determine message length!");
return;
}
if ( currentMessage_length + 2 + SSL3_1_LENGTHOFFSET != len )
{
// This should never happen; otherwise there is a bug in the
// SSL_RecordBuilder.
interpreter->Weird("SSLv3x: FATAL: recordLength doesn't match data block length!");
interpreter->Proxy()->SetSkip(1);
return;
}
ProcessMessage(data, len);
}
void SSLv3_Endpoint::ProcessMessage(const u_char* data, int len)
{
SSL3_1_ContentType ct = ExtractContentType(data, len);
if ( ! ExtractVersion(data, len) )
return;
switch ( ct ) {
case SSL3_1_TYPE_CHANGE_CIPHER_SPEC:
{
SSLv3_ChangeCipherRecord* rec = new
SSLv3_ChangeCipherRecord(data + SSL3_1_HEADERLENGTH,
len - SSL3_1_HEADERLENGTH, sslVersion, this);
// Multiple handshake messages may be coalesced into
// a single record.
rec->Deliver((SSLv3_Interpreter*) interpreter);
Unref(rec);
break;
}
case SSL3_1_TYPE_ALERT:
{
SSLv3_AlertRecord* rec = new
SSLv3_AlertRecord(data + SSL3_1_HEADERLENGTH,
len - SSL3_1_HEADERLENGTH, sslVersion, this);
rec->Deliver((SSLv3_Interpreter*) interpreter);
Unref(rec);
break;
}
case SSL3_1_TYPE_HANDSHAKE:
{
SSLv3_HandshakeRecord* rec =
new SSLv3_HandshakeRecord(data + SSL3_1_HEADERLENGTH,
len - SSL3_1_HEADERLENGTH, sslVersion, this);
rec->Deliver((SSLv3_Interpreter*) interpreter);
Unref(rec);
break;
}
case SSL3_1_TYPE_APPLICATION_DATA:
{
SSLv3_ApplicationRecord* rec =
new SSLv3_ApplicationRecord(data + SSL3_1_HEADERLENGTH,
len - SSL3_1_HEADERLENGTH, sslVersion, this);
rec->Deliver((SSLv3_Interpreter*) interpreter);
Unref(rec);
break;
}
default:
{
interpreter->Weird("SSLv3x: Could not determine content type!");
break;
}
}
}
SSL3_1_ContentType SSLv3_Endpoint::ExtractContentType(const u_char* data,
int len)
{
return SSL3_1_ContentType(uint8(*(data + SSL3_1_CONTENTTYPEOFFSET)));
}
int SSLv3_Endpoint::ExtractVersion(const u_char* data, int len)
{
sslVersion = uint16(data[SSL3_1_VERSIONTYPEOFFSET] << 8) |
data[SSL3_1_VERSIONTYPEOFFSET + 1];
if ( sslVersion != SSLProxy_Analyzer::SSLv30 &&
sslVersion != SSLProxy_Analyzer::SSLv31 )
{
interpreter->Weird("SSLv3x: Unsupported SSL-Version (not SSLv3x)!");
return 0;
}
else
return 1;
}
// ---SSLv3_Record----------------------------------------------------------------
SSLv3_Record::SSLv3_Record(const u_char* data, int len,
uint16 version, SSLv3_Endpoint const* e)
{
recordLength = len;
sslVersion = version;
endp = e;
this->data = data;
}
SSLv3_Record::~SSLv3_Record()
{
// The memory for data is deleted after processing the ssl record
// in the common ssl reassembler.
}
void SSLv3_Record::Describe(ODesc* d) const
{
d->Add("sslrecord");
}
SSLv3_Endpoint const* SSLv3_Record::GetEndpoint() const
{
return endp;
}
const u_char* SSLv3_Record::GetData() const
{
return data;
}
int SSLv3_Record::ExtractInt24(const u_char* data, int len, int offset)
{
if ( offset + int(sizeof(unsigned long)) - 1 > len)
return 0;
uint32 val;
val = 0;
val = uint32(*(data + offset + 2));
val |= uint32(*(data + offset + 1)) << 8;
val |= uint32(*(data + offset)) << 16;
return val;
}
int SSLv3_Record::GetRecordLength() const
{
return recordLength;
}
SSLv3_HandshakeRecord::SSLv3_HandshakeRecord(const u_char* data, int len,
uint16 version, SSLv3_Endpoint const* e)
: SSLv3_Record(data, len, version, e)
{
// Don't analyze encrypted client handshake messages.
if ( e->IsOrig() &&
((SSLv3_Interpreter*) e->Interpreter())->change_cipher_client_seen &&
! ((SSLv3_Interpreter*) e->Interpreter())->fin_client_seen )
{
type = 255;
length = 0;
next = 0;
return;
}
// Don't analyze encrypted server handshake messages.
if ( ! e->IsOrig() &&
((SSLv3_Interpreter*) e->Interpreter())->change_cipher_server_seen &&
! ((SSLv3_Interpreter*) e->Interpreter())->fin_server_seen )
{
type = 255;
length = 0;
next = 0;
return;
}
type = uint8(*(this->data));
length = ExtractInt24(data, len, 1);
if ( length == 0 ) // this is a special case to deal with 0 length certs
next = 0;
else if ( length + 4 < len )
next = new SSLv3_HandshakeRecord(data + length + 4,
len - (length + 4), version, e);
else if ( length + 4 > len )
{
e->Interpreter()->Weird("SSLv3x: Handshake-header-length inconsistent (too big)");
next = 0;
}
else
next = 0;
}
SSLv3_HandshakeRecord::~SSLv3_HandshakeRecord()
{
if ( next )
{
delete next;
}
}
void SSLv3_HandshakeRecord::Deliver(SSLv3_Interpreter* conn)
{
SSLv3_HandshakeRecord* it = this;
while ( it != 0)
{
conn->DeliverSSLv3_Record(it);
it = it->GetNext();
}
}
int SSLv3_HandshakeRecord::GetType() const
{
return type;
}
int SSLv3_HandshakeRecord::GetLength() const
{
return length;
}
SSLv3_HandshakeRecord* SSLv3_HandshakeRecord::GetNext()
{
return next;
}
int SSLv3_HandshakeRecord::checkClientHello()
{
if ( recordLength < 42 )
{
endp->Interpreter()->Weird("SSLv3x: Client hello too small!");
return 0;
}
uint16 version = uint16(data[4] << 8 ) | data[5];
if ( version != SSLProxy_Analyzer::SSLv30 &&
version != SSLProxy_Analyzer::SSLv31 )
endp->Interpreter()->Weird("SSLv3x: Corrupt version information in Client hello!");
uint16 offset = 38;
uint8 sessionIDLength = uint8(data[offset]);
offset += (1 + sessionIDLength);
if ( sessionIDLength > 32 )
{
endp->Interpreter()->Weird("SSLv3x: SessionID too long in Client hello!");
return 0;
}
uint16 cipherSuiteLength =
uint16(data[offset] << 8) | data[offset+1];
offset += (2 + cipherSuiteLength);
if ( cipherSuiteLength < 2 )
endp->Interpreter()->Weird("SSLv3x: CipherSuite length too small!");
if ( offset > recordLength )
{
endp->Interpreter()->Weird("SSLv3x: Client hello too small, corrupt length fields!");
return 0;
}
uint8 compressionMethodLength = uint8(data[offset]);
offset += (1 + compressionMethodLength);
if ( compressionMethodLength < 1 )
endp->Interpreter()->Weird("SSLv3x: CompressionMethod length too small!");
if ( offset < length )
{
uint16 sslExtensionsLength =
uint16(data[offset] << 8) | data[offset+1];
offset += 2;
if ( sslExtensionsLength < 4 )
endp->Interpreter()->Weird("SSLv3x: Extensions length too small!");
// TODO: extract SSL extensions here
offset += sslExtensionsLength;
if ( offset != length+4 )
{
endp->Interpreter()->Weird("SSLv3x: Corrupt length fields in Client hello!");
return 0;
}
}
return 1;
}
int SSLv3_HandshakeRecord::checkServerHello()
{
if ( recordLength < 42 )
{
endp->Interpreter()->Weird("SSLv3x: Server hello too small!");
return 0;
}
uint16 version = uint16(data[4] << 8) | data[5];
if ( version != SSLProxy_Analyzer::SSLv30 &&
version != SSLProxy_Analyzer::SSLv31 )
endp->Interpreter()->Weird("SSLv3x: Corrupt version information in Server hello!");
uint16 offset = 38;
uint8 sessionIDLength = uint8(data[offset]);
if ( sessionIDLength > 32 )
{
endp->Interpreter()->Weird("SSLv3x: SessionID too long in Server hello!");
return 0;
}
offset += (1 + sessionIDLength);
offset += 3; // account for cipher and compression method
if ( offset < length )
{
uint16 sslExtensionsLength =
uint16(data[offset] << 8) | data[offset+1];
offset += 2;
if ( sslExtensionsLength < 4 )
endp->Interpreter()->Weird("SSLv3x: Extensions length too small!");
// TODO: extract SSL extensions here
offset += sslExtensionsLength;
if ( offset != length+4 )
{
endp->Interpreter()->Weird("SSLv3x: Corrupt length fields in Server hello!");
return 0;
}
return 0;
}
return 1;
}
SSLv3_AlertRecord::SSLv3_AlertRecord(const u_char* data, int len,
uint16 version, SSLv3_Endpoint const* e)
: SSLv3_Record(data, len, version, e)
{
if ( len < 2 )
{
e->Interpreter()->Weird("SSLv3x: Alert header length too small!");
level = 255;
description = 255;
}
// No further consistency-check, because alerts may be
// already encrypted.
level = uint8(*((this->data) + SSL3_1_ALERT_LEVEL_OFFSET));
description = uint8(*((this->data) + SSL3_1_ALERT_DESCRIPTION_OFFSET));
}
SSLv3_AlertRecord::~SSLv3_AlertRecord()
{
}
int SSLv3_AlertRecord::GetDescription() const
{
return description;
}
int SSLv3_AlertRecord::GetLevel() const
{
return level;
}
void SSLv3_AlertRecord::Deliver(SSLv3_Interpreter* conn)
{
conn->DeliverSSLv3_Record(this);
}
SSLv3_ChangeCipherRecord::SSLv3_ChangeCipherRecord(const u_char* data, int len,
uint16 version, SSLv3_Endpoint const* e)
: SSLv3_Record(data, len, version, e)
{
if ( len < 1 )
{
e->Interpreter()->Weird("SSLv3x: Change cipher header length too small!");
type = 255;
}
else
type = uint8(*((this->data) + SSL3_1_CHANGE_CIPHER_TYPE_OFFSET));
}
SSLv3_ChangeCipherRecord::~SSLv3_ChangeCipherRecord()
{
}
int SSLv3_ChangeCipherRecord::GetType() const
{
return type;
}
void SSLv3_ChangeCipherRecord::Deliver(SSLv3_Interpreter* conn)
{
conn->DeliverSSLv3_Record(this);
}
SSLv3_ApplicationRecord::SSLv3_ApplicationRecord(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e)
: SSLv3_Record(data, len, version, e)
{
}
SSLv3_ApplicationRecord::~SSLv3_ApplicationRecord()
{
}
void SSLv3_ApplicationRecord::Deliver(SSLv3_Interpreter* conn)
{
conn->DeliverSSLv3_Record(this);
}