Branch data Line data Source code
1 : : // $Id: SSLProxy.h 5952 2008-07-13 19:45:15Z vern $
2 : :
3 : : #ifndef SSLPROXY_H
4 : : #define SSLPROXY_H
5 : :
6 : : #include "TCP.h"
7 : : #include "SSLInterpreter.h"
8 : : #include "binpac_bro.h"
9 : :
10 : : // --- forward declarations ---------------------------------------------------
11 : :
12 : : class SSL_Interpreter;
13 : : class SSL_RecordBuilder;
14 : : class Contents_SSL;
15 : :
16 : : // --- class SSL_DataBlock ----------------------------------------------------
17 : :
18 : : /*!
19 : : * \brief This class is used to store a block of data on the heap, which is
20 : : * allocated and copied by the constructor, and freed by the destructor.
21 : : *
22 : : * It is mainly used by the SSL_RecordBuilder to store the received data. To
23 : : * reduce heap operations (HeapOps), which can be quite expensive, it is
24 : : * possible to let the constructor allocate a minimum heap block size. The
25 : : * class members keep track of how much data has been allocated and how much of
26 : : * it has been used. Plus, there's a pointer to the next SSL_DataBlock, for
27 : : * easy creation of a single-linked list.
28 : : */
29 : :
30 : : class SSL_DataBlock {
31 : : public:
32 : : SSL_DataBlock(const u_char* data, int len, int min_len = 0);
33 : :
34 : : int len; ///< The <b>used</b> size of the reserved heap block.
35 : : int size; ///< The <b>allocated</b> size of the reserved heap block.
36 : : u_char* data; ///< Pointer to the allocated heap block.
37 : : SSL_DataBlock* next; ///< Pointer to the next SSL_Datablock in the chain.
38 : :
39 : : /*!
40 : : * The destructor will free the allocated data block.
41 : : */
42 [ # # ]: 0 : ~SSL_DataBlock() { delete [] data; }
43 : :
44 : : void toStream(FILE* stream) const;
45 : : char* toString() const;
46 : : };
47 : :
48 : : // --- class SSL_RecordBuilder ------------------------------------------------
49 : :
50 : : /*!
51 : : * \brief This class is used to reassemble SSL records from a stream of data.
52 : : *
53 : : * It supports both SSLv2 and SSLv3 record formats at the same time. The record
54 : : * builder has been designed to be robust, efficient and hard to attack. To add
55 : : * a segments of data, call addSegment(). Whenever a SSL record has been
56 : : * reassembled, the DoDeliver() function of the corresponding Contents_SSL
57 : : * will be called.
58 : : *
59 : : * Two forms of attack have been taken into consideration:
60 : : * -# The "fake size" attack, where the actual size of the SSL record is much
61 : : * smaller then the size given in the record header. This way, an attacker
62 : : * could force Bro to allocate a huge amount of memory and make it crash.
63 : : * -# The "small fragment" attack, where an attacker sends huge SSL records
64 : : * in very small (1 byte or so) TCP segments. This could lead to a huge
65 : : * amount of very small memory blocks allocated by Bro. After the last byte
66 : : * of an SSL record has been received, all allocated blocks have to be
67 : : * freed. Freeing something like 32K blocks of memory can be quite expensive,
68 : : * so packet drops may occur, which could prevent Bro from detecting an
69 : : * attacker.
70 : : *
71 : : * The current implementation always allocates a minimum size of data on the
72 : : * heap, which is MIN_ALLOC_SIZE. The processed SSL record fragments are stored
73 : : * in a single-linked list of type SSL_DataBlock.
74 : : *
75 : : * The following assumptions are made:
76 : : * - neededSize <= min( expectedSize )
77 : : * - neededSize <= MIN_ALLOC_SIZE, so the data needed to determine the SSL
78 : : * record version fits in one SSL_DataBlock
79 : : */
80 : :
81 : : class SSL_RecordBuilder {
82 : : public:
83 : : SSL_RecordBuilder(Contents_SSL* sslEndpoint);
84 : : ~SSL_RecordBuilder();
85 : :
86 : : static const uint MIN_ALLOC_SIZE = 16; ///< min. size of memory to alloc
87 : : static const int MIN_FRAGMENT_SIZE = 100; ///< min. size of a middle TCP Segment
88 : : static uint maxAllocCount; ///< max. number of allocated data blocks for an instance of a reassembler
89 : : static uint maxFragmentCount; ///< max. number of fragments for a ssl record
90 : : static uint fragmentedHeaders; ///< counter for the number of fragmented headers (header=neededSize)
91 : :
92 : : bool addSegment(const u_char* data, int length);
93 : :
94 : : /*!
95 : : * Calls this method to see if there's currently data in the
96 : : * record builder pending.
97 : : * \return true if there's data pending, false otherwise
98 : : */
99 : 0 : bool isDataPending() { return hasPendingData; };
100 : :
101 : : protected:
102 : : u_char* assembleBlocks(const u_char* data, int length);
103 : : int analyzeSSLRecordFormat(const u_char* data, int length);
104 : : bool computeExpectedSize (const u_char* data, int length);
105 : : void addData(const u_char* data, int length);
106 : :
107 : : SSL_DataBlock* head; ///< pointer to the first element in the linked list of SSL_DataBlocks
108 : : SSL_DataBlock* tail; ///< pointer to the last element in the linked list of SSL_DataBlocks
109 : : Contents_SSL* sslEndpoint; ///< pointer to the containing Contents_SSL
110 : : int expectedSize; ///< expected size of SSLv2 record including header
111 : : int currentSize; ///< current bytes stored in data blocks (that is, processed size of actual record)
112 : : int neededSize; ///< min. size in bytes so that the length of the current record can be determinded
113 : : bool hasPendingData; ///< true if there's data following in the current tcp segment
114 : : uint fragmentCounter; ///< counter for the number of tcp segments for the current record
115 : : };
116 : :
117 : :
118 : : // --- class SSLProxy_Analyzer ----------------------------------------------
119 : :
120 : : /** This class represents an SSL_Connection with two SSL_ConnectionEndpoints.
121 : : * Note, that this class acts as a proxy, because there are different versions
122 : : * of the SSL protocol in use and you don't know in advance which SSL version
123 : : * really will be used. This depends on the first two messages of the SSL handshake
124 : : * process. Because Bro offers no possibility for switching connections we
125 : : * decided only to inherit this proxy from TCP_Connection.
126 : : * The different SSL versions are implemented in classed derived from
127 : : * SSL_Interpreter/SSL_InterpreterEndpoint and so, we can easily switch the flow
128 : : * of data to the appropriate SSL Interpreter.
129 : : * Currently, we support SSL Version 2.0 and 3.0/3.1(TLS)(@see SSLv2_Interpreter and @see
130 : : * SSLv3_Interpreter).
131 : : * This class holds an instance of both SSLv2- and SSLv3_Interpreter. The version
132 : : * of the SSL that is used for a connection is negotiated within the first
133 : : * two records (SSL messages): client hello and server hello.
134 : : * So after scanning this two records (which is mainly done in @see SSL_RecordBuilder and
135 : : * @see Contents_SSL) and determing the versions, it is clear which
136 : : * SSL version will be used for the succeding SSL records. From now
137 : : * on, they can be directly passed through to the appropriate SSL_Interpreter.
138 : : *
139 : : * FIXME: Now we have a dynamic analyzer framework so this could be restructured.
140 : : */
141 : : class SSLProxy_Analyzer: public TCP_ApplicationAnalyzer {
142 : : public:
143 : : SSLProxy_Analyzer(Connection* conn);
144 : : virtual ~SSLProxy_Analyzer();
145 : :
146 : : static uint totalPackets; ///< counter for total ssl packets seen
147 : : static uint totalRecords; ///< counter for total ssl records seen
148 : : static uint nonSSLConnections; ///< counter for connections where we couldn't reassemble a ssl record
149 : :
150 : : static const bool recordSSLv2Traffic = false; ///< if true, only recording of SSLv2 connections is done (no analysis)
151 : :
152 : : static bool bInited;
153 : :
154 : : enum SSL_Versions {
155 : : SSLv20 = 0x0002,
156 : : SSLv30 = 0x0300,
157 : : SSLv31 = 0x0301 // = TLS 1.0
158 : : };
159 : :
160 : : /* This method is called from the corresponding Contents_SSL to
161 : : * deliver the data to the SSL_ProxyConnection. It decides which
162 : : * SSL_Interpreter (Version 2 or Version 3x) gets the record or
163 : : * directly passes it through, if it's already clear which version
164 : : * this SSL connection uses.
165 : : * @param endp the sending endpoint
166 : : * @param len length of SSL record
167 : : * @param data the SSL record
168 : : *
169 : : * SC mod - pass a TCP_Contents rather than endpoint in terms of an actual
170 : : * Contents_SSL. There is much less overall work to do since we
171 : : * have already done the assosciation.
172 : : */
173 : : void NewSSLRecord(Contents_SSL* endp, int len, const u_char* data);
174 : :
175 : : // Initialises the SSLv2- and SSLv3_Interpreters.
176 : : virtual void Init();
177 : :
178 : : // This method is used for passing messages to Bro that contain
179 : : // information about weaknesses in the choosen SSL encryption
180 : : // (short keys, unverifyable certificates, ...)
181 : : // @param name the name of the weakness.
182 : : void Weak(const char* name);
183 : :
184 : 0 : static Analyzer* InstantiateAnalyzer(Connection* conn)
185 : 0 : { return new SSLProxy_Analyzer(conn); }
186 : :
187 : 1 : static bool Available()
188 : : {
189 : : return (ssl_certificate_seen || ssl_certificate ||
190 : : ssl_conn_attempt || ssl_conn_server_reply ||
191 : : ssl_conn_established || ssl_conn_reused ||
192 : : ssl_conn_alert)
193 [ + - ][ + - ]: 1 : && ! FLAGS_use_binpac;
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ # # ]
194 : : }
195 : :
196 : : static void printStats();
197 : :
198 : : protected:
199 : : bool bPassThrough; ///< whether it is clear which SSL version the connection will use
200 : :
201 : : SSL_Interpreter* sSLv2Interpreter; ///< Interpreter for SSL version 2
202 : : SSL_Interpreter* sSLv3xInterpreter; ///< Interpreter for SSL version 3.0 and 3.1
203 : : SSL_Interpreter* sSLInterpreter; ///< Pointer to the interpreter currently in use
204 : :
205 : : Contents_SSL* sslpeo;
206 : : Contents_SSL* sslper;
207 : :
208 : : /** Internally called from this class Deliver()-method.
209 : : * It delivers the data to the correct corresponding
210 : : * SSL_InterpreterEndpoint.
211 : : * @param endp the sending endpoint
212 : : * @param t time, when the segment was received by bro (not used)
213 : : * @param seq relative sequenze number (from Endpoint::start_seq) (not used)
214 : : * @param len length of SSL record
215 : : * @param data the SSL record
216 : : */
217 : : void DoDeliver(int len, const u_char* data, bool orig);
218 : :
219 : : // Initialises the dictionary where the SSL cipher specs are stored.
220 : : // It needs only to be called once for a whole bro. @see SSLDefines.h
221 : : void BuildCipherDict();
222 : : };
223 : :
224 : : // --- class Contents_SSL ------------------------------------------------
225 : :
226 : : /** This class represents an endpoint of a SSLProxy_Analyzer.
227 : : * It receives the new data (TCP segments) within the Deliver()-method, does
228 : : * some basic checks on the segment and passes it on to the SSL_RecordBuilder,
229 : : * which reassembles the segments into SSL records and determines the
230 : : * versions of the records. If the SSL_RecordBuilder was able to determine
231 : : * the versions of the records it delivers the reassembled records back tho this
232 : : * Contents_SSL by calling the DoDeliver()-method.
233 : : * The Contents_SSL then hands the record over to the corresponding
234 : : * SSLProxy_Analyzer by invoking it's NewSSLRecord()-method.
235 : : *
236 : : * SC mod: change class Contents_SSL: public TCP_EndpointContents
237 : : * to class Contents_SSL: public TCP_Contents
238 : : * this is done since the class uses the Deliver() method to take care of data.
239 : : *
240 : : */
241 : : class Contents_SSL: public TCP_SupportAnalyzer {
242 : : public:
243 : : /* The constructor builds up and initialises the Contents_SSL.
244 : : * @param conn the corresponding Connection
245 : : * @param whether this is the originator
246 : : */
247 : : Contents_SSL(Connection* conn, bool orig);
248 : : ~Contents_SSL();
249 : :
250 : : int sslRecordVersion; ///< record version of the first SSL record seen (set by SSLProxy_Analyzer and SSL_RecordBuilder)
251 : : uint16 sslVersion; ///< SSL version of the SSL record seen (set by SSL_RecordBuilder)
252 : :
253 : : /** Via this method, this Contents_SSL receives the
254 : : * TCP segments.
255 : : * @param len length of TCP-Segment
256 : : * @param data content of TCP-Segment
257 : : * @param orig whether sending endpoint is originator
258 : : */
259 : : virtual void DeliverStream(int len, const u_char* data, bool orig);
260 : :
261 : : /** This method is called by the corresponding SSL_RecordBuilder
262 : : * upon delivering a new reassembled SSL record.
263 : : * @param len the length of the record
264 : : * @param data the record
265 : : */
266 : : void DoDeliver(int len, const u_char* data);
267 : :
268 : : /* @return whether we have already seen the first record of the connection of this endpoint yet
269 : : */
270 : : bool VersionRecognized();
271 : :
272 : : /* @return whether the first record was of SSL version 2.0
273 : : */
274 : : bool IsSSLv2Record();
275 : :
276 : : /* @return whether the corresponding SSL_RecordBuilder has pending data
277 : : */
278 : : bool isDataPending(); // should be inline
279 : :
280 : : SSL_RecordBuilder* sslRecordBuilder;
281 : :
282 : : protected:
283 : : bool bVersionRecognized; ///< False, if we haven't seen the first record of the connection of this endpoint yet
284 : : bool bIsSSLv2Record; ///< Was the first record of SSL version 2.0
285 : : };
286 : :
287 : : #endif
|