Branch data Line data Source code
1 : : // $Id: SSLv2.cc 5988 2008-07-19 07:02:12Z vern $
2 : :
3 : : #include "SSLv2.h"
4 : : #include "SSLv3.h"
5 : :
6 : : // --- Initalization of static variables --------------------------------------
7 : :
8 : : uint SSLv2_Interpreter::totalConnections = 0;
9 : : uint SSLv2_Interpreter::analyzedConnections = 0;
10 : : uint SSLv2_Interpreter::openedConnections = 0;
11 : : uint SSLv2_Interpreter::failedConnections = 0;
12 : : uint SSLv2_Interpreter::weirdConnections = 0;
13 : : uint SSLv2_Interpreter::totalRecords = 0;
14 : : uint SSLv2_Interpreter::clientHelloRecords = 0;
15 : : uint SSLv2_Interpreter::serverHelloRecords = 0;
16 : : uint SSLv2_Interpreter::clientMasterKeyRecords = 0;
17 : : uint SSLv2_Interpreter::errorRecords = 0;
18 : :
19 : :
20 : : // --- SSLv2_Interpreter -------------------------------------------------------
21 : :
22 : : /*!
23 : : * The Constructor.
24 : : *
25 : : * \param proxy Pointer to the SSLProxy_Analyzer who created this instance.
26 : : */
27 : 0 : SSLv2_Interpreter::SSLv2_Interpreter(SSLProxy_Analyzer* proxy)
28 : 0 : : SSL_Interpreter(proxy)
29 : : {
30 : 0 : ++totalConnections;
31 : 0 : records = 0;
32 : 0 : bAnalyzedCounted = false;
33 : 0 : connState = START;
34 : :
35 : 0 : pServerCipherSpecs = 0;
36 : 0 : pClientCipherSpecs = 0;
37 : 0 : bClientWantsCachedSession = false;
38 : 0 : usedCipherSpec = (SSLv2_CipherSpec) 0;
39 : :
40 : 0 : pConnectionId = 0;
41 : 0 : pChallenge = 0;
42 : 0 : pSessionId = 0;
43 : 0 : pMasterClearKey = 0;
44 : 0 : pMasterEncryptedKey = 0;
45 : 0 : pClientReadKey = 0;
46 : 0 : pServerReadKey = 0;
47 : 0 : }
48 : :
49 : : /*!
50 : : * The Destructor.
51 : : */
52 : 0 : SSLv2_Interpreter::~SSLv2_Interpreter()
53 : : {
54 [ # # ][ # # ]: 0 : if ( connState != CLIENT_MASTERKEY_SEEN &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
55 : : connState != CACHED_SESSION &&
56 : : connState != START && // we only complain if we saw some data
57 : : connState != ERROR_SEEN )
58 : 0 : ++failedConnections;
59 : :
60 [ # # ][ # # ]: 0 : if ( connState != CLIENT_MASTERKEY_SEEN && connState != CACHED_SESSION )
[ # # ][ # # ]
[ # # ][ # # ]
61 : 0 : ++weirdConnections;
62 : :
63 [ # # ][ # # ]: 0 : delete pServerCipherSpecs;
[ # # ]
64 [ # # ][ # # ]: 0 : delete pClientCipherSpecs;
[ # # ]
65 [ # # ][ # # ]: 0 : delete pConnectionId;
[ # # ]
66 [ # # ][ # # ]: 0 : delete pChallenge;
[ # # ]
67 [ # # ][ # # ]: 0 : delete pSessionId;
[ # # ]
68 [ # # ][ # # ]: 0 : delete pMasterClearKey;
[ # # ]
69 [ # # ][ # # ]: 0 : delete pMasterEncryptedKey;
[ # # ]
70 [ # # ][ # # ]: 0 : delete pClientReadKey;
[ # # ]
71 [ # # ][ # # ]: 0 : delete pServerReadKey;
[ # # ]
72 [ # # ][ # # ]: 0 : }
[ # # ]
73 : :
74 : : /*!
75 : : * This method implements SSL_Interpreter::BuildInterpreterEndpoints()
76 : : */
77 : 0 : void SSLv2_Interpreter::BuildInterpreterEndpoints()
78 : : {
79 : 0 : orig = new SSLv2_Endpoint(this, 1);
80 : 0 : resp = new SSLv2_Endpoint(this, 0);
81 : 0 : }
82 : :
83 : : /*!
84 : : * This method prints some counters.
85 : : */
86 : 0 : void SSLv2_Interpreter::printStats()
87 : : {
88 : 0 : printf("SSLv2:\n");
89 : 0 : printf("totalConnections = %u\n", totalConnections);
90 : 0 : printf("analyzedConnections = %u\n", analyzedConnections);
91 : 0 : printf("openedConnections = %u\n", openedConnections);
92 : 0 : printf("failedConnections = %u\n", failedConnections);
93 : 0 : printf("weirdConnections = %u\n", weirdConnections);
94 : :
95 : 0 : printf("totalRecords = %u\n", totalRecords);
96 : 0 : printf("clientHelloRecords = %u\n", clientHelloRecords);
97 : 0 : printf("serverHelloRecords = %u\n", serverHelloRecords);
98 : 0 : printf("clientMasterKeyRecords = %u\n", clientMasterKeyRecords);
99 : 0 : printf("errorRecords = %u\n", errorRecords);
100 : :
101 : 0 : printf("SSL_RecordBuilder::maxAllocCount = %u\n", SSL_RecordBuilder::maxAllocCount);
102 : 0 : printf("SSL_RecordBuilder::maxFragmentCount = %u\n", SSL_RecordBuilder::maxFragmentCount);
103 : 0 : printf("SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders);
104 : 0 : }
105 : :
106 : : /*!
107 : : * \return the current state of the ssl connection
108 : : */
109 : 0 : SSLv2_States SSLv2_Interpreter::ConnState()
110 : : {
111 : 0 : return connState;
112 : : }
113 : :
114 : : /*!
115 : : * This method is called by SSLv2_Endpoint::Deliver(). It is the main entry
116 : : * point of this class. The header of the given SSLV2 record is analyzed and
117 : : * its contents are then passed to the corresponding analyzer method. After
118 : : * the record has been analyzed, the ssl connection state is updated.
119 : : *
120 : : * \param s Pointer to the endpoint which sent the record
121 : : * \param length length of SSLv2 record
122 : : * \param data pointer to SSLv2 record to analyze
123 : : */
124 : : void SSLv2_Interpreter::NewSSLRecord(SSL_InterpreterEndpoint* s,
125 : 0 : int length, const u_char* data)
126 : : {
127 : 0 : ++records;
128 : 0 : ++totalRecords;
129 : :
130 [ # # ]: 0 : if ( ! bAnalyzedCounted )
131 : : {
132 : 0 : ++analyzedConnections;
133 : 0 : bAnalyzedCounted = true;
134 : : }
135 : :
136 : : // We should see a maximum of 4 cleartext records.
137 [ # # ]: 0 : if ( records == 5 )
138 : : { // so this should never happen
139 : 0 : Weird("SSLv2: Saw more than 4 records, skipping connection...");
140 : 0 : proxy->SetSkip(1);
141 : 0 : return;
142 : : }
143 : :
144 : : // SSLv2 record header analysis
145 : 0 : uint32 recordLength = 0; // data length of SSLv2 record
146 : 0 : bool isEscape = false;
147 : 0 : uint8 padding = 0;
148 : : const u_char* contents;
149 : :
150 [ # # ]: 0 : if ( (data[0] & 0x80) > 0 )
151 : : { // we have a two-byte record header
152 : 0 : recordLength = ((data[0] & 0x7f) << 8) | data[1];
153 : 0 : contents = data + 2;
154 [ # # ]: 0 : if ( recordLength + 2 != uint32(length) )
155 : : {
156 : : // This should never happen, otherwise
157 : : // we have a bug in the SSL_RecordBuilder.
158 : 0 : Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
159 : 0 : connState = ERROR_REQUIRED;
160 : 0 : proxy->SetSkip(1);
161 : 0 : return;
162 : : }
163 : : }
164 : : else
165 : : { // We have a three-byte record header.
166 : 0 : recordLength = ((data[0] & 0x3f) << 8) | data[1];
167 : 0 : isEscape = (data[0] & 0x40) != 0;
168 : 0 : padding = data[2];
169 : 0 : contents = data + 3;
170 [ # # ]: 0 : if ( recordLength + 3 != uint32(length) )
171 : : {
172 : : // This should never happen, otherwise
173 : : // we have a bug in the SSL_RecordBuilder.
174 : 0 : Weird("SSLv2: FATAL: recordLength doesn't match data block length!");
175 : 0 : connState = ERROR_REQUIRED;
176 : 0 : proxy->SetSkip(1);
177 : 0 : return;
178 : : }
179 : :
180 [ # # ][ # # ]: 0 : if ( padding == 0 && ! isEscape )
181 : 0 : Weird("SSLv2: 3 Byte record header, but no escape, no padding!");
182 : : }
183 : :
184 [ # # ]: 0 : if ( recordLength == 0 )
185 : : {
186 : 0 : Weird("SSLv2: Record length is zero (no record data)!");
187 : 0 : return;
188 : : }
189 : :
190 [ # # ]: 0 : if ( isEscape )
191 : 0 : Weird("SSLv2: Record has escape bit set (security escape)!");
192 : :
193 [ # # ][ # # ]: 0 : if ( padding > 0 && connState != CACHED_SESSION &&
[ # # ]
194 : : connState != CLIENT_MASTERKEY_SEEN )
195 : 0 : Weird("SSLv2 record with padding > 0 in cleartext!");
196 : :
197 : : // MISSING:
198 : : // A final consistency check is done when a block cipher is used
199 : : // and the protocol is using encryption. The amount of data present
200 : : // in a record (RECORD-LENGTH))must be a multiple of the cipher's
201 : : // block size. If the received record is not a multiple of the
202 : : // cipher's block size then the record is considered damaged, and it
203 : : // is to be treated as if an "I/O Error" had occurred (i.e. an
204 : : // unrecoverable error is asserted and the connection is closed).
205 : :
206 [ # # # # # : 0 : switch ( connState ) {
# # # ]
207 : : case START:
208 : : // Only CLIENT-HELLLOs allowed here.
209 [ # # ]: 0 : if ( contents[0] != SSLv2_MT_CLIENT_HELLO )
210 : : {
211 : 0 : Weird("SSLv2: First packet is not a CLIENT-HELLO!");
212 : 0 : analyzeRecord(s, recordLength, contents);
213 : 0 : connState = ERROR_REQUIRED;
214 : : }
215 : : else
216 : 0 : connState = ClientHelloRecord(s, recordLength, contents);
217 : 0 : break;
218 : :
219 : : case CLIENT_HELLO_SEEN:
220 : : // Only SERVER-HELLOs or ERRORs allowed here.
221 [ # # ]: 0 : if ( contents[0] == SSLv2_MT_SERVER_HELLO )
222 : 0 : connState = ServerHelloRecord(s, recordLength, contents);
223 [ # # ]: 0 : else if ( contents[0] == SSLv2_MT_ERROR )
224 : 0 : connState = ErrorRecord(s, recordLength, contents);
225 : : else
226 : : {
227 : 0 : Weird("SSLv2: State violation in CLIENT_HELLO_SEEN!");
228 : 0 : analyzeRecord(s, recordLength, contents);
229 : 0 : connState = ERROR_REQUIRED;
230 : : }
231 : 0 : break;
232 : :
233 : : case NEW_SESSION:
234 : : // We expect a client master key.
235 [ # # ]: 0 : if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY )
236 : 0 : connState = ClientMasterKeyRecord(s, recordLength, contents);
237 [ # # ]: 0 : else if ( contents[0] == SSLv2_MT_ERROR )
238 : 0 : connState = ErrorRecord(s, recordLength, contents);
239 : : else
240 : : {
241 : 0 : Weird("SSLv2: State violation in NEW_SESSION or encrypted record!");
242 : 0 : analyzeRecord(s, recordLength, contents);
243 : 0 : connState = ERROR_REQUIRED;
244 : : }
245 : :
246 [ # # ]: 0 : delete pServerCipherSpecs;
247 : 0 : pServerCipherSpecs = 0;
248 : 0 : break;
249 : :
250 : : case CACHED_SESSION:
251 [ # # ]: 0 : delete pServerCipherSpecs;
252 : 0 : pServerCipherSpecs = 0;
253 : : // No break here.
254 : :
255 : : case CLIENT_MASTERKEY_SEEN:
256 : : // If no error record, no further analysis.
257 [ # # ][ # # ]: 0 : if ( contents[0] == SSLv2_MT_ERROR &&
258 : : recordLength == SSLv2_ERROR_RECORD_SIZE )
259 : 0 : connState = ErrorRecord(s, recordLength, contents);
260 : : else
261 : : {
262 : : // So we finished the cleartext handshake.
263 : : // Skip all further data.
264 : :
265 : 0 : proxy->SetSkip(1);
266 : 0 : ++openedConnections;
267 : : }
268 : 0 : break;
269 : :
270 : : case ERROR_REQUIRED:
271 [ # # ]: 0 : if ( contents[0] == SSLv2_MT_ERROR )
272 : 0 : connState = ErrorRecord(s, recordLength, contents);
273 : : else
274 : : {
275 : : // We lost tracking: this should not happen.
276 : 0 : Weird("SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!");
277 : 0 : analyzeRecord(s, recordLength, contents);
278 : 0 : connState = ERROR_REQUIRED;
279 : : }
280 : 0 : break;
281 : :
282 : : case ERROR_SEEN:
283 : : // We don't have recoverable errors in cleartext phase,
284 : : // so we shouldn't see anymore packets.
285 : 0 : Weird("SSLv2: Traffic after error record!");
286 : 0 : analyzeRecord(s, recordLength, contents);
287 : 0 : break;
288 : :
289 : : default:
290 : 0 : internal_error("SSLv2: unknown state");
291 : : break;
292 : : }
293 : : }
294 : :
295 : : /*!
296 : : * This method is called whenever the connection tracking failed. It calls
297 : : * the corresponding analyzer method for the given SSLv2 record, but does not
298 : : * update the ssl connection state.
299 : : *
300 : : * \param s Pointer to the endpoint which sent the record
301 : : * \param length length of SSLv2 record
302 : : * \param data pointer to SSLv2 record to analyze
303 : : */
304 : : void SSLv2_Interpreter::analyzeRecord(SSL_InterpreterEndpoint* s,
305 : 0 : int length, const u_char* data)
306 : : {
307 [ # # # # # : 0 : switch ( data[0] ) {
# ]
308 : : case SSLv2_MT_ERROR:
309 : 0 : ErrorRecord(s, length, data);
310 : 0 : break;
311 : :
312 : : case SSLv2_MT_CLIENT_HELLO:
313 : 0 : ClientHelloRecord(s, length, data);
314 : 0 : break;
315 : :
316 : : case SSLv2_MT_CLIENT_MASTER_KEY:
317 : 0 : ClientMasterKeyRecord(s, length, data);
318 : 0 : break;
319 : :
320 : : case SSLv2_MT_SERVER_HELLO:
321 : 0 : ServerHelloRecord(s, length, data);
322 : 0 : break;
323 : :
324 : : case SSLv2_MT_CLIENT_FINISHED:
325 : : case SSLv2_MT_SERVER_VERIFY:
326 : : case SSLv2_MT_SERVER_FINISHED:
327 : : case SSLv2_MT_REQUEST_CERTIFICATE:
328 : : case SSLv2_MT_CLIENT_CERTIFICATE:
329 : 0 : Weird("SSLv2: Encrypted record type seems to be in cleartext");
330 : 0 : break;
331 : :
332 : : default:
333 : : // Unknown record type.
334 : 0 : Weird("SSLv2: Unknown record type or encrypted record");
335 : : break;
336 : : }
337 : 0 : }
338 : :
339 : : /*!
340 : : * This method analyses a SSLv2 CLIENT-HELLO record.
341 : : *
342 : : * \param s Pointer to the endpoint which sent the record
343 : : * \param length length of SSLv2 CLIENT-HELLO record
344 : : * \param data pointer to SSLv2 CLIENT-HELLO record to analyze
345 : : *
346 : : * \return the updated state of the current ssl connection
347 : : */
348 : : SSLv2_States SSLv2_Interpreter::ClientHelloRecord(SSL_InterpreterEndpoint* s,
349 : 0 : int recordLength, const u_char* recordData)
350 : : {
351 : : // This method gets the record's data (without the header).
352 : 0 : ++clientHelloRecords;
353 : :
354 [ # # ]: 0 : if ( s != orig )
355 : 0 : Weird("SSLv2: CLIENT-HELLO record from server!");
356 : :
357 : : // There should not be any pending data in the SSLv2 reassembler,
358 : : // because the client should wait for a server response.
359 [ # # ]: 0 : if ( ((SSLv2_Endpoint*) s)->isDataPending() )
360 : 0 : Weird("SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!");
361 : :
362 : : // Client hello minimum header size check.
363 [ # # ]: 0 : if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE )
364 : : {
365 : 0 : Weird("SSLv2: CLIENT-HELLO is too small!");
366 : 0 : return ERROR_REQUIRED;
367 : : }
368 : :
369 : : // Extract the data of the client hello header.
370 : : SSLv2_ClientHelloHeader ch;
371 : 0 : ch.clientVersion = uint16(recordData[1] << 8) | recordData[2];
372 : 0 : ch.cipherSpecLength = uint16(recordData[3] << 8) | recordData[4];
373 : 0 : ch.sessionIdLength = uint16(recordData[5] << 8) | recordData[6];
374 : 0 : ch.challengeLength = uint16(recordData[7] << 8) | recordData[8];
375 : :
376 [ # # ][ # # ]: 0 : if ( ch.clientVersion != SSLProxy_Analyzer::SSLv20 &&
[ # # ]
377 : : ch.clientVersion != SSLProxy_Analyzer::SSLv30 &&
378 : : ch.clientVersion != SSLProxy_Analyzer::SSLv31 )
379 : : {
380 : 0 : Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO");
381 : 0 : return ERROR_REQUIRED;
382 : : }
383 : :
384 [ # # ]: 0 : if ( ch.challengeLength + ch.cipherSpecLength + ch.sessionIdLength +
385 : : SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength )
386 : : {
387 : 0 : Weird("SSLv2: Size inconsistency in CLIENT-HELLO");
388 : 0 : return ERROR_REQUIRED;
389 : : }
390 : :
391 : : // The CIPHER-SPECS-LENGTH must be > 0 and a multiple of 3.
392 [ # # ][ # # ]: 0 : if ( ch.cipherSpecLength == 0 || ch.cipherSpecLength % 3 != 0 )
393 : : {
394 : 0 : Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO.");
395 : 0 : return ERROR_REQUIRED;
396 : : }
397 : :
398 : : // The SESSION-ID-LENGTH must either be zero or 16.
399 [ # # ][ # # ]: 0 : if ( ch.sessionIdLength != 0 && ch.sessionIdLength != 16 )
400 : 0 : Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO.");
401 : :
402 [ # # ][ # # ]: 0 : if ( (ch.challengeLength < 16) || (ch.challengeLength > 32))
403 : 0 : Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO.");
404 : :
405 : 0 : const u_char* ptr = recordData;
406 : 0 : ptr += SSLv2_CLIENT_HELLO_HEADER_SIZE + ch.cipherSpecLength;
407 : :
408 : 0 : pSessionId = new SSL_DataBlock(ptr, ch.sessionIdLength);
409 : :
410 : : // If decrypting, store the challenge.
411 [ # # # # ]: 0 : if ( ssl_store_key_material && ch.challengeLength <= 32 )
412 : 0 : pChallenge = new SSL_DataBlock(ptr, ch.challengeLength);
413 : :
414 : 0 : bClientWantsCachedSession = ch.sessionIdLength != 0;
415 : :
416 : : TableVal* currentCipherSuites =
417 : : analyzeCiphers(s, ch.cipherSpecLength,
418 : 0 : recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE);
419 : :
420 : 0 : fire_ssl_conn_attempt(ch.clientVersion, currentCipherSuites);
421 : :
422 : 0 : return CLIENT_HELLO_SEEN;
423 : : }
424 : :
425 : : /*!
426 : : * This method analyses a SSLv2 SERVER-HELLO record.
427 : : *
428 : : * \param s Pointer to the endpoint which sent the record
429 : : * \param length length of SSLv2 SERVER-HELLO record
430 : : * \param data pointer to SSLv2 SERVER-HELLO record to analyze
431 : : *
432 : : * \return the updated state of the current ssl connection
433 : : */
434 : : SSLv2_States SSLv2_Interpreter::ServerHelloRecord(SSL_InterpreterEndpoint* s,
435 : 0 : int recordLength, const u_char* recordData)
436 : : {
437 : 0 : ++serverHelloRecords;
438 : 0 : TableVal* currentCipherSuites = NULL;
439 : :
440 [ # # ]: 0 : if ( s != resp )
441 : 0 : Weird("SSLv2: SERVER-HELLO from client!");
442 : :
443 [ # # ]: 0 : if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE )
444 : : {
445 : 0 : Weird("SSLv2: SERVER-HELLO is too small!");
446 : 0 : return ERROR_REQUIRED;
447 : : }
448 : :
449 : : // Extract the data of the client hello header.
450 : : SSLv2_ServerHelloHeader sh;
451 : 0 : sh.sessionIdHit = recordData[1];
452 : 0 : sh.certificateType = recordData[2];
453 : 0 : sh.serverVersion = uint16(recordData[3] << 8) | recordData[4];
454 : 0 : sh.certificateLength = uint16(recordData[5] << 8) | recordData[6];
455 : 0 : sh.cipherSpecLength = uint16(recordData[7] << 8) | recordData[8];
456 : 0 : sh.connectionIdLength = uint16(recordData[9] << 8) | recordData[10];
457 : :
458 [ # # ]: 0 : if ( sh.serverVersion != SSLProxy_Analyzer::SSLv20 )
459 : : {
460 : 0 : Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO");
461 : 0 : return ERROR_REQUIRED;
462 : : }
463 : :
464 [ # # ]: 0 : if ( sh.certificateLength + sh.cipherSpecLength +
465 : : sh.connectionIdLength +
466 : : SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength )
467 : : {
468 : 0 : Weird("SSLv2: Size inconsistency in SERVER-HELLO");
469 : 0 : return ERROR_REQUIRED;
470 : : }
471 : :
472 : : // The length of the CONNECTION-ID must be between 16 and 32 bytes.
473 [ # # ][ # # ]: 0 : if ( sh.connectionIdLength < 16 || sh.connectionIdLength > 32 )
474 : 0 : Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO");
475 : :
476 : : // If decrypting, store the connection ID.
477 [ # # ][ # # ]: 0 : if ( ssl_store_key_material && sh.connectionIdLength <= 32 )
478 : : {
479 : 0 : const u_char* ptr = recordData;
480 : :
481 : : ptr += SSLv2_SERVER_HELLO_HEADER_SIZE + sh.cipherSpecLength +
482 : 0 : sh.certificateLength;
483 : :
484 : 0 : pConnectionId = new SSL_DataBlock(ptr, sh.connectionIdLength);
485 : : }
486 : :
487 [ # # ]: 0 : if ( sh.sessionIdHit == 0 )
488 : : {
489 : : // Generating reusing-connection event.
490 : 0 : EventHandlerPtr event = ssl_session_insertion;
491 : :
492 [ # # ]: 0 : if ( event )
493 : : {
494 : : TableVal* sessionIDTable =
495 : : MakeSessionID(
496 : : recordData +
497 : : SSLv2_SERVER_HELLO_HEADER_SIZE +
498 : : sh.certificateLength +
499 : : sh.cipherSpecLength,
500 : 0 : sh.connectionIdLength);
501 : :
502 : 0 : val_list* vl = new val_list;
503 : 0 : vl->append(proxy->BuildConnVal());
504 : 0 : vl->append(sessionIDTable);
505 : :
506 : 0 : proxy->ConnectionEvent(ssl_session_insertion, vl);
507 : : }
508 : : }
509 : :
510 : : SSLv2_States nextState;
511 : :
512 [ # # ]: 0 : if ( sh.sessionIdHit != 0 )
513 : : { // we're using a cached session
514 : :
515 : : // There should not be any pending data in the SSLv2
516 : : // reassembler, because the server should wait for a
517 : : // client response.
518 : 0 : if ( ((SSLv2_Endpoint*) s)->isDataPending() )
519 : : {
520 : : // But turns out some SSL Implementations do this
521 : : // when using a cached session.
522 : : }
523 : :
524 : : // Consistency check for SESSION-ID-HIT.
525 [ # # ]: 0 : if ( ! bClientWantsCachedSession )
526 : 0 : Weird("SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!");
527 : :
528 : : // If the SESSION-ID-HIT flag is non-zero then the
529 : : // CERTIFICATE-TYPE, CERTIFICATE-LENGTH and
530 : : // CIPHER-SPECS-LENGTH fields will be zero.
531 [ # # ][ # # ]: 0 : if ( sh.certificateType != 0 || sh.certificateLength != 0 ||
[ # # ]
532 : : sh.cipherSpecLength != 0 )
533 : 0 : Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO");
534 : :
535 : : // Generate reusing-connection event.
536 [ # # ]: 0 : if ( pSessionId )
537 : : {
538 : 0 : fire_ssl_conn_reused(pSessionId);
539 [ # # ]: 0 : delete pSessionId;
540 : 0 : pSessionId = 0;
541 : : }
542 : :
543 : 0 : nextState = CACHED_SESSION;
544 : : }
545 : : else
546 : : { // we're starting a new session
547 : :
548 : : // There should not be any pending data in the SSLv2
549 : : // reassembler, because the server should wait for
550 : : // a client response.
551 [ # # ]: 0 : if ( ((SSLv2_Endpoint*) s)->isDataPending() )
552 : 0 : Weird("SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!");
553 : :
554 : : // TODO: check certificate length ???
555 [ # # ]: 0 : if ( sh.certificateLength == 0 )
556 : 0 : Weird("SSLv2: No certificate in SERVER-HELLO!");
557 : :
558 : : // The CIPHER-SPECS-LENGTH must be > zero and a multiple of 3.
559 [ # # ]: 0 : if ( sh.cipherSpecLength == 0 )
560 : 0 : Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!");
561 : :
562 [ # # ]: 0 : if ( sh.cipherSpecLength % 3 != 0 )
563 : : {
564 : 0 : Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO");
565 : 0 : return ERROR_REQUIRED;
566 : : }
567 : :
568 : 0 : const u_char* ptr = recordData;
569 : 0 : ptr += sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE;
570 : 0 : currentCipherSuites = analyzeCiphers(s, sh.cipherSpecLength, ptr);
571 : :
572 : 0 : nextState = NEW_SESSION;
573 : : }
574 : :
575 : : // Check if at least one cipher is supported by the client.
576 [ # # ][ # # ]: 0 : if ( pClientCipherSpecs && pServerCipherSpecs )
577 : : {
578 : 0 : bool bFound = false;
579 [ # # ]: 0 : for ( int i = 0; i < pClientCipherSpecs->len; i += 3 )
580 : : {
581 [ # # ]: 0 : for ( int j = 0; j < pServerCipherSpecs->len; j += 3 )
582 : : {
583 [ # # ]: 0 : if ( memcmp(pClientCipherSpecs + i,
584 : : pServerCipherSpecs + j, 3) == 0 )
585 : : {
586 : 0 : bFound = true;
587 : 0 : i = pClientCipherSpecs->len;
588 : 0 : break;
589 : : }
590 : : }
591 : : }
592 : :
593 [ # # ]: 0 : if ( ! bFound )
594 : : {
595 : 0 : Weird("SSLv2: Client's and server's CIPHER-SPECS don't match!");
596 : 0 : nextState = ERROR_REQUIRED;
597 : : }
598 : :
599 [ # # ]: 0 : delete pClientCipherSpecs;
600 : 0 : pClientCipherSpecs = 0;
601 : : }
602 : :
603 : : // Certificate analysis.
604 [ # # ][ # # ]: 0 : if ( sh.certificateLength > 0 && ssl_analyze_certificates != 0 )
605 : : {
606 : : analyzeCertificate(s, recordData + SSLv2_SERVER_HELLO_HEADER_SIZE,
607 : 0 : sh.certificateLength, sh.certificateType, false);
608 : : }
609 : :
610 [ # # ]: 0 : if ( nextState == NEW_SESSION )
611 : : // generate server-reply event
612 : 0 : fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
613 : :
614 [ # # ]: 0 : else if ( nextState == CACHED_SESSION )
615 : : { // generate server-reply event
616 : 0 : fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites);
617 : : // Generate a connection-established event with a dummy
618 : : // cipher suite, since we can't remember session information
619 : : // (yet).
620 : : // Note: A new session identifier is sent encrypted in SSLv2!
621 : 0 : fire_ssl_conn_established(sh.serverVersion, 0xABCD);
622 : : }
623 : : else
624 : : // Unref, since the table is not delivered to any event.
625 : 0 : Unref(currentCipherSuites);
626 : :
627 : 0 : return nextState;
628 : : }
629 : :
630 : : /*!
631 : : * This method analyses a SSLv2 CLIENT-MASTER-KEY record.
632 : : *
633 : : * \param s Pointer to the endpoint which sent the record
634 : : * \param length length of SSLv2 CLIENT-MASTER-KEY record
635 : : * \param data pointer to SSLv2 CLIENT-MASTER-KEY record to analyze
636 : : *
637 : : * \return the updated state of the current ssl connection
638 : : */
639 : : SSLv2_States SSLv2_Interpreter::
640 : : ClientMasterKeyRecord(SSL_InterpreterEndpoint* s, int recordLength,
641 : 0 : const u_char* recordData)
642 : : {
643 : 0 : ++clientMasterKeyRecords;
644 : 0 : SSLv2_States nextState = CLIENT_MASTERKEY_SEEN;
645 : :
646 [ # # ]: 0 : if ( s != orig )
647 : 0 : Weird("SSLv2: CLIENT-MASTER-KEY from server!");
648 : :
649 [ # # ]: 0 : if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE )
650 : : {
651 : 0 : Weird("SSLv2: CLIENT-MASTER-KEY is too small!");
652 : 0 : return ERROR_REQUIRED;
653 : : }
654 : :
655 : : // Extract the data of the client master key header.
656 : : SSLv2_ClientMasterKeyHeader cmk;
657 : : cmk.cipherKind =
658 : 0 : ((recordData[1] << 16) | recordData[2] << 8) | recordData[3];
659 : 0 : cmk.clearKeyLength = uint16(recordData[4] << 8) | recordData[5];
660 : 0 : cmk.encryptedKeyLength = uint16(recordData[6] << 8) | recordData[7];
661 : 0 : cmk.keyArgLength = uint16(recordData[8] << 8) | recordData[9];
662 : :
663 [ # # ]: 0 : if ( cmk.clearKeyLength + cmk.encryptedKeyLength + cmk.keyArgLength +
664 : : SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength )
665 : : {
666 : 0 : Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY");
667 : 0 : return ERROR_REQUIRED;
668 : : }
669 : :
670 : : // Check if cipher is supported by the server.
671 [ # # ]: 0 : if ( pServerCipherSpecs )
672 : : {
673 : 0 : bool bFound = false;
674 [ # # ]: 0 : for ( int i = 0; i < pServerCipherSpecs->len; i += 3 )
675 : : {
676 : : uint32 cipherSpec =
677 : : ((pServerCipherSpecs->data[i] << 16) |
678 : : pServerCipherSpecs->data[i+1] << 8) |
679 : 0 : pServerCipherSpecs->data[i+2];
680 : :
681 [ # # ]: 0 : if ( cmk.cipherKind == cipherSpec )
682 : : {
683 : 0 : bFound = true;
684 : 0 : break;
685 : : }
686 : : }
687 : :
688 [ # # ]: 0 : if ( ! bFound )
689 : : {
690 : 0 : Weird("SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!");
691 : 0 : nextState = ERROR_REQUIRED;
692 : : }
693 : : else
694 : 0 : nextState = CLIENT_MASTERKEY_SEEN;
695 : :
696 [ # # ]: 0 : delete pServerCipherSpecs;
697 : 0 : pServerCipherSpecs = 0;
698 : : }
699 : :
700 : : // TODO: check if cipher has been advertised before.
701 : :
702 : 0 : SSL_CipherSpec* pCipherSpecTemp = 0;
703 : :
704 : 0 : HashKey h(static_cast<bro_uint_t>(cmk.cipherKind));
705 : 0 : pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
706 [ # # # # ]: 0 : if ( ! pCipherSpecTemp || ! (pCipherSpecTemp->flags & SSL_FLAG_SSLv20) )
707 : 0 : Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!");
708 : : else
709 : : { // check for conistency of clearKeyLength
710 [ # # ]: 0 : if ( cmk.clearKeyLength * 8 != pCipherSpecTemp->clearKeySize )
711 : : {
712 : 0 : Weird("SSLv2: Inconsistency of clearKeyLength in CLIENT-MASTER-KEY!");
713 : : // nextState = ERROR_REQUIRED;
714 : : }
715 : :
716 : : // TODO: check for consistency of encryptedKeyLength.
717 : : // TODO: check for consistency of keyArgLength.
718 : : // switch ( cmk.cipherKind )
719 : : // {
720 : : // case SSL_CK_RC4_128_WITH_MD5:
721 : : // case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
722 : : // if ( cmk.keyArgLength != 0 )
723 : : // {
724 : : // Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
725 : : // //nextState = ERROR_REQUIRED;
726 : : // }
727 : : // break;
728 : : // case SSL_CK_DES_64_CBC_WITH_MD5:
729 : : // case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
730 : : // case SSL_CK_RC2_128_CBC_WITH_MD5:
731 : : // case SSL_CK_IDEA_128_CBC_WITH_MD5:
732 : : // case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
733 : : // if ( cmk.keyArgLength != 8 )
734 : : // {
735 : : // Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!");
736 : : // }
737 : : // break;
738 : : // }
739 : : }
740 : :
741 : : // Remember the used cipher spec.
742 : 0 : usedCipherSpec = SSLv2_CipherSpec(cmk.cipherKind);
743 : :
744 : : // If decrypting, store the clear key part of the master key.
745 [ # # ]: 0 : if ( ssl_store_key_material /* && cmk.clearKeyLength == 11 */ )
746 : : {
747 : : pMasterClearKey =
748 : 0 : new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE), cmk.clearKeyLength);
749 : :
750 : : pMasterEncryptedKey =
751 : 0 : new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE + cmk.clearKeyLength ), cmk.encryptedKeyLength);
752 : : }
753 : :
754 [ # # ]: 0 : if ( nextState == CLIENT_MASTERKEY_SEEN )
755 : : fire_ssl_conn_established(SSLProxy_Analyzer::SSLv20,
756 : 0 : cmk.cipherKind);
757 : :
758 : 0 : return nextState;
759 : : }
760 : :
761 : :
762 : : /*!
763 : : * This method analyses a SSLv2 ERROR record.
764 : : *
765 : : * \param s Pointer to the endpoint which sent the record
766 : : * \param length length of SSLv2 ERROR record
767 : : * \param data pointer to SSLv2 ERROR record to analyze
768 : : *
769 : : * \return the updated state of the current ssl connection
770 : : */
771 : : SSLv2_States SSLv2_Interpreter::ErrorRecord(SSL_InterpreterEndpoint* s,
772 : 0 : int recordLength, const u_char* recordData)
773 : : {
774 : 0 : ++errorRecords;
775 : :
776 [ # # ]: 0 : if ( unsigned(recordLength) != SSLv2_ERROR_RECORD_SIZE )
777 : : {
778 : 0 : Weird("SSLv2: Size mismatch in Error Record!");
779 : 0 : return ERROR_REQUIRED;
780 : : }
781 : :
782 : : SSLv2_ErrorRecord er;
783 : 0 : er.errorCode = (recordData[1] << 8) | recordData[2];
784 : 0 : SSL3x_AlertLevel al = SSL3x_AlertLevel(255);
785 : :
786 [ # # # # : 0 : switch ( er.errorCode ) {
# ]
787 : : case SSLv2_PE_NO_CIPHER:
788 : : // The client doesn't support a cipher which the server
789 : : // supports. Only from client to server and not recoverable!
790 : 0 : al = SSL3x_ALERT_LEVEL_FATAL;
791 : 0 : break;
792 : :
793 : : case SSLv2_PE_NO_CERTIFICATE:
794 [ # # ]: 0 : if ( s == orig )
795 : : // from client to server: not recoverable
796 : 0 : al = SSL3x_ALERT_LEVEL_FATAL;
797 : : else
798 : : // from server to client: recoverable
799 : 0 : al = SSL3x_ALERT_LEVEL_WARNING;
800 : 0 : break;
801 : :
802 : : case SSLv2_PE_BAD_CERTIFICATE:
803 [ # # ]: 0 : if ( s == orig )
804 : : // from client to server: not recoverable
805 : 0 : al = SSL3x_ALERT_LEVEL_FATAL;
806 : : else
807 : : // from server to client: recoverable
808 : 0 : al = SSL3x_ALERT_LEVEL_WARNING;
809 : 0 : break;
810 : :
811 : : case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
812 [ # # ]: 0 : if ( s == orig )
813 : : // from client to server: not recoverable
814 : 0 : al = SSL3x_ALERT_LEVEL_FATAL;
815 : : else
816 : : // from server to client: recoverable
817 : 0 : al = SSL3x_ALERT_LEVEL_WARNING;
818 : 0 : break;
819 : :
820 : : default:
821 : 0 : al = SSL3x_ALERT_LEVEL_FATAL;
822 : : break;
823 : : }
824 : :
825 : 0 : fire_ssl_conn_alert(SSLProxy_Analyzer::SSLv20, al, er.errorCode);
826 : :
827 : 0 : return ERROR_SEEN;
828 : : }
829 : :
830 : : /*!
831 : : * This method analyses a set of SSLv2 cipher suites.
832 : : *
833 : : * \param s Pointer to the endpoint which sent the cipher suites
834 : : * \param length length of cipher suites
835 : : * \param data pointer to cipher suites to analyze
836 : : *
837 : : * \return a pointer to a Bro TableVal (of type cipher_suites_list) which contains
838 : : * the cipher suites list of the current analyzed record
839 : : */
840 : : TableVal* SSLv2_Interpreter::analyzeCiphers(SSL_InterpreterEndpoint* s,
841 : 0 : int length, const u_char* data)
842 : : {
843 [ # # ]: 0 : if ( length > MAX_CIPHERSPEC_SIZE )
844 : : {
845 [ # # ]: 0 : if ( s == orig )
846 : 0 : Weird("SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE");
847 : : else
848 : 0 : Weird("SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE");
849 : : }
850 : : else
851 : : { // cipher specs are not too big
852 [ # # ]: 0 : if ( ssl_compare_cipherspecs )
853 : : { // store cipher specs for state analysis
854 [ # # ]: 0 : if ( s == resp )
855 : : pServerCipherSpecs =
856 : 0 : new SSL_DataBlock(data, length);
857 : : else
858 : : pClientCipherSpecs =
859 : 0 : new SSL_DataBlock(data, length);
860 : : }
861 : : }
862 : :
863 : 0 : const u_char* pCipher = data;
864 : 0 : bool bExtractCipherSuite = false;
865 : 0 : TableVal* pCipherTable = 0;
866 : :
867 : : // We only extract the cipher suite when the corresponding
868 : : // ssl events are defined (otherwise we do work for nothing
869 : : // and suffer a memory leak).
870 : : // FIXME: This check needs to be done only once!
871 [ # # ][ # # ]: 0 : if ( (s == orig && ssl_conn_attempt) ||
[ # # ][ # # ]
[ # # ]
872 : : (s == resp && ssl_conn_server_reply) )
873 : : {
874 : 0 : pCipherTable = new TableVal(cipher_suites_list);
875 : 0 : bExtractCipherSuite = true;
876 : : }
877 : :
878 [ # # ]: 0 : for ( int i = 0; i < length; i += 3 )
879 : : {
880 : : SSL_CipherSpec* pCurrentCipherSpec;
881 : : uint32 cipherSpecID =
882 : 0 : ((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2];
883 : :
884 : : // Check for unknown cipher specs.
885 : 0 : HashKey h(static_cast<bro_uint_t>(cipherSpecID));
886 : : pCurrentCipherSpec =
887 : 0 : (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
888 : :
889 [ # # ]: 0 : if ( ! pCurrentCipherSpec )
890 : : {
891 [ # # ]: 0 : if ( s == orig )
892 : 0 : Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!");
893 : : else
894 : 0 : Weird("SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!");
895 : : }
896 : :
897 [ # # ]: 0 : if ( bExtractCipherSuite )
898 : : {
899 : 0 : Val* index = new Val(cipherSpecID, TYPE_COUNT);
900 : 0 : pCipherTable->Assign(index, 0);
901 : 0 : Unref(index);
902 : : }
903 : :
904 : 0 : pCipher += 3;
905 : : }
906 : :
907 : 0 : return pCipherTable;
908 : : }
909 : :
910 : : // --- SSLv2_EndPoint ---------------------------------------------------------
911 : :
912 : : /*!
913 : : * The constructor.
914 : : *
915 : : * \param interpreter Pointer to the SSLv2 interpreter to whom this endpoint belongs to
916 : : * \param is_orig true if this is the originating endpoint of the ssl connection,
917 : : * false otherwise
918 : : */
919 : 0 : SSLv2_Endpoint::SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig)
920 : 0 : : SSL_InterpreterEndpoint(interpreter, is_orig)
921 : : {
922 : 0 : sentRecords = 0;
923 : 0 : }
924 : :
925 : : /*!
926 : : * The destructor.
927 : : */
928 : 0 : SSLv2_Endpoint::~SSLv2_Endpoint()
929 : : {
930 [ # # ][ # # ]: 0 : }
[ # # ]
931 : :
932 : : /*!
933 : : * This method is called by the SSLProxy_Analyzer with a complete reassembled
934 : : * SSLv2 record. It passes the record to SSLv2_Interpreter::NewSSLRecord().
935 : : *
936 : : * \param t <b>reserved</b> (always zero)
937 : : * \param seq <b>reserved</b> (always zero)
938 : : * \param len length of the data block containing the ssl record
939 : : * \param data pointer to the data block containing the ssl record
940 : : */
941 : 0 : void SSLv2_Endpoint::Deliver(int len, const u_char* data)
942 : : {
943 : 0 : ++((SSLv2_Endpoint*)peer)->sentRecords;
944 : :
945 : 0 : ((SSLv2_Interpreter*)interpreter)->NewSSLRecord(this, len, data);
946 [ + - ][ + - ]: 6 : }
|