// $Id$ #ifndef sslv3_h #define sslv3_h #include "SSLInterpreter.h" #include "SSLProxy.h" #include "SSLv3Automaton.h" #include "SSLDefines.h" // Offsets in SSL record layer header. const int SSL3_1_CONTENTTYPEOFFSET = 0; const int SSL3_1_VERSIONTYPEOFFSET = 1; const int SSL3_1_LENGTHOFFSET = 3; const int SSL3_1_HEADERLENGTH = 5; // --- forward declarations --------------------------------------------------- class SSL_Interpreter; class SSL_InterpreterEndpoint; class SSLProxy_Analyzer; class SSLv3_Endpoint; class SSLv3_Record; class SSLv3_HandshakeRecord; class SSLv3_AlertRecord; class SSLv3_ApplicationRecord; class SSLv3_ChangeCipherRecord; class CertStore; struct SSL_CipherSpec; // --- enums for SSLv3.0/3.1 message handling --------------------------------- enum SSL3_1_ContentType { SSL3_1_TYPE_CHANGE_CIPHER_SPEC = 20, SSL3_1_TYPE_ALERT = 21, SSL3_1_TYPE_HANDSHAKE = 22, SSL3_1_TYPE_APPLICATION_DATA = 23 }; enum SSL3_1_HandshakeType { SSL3_1_HELLO_REQUEST = 0, SSL3_1_CLIENT_HELLO = 1, SSL3_1_SERVER_HELLO = 2, SSL3_1_CERTIFICATE = 11, SSL3_1_SERVER_KEY_EXCHANGE = 12, SSL3_1_CERTIFICATE_REQUEST = 13, SSL3_1_SERVER_HELLO_DONE = 14, SSL3_1_CERTIFICATE_VERIFY = 15, SSL3_1_CLIENT_KEY_EXCHANGE = 16, SSL3_1_FINISHED = 20 }; enum SSL3_1_AlertDescription { SSL3_1_CLOSE_NOTIFY = 0, SSL3_1_UNEXPECTED_MESSAGE = 10, SSL3_1_BAD_RECORD_MAC = 20, SSL3_1_DECRYPTION_FAILED = 21, SSL3_1_RECORD_OVERFLOW = 22, SSL3_1_DECOMPRESSION_FAILURE = 30, SSL3_1_HANDSHAKE_FAILURE = 40, SSL3_0_NO_CERTIFICATE = 41, SSL3_1_BAD_CERTIFICATE = 42, SSL3_1_UNSUPPORTED_CERTIFICATE = 43, SSL3_1_CERTIFICATE_REVOKED = 44, SSL3_1_CERTIFICATE_EXPIRED = 45, SSL3_1_CERTIFICATE_UNKNOWN = 46, SSL3_1_ILLEGAL_PARAMETER = 47, SSL3_1_UNKNOWN_CA = 48, SSL3_1_ACCESS_DENIED = 49, SSL3_1_DECODE_ERROR = 50, SSL3_1_DECRYPT_ERROR = 51, SSL3_1_EXPORT_RESTRICTION = 60, SSL3_1_PROTOCOL_VERSION = 70, SSL3_1_INSUFFICIENT_SECURITY = 71, SSL3_1_INTERNAL_ERROR = 80, SSL3_1_USER_CANCELED = 90, SSL3_1_NO_RENEGOTIATION = 100 }; enum SSL3x_AlertLevel { SSL3x_ALERT_LEVEL_WARNING = 1, SSL3x_ALERT_LEVEL_FATAL = 2 }; // --- structs ---------------------------------------------------------------- struct SSLv3x_Random { uint32 gmt_unix_time; SSL_DataBlock* random_bytes; // 28-bytes }; struct SSLv3x_ServerRSAParams { SSL_DataBlock* rsa_modulus; // <1..2^16-1> SSL_DataBlock* rsa_exponent; // <1..2^16-1> }; struct SSLv3x_ServerDHParams{ SSL_DataBlock* dh_p; // <1..2^16-1> SSL_DataBlock* dh_g; // <1..2^16-1> SSL_DataBlock* dh_Ys; // <1..2^16-1> }; struct SSLv3x_EncryptedPremasterSecret{ SSL_DataBlock* encryptedSecret; }; struct SSLv3x_ClientDHPublic{ SSL_DataBlock* dh_Yc; // <1..2^16-1> }; // ---------------------------------------------------------------------------- /** * Class SSLv3_Interpreter is the implementation for a SSLv3.0/SSLv3.1 connection * interpreter (derived from the abstract class SSL_Interpreter). * * The corresponding SSLProxy_Analyzer creates an instance of this class and * properly initialises the corresponding SSLv3_Endpoints by calling the * SSL_Interpreter's Init() method which then invokes the BuildInterpreterEndpoints() method * (of the SSLv3_Interpreter) which causes the SSLv3_Endpoints to be created properly. * * The SSLv3_Interpreter receives the four various SSLv3_Records: * - SSLv3_HandshakeRecord * - SSLv3_AlertRecord * - SSLv3_ChangeCipherRecord * - SSLv3_ApplicationRecord * via the DeliverSSLv3_Record() methods from the two corresponding SSLv3_Endpoints * (which get fed by the SSLProxy_Analyzer). * * There is one global static SSLv3_Automaton which describes the possible transitions * in the SSLv3.0/SSLv3.1 state machine for the handshaking phase. This automaton * is initialised once, when Bro sees the first SSL connection. By the attribute * currentState every instance of SSLv3_Interpreter holds the automaton state it * is currently in and so is able * to track the correctness of the SSL handshaking process. It weird-checks and verifies * all arriving SSL records up to the point where handshaking is finished or an * error occures caused by weird SSL records or not allowed transitions in the * state machine. Information that was negotiated between the client and server * during the handshaking phase is/may also be stored. That is: * - used SSL version * - negotiated cipher suite * - session ID * - client/server random * - key exchange algorithms * - cryptographic parameters * - encrypted pre-master secret * * The certificates are verified using the analyzeCertificate() method of the * SSL_Interpreter class. * Events for Bro scripting are thrown for client connection attempt, server reply, * ssl connection establishment/reuse of former connection, proposed cipher suites and * seen certificates. * * @see SSLv3_Endpoint */ class SSLv3_Interpreter : public SSL_Interpreter { public: /** The constructor takes the SSLProxy_Analyzer as argument, * that created this SSLv3_Interpreter. * * @param proxy the creating SSL_ConectionProxy */ SSLv3_Interpreter(SSLProxy_Analyzer* proxy); ~SSLv3_Interpreter(); /** Delivers an SSLv3_HandshakeRecord to the SSLv3_Interpreter. * The record gets verified and it is checked whether it is allowed * in the current phase of the handshaking process. * * @param rec the SSLv3_HandshakeRecord */ void DeliverSSLv3_Record(SSLv3_HandshakeRecord* rec); /** Delivers an SSLv3_AlertRecord to the SSLv3_Interpreter. * The record gets verified and weird checked. * * @param rec the SSLv3_AlertRecord */ void DeliverSSLv3_Record(SSLv3_AlertRecord* rec); /** Delivers an SSLv3_ChangeCipherRecord to the SSLv3_Interpreter. * The record gets verified and weird checked. If a change cipher * record is received the next record from this endpoint needs * to be a finished message. * * @param rec the SSLv3_ChangeCipherRecord */ void DeliverSSLv3_Record(SSLv3_ChangeCipherRecord* rec); /** Delivers a SSLv3_ApplicationRecord to the SSLv3_Interpreter. * It is checked, whether handshaking phase is already finished * and sending application data is valid (the normal case is, * that after finishing the handshaking phase, all further data * is skipped). * * @param rec the SSLv3_AlertRecord */ void DeliverSSLv3_Record(SSLv3_ApplicationRecord* rec); /** This method sets the currentState variable of this SSLv3_Interpreter * and so sets the SSLv3.0/SSLv3.1 state machine to the state passed * as parameter.It is invoked in the SSLProxy_Analyzer to enable * this SSLv3_Interpreter to start work without having seen the first * handshake record. This happens, when the client hello is sent in * SSLv2 format and processed by the SSLv2_Interpreter but the further * SSL connection taking place as a SSLv3.0/SSLv3.1 session. * * @param i the new state of the sslAutomaton */ void SetState(int i); static void printStats(); // Total SSLv3x connections. static uint totalConnections; // Total SSLv3x connections with complete handshake. static uint openedConnections; static uint totalRecords; ///< counter for total SSLv3x records seen static uint handshakeRecords; ///< counter for SSLv3x handshake records seen static uint clientHelloRecords; ///< counter for SSLv3x client hellos seen static uint serverHelloRecords; ///< counter for SSLv3x server hellos seen static uint alertRecords; ///< counter for SSLv3x alert records seen static uint changeCipherRecords; ///< counter for SSLv3x change cipher records seen /**Flags for handling the change-cipher-messages and fin-handshake- * messages */ bool change_cipher_client_seen; ///< whether a client change cipher record was seen bool change_cipher_server_seen; ///< whether a server change cipher record was seen bool fin_client_seen; ///< whether a client finished handshake message was seen (must immediately follow the client change cipher) bool fin_server_seen; ///< whether a server finished handshake message was seen (must immediately follow the server change cipher) protected: static SSLv3_Automaton sslAutomaton; ///< represents the SSLv3.0/SSLv3.1 automaton static bool bInited; ///< whether the automaton is already initialised (has to be only done once) int currentState; ///< the current state of the SSL automaton in this SSLv3_Interpreter instance // uint16 cipherSuite; ///< the cipher spec client and server agreed upon SSL_DataBlock* pClientCipherSpecs; ///< the CIPHER-SPECs from the client SSL_CipherSpec* pCipherSuite; ///< pointer to the cipher spec definition client and server agreed upon uint32 cipherSuiteIdentifier; ///< only used for unknown cipher-specs SSL_DataBlock* clientSessionID; ///< the session ID of the client hello record SSL_DataBlock* serverSessionID; ///< the session ID for this SSL session /**Attributes for cryptographic computations*/ SSLv3x_Random* clientRandom; SSLv3x_Random* serverRandom; //SSL_KeyExchangeAlgorithm keyXAlgorithm; SSLv3x_ServerRSAParams* serverRSApars; SSLv3x_ServerDHParams* serverDHPars; SSLv3x_EncryptedPremasterSecret* encryptedPreSecret; SSLv3x_ClientDHPublic* clientDHpublic; bool helloRequestValid; ///< Whether sending a hello request is valid (normally after handshaking phase) /** This method builds the corresponding SSLv3_Endpoints for this SSLv3_Interpreter. * It is called in the SSL_Interpreter's Init() method. */ void BuildInterpreterEndpoints(); /** This method initialises the SSL state automaton; sets the states and transitions. * It needs only to be called once for a whole bro. @see SSLDefines.h */ void BuildAutomaton(); /** This helper method translates the handshake types included in the SSL handshake * records to the corresponding transition of the SSL automaton. It is invoked within * the DeliverSSLv3_Record(SSLv3_HandshakeRecord*) method. * * @param type the handshake type of the handshake record */ int HandshakeType2Trans(int type); /** This method is used for event generation during the handshaking phase and * generates the connection-attempt, server-reply, connection-established, connection-reused * events dependant on the currentState of the SSL Automaton. * It calls the appropriate fire_* methods of the SSL_Interpreter for this. * The method is called within the the DeliverSSLv3_Record() methods. * * @param rec the SSLv3_Record which is currently processed */ void GenerateEvents(SSLv3_Record* rec, TableVal* curCipherSuites); /** This method analyzes the cipher suites the client and server offer * each other during handshaking phase. It checks, whether it's a 'common' * cipher suite and sets the pCipherSuite attribute according to the * cipher suite client and server agreed on. * * @param s the SSLv3_Endpoint which sent the SSL record with the cipher suite(s) to be analyzed * @param length length of data * @param data pointer to where the cipher suites can be found * @param version SSL version of the SSL record that contained the cipher suite(s) * @return a pointer to a Bro TableVal (of type cipher_suites_list) which contains * the cipher suites list of the current analyzed record */ TableVal* analyzeCiphers(const SSLv3_Endpoint* s, int length, const u_char* data, uint16 version); }; // ---------------------------------------------------------------------------- /** Class SSLv3_Endpoint is the implementation for SSLv3.0/SSLv3.1 connection * endpoints (derived from the abstract class SSL_InterpreterEndpoint). * * A SSLv3_Endpoint gets completely reassembled ssl records via the method * Deliver(), which is invoked in this Endpoint's corresponding SSLProxy_Analyzer. * The defragmentation and reassembling already took place in the * SSLProxy_Analyzer's SSL_RecordBuilder. * The Deliver()-method does some basic weird checks and then calls * ProcessMessage() which determines the content type of the ssl record * and, dependant on that, creates an instance of the appropriate SSLv3_Record. * This is passed on to this endpoint's corresponding SSLv3_Interpreter via * the DeliverSSLv3_Record()-method. */ class SSLv3_Endpoint : public SSL_InterpreterEndpoint { public: /** The constructor takes the corresponding SSL_Interpreter as argument. * is_orig sets this endpoint as originator of the connection (1), and * responder otherwise (0). * * @param interpreter the SSL_Interpreter this endpoint is bound to. * @param is_orig whether this endpoint is the originator (1) of the * connection or not (0). */ SSLv3_Endpoint(SSL_Interpreter* interpreter, int is_orig); virtual ~SSLv3_Endpoint(); /** This method is invoked by this endpoint's corresponding * SSLProxy_Analyzer and receives completely reassembled SSL * records (by the data argument). * * @param t time is always 0 (former: when the segment was received * by bro (?)) * @param len length of SSL record * @param data content of SSL record */ void Deliver(int len, const u_char* data); protected: uint16 sslVersion; ///< holds the version of the just delivered SSL record uint16 currentMessage_length; ///< the length of the just delivered SSL record /** This method extracts the content type of the SSL record passed * in the first parameter. * * @param data the SSL record * @param len length of the record * @return SSL3_1_ContentType of SSL record */ SSL3_1_ContentType ExtractContentType(const u_char* data, int len); /** This method determines the version of the SSL record passed to it. * It sets the field sslVersion of this endpoint an is called within * the method ProcessMessage(). * * @param data the SSL record * @param len length of the record * @return 0 if version is NOT 3.0/3.1, 1 otherwise */ int ExtractVersion(const u_char* data, int len); /** This method processes a complete SSL record. It * determines the content type of the SSL record * (handshake, alert, change-cipher-spec, application), * cuts away the SSL record layer header and generates * the appropriate SSLv3_Record. Then it calls the SSLv3_Record's * Deliver() method, which manages the delivery of the record * to the corresponding SSLv3_Interpreter * * @param data the complete SSL record * @param len data's (record's) length */ void ProcessMessage(const u_char* data, int len); }; // ---------------------------------------------------------------------------- // Offsets are now relative to the end of the SSL record layer header #define SSL3_1_CHANGE_CIPHER_TYPE_OFFSET (SSL3_1_HEADERLENGTH - 5) #define SSL3_1_ALERT_LEVEL_OFFSET (SSL3_1_HEADERLENGTH - 5) #define SSL3_1_ALERT_DESCRIPTION_OFFSET (SSL3_1_HEADERLENGTH - 4) #define SSL3_1_SESSION_ID_LENGTH_OFFSET 38 #define SSL3_1_SESSION_ID_OFFSET 39 /** This class is an abstract base class for the four different * SSLv3.0/SSLv3.1 record types (handshake, alert, change-cipher-spec, * application). * * It contains a pointer to the data of the SSL record without * the SSL record layer header, it's length and the version information, which * was present in the now cut away SSL record layer header. * * (Note: the version field of the SSL record layer header may differ from * the version of the record format that was used when sending the record. * (e.g. a client may send a SSLv2 record including * a version field containing 3.1 (for SSLv3.1) to show, that he supports * version 3.1.)) * * Every subclass of SSLv3_Record implements the Deliver() method, which * manages the delivery of the record to the corresponding SSLv3_Interpreter. * Instances of SSLv3_Record (resp. it's subclasses) are created within * the ProcessMessage() method of a SSLv3_Endpoint. * */ class SSLv3_Record : public BroObj{ public: /** The constructor gets a pointer to the SSL record without the * record layer header, it's length, the version information * contained in the record layer header and a pointer to the * SSLv3_Endpoint that created this instance of SSLv3_Record. * * @param data pointer to the SSL record without record layer header * @param data's length * @param version version information contained in the SSL record layer header * @param e the SSLv3_Endpoint that created this instance */ SSLv3_Record(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e); ~SSLv3_Record(); void Describe(ODesc* d) const; int GetRecordLength() const; const u_char* GetData() const; uint16 GetVersion() const; SSLv3_Endpoint const* GetEndpoint() const; /** This abstract method is implemented by the various SSLv3_Record * subclasses for handshake, alert, change cipher spec and application * records. It manages the delivery of the SSLv3_Record to the * SSLv3_Interpreter passed as argument. * SSLv3_Records are created within the ProcessMessage() method of the * SSLv3_Endpoint which then calls the just created SSLv3_Records * Deliver() method with it's corresponding SSLv3_Interpreter as * argument which then receives the (evtl. preprocessed) SSLv3_Record * (via the method(s) DeliverSSLv3_Record()). * * @param conn the SSLv3_Interpreter to which this SSLv3_Record should be deliverd */ virtual void Deliver(SSLv3_Interpreter* conn) =0; /** Helper function that converts from 24-bit big endian integer * starting at offset to 32 bit integer in little endian format. * * @param data the ssl-record * @param len length of data (record) * @param offset where the 24 bit big endian starts * @return 32 bit little endian */ int ExtractInt24(const u_char* data, int len, int offset); int recordLength; ///< total length of the SSL record without the record layer header const u_char* data; ///< pointer to the SSL record without the record layer header SSLv3_Endpoint const* endp; ///< pointer to the SSLv3_Endpoint that created this instance of SSLv3_Record uint16 sslVersion; ///< version information of the SSL record layer header }; // ---------------------------------------------------------------------------- /* This class represents a handshake record used in SSLv3.0/SSLv3.1. * * Handshake records in SSLv3.0/SSLv3.1 need a special treatment, * because it is possible that multiple handshake messages are coalesced into * a single SSLv3.0/SSLv3.1 record. * I think, this only can happen to * handshake records (even RFC2246 page 16 generally talks about all * messages of a same content type), because only handshake records * have got an own length descriptor within and thus make de-coalescing * possible. * So when generating a new instance of a SSLv3_HandshakeRecord, it is checked whether there * are more handshake records within data. * If so, they are put apart and linked together to a chain by using * the next-pointer. * The Deliver() method takes this into account and delivers every single * handshake record one by one to the SSLv3_Interpreter. */ class SSLv3_HandshakeRecord : public SSLv3_Record{ public: SSLv3_HandshakeRecord(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e); ~SSLv3_HandshakeRecord(); int GetType() const; int GetLength() const; /** This method delivers the SSLv3_HandshakeRecord(s) to the * SSLv3_Interpreter passed as argument. The method follows * the next-pointer and delivers every SSLv3_HandshakeRecord * contained in this list to the SSLv3_Interpreter. * * @param conn the SSLv3_Interpreter to which this SSLv3_HandshakeRecord should be deliverd */ void Deliver(SSLv3_Interpreter* conn); /* This method is invoked within the SSLv3_Interpreter and does lots of * weird and consistency checks on a client hello SSL handshake record. * * @return 0 if further processing of this client hello is not * possible due to inconsistency and 1 otherwise. */ int checkClientHello(); /* This method is invoked within the SSLv3_Interpreter and does lots of * weird and consistency checks on a server hello SSL handshake record. * * @return 0 if further processing of this server hello is not * possible due to inconsistency and 1 otherwise. */ int checkServerHello(); int type; ///< holds the handshake type of the handshake record (first byte) int length; ///< holds the length of this handshake record (which is needed due to coalesced handshake messages) private: SSLv3_HandshakeRecord* next; ///< pointer to the next ssl handshake record if they are coalesced into a single record SSLv3_HandshakeRecord* GetNext(); }; // ---------------------------------------------------------------------------- /** This class represents an alert record used in SSLv3.0/SSLv3.1. * * description holds the SSL alert description and level the alert level. */ class SSLv3_AlertRecord : public SSLv3_Record { public: SSLv3_AlertRecord(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e); ~SSLv3_AlertRecord(); int GetDescription() const; int GetLevel() const; /** This method delivers the SSLv3_AlertRecord to the SSLv3_Interpreter passed as * argument. * * @param conn the SSLv3_Interpreter to which this SSLv3_AlertRecord should be deliverd */ void Deliver(SSLv3_Interpreter* conn); int description; ///< holds the alert description int level; ///< holds the alert level }; // ---------------------------------------------------------------------------- /** This class represents a change cipher record used in SSLv3.0/SSLv3.1. * * type holds the change cipher type used (currently only 1 is valid (rfc 2246)) */ class SSLv3_ChangeCipherRecord : public SSLv3_Record{ public: SSLv3_ChangeCipherRecord(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e); ~SSLv3_ChangeCipherRecord(); int GetType() const; /** This method delivers the SSLv3_ChangeCipherRecord to the * SSLv3_Interpreter passed as argument. * * @param conn the SSLv3_Interpreter to which this * SSLv3_ChangeCipherRecord should be delivered */ void Deliver(SSLv3_Interpreter* conn); int type; ///< holds the change cipher type }; // ---------------------------------------------------------------------------- /** This class represents an application record used in SSLv3.0/SSLv3.1. */ class SSLv3_ApplicationRecord : public SSLv3_Record { public: SSLv3_ApplicationRecord(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e); ~SSLv3_ApplicationRecord(); /** This method delivers the SSLv3_ApplicationRecord to the * SSLv3_Interpreter passed as argument. * * @param conn the SSLv3_Interpreter to which this * SSLv3_ApplicationRecord should be deliverd */ void Deliver(SSLv3_Interpreter* conn); }; #endif