Branch data Line data Source code
1 : : // $Id: SSLProxy.cc 6008 2008-07-23 00:24:22Z vern $
2 : :
3 : : #include "SSLProxy.h"
4 : : #include "SSLv3.h"
5 : : #include "SSLv2.h"
6 : :
7 : : // --- Initalization of static variables --------------------------------------
8 : :
9 : : uint SSLProxy_Analyzer::totalPackets = 0;
10 : : uint SSLProxy_Analyzer::totalRecords = 0;
11 : : uint SSLProxy_Analyzer::nonSSLConnections = 0;
12 : :
13 : : // --- SSL_DataBlock --------------------------------------------------------
14 : :
15 : : /*!
16 : : * This constructor will allocate a block of data on the heap. If min_len is
17 : : * given, it will determine the minimum size of the new block. The data block
18 : : * referenced by data will be then be copied into the new block.
19 : : *
20 : : * \param data Pointer to the data which will be copied into the newly
21 : : * allocated heap block.
22 : : * \param len Length of the data block to copy.
23 : : * \param min_len The minimum size of data to allocate on the heap, can be omitted.
24 : : */
25 : :
26 : 0 : SSL_DataBlock::SSL_DataBlock(const u_char* arg_data, int len, int min_len)
27 : : {
28 : : // For performance reasons, we allocate at least min_len.
29 [ # # ][ # # ]: 0 : if ( len < min_len )
30 : : {
31 : 0 : data = new u_char[min_len];
32 : 0 : size = min_len;
33 : : }
34 : : else
35 : : {
36 : 0 : data = new u_char[len];
37 : 0 : this->size = len;
38 : : }
39 : :
40 : 0 : memcpy(data, arg_data, len);
41 : 0 : this->len = len;
42 : 0 : next = 0;
43 : 0 : }
44 : :
45 : : /*!
46 : : * This is an experimental function which will print the contents of the
47 : : * internal data block in a human-readable fashion to a stream.
48 : : *
49 : : * \param stream The stream for printing the data block to.
50 : : */
51 : :
52 : 0 : void SSL_DataBlock::toStream(FILE* stream) const
53 : : {
54 [ # # ]: 0 : if ( len <= 0 )
55 : 0 : return;
56 : :
57 : : int idx;
58 [ # # ]: 0 : for ( idx = 0; idx < len-1; ++idx )
59 : 0 : fprintf(stream, "%02X:", data[idx]);
60 : :
61 : 0 : fprintf(stream, "%02X", data[idx]);
62 : : }
63 : :
64 : : /*!
65 : : * This is an experimental function which will print the contents of the
66 : : * internal data block in a human-readable fashion to a string.
67 : : *
68 : : * \return A string which has to be freed by the caller.
69 : : */
70 : :
71 : 0 : char* SSL_DataBlock::toString() const
72 : : {
73 [ # # ]: 0 : if ( len <= 0 )
74 : : {
75 : : // Currently, we return an empty string if data block is empty.
76 : 0 : char* pDummy = new char[1];
77 : 0 : pDummy[0] = '\0';
78 : 0 : return pDummy;
79 : : }
80 : :
81 : 0 : char* pString = new char[len*3];
82 : 0 : char* pItx = pString;
83 : :
84 : : int idx;
85 [ # # ]: 0 : for ( idx = 0; idx < len-1; ++idx )
86 : : {
87 : 0 : sprintf(pItx, "%02X:", data[idx]);
88 : 0 : pItx += 3;
89 : : }
90 : :
91 : 0 : sprintf(pItx, "%02X", data[idx]);
92 : :
93 : 0 : return pString;
94 : : }
95 : :
96 : : // --- SSL_RecordBuilder ------------------------------------------------------
97 : :
98 : : uint SSL_RecordBuilder::maxAllocCount = 0;
99 : : uint SSL_RecordBuilder::maxFragmentCount = 0;
100 : : uint SSL_RecordBuilder::fragmentedHeaders = 0;
101 : :
102 : : /*!
103 : : * The constructor takes an Contents_SSL as parameter. Whenever a SSL
104 : : * record has been reassembled, the DoDeliver() function of this
105 : : * Contents_SSL will be called.
106 : : *
107 : : * \param sslEndpoint The Contents_SSL to which this instance of
108 : : * SSL_RecordBuilder is bound.
109 : : */
110 : :
111 : 0 : SSL_RecordBuilder::SSL_RecordBuilder(Contents_SSL* arg_sslEndpoint)
112 : : {
113 : 0 : head = tail = 0;
114 : 0 : currentSize = 0;
115 : 0 : expectedSize = -1; // -1 means we don't know yet
116 : 0 : hasPendingData = false;
117 : 0 : fragmentCounter = 0;
118 : 0 : neededSize = 5; // we need at least 5 bytes to determine version
119 : :
120 : 0 : sslEndpoint = arg_sslEndpoint;
121 : 0 : }
122 : :
123 : : /*!
124 : : * The destructor frees the chain of SSL_DataBlocks.
125 : : */
126 : :
127 : 0 : SSL_RecordBuilder::~SSL_RecordBuilder()
128 : : {
129 : : // Free the data chain.
130 : 0 : SSL_DataBlock* idx = head;
131 : : SSL_DataBlock* rm;
132 : :
133 [ # # ][ # # ]: 0 : while ( idx )
134 : : {
135 : 0 : rm = idx;
136 : 0 : idx = idx->next;
137 [ # # ][ # # ]: 0 : delete rm;
138 : : }
139 : 0 : }
140 : :
141 : : /*!
142 : : * This function is the main entry point of the class. Call it with a segment
143 : : * of data to process.
144 : : *
145 : : * \param data pointer to a data segment that will be reassembled
146 : : * \param length length of the data segment to be reassembled
147 : : *
148 : : * \return true if succesfull, false otherwise
149 : : */
150 : :
151 : 0 : bool SSL_RecordBuilder::addSegment(const u_char* data, int length)
152 : : {
153 [ # # ]: 0 : while ( length > 0 )
154 : : {
155 [ # # ]: 0 : if ( ! head )
156 : : {
157 : : // This is the first fragment of a SSLv2 record,
158 : : // so we analyze the header.
159 : :
160 : : // Special case: SSL header has been fragmented.
161 [ # # ]: 0 : if ( length < neededSize )
162 : : {
163 : : // We can't determine the record size yet,
164 : : // so we just add this stuff.
165 : 0 : ++fragmentedHeaders;
166 : : head = tail = new SSL_DataBlock(data, length,
167 : 0 : MIN_ALLOC_SIZE);
168 : 0 : currentSize += length;
169 : 0 : expectedSize = -1; // special meaning
170 : 0 : break;
171 : : }
172 : :
173 : : // Get the expected length of this record.
174 [ # # ]: 0 : if ( ! computeExpectedSize(data, length) )
175 : 0 : return false;
176 : :
177 : : // Insert weird here replacing assert.
178 [ # # ]: 0 : if ( neededSize > expectedSize )
179 : : {
180 : 0 : sslEndpoint->Weird("SSL_RecordBuilder::addSegment neededSize > expectedSize");
181 : 0 : return false;
182 : : }
183 : :
184 [ # # ]: 0 : if ( tail != 0 )
185 : : {
186 : 0 : sslEndpoint->Parent()->Weird("SSL_RecordBuilder::addSegment tail != 0");
187 : 0 : return false;
188 : : }
189 : :
190 [ # # ]: 0 : if ( length > expectedSize )
191 : : {
192 : : // No fragmentation -> no memory-reallocation.
193 : : // We have additional data pending.
194 : 0 : hasPendingData = true;
195 : 0 : sslEndpoint->DoDeliver(expectedSize, data);
196 : 0 : length -= expectedSize;
197 : 0 : data += expectedSize;
198 : 0 : expectedSize = -1;
199 : : }
200 : :
201 [ # # ]: 0 : else if ( length == expectedSize )
202 : : {
203 : : // No fragmentation -> no memory-reallocation.
204 : : // No additional data pending.
205 : 0 : hasPendingData = false;
206 : 0 : sslEndpoint->DoDeliver(expectedSize, data);
207 : 0 : length -= expectedSize;
208 : 0 : data += expectedSize;
209 : 0 : expectedSize = -1;
210 : 0 : break;
211 : : }
212 : : else
213 : :
214 : : {
215 : : // First fragment of a record.
216 : : head = tail = new SSL_DataBlock(data, length,
217 : 0 : MIN_ALLOC_SIZE);
218 : 0 : currentSize += length;
219 : 0 : break;
220 : : }
221 : :
222 : 0 : continue;
223 : : }
224 : :
225 : : // ! head.
226 : : // We already have some data, so add the current
227 : : // segment special case.
228 [ # # ]: 0 : if ( expectedSize < 0 )
229 : : {
230 : : // We don't know the expected size of
231 : : // this record yet.
232 [ # # ]: 0 : if ( currentSize + length < neededSize )
233 : : {
234 : : // We still can't determine the expected size,
235 : : // so we just add the current fragment.
236 : 0 : addData(data, length);
237 : 0 : break;
238 : : }
239 : :
240 : : // Now we can determine the expected size the
241 : : // header has been fragmented, so we have to
242 : : // reassemble it.
243 : 0 : uint8 Header[neededSize];
244 : 0 : memcpy(Header, head->data, head->len);
245 : 0 : memcpy(Header + head->len, data, neededSize - head->len);
246 [ # # ]: 0 : if ( ! computeExpectedSize(Header, neededSize) )
247 : : {
248 : : // Since neededSize <= MIN_ALLOC_SIZE,
249 : : // we free only head.
250 [ # # ]: 0 : delete head;
251 : 0 : head = tail = 0;
252 : 0 : return false;
253 : : }
254 : :
255 [ # # ]: 0 : if ( neededSize > expectedSize )
256 : : {
257 : 0 : sslEndpoint->Parent()->Weird("SSL_RecordBuilder::addSegment neededSize > expectedSize");
258 [ # # # ]: 0 : return false;
259 : : }
260 : :
261 : : // No break, go on with this packet.
262 : : }
263 : :
264 [ # # ]: 0 : if ( currentSize + length == expectedSize )
265 : : { // this is exactly the last segment of the record
266 : 0 : hasPendingData = false;
267 : :
268 : : // Create a continuous data structure and call
269 : : // DoDeliver().
270 : 0 : u_char* pBlock = assembleBlocks(data, length);
271 : 0 : sslEndpoint->DoDeliver(expectedSize, pBlock);
272 [ # # ]: 0 : delete [] pBlock;
273 : 0 : expectedSize = -1;
274 : 0 : break;
275 : : }
276 : :
277 [ # # ]: 0 : else if ( currentSize + length < expectedSize )
278 : : { // another (middle) segment
279 [ # # ]: 0 : if ( length <= MIN_FRAGMENT_SIZE )
280 : 0 : sslEndpoint->Parent()->Weird( "SSLProxy: Excessive small TCP Segment!" );
281 : :
282 : 0 : addData(data, length);
283 : 0 : break;
284 : : }
285 : :
286 : : else
287 : : {
288 : : // This is the last fragment of the current record,
289 : : // but there's more data in this segment.
290 : 0 : int deltaSize = expectedSize - currentSize;
291 : 0 : hasPendingData = true;
292 : :
293 : : // Create a continuous data structure and call
294 : : // DoDeliver().
295 : 0 : u_char* pBlock = assembleBlocks(data, deltaSize);
296 : 0 : sslEndpoint->DoDeliver(expectedSize, pBlock);
297 [ # # ]: 0 : delete [] pBlock;
298 : 0 : expectedSize = -1;
299 : :
300 : : // Process the rest.
301 : 0 : length -= deltaSize;
302 : 0 : data += deltaSize;
303 : : }
304 : : } // while
305 : :
306 : 0 : return true;
307 : : }
308 : :
309 : : /*!
310 : : * This function is called internally by addSegment(), and add's a new SSL
311 : : * record fragment to the internally used list of SSL_DataBlocks. Note that
312 : : * the data will be copied!
313 : : *
314 : : * \param data pointer to the data that will be added
315 : : * \param length length of the data that will be added
316 : : */
317 : :
318 : 0 : inline void SSL_RecordBuilder::addData(const u_char* data, int length)
319 : : {
320 : 0 : ++fragmentCounter;
321 : :
322 : : // Check if there's some space left in the last datablock.
323 : 0 : int bytesLeft = tail->size - tail->len;
324 [ # # ]: 0 : if ( bytesLeft > 0 )
325 : : {
326 : : // There's some space left in the last data block.
327 [ # # ]: 0 : if ( bytesLeft >= length )
328 : : {
329 : : // We can store all bytes in the last data block.
330 : 0 : memcpy(tail->data + tail->len, data, length);
331 : 0 : tail->len += length;
332 : 0 : currentSize += length;
333 : : }
334 : : else
335 : : {
336 : : // We cannot store all bytes in the last data block,
337 : : // so we also need to add a new one.
338 : 0 : memcpy(tail->data + tail->len, data, bytesLeft);
339 : 0 : tail->len = tail->size;
340 : 0 : currentSize += length;
341 : :
342 : 0 : data += bytesLeft;
343 : 0 : length -= bytesLeft;
344 : :
345 : 0 : tail->next = new SSL_DataBlock(data, length, MIN_ALLOC_SIZE);
346 : 0 : tail = tail->next;
347 : : }
348 : : }
349 : :
350 : : else
351 : : {
352 : : // Last data block is full.
353 : 0 : tail->next = new SSL_DataBlock(data, length, MIN_ALLOC_SIZE);
354 : 0 : tail = tail->next;
355 : 0 : currentSize += length;
356 : : }
357 : 0 : }
358 : :
359 : : /*!
360 : : * This function is called internally by addSegment(), whenever a SSL record
361 : : * has been fully received. It creates a single data block from the list of
362 : : * SSL record fragments while freeing them.
363 : : *
364 : : * \param data pointer to the last SSL record fragment
365 : : * \param length size of the last SSL record fragment
366 : : *
367 : : * \return pointer to a data block which contains the reassembled SSL record
368 : : */
369 : :
370 : 0 : u_char* SSL_RecordBuilder::assembleBlocks(const u_char* data, int length)
371 : : {
372 : : // We don't store the last SSL record fragment in a DataBlock,
373 : : // instead we get it directly as parameter.
374 : 0 : u_char* dataptr = new u_char[currentSize + length];
375 : 0 : u_char* nextseg = dataptr;
376 : :
377 : 0 : SSL_DataBlock* idx = head;
378 : : SSL_DataBlock* rm;
379 : 0 : uint allocCounter = 0;
380 : :
381 [ # # ]: 0 : while ( idx )
382 : : {
383 : 0 : ++allocCounter;
384 : 0 : memcpy(nextseg, idx->data, idx->len);
385 : 0 : nextseg += idx->len;
386 : 0 : rm = idx;
387 : 0 : idx = idx->next;
388 [ # # ]: 0 : delete rm;
389 : : }
390 : :
391 : : // The last fragment isn't stored in a datablock.
392 : 0 : memcpy(nextseg, data, length);
393 : :
394 : : // The first and last fragments aren't counted.
395 : 0 : fragmentCounter += 2;
396 : :
397 : : // Update statistics.
398 [ # # ]: 0 : if ( allocCounter > maxAllocCount )
399 : 0 : maxAllocCount = allocCounter;
400 : :
401 [ # # ]: 0 : if ( fragmentCounter > maxFragmentCount )
402 : 0 : maxFragmentCount = fragmentCounter;
403 : :
404 : 0 : fragmentCounter = 0;
405 : 0 : currentSize = 0;
406 : 0 : head = tail = 0;
407 : :
408 : 0 : return dataptr;
409 : : }
410 : :
411 : : /*!
412 : : * This method is called internally by computeExpectedSize(), when the SSL
413 : : * record format has not been determined yet. It tries to do so by using
414 : : * heuristics, since there's no definitive way to distinguish SSLv2 vs. SSLv3
415 : : * record headers.
416 : : *
417 : : * \param data pointer to a data block containing the SSL record to analyze
418 : : * \param length length of the SSL record to analyze, has to be >= neededSize!
419 : : *
420 : : * \return
421 : : * - 2 for SSLv2 record format
422 : : * - 3 for SSLv3 record format
423 : : * - -1 if an error occurred
424 : : */
425 : :
426 : 0 : int SSL_RecordBuilder::analyzeSSLRecordFormat(const u_char* data, int length)
427 : : {
428 : : // We have to use heuristics for this one.
429 : :
430 [ # # ]: 0 : if ( length < neededSize )
431 : : {
432 : 0 : sslEndpoint->Parent()->Weird("SSLProxy: analyzeSSLRecordFormat length < neededSize");
433 : 0 : return -1;
434 : : }
435 : :
436 : 0 : bool found_ssl3x = 0;
437 : 0 : bool found_ssl2x = 0;
438 : :
439 : : // SSLv3x-check.
440 : 0 : SSL3_1_ContentType ct = SSL3_1_ContentType(uint8(*data));
441 [ # # ]: 0 : switch ( ct ) {
442 : : case SSL3_1_TYPE_CHANGE_CIPHER_SPEC:
443 : : case SSL3_1_TYPE_ALERT:
444 : : case SSL3_1_TYPE_HANDSHAKE:
445 : : case SSL3_1_TYPE_APPLICATION_DATA:
446 : : {
447 : 0 : sslEndpoint->sslVersion = ((data[1]) << 8) | data[2];
448 : 0 : uint16 v = sslEndpoint->sslVersion;
449 [ # # ][ # # ]: 0 : if ( v == uint16(SSLProxy_Analyzer::SSLv30) ||
450 : : v == uint16(SSLProxy_Analyzer::SSLv31) )
451 : 0 : found_ssl3x = true;
452 : : break;
453 : : }
454 : : }
455 : :
456 : : // SSLv2 check.
457 : : // We look for CLIENT-HELLOs, SERVER-HELLOs and ERRORs.
458 : 0 : const u_char* pContents = data;
459 : 0 : uint offset = 0;
460 : 0 : uint16 size = 0;
461 [ # # ]: 0 : if ( (data[0] & 0x80) > 0 )
462 : : { // we have a two-byte record header
463 : 0 : offset = 2;
464 : 0 : size = (((data[0] & 0x7f) << 8) | data[1]) + 2;
465 : : }
466 : : else
467 : : { // we have a three-byte record header
468 : 0 : offset = 3;
469 : 0 : size = (((data[0] & 0x3f) << 8) | data[1]) + 3;
470 : : }
471 : 0 : pContents += offset;
472 : :
473 [ # # # # ]: 0 : switch ( SSLv2_MessageTypes(pContents[0]) ) {
474 : : case SSLv2_MT_ERROR:
475 [ # # ]: 0 : if ( size == SSLv2_ERROR_RECORD_SIZE + offset)
476 : : {
477 : 0 : found_ssl2x = true;
478 : : sslEndpoint->sslVersion =
479 : 0 : uint16(SSLProxy_Analyzer::SSLv20);
480 : : }
481 : 0 : break;
482 : :
483 : : case SSLv2_MT_CLIENT_HELLO:
484 : : {
485 : : sslEndpoint->sslVersion =
486 : 0 : uint16(pContents[1] << 8) | pContents[2];
487 : 0 : uint16 v = sslEndpoint->sslVersion;
488 : :
489 [ # # ][ # # ]: 0 : if ( v == SSLProxy_Analyzer::SSLv20 ||
[ # # ]
490 : : v == SSLProxy_Analyzer::SSLv30 ||
491 : : v == SSLProxy_Analyzer::SSLv31 )
492 : 0 : found_ssl2x = true;
493 : 0 : break;
494 : : }
495 : :
496 : : case SSLv2_MT_SERVER_HELLO:
497 : : {
498 : : sslEndpoint->sslVersion =
499 : 0 : uint16(pContents[3] << 8) | pContents[4];
500 : 0 : uint16 v = sslEndpoint->sslVersion;
501 : :
502 [ # # ][ # # ]: 0 : if ( v == SSLProxy_Analyzer::SSLv20 ||
[ # # ]
503 : : v == SSLProxy_Analyzer::SSLv30 ||
504 : : v == SSLProxy_Analyzer::SSLv31 )
505 : 0 : found_ssl2x = true;
506 : : break;
507 : : }
508 : :
509 : : default:
510 : : break;
511 : : }
512 : :
513 : : // Consistency checks.
514 [ # # ][ # # ]: 0 : if ( (found_ssl3x || found_ssl2x) == false )
515 : : {
516 : 0 : sslEndpoint->Parent()->Weird("SSLProxy: Could not determine SSL version!");
517 : 0 : return -1;
518 : : }
519 : :
520 [ # # ][ # # ]: 0 : if ( (found_ssl3x && found_ssl2x) == true )
521 : : {
522 : 0 : sslEndpoint->Parent()->Weird("SSLProxy: Found ambigous SSL version!");
523 : 0 : return -1;
524 : : }
525 : :
526 [ # # ]: 0 : if ( found_ssl2x )
527 : 0 : return 2;
528 : : else
529 : 0 : return 3;
530 : : }
531 : :
532 : : /*!
533 : : * This method is called internally by addSegment() to determine the expected
534 : : * size of a SSL record.
535 : : *
536 : : * \param data pointer to the SSL record to analyze
537 : : * \param length length of the SSL record to analyze
538 : : *
539 : : * \return true if succesfull, false otherwise
540 : : */
541 : :
542 : 0 : bool SSL_RecordBuilder::computeExpectedSize(const u_char* data, int length)
543 : : {
544 [ # # ]: 0 : if ( sslEndpoint->sslRecordVersion < 0 )
545 : : {
546 : : // We don't know the ssl record format yet, so we try
547 : : // to find out.
548 : : sslEndpoint->sslRecordVersion =
549 : 0 : analyzeSSLRecordFormat(data, length);
550 : :
551 [ # # # # ]: 0 : if ( sslEndpoint->sslRecordVersion != 2 &&
552 : : sslEndpoint->sslRecordVersion != 3 )
553 : : // We could not determine the ssl record version.
554 : 0 : return false;
555 : : }
556 : :
557 : : // Get the expected length of this record.
558 [ # # ]: 0 : if ( sslEndpoint->sslRecordVersion == 2 )
559 : : {
560 [ # # ]: 0 : if ( (data[0] & 0x80) > 0 )
561 : : // We have a two-byte record header.
562 : 0 : expectedSize = (((data[0] & 0x7f) << 8) | data[1]) + 2;
563 : : else
564 : : // We have a three-byte record header.
565 : 0 : expectedSize = (((data[0] & 0x3f) << 8) | data[1]) + 3;
566 : : }
567 : :
568 [ # # ]: 0 : else if ( sslEndpoint->sslRecordVersion == 3 )
569 : 0 : expectedSize = ((data[3] << 8) | data[4]) + 5;
570 : :
571 [ # # ]: 0 : if ( expectedSize < neededSize )
572 : : {
573 : : // This should never happen (otherwise: UNTESTED).
574 : 0 : sslEndpoint->Parent()->Weird( "SSLProxy: expectedSize < neededSize in RecordBuilder!" );
575 : 0 : return false;
576 : : }
577 : :
578 : 0 : return true;
579 : : }
580 : :
581 : :
582 : : // --- SSL_Connection_Proxy ---------------------------------------------------
583 : :
584 : : bool SSLProxy_Analyzer::bInited = false;
585 : :
586 : 0 : SSLProxy_Analyzer::SSLProxy_Analyzer(Connection* conn)
587 : 0 : : TCP_ApplicationAnalyzer(AnalyzerTag::SSL, conn)
588 : : {
589 : 0 : sSLv2Interpreter = new SSLv2_Interpreter(this);
590 : 0 : sSLv3xInterpreter = new SSLv3_Interpreter(this);
591 : 0 : sSLInterpreter = 0;
592 : 0 : bPassThrough = false;
593 [ # # # # ]: 0 : if ( ! bInited )
594 : : {
595 : 0 : BuildCipherDict();
596 : 0 : bInited = true;
597 : : }
598 : :
599 : 0 : AddSupportAnalyzer(sslpeo = new Contents_SSL(conn, true));
600 : 0 : AddSupportAnalyzer(sslper = new Contents_SSL(conn, false));
601 : 0 : }
602 : :
603 : 0 : SSLProxy_Analyzer::~SSLProxy_Analyzer()
604 : : {
605 [ # # ][ # # ]: 0 : delete sSLv2Interpreter;
[ # # ]
606 [ # # ][ # # ]: 0 : delete sSLv3xInterpreter;
[ # # ]
607 [ # # ][ # # ]: 0 : }
[ # # ]
608 : :
609 : 0 : void SSLProxy_Analyzer::Init()
610 : : {
611 : 0 : TCP_ApplicationAnalyzer::Init();
612 : :
613 : 0 : sSLv2Interpreter->Init();
614 : 0 : sSLv3xInterpreter->Init();
615 : :
616 : : sSLv2Interpreter->Orig()
617 : 0 : ->SetProxyEndpoint(sSLv3xInterpreter->Orig()->GetProxyEndpoint());
618 : : sSLv2Interpreter->Resp()
619 : 0 : ->SetProxyEndpoint(sSLv3xInterpreter->Resp()->GetProxyEndpoint());
620 : 0 : }
621 : :
622 : 0 : void SSLProxy_Analyzer::BuildCipherDict()
623 : : {
624 [ # # ]: 0 : for ( uint idx = 0; idx < SSL_CipherSpecs_Count; ++idx )
625 : : {
626 : 0 : HashKey h(static_cast<bro_uint_t>(SSL_CipherSpecs[idx].identifier));
627 : 0 : SSL_CipherSpecDict.Insert(&h, &SSL_CipherSpecs[idx]);
628 : : }
629 : 0 : }
630 : :
631 : : void SSLProxy_Analyzer::NewSSLRecord(Contents_SSL* endp,
632 : 0 : int len, const u_char* data)
633 : : {
634 : : // This is to extract only SSLv2 traffic.
635 : : if ( recordSSLv2Traffic )
636 : : {
637 : : uint16 sslVersion = 0;
638 : : if ( (data[0] & 0x80) > 0 )
639 : : // We have a two-byte record header.
640 : : sslVersion = (data[3] << 8) | data[4];
641 : : else
642 : : // We have a three-byte record header.
643 : : sslVersion = (data[4] << 8) | data[5];
644 : :
645 : : if ( ! endp->IsSSLv2Record() ||
646 : : sslVersion != SSLProxy_Analyzer::SSLv20 )
647 : : {
648 : : SetSkip(1);
649 : : Conn()->SetRecordPackets(0);
650 : : Conn()->SetRecordContents(0);
651 : : // FIXME: Could do memory cleanup here.
652 : : }
653 : : else
654 : : // No analysis - only recording.
655 : : SetSkip(1);
656 : :
657 : : return;
658 : : }
659 : :
660 [ # # ]: 0 : if ( bPassThrough )
661 : : {
662 : 0 : DoDeliver(len, data, endp->IsOrig());
663 : 0 : return;
664 : : }
665 : :
666 [ # # ]: 0 : if ( ! endp->IsSSLv2Record() )
667 : : {
668 : : // It's TLS or SSLv3, so we are done ...
669 : 0 : sSLInterpreter = sSLv3xInterpreter;
670 : 0 : bPassThrough = true;
671 : : // Tell the other record builder we have SSLv3x.
672 : 0 : endp->sslRecordVersion = 3;
673 : 0 : DoDeliver(len, data, endp->IsOrig());
674 : : }
675 : :
676 : : else
677 : : { // we have a SSLv2 record ...
678 : 0 : sSLInterpreter = sSLv2Interpreter;
679 : :
680 : : // Check whether it's the first or second we've seen ...
681 [ # # ][ # # ]: 0 : if ( sslpeo->VersionRecognized() &&
[ # # ]
682 : : sslper->VersionRecognized() )
683 : : {
684 : : // Second record we've seen.
685 : : // O.K. Both endpoints recognized the version.
686 : : // So this needs to be an SSLv2-Connection ...
687 : 0 : bPassThrough = true;
688 : 0 : DoDeliver(len, data, endp->IsOrig());
689 : : }
690 : :
691 : : // First record we see.
692 : : // The next one may be SSLv2 or SSLv3x,
693 : : // we don't know yet ...
694 [ # # ]: 0 : else if ( endp->sslVersion == SSLv20 )
695 : : {
696 : : // The client supports only SSLv2, so we're done.
697 : 0 : bPassThrough = true;
698 : 0 : endp->sslRecordVersion = 2;
699 : 0 : endp->sslVersion = SSLv20;
700 : 0 : DoDeliver(len, data, endp->IsOrig());
701 : : }
702 : :
703 : : else
704 : : {
705 : 0 : bPassThrough = false;
706 : 0 : DoDeliver(len, data, endp->IsOrig());
707 : :
708 : : // Transfer the state of the SSLv2-Interpreter
709 : : // to the state of the SSLv3x-Interpreter ...
710 [ # # ]: 0 : if ( ((SSLv2_Interpreter*) sSLInterpreter)->ConnState() == CLIENT_HELLO_SEEN )
711 : 0 : ((SSLv3_Interpreter*) sSLv3xInterpreter)->SetState(SSL3_1_STATE_CLIENT_HELLO_SENT);
712 : : }
713 : : }
714 : : }
715 : :
716 : 0 : void SSLProxy_Analyzer::DoDeliver(int len, const u_char* data, bool orig)
717 : : {
718 [ # # ]: 0 : if ( orig )
719 : 0 : sSLInterpreter->Orig()->Deliver(len, data);
720 : : else
721 : 0 : sSLInterpreter->Resp()->Deliver(len, data);
722 : 0 : }
723 : :
724 : 0 : void SSLProxy_Analyzer::printStats()
725 : : {
726 : 0 : printf("SSLProxy_Analyzer::totalPackets = %u\n", totalPackets);
727 : 0 : printf("SSLProxy_Analyzer::totalRecords = %u\n", totalRecords);
728 : 0 : printf("SSLProxy_Analyzer::nonSSLConnections = %u\n", nonSSLConnections);
729 : 0 : }
730 : :
731 : :
732 : 0 : void SSLProxy_Analyzer::Weak(const char* name)
733 : : {
734 [ # # ]: 0 : if ( ssl_conn_weak )
735 : 0 : Event(ssl_conn_weak, name);
736 : 0 : }
737 : :
738 : : // --- Contents_SSL ------------------------------------------------------
739 : :
740 : : /*!
741 : : * mod Contents_SSL::Contents_SSL( TCP_Endpoint* arg_endpt, int stop_on_gap )
742 : : * : TCP_Contents( arg_conn, stop_on_gap, punt_on_partial )
743 : : */
744 : :
745 : 0 : Contents_SSL::Contents_SSL(Connection* conn, bool orig)
746 : 0 : : TCP_SupportAnalyzer(AnalyzerTag::Contents_SSL, conn, orig)
747 : : {
748 : 0 : sslRecordBuilder = new SSL_RecordBuilder(this);
749 : 0 : bVersionRecognized = false;
750 : 0 : bIsSSLv2Record = false;
751 : :
752 : 0 : sslRecordVersion = -1; // -1 means we don't know yet
753 : 0 : sslVersion = 0; // 0 means we don't know yet
754 : 0 : }
755 : :
756 : 0 : Contents_SSL::~Contents_SSL()
757 : : {
758 [ # # ][ # # ]: 0 : delete sslRecordBuilder;
[ # # ]
759 [ # # ][ # # ]: 0 : }
[ # # ]
760 : :
761 : 0 : bool Contents_SSL::isDataPending()
762 : : {
763 : 0 : return sslRecordBuilder->isDataPending();
764 : : }
765 : :
766 : 0 : void Contents_SSL::DeliverStream(int len, const u_char* data, bool orig)
767 : : {
768 : 0 : TCP_SupportAnalyzer::DeliverStream(len, data, orig);
769 : :
770 : 0 : TCP_Analyzer* tcp = static_cast<TCP_ApplicationAnalyzer *>(Parent())->TCP();
771 [ # # ]: 0 : assert(tcp);
772 : :
773 [ # # ][ # # ]: 0 : if ( tcp->HadGap(orig) || tcp->IsPartial() )
[ # # ]
774 : 0 : return;
775 : :
776 : 0 : ++SSLProxy_Analyzer::totalPackets;
777 : :
778 [ # # ]: 0 : TCP_Endpoint* endp = orig ? tcp->Orig() : tcp->Resp();
779 : :
780 : : #if 0
781 : : // FIXME: What's this???
782 : : int ack = endp->AckSeq() - endp->StartSeq();
783 : : int top_seq = seq + len;
784 : :
785 : : if ( top_seq <= ack )
786 : : // There is no new data in this packet.
787 : : return;
788 : : #endif
789 : :
790 [ # # ]: 0 : if ( len <= 0 )
791 : 0 : return;
792 : :
793 : : // No further processing if we have a partial connection.
794 [ # # ][ # # ]: 0 : if ( endp->state == TCP_ENDPOINT_PARTIAL ||
795 : : endp->peer->state == TCP_ENDPOINT_PARTIAL )
796 : : {
797 : 0 : Parent()->SetSkip(1);
798 : 0 : Conn()->SetRecordPackets(0);
799 : 0 : return;
800 : : }
801 : :
802 [ # # ]: 0 : if ( ! sslRecordBuilder->addSegment(data, len) )
803 : : {
804 : : // The RecordBuilder failed to determine the SSL record version,
805 : : // so we can't analyze this connection any further.
806 : 0 : ++SSLProxy_Analyzer::nonSSLConnections;
807 : 0 : Parent()->Weird("SSL: Skipping connection (not an SSL connection?!)!");
808 : 0 : Parent()->SetSkip(1);
809 : 0 : Conn()->SetRecordPackets(0);
810 : : }
811 : : }
812 : :
813 : : // Called by the RecordBuilder with a complete SSL record.
814 : 0 : void Contents_SSL::DoDeliver(int len, const u_char* data)
815 : : {
816 : 0 : ++SSLProxy_Analyzer::totalRecords;
817 : :
818 : 0 : bIsSSLv2Record = sslRecordVersion == 2;
819 : 0 : bVersionRecognized = true;
820 : :
821 : 0 : ((SSLProxy_Analyzer*) Parent())->NewSSLRecord(this, len, data);
822 : 0 : }
823 : :
824 : 0 : bool Contents_SSL::IsSSLv2Record()
825 : : {
826 : 0 : return bIsSSLv2Record;
827 : : }
828 : :
829 : 0 : bool Contents_SSL::VersionRecognized()
830 : : {
831 : 0 : return bVersionRecognized;
832 [ + - ][ + - ]: 6 : }
|