diff -uNr bro-pub-0.8a41/Hash.cc bro-pub-0.841-ssl/Hash.cc
--- bro-pub-0.8a41/Hash.cc	Mon Sep 22 02:18:51 2003
+++ bro-pub-0.841-ssl/Hash.cc	Wed Oct 15 05:17:51 2003
@@ -131,7 +131,7 @@
 
 int hash_cnt_all = 0, hash_cnt_uhash = 0;
 
-hash_t HashKey::HashBytes(const void* bytes, int size) const
+hash_t HashKey::HashBytes(const void* bytes, int size)
 	{
 #ifdef USE_OLD_BRO_HASH
   	const unsigned char* cp = (const unsigned char*) bytes;
diff -uNr bro-pub-0.8a41/Hash.h bro-pub-0.841-ssl/Hash.h
--- bro-pub-0.8a41/Hash.h	Mon Sep 22 02:18:51 2003
+++ bro-pub-0.841-ssl/Hash.h	Wed Oct 15 05:17:51 2003
@@ -73,9 +73,10 @@
 	int Size() const	{ return size; }
 	hash_t Hash() const	{ return hash; }
 
+	static hash_t HashBytes(const void* bytes, int size);
+
 protected:
 	void* CopyKey(const void* key, int size) const;
-	hash_t HashBytes(const void* bytes, int size) const;
 
 	union {
 		int i;
diff -uNr bro-pub-0.8a41/Makefile.in bro-pub-0.841-ssl/Makefile.in
--- bro-pub-0.8a41/Makefile.in	Fri Oct 10 07:48:10 2003
+++ bro-pub-0.841-ssl/Makefile.in	Wed Oct 15 05:21:44 2003
@@ -64,7 +64,7 @@
 COMPRESS = @COMPRESS@
 
 # Objects which depend on OpenSSL (empty currently)
-SSL_OBJ=
+SSL_OBJ= X509.o
 
 # Targets that depend on OpenSSL
 SSL_TARGET= bdcat
@@ -84,7 +84,8 @@
 	PolicyFile.o Portmap.o PrefixTable.o PriorityQueue.o \
 	Queue.o RE.o RPC.o Reassem.o RemoteSerializer.o Rlogin.o Rule.o \
 	RuleAction.o RuleCondition.o RuleMatcher.o SMTP.o \
-	SSH.o Scope.o SerializationFormat.o Serializer.o \
+	SSH.o SSLv3.o SSLv3Automaton.o SSLv2.o SSLProxy.o SSLInterpreter.o \
+	SSLCiphers.o Scope.o SerializationFormat.o Serializer.o \
 	Sessions.o SteppingStone.o Stmt.o TCP.o TCP_Rewriter.o \
 	Telnet.o Timer.o Type.o UDP.o Val.o Var.o XDR.o \
 	cq.o md5.o patricia.o setsignal.o version.o @LIBOBJS@ @WANT_SSL_OBJ@
@@ -399,6 +401,24 @@
 SSH.o: SSH.cc SSH.h
 	$(CPLUS) $(CFLAGS) -c SSH.cc
 
+SSLv3.o: SSLv3.cc SSLv3.h SSLDefines.h
+	$(CPLUS) $(CFLAGS) -c SSLv3.cc
+
+SSLv3Automaton.o: SSLv3Automaton.cc SSLv3Automaton.h SSLDefines.h
+	$(CPLUS) $(CFLAGS) -c SSLv3Automaton.cc
+	
+SSLCiphers.o: SSLCiphers.cc SSLCiphers.h
+	$(CPLUS) $(CFLAGS) -c SSLCiphers.cc
+
+SSLInterpreter.o: SSLInterpreter.cc SSLInterpreter.h
+	$(CPLUS) $(CFLAGS) -c SSLInterpreter.cc
+
+SSLProxy.o: SSLProxy.cc SSLProxy.h
+	$(CPLUS) $(CFLAGS) -c SSLProxy.cc
+
+SSLv2.o: SSLv2.cc SSLv2.h
+	$(CPLUS) $(CFLAGS) -c SSLv2.cc
+
 SteppingStone.o: SteppingStone.cc SteppingStone.h
 	$(CPLUS) $(CFLAGS) -c SteppingStone.cc
 
@@ -432,6 +452,9 @@
 
 Var.o: Var.cc Var.h
 	$(CPLUS) $(CFLAGS) -c Var.cc
+	
+X509.o: X509.cc X509.h
+	$(CPLUS) $(CFLAGS) -c X509.cc
 
 XDR.o: XDR.cc XDR.h
 	$(CPLUS) $(CFLAGS) -c XDR.cc
diff -uNr bro-pub-0.8a41/NetVar.cc bro-pub-0.841-ssl/NetVar.cc
--- bro-pub-0.8a41/NetVar.cc	Fri Oct 10 08:38:20 2003
+++ bro-pub-0.841-ssl/NetVar.cc	Wed Oct 15 05:17:51 2003
@@ -55,6 +55,18 @@
 double tcp_reset_delay;
 double tcp_partial_close_delay;
 
+// see policy/ssl.bro for details
+int ssl_compare_cipherspecs;
+int ssl_analyze_certificates;
+int ssl_store_certificates;
+int ssl_verify_certificates;
+int ssl_store_key_material;
+int ssl_max_cipherspec_size;
+StringVal* ssl_store_cert_path;
+StringVal* x509_trusted_cert_path;
+TableType* cipher_suites_list;
+RecordType* x509_type;
+
 double non_analyzed_lifetime;
 double default_inactivity_timeout;
 
@@ -196,6 +208,34 @@
 	tcp_close_delay = opt_internal_double("tcp_close_delay");
 	tcp_reset_delay = opt_internal_double("tcp_reset_delay");
 	tcp_partial_close_delay = opt_internal_double("tcp_partial_close_delay");
+	
+	ssl_compare_cipherspecs  = opt_internal_int("ssl_compare_cipherspecs");
+	ssl_analyze_certificates = opt_internal_int("ssl_analyze_certificates");
+	ssl_store_certificates   = opt_internal_int("ssl_store_certificates");
+	ssl_verify_certificates  = opt_internal_int("ssl_verify_certificates");
+	ssl_store_key_material = opt_internal_int("ssl_store_key_material");
+	ssl_max_cipherspec_size  = opt_internal_int("ssl_max_cipherspec_size");
+	Val* pVal = opt_internal_val("x509_trusted_cert_path");
+	if (pVal)
+	{
+		x509_trusted_cert_path = pVal->AsStringVal();
+	}
+	else
+	{
+		x509_trusted_cert_path = NULL;
+	}
+	pVal = NULL;
+	pVal = opt_internal_val("ssl_store_cert_path");
+	if (pVal)
+	{
+		ssl_store_cert_path = pVal->AsStringVal();
+	}
+	else
+	{
+		ssl_store_cert_path = NULL;
+	}	
+	cipher_suites_list = internal_type("cipher_suites_list")->AsTableType();
+	x509_type = internal_type("x509")->AsRecordType();
 
 	non_analyzed_lifetime = opt_internal_double("non_analyzed_lifetime");
 	default_inactivity_timeout = opt_internal_double("inactivity_timeout");
diff -uNr bro-pub-0.8a41/NetVar.h bro-pub-0.841-ssl/NetVar.h
--- bro-pub-0.8a41/NetVar.h	Fri Oct 10 08:38:20 2003
+++ bro-pub-0.841-ssl/NetVar.h	Wed Oct 15 05:17:51 2003
@@ -57,6 +57,18 @@
 extern double tcp_partial_close_delay;
 extern double tcp_reset_delay;
 
+// see policy/ssl.bro for details
+extern int ssl_compare_cipherspecs;
+extern int ssl_analyze_certificates;
+extern int ssl_store_certificates;
+extern int ssl_verify_certificates;
+extern int ssl_store_key_material;
+extern int ssl_max_cipherspec_size;
+extern StringVal* ssl_store_cert_path;
+extern StringVal* x509_trusted_cert_path;
+extern TableType* cipher_suites_list;
+extern RecordType* x509_type;
+
 extern double non_analyzed_lifetime;
 extern double default_inactivity_timeout;
 
diff -uNr bro-pub-0.8a41/SSLCiphers.cc bro-pub-0.841-ssl/SSLCiphers.cc
--- bro-pub-0.8a41/SSLCiphers.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLCiphers.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,591 @@
+// -----------------------------------------------------
+// SSL/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#include "SSLCiphers.h"
+
+PDict(SSL_CipherSpec) SSL_CipherSpecDict;
+
+// --- definitions for ssl cipher handling ------------------------------------
+
+SSL_CipherSpec SSL_CipherSpecs[] =
+{
+	// --- SSL 2.0 cipher specs
+	{ SSL_CK_RC4_128_WITH_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv20,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		128
+	},
+	{ SSL_CK_RC4_128_EXPORT40_WITH_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv20,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		88,
+		40,
+		128
+	},
+	{ SSL_CK_RC2_128_CBC_WITH_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv20,
+		SSL_CIPHER_RC2,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		128
+	},
+	{ SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv20,
+		SSL_CIPHER_RC2,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		88,
+		40,
+		128
+	},
+	{ SSL_CK_IDEA_128_CBC_WITH_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv20,
+		SSL_CIPHER_IDEA,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		128
+	},
+	{ SSL_CK_DES_64_CBC_WITH_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv20,
+		SSL_CIPHER_DES,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		64,
+		128
+	},
+	{ SSL_CK_DES_192_EDE3_CBC_WITH_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv20,
+		SSL_CIPHER_3DES,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		192,
+		128
+	},
+	// --- SSL 3.0 / 3.1 cipher specs
+	{ TLS_NULL_WITH_NULL_NULL,
+		SSL_CIPHER_TYPE_NULL,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_NULL,
+		SSL_MAC_NULL,
+		SSL_KEY_EXCHANGE_NULL,
+		0,
+		0,
+		0
+	},
+	{ TLS_RSA_WITH_NULL_MD5,
+		SSL_CIPHER_TYPE_NULL,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_NULL,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		0,
+		128
+	},
+	{ TLS_RSA_WITH_NULL_SHA,
+		SSL_CIPHER_TYPE_NULL,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_NULL,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		0,
+		160
+	},
+	{ TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA_EXPORT,
+		0,
+		40,
+		128
+	},
+	{ TLS_RSA_WITH_RC4_128_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		128
+	},
+	{ TLS_RSA_WITH_RC4_128_SHA,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		160
+	},
+	{ TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC2,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_RSA_EXPORT,
+		0,
+		40,
+		128
+	},
+	{ TLS_RSA_WITH_IDEA_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_IDEA,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		160
+	},
+	{ TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA_EXPORT,
+		0,
+		40,
+		160
+	},
+	{ TLS_RSA_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		56,
+		160
+	},
+	{ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		168,
+		160
+	},
+	{ TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_DSS_EXPORT,
+		0,
+		40,
+		160
+	},
+	{ TLS_DH_DSS_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_DSS,
+		0,
+		56,
+		160
+	},
+	{ TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_DSS,
+		0,
+		168,
+		160
+	},
+	{ TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_RSA_EXPORT,
+		0,
+		168,
+		160
+	},
+	{ TLS_DH_RSA_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_RSA,
+		0,
+		56,
+		160
+	},
+	{ TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_RSA,
+		0,
+		168,
+		160
+	},
+	{ TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS_EXPORT,
+		0,
+		40,
+		160
+	},
+	{ TLS_DHE_DSS_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS,
+		0,
+		56,
+		160
+	},
+	{ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS,
+		0,
+		168,
+		160
+	},
+	{ TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_RSA_EXPORT,
+		0,
+		40,
+		160
+	},
+	{ TLS_DHE_RSA_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_RSA,
+		0,
+		56,
+		160
+	},
+	{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_RSA,
+		0,
+		168,
+		160
+	},
+	{ TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_DH_ANON_EXPORT,
+		0,
+		40,
+		128
+	},
+	{ TLS_DH_ANON_WITH_RC4_128_MD5,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_MD5,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		128,
+		128
+	},
+	{ TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES40,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		40,
+		160
+	},
+	{ TLS_DH_ANON_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		56,
+		160
+	},
+	{ TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		168,
+		160
+	},
+	{ SSL_FORTEZZA_KEA_WITH_NULL_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30,
+		SSL_CIPHER_NULL,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_FORTEZZA_KEA,
+		0,
+		0,
+		160
+	},
+	{ SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30,
+		SSL_CIPHER_FORTEZZA,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_FORTEZZA_KEA,
+		0,
+		96,
+		160
+	},
+	{ SSL_FORTEZZA_KEA_WITH_RC4_128_SHA,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv30,
+		SSL_CIPHER_RC4,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_FORTEZZA_KEA,
+		0,
+		128,
+		160
+	},
+	// --- special SSLv3 FIPS ciphers
+	{ SSL_RSA_FIPS_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		56,
+		160
+	},
+	{ SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_3DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		168,
+		160
+	},
+	// --- new 56 bit export ciphers
+	{ TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA_EXPORT1024,
+		0,
+		56,
+		160
+	},
+	{ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA_EXPORT1024,
+		0,
+		56,
+		160
+	},
+	{ TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_DES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024,
+		0,
+		56,
+		160
+	},
+	{ TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_EXPORT | SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024,
+		0,
+		56,
+		160
+	},
+	{ TLS_DHE_DSS_WITH_RC4_128_SHA,
+		SSL_CIPHER_TYPE_STREAM,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_RC4,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS,
+		0,
+		128,
+		160
+	},
+	// --- new AES ciphers
+	{ TLS_RSA_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		128,
+		160
+	},
+	{ TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_DSS,
+		0,
+		128,
+		160
+	},
+	{ TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_RSA,
+		0,
+		128,
+		160
+	},
+	{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS,
+		0,
+		128,
+		160
+	},
+	{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_RSA,
+		0,
+		128,
+		160
+	},
+	{ TLS_DH_ANON_WITH_AES_128_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		128,
+		160
+	},
+	{ TLS_RSA_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_RSA,
+		0,
+		256,
+		160
+	},
+	{ TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_DSS,
+		0,
+		256,
+		160
+	},
+	{ TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_RSA,
+		0,
+		256,
+		160
+	},
+	{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_DSS,
+		0,
+		256,
+		160
+	},
+	{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DHE_RSA,
+		0,
+		256,
+		160
+	},
+	{ TLS_DH_ANON_WITH_AES_256_CBC_SHA,
+		SSL_CIPHER_TYPE_BLOCK,
+		SSL_FLAG_SSLv30 | SSL_FLAG_SSLv31,
+		SSL_CIPHER_AES,
+		SSL_MAC_SHA,
+		SSL_KEY_EXCHANGE_DH_ANON,
+		0,
+		256,
+		160
+	}
+};
+
+const uint SSL_CipherSpecs_Count = sizeof(SSL_CipherSpecs) / sizeof(SSL_CipherSpec);
diff -uNr bro-pub-0.8a41/SSLCiphers.h bro-pub-0.841-ssl/SSLCiphers.h
--- bro-pub-0.8a41/SSLCiphers.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLCiphers.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,183 @@
+// -----------------------------------------------------
+// SSL/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef SSL_CIPHERS_H
+#define SSL_CIPHERS_H
+
+#include "Dict.h"
+
+// --- definitions for sslv3x cipher handling ---------------------------------
+
+/*!
+ * In SSLv2, a cipher spec consists of three bytes.
+ */
+enum SSLv2_CipherSpec
+{
+	// --- standard SSLv2 ciphers
+	SSL_CK_RC4_128_WITH_MD5              = 0x010080,
+	SSL_CK_RC4_128_EXPORT40_WITH_MD5     = 0x020080,
+	SSL_CK_RC2_128_CBC_WITH_MD5          = 0x030080,
+	SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5 = 0x040080,
+	SSL_CK_IDEA_128_CBC_WITH_MD5         = 0x050080,
+	SSL_CK_DES_64_CBC_WITH_MD5           = 0x060040,
+	SSL_CK_DES_192_EDE3_CBC_WITH_MD5     = 0x0700C0
+};
+
+
+/*!
+ * In SSLv3x, a cipher spec consists of two bytes.
+ */
+enum SSL3_1_CipherSpec {
+	// --- standard SSLv3x ciphers
+	TLS_NULL_WITH_NULL_NULL                = 0x0000,
+	TLS_RSA_WITH_NULL_MD5                  = 0x0001,
+	TLS_RSA_WITH_NULL_SHA                  = 0x0002,
+	TLS_RSA_EXPORT_WITH_RC4_40_MD5         = 0x0003,
+	TLS_RSA_WITH_RC4_128_MD5               = 0x0004,
+	TLS_RSA_WITH_RC4_128_SHA               = 0x0005,
+	TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5     = 0x0006,
+	TLS_RSA_WITH_IDEA_CBC_SHA              = 0x0007,
+	TLS_RSA_EXPORT_WITH_DES40_CBC_SHA      = 0x0008,
+	TLS_RSA_WITH_DES_CBC_SHA               = 0x0009,
+	TLS_RSA_WITH_3DES_EDE_CBC_SHA          = 0x000A,
+	TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA   = 0x000B,
+	TLS_DH_DSS_WITH_DES_CBC_SHA            = 0x000C,
+	TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA       = 0x000D,
+	TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA   = 0x000E,
+	TLS_DH_RSA_WITH_DES_CBC_SHA            = 0x000F,
+	TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA       = 0x0010,
+	TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA  = 0x0011,
+	TLS_DHE_DSS_WITH_DES_CBC_SHA           = 0x0012,
+	TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA      = 0x0013,
+	TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA  = 0x0014,
+	TLS_DHE_RSA_WITH_DES_CBC_SHA           = 0x0015,
+	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA      = 0x0016,
+	TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5     = 0x0017,
+	TLS_DH_ANON_WITH_RC4_128_MD5           = 0x0018,
+	TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA  = 0x0019,
+	TLS_DH_ANON_WITH_DES_CBC_SHA           = 0x001A,
+	TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA      = 0x001B,
+	// --- special SSLv3 ciphers
+	SSL_FORTEZZA_KEA_WITH_NULL_SHA         = 0x001C,
+	SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA = 0x001D,
+	SSL_FORTEZZA_KEA_WITH_RC4_128_SHA      = 0x001E,
+	// --- special SSLv3 FIPS ciphers
+	SSL_RSA_FIPS_WITH_DES_CBC_SHA 		   = 0xFEFE,
+	SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA	   = 0XFEFF,
+	// --- new 56 bit export ciphers
+	TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA     = 0x0062,
+	TLS_RSA_EXPORT1024_WITH_RC4_56_SHA      = 0x0064,
+	TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = 0x0063,
+	TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA  = 0x0065,
+	TLS_DHE_DSS_WITH_RC4_128_SHA            = 0x0066,
+	// --- new AES ciphers
+	TLS_RSA_WITH_AES_128_CBC_SHA      = 0x002F,
+	TLS_DH_DSS_WITH_AES_128_CBC_SHA   = 0x0030,
+	TLS_DH_RSA_WITH_AES_128_CBC_SHA   = 0x0031,
+	TLS_DHE_DSS_WITH_AES_128_CBC_SHA  = 0x0032,
+	TLS_DHE_RSA_WITH_AES_128_CBC_SHA  = 0x0033,
+	TLS_DH_ANON_WITH_AES_128_CBC_SHA  = 0x0034,
+	TLS_RSA_WITH_AES_256_CBC_SHA      = 0x0035,
+	TLS_DH_DSS_WITH_AES_256_CBC_SHA   = 0x0036,
+	TLS_DH_RSA_WITH_AES_256_CBC_SHA   = 0x0037,
+	TLS_DHE_DSS_WITH_AES_256_CBC_SHA  = 0x0038,
+	TLS_DHE_RSA_WITH_AES_256_CBC_SHA  = 0x0039,
+	TLS_DH_ANON_WITH_AES_256_CBC_SHA  = 0x003A
+};
+
+enum SSL_CipherType
+{
+	SSL_CIPHER_TYPE_STREAM,
+	SSL_CIPHER_TYPE_BLOCK,
+	SSL_CIPHER_TYPE_NULL
+};
+
+enum SSL_BulkCipherAlgorithm
+{
+	SSL_CIPHER_NULL,
+	SSL_CIPHER_RC4,
+	SSL_CIPHER_RC2,
+	SSL_CIPHER_DES,
+	SSL_CIPHER_3DES,
+	SSL_CIPHER_DES40,
+	SSL_CIPHER_FORTEZZA,
+	SSL_CIPHER_IDEA,
+	SSL_CIPHER_AES
+};
+
+enum SSL_MACAlgorithm
+{
+	SSL_MAC_NULL,
+	SSL_MAC_MD5,
+	SSL_MAC_SHA
+};
+
+enum SSL_KeyExchangeAlgorithm
+{
+	SSL_KEY_EXCHANGE_NULL,
+	SSL_KEY_EXCHANGE_RSA,
+	SSL_KEY_EXCHANGE_RSA_EXPORT,
+	SSL_KEY_EXCHANGE_DH,
+	SSL_KEY_EXCHANGE_DH_DSS,
+	SSL_KEY_EXCHANGE_DH_DSS_EXPORT,
+	SSL_KEY_EXCHANGE_DH_RSA,
+	SSL_KEY_EXCHANGE_DH_RSA_EXPORT,
+	SSL_KEY_EXCHANGE_DHE_DSS,
+	SSL_KEY_EXCHANGE_DHE_DSS_EXPORT,
+	SSL_KEY_EXCHANGE_DHE_RSA,
+	SSL_KEY_EXCHANGE_DHE_RSA_EXPORT,
+	SSL_KEY_EXCHANGE_DH_ANON,
+	SSL_KEY_EXCHANGE_DH_ANON_EXPORT,
+	SSL_KEY_EXCHANGE_FORTEZZA_KEA,
+	// --- new 56 bit export ciphers
+	SSL_KEY_EXCHANGE_RSA_EXPORT1024,
+	SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024
+};
+
+/*
+struct SSL_CipherSpecImproved //new
+{
+	uint32 identifier;
+
+	//SSL_CipherType cipherType;
+	SSL_BulkCipherAlgorithm encryptionAlgorithm;
+	SSL_BulkCipherAlgorithm authenticationAlgorithm;
+	SSL_BulkCipherAlgorithm keyAlgorithm;
+	SSL_MACAlgorithm        macAlgorithm;
+
+	int clearkeySize;
+	int encryptedkeySize;
+	uint32 flags; // IsExportable IsSSLv2 IsSSLv30 IsSSLv31
+	const char* fullName = "TLS_WITH_NULL_NULL";
+
+};*/
+
+struct SSL_CipherSpec
+{
+	uint32 identifier; ///< type code of the CIPHER-SPEC (2 or 3 Bytes)
+
+	SSL_CipherType cipherType;
+	uint32 flags;
+	SSL_BulkCipherAlgorithm bulkCipherAlgorithm;
+	SSL_MACAlgorithm macAlgorithm;
+	SSL_KeyExchangeAlgorithm keyExchangeAlgorithm;
+
+	int clearKeySize;     ///< size in bits of the plaintext part of the master key
+	int encryptedKeySize; ///< size in bits of the encrypted part of the master key
+	int hashSize;
+};
+
+// some flag definitions
+const uint32 SSL_FLAG_EXPORT = 0x0001; ///< set if the cipher is an exportable cipher
+const uint32 SSL_FLAG_SSLv20 = 0x0002; ///< set if the cipher is defined for SSLv20
+const uint32 SSL_FLAG_SSLv30 = 0x0004; ///< set if the cipher is defined for SSLv30
+const uint32 SSL_FLAG_SSLv31 = 0x0008; ///< set if the cipher is defined for SSLv31
+
+declare(PDict, SSL_CipherSpec);
+extern PDict(SSL_CipherSpec) SSL_CipherSpecDict;
+extern SSL_CipherSpec SSL_CipherSpecs[];
+extern const uint SSL_CipherSpecs_Count;
+
+#endif
diff -uNr bro-pub-0.8a41/SSLDefines.h bro-pub-0.841-ssl/SSLDefines.h
--- bro-pub-0.8a41/SSLDefines.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLDefines.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,50 @@
+//Defines the states and transitions in the ssl-protocol-machine.
+
+#ifndef SSL_DEFINES_H
+#define SSL_DEFINES_H
+
+//states...
+const int SSL3_1_NUM_STATES = 20;
+enum SSL3_1_States
+	{
+	SSL3_1_STATE_ERROR = 0,
+	SSL3_1_STATE_INIT  = 1,
+	SSL3_1_STATE_SERVER_HELLO_REQ_SENT = 2,
+	SSL3_1_STATE_CLIENT_HELLO_SENT = 3,
+	SSL3_1_STATE_SERVER_HELLO_SENT = 4,
+	SSL3_1_STATE_SERVER_CERT_SENT = 5,
+	SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT = 6,
+	SSL3_1_STATE_SERVER_CERT_REQ_SENT = 7,
+	SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A = 8,
+	SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B = 9,
+	SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A = 10,
+	SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B = 11,
+	SSL3_1_STATE_CLIENT_CERT_SENT = 12,
+	SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT = 13,
+	SSL3_1_STATE_CLIENT_FIN_SENT_A = 14,
+	SSL3_1_STATE_SERVER_FIN_SENT_A = 15,
+	SSL3_1_STATE_CLIENT_FIN_SENT_B = 16,
+	SSL3_1_STATE_SERVER_FIN_SENT_B = 17,
+	SSL3_1_STATE_HS_FIN_A = 18,
+	SSL3_1_STATE_HS_FIN_B = 19
+	};
+
+//transitions...
+const int SSL3_1_NUM_TRANS  = 11;
+enum SSL_3_1_Transitions
+	{
+	SSL3_1_TRANS_SERVER_HELLO_REQ = 0,
+	SSL3_1_TRANS_CLIENT_HELLO = 1,
+	SSL3_1_TRANS_SERVER_HELLO = 2,
+	SSL3_1_TRANS_SERVER_CERT = 3,
+	SSL3_1_TRANS_SERVER_KEY_EXCHANGE = 4,
+	SSL3_1_TRANS_SERVER_CERT_REQ = 5,
+	SSL3_1_TRANS_SERVER_HELLO_DONE = 6,
+	SSL3_1_TRANS_CLIENT_CERT = 3,
+	SSL3_1_TRANS_CLIENT_KEY_EXCHANGE = 7,
+	SSL3_1_TRANS_CLIENT_CERT_VERIFY = 8,
+	SSL3_1_TRANS_CLIENT_FIN = 9,
+	SSL3_1_TRANS_SERVER_FIN = 10
+	};
+
+#endif
diff -uNr bro-pub-0.8a41/SSLInterpreter.cc bro-pub-0.841-ssl/SSLInterpreter.cc
--- bro-pub-0.8a41/SSLInterpreter.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLInterpreter.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,546 @@
+// -----------------------------------------------------
+// SSL Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#include "SSLInterpreter.h"
+#include "SSLv2.h"
+
+#ifdef USE_OPENSSL
+	#include "X509.h"
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+declare(PDict, CertStore);
+PDict(CertStore) cert_states;
+
+// --- Initalization of static variables --------------------------------------
+
+uint32 SSL_Interpreter::analyzedCertificates = 0;
+uint32 SSL_Interpreter::verifiedCertificates = 0;
+uint32 SSL_Interpreter::failedCertificates   = 0;
+uint32 SSL_Interpreter::certificateChains    = 0;
+
+// --- SSL_Interpreter --------------------------------------------------------
+
+/*!
+ * The constructor.
+ *
+ * \param proxy Pointer to the SSL_ConnectionProxy which created this instance.
+ */
+SSL_Interpreter::SSL_Interpreter(SSL_ConnectionProxy* proxy)
+	{
+	this->proxy = proxy;
+	}
+
+/*!
+ * The destructor.
+ */
+SSL_Interpreter::~SSL_Interpreter()
+	{
+	//Done();
+	delete orig;
+	delete resp;
+	}
+
+/*!
+ * Accordingly to TCP_Connection::Init(), this method calls
+ * BuildInterpreterEndpoints() to create the corresponding endpoints.
+ */
+void SSL_Interpreter::Init()
+	{
+	BuildInterpreterEndpoints();
+	orig->SetPeer(resp);
+	resp->SetPeer(orig);
+	}
+
+/*!
+ * This method analyzes a given certificate (chain), using the OpenSSL library.
+ *
+ * \param s Pointer to the SSL_InterpreterEndpoint which received the
+ *          cerificate (chain).
+ * \param data Pointer to the data block which contains the certificate (chain).
+ * \param length Size of the data block.
+ * \param type the certificate type
+ * \param isChain false if data is pointing to a single certificate,
+                  true if data is pointing to a certificate chain
+ */
+void SSL_Interpreter::analyzeCertificate( SSL_InterpreterEndpoint* s,
+										   u_char* data,
+										   int length,
+										   uint8 type,
+										   bool isChain )
+{
+	// see if we should continue with this certificate
+	// we get the answer from a BroSkript Event
+	EventHandlerPtr event = ssl_certificate_seen;
+	if ( event )
+		{
+    	val_list* vl = new val_list;
+		vl->append(proxy->BuildConnVal());
+		if ( s->IsOrig() )
+			{
+			vl->append(new Val(0, TYPE_BOOL));
+			}
+		else
+			{
+			vl->append(new Val(1, TYPE_BOOL));
+			}
+		proxy->ConnectionEvent(event, vl);
+		}
+
+	analyzedCertificates++;
+
+	u_char* pCert      = data;
+	uint32  certLength = length;
+	uint    certCount  = 0;
+
+	if ( isChain )
+	{
+		certificateChains++;
+		//sum of all cert sizes has to match certListLength
+		uint tempLength = 0;
+		while( tempLength < length )
+			{
+				certCount++;
+				uint32 certLength = (uint32) ((data[tempLength + 0] << 16) |
+											   data[tempLength + 1] << 8) |
+											   data[tempLength + 2];
+				tempLength += certLength + 3;
+			}
+		if ( tempLength > length )
+			{
+			Weird( "SSLv3x: sum of size of certificates doesn't match size of certificate chain" );
+			return;
+			}
+		//printf( "ccc certCount = %u\n", certCount );
+
+		// get the first certificate
+		pCert = data + 3;
+		certLength = (uint32) ((data[0] << 16) |
+								data[1] << 8) |
+								data[2];
+	}
+
+	// create a hashsum of the current certificate
+	hash_t hashsum = HashKey::HashBytes( pCert, certLength );
+
+	// check if we've seen a certificate from this ip+port before
+	//HashKey h( ip_address );
+	uint8 key[6];
+	uint32 ip_address = *(s->proxyEndpoint->dst_addr);
+	uint16 port = (uint16) s->proxyEndpoint->conn->RespPort();
+	memcpy( key, &ip_address, 4 );
+	memcpy( &key[4], &port, 2 );
+
+	HashKey h( key, sizeof( key ) );
+	CertStore* pCertState = NULL;
+	pCertState = (CertStore*) cert_states.Lookup( &h );
+	if ( !pCertState )
+	{
+		// new ip address!
+		pCertState = new CertStore( ip_address, port, hashsum, certLength );
+		cert_states.Insert( &h, pCertState );
+	}
+	else
+	{
+		// we've seen this ip/certificate before
+
+		// check if certificate changed
+		if ( !pCertState->isSameCert( hashsum, certLength ) )
+		{
+			// this shouldn't happen
+			Weird( "SSL: Certificate changed for this ip+port !!!" );
+
+			// update status
+			pCertState->changes++;
+			pCertState->certHash = hashsum;
+			pCertState->certSize = certLength;
+			pCertState->isValid  = -1;
+		}
+		else
+		{
+			// cert didn't change
+
+			if ( pCertState->isValid == 0 )
+			{
+				// this has been an invalid cert
+				// but we warned before
+			}
+
+			// save time - don't analyze it any further!
+			return;
+		}
+	}
+
+	// certificate verification
+	if ( ssl_verify_certificates != 0 )
+	{
+		verifiedCertificates++;
+		int ret = 0;
+		switch ( type )
+		{
+			case SSLv2_CT_X509_CERTIFICATE:
+			#ifdef USE_OPENSSL
+				if ( !isChain )
+				{
+				ret = X509_Cert::verify( s->proxyEndpoint, pCert, certLength );
+				}
+				else
+				{
+				ret = X509_Cert::verifyChain( s->proxyEndpoint, data, length );
+				}
+			#else
+			proxy->Weak( "SSL: Could not verify certificate (missing OpenSSL support)!" );
+			ret = 0;
+			#endif
+			break;
+			default:
+				Weird("SSL: Unknown CERTIFICATE-TYPE!");
+				ret = 1; // quick 'n dirty :)
+			break;
+		}
+
+		if ( ret != 0 )
+		{
+			proxy->Weak( "SSL: Certificate check FAILED!" );
+			pCertState->isValid = 0;
+			failedCertificates++;
+		}
+		else
+		{
+			pCertState->isValid = 1;
+		}
+	}
+
+	// store the certificate
+	if ( ssl_store_certificates != 0 )
+	{
+		// let's hope the adress is in network byte order :)
+		in_addr addr;
+		addr.s_addr = ip_address;
+		char* pDummy = inet_ntoa( addr );
+		char sFileName[100];
+
+		if ( ssl_store_cert_path &&
+		 	 ssl_store_cert_path->AsString()->Len() > 0 )
+		{
+			BroString* pString = ssl_store_cert_path->AsString();
+			sprintf( sFileName,
+					"%s/%s-server-c%i.der",
+					pString->Bytes(),
+					pDummy,
+					pCertState->changes );
+		}
+		else
+		{
+			sprintf( sFileName,
+					"%s-server-c%i.der",
+					pDummy,
+					pCertState->changes );
+		}
+
+		FILE* certFile = fopen( sFileName, "wb" );
+		if ( certFile == NULL )
+		{
+			fprintf( stderr, "SSL_Interpreter::analyzeCertificate(): Error opening '%s'!\n", sFileName );
+			return;
+		}
+		fwrite( pCert, 1, certLength, certFile );
+		fclose( certFile );	
+	}
+
+    // TODO: test if the certificate is valid for the ip adress we got it from
+}
+
+
+/*
+void SSL_Interpreter::Done()
+	{
+	
+	}
+*/
+
+/*!
+ * \return the originating SSL_InterpreterEndpoint
+ */
+SSL_InterpreterEndpoint* SSL_Interpreter::Orig() const
+	{
+	return orig;
+	}
+
+/*!
+ * \return the responding SSL_InterpreterEndpoint
+ */
+SSL_InterpreterEndpoint* SSL_Interpreter::Resp() const
+	{
+	return resp;
+	}
+
+/*!
+ * \param p Pointer to an SSL_InterpreterEndpoint to test
+ *
+ * \return true if p is the originating SSL_InterpreterEndpoint,
+ *         false otherwise
+ */
+int SSL_Interpreter::Is_Orig(SSL_InterpreterEndpoint* p) const
+	{
+	return ( p == orig );
+	}
+
+/*!
+ * \return the responding SSL_InterpreterEndpoint
+ */
+SSL_ConnectionProxy* SSL_Interpreter::Proxy() const
+	{
+	return proxy;
+	}
+
+/*!
+ * This methods prints a string into the "weird" log file.
+ *
+ * \param name String to log into the "weird" file.
+ */
+void SSL_Interpreter::Weird(const char* name) const
+	{
+	proxy->Weird(name);
+	}
+
+/*!
+ * Prints some counters.
+ */
+void SSL_Interpreter::printStats()
+	{
+	printf( "SSL_Interpreter:\n" );
+	printf( "analyzedCertificates = %u\n", analyzedCertificates );
+	printf( "verifiedCertificates = %u\n", verifiedCertificates );
+	printf( "failedCertificates   = %u\n", failedCertificates );
+	printf( "certificateChains    = %u\n", certificateChains );
+	}
+
+/*!
+ * Wrapper function for the event ssl_conn_attempt.
+ *
+ * \param sslVersion the SSL version for which the event occured
+ *
+ * \see SSL_ConnectionProxy::SSL_Versions
+ */
+void SSL_Interpreter::fire_ssl_conn_attempt( uint16 sslVersion, TableVal* currentCipherSuites )
+	{
+	EventHandlerPtr event = ssl_conn_attempt;
+	if ( event )
+		{
+		val_list* vl = new val_list;
+		vl->append( proxy->BuildConnVal() );
+		vl->append(new Val(sslVersion, TYPE_COUNT));
+		vl->append(currentCipherSuites);
+
+		proxy->ConnectionEvent( event, vl );
+		}
+	}
+
+/*!
+ * Wrapper function for the event ssl_conn_server_reply.
+ *
+ * \param sslVersion the SSL version for which the event occured
+ *
+ * \see SSL_ConnectionProxy::SSL_Versions
+ */
+void SSL_Interpreter::fire_ssl_conn_server_reply( uint16 sslVersion, TableVal* currentCipherSuites )
+	{
+	EventHandlerPtr event = ssl_conn_server_reply;
+	if ( event )
+		{
+		val_list* vl = new val_list;
+		vl->append( proxy->BuildConnVal() );
+		vl->append( new Val( sslVersion, TYPE_COUNT ) );
+		vl->append(currentCipherSuites);
+
+		proxy->ConnectionEvent(event, vl);
+		}
+	}
+
+/*!
+ * Wrapper function for the event ssl_conn_established.
+ *
+ * \param sslVersion the SSL version for which the event occured
+ * \param cipherSuite constant indicating the used SSL cipher suite
+ *
+ * \see SSL_ConnectionProxy::SSL_Versions, SSLv2_CipherSpecs and SSL3_1_CipherSpec.
+ */
+void SSL_Interpreter::fire_ssl_conn_established( uint16 sslVersion, uint32 cipherSuite )
+	{
+	EventHandlerPtr event = ssl_conn_established;
+	if ( event )
+		{
+		val_list* vl = new val_list;
+		vl->append( proxy->BuildConnVal() );
+		vl->append( new Val( sslVersion, TYPE_COUNT ) );
+		vl->append( new Val( cipherSuite, TYPE_COUNT ) );
+	
+		proxy->ConnectionEvent(event, vl);
+		}
+
+	}
+
+/*!
+ * Wrapper function for the event ssl_conn_reused
+ *
+ * \param pData Pointer to a SSL_DataBlock which contains the SSL session ID
+ *        of the originating ssl session.
+ */
+void SSL_Interpreter::fire_ssl_conn_reused( const SSL_DataBlock* pData )
+	{
+	EventHandlerPtr event = ssl_conn_reused;
+	if ( event )
+		{
+		val_list* vl = new val_list;
+		vl->append(proxy->BuildConnVal());
+		char* pString = pData->toString();
+		vl->append( new StringVal( pString ) );
+		delete pString;
+
+		proxy->ConnectionEvent(event, vl);
+		}
+	}
+
+/*!
+ * Wrapper function for the event ssl_conn_alert
+ *
+ * \param sslVersion the SSL version for which the event occured
+ * \param level constant indicating the level of severity
+ * \param description constant indicating the type of alert/error
+ *
+ * \see SSL_ConnectionProxy::SSL_Versions, SSL3x_AlertLevel, SSL3_1_AlertDescription
+ *      and SSLv2_ErrorCodes.
+ */
+void SSL_Interpreter::fire_ssl_conn_alert( uint16 sslVersion, uint16 level, uint16 description )
+	{
+	if ( ssl_conn_alert )
+		{
+		EventHandlerPtr event = ssl_conn_alert;
+		if ( event )
+			{
+			val_list* vl = new val_list;
+			vl->append( proxy->BuildConnVal() );
+			vl->append( new Val( sslVersion, TYPE_COUNT ) );
+			vl->append( new Val( level, TYPE_COUNT ) );
+			vl->append( new Val( description, TYPE_COUNT ) );
+
+			proxy->ConnectionEvent(event, vl);
+			}
+		}
+	}
+
+//--- SSL_InterpreterEndpoint -------------------------------------------------
+
+/*!
+ * The constructor.
+ *
+ * \param interpreter Pointer to the instance of an SSL_Interpreter to which
+ *                    this endpoint belongs to.
+ * \param is_orig true if this endpoint is the originator of the connection,
+ *                false otherwise
+ */
+SSL_InterpreterEndpoint::SSL_InterpreterEndpoint(SSL_Interpreter* interpreter,
+												 bool is_orig )
+	{
+	this->interpreter = interpreter;
+	this->is_orig = is_orig;
+	if ( is_orig )
+		{
+			this->proxyEndpoint = (SSL_ProxyEndpoint*) interpreter->Proxy()->Orig();
+		}
+	else
+		{
+			this->proxyEndpoint = (SSL_ProxyEndpoint*) interpreter->Proxy()->Resp();
+		}
+	}
+
+/*!
+ * The destructor.
+ */
+SSL_InterpreterEndpoint::~SSL_InterpreterEndpoint()
+	{
+	}
+
+/*!
+ * \return true if there's currently data pending for this endpoint,
+ *         false otherwise
+ */
+bool SSL_InterpreterEndpoint::isDataPending()
+{
+	return proxyEndpoint->isDataPending();
+}
+
+/*!
+ * Sets the peer of this endpoint.
+ *
+ * \param p Pointer to an interpreter endpoint which will be set as the peer
+ *          of this endpoint.
+ */
+void SSL_InterpreterEndpoint::SetPeer(SSL_InterpreterEndpoint* p)
+	{
+	peer = p;
+	}
+
+/*!
+ * \return is_orig true if this endpoint is the originator of the connection,
+ *                 false otherwise
+ */
+int SSL_InterpreterEndpoint::IsOrig() const
+	{
+	return is_orig;
+	}
+
+/*!
+ * \return the peer of this endpoint
+ */
+SSL_InterpreterEndpoint* SSL_InterpreterEndpoint::Peer() const
+	{
+	return peer;
+	}
+
+/*!
+ * \return the interpreter of this endpoint
+ */
+SSL_Interpreter* SSL_InterpreterEndpoint::Interpreter() const
+	{
+	return interpreter;
+	}
+
+// --- CertStore --------------------------------------------------------------
+
+/*
+ * The constructor.
+ *
+ * \param ip ip adress where this certificate came from
+ * \param port port number where this certificate came from
+ * \param hash hahssum for this certificate
+ * \param size of this certificate in bytes
+ */
+CertStore::CertStore( uint32 ip, uint32 port, hash_t hash, int size )
+	{
+	ip_addr = ip;
+	certHash = hash;
+	certSize = size;
+	isValid = -1;
+	changes = 0;
+	this->port = port;
+	}
+
+/*
+ * This method can be used to compare certificates by certain criterias.
+ *
+ * \param hash hashsum of the certificate to compare
+ * \param size size of the certificate to compare
+ *
+ * \return true if the criterias match, false otherwise
+ */
+bool CertStore::isSameCert( hash_t hash, int length )
+	{
+	return ( hash == certHash && length == certSize );
+	}
diff -uNr bro-pub-0.8a41/SSLInterpreter.h bro-pub-0.841-ssl/SSLInterpreter.h
--- bro-pub-0.8a41/SSLInterpreter.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLInterpreter.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,149 @@
+// -----------------------------------------------------
+// SSL Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef sslinterpreter_h
+#define sslinterpreter_h
+
+#include "util.h"
+#include "SSLProxy.h"
+
+// --- macros ------------------------------------------------------------------
+
+#define SAFE_DELETE( x ) if ( x != NULL ) { delete x; x = NULL; }
+
+// --- forward declarations ----------------------------------------------------
+
+class SSL_ConnectionProxy;
+class SSL_ProxyEndpoint;
+class SSL_InterpreterEndpoint;
+class SSL_DataBlock;
+
+// --- SSL_Interpreter --------------------------------------------------------
+
+/*!
+ * \brief This class is the abstract base-class for the different ssl
+ *        interpreters used for the different ssl versions.
+ *
+ * Since there is currently no support in Bro for a change of the connection
+ * type (IMAP -> TLS, for example), we decided not to inherit from the class
+ * Connection. This way, we can easily switch to SSLv3x after we've seen (and
+ * analyzed) a SSLv2 client hello record with a version number > SSLv2.
+ *
+ * There currently two (non-abstract) interpreters: SSLv2_Interpreter and
+ * SSLv3_Interpreter. The first one supports SSL 2.0, the second one supports
+ * both SSL 3.0 and SSL 3.1/TLS 1.0.
+ *
+ * See SSL_ConnectionProxy for additional information.
+ */
+class SSL_Interpreter
+{
+public:
+
+	static uint32 analyzedCertificates; ///< how often analyzeCertificate() has been called
+	static uint32 verifiedCertificates; ///< how many certificates have actually been verified
+	static uint32 failedCertificates;   ///< how many certificates have failed verification
+	static uint32 certificateChains;    ///< counter for certificate chains
+
+	SSL_Interpreter(SSL_ConnectionProxy* proxy);
+	~SSL_Interpreter();
+	
+	/** In order to initialize the correct SSL_InterpreterEndpoints, overwrite
+	 * it in the corresponding subclass.
+	 */
+	virtual void BuildInterpreterEndpoints() = 0;
+	virtual void Init();
+	
+	virtual void analyzeCertificate( SSL_InterpreterEndpoint* s,
+									 u_char* data,
+									 int length,
+									 uint8 type,
+									 bool isChain );
+	//virtual void Done();
+	void Weird(const char* name) const;
+	SSL_InterpreterEndpoint* Orig() const;
+	SSL_InterpreterEndpoint* Resp() const;
+	int Is_Orig(SSL_InterpreterEndpoint* p) const;
+	SSL_ConnectionProxy* Proxy() const;
+	static void printStats();
+
+	// event helper methods
+	void fire_ssl_conn_attempt( uint16 sslVersion, TableVal* currentCipherSuites );
+	void fire_ssl_conn_server_reply( uint16 sslVersion , TableVal* currentCipherSuites);
+	void fire_ssl_conn_established( uint16 sslVersion, uint32 cipherSuite );
+	void fire_ssl_conn_reused( const SSL_DataBlock* pData );
+	void fire_ssl_conn_alert( uint16 sslVersion, uint16 level, uint16 description );
+	
+protected:
+	SSL_ConnectionProxy* proxy;
+	SSL_InterpreterEndpoint* orig;
+	SSL_InterpreterEndpoint* resp;
+	
+};
+
+// --- SSL_InterpreterEndpoint ------------------------------------------------
+
+/*!
+ * \brief This abstract class represents the SSL_InterpreterEndpoints for the
+ *        SSL_Interpreter.
+ *
+ * The key-method is Deliver() which receives the ssl records
+ * from the SSL_ConnectionProxy. So overwrite the Deliver()-method and do
+ * whatever analysis on the record content (and/or pass it to the corresponding
+ * SSL_Interpreter).
+ */
+class SSL_InterpreterEndpoint
+{
+public:
+	SSL_InterpreterEndpoint(SSL_Interpreter* interpreter, bool is_orig );
+	~SSL_InterpreterEndpoint();
+	
+	/**This method is called by corresponding SSL_ConnectionProxy and
+	 * delivers the data.
+	 * @param t time, when the segment was received by bro (?)
+	 * @param seq relative sequence number (from Endpoint::start_seq)
+	 * @param len length of TCP-Segment
+	 * @param data content of TCP-Segment
+	 */
+	virtual void Deliver(double t, int seq, int len, u_char* data) = 0;
+	bool isDataPending();
+	void SetPeer(SSL_InterpreterEndpoint* p);
+	int IsOrig() const;
+	SSL_InterpreterEndpoint* Peer() const;
+	SSL_Interpreter* Interpreter() const;
+
+	SSL_ProxyEndpoint* proxyEndpoint; ///< Pointer to the corresponding SSL_ProxyEndpoint
+	
+protected:
+	SSL_Interpreter* interpreter;  ///< Pointer to the SSL_Interpreter to which this endpoint belongs to
+	SSL_InterpreterEndpoint* peer; ///< Pointer to the peer of this endpoint
+	int is_orig;                   ///< true if this endpoint is the originator of the connection, false otherwise
+};
+
+// --- class CertStore --------------------------------------------------------
+/*!
+ * \brief This class is used to store some information about a X509 certificate.
+ *
+ * To save memory, we only store some characteristic criterias about a
+ * certificate, that's currently it's size and a hashsum.
+ *
+ * \note This class is currently <b>experimental</b>.
+ */
+class CertStore
+{
+	public:
+
+	uint32 ip_addr; ///< ip address where this certificate is from
+	uint32 port;    ///< port number where this certificate is from
+
+	int certSize;    ///< size of the certificate in bytes
+	hash_t certHash; ///< hashsum obver the entire certificate
+	int isValid;     ///< boolean value indicating if the certificate is valid
+	int changes;     ///< counter for how often this certificate has changed for the above ip + port number
+
+	CertStore( uint32 ip, uint32 port, hash_t hash, int size );
+	bool isSameCert( hash_t hash, int length );
+};
+
+#endif
diff -uNr bro-pub-0.8a41/SSLProxy.cc bro-pub-0.841-ssl/SSLProxy.cc
--- bro-pub-0.8a41/SSLProxy.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLProxy.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,860 @@
+// -----------------------------------------------------
+// SSL Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#include "SSLProxy.h"
+#include "SSLv3.h"
+#include "SSLv2.h"
+
+// --- Initalization of static variables --------------------------------------
+
+uint SSL_ConnectionProxy::totalPackets        = 0;
+uint SSL_ConnectionProxy::totalRecords        = 0;
+uint SSL_ConnectionProxy::nonSSLConnections   = 0;
+
+// --- SSL_DataBlock --------------------------------------------------------
+
+/*!
+ * This constructor will allocate a block of data on the heap. If min_len is
+ * given, it will determine the minimum size of the new block. The data block
+ * referenced by data will be then be copied into the new block.
+ *
+ * \param data    Pointer to the data which will be copied into the newly
+ *                allocated heap block.
+ * \param len     Length of the data block to copy.
+ * \param min_len The minimum size of data to allocate on the heap, can be omitted.
+ */
+
+SSL_DataBlock::SSL_DataBlock( u_char* data, int len, int min_len )
+	{
+	// for performance reasons, we allocate at least min_len
+	if ( len < min_len )
+		{
+		//printf( "SSL_DataBlock::SSL_DataBlock with len < men_len (%i)!\n", len );
+		this->data = new u_char[min_len];
+		this->size = min_len;
+		}
+	else
+		{
+		this->data = new u_char[len];
+		this->size = len;
+		}
+
+	memcpy( this->data, data, len );
+	this->len = len;
+	next = NULL;
+	}
+
+
+/*!
+ * This is an experimental function which will print the contents of the
+ * internal data block in a human-readable fashion to a stream.
+ *
+ * \param stream The stream for printing the data block to.
+ */
+
+void SSL_DataBlock::toStream( FILE* stream ) const
+	{
+	if ( len <= 0 )
+		{
+			return;
+		}
+	/*
+	int idx;
+	for ( idx = 0; (idx / 16)  < (len / 16); idx += 16 )
+		{
+		fprintf( stream,
+				 "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
+				 data[idx], data[idx+1], data[idx+2], data[idx+3], data[idx+4], data[idx+5], data[idx+6], data[idx+7],
+				 data[idx+8], data[idx+9], data[idx+10], data[idx+11], data[idx+12], data[idx+13], data[idx+14], data[idx+15] );
+		}
+
+	for ( ; (idx % 16) < (len % 16); idx++ )
+		{
+		fprintf( stream, "0x%02X ", data[idx] );
+		}
+	*/
+
+	int idx = 0;
+	for ( ; idx < len-1; idx++ )
+		{
+		fprintf( stream, "%02X:", data[idx] );
+		}
+		fprintf( stream, "%02X", data[idx] );
+	}
+
+
+/*!
+ * This is an experimental function which will print the contents of the
+ * internal data block in a human-readable fashion to a string.
+ *
+ * \return A string which has to be freed by the caller.
+ */
+
+char* SSL_DataBlock::toString() const
+	{
+	if ( len <= 0 )
+		{
+			// so far, we return an enmpty string if the data block is empty
+			char* pDummy = new char[1];
+			pDummy[0] = '\0';
+			return pDummy;
+		}
+
+		char* pString = new char[len*3];
+		char* pItx = pString;
+	
+		int idx = 0;
+		for ( ; idx < len-1; idx++ )
+			{
+			sprintf( pItx, "%02X:", data[idx] );
+			pItx += 3;
+			}
+		sprintf( pItx, "%02X", data[idx] );
+
+		return pString;
+	}
+
+// --- SSL_RecordBuilder ------------------------------------------------------
+
+uint SSL_RecordBuilder::maxAllocCount     = 0;
+uint SSL_RecordBuilder::maxFragmentCount  = 0;
+uint SSL_RecordBuilder::fragmentedHeaders = 0;
+
+/*!
+ * The constructor takes an SSL_ProxyEndpoint as parameter. Whenever a SSL
+ * record has been reassembled, the DoDeliver() function of this
+ * SSL_ProxyEndpoint will be called.
+ *
+ * \param sslEndpoint The SSL_ProxyEndpoint to which this instance of
+ *        SSL_RecordBuilder is bound.
+ */
+
+SSL_RecordBuilder::SSL_RecordBuilder( SSL_ProxyEndpoint* sslEndpoint )
+	{
+	head = tail      = NULL;
+	currentSize      = 0;
+	expectedSize     = -1; // -1 means we don't know yet
+	hasPendingData   = false;
+	fragmentCounter  = 0;
+	neededSize       = 5;  // we need at least 5 bytes to determine the ssl version
+
+	this->sslEndpoint = sslEndpoint;
+	}
+
+/*!
+ * The destructor frees the chain of SSL_DataBlocks.
+ */
+
+SSL_RecordBuilder::~SSL_RecordBuilder()
+	{
+	// free the data chain
+	SSL_DataBlock* idx = head;
+	SSL_DataBlock* rm;
+	while ( idx )
+		{
+		rm  = idx;
+		idx = idx->next;
+		delete rm;
+		}
+	}
+
+/*!
+ * This function is the main entry point of the class. Call it with a segment
+ * of data to process.
+ *
+ * \param data   pointer to a data segment that will be reassembled
+ * \param length length of the data segment to be reassembled
+ *
+ * \return true if succesfull, false otherwise
+ */
+
+bool SSL_RecordBuilder::addSegment( u_char* data, int length )
+	{
+	while ( length > 0 )
+		{
+		if ( !head )
+			{
+			// this is the first fragment of a SSLv2 record,
+			// so we analyze the header
+
+			// special case: ssl header has been fragmented
+			if ( length < neededSize )
+				{
+				// we can't determine the record size yet,
+				// so we just add this stuff
+				fragmentedHeaders++;
+				head = tail = new SSL_DataBlock( data, length, MIN_ALLOC_SIZE );
+				currentSize += length;
+				expectedSize = -1; // special meaning
+				break;
+				}
+
+			// get the expected length of this record
+			if ( !computeExpectedSize( data, length ) )
+				{
+				return false;
+				}
+
+			assert( neededSize <= expectedSize ); // TBR
+			assert( tail == 0 );
+
+			if ( length > expectedSize )
+				{
+				// no fragmentation -> no memory-reallocation
+				// we have additional data pending
+				hasPendingData = true;
+				sslEndpoint->DoDeliver( expectedSize, data );
+				length -= expectedSize;
+				data   += expectedSize;
+				expectedSize = -1;
+				}
+			else if ( length == expectedSize )
+				{
+				// no fragmentation -> no memory-reallocation
+				// no additional data pending
+				hasPendingData = false;
+				sslEndpoint->DoDeliver( expectedSize, data );
+				length -= expectedSize;
+				data   += expectedSize;
+				expectedSize = -1;
+				break;
+				}
+			else
+				{
+				// first fragment of a record
+				head = tail = new SSL_DataBlock( data, length, MIN_ALLOC_SIZE );
+				currentSize += length;
+				break;
+				}
+			}
+		else // !Head
+			{
+			// we already have some data, so add the current segment
+
+			// special case
+			if ( expectedSize < 0 )
+				{
+				// we don't know the expected size of this record yet
+				if ( currentSize + length >= neededSize )
+					{
+					// now we can determine the expected size
+
+					// the header has been fragmented, so we have to reassemble it
+					uint8 Header[neededSize];
+					memcpy( Header, head->data, head->len );
+					memcpy( Header + head->len, data, neededSize - head->len );
+					if ( !computeExpectedSize( Header, neededSize ) )
+						{
+						// since (neededSize <= MIN_ALLOC_SIZE), we free only head
+						delete head;
+						head = tail = NULL;
+						return false;
+						}
+
+					assert( neededSize <= expectedSize ); // TBR
+					// no break, go on with this packet
+					}
+				else
+					{
+					// we still can't determine the expected size,
+					// so we just add the current fragment
+					addData( data, length );
+					break;
+					}
+				}
+
+			if ( currentSize + length == expectedSize )
+				{
+				// this is exactly the last segment of the record
+				hasPendingData = false;
+				// create a continuous data structure and call DoDeliver()
+				u_char* pBlock = NULL;
+				pBlock = assembleBlocks( data, length );
+				sslEndpoint->DoDeliver( expectedSize, pBlock );
+				delete pBlock;
+				expectedSize = -1;
+				break;
+				}
+			else if ( currentSize + length < expectedSize )
+				{
+				// another (middle) segment
+				if ( length <= MIN_FRAGMENT_SIZE )
+					{
+					sslEndpoint->conn->Weird( "SSLProxy: Excessive small TCP Segment!" );
+					}
+
+				addData( data, length );
+				break;
+				}
+			else
+				{
+				// this is the last fragment of the current record,
+				// but there's more data in this segment
+				int deltaSize = expectedSize - currentSize;
+				hasPendingData = true;
+				// create a continuous data structure and call DoDeliver()
+				u_char* pBlock = NULL;
+				pBlock = assembleBlocks( data, deltaSize );
+				sslEndpoint->DoDeliver( expectedSize, pBlock );
+				delete pBlock;
+				expectedSize = -1;
+
+				// process the rest
+				length -= deltaSize;
+				data   += deltaSize;
+				}
+			}
+		} // while
+
+	return true;
+	}
+
+
+/*!
+ * This function is called internally by addSegment(), and add's a new SSL
+ * record fragment to the internally used list of SSL_DataBlocks. Note that
+ * the data will be copied!
+ *
+ * \param data   pointer to the data that will be added
+ * \param length length of the data that will be added
+ */
+
+inline void SSL_RecordBuilder::addData( u_char* data, int length )
+	{
+	fragmentCounter++;
+
+	// check if there's some space left in the last datablock
+	int bytesLeft = tail->size - tail->len;
+	if ( bytesLeft > 0 )
+		{
+		// there's some space left in the last data block
+		if ( bytesLeft >= length )
+			{
+			// we can store all bytes in the last data block
+			memcpy( tail->data + tail->len, data, length );
+			tail->len   += length;
+			currentSize += length;
+			}
+		else
+			{
+			// we cannot store all bytes in the last data block,
+			// so we also need to add a new one
+			memcpy( tail->data + tail->len, data, bytesLeft );
+			tail->len = tail->size;
+			currentSize += length;
+			data   += bytesLeft;
+			length -= bytesLeft;
+			tail->next = new SSL_DataBlock( data, length, MIN_ALLOC_SIZE );
+			tail = tail->next;
+			}
+		}
+	else
+		{
+		// last data block is full
+		tail->next = new SSL_DataBlock( data, length, MIN_ALLOC_SIZE );
+		tail = tail->next;	
+		currentSize += length;
+		}
+	}
+
+/*!
+ * This function is called internally by addSegment(), whenever a SSL record
+ * has been fully received. It creates a single data block from the list of
+ * SSL record fragments while freeing them.
+ *
+ * \param data   pointer to the last SSL record fragment
+ * \param length size of the last SSL record fragment
+ *
+ * \return pointer to a data block which contains the reassembled SSL record
+ */
+
+u_char* SSL_RecordBuilder::assembleBlocks( u_char* data, int length )
+	{
+	// we don't store the last SSL record fragment in a DataBlock,
+	// instead we get it directly as parameter
+	u_char* dataptr = new u_char[currentSize + length];
+	u_char* nextseg = dataptr;
+	SSL_DataBlock* idx = head;
+	SSL_DataBlock* rm;
+	uint allocCounter = 0;
+	while ( idx )
+		{
+		allocCounter++;
+		memcpy( nextseg, idx->data, idx->len );
+		nextseg += idx->len;
+		rm = idx;
+		idx = idx->next;
+		delete rm;
+    	}
+	// the last fragment isn't stored in a datablock
+    memcpy( nextseg, data, length );
+
+	// the first and last fragments aren't counted
+	fragmentCounter += 2;
+
+	// update statistics
+	if ( allocCounter > maxAllocCount )
+		{
+		maxAllocCount = allocCounter;
+		}
+	if ( fragmentCounter > maxFragmentCount )
+		{
+		maxFragmentCount = fragmentCounter;
+		}
+
+	fragmentCounter = 0;
+	currentSize = 0;
+	head = tail = NULL;
+
+	return dataptr;
+	}
+
+/*!
+ * This method is called internally by computeExpectedSize(), when the SSL
+ * record format has not been determined yet. It tries to do so by using
+ * heuristics, since there's no definitive way to distinguish SSLv2 vs. SSLv3
+ * record headers.
+ *
+ * \param data   pointer to a data block containing the SSL record to analyze
+ * \param length length of the SSL record to analyze, has to be >= neededSize!
+ *
+ * \return
+ *         -  2 for SSLv2 record format
+ *         -  3 for SSLv3 record format
+ *         - -1 if an error occurred
+ */
+
+int SSL_RecordBuilder::analyzeSSLRecordFormat( u_char* data, int length )
+	{
+	// we have to use heuristics for this one
+	assert( length >= neededSize );
+
+	bool found_ssl3x  = 0;
+	bool found_ssl2x  = 0;
+
+	//SSLv3x-check
+	SSL3_1_ContentType ct = SSL3_1_ContentType((uint8)(*data));
+	switch (ct)
+		{
+		case SSL3_1_TYPE_CHANGE_CIPHER_SPEC:
+		case SSL3_1_TYPE_ALERT:
+		case SSL3_1_TYPE_HANDSHAKE:
+		case SSL3_1_TYPE_APPLICATION_DATA:
+			{
+			sslEndpoint->sslVersion = ((data[1]) << 8 ) | data[2];
+			if ( sslEndpoint->sslVersion == (uint16) SSL_ConnectionProxy::SSLv30 ||
+				 sslEndpoint->sslVersion == (uint16) SSL_ConnectionProxy::SSLv31 )
+				{
+				found_ssl3x = true;
+				}
+			break;
+			}
+		}
+
+	// SSLv2 check
+    // we look for CLIENT-HELLOs, SERVER-HELLOs and ERRORs
+	u_char* pContents = data;
+	uint offset = 0;
+	uint16 size = 0;
+	if ( (data[0] & 0x80) > 0 )
+		{
+		// we have a two-byte record header
+		offset = 2;
+		size = (((data[0] & 0x7f) << 8) | data[1]) + 2;
+ 		}
+	else
+		{
+		// we have a three-byte record header
+		offset = 3;
+		size = (((data[0] & 0x3f) << 8) | data[1]) + 3;
+		}
+	pContents += offset;
+	
+	switch ((SSLv2_MessageTypes) pContents[0])
+		{
+		case SSLv2_MT_ERROR:
+			{
+				if ( size == SSLv2_ERROR_RECORD_SIZE + offset) 
+				{
+					found_ssl2x = true;
+					sslEndpoint->sslVersion = (uint16) SSL_ConnectionProxy::SSLv20;
+				}
+				break;
+			}
+		case SSLv2_MT_CLIENT_HELLO:
+			{
+			sslEndpoint->sslVersion = (uint16) (pContents[1] << 8 ) | pContents[2];
+			if ( sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv20 ||
+				 sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv30 ||
+				 sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv31 )
+				{
+				found_ssl2x = true;
+				}
+			break;
+			}
+		case SSLv2_MT_SERVER_HELLO:
+			{
+			sslEndpoint->sslVersion = (uint16) (pContents[3] << 8 ) | pContents[4];
+			if ( sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv20 ||
+				 sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv30 ||
+				 sslEndpoint->sslVersion == SSL_ConnectionProxy::SSLv31 )
+				{
+				found_ssl2x = true;
+				}
+			break;
+			}
+		}
+	
+	// consistency checks
+	if ( (found_ssl3x || found_ssl2x) == false )
+		{
+		sslEndpoint->conn->Weird( "SSLProxy: Could not determine SSL version!" );
+		return -1;
+		}
+
+	if ( (found_ssl3x && found_ssl2x) == true )
+		{
+		sslEndpoint->conn->Weird( "SSLProxy: Found ambigous SSL version!" );
+		return -1;
+		}
+
+	if ( found_ssl2x )
+		{
+		return 2;
+		}
+	else
+		{
+		return 3;
+		}
+	}
+
+/*!
+ * This method is called internally by addSegment() to determine the expected
+ * size of a SSL record.
+ *
+ * \param data   pointer to the SSL record to analyze
+ * \param length length of the SSL record to analyze
+ *
+ * \return true if succesfull, false otherwise
+ */
+
+bool SSL_RecordBuilder::computeExpectedSize( u_char* data, int length )
+	{
+	if ( sslEndpoint->sslRecordVersion < 0 )
+		{
+		// we don't know the ssl record format yet, so we try to find out
+		sslEndpoint->sslRecordVersion = analyzeSSLRecordFormat( data, length );
+
+		if ( sslEndpoint->sslRecordVersion != 2 &&
+		     sslEndpoint->sslRecordVersion != 3 )
+			{
+			// we could not determine the ssl record version
+			return false;
+			}
+		}
+
+	// get the expected length of this record
+	if ( sslEndpoint->sslRecordVersion == 2 )
+		{
+		if ( (data[0] & 0x80) > 0 )
+			{
+			// we have a two-byte record header
+			expectedSize = (((data[0] & 0x7f) << 8) | data[1]) + 2;
+			}
+		else
+			{
+			//we have a three-byte record header
+			expectedSize = (((data[0] & 0x3f) << 8) | data[1]) + 3;
+			}
+		}
+	else if ( sslEndpoint->sslRecordVersion == 3 )
+		{
+		expectedSize = ((data[3] << 8) | data[4]) + 5;
+		}
+
+	if ( expectedSize < neededSize )
+		{
+		// this should never happen (otherwise: UNTESTED)
+		sslEndpoint->conn->Weird( "SSLProxy: expectedSize < neededSize in RecordBuilder!" );
+		return false;
+		}
+
+	return true;
+	}
+
+
+// --- SSL_Connection_Proxy ---------------------------------------------------
+
+bool SSL_ConnectionProxy::bInited = false;
+
+SSL_ConnectionProxy::SSL_ConnectionProxy( NetSessions* s,
+								   HashKey* k,
+								   double t,
+								   const ConnID* id,
+								   const struct tcphdr* tp)
+: TCP_Connection(s, k, t, id, tp)
+	{
+	sSLv2Interpreter = new SSLv2_Interpreter(this);
+	sSLv3xInterpreter = new SSLv3_Interpreter(this);
+	sSLInterpreter = NULL;
+	bPassThrough = false;
+	if ( !bInited )
+		{
+		BuildCipherDict();
+		bInited = true;
+		}
+	}
+
+SSL_ConnectionProxy::~SSL_ConnectionProxy()
+	{
+	delete sSLv2Interpreter;
+	delete sSLv3xInterpreter;
+	}
+
+void SSL_ConnectionProxy::BuildEndpoints()
+	{
+	orig = new SSL_ProxyEndpoint(this, 1);
+	resp = new SSL_ProxyEndpoint(this, 0);
+	}
+
+void SSL_ConnectionProxy::Init()
+	{
+	// call the Init() menthod of the base class
+	TCP_Connection::Init();
+
+	// now init the 2 interpreters
+	sSLv2Interpreter->Init();
+	sSLv3xInterpreter->Init();
+	}
+
+void SSL_ConnectionProxy::Done()
+	{
+	TCP_Connection::Done();
+	}
+
+void SSL_ConnectionProxy::BuildCipherDict()
+	{
+	for ( int idx = 0; idx < SSL_CipherSpecs_Count; idx++ )
+		{
+		HashKey h( (uint32) SSL_CipherSpecs[idx].identifier );
+		SSL_CipherSpecDict.Insert(&h, &SSL_CipherSpecs[idx]);
+		//printf( "Adding Cipherspec 0x%X...\n", SSL_CipherSpecs[idx].identifier );
+		}
+	}
+
+void SSL_ConnectionProxy::NewSSLRecord( TCP_Endpoint* endp,
+										int len,
+										u_char* data )
+	{
+
+	// this is to extract only SSLv2 traffic
+	if ( recordSSLv2Traffic )
+		{
+		uint16 sslVersion = 0;
+		if ( (data[0] & 0x80) > 0 )
+			{
+			// we have a two-byte record header
+			sslVersion = (data[3] << 8) | data[4];
+ 			}
+		else
+			{
+			// we have a three-byte record header
+			sslVersion = (data[4] << 8) | data[5];
+			}
+
+		if ( !((SSL_ProxyEndpoint*)endp)->IsSSLv2Record() ||
+			 sslVersion != SSL_ConnectionProxy::SSLv20 )
+			{
+			SetSkip(1);
+			SetRecordPackets(0);
+			SetRecordContents(0);
+			// FIXME: Could do memory cleanup here
+			return;
+			}
+		else
+			{
+			// no analysis - only recording
+			SetSkip(1);
+			return;
+			}
+		}
+
+	if ( !bPassThrough )
+		{
+		if ( !((SSL_ProxyEndpoint*)endp)->IsSSLv2Record() )
+			{
+			//it's TLS or SSLv3, so we are done...
+			sSLInterpreter = sSLv3xInterpreter;
+			bPassThrough = true;
+			// tell the other record builder we have SSLv3x
+			((SSL_ProxyEndpoint*)endp->peer)->sslRecordVersion = 3;
+			DoDeliver(endp, 0, 0, len, data);
+			}
+		else
+			{
+			//o.k., we have a SSLv2 record...
+			//check, whether it's the first or second one we see...
+			if ( ((SSL_ProxyEndpoint*)orig)->VersionRecognized() &&
+				((SSL_ProxyEndpoint*)resp)->VersionRecognized() )
+				{
+				//Second record we see.
+				//O.K. Both Endpoints Recognized the version.
+				//So this needs to be an SSLv2-Connection...
+				sSLInterpreter = sSLv2Interpreter;
+				bPassThrough = true;
+				DoDeliver(endp, 0, 0, len, data);
+				}
+			else
+				{
+				//First record we see.
+				//The next one may be SSLv2 or SSLv3x, we don't know yet...
+				sSLInterpreter = sSLv2Interpreter;
+				if ( ((SSL_ProxyEndpoint*)endp)->sslVersion == SSLv20 )
+					{
+					// the client supports only SSLv2, so we're done
+					bPassThrough = true;
+					((SSL_ProxyEndpoint*)(endp->peer))->sslRecordVersion = 2;
+					((SSL_ProxyEndpoint*)(endp->peer))->sslVersion = SSLv20;
+					DoDeliver(endp, 0, 0, len, data);
+					}
+				else
+					{
+					bPassThrough = false;
+					DoDeliver(endp, 0, 0, len, data);
+					//transfer the state of the SSLv2-Interpreter to the state
+					//of the SSLv3x-Interpreter...
+					if ( ((SSLv2_Interpreter*)sSLInterpreter)->ConnState() == CLIENT_HELLO_SEEN )
+						{
+						((SSLv3_Interpreter*)sSLv3xInterpreter)->SetState(SSL3_1_STATE_CLIENT_HELLO_SENT);
+						}
+					}
+				}
+			}	
+		}
+	else
+		{
+		DoDeliver(endp, 0, 0, len, data);
+		}
+	}
+	
+void SSL_ConnectionProxy::DoDeliver(TCP_Endpoint* endp, double t,
+			int seq, int len, u_char* data)
+	{
+	if ( IsOrig(endp) )
+		{
+		sSLInterpreter->Orig()->Deliver(t, seq, len, data);
+		}
+	else
+		{
+		sSLInterpreter->Resp()->Deliver(t, seq, len, data);
+		}
+	}
+
+void SSL_ConnectionProxy::printStats()
+	{
+	printf( "SSL_ConnectionProxy::totalPackets = %u\n", totalPackets );
+	printf( "SSL_ConnectionProxy::totalRecords = %u\n", totalRecords );
+	printf( "SSL_ConnectionProxy::nonSSLConnections = %u\n", nonSSLConnections );
+	}
+	
+
+void SSL_ConnectionProxy::Weak( const char* name )
+	{
+	if ( conn_weak )
+		{
+		Event(conn_weak, name);
+		}
+	else
+		{
+		fprintf(stderr, "%.06f weak: %s\n", network_time, name);
+		}
+	}
+
+// --- SSL_ProxyEndpoint ------------------------------------------------------
+
+SSL_ProxyEndpoint::SSL_ProxyEndpoint( TCP_Connection* arg_conn, int is_orig )
+	: TCP_EndpointContents( arg_conn, is_orig )
+	{
+	sslRecordBuilder = new SSL_RecordBuilder( this );
+	bVersionRecognized = false;
+	bIsSSLv2Record = false;
+
+	sslRecordVersion = -1; // -1 means we don't know yet
+	sslVersion       =  0; // 0 means we don't know yet
+	}
+
+SSL_ProxyEndpoint::~SSL_ProxyEndpoint()
+	{
+	delete sslRecordBuilder;
+	}
+
+bool SSL_ProxyEndpoint::isDataPending()
+	{
+	return sslRecordBuilder->isDataPending();
+	}
+
+void SSL_ProxyEndpoint::Deliver(double t, int seq, int len, u_char* data)
+	{
+	SSL_ConnectionProxy::totalPackets++;
+
+	// here comes our tcp segment data
+
+	int ack = AckSeq() - StartSeq();
+	int top_seq = seq + len;
+	
+	if ( top_seq <= ack )
+		{
+		//There is no new data in this packet.
+		//(we already saw the data in this packet)
+		return;
+		}
+		
+	if ( len <= 0 || skip_deliveries )
+		{
+		return;
+		}
+		
+	// no further processing if we have a partial connection
+	if (state == TCP_PARTIAL || peer->state == TCP_PARTIAL)
+		{
+		conn->Weird( "SSL: Skipping partial connection!" );
+		conn->SetSkip(1);
+		conn->SetRecordPackets(0);
+		return;
+		}
+	
+	if ( !sslRecordBuilder->addSegment( data, len ) )
+		{
+		// the RecordBuilder failed to determine the SSL record version,
+		// so we can't analyze this connection any further
+		SSL_ConnectionProxy::nonSSLConnections++;
+		conn->Weird( "SSL: Skipping connection (not an SSL connection?!)!" );
+		conn->SetSkip(1);
+		conn->SetRecordPackets(0);
+		return;
+		}
+
+	}
+
+void SSL_ProxyEndpoint::DoDeliver( int len, u_char* data )
+	{
+	// this is called by the RecordBuilder with a complete SSL record
+	SSL_ConnectionProxy::totalRecords++;
+
+	bIsSSLv2Record = ( sslRecordVersion == 2 );
+	bVersionRecognized = true;
+	((SSL_ConnectionProxy*)conn)->NewSSLRecord(this, len, data);
+	}
+
+bool SSL_ProxyEndpoint::IsSSLv2Record()
+	{
+	return bIsSSLv2Record;
+	}
+	
+bool SSL_ProxyEndpoint::VersionRecognized()
+	{
+	return bVersionRecognized;
+	}
+	
diff -uNr bro-pub-0.8a41/SSLProxy.h bro-pub-0.841-ssl/SSLProxy.h
--- bro-pub-0.8a41/SSLProxy.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLProxy.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,300 @@
+// -----------------------------------------------------
+// SSL Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef SSLPROXY_H
+#define SSLPROXY_H
+
+#include "TCP.h"
+#include "SSLInterpreter.h"
+
+// --- forward declarations ---------------------------------------------------
+
+class SSL_Interpreter;
+class SSL_RecordBuilder;
+class SSL_ProxyEndpoint;
+
+// --- class SSL_DataBlock ----------------------------------------------------
+
+/*!
+ * \brief This class is used to store a block of data on the heap, which is
+ *        allocated and copied by the constructor, and freed by the destructor.
+ *
+ * It is mainly used by the SSL_RecordBuilder to store the received data. To
+ * reduce heap operations (HeapOps), which can be quite expensive, it is
+ * possible to let the constructor allocate a minimum heap block size. The
+ * class members keep track of how much data has been allocated and how much of
+ * it has been used. Plus, there's a pointer to the next SSL_DataBlock, for
+ * easy creation of a single-linked list.
+ */
+
+class SSL_DataBlock
+{
+	public:
+	int len;             ///< The <b>used</b> size of the reserved heap block.
+	int size;            ///< The <b>allocated</b> size of the reserved heap block.
+	u_char* data;        ///< Pointer to the allocated heap block.
+	SSL_DataBlock* next; ///< Pointer to the next SSL_Datablock in the chain.
+
+	SSL_DataBlock( u_char* data, int len, int min_len = 0 );
+
+	/*!
+	 * The destructor will free the allocated data block.
+	 */
+	~SSL_DataBlock() { delete data; }
+
+	void toStream( FILE* stream ) const;
+	char* toString() const;
+};
+
+// --- class SSL_RecordBuilder ------------------------------------------------
+
+/*!
+ * \brief This class is used to reassemble SSL records from a stream of data.
+ *
+ * It supports both SSLv2 and SSLv3 record formats at the same time. The record
+ * builder has been designed to be robust, efficient and hard to attack. To add
+ * a segments of data, call addSegment(). Whenever a SSL record has been
+ * reassembled, the DoDeliver() function of the corresponding SSL_ProxyEndpoint
+ * will be called.
+ *
+ * Two forms of attack have been taken into consideration:
+ * -# The "fake size" attack, where the actual size of the SSL record is much
+ *    smaller then the size given in the record header. This way, an attacker
+ *    could force Bro to allocate a huge amount of memory and make it crash.
+ * -# The "small fragment" attack, where an attacker sends huge SSL records
+ *    in very small (1 byte or so) TCP segments. This could lead to a huge
+ *    amount of very small memory blocks allocated by Bro. After the last byte
+ *    of an SSL record has been received, all allocated blocks have to be
+ *    freed. Freeing something like 32K blocks of memory can be quite expensive,
+ *    so packet drops may occur, which could prevent Bro from detecting an
+ *    attacker.
+ *
+ * The current implementation always allocates a minimum size of data on the
+ * heap, which is MIN_ALLOC_SIZE. The processed SSL record fragments are stored
+ * in a single-linked list of type SSL_DataBlock.
+ *
+ * The following assumptions are made:
+ * - neededSize <= min( expectedSize )
+ * - neededSize <= MIN_ALLOC_SIZE, so the data needed to determine the SSL
+ *   record version fits in one SSL_DataBlock
+ */
+
+class SSL_RecordBuilder
+{
+
+	protected:
+
+	SSL_DataBlock* head;  ///< pointer to the first element in the linked list of SSL_DataBlocks
+	SSL_DataBlock* tail;  ///< pointer to the last element in the linked list of SSL_DataBlocks
+	SSL_ProxyEndpoint*  sslEndpoint; ///< pointer to the containing SSL_ProxyEndpoint
+	int  expectedSize;    ///< expected size of SSLv2 record including header
+	int  currentSize;     ///< current bytes stored in data blocks (that is, processed size of actual record)
+	int  neededSize;      ///< min. size in bytes so that the length of the current record can be determinded
+	bool hasPendingData;  ///< true if there's data following in the current tcp segment
+	uint fragmentCounter; ///< counter for the number of tcp segments for the current record
+
+	public:
+
+	static const uint MIN_ALLOC_SIZE    = 16;  ///< min. size of memory to alloc
+	static const uint MIN_FRAGMENT_SIZE = 100; ///< min. size of a middle TCP Segment
+	static uint maxAllocCount;                 ///< max. number of allocated data blocks for an instance of a reassembler
+	static uint maxFragmentCount;              ///< max. number of fragments for a ssl record
+	static uint fragmentedHeaders;             ///< counter for the number of fragmented headers (header=neededSize)
+
+	SSL_RecordBuilder( SSL_ProxyEndpoint* sslEndpoint );
+	~SSL_RecordBuilder();
+
+	bool addSegment( u_char* data, int length );
+	/*!
+     * Calls this method to see if there's currently data in the record builder pending.
+     * \return true if there's data pending, false otherwise
+     */
+	bool isDataPending() { return hasPendingData; };
+	
+	protected:
+
+	u_char* assembleBlocks( u_char* data, int length );
+	int analyzeSSLRecordFormat( u_char* data, int length );
+	bool computeExpectedSize  ( u_char* data, int length );
+	void addData( u_char* data, int length );
+
+	// obsolete ?!
+	//int  getMissingDataSize() { return expectedSize - currentSize; };
+	//flush()
+};
+
+
+// --- class SSL_ConnectionProxy ----------------------------------------------
+
+/** This class represents an SSL_Connection with two SSL_ConnectionEndpoints.
+ * Note, that this class acts as a proxy, because there are different versions
+ * of the SSL protocol in use and you don't know in advance which SSL version 
+ * really will be used. This depends on the first two messages of the SSL handshake
+ * process. Because Bro offers no possibility for switching connections we 
+ * decided only to inherit this proxy from TCP_Connection.
+ * The different SSL versions are implemented in classed derived from
+ * SSL_Interpreter/SSL_InterpreterEndpoint and so, we can easily switch the flow
+ * of data to the appropriate SSL Interpreter.
+ * Currently, we support SSL Version 2.0 and 3.0/3.1(TLS)(@see SSLv2_Interpreter and @see
+ * SSLv3_Interpreter).
+ * This class holds an instance of both SSLv2- and SSLv3_Interpreter. The version
+ * of the SSL that is used for a connection is negotiated within the first 
+ * two records (SSL messages): client hello and server hello. 
+ * So after scanning this two records (which is mainly done in @see SSL_RecordBuilder and 
+ * @see SSL_ProxyEndpoint) and determing the versions, it is clear which
+ * SSL version will be used for the succeding SSL records. From now
+ * on, they can be directly passed through to the appropriate SSL_Interpreter.
+ */
+class SSL_ConnectionProxy: public TCP_Connection
+{
+	public:
+
+	static uint totalPackets;      ///< counter for total ssl packets seen
+	static uint totalRecords;      ///< counter for total ssl records seen
+	static uint nonSSLConnections; ///< counter for connections where we couldn't reassemble a ssl record
+
+	static const bool recordSSLv2Traffic = false; ///< if true, only recording of SSLv2 connections is done (no analysis)
+
+	static bool bInited;
+
+	enum SSL_Versions
+	{
+		SSLv20 = 0x0002,
+		SSLv30 = 0x0300,
+		SSLv31 = 0x0301  // = TLS 1.0
+	};
+
+	SSL_ConnectionProxy( NetSessions* s,
+							HashKey* k,
+							double t,
+							const ConnID* id,
+							const struct tcphdr* tp);
+	~SSL_ConnectionProxy();
+	
+	/* This method is called from the corresponding SSL_ProxyEndpoint to
+	 * deliver the data to the SSL_ProxyConnection. It decides which
+	 * SSL_Interpreter (Version 2 or Version 3x) gets the record or
+	 * directly passes it through, if it's already clear which version
+	 * this SSL connection uses.
+	 * @param endp the sending endpoint
+	 * @param len length of SSL record
+	 * @param data the SSL record
+	 */
+	void NewSSLRecord( TCP_Endpoint* endp, int len, u_char* data );
+
+	/* Builds up and initialises the corresponding SSL_ProxyEndpoints.
+	 */
+	void BuildEndpoints();
+	
+	/* Called, when the connection is finished.
+	 */
+	void Done();
+	
+	/* Initialises the SSLv2- and SSLv3_Interpreters. 
+	 */
+	void Init();
+	
+	/* This method is used for passing messages to Bro that contain 
+	 * information about weaknesses in the choosen SSL encryption
+	 * (short keys, unverifyable certificates, ...)
+	 * @param name the name of the weakness
+	 */
+	void Weak(const char* name);
+
+	/* Prints out some statistics.
+	 */
+	static void printStats();
+
+protected:
+	bool bPassThrough; ///< whether it is clear which SSL version the connection will use
+
+	SSL_Interpreter* sSLv2Interpreter; ///< Interpreter for SSL version 2
+	SSL_Interpreter* sSLv3xInterpreter; ///< Interpreter for SSL version 3.0 and 3.1
+	SSL_Interpreter* sSLInterpreter; ///< Pointer to the interpreter currently in use
+	
+	/** Internally called from this class Deliver()-method.
+	 * It delivers the data to the correct corresponding 
+	 * SSL_InterpreterEndpoint.
+	 * @param endp the sending endpoint
+	 * @param t time, when the segment was received by bro (not used)
+	 * @param seq relative sequenze number (from Endpoint::start_seq) (not used)
+	 * @param len length of SSL record
+	 * @param data the SSL record
+	 */
+	void DoDeliver(TCP_Endpoint* endp, double t, 
+		int seq, int len, u_char* data);
+
+
+	/** This method initialises the dictionary where the SSL cipher specs are stored.
+	 * It needs only to be called once for a whole bro. @see SSLDefines.h
+     */
+	void BuildCipherDict();
+};
+
+// --- class SSL_ProxyEndpoint ------------------------------------------------
+
+/** This class represents an endpoint of a SSL_ConnectionProxy.
+ * It receives the new data (TCP segments) within the Deliver()-method, does
+ * some basic checks on the segment and passes it on to the SSL_RecordBuilder,
+ * which reassembles the segments into SSL records and determines the 
+ * versions of the records. If the SSL_RecordBuilder was able to determine 
+ * the versions of the records it delivers the reassembled records back tho this
+ * SSL_ProxyEndpoint by calling the DoDeliver()-method.
+ * The SSL_ProxyEndpoint then hands the record over to the corresponding
+ * SSL_ConnectionProxy by invoking it's NewSSLRecord()-method.
+ */
+class SSL_ProxyEndpoint: public TCP_EndpointContents
+{
+	protected:
+
+	bool bVersionRecognized; ///< False, if we haven't seen the first record of the connection of this endpoint yet
+	bool bIsSSLv2Record; ///< Was the first record of SSL version 2.0
+
+	public:
+	int sslRecordVersion; ///< record version of the first SSL record seen (set by SSL_ConnectionProxy and SSL_RecordBuilder)
+	uint16 sslVersion; ///< SSL version of the SSL record seen (set by SSL_RecordBuilder)
+
+	/* The constructor builds up and initialises the SSL_ProxyEndpoint.
+	 * @param arg_conn the corresponding TCP_Connection
+	 * @param is_orig whether this endpoint was the originator of the TCP_Connection
+	 */
+	SSL_ProxyEndpoint( TCP_Connection* arg_conn, int is_orig );
+	~SSL_ProxyEndpoint();
+	
+	/** Via this method, this SSL_ProxyEndpoint receives the
+	 * TCP segments. It is called in this endpoint's corresponding 
+	 * tcp reassembler(t_reassem) BlockInserted() method.
+	 * @param sender the sending endpoint
+	 * @param t time, when the segment was received by bro
+	 * @param seq relative sequenze number (from Endpoint::start_seq)
+	 * @param len length of TCP-Segment
+	 * @param data content of TCP-Segment
+	 */
+	void Deliver(double t, int seq, int len, u_char* data);
+	
+	/** This method is called by the corresponding SSL_RecordBuilder 
+	 * upon delivering a new reassembled SSL record.
+	 * @param len the length of the record
+	 * @param data the record
+	 */
+	void DoDeliver( int len, u_char* data );
+	
+	/* @return whether we have already seen the first record of the connection of this endpoint yet
+	 */
+	bool VersionRecognized();
+	
+	/* @return whether the first record was of SSL version 2.0
+	 */
+	bool IsSSLv2Record();
+	
+	/* @return whether the corresponding SSL_RecordBuilder has pending data
+	 */
+	bool isDataPending(); // should be inline
+	
+	SSL_RecordBuilder* sslRecordBuilder;
+
+};
+
+#endif
diff -uNr bro-pub-0.8a41/SSLv2.cc bro-pub-0.841-ssl/SSLv2.cc
--- bro-pub-0.8a41/SSLv2.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv2.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,1219 @@
+// -----------------------------------------------------
+// SSLv2 Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#include "SSLv2.h"
+#include "SSLv3.h"
+
+// --- Initalization of static variables --------------------------------------
+
+uint SSLv2_Interpreter::totalConnections       = 0;
+uint SSLv2_Interpreter::analyzedConnections    = 0;
+uint SSLv2_Interpreter::openedConnections      = 0;
+uint SSLv2_Interpreter::failedConnections      = 0;
+uint SSLv2_Interpreter::weiredConnections      = 0;
+uint SSLv2_Interpreter::totalRecords           = 0;
+uint SSLv2_Interpreter::clientHelloRecords     = 0;
+uint SSLv2_Interpreter::serverHelloRecords     = 0;
+uint SSLv2_Interpreter::clientMasterKeyRecords = 0;
+uint SSLv2_Interpreter::errorRecords           = 0;
+
+
+// --- SSLv2_Interpreter -------------------------------------------------------
+
+/*!
+ * The Constructor.
+ *
+ * \param proxy Pointer to the SSL_ConnectionProxy who created this instance.
+ */
+SSLv2_Interpreter::SSLv2_Interpreter( SSL_ConnectionProxy* proxy )
+: SSL_Interpreter(proxy)
+	{
+	totalConnections++;
+	records = 0;
+	bAnalyzedCounted = false;
+	connState = START;
+	pServerCipherSpecs = NULL;
+	pClientCipherSpecs = NULL;
+	bClientWantsCachedSession = false;
+	usedCipherSpec = (SSLv2_CipherSpec) 0;
+
+	pConnectionId       = NULL;
+	pChallenge          = NULL;
+	pSessionId          = NULL;
+	pMasterClearKey     = NULL;
+	pMasterEncryptedKey = NULL;
+	pClientReadKey      = NULL;
+	pServerReadKey      = NULL;
+	}
+
+/*!
+ * The Destructor.
+ */
+SSLv2_Interpreter::~SSLv2_Interpreter()
+	{
+	if ( connState != CLIENT_MASTERKEY_SEEN &&
+		 connState != CACHED_SESSION &&
+		 connState != START &&     // we only complain if we saw some data
+		 connState != ERROR_SEEN ) // connection should be closed if there has been an error record
+		{
+		failedConnections++;
+		// this can be very annoying
+		//Weird( "SSLv2: Connection handshake failure!" );
+		}
+
+	if ( connState != CLIENT_MASTERKEY_SEEN &&
+		 connState != CACHED_SESSION )
+		{
+		weiredConnections++;
+		// this can be very annoying
+		//Weird( "SSLv2: Connection handshake failure!" );
+		}
+
+	SAFE_DELETE( pServerCipherSpecs );
+	SAFE_DELETE( pClientCipherSpecs );
+
+	SAFE_DELETE( pConnectionId );
+	SAFE_DELETE( pChallenge );
+	SAFE_DELETE( pSessionId );
+	SAFE_DELETE( pMasterClearKey );
+	SAFE_DELETE( pMasterEncryptedKey );
+	SAFE_DELETE( pClientReadKey );
+	SAFE_DELETE( pServerReadKey );
+	}
+
+/*!
+ * This method implements SSL_Interpreter::BuildInterpreterEndpoints()
+ */
+void SSLv2_Interpreter::BuildInterpreterEndpoints()
+	{
+	orig = new SSLv2_Endpoint(this, 1);
+	resp = new SSLv2_Endpoint(this, 0);
+	}
+
+/*!
+ * This method prints some counters.
+ */
+void SSLv2_Interpreter::printStats()
+	{
+	// Debug Output: print some stats
+	printf( "SSLv2:\n" );
+	printf( "totalConnections    = %u\n", totalConnections );
+	printf( "analyzedConnections = %u\n", analyzedConnections );
+	printf( "openedConnections   = %u\n", openedConnections );
+	printf( "failedConnections   = %u\n", failedConnections );
+	printf( "weiredConnections   = %u\n", weiredConnections );
+
+	printf( "totalRecords            = %u\n", totalRecords );
+	printf( "clientHelloRecords      = %u\n", clientHelloRecords );
+	printf( "serverHelloRecords      = %u\n", serverHelloRecords );
+	printf( "clientMasterKeyRecords  = %u\n", clientMasterKeyRecords );
+	printf( "errorRecords            = %u\n", errorRecords );
+
+	printf( "SSL_RecordBuilder::maxAllocCount     = %u\n", SSL_RecordBuilder::maxAllocCount );	
+	printf( "SSL_RecordBuilder::maxFragmentCount  = %u\n", SSL_RecordBuilder::maxFragmentCount );
+	printf( "SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders );	
+	}
+
+/*!
+ * \return the current state of the ssl connection
+ */
+SSLv2_States SSLv2_Interpreter::ConnState()
+	{
+	return connState;
+	}
+
+/*!
+ * This method is called by SSLv2_Endpoint::Deliver(). It is the main entry
+ * point of this class. The header of the given SSLV2 record is analyzed and
+ * its contents are then passed to the corresponding analyzer method. After
+ * the record has been analyzed, the ssl connection state is updated.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 record
+ * \param data pointer to SSLv2 record to analyze
+ */
+void SSLv2_Interpreter::NewSSLRecord( SSL_InterpreterEndpoint* s,
+									int length,
+									u_char* data )
+	{
+	// update some counters
+	records++;
+	totalRecords++;
+	if ( !bAnalyzedCounted )
+		{
+		analyzedConnections++;
+		bAnalyzedCounted = true;
+		}
+
+	// we should see max. 4 cleartext records
+	if ( records == 5 )
+		{
+		// so this should never happen
+		Weird( "SSLv2: Saw more than 4 records, skipping connection..." );
+		proxy->SetSkip( 1 );
+		return;
+		}
+	
+	// SSLv2 record header analysis
+	uint32 recordLength = 0; // data length of SSLv2 record
+	bool isEscape = false;
+	uint8 padding = 0;
+	u_char* contents;
+
+	if ( (data[0] & 0x80) > 0 )
+		{
+		// we have a two-byte record header
+		recordLength = ((data[0] & 0x7f) << 8) | data[1];
+		contents = data + 2;
+		if ( recordLength + 2 != length )
+			{
+			// this should never happen, otherwise
+			// we have a bug in the SSL_RecordBuilder
+			Weird( "SSLv2: FATAL: recordLength doesn't match data block length!" );
+			connState = ERROR_REQUIRED;
+			proxy->SetSkip( 1 );
+			return;
+			}
+	    }
+    else
+		{
+		// we have a three-byte record header
+		recordLength = ((data[0] & 0x3f) << 8) | data[1];
+		isEscape = (data[0] & 0x40) != 0;
+		padding = data[2];
+		contents = data + 3;
+		if ( recordLength + 3 != length )
+			{
+			// this should never happen, otherwise
+			// we have a bug in the SSL_RecordBuilder
+			Weird( "SSLv2: FATAL: recordLength doesn't match data block length!" );
+			connState = ERROR_REQUIRED;
+			proxy->SetSkip( 1 );
+			return;
+			}
+
+		if ( padding == 0 && !isEscape )
+			{
+			Weird( "SSLv2: 3 Byte record header, but no escape, no padding!" );
+			}
+		}
+
+	if ( recordLength == 0 )
+		{
+		Weird( "SSLv2: Record length is zero (no record data)!" );
+		return;
+		}
+
+	if ( isEscape )
+		{
+		Weird( "SSLv2: Record has escape bit set (security escape)!" );
+		}
+
+	if  ( padding > 0 &&
+		  connState != CACHED_SESSION &&
+		  connState != CLIENT_MASTERKEY_SEEN )
+		{
+		Weird( "SSLv2 record with padding > 0 in cleartext!" );
+		}
+
+	// MISSING:	
+	//A final consistency check is done when a block cipher is used and the
+	//protocol is using encryption. The amount of data present in a record
+	//(RECORD-LENGTH))must be a multiple of the cipher's block size.
+	// If the received record is not a multiple of the cipher's block size then
+	//the record is considered damaged, and it is to be treated as if an
+	//"I/O Error" had occurred (i.e. an unrecoverable error is asserted and the connection is closed).
+
+	// basic state check
+	switch( connState )
+		{
+		case START:
+			// only CLIENT-HELLLOs allowed here
+			if ( contents[0] != SSLv2_MT_CLIENT_HELLO )
+				{
+				Weird( "SSLv2: First packet is not a CLIENT-HELLO!" );
+				analyzeRecord( s, recordLength, contents );
+				connState = ERROR_REQUIRED;
+    			break;
+				}
+			connState = ClientHelloRecord( s, recordLength, contents );
+		break;
+		case CLIENT_HELLO_SEEN:
+			// only SERVER-HELLOs or ERRORs allowed here
+			if ( contents[0] == SSLv2_MT_SERVER_HELLO )
+				{
+				connState = ServerHelloRecord( s, recordLength, contents );
+				}
+			else if ( contents[0] == SSLv2_MT_ERROR )
+				{
+				connState = ErrorRecord( s, recordLength, contents );
+				}
+			else
+				{
+				Weird( "SSLv2: State violation in CLIENT_HELLO_SEEN!" );
+				analyzeRecord( s, recordLength, contents );
+				connState = ERROR_REQUIRED;
+				}
+		break;
+		case NEW_SESSION:
+			// we expect a client master key
+			if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY )
+				{
+				connState = ClientMasterKeyRecord( s, recordLength, contents );
+				}
+			else if ( contents[0] == SSLv2_MT_ERROR )
+				{
+				connState = ErrorRecord( s, recordLength, contents );
+				}
+			else
+				{
+				Weird( "SSLv2: State violation in NEW_SESSION or encrypted record!" );
+				analyzeRecord( s, recordLength, contents );
+				connState = ERROR_REQUIRED;
+				}
+
+			SAFE_DELETE( pServerCipherSpecs );
+		break;
+		case CACHED_SESSION:
+			SAFE_DELETE( pServerCipherSpecs );
+			// no break here
+		case CLIENT_MASTERKEY_SEEN:
+			// if no error record, no further analysis
+			if (( contents[0] == SSLv2_MT_ERROR ) &&
+				( recordLength == SSLv2_ERROR_RECORD_SIZE ))
+				{
+				connState = ErrorRecord( s, recordLength, contents );
+				}
+			else
+				{
+				//So we finished the cleartext handshake.
+				//Skip all further data.
+
+				proxy->SetSkip(1);
+				openedConnections++;
+				proxy->SetSkip( 1 );
+
+				
+				/*
+				// we try to decode the next packet
+				int outlen;
+				uint8* decodedData;
+				decodeRecord( s, recordLength, contents, &outlen, &decodedData );
+				*/
+				}
+		break;
+		case ERROR_REQUIRED:
+			if ( contents[0] == SSLv2_MT_ERROR )
+				{
+				connState = ErrorRecord( s, recordLength, contents );
+				}
+			else
+				{
+				// we lost tracking: this should not happen
+				Weird( "SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!" );
+				analyzeRecord( s, recordLength, contents );
+				connState = ERROR_REQUIRED;
+				}
+		break;
+		case ERROR_SEEN:
+			// we don't have recoverable errors in cleartext phase,
+			// so we shouldn't see anymore packets
+			Weird( "SSLv2: Traffic after error record!" );
+			analyzeRecord( s, recordLength, contents );
+		break;
+		default:
+			// should NEVER happen
+			Weird( "SSLv2: Unknown state!" );
+		break;
+		}
+	}
+
+/*!
+ * This method is called whenever the connection tracking failed. It calls
+ * the corresponding analyzer method for the given SSLv2 record, but does not
+ * update the ssl connection state.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 record
+ * \param data pointer to SSLv2 record to analyze
+ */
+void SSLv2_Interpreter::analyzeRecord( SSL_InterpreterEndpoint* s, int length, u_char* data )
+	{
+	switch( data[0] )
+		{
+		case SSLv2_MT_ERROR:
+			//printf( "SSL_MT_ERROR\n" );
+			ErrorRecord( s, length, data );
+		break;
+		
+		case SSLv2_MT_CLIENT_HELLO:
+			//printf( "SSL_MT_CLIENT_HELLO\n" );
+			ClientHelloRecord( s, length, data );
+		break;
+
+		case SSLv2_MT_CLIENT_MASTER_KEY:
+			//printf( "SSL_MT_CLIENT_MASTER_KEY\n" );
+			ClientMasterKeyRecord( s, length, data );
+  		break;
+
+		case SSLv2_MT_SERVER_HELLO:
+			//printf( "SSL_MT_SERVER_HELLO\n" );
+			ServerHelloRecord( s, length, data );
+		break;
+
+		case SSLv2_MT_CLIENT_FINISHED:
+		case SSLv2_MT_SERVER_VERIFY:
+		case SSLv2_MT_SERVER_FINISHED:
+		case SSLv2_MT_REQUEST_CERTIFICATE:
+		case SSLv2_MT_CLIENT_CERTIFICATE:
+			// we shouldn't see this in cleartext
+			Weird( "SSLv2: Encrypted record type seems to be in cleartext!" );
+  		break;
+	
+		default:
+			// unknown record type
+			Weird( "SSLv2: Unknown record type or encrypted record!" );
+		break;
+		}
+	}
+
+/*!
+ * This method analyses a SSLv2 CLIENT-HELLO record.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 CLIENT-HELLO record
+ * \param data pointer to SSLv2 CLIENT-HELLO record to analyze
+ *
+ * \return the updated state of the current ssl connection
+ */
+SSLv2_States SSLv2_Interpreter::ClientHelloRecord( SSL_InterpreterEndpoint* s,
+												 int recordLength,
+												 u_char* recordData )
+	{
+	// this method gets the record's data (without the header)!
+	clientHelloRecords++;
+
+	// this message can only be generated by a client
+	if ( s != orig )
+		{
+		Weird( "SSLv2: CLIENT-HELLO record from server!" );
+		}
+
+	// there should not be any pending data in the SSLv2 reassembler,
+	// because the client should wait for a server response
+	if ( ((SSLv2_Endpoint*) s)->isDataPending() )
+		{
+		Weird( "SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!" );
+		}
+
+	// client hello min. header size check
+	if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE )
+		{
+		Weird( "SSLv2: CLIENT-HELLO is too small!" );
+		return ERROR_REQUIRED;
+		}
+
+	// extract the data of the client hello header
+	SSLv2_ClientHelloHeader ch;
+	ch.clientVersion    = (uint16) (recordData[1] << 8 ) | recordData[2];
+	ch.cipherSpecLength = (uint16) (recordData[3] << 8 ) | recordData[4];
+	ch.sessionIdLength  = (uint16) (recordData[5] << 8 ) | recordData[6];
+	ch.challengeLength  = (uint16) (recordData[7] << 8 ) | recordData[8];
+
+	// version check
+	if ( ch.clientVersion != SSL_ConnectionProxy::SSLv20 &&
+		 ch.clientVersion != SSL_ConnectionProxy::SSLv30 &&
+		 ch.clientVersion != SSL_ConnectionProxy::SSLv31 )
+		{
+		Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO");
+		return ERROR_REQUIRED;
+		}
+
+	// size consistency check
+	if ( ch.challengeLength +
+		 ch.cipherSpecLength +
+		 ch.sessionIdLength +
+		 SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength )
+		{
+		Weird("SSLv2: Size inconsistency in CLIENT-HELLO");
+		return ERROR_REQUIRED;
+		}
+
+	// The CIPHER-SPECS-LENGTH must be greater than zero and a multiple of 3.
+	if ( (ch.cipherSpecLength == 0) ||
+		 (ch.cipherSpecLength % 3 != 0))
+		{
+		Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO.");
+		return ERROR_REQUIRED;
+		}
+		
+	// The SESSION-ID-LENGTH must either be zero or 16.
+	if ( (ch.sessionIdLength != 0) &&
+		 (ch.sessionIdLength != 16))
+		{
+		Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO.");
+		}
+
+	// The CHALLENGE-LENGTH must be greater than or equal to 16 and less than or equal to 32.
+	if ( (ch.challengeLength < 16) ||
+		 (ch.challengeLength > 32))
+		{
+		Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO.");
+		}
+
+	// if decrypting, store the challenge
+	if ( ssl_store_key_material && ch.challengeLength <= 32 )
+		{
+		pChallenge = new SSL_DataBlock( (recordData +
+										SSLv2_CLIENT_HELLO_HEADER_SIZE +
+										ch.cipherSpecLength +
+										ch.sessionIdLength),
+										ch.challengeLength );
+		}
+
+	pSessionId = new SSL_DataBlock( (recordData +
+										SSLv2_CLIENT_HELLO_HEADER_SIZE +
+										ch.cipherSpecLength),
+										ch.sessionIdLength );
+
+	bClientWantsCachedSession = ( ch.sessionIdLength != 0 );
+
+	// cipher check
+	TableVal* currentCipherSuites =
+		analyzeCiphers( s, ch.cipherSpecLength, recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE );
+
+	//printf( "SSLv2: CLIENT-HELLO\n" );
+	//printf( "clientVersion = %hu\n", ch.clientVersion );
+	//printf( "cipherSpecLength = %hu\n", ch.cipherSpecLength );
+	//printf( "sessionIdLength = %hu\n", ch.sessionIdLength);
+	//printf( "challengeLength = %hu\n", ch.challengeLength);
+
+	//generate connection-attempt event
+	fire_ssl_conn_attempt( ch.clientVersion, currentCipherSuites );
+	
+	return CLIENT_HELLO_SEEN;
+	}
+
+/*!
+ * This method analyses a SSLv2 SERVER-HELLO record.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 SERVER-HELLO record
+ * \param data pointer to SSLv2 SERVER-HELLO record to analyze
+ *
+ * \return the updated state of the current ssl connection
+ */
+SSLv2_States SSLv2_Interpreter::ServerHelloRecord( SSL_InterpreterEndpoint* s,
+										 int recordLength,
+										 u_char* recordData )
+	{
+	serverHelloRecords++;
+	SSLv2_States nextState;
+	TableVal* currentCipherSuites = NULL;
+
+	// this message can only be generated by a server
+	if ( s != resp )
+		{
+		Weird( "SSLv2: SERVER-HELLO from client!" );
+		}
+
+	// server hello min. header size check
+	if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE )
+		{
+		Weird( "SSLv2: SERVER-HELLO is too small!" );
+		return ERROR_REQUIRED;
+		}
+	
+	// extract the data of the client hello header
+	SSLv2_ServerHelloHeader sh;
+	sh.sessionIdHit       = recordData[1];
+	sh.certificateType    = recordData[2];
+	sh.serverVersion      = (uint16) (recordData[3] << 8 ) | recordData[4];
+	sh.certificateLength  = (uint16) (recordData[5] << 8 ) | recordData[6];
+	sh.cipherSpecLength   = (uint16) (recordData[7] << 8 ) | recordData[8];
+	sh.connectionIdLength = (uint16) (recordData[9] << 8 ) | recordData[10];
+
+	// SSL version check
+	if ( sh.serverVersion != SSL_ConnectionProxy::SSLv20 )
+		{
+		Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO");
+		return ERROR_REQUIRED;
+		}
+
+	// size consistency check
+	if ( sh.certificateLength +
+		 sh.cipherSpecLength +
+		 sh.connectionIdLength +
+		 SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength )
+		{
+		Weird("SSLv2: Size inconsistency in SERVER-HELLO");
+		return ERROR_REQUIRED;
+		}
+
+	//The length of the CONNECTION-ID must be between 16 and 32 bytes, inclusive.
+	if ( (sh.connectionIdLength < 16) ||
+		 (sh.connectionIdLength > 32))
+		{
+		Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO");
+		}
+
+	// if decrypting, store the connection id
+	if ( ssl_store_key_material && sh.connectionIdLength <= 32 )
+		{
+		pConnectionId = new SSL_DataBlock( (recordData +
+											SSLv2_SERVER_HELLO_HEADER_SIZE +
+											sh.cipherSpecLength +
+											sh.certificateLength),
+											sh.connectionIdLength );
+		}
+
+	if ( sh.sessionIdHit != 0 )
+		{
+		// we're using a cached session
+
+		// there should not be any pending data in the SSLv2 reassembler,
+		// because the server should wait for a client response
+		if ( ((SSLv2_Endpoint*) s)->isDataPending() )
+			{
+			// but some SSL Implementations do this when using a cached session
+			//Weird( "SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (cached session)!" );
+			}
+
+		// consistency check for SESSION-ID-HIT
+		if ( !bClientWantsCachedSession )
+			{
+			Weird( "SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!" );
+			}
+
+		// If the SESSION-ID-HIT flag is non-zero then the CERTIFICATE-TYPE,
+		// CERTIFICATE-LENGTH and CIPHER-SPECS-LENGTH fields will be zero.
+		if (sh.certificateType != 0 ||
+			sh.certificateLength != 0 ||
+			sh.cipherSpecLength != 0)
+			{
+			Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO");
+			}
+		
+		// generate reusing-connection event
+		if ( pSessionId )
+			{
+			fire_ssl_conn_reused( pSessionId );
+			delete pSessionId;
+			pSessionId = NULL;
+			}
+
+		nextState = CACHED_SESSION;
+		}
+	else
+		{
+		// we're starting a new session
+
+		// there should not be any pending data in the SSLv2 reassembler,
+		// because the server should wait for a client response
+		if ( ((SSLv2_Endpoint*) s)->isDataPending() )
+			{
+			Weird( "SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!" );
+			}
+
+		// TODO: check certificate length ??? (zero - too small -- too big)
+		if ( sh.certificateLength == 0 )
+			{
+			Weird("SSLv2: No certificate in SERVER-HELLO!");
+			}
+
+		//The CIPHER-SPECS-LENGTH must be greater than zero and a multiple of 3.
+		if ( sh.cipherSpecLength == 0 )
+			{
+			Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!");
+			}
+		if ( sh.cipherSpecLength % 3 != 0 )
+			{
+			Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO");
+			return ERROR_REQUIRED;
+			}
+
+		// cipher check
+		currentCipherSuites =
+						analyzeCiphers( s,
+  						sh.cipherSpecLength,
+        				recordData + sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE );
+
+		nextState = NEW_SESSION;
+		}
+		
+	// check if at least one cipher is supported by the client
+	if ( pClientCipherSpecs && pServerCipherSpecs )
+		{
+		bool bFound = false;
+		for ( int idx = 0; idx < pClientCipherSpecs->len; idx += 3 )
+			{
+			for ( int jdx = 0; jdx < pServerCipherSpecs->len; jdx += 3 )
+				{
+				if ( memcmp( pClientCipherSpecs + idx,
+							 pServerCipherSpecs + jdx,
+							 3 ) == 0 )
+					{
+					bFound = true;
+					idx = pClientCipherSpecs->len;
+					break;
+					}
+				}
+			}
+	
+		if ( !bFound )
+			{
+			Weird( "SSLv2: Client's and server's CIPHER-SPECS don't match!" );
+			nextState = ERROR_REQUIRED;
+			}
+
+		delete pClientCipherSpecs;
+		pClientCipherSpecs = NULL;
+		}
+
+	// Certificate Analysis
+	if (( sh.certificateLength > 0 ) &&
+		( ssl_analyze_certificates != 0 ))
+		{
+		analyzeCertificate( s,
+							recordData + SSLv2_SERVER_HELLO_HEADER_SIZE,
+							sh.certificateLength,
+							sh.certificateType,
+							false );
+		}
+
+	//printf( "SSLv2: SERVER-HELLO\n" );
+	//printf( "sessionIdHit = %c\n", (uint8) sh.sessionIdHit );
+	//printf( "certificateType = %c\n", (uint8) sh.certificateType );
+	//printf( "serverVersion = %hu\n", (uint16) sh.serverVersion);
+	//printf( "certificateLength = %hu\n", (uint16) sh.certificateLength );
+	//printf( "cipherSpecLength = %hu\n", (uint16) sh.cipherSpecLength);
+	//printf( "connectionIdLength = %hu\n", (uint16) sh.connectionIdLength);
+
+
+	if ( nextState == NEW_SESSION )
+		{
+		//generate server-reply event
+		fire_ssl_conn_server_reply( sh.serverVersion, currentCipherSuites );
+		}
+	else if ( nextState == CACHED_SESSION )
+		{
+		//generate server-reply event
+		fire_ssl_conn_server_reply( sh.serverVersion, currentCipherSuites );
+		// generate a connection-established event with a dummy cipher suite,
+		// since we can't remember session information (yet)
+		// Note: A new session identifier is sent encrypted in SSLv2!
+		fire_ssl_conn_established( sh.serverVersion, 0xABCD );
+		}
+
+	return nextState;
+	}
+
+/*!
+ * This method analyses a SSLv2 CLIENT-MASTER-KEY record.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 CLIENT-MASTER-KEY record
+ * \param data pointer to SSLv2 CLIENT-MASTER-KEY record to analyze
+ *
+ * \return the updated state of the current ssl connection
+ */
+SSLv2_States SSLv2_Interpreter::ClientMasterKeyRecord( SSL_InterpreterEndpoint* s,
+											  int recordLength,
+											  u_char* recordData )
+	{
+	clientMasterKeyRecords++;
+	SSLv2_States nextState = CLIENT_MASTERKEY_SEEN;
+
+	// this message can only be generated by a client
+	if ( s != orig )
+		{
+		Weird( "SSLv2: CLIENT-MASTER-KEY from server!" );
+		}
+
+	// client master key min. header size check
+	if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE )
+		{
+		Weird( "SSLv2: CLIENT-MASTER-KEY is too small!" );
+		return ERROR_REQUIRED;
+		}
+
+	// extract the data of the client master key header
+	SSLv2_ClientMasterKeyHeader cmk;
+	cmk.cipherKind         = ((recordData[1] << 16) |
+							   recordData[2] << 8) |
+							   recordData[3];
+	cmk.clearKeyLength     = (uint16) (recordData[4] << 8 ) | recordData[5];
+	cmk.encryptedKeyLength = (uint16) (recordData[6] << 8 ) | recordData[7];
+	cmk.keyArgLength       = (uint16) (recordData[8] << 8 ) | recordData[9];
+
+	// size consistency check
+	if ( cmk.clearKeyLength +
+		 cmk.encryptedKeyLength +
+		 cmk.keyArgLength +
+		 SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength )
+		{
+		Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY");
+		return ERROR_REQUIRED;
+		}
+
+	// check if cipher is supported by the server
+	if ( pServerCipherSpecs )
+		{
+		bool bFound = false;
+		for ( int idx = 0; idx < pServerCipherSpecs->len; idx += 3 )
+			{
+			uint32 cipherSpec = ((pServerCipherSpecs->data[idx] << 16) |
+								  pServerCipherSpecs->data[idx+1] << 8) |
+								  pServerCipherSpecs->data[idx+2];
+
+			if ( cmk.cipherKind == cipherSpec )
+				{
+				bFound = true;
+				break;
+				}
+			}
+		
+		if ( !bFound )
+			{
+			Weird( "SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!" );
+			nextState = ERROR_REQUIRED;
+			}
+		else
+			{
+			nextState = CLIENT_MASTERKEY_SEEN;
+			}
+
+		delete pServerCipherSpecs;
+		pServerCipherSpecs = NULL;
+		}
+
+	// TODO: check if cipher has been advertised before
+
+	HashKey h(cmk.cipherKind);
+	SSL_CipherSpec* pCipherSpecTemp = NULL;
+	pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
+	if (!pCipherSpecTemp || !(pCipherSpecTemp->flags & SSL_FLAG_SSLv20) )
+		{
+		Weird( "SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!" );
+		}
+	else
+		{
+		// check for conistency of clearKeyLength
+		if ( ( cmk.clearKeyLength * 8 ) != pCipherSpecTemp->clearKeySize )
+			{
+			Weird( "SSLv2: Inconsistency of	 clearKeyLength in CLIENT-MASTER-KEY!" );
+			//nextState = ERROR_REQUIRED;
+			}
+
+		// TODO: check for consistency of encryptedKeyLength
+		// TODO: check for consistency of keyArgLength
+//		switch( cmk.cipherKind )
+//			{
+//			case SSL_CK_RC4_128_WITH_MD5:
+//			case SSL_CK_RC4_128_EXPORT40_WITH_MD5:
+//				if ( cmk.keyArgLength != 0 )
+//					{
+//					Weird( "SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!" );
+//					//nextState = ERROR_REQUIRED;
+//					}
+//			break;
+//			case SSL_CK_DES_64_CBC_WITH_MD5:
+//			case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5:
+//			case SSL_CK_RC2_128_CBC_WITH_MD5:
+//				case SSL_CK_IDEA_128_CBC_WITH_MD5:
+//			case SSL_CK_DES_192_EDE3_CBC_WITH_MD5:
+//				if ( cmk.keyArgLength != 8 )
+//					{
+//					Weird( "SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!" );
+//					}
+//			break;
+//			}
+		}
+
+	//printf( "clearKeyLength = %hu\n", (uint16) cmk.clearKeyLength );
+	//printf( "encryptedKeyLength = %hu\n", (uint16) cmk.encryptedKeyLength);
+	//printf( "keyArgLength = %hu\n", (uint16) cmk.keyArgLength);
+
+	// remember the used cipher spec
+	usedCipherSpec = (SSLv2_CipherSpec) cmk.cipherKind;
+
+	// if decrypting, store the clear key part of the master key
+	if ( ssl_store_key_material /*&& cmk.clearKeyLength == 11*/ )
+		{
+		pMasterClearKey = new SSL_DataBlock( (recordData +
+											  SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE),
+											  cmk.clearKeyLength );
+
+		pMasterEncryptedKey = new SSL_DataBlock( (recordData +
+												  SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE +
+												  cmk.clearKeyLength ),
+												  cmk.encryptedKeyLength );
+
+        /*
+		// print some debugging info
+		printf( "Started a new session:\n" );
+		printf( "CIPHER_SPEC:   0x%06X\n", usedCipherSpec );
+		printf( "CHALLENGE:     " );
+		pChallenge->toStream( stdout );
+		printf( "\n" );
+		printf( "CONNECTION-ID: " );
+		pConnectionId->toStream( stdout );
+		printf( "\n" );
+		printf( "CLEAR-KEY:     " );
+		pMasterClearKey->toStream( stdout );
+		printf( "\n" );
+		// The encryption block is formatted using block type 2 from PKCS#1
+		printf( "ENCRYPTED-KEY: " );
+		pMasterEncryptedKey->toStream( stdout );
+		printf( "\n" );
+
+		static bool bFirstOne = false;
+		if ( !bFirstOne )
+			{
+			bFirstOne = true;
+			FILE* dumpFile = fopen( "masterkey.dump", "wb" );
+			if ( dumpFile == NULL )
+				{
+				fprintf( stderr, "Error dumping Master Key" );
+				}
+			fwrite( pMasterEncryptedKey->data, 1, pMasterEncryptedKey->len, dumpFile );
+			fclose( dumpFile );
+			}
+		*/
+		}
+
+	if ( nextState == CLIENT_MASTERKEY_SEEN )
+		{
+		fire_ssl_conn_established( SSL_ConnectionProxy::SSLv20, cmk.cipherKind );
+		}
+
+	return nextState;
+	}
+
+
+/*!
+ * This method analyses a SSLv2 ERROR record.
+ *
+ * \param s Pointer to the endpoint which sent the record
+ * \param length length of SSLv2 ERROR record
+ * \param data pointer to SSLv2 ERROR record to analyze
+ *
+ * \return the updated state of the current ssl connection
+ */
+SSLv2_States SSLv2_Interpreter::ErrorRecord( SSL_InterpreterEndpoint* s,
+									int recordLength,
+									u_char* recordData )
+	{
+	errorRecords++;
+
+	if ( recordLength != SSLv2_ERROR_RECORD_SIZE )
+		{
+		Weird( "SSLv2: Size mismatch in Error Record!" );
+		return ERROR_REQUIRED;
+		}
+
+	SSLv2_ErrorRecord er;
+	er.errorCode = ( recordData[1] << 8 ) | recordData[2];
+	SSL3x_AlertLevel al = (SSL3x_AlertLevel) 255;
+
+	switch( er.errorCode )
+		{
+		case SSLv2_PE_NO_CIPHER:
+			// The client doesn't support a cipher which the server supports.
+			// only from client to server and not recoverable!
+			al = SSL3x_ALERT_LEVEL_FATAL;
+		break;
+		case SSLv2_PE_NO_CERTIFICATE:
+			// There's no certificate available.
+			if ( s == orig )
+				{
+				// from client to server: not recoverable
+				al = SSL3x_ALERT_LEVEL_FATAL;
+				}
+			else
+				{
+				// from server to client: recoverable
+				al = SSL3x_ALERT_LEVEL_WARNING;
+				}
+		break;
+		case SSLv2_PE_BAD_CERTIFICATE:
+			// The certificate was found bad.
+			if ( s == orig )
+				{
+				// from client to server: not recoverable
+				al = SSL3x_ALERT_LEVEL_FATAL;
+				}
+			else
+				{
+				// from server to client: recoverable
+				al = SSL3x_ALERT_LEVEL_WARNING;
+				}
+		break;
+		case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE:
+			// The certificate type is unsupported.
+			if ( s == orig )
+				{
+				// from client to server: not recoverable
+				al = SSL3x_ALERT_LEVEL_FATAL;
+				}
+			else
+				{
+				// from server to client: recoverable
+				al = SSL3x_ALERT_LEVEL_WARNING;
+				}
+		break;
+		default:
+			al = SSL3x_ALERT_LEVEL_FATAL;
+			//Weird( "SSLv2: Unknown error code in Error Record!" );
+			//return ERROR_SEEN;
+		break;
+		}
+
+	// fire an alert event
+	fire_ssl_conn_alert( SSL_ConnectionProxy::SSLv20, al, er.errorCode );
+	
+	return ERROR_SEEN;
+	}
+
+/*!
+ * This method analyses a set of SSLv2 cipher suites.
+ *
+ * \param s Pointer to the endpoint which sent the cipher suites
+ * \param length length of cipher suites
+ * \param data pointer to cipher suites to analyze
+ *
+ * \return a pointer to a Bro TableVal (of type cipher_suites_list) which contains 
+ *         the cipher suites list of the current analyzed record
+ */
+TableVal* SSLv2_Interpreter::analyzeCiphers( SSL_InterpreterEndpoint* s, int length, u_char* data )
+	{
+	if ( length > MAX_CIPHERSPEC_SIZE )
+		{
+		if ( s == orig )
+			{
+			Weird( "SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE" );
+			}
+		else
+			{
+			Weird( "SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE" );
+			}
+		}
+	else
+		{
+		// cipher specs are not too big
+		if ( ssl_compare_cipherspecs )
+			{
+			// store cipher specs for state analysis
+			if ( s == resp )
+				{
+				pServerCipherSpecs = new SSL_DataBlock( data, length );
+				}
+			else
+				{
+				pClientCipherSpecs = new SSL_DataBlock( data, length );
+				}
+			}
+		}
+
+	u_char*   pCipher = data;
+	bool      bExtractCipherSuite = false;
+	TableVal* pCipherTable = NULL;
+
+	// We only extract the cipher suite when the corresponding
+	// ssl events are defined (otherwise we do work for nothing
+	// and get a memory leak).
+	// FIXME: This check needs to be done only once!
+	if (( s == orig && ssl_conn_attempt ) ||
+        ( s == resp && ssl_conn_server_reply ))
+	{
+		pCipherTable = new TableVal( cipher_suites_list );	
+		bExtractCipherSuite = true;
+	}
+
+	for ( int idx = 0; idx < length; idx += 3 )
+		{
+		SSL_CipherSpec* pCurrentCipherSpec;
+		uint32 cipherSpecID = ((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2];
+
+		// check for unknown CHIPHER SPECS
+		HashKey h( cipherSpecID );
+		pCurrentCipherSpec = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup( &h );
+		if ( !pCurrentCipherSpec )
+			{
+			if ( s == orig )
+				{
+				Weird( "SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!" );
+				}
+			else
+				{
+				Weird( "SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!" );
+				}
+			}
+
+		// build the CIPHER SPEC table
+		if ( bExtractCipherSuite )
+			{
+			pCipherTable->Assign( new Val( idx / 3, TYPE_COUNT) ,
+								   new Val( cipherSpecID, TYPE_COUNT ));
+			}
+
+		pCipher += 3;
+		}
+
+	return pCipherTable;
+	}
+
+
+#ifdef SSLv2_EXPERIMENTAL_HACK
+// --- BEGIN EXPERIMENTAL HACK
+#include <openssl/md5.h>
+#include <openssl/rc4.h>
+void SSLv2_Interpreter::decodeRecord( SSL_InterpreterEndpoint* s,
+									int inlen,
+									u_char* indata,
+									int* outlen,
+									u_char** outdata )
+	{
+	// simple decoding test
+
+	if ( usedCipherSpec != SSL_CK_RC4_128_WITH_MD5 )
+		{
+		printf( "SSLv2: Can only decode SSLv2_CK_RC4_128_WITH_MD5\n" );
+		return;
+		}
+
+	// get the MASTER-KEY (manually)
+	// wrong order ?!?!?
+	unsigned char masterKey[16]=
+		{
+//		0xe5,0x8a,0x51,0xb9,0x43,0x5c,0x2d,0x82,
+//		0x99,0xae,0xd6,0x4f,0xb6,0xf2,0xa9,0xfb
+		0xfb,0xa9,0xf2,0xb6,0x4f,0xd6,0xae,0x99,
+		0x82,0x2d,0x5c,0x43,0xb9,0x51,0x8a,0xe5
+		};
+
+	// create the connection keys
+	// this has to be done once per connection
+
+	//KEY-MATERIAL-0 = MD5[ MASTER-KEY, "0", CHALLENGE, CONNECTION-ID ]
+	//KEY-MATERIAL-1 = MD5[ MASTER-KEY, "1", CHALLENGE, CONNECTION-ID ]
+
+	//CLIENT-READ-KEY = KEY-MATERIAL-0[0-15]
+	//CLIENT-WRITE-KEY = KEY-MATERIAL-1[0-15]
+
+	static bool bFirstTime = true;
+	static uint8 clientReadKey[16];
+	static uint8 serverReadKey[16];
+	static RC4_KEY clientReadKeyInternal;
+	static RC4_KEY serverReadKeyInternal;
+	if ( bFirstTime )
+		{
+		bFirstTime = false;
+
+		uint8 keyMaterial[49];
+		uint8* pDummy = keyMaterial;
+		memcpy( pDummy, masterKey, 16 );
+		pDummy += 17;
+		memcpy( pDummy, pChallenge->data, pChallenge->len );
+		pDummy += 16;
+		memcpy( pDummy, pConnectionId->data, pConnectionId->len );
+
+		keyMaterial[16] = '0';
+		MD5( keyMaterial, 49, clientReadKey );
+		RC4_set_key( &clientReadKeyInternal, 16, clientReadKey);
+	
+		keyMaterial[16] = '1';
+		MD5( keyMaterial, 49, serverReadKey );
+		RC4_set_key( &serverReadKeyInternal, 16, serverReadKey);
+		}
+
+	uint8 decodedStuff[inlen+1];
+	if ( s == orig )
+		{
+		// the message has been sent by the client
+		// decode it using the server's read key
+
+		RC4( &serverReadKeyInternal, inlen, indata, decodedStuff );
+		*outlen = inlen;
+
+		if ( ((SSLv2_Endpoint*)s)->sentRecords == 3 )
+			{
+			// should be client finish
+			}
+		else if (((SSLv2_Endpoint*)s)->sentRecords > 3 )
+			{
+				decodedStuff[inlen] = '\0';
+				printf( "Got record from client: %s", decodedStuff );
+			}
+		
+		}
+	else
+		{
+		// the message has been sent by the server
+		// decode it using the client's read key
+
+		RC4( &clientReadKeyInternal, inlen, indata, decodedStuff );
+		*outlen = inlen;
+		}
+	}
+// --- END EXPERIMENTAL HACK
+#endif
+
+// --- SSLv2_EndPoint ---------------------------------------------------------
+
+/*!
+ * The constructor.
+ *
+ * \param interpreter Pointer to the SSLv2 interpreter to whom this endpoint belongs to
+ * \param is_orig true if this is the originating endpoint of the ssl connection,
+ *                false otherwise
+ */
+SSLv2_Endpoint::SSLv2_Endpoint( SSLv2_Interpreter* interpreter, int is_orig )
+	: SSL_InterpreterEndpoint( interpreter, is_orig )
+	{
+	sentRecords = 0;
+	}
+
+/*!
+ * The destructor.
+ */
+SSLv2_Endpoint::~SSLv2_Endpoint()
+	{
+	}
+
+/*!
+ * This method is called by the SSL_ConnectionProxy with a complete reassembled
+ * SSLv2 record. It passes the record to SSLv2_Interpreter::NewSSLRecord().
+ *
+ * \param t <b>reserved</b> (always zero)
+ * \param seq <b>reserved</b> (always zero)
+ * \param len length of the data block containing the ssl record
+ * \param data pointer to the data block containing the ssl record
+ */
+void SSLv2_Endpoint::Deliver(double t, int seq, int len, u_char* data)
+	{
+	((SSLv2_Endpoint*)peer)->sentRecords++;
+
+	/*
+	static bool bFirstOne = false;
+	if ( !bFirstOne )
+	{
+		bFirstOne = true;
+		FILE* certFile = fopen( "client-hello.dump", "wb" );
+		if ( certFile == NULL )
+		{
+			fprintf( stderr, "Error dumping Client Hello" );
+			return;
+		}
+		fwrite( data, 1, len, certFile );
+		fclose( certFile );	
+	}
+	*/
+
+	((SSLv2_Interpreter*)interpreter)->NewSSLRecord( this, len, data );
+	}
+
+
+
diff -uNr bro-pub-0.8a41/SSLv2.h bro-pub-0.841-ssl/SSLv2.h
--- bro-pub-0.8a41/SSLv2.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv2.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,261 @@
+// -----------------------------------------------------
+// SSLv2 Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef SSLV2_H
+#define SSLV2_H
+
+#include "SSLInterpreter.h"
+#include "SSLCiphers.h"
+
+// --- constants for SSLv2 ---------------------------------------------------
+
+/*!
+ * In SSLv2, each record is of a special message type. Note that the message
+ * type is encrypted if the record has been encrypted, so we can determine
+ * the message type only if we have a cleartext record.
+ */
+enum SSLv2_MessageTypes
+{
+	SSLv2_MT_ERROR               = 0, ///< can be in cleartext or encrypted
+	SSLv2_MT_CLIENT_HELLO        = 1, ///< always in cleartext
+	SSLv2_MT_CLIENT_MASTER_KEY   = 2, ///< always in cleartext
+	SSLv2_MT_CLIENT_FINISHED     = 3, ///< always encrypted
+	SSLv2_MT_SERVER_HELLO        = 4, ///< always in cleartext
+	SSLv2_MT_SERVER_VERIFY       = 5, ///< always encrypted
+	SSLv2_MT_SERVER_FINISHED     = 6, ///< always encrypted
+	SSLv2_MT_REQUEST_CERTIFICATE = 7, ///< always encrypted
+	SSLv2_MT_CLIENT_CERTIFICATE  = 8  ///< always encrypted
+};
+
+//Certificate Type Codes
+//Authentication Type Codes
+//#define SSL_AT_MD5_WITH_RSA_ENCRYPTION		0x01
+//Upper/Lower Bounds
+//#define SSL_MAX_MASTER_KEY_LENGTH_IN_BITS	256
+//#define SSL_MAX_SESSION_ID_LENGTH_IN_BYTES	16
+//#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES	64
+//#define SSL_MAX_RECORD_LENGTH_2_BYTE_HEADER	32767
+//#define SSL_MAX_RECORD_LENGTH_3_BYTE_HEADER	16383
+
+const uint8 SSLv2_CT_X509_CERTIFICATE = 0x01;
+
+/*!
+ * Error codes used in the error record.
+ */
+enum SSLv2_ErrorCodes
+{
+	SSLv2_PE_NO_CIPHER                    = 0x0001,
+	SSLv2_PE_NO_CERTIFICATE               = 0x0002,
+	SSLv2_PE_BAD_CERTIFICATE              = 0x0004,
+	SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE = 0x0006
+};
+
+// --- structs ----------------------------------------------------------------
+
+const int SSLv2_CLIENT_HELLO_HEADER_SIZE = 9;
+struct SSLv2_ClientHelloHeader
+{
+	uint8  messageType;
+	uint16 clientVersion;
+	uint16 cipherSpecLength;
+	uint16 sessionIdLength;
+	uint16 challengeLength;
+};
+
+const int SSLv2_SERVER_HELLO_HEADER_SIZE = 11;
+struct SSLv2_ServerHelloHeader
+{
+	uint8  messageType;
+	uint8  sessionIdHit;
+	uint8  certificateType;
+	uint16 serverVersion;
+	uint16 certificateLength;
+	uint16 cipherSpecLength;
+	uint16 connectionIdLength;
+};
+
+const int SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE = 10;
+struct SSLv2_ClientMasterKeyHeader
+{
+	uint8  messageType;
+	uint32 cipherKind; // caution: is an uint24
+	uint16 clearKeyLength;
+	uint16 encryptedKeyLength;
+	uint16 keyArgLength;
+};
+
+const int SSLv2_ERROR_RECORD_SIZE = 3;
+struct SSLv2_ErrorRecord
+{
+	uint8  messageType;
+	uint16 errorCode;
+};
+
+const int SSLv2_CLIENT_FINISHED_HEADER_SIZE = 1;
+struct SSLv2_ClientFinished
+{
+	uint8 messageType;
+	//char CONNECTION-ID[N-1]
+};
+
+struct SSLv2_ServerVerify
+{
+	uint8 messageType;
+	//char CHALLENGE-DATA[N-1]
+};
+
+struct SSLv2_ServerFinished
+{
+	uint8 messageType;
+	//char SESSION-ID-DATA[N-1]
+};
+
+// MISSING:
+// CLIENT-CERTIFICATE
+// REQUEST-CERTIFICATE
+
+/*!
+ * States used by the internal SSLv2 automaton.
+ */
+enum SSLv2_States
+{
+	START,                 ///< start state, no data seen yet
+	CLIENT_HELLO_SEEN,     ///< client hello flew by
+	NEW_SESSION,           ///< server hello with sessionIdHit == 0 seen
+	CACHED_SESSION,        ///< server hello with sessionIdHit != 0 seen
+	CLIENT_MASTERKEY_SEEN, ///< we saw a client master key record
+	ERROR_SEEN,            ///< we saw an error record
+	ERROR_REQUIRED         ///< one of our critical checks failed, so we think we should see an error record
+};
+
+
+// --- forward declarations ---------------------------------------------------
+
+class SSLv2_Interpreter;
+class SSLv2_Endpoint;
+class SSLv2_Record;
+class SSL_DataBlock;
+class SSL_RecordBuilder;
+
+// --- class SSLv2_Interpreter ------------------------------------------------
+
+/*!
+ * \brief This class is used to analyze SSLv2 connections.
+ *
+ * Since there's currently no support for decrypting ssl connections, analysis
+ * stops when a connection switches to encrypted communication.
+ * The interpreter does several checks, both record- and connection-orientated.
+ *
+ * The record checks mainly consist of consistency checks, where the correct
+ * use of the SSL 2.0 specification is checked. Furthermore, the CIPHER-SPECS
+ * of the client and the server can be compared to detect non-intersecting sets.
+ *
+ * The connection check monitors the handshaking process for invalid transitions,
+ * until the end of the cleartext phase.
+ *
+ * Several events are thrown for BroScript, including client connection attempt,
+ * server reply, ssl connection establishment/reuse of former connection, proposed
+ * cipher suites and certificates seen.
+ *
+ * \see SSLv2_Endpoint
+ */
+class SSLv2_Interpreter : public SSL_Interpreter
+{
+	public:
+	//static const uint MAX_CIPHERSPEC_SIZE = ssl_max_cipherspec_size;
+	#define MAX_CIPHERSPEC_SIZE ssl_max_cipherspec_size
+
+	// global connection counters
+	static uint totalConnections;     ///< counter for total sslv2 connections
+	static uint analyzedConnections;  ///< counter for analyzed (=not partial) connections
+	static uint openedConnections;    ///< counter for SSLv2 connections with complete handshake
+	static uint failedConnections;    ///< counter for SSLv2 connections with failed but correct handshake
+	static uint weiredConnections;    ///< counter for SSLv2 connections with failed and weired handshake
+
+	// global record counters
+	static uint totalRecords;           ///< counter for total SSLv2 records seen
+	static uint clientHelloRecords;     ///< counter for SSLv2 CLIENT-HELLOs seen
+	static uint serverHelloRecords;     ///< counter for SSLv2 SERVER-HELLOs seen
+	static uint clientMasterKeyRecords; ///< counter for SSLv2 CLIENT-MASTER-KEYSs seen
+	static uint errorRecords;           ///< counter for SSLv2 ERRORs seen
+
+	// counters for this instance
+	uint32 records;                    ///< counter for SSLv2 records of this connection
+	SSLv2_States connState;           ///< state of connection
+
+	bool bAnalyzedCounted; ///< flag for counting analyzedConnections
+
+	// FIXME: this should be states
+	bool bClientWantsCachedSession;    ///< true if the client wants a cached session, false otherwise
+
+	SSLv2_Interpreter( SSL_ConnectionProxy* proxy );
+	~SSLv2_Interpreter();
+
+	void NewSSLRecord( SSL_InterpreterEndpoint* s, int length, u_char* data );
+	void analyzeRecord( SSL_InterpreterEndpoint* s, int length, u_char* data );
+	SSLv2_States ClientHelloRecord( SSL_InterpreterEndpoint* s,
+	                                int recordLength,
+	                                u_char* recordData );
+	SSLv2_States ServerHelloRecord( SSL_InterpreterEndpoint* s,
+	                                int recordLength, u_char* recordData );
+	SSLv2_States ClientMasterKeyRecord( SSL_InterpreterEndpoint* s,
+	                                    int recordLength,
+	                                    u_char* recordData );
+	SSLv2_States ErrorRecord( SSL_InterpreterEndpoint* s,
+	                          int recordLength,
+	                          u_char* recordData );
+
+	TableVal* analyzeCiphers( SSL_InterpreterEndpoint* s, int length, u_char* data );
+	SSLv2_States ConnState();
+#ifdef SSLv2_EXPERIMENTAL_HACK
+	void decodeRecord( SSL_InterpreterEndpoint* s,
+				 int inlen,
+				 u_char* indata,
+				 int* outlen,
+				 u_char** outdata );
+#endif
+
+	static void printStats();
+
+	protected:
+	SSL_DataBlock* pClientCipherSpecs; ///< the CIPHER-SPECs from the client
+	SSL_DataBlock* pServerCipherSpecs; ///< the CIPHER-SPECs from the server
+	SSLv2_CipherSpec usedCipherSpec;  ///< the used CIPHER-SPEC for this connection
+
+	// currently experimental
+	SSL_DataBlock* pConnectionId;   // 16 <= ConnectionId <= 32
+	SSL_DataBlock* pChallenge;      // 16 <= Challenge <= 32
+	SSL_DataBlock* pSessionId;      // has to be 16 Bytes
+	SSL_DataBlock* pMasterClearKey;
+	SSL_DataBlock* pMasterEncryptedKey;
+	SSL_DataBlock* pClientReadKey;
+	SSL_DataBlock* pServerReadKey;
+
+	void BuildInterpreterEndpoints();
+};
+
+// --- class SSLv2_Endpoint ---------------------------------------------------
+
+/*!
+ * \brief This class represents an endpoint of an SSLv2 connection.
+ *
+ * Fully reassembled SSLv2 records are passed to its Deliver() function.
+ * There, some counters are updated and the record is then passed to
+ * SSLv2_Interpreter::NewSSLRecord().
+ */
+class SSLv2_Endpoint: public SSL_InterpreterEndpoint
+{
+	public:
+
+	uint32 sentRecords; ///< counter for sent records of this endpoint
+
+	SSLv2_Endpoint( SSLv2_Interpreter* interpreter, int is_orig );
+	~SSLv2_Endpoint();
+	void Deliver(double t, int seq, int len, u_char* data);
+};
+
+#endif
+
+
diff -uNr bro-pub-0.8a41/SSLv3.cc bro-pub-0.841-ssl/SSLv3.cc
--- bro-pub-0.8a41/SSLv3.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv3.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,1524 @@
+// -----------------------------------------------------
+// SSLv3/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+#include "SSLv3.h"
+#include "SSLCiphers.h"
+
+// --- Initalization of static variables --------------------------------------
+
+bool SSLv3_Interpreter::bInited = false;
+
+uint SSLv3_Interpreter::totalConnections       = 0;
+uint SSLv3_Interpreter::openedConnections      = 0;
+uint SSLv3_Interpreter::totalRecords           = 0;
+uint SSLv3_Interpreter::handshakeRecords	   = 0;
+uint SSLv3_Interpreter::clientHelloRecords     = 0;
+uint SSLv3_Interpreter::serverHelloRecords     = 0;
+uint SSLv3_Interpreter::alertRecords		   = 0;
+uint SSLv3_Interpreter::changeCipherRecords    = 0;
+
+
+// ---SSLv3_Interpreter--------------------------------------------------------
+
+SSLv3_Automaton SSLv3_Interpreter::sslAutomaton(SSL3_1_NUM_STATES,
+									SSL3_1_NUM_TRANS,
+									SSL3_1_STATE_ERROR);
+		
+SSLv3_Interpreter::SSLv3_Interpreter(SSL_ConnectionProxy* proxy)
+: SSL_Interpreter(proxy)
+	{
+	//cipherSuite = 0;
+	pCipherSuite = 0;
+	cipherSuiteIdentifier = 0;
+	pClientCipherSpecs = 0;
+	currentCipherSuites = 0;
+	clientSessionID = 0;
+	serverSessionID = 0;
+	clientRandom = 0;
+	serverRandom = 0;
+	serverRSApars = 0;
+	serverDHPars = 0;
+	encryptedPreSecret = 0;
+	clientDHpublic = 0;
+	//keyXAlgorithm = SSL_KEY_EXCHANGE_NULL;
+	change_cipher_client_seen = false;
+	change_cipher_server_seen = false;
+	fin_client_seen = false;
+	fin_server_seen = false;
+	helloRequestValid = true;
+	if ( !bInited )
+		{
+		BuildAutomaton();
+		//BuildCipherDict();
+		bInited = true;
+		}
+	currentState = SSL3_1_STATE_INIT;
+	totalConnections++;
+	}
+	
+SSLv3_Interpreter::~SSLv3_Interpreter()
+	{
+	SAFE_DELETE( pClientCipherSpecs );
+	SAFE_DELETE( clientSessionID );
+	SAFE_DELETE( serverSessionID );
+	if ( ssl_store_key_material )
+		{
+		SAFE_DELETE( clientRandom );
+		SAFE_DELETE( serverRandom );
+		SAFE_DELETE( serverRSApars );
+		SAFE_DELETE( serverDHPars );
+		SAFE_DELETE( encryptedPreSecret );
+		SAFE_DELETE( clientDHpublic );
+		}
+	}
+
+void SSLv3_Interpreter::BuildInterpreterEndpoints()
+	{
+	orig = new SSLv3_Endpoint(this, 1);
+	resp = new SSLv3_Endpoint(this, 0);
+	}
+	
+void SSLv3_Interpreter::BuildAutomaton()
+	{
+	
+	sslAutomaton.addTrans(SSL3_1_STATE_INIT, SSL3_1_TRANS_SERVER_HELLO_REQ,
+		SSL3_1_STATE_SERVER_HELLO_REQ_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_REQ_SENT, SSL3_1_TRANS_CLIENT_HELLO,
+		SSL3_1_STATE_CLIENT_HELLO_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_INIT, SSL3_1_TRANS_CLIENT_HELLO,
+		SSL3_1_STATE_CLIENT_HELLO_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_HELLO_SENT, SSL3_1_TRANS_SERVER_HELLO,
+		SSL3_1_STATE_SERVER_HELLO_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT, SSL3_1_TRANS_SERVER_CERT,
+		SSL3_1_STATE_SERVER_CERT_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT, SSL3_1_TRANS_SERVER_KEY_EXCHANGE,
+		SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT);
+		
+	//server key-exchange and/or server requests cert. from client
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT, SSL3_1_TRANS_SERVER_KEY_EXCHANGE,
+		SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT, SSL3_1_TRANS_SERVER_HELLO_DONE,
+		SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_KEY_EXCHANGE_SENT, SSL3_1_TRANS_SERVER_CERT_REQ,
+		SSL3_1_STATE_SERVER_CERT_REQ_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT, SSL3_1_TRANS_SERVER_CERT_REQ,
+		SSL3_1_STATE_SERVER_CERT_REQ_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_REQ_SENT, SSL3_1_TRANS_SERVER_HELLO_DONE,
+		SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_DONE_SENT_B, SSL3_1_TRANS_CLIENT_CERT,
+		SSL3_1_STATE_CLIENT_CERT_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_SENT, SSL3_1_TRANS_CLIENT_KEY_EXCHANGE,
+		SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B, SSL3_1_TRANS_CLIENT_CERT_VERIFY,
+		SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_CLIENT_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_CLIENT_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_A, SSL3_1_TRANS_SERVER_FIN, 
+		SSL3_1_STATE_HS_FIN_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_B, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_SERVER_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_CERT_VERIFY_SENT, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_SERVER_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_A, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_HS_FIN_A);
+	
+	//server hello done after server cert. sent
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_CERT_SENT, SSL3_1_TRANS_SERVER_HELLO_DONE,
+		SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A, SSL3_1_TRANS_CLIENT_KEY_EXCHANGE,
+		SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_CLIENT_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_KEY_EXCHANGE_SENT_A, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_SERVER_FIN_SENT_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_A, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_HS_FIN_A);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_A, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_HS_FIN_A);
+	
+	//when reestablishing a session...
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_CLIENT_FIN_SENT_B);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_HELLO_SENT, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_SERVER_FIN_SENT_B);
+	sslAutomaton.addTrans(SSL3_1_STATE_CLIENT_FIN_SENT_B, SSL3_1_TRANS_SERVER_FIN,
+		SSL3_1_STATE_HS_FIN_B);
+	sslAutomaton.addTrans(SSL3_1_STATE_SERVER_FIN_SENT_B, SSL3_1_TRANS_CLIENT_FIN,
+		SSL3_1_STATE_HS_FIN_B);
+	
+	sslAutomaton.setStartState(SSL3_1_STATE_INIT);
+	
+	}
+
+void SSLv3_Interpreter::printStats()
+	{
+	//Print some stats
+	printf( "SSLv3x:\n" );
+	printf( "Note: Because handshake messages may be coalesced into a \n");
+	printf( "      single SSLv3x record, the number of total messages for SSLv3x plus \n");
+	printf( "      the number of total records seen for SSLv2 won't match \n");
+	printf( "      SSL_ConnectionProxy::totalRecords! \n");
+	printf( "total connections			= %u\n", totalConnections );
+	printf( "opened connections (complete handshake)	= %u\n", openedConnections );
+
+	printf( "total messages seen			= %u\n", totalRecords );
+	printf( "handshake messages seen			= %u\n", handshakeRecords );
+	printf( "alert records seen			= %u\n", alertRecords );
+	printf( "change cipher records seen		= %u\n", changeCipherRecords );
+	printf( "client hello messages seen		= %u\n", clientHelloRecords );
+	printf( "server hello messages seen		= %u\n", serverHelloRecords );
+	
+	}
+	
+int SSLv3_Interpreter::HandshakeType2Trans(int type)
+	{
+	switch (SSL3_1_HandshakeType(type))
+		{
+		case SSL3_1_HELLO_REQUEST:
+			{
+			return SSL3_1_TRANS_SERVER_HELLO_REQ;
+			break;
+			}
+		case SSL3_1_CLIENT_HELLO:
+			{
+			return SSL3_1_TRANS_CLIENT_HELLO;
+			break;
+			}
+		case SSL3_1_SERVER_HELLO:
+			{
+			return SSL3_1_TRANS_SERVER_HELLO;
+			break;
+			}
+		//client- and server certificate handshake records lead to the same transition
+		//in the SSL automaton (see SSLDefines.h)
+		case SSL3_1_CERTIFICATE:
+			{
+			return SSL3_1_TRANS_SERVER_CERT;
+			break;
+			}
+		case SSL3_1_SERVER_KEY_EXCHANGE:
+			{
+			return SSL3_1_TRANS_SERVER_KEY_EXCHANGE;
+			break;
+			}
+		case SSL3_1_CERTIFICATE_REQUEST:
+			{
+			return SSL3_1_TRANS_SERVER_CERT_REQ;
+			break;
+			}
+		case SSL3_1_SERVER_HELLO_DONE:
+			{
+			return SSL3_1_TRANS_SERVER_HELLO_DONE;
+			break;
+			}
+		case SSL3_1_CERTIFICATE_VERIFY:
+			{
+			return SSL3_1_TRANS_CLIENT_CERT_VERIFY;
+			break;
+			}
+		case SSL3_1_CLIENT_KEY_EXCHANGE:
+			{
+			return SSL3_1_TRANS_CLIENT_KEY_EXCHANGE;
+			break;
+			}
+		//client- and server finished handshake records lead to the same transition
+		//in the SSL automaton (see SSLDefines.h)
+		case SSL3_1_FINISHED:
+			{
+			return SSL3_1_TRANS_CLIENT_FIN;
+			break;
+			}
+		default:
+			{
+			return -1;
+			}
+		}
+	}
+	
+void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_HandshakeRecord* rec)
+	{
+	SSLv3_Interpreter::totalRecords++;
+	SSLv3_Interpreter::handshakeRecords++;
+	
+	//first: Consistency-checks:
+	//special treatment for finished messages, because they are
+	//already encrypted(encrypted handshake message)
+	if ( ( change_cipher_client_seen && ((rec->endp)->IsOrig() ) && !(fin_client_seen) )||
+		 ( change_cipher_server_seen && !((rec->endp)->IsOrig()) && !(fin_server_seen) ) )
+		{
+		//no checks can be performed due encryption...
+		}
+	else
+		{
+		SSL3_1_HandshakeType ht = (SSL3_1_HandshakeType) rec->type;
+		switch (ht)
+			{
+			case SSL3_1_HELLO_REQUEST:
+				{
+				if ( rec->length != 0 )
+					{
+					Weird( "SSLv3x: Hello request too long!" );
+					}
+				if ( !helloRequestValid )
+					{
+					Weird( "SSLv3x: Received hello request during handshake!" );
+					}
+				//There should only be sent one hello request at a time
+				helloRequestValid = false;
+				break;
+				}
+			case SSL3_1_CLIENT_HELLO:
+				{
+				SSLv3_Interpreter::clientHelloRecords++;
+				//during handshaking phase, we don't want any more hello requests...
+				helloRequestValid = false;
+				
+				if ( rec->checkClientHello() == 0 )
+					{
+					return;
+					}
+				u_char* pTemp = (u_char*)rec->data;
+				uint8 sessionIDLength = (uint8)(pTemp[38]);
+				clientSessionID = new SSL_DataBlock( (pTemp + 39), sessionIDLength );
+				uint16 cipherSuiteLength = (uint16) (pTemp[39 + sessionIDLength] << 8 ) |
+										pTemp[40 + sessionIDLength];
+				currentCipherSuites = analyzeCiphers(rec->endp, ( cipherSuiteLength ) ,
+								( rec->data + 41 + sessionIDLength) , rec->sslVersion);
+				if ( ssl_store_key_material )
+					{
+					clientRandom = new SSLv3x_Random();
+					clientRandom->gmt_unix_time = uint32 (((pTemp[6] << 24 ) | 
+													pTemp[7] << 16 ) |
+													pTemp[8] << 8 ) |
+													pTemp[9];
+					clientRandom->random_bytes = new SSL_DataBlock(pTemp + 10, 28);
+					}
+				break;
+				}
+			case SSL3_1_SERVER_HELLO:
+				{
+				SSLv3_Interpreter::serverHelloRecords++;
+				if ( rec->checkServerHello() == 0)
+					{
+					return;
+					}
+				u_char* pTemp = (u_char*)rec->data;
+				uint8 sessionIDLength = (uint8)(pTemp[38]);
+				serverSessionID = new SSL_DataBlock( (pTemp + 39), sessionIDLength );
+				currentCipherSuites = analyzeCiphers(rec->endp, 2 ,
+								( rec->data + 39 + sessionIDLength) , rec->sslVersion);
+				//check, if the cipher suite the server choosed was included
+				//in the cipher suites the client anounced
+				if ( pClientCipherSpecs && pCipherSuite )
+					{
+					bool bFound = false;
+					uint16 tempClientCipher;
+					for ( int idx = 0; idx < pClientCipherSpecs->len; idx += 2 )
+						{
+						tempClientCipher = (pClientCipherSpecs->data[idx] << 8)
+											| pClientCipherSpecs->data[idx+1];
+						if ( tempClientCipher == pCipherSuite->identifier )
+							{
+							bFound = true;
+							idx = pClientCipherSpecs->len;
+							}
+						}
+					if ( !bFound )
+						{
+						Weird( "SSLv3x: Server choosed cipher spec that client didn't anounce!" );
+						}
+					delete pClientCipherSpecs;
+					pClientCipherSpecs = 0;
+					}
+				
+				if ( ssl_store_key_material )
+					{
+					serverRandom = new SSLv3x_Random();
+					serverRandom->gmt_unix_time = uint32 (((pTemp[6] << 8 ) | 
+													pTemp[7] << 8 ) |
+													pTemp[8] << 8 ) |
+													pTemp[9];
+					serverRandom->random_bytes = new SSL_DataBlock(pTemp + 10, 28);
+					}
+				break;
+				}
+			case SSL3_1_CERTIFICATE:
+				{
+				if ( rec->length >= 3 )
+					{
+					const u_char* pData = rec->data;
+					uint32 certListLength = (uint32) ((pData[4] << 16) | pData[5] << 8) | pData[6];
+
+					// size consistency checks
+					if ( certListLength + 3 != rec->length )
+						{
+						if ( (rec->endp)->IsOrig() )
+							{
+							Weird( "SSLv3x: Corrupt length field in client certificate list!" );
+							}
+						else
+							{
+							Weird( "SSLv3x: Corrupt length field in server certificate list!" );
+							}
+						return;
+						}
+					
+					//sum of all cert sizes has to match certListLength
+					uint tempLength = 0;
+					uint certCount = 0;
+					while( tempLength < certListLength )
+						{
+						if ( tempLength + 3 <= certListLength )
+							{
+							certCount++;
+							uint32 certLength = (uint32) ((pData[tempLength + 7] << 16) |
+														   pData[tempLength + 8] << 8) |
+														   pData[tempLength + 9];
+							tempLength += certLength + 3;
+							}
+						else
+							{
+							Weird( "SSLv3x: Corrupt length field in certificate list!" );
+							return;
+							}
+						}
+					if ( tempLength > certListLength )
+						{
+						Weird( "SSLv3x: sum of size of certificates doesn't match size of certificate chain" );
+						return;
+						}
+
+					SSL_InterpreterEndpoint* pEp = (SSL_InterpreterEndpoint*)rec->endp;
+					if ( certCount == 0 )
+						{
+						// we don't have a certificate...
+						if ( (rec->endp)->IsOrig() )
+							{
+								// ...for the client
+								Weird( "SSLv3x: Client certificate is null!" );
+								break;
+							}
+						else
+							{
+								// ...for the server
+								Weird( "SSLv3x: Server certificate is null!" );
+								break;
+							}
+						}
+					if ( certCount > 1 )
+						{
+						// we have a chain
+
+						analyzeCertificate( pEp,
+										    (u_char*)(rec->data + 7),
+											certListLength,
+											1,
+											true );
+						}
+					else
+						{
+						// we have a single certificate
+						analyzeCertificate( pEp,
+											(u_char*)(rec->data + 10),
+											certListLength-3,
+											1,
+											false); // FIXME	
+						}
+						
+					}
+				else
+					{
+					Weird( "SSLv3x: Certificate record too small! ");
+					}
+				break;
+				}
+			case SSL3_1_SERVER_KEY_EXCHANGE:
+				{
+				/*
+				switch (cipherSuite)
+					{
+					//It would be necessary to have the RSA key length
+					//out of the server's certificate. If the cipher suite
+					//is EXPORT, than a RSA key length larger than 512 bits
+					//is not allowed for encryption and thus, the server needs
+					//to send a key-exchange-message in order to negotiate the
+					//pre-master secret (see rfc 2246 page 39)
+					case TLS_RSA_WITH_NULL_MD5:
+					case TLS_RSA_WITH_NULL_SHA:
+					//case TLS_RSA_EXPORT_WITH_RC4_40_MD5: //see comment above
+					case TLS_RSA_WITH_RC4_128_MD5:
+					case TLS_RSA_WITH_RC4_128_SHA:
+					//case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5: //see comment above
+					case TLS_RSA_WITH_IDEA_CBC_SHA:
+					//case TLS_RSA_EXPORT_WITH_DES40_CBC_SHA: //see comment above
+					case TLS_RSA_WITH_DES_CBC_SHA:
+					case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+					case TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+					case TLS_DH_DSS_WITH_DES_CBC_SHA:
+					case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+					case TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+					case TLS_DH_RSA_WITH_DES_CBC_SHA:
+					case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+						{
+						Weird( "SSLv3x: Sending server-key-exchange not allowed for this cipher suite!" );
+						return;
+						break;
+						}
+					default:
+						break;
+					}
+				*/
+				if ( !pCipherSuite )
+					{
+					// if we have an unknown CIPHER-SPEC, we can't do our weird checks
+					break;
+					}
+				
+				SSL_KeyExchangeAlgorithm keyXAlgorithm = pCipherSuite->keyExchangeAlgorithm;
+				if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
+					 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS ||
+					 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA )
+					{
+					Weird( "SSLv3x: Sending server-key-exchange not allowed for this cipher suite!" );
+					return;
+					}
+				//FIXME: check where DHE_RSA etc. belongs to
+				u_char* pTemp = (u_char*)rec->data;
+				if ( ssl_store_key_material )
+					{
+					if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
+						 keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
+						 keyXAlgorithm == SSL_KEY_EXCHANGE_RSA_EXPORT1024 )
+						{
+						//Some weird checks
+						if ( rec->length < 2 )
+							{
+							Weird( "SSLv3x: server-key-exchange empty!" );
+							return;
+							}
+						uint16 modulusLength = (uint16) (pTemp[4] << 8 ) |
+										pTemp[5];
+						if ( modulusLength > 65535 )
+							{
+							Weird( "SSLv3x: RSA modulus length to long in server-key-exchange!" );
+							return;
+							}
+						if ( modulusLength + 4 > rec->length )
+							{
+							Weird( "SSLv3x: Corrupt length fields in server-key-exchange!" );
+							break;
+							} 
+						uint16 exponentLength = (uint16)(pTemp[6 + modulusLength] << 8 ) |
+										pTemp[7 + modulusLength];
+						if ( exponentLength > 65535 )
+							{
+							Weird( "SSLv3x: RSA exponent length to long in server-key-exchange!" );
+							return;
+							}
+						if ( modulusLength + exponentLength + 4 > rec->length )
+							{
+							Weird( "SSLv3x: Corrupt length fields in server-key-exchange!" );
+							return;
+							}
+						
+						serverRSApars = new SSLv3x_ServerRSAParams;
+						serverRSApars->rsa_modulus = new SSL_DataBlock(pTemp + 6, modulusLength);
+						serverRSApars->rsa_exponent = new SSL_DataBlock(
+												pTemp + 8 + modulusLength, exponentLength);
+										
+						}
+					else
+						{
+						if ( keyXAlgorithm == SSL_KEY_EXCHANGE_DH ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_ANON ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_ANON_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024 )
+							{
+							//Some weird checks
+							if ( rec->length < 2 )
+								{
+								Weird( "SSLv3x: server-key-exchange empty!" );
+								return;
+								}
+							uint16 dh_pLength = (uint16) (pTemp[4] << 8 ) |
+										pTemp[5];
+							if ( dh_pLength > 65535 )
+								{
+								Weird( "SSLv3x: DH prime modulus length to long in server-key-exchange!" );
+								return;
+								}
+							if ( dh_pLength + 4 > rec->length )
+								{
+								Weird( "SSLv3x: Corrupt length fields in server-key-exchange!" );
+								break;
+								}
+							uint16 dh_gLength =  (uint16)(pTemp[6 + dh_pLength] << 8 ) |
+										pTemp[7 + dh_pLength];
+							if ( dh_gLength > 65535 )
+								{
+								Weird( "SSLv3x: DH generator length to long in server-key-exchange!" );
+								return;
+								}
+							uint16 dh_YsLength = (uint16)(pTemp[8 + dh_pLength + dh_gLength] << 8 ) |
+										pTemp[9 + dh_pLength + dh_gLength];
+							if ( dh_YsLength > 65535 )
+								{
+								Weird( "SSLv3x: DH server's public value length to long in server-key-exchange!" );
+								return;
+								}
+							if ( dh_pLength + dh_gLength + dh_YsLength + 6 > rec->length )
+								{
+								Weird( "SSLv3x: Corrupt length fields in server-key-exchange!" );
+								printf("xxx %u > %u \n", (dh_pLength + dh_gLength + dh_YsLength + 6), rec->length);
+								return;
+								}
+								
+							serverDHPars = new SSLv3x_ServerDHParams;
+							serverDHPars->dh_p = new SSL_DataBlock(pTemp + 6
+									, dh_pLength);
+							serverDHPars->dh_g = new SSL_DataBlock(pTemp + 8 
+									+ dh_pLength, dh_gLength);
+							serverDHPars->dh_Ys = new SSL_DataBlock(pTemp + 10 
+									+ dh_pLength + dh_gLength, dh_YsLength);
+							}
+						}
+					}
+				break;
+				}
+			case SSL3_1_CERTIFICATE_REQUEST:
+				{
+				//only if server not anonymous
+				/*
+				switch (cipherSuite)
+					{
+					case TLS_NULL_WITH_NULL_NULL:
+					case TLS_DH_ANON_EXPORT_WITH_RC4_40_MD5:
+					case TLS_DH_ANON_WITH_RC4_128_MD5:
+					case TLS_DH_ANON_EXPORT_WITH_DES40_CBC_SHA:
+					case TLS_DH_ANON_WITH_DES_CBC_SHA:
+					case TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA:
+						{
+						Weird( "SSLv3x: Sending certificate-request not allowed for anonymous servers!" );
+						break;
+						}
+					default: 
+						{
+						break;
+						}
+					}
+				*/
+				if ( !pCipherSuite )
+					{
+					// if we have an unknown CIPHER-SPEC, we can't do our weird checks
+					break;
+					}
+
+				if ( pCipherSuite->keyExchangeAlgorithm == SSL_KEY_EXCHANGE_DH_ANON ||
+					 pCipherSuite->keyExchangeAlgorithm == SSL_KEY_EXCHANGE_DH_ANON_EXPORT )
+					{
+					Weird( "SSLv3x: Sending certificate-request not allowed for anonymous servers!" );
+					}
+				//FIXME: Insert Weird checks!
+				break;
+				}	
+			case SSL3_1_SERVER_HELLO_DONE:
+				{
+				if ( rec->length != 0 )
+					{
+					Weird( "SSLv3x: Server hello too long!" );
+					}
+				break;
+				}
+			case SSL3_1_CLIENT_KEY_EXCHANGE:
+				{
+				if ( !pCipherSuite )
+					{
+					// if we have an unknown CIPHER-SPEC, we can't do our weird checks
+					break;
+					}
+
+				u_char* pTemp = (u_char*)rec->data;
+				if ( ssl_store_key_material )
+					{
+					SSL_KeyExchangeAlgorithm keyXAlgorithm = pCipherSuite->keyExchangeAlgorithm;
+					if ( keyXAlgorithm == SSL_KEY_EXCHANGE_RSA ||
+					 	 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS ||
+					 	 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA )
+						{
+						encryptedPreSecret = new SSLv3x_EncryptedPremasterSecret;
+						encryptedPreSecret->encryptedSecret = new SSL_DataBlock(
+											pTemp + 4, rec->length);
+						}
+					else
+						{
+						if ( keyXAlgorithm == SSL_KEY_EXCHANGE_DH ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_DSS_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_RSA_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_RSA_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_ANON ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DH_ANON_EXPORT ||
+							 keyXAlgorithm == SSL_KEY_EXCHANGE_DHE_DSS_EXPORT1024 )
+							{
+							if ( rec->length < 2 )
+								{
+								//this may happen (see rfc 2246 p. 45)
+								return;
+								}
+							uint16 DHpublicLength = (uint16)(pTemp[4] << 8 ) |
+									pTemp[5];
+							if ( DHpublicLength + 2 < rec->length )
+								{
+								Weird( "SSLv3x:Corrupt length fields in client-key-exchange!" );
+								return;
+								}
+									
+							clientDHpublic = new SSLv3x_ClientDHPublic;
+							clientDHpublic->dh_Yc = new SSL_DataBlock(
+											pTemp + 6, DHpublicLength);
+							}
+						}
+									 
+					}
+				break;
+				}	
+			case SSL3_1_CERTIFICATE_VERIFY:
+				{
+				//FIXME: Insert Weird checks!
+				break;
+				}
+			case SSL3_1_FINISHED:
+				{
+				//We won't get here, because finished messages are already 
+				//encrypted, so we can't get the content type of this 
+				//handshake-message...
+				break;
+				}
+			default:
+				{
+				if ( currentState == SSL3_1_STATE_SERVER_FIN_SENT_A ||
+				     currentState == SSL3_1_STATE_CLIENT_FIN_SENT_B )
+					{
+					Weird( "SSLv3x: Handshake message (unknown type) after finished message!" );
+					return;
+					}
+				else
+					{				    
+				   	Weird( "SSLv3x: Invalid HandshakeType! Maybe finished message without predecessing change-cipher-message!" );
+				    return;
+				    }
+				}
+			}
+		}
+	
+	//maybe we need it later on...
+	int oldState = currentState;
+	
+	bool alreadySwitchedState = false;
+	
+	//First: Special handling of finished messages. They must be send immediately
+	//after a sent change cipher message and are already encrypted.
+	//from client?
+	if ( (rec->endp)->IsOrig() )
+		{
+		if ( change_cipher_client_seen )
+			{
+			if ( !fin_client_seen )
+				{
+				//so this must be a (valid) client finished.
+				//We assume it to be one, because the predecessing message
+				//was a change cipher.
+				fin_client_seen = true;
+				change_cipher_client_seen = false;
+				alreadySwitchedState = true;
+				currentState = sslAutomaton.getNextState(currentState,
+					SSL3_1_TRANS_CLIENT_FIN);
+				}
+			else
+				{
+				//we already saw a client finished (should not be possible)
+				Weird( "SSLv3x: Already received client finished message!" );
+				currentState = sslAutomaton.getNextState(currentState,
+					SSL3_1_TRANS_CLIENT_FIN);
+				fin_client_seen = true;
+				change_cipher_client_seen = false;
+				alreadySwitchedState = true;
+				}
+			}
+		}
+	//from server
+	else
+		{
+		if ( change_cipher_server_seen ) 
+			{
+			if ( !fin_server_seen )
+				{
+				//so this must be a (valid) server finished.
+				//We assume it to be one, because the predecessing message
+				//was a change cipher.
+				fin_server_seen = true;
+				change_cipher_server_seen = false;
+				alreadySwitchedState = true;
+				currentState = sslAutomaton.getNextState(currentState,
+					SSL3_1_TRANS_SERVER_FIN);
+				}
+			else
+				{
+				//we already saw a server-finished (should not be possible)
+				Weird( "SSLv3x: Already received server finished message!" );
+				currentState = sslAutomaton.getNextState(currentState,
+					SSL3_1_TRANS_SERVER_FIN);
+				alreadySwitchedState = true;
+				fin_server_seen = true;
+				change_cipher_server_seen = false;
+				}
+			}
+		}
+	
+	if (!alreadySwitchedState)
+		{
+		switch (currentState)
+			{
+			//check, whether we are already finished with the handshaking process...
+			case SSL3_1_STATE_HS_FIN_A:
+			case SSL3_1_STATE_HS_FIN_B:
+				{
+				Weird( "SSLv3x: Received handshake message after finishing handshake!" );
+				break;
+				}
+			//so it's a "normal" handshake message...
+			default:
+				{
+				currentState = sslAutomaton.getNextState(currentState,
+					HandshakeType2Trans(rec->type));
+				}
+			}
+		}
+	
+	if ( currentState == SSL3_1_STATE_ERROR )
+		{
+		//proxy->SetSkip(1);
+		}
+	
+	//only if we changed the currentState, we need to call GenerateEvents
+	//because event generation in GenerateEvents() is based on currentState
+	if ( oldState != currentState )
+		{
+		GenerateEvents(rec);
+		}
+	}
+	
+void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_AlertRecord* rec)
+	{
+	SSLv3_Interpreter::totalRecords++;
+	SSLv3_Interpreter::alertRecords++;
+	//first: consistency-checks:
+	//only if handshake not already finished. Otherwise alerts may be encrypted, so we
+	//could do nothing...
+	if ( ! (currentState == SSL3_1_STATE_SERVER_FIN_SENT_A ||
+		 currentState == SSL3_1_STATE_CLIENT_FIN_SENT_B ||
+   		 currentState == SSL3_1_STATE_CLIENT_FIN_SENT_A ||
+		 currentState == SSL3_1_STATE_SERVER_FIN_SENT_B ||
+		 currentState == SSL3_1_STATE_HS_FIN_A ||
+		 currentState == SSL3_1_STATE_HS_FIN_B ||
+		 change_cipher_client_seen ||
+		 change_cipher_server_seen ) )
+		{
+		if ( rec->level != SSL3x_ALERT_LEVEL_WARNING &&
+			 rec->level != SSL3x_ALERT_LEVEL_FATAL )
+			{
+			Weird( "SSLv3x: Unknown ssl alert level!" );
+			}
+		SSL3_1_AlertDescription ad = SSL3_1_AlertDescription(rec->description);
+		switch (ad)
+			{
+			case SSL3_1_CLOSE_NOTIFY:
+			case SSL3_1_UNEXPECTED_MESSAGE:
+			case SSL3_1_BAD_RECORD_MAC:
+			case SSL3_1_DECRYPTION_FAILED:
+			case SSL3_1_RECORD_OVERFLOW:
+			case SSL3_1_DECOMPRESSION_FAILURE:
+			case SSL3_1_HANDSHAKE_FAILURE:
+				break;
+			case SSL3_0_NO_CERTIFICATE:
+				{
+				//This may happen ONLY in SSLv3.0 when the server sends
+				//a certificate request but the client has none.
+				if ( rec->sslVersion == SSL_ConnectionProxy::SSLv30 )
+					{
+					currentState = SSL3_1_STATE_SERVER_HELLO_DONE_SENT_A;
+					}
+				else
+					{
+					Weird( "SSLv3x: No certificate alert not defined for SSL 3.1!" );
+					}
+				break;
+				}
+			case SSL3_1_BAD_CERTIFICATE:
+			case SSL3_1_UNSUPPORTED_CERTIFICATE:
+			case SSL3_1_CERTIFICATE_REVOKED:
+			case SSL3_1_CERTIFICATE_EXPIRED:
+			case SSL3_1_CERTIFICATE_UNKNOWN:
+			case SSL3_1_ILLEGAL_PARAMETER:
+			case SSL3_1_UNKNOWN_CA:
+			case SSL3_1_ACCESS_DENIED:
+			case SSL3_1_DECODE_ERROR:
+			case SSL3_1_DECRYPT_ERROR:
+			case SSL3_1_EXPORT_RESTRICTION:
+			case SSL3_1_PROTOCOL_VERSION:
+			case SSL3_1_INSUFFICIENT_SECURITY:
+			case SSL3_1_INTERNAL_ERROR:
+			case SSL3_1_USER_CANCELED:
+			case SSL3_1_NO_RENEGOTIATION:
+				break;
+			default:
+				{
+				Weird(" SSLv3x: Unknown ssl alert description!" );
+				}
+			}
+		if ( rec->level == 2 )
+			{
+			//Fatal alert!
+			currentState = SSL3_1_STATE_INIT;
+			}
+		if ( rec->level == 1 && ad == SSL3_1_CLOSE_NOTIFY )
+			{
+			//close notify...
+			currentState == SSL3_1_STATE_INIT;
+			}
+			
+		//generate ssl_conn_alert event
+		fire_ssl_conn_alert( rec->sslVersion,
+							 rec->level,
+							 rec->description );
+		
+		}
+	}
+	
+void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_ChangeCipherRecord* rec)
+	{
+	SSLv3_Interpreter::totalRecords++;
+	SSLv3_Interpreter::changeCipherRecords++;
+	//first: consistency checks:
+	if ( rec->type != 1 )
+		{
+		Weird( "SSLv3x: Unknown change cipher type!" );
+		}
+	if ( rec->recordLength != 1 )
+		{
+		Weird( "SSLv3x: Change cipher message too long!" );
+		}
+	
+	//maybe we need it later on...
+	int oldState = currentState;
+	
+	//after receiving a change cipher spec message, the next message sent
+	//MUST be a finished message. So we set the appropriate flag: 
+	//change_cipher_client/server_seen
+	//change-cipher from client?
+	if ((rec->endp)->IsOrig())
+		{
+		if ( change_cipher_client_seen )
+			{
+			Weird( "SSLv3x: Received multiple change cipher message from client!" );
+			}
+		change_cipher_client_seen = true;
+		fin_client_seen = false;
+		}
+	else
+		{
+		if ( change_cipher_server_seen )
+			{
+			Weird( "SSLv3x: Received multiple change cipher message from server!" );
+			}
+		change_cipher_server_seen = true;
+		fin_server_seen = false;
+		}
+	
+	if ( currentState == SSL3_1_STATE_ERROR ) 
+		{
+		//proxy->SetSkip(1);
+		}
+	
+	//We don't need a GenerateEvents here, because we didn't change
+	//the currentState of the SSL automaton.(Event generation in GenerateEvents()
+	//is done based on currentState.
+	//GenerateEvents(rec);
+	
+	}
+	
+void SSLv3_Interpreter::DeliverSSLv3_Record(SSLv3_ApplicationRecord* rec)
+	{
+	SSLv3_Interpreter::totalRecords++;
+	//maybe we need it later on...
+	int oldState = currentState;
+	
+	if (currentState == SSL3_1_STATE_HS_FIN_A ||
+		currentState == SSL3_1_STATE_HS_FIN_B)
+		{
+		//O.K., sending application data is valid
+		//this was the last record we analyzed...
+		proxy->SetSkip(1);
+		}
+	else
+		{
+		//sending application data now is not valid...
+		//so the SSL connection is probably already established
+		//and we didn't get the handshake...
+		Weird( "SSLv3x: Sending application data now is not valid; Handshake not finished yet!" );
+		currentState = SSL3_1_STATE_ERROR;
+		GenerateEvents(rec);
+		}
+		
+	}
+	
+TableVal* SSLv3_Interpreter::analyzeCiphers(const SSLv3_Endpoint* s, int length, const u_char* data,
+										uint16 version)
+	{
+	if ( length > ssl_max_cipherspec_size )
+		{
+		if ( (SSL_InterpreterEndpoint*)s == orig )
+			{
+			Weird( "SSLv2: Client has CipherSpecs > ssl_max_cipherspec_size" );
+			}
+		else
+			{
+			Weird( "SSLv2: Server has CipherSpecs > ssl_max_cipherspec_size" );
+			}
+		}	
+	
+	const u_char* pCipher = data;
+	SSL_CipherSpec* pCipherSuiteTemp = 0;
+	uint16 cipherSuite;
+	for ( int idx = 0; idx < length; idx = idx +2)
+		{
+		cipherSuite = (uint16) (pCipher[0+idx] << 8) | pCipher[1+idx];
+		HashKey h(cipherSuite);
+		pCipherSuiteTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h);
+		if (!pCipherSuiteTemp)
+			{
+			if ( (SSL_InterpreterEndpoint*)s == orig )
+				{
+				proxy->Weird( "SSLv3x: Unknown CIPHER-SPEC in CLIENT-HELLO" );
+				}
+			else
+				{
+				proxy->Weird( "SSLv3x: Unknown CIPHER-SPEC in SERVER-HELLO" );
+				}
+			}
+		}
+	// store server's cipher specs
+	if ( (SSL_InterpreterEndpoint*)s == resp )
+		{
+		pCipherSuite = pCipherSuiteTemp;
+		if ( !pCipherSuite )
+			{
+			//special case: we store the identifier directly for unknown cipher-specs
+			cipherSuiteIdentifier = (uint16) (pCipher[0] << 8) | pCipher[1];
+			}
+		}
+	if ( ssl_compare_cipherspecs && ( length <= ssl_max_cipherspec_size ) )
+		{
+		// store cipher specs for analysis: was the choosen server cipher suite
+		// announced by the client?
+		if ( (SSL_InterpreterEndpoint*)s == orig )
+			{
+			pClientCipherSpecs = new SSL_DataBlock( (u_char*)data, length );
+			}
+		}
+	if ( ((SSL_InterpreterEndpoint*)s == resp && ssl_conn_server_reply) ||
+		 ((SSL_InterpreterEndpoint*)s == orig && ssl_conn_attempt) )
+		{
+	
+		TableVal* pCipherTable = new TableVal( cipher_suites_list );
+		for ( int idx = 0; idx < length; idx += 2 )
+			{
+			uint32 cipherSpec = (pCipher[0] << 8) | pCipher[1];
+			pCipherTable->Assign( new Val( idx / 2, TYPE_COUNT) ,
+							   new Val( cipherSpec, TYPE_COUNT ));
+			pCipher += 2;
+			}
+		return pCipherTable;
+		}
+	else
+		{
+		return NULL;
+		}
+	}
+	
+void SSLv3_Interpreter::GenerateEvents(SSLv3_Record* rec)
+	{
+	//Generating events...
+	switch (currentState)
+		{
+		case SSL3_1_STATE_CLIENT_HELLO_SENT:
+			{
+			fire_ssl_conn_attempt( rec->sslVersion, currentCipherSuites );
+			break;
+			}
+		case SSL3_1_STATE_SERVER_HELLO_SENT:
+			{
+			fire_ssl_conn_server_reply( rec->sslVersion, currentCipherSuites );
+			break;
+			}
+		case SSL3_1_STATE_HS_FIN_A:
+		case SSL3_1_STATE_HS_FIN_B:
+			{
+			SSLv3_Interpreter::openedConnections++;
+			fire_ssl_conn_established( rec->sslVersion,
+									   pCipherSuite->identifier );
+
+			//So we finished handshake.
+			//Skip all further data.
+			proxy->SetSkip(1);
+			helloRequestValid = true;
+			break;
+			}
+		case SSL3_1_STATE_SERVER_FIN_SENT_B:
+			{
+			//first, check for session-ID match...
+			if ( clientSessionID && serverSessionID )
+				{
+				if ( memcmp(clientSessionID->data, serverSessionID->data, 
+							clientSessionID->len) != 0 )
+					{
+					Weird( "SSLv3x: Reusing session but session ID mismatch!" );
+					}
+				}
+			//printf("Fireing reusing session");
+			fire_ssl_conn_reused( serverSessionID );
+			break;
+			}
+		case SSL3_1_STATE_ERROR:
+			{
+			Weird( "SSLv3x: Received unexpected ssl record!" );
+			proxy->SetSkip(1);
+			}
+		}
+	}
+
+void SSLv3_Interpreter::SetState(int i)
+	{
+	if ( i < SSL3_1_NUM_STATES && i >= 0)
+		{
+		currentState = i;
+		}
+	}
+
+// ---SSLv3_Endpoint--------------------------------------------------------------
+	
+SSLv3_Endpoint::SSLv3_Endpoint(SSL_Interpreter* interpreter, int is_orig)
+: SSL_InterpreterEndpoint(interpreter, is_orig)
+	{
+	sslVersion = 0;
+	}	
+	
+SSLv3_Endpoint::~SSLv3_Endpoint()
+	{
+	}
+
+void SSLv3_Endpoint::Deliver(double t, int seq, int len, u_char* data)
+	{
+	if ( SSL3_1_LENGTHOFFSET + sizeof(uint16) <= len )
+		{
+		currentMessage_length = (uint16)(data[SSL3_1_LENGTHOFFSET] << 8) 
+								| data[SSL3_1_LENGTHOFFSET +1 ]; 
+		if ( currentMessage_length > 18432 )
+			{
+			interpreter->Weird( "SSLv3x: Message length too long!" );
+			}
+		}
+	else
+		{
+		interpreter->Weird( "SSLv3x: Could not determine message length!" );
+		return;
+		}
+	if ( currentMessage_length + 2 + SSL3_1_LENGTHOFFSET != len )
+		{
+		//this should never happen; otherwise there is a bug in the
+		//SSL_RecordBuilder
+		interpreter->Weird( "SSLv3x: FATAL: recordLength doesn't match data block length!" );
+		interpreter->Proxy()->SetSkip( 1 );
+		return;
+		}
+	ProcessMessage(data, len);
+	}
+	
+void SSLv3_Endpoint::ProcessMessage(const u_char* data, int len)
+	{
+	SSL3_1_ContentType ct = ExtractContentType(data, len);
+	int versionLegal = ExtractVersion(data, len);
+	if ( versionLegal )
+		{
+		switch (ct)
+			{
+			case SSL3_1_TYPE_CHANGE_CIPHER_SPEC:
+				{
+				SSLv3_ChangeCipherRecord* rec = new 
+					SSLv3_ChangeCipherRecord(data + SSL3_1_HEADERLENGTH, len - SSL3_1_HEADERLENGTH, sslVersion, this);
+				//multiple handshake messages may be coalesced into 
+				//a single record...
+				rec->Deliver((SSLv3_Interpreter*)this->interpreter);
+				Unref(rec);
+				break;
+				}
+			case SSL3_1_TYPE_ALERT:
+				{
+				SSLv3_AlertRecord* rec = new 
+					SSLv3_AlertRecord(data + SSL3_1_HEADERLENGTH, len - SSL3_1_HEADERLENGTH, sslVersion, this);
+				rec->Deliver((SSLv3_Interpreter*)this->interpreter);
+				Unref(rec);
+				break;
+				}
+			case SSL3_1_TYPE_HANDSHAKE:
+				{
+				SSLv3_HandshakeRecord* rec = 
+					new SSLv3_HandshakeRecord(data + SSL3_1_HEADERLENGTH, len - SSL3_1_HEADERLENGTH, sslVersion, this);
+				rec->Deliver((SSLv3_Interpreter*)this->interpreter);
+				Unref(rec);
+				break;
+				}
+			case SSL3_1_TYPE_APPLICATION_DATA:
+				{
+				SSLv3_ApplicationRecord* rec = 
+					new SSLv3_ApplicationRecord(data + SSL3_1_HEADERLENGTH, len - SSL3_1_HEADERLENGTH, sslVersion, this);
+				rec->Deliver((SSLv3_Interpreter*)this->interpreter);
+				Unref(rec);
+				break;
+				}
+			default:
+				{
+				interpreter->Weird( "SSLv3x: Could not determine content type!" );
+				break;
+				}
+			}
+		}
+	else
+		{
+		//SSL version not 3.0/3.1... do nothing
+		}	
+	}
+	
+SSL3_1_ContentType SSLv3_Endpoint::ExtractContentType(const u_char* data, int len)
+	{
+	return SSL3_1_ContentType((uint8)(*(data + SSL3_1_CONTENTTYPEOFFSET)));
+	}
+	
+int SSLv3_Endpoint::ExtractVersion(const u_char* data, int len)
+	{
+	sslVersion = (uint16)(data[SSL3_1_VERSIONTYPEOFFSET] << 8) | data[SSL3_1_VERSIONTYPEOFFSET + 1];
+	if ( sslVersion != SSL_ConnectionProxy::SSLv30 &&
+		 sslVersion != SSL_ConnectionProxy::SSLv31 )
+		{
+		interpreter->Weird( "SSLv3x: Unsupported SSL-Version (not SSLv3x)!" );
+		return 0;
+		}
+	else
+		{
+		return 1;
+		}
+	}
+	
+// ---SSLv3_Record----------------------------------------------------------------
+
+SSLv3_Record::SSLv3_Record(const u_char* data, int len, uint16 version, SSLv3_Endpoint const* e)
+	{
+	recordLength = len;
+	sslVersion = version;
+	endp = e;
+	this->data = data;
+	}
+	
+SSLv3_Record::~SSLv3_Record()
+	{
+	//the memory for data is deleted after processing the ssl record
+	//in the common ssl reassembler
+	}
+
+void SSLv3_Record::Describe(ODesc* d) const
+	{
+	d->Add("sslrecord");
+	}
+	
+SSLv3_Endpoint const* SSLv3_Record::GetEndpoint() const
+	{
+	return endp;
+	}
+	
+const u_char* SSLv3_Record::GetData() const
+	{
+	return data;
+	}
+	
+int SSLv3_Record::ExtractInt24(const u_char* data, int len, int offset)
+	{
+	if ( offset + int(sizeof(unsigned long)) - 1 > len)
+		return 0;
+	
+	uint32 val;
+	
+	val = 0;
+	val = (uint32)(*(data + offset + 2));
+	val |= (uint32)(*(data + offset + 1)) << 8;
+	val |= (uint32)(*(data + offset)) << 16;
+	
+	return val;
+	}
+
+int SSLv3_Record::GetRecordLength() const
+	{
+	return recordLength;
+	}
+	
+SSLv3_HandshakeRecord::SSLv3_HandshakeRecord(const u_char* data, 
+		int len, uint16 version, SSLv3_Endpoint const* e)
+: SSLv3_Record(data, len, version, e)
+	{
+	//weird-check for minimum handshake length header
+	if ( len < 4 )
+		{
+		e->Interpreter()->Weird( "SSLv3x: Handshake-header-length too small!" );
+		type = 255;
+		length = 0;
+		next = 0;
+		}
+	else
+		{
+		// don't analyze encrypted client handshake messages
+		if ( e->IsOrig() &&
+			(((SSLv3_Interpreter*) e->Interpreter())->change_cipher_client_seen) &&
+			!(((SSLv3_Interpreter*) e->Interpreter())->fin_client_seen))
+			{
+			type = 255;
+			length = 0;
+			next = 0;
+			return;
+			}
+			
+		// don't analyze encrypted server handshake messages
+		if ( !e->IsOrig() &&
+			(((SSLv3_Interpreter*) e->Interpreter())->change_cipher_server_seen) &&
+			!(((SSLv3_Interpreter*) e->Interpreter())->fin_server_seen))
+			{
+			type = 255;
+			length = 0;
+			next = 0;
+			return;
+			}
+			
+		type = (uint8)( *(this->data));
+		length = ExtractInt24(data, len, 1);
+		if ( length + 4 < len )
+			{
+			next = new SSLv3_HandshakeRecord(data + length + 4, len - (length + 4), 
+				version, e);
+			}
+		else if ( length + 4 > len )
+			{
+			e->Interpreter()->Weird( "SSLv3x: Handshake-header-length inconsistent (too big)" );
+			next = 0;
+			}
+		else
+			{
+			next = 0;
+			}
+		}
+	}
+	
+SSLv3_HandshakeRecord::~SSLv3_HandshakeRecord()
+	{
+	if (next)
+		{
+	   	delete next;
+		}
+	}
+	
+void SSLv3_HandshakeRecord::Deliver(SSLv3_Interpreter* conn)
+	{
+	SSLv3_HandshakeRecord* it = this;
+	while ( it != 0)
+		{
+		conn->DeliverSSLv3_Record(it);
+		it = it->GetNext();
+		}
+	}
+	
+int SSLv3_HandshakeRecord::GetType() const
+	{
+	return type;
+	}
+	
+int SSLv3_HandshakeRecord::GetLength() const
+	{
+	return length;
+	}
+	
+SSLv3_HandshakeRecord* SSLv3_HandshakeRecord::GetNext()
+	{
+	return next;
+	}
+	
+int SSLv3_HandshakeRecord::checkClientHello()
+	{
+	if ( recordLength < 42 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Client hello too small! ");
+		return 0;
+		}
+	
+	uint16 version = (uint16) (data[4] << 8 ) | data[5];
+	if ( (version != SSL_ConnectionProxy::SSLv30) && (version != SSL_ConnectionProxy::SSLv31) )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Corrupt version information in Client hello!" );
+		}
+	uint8 sessionIDLength = (uint8)(data[38]);
+	if ( sessionIDLength > 32 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: SessionID too long in Client hello!" );
+		return 0;
+		}
+	uint16 cipherSuiteLength = (uint16) (data[39 + sessionIDLength] << 8 ) |
+										data[40 + sessionIDLength];
+	if ( cipherSuiteLength < 2 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: CipherSuite length too small!" );
+		}
+	if ( cipherSuiteLength + sessionIDLength + 41 > recordLength )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Client hello too small, corrupt length fields!" );
+		return 0;
+		}
+	uint8 compressionMethodLength = (uint8) ( data[41 + sessionIDLength + cipherSuiteLength] );
+	if ( compressionMethodLength < 1 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: CompressionMethod length too small!" );
+		}
+	if ( (sessionIDLength + cipherSuiteLength + compressionMethodLength + 38) != 
+		length )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Corrupt length fields in Client hello!" );
+		return 0;
+		}
+	return 1;
+	
+	}
+	
+int SSLv3_HandshakeRecord::checkServerHello()
+	{
+	if ( recordLength < 42 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Server hello too small! ");
+		return 0;
+		}
+	uint16 version = (uint16) (data[4] << 8 ) | data[5];
+	if ( (version != SSL_ConnectionProxy::SSLv30) && (version != SSL_ConnectionProxy::SSLv31) )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Corrupt version information in Server hello!" );
+		}
+	uint8 sessionIDLength = (uint8)(data[38]);
+	if ( sessionIDLength > 32 )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: SessionID too long in Server hello!" );
+		return 0;
+		}	
+	if ( (sessionIDLength + 38) != length )
+		{
+		endp->Interpreter()->Weird( "SSLv3x: Corrupt length fields in Server hello!" );
+		return 0;
+		}
+	return 1;
+	}
+	
+SSLv3_AlertRecord::SSLv3_AlertRecord(const u_char* data, 
+	int len, uint16 version, SSLv3_Endpoint const* e)
+: SSLv3_Record(data, len, version, e)
+	{
+	if ( len < 2 ) 
+		{
+		e->Interpreter()->Weird( "SSLv3x: Alert header length too small!" );
+		level = 255;
+		description = 255;
+		}
+	//no further consistency-check ,because alerts may be already encrypted!
+	level = (uint8)( *((this->data) + SSL3_1_ALERT_LEVEL_OFFSET));
+	description = (uint8)( *((this->data) + SSL3_1_ALERT_DESCRIPTION_OFFSET));
+	}
+	
+SSLv3_AlertRecord::~SSLv3_AlertRecord()
+	{
+	}
+	
+int SSLv3_AlertRecord::GetDescription() const
+	{
+	return description;
+	}
+	
+int SSLv3_AlertRecord::GetLevel() const
+	{
+	return level;
+	}
+
+void SSLv3_AlertRecord::Deliver(SSLv3_Interpreter* conn)
+	{
+	conn->DeliverSSLv3_Record(this);
+	}	
+	
+SSLv3_ChangeCipherRecord::SSLv3_ChangeCipherRecord(const u_char* data, 
+	int len, uint16 version, SSLv3_Endpoint const* e)
+: SSLv3_Record(data, len, version, e)
+	{
+	if ( len < 1 )
+		{
+		e->Interpreter()->Weird( "SSLv3x: Change cipher header length too small!" );
+		type = 255;
+		}
+	else
+		{
+		type = (uint8)( *((this->data) + SSL3_1_CHANGE_CIPHER_TYPE_OFFSET));
+		}
+	}
+	
+SSLv3_ChangeCipherRecord::~SSLv3_ChangeCipherRecord()
+	{
+	}
+	
+int SSLv3_ChangeCipherRecord::GetType() const
+	{
+	return type;
+	}
+	
+void SSLv3_ChangeCipherRecord::Deliver(SSLv3_Interpreter* conn)
+	{
+	conn->DeliverSSLv3_Record(this);
+	}	
+	
+SSLv3_ApplicationRecord::SSLv3_ApplicationRecord(const u_char* data, 
+	int len, uint16 version, SSLv3_Endpoint const* e)
+: SSLv3_Record(data, len, version, e)
+	{
+	}
+	
+SSLv3_ApplicationRecord::~SSLv3_ApplicationRecord()
+	{
+	}
+	
+void SSLv3_ApplicationRecord::Deliver(SSLv3_Interpreter* conn)
+	{
+	conn->DeliverSSLv3_Record(this);
+	}	
+
diff -uNr bro-pub-0.8a41/SSLv3.h bro-pub-0.841-ssl/SSLv3.h
--- bro-pub-0.8a41/SSLv3.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv3.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,591 @@
+// -----------------------------------------------------
+// SSLv3/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#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 SSL_ConnectionProxy;
+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
+	//(255)
+};
+
+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
+	//(255)
+};
+
+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
+	//(255)
+};
+
+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 SSL_ConnectionProxy 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 "feeded" by the SSL_ConnectionProxy).
+ * 
+ * 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:
+
+	// some global counters
+	static uint totalConnections;     // counter for total SSLv3x connections
+	static uint openedConnections;    // counter for total SSLv3x connections with <b>complete</b> handshake
+
+	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)
+
+	
+	/** The constructor takes the SSL_ConnectionProxy as argument, that created
+	 * this SSLv3_Interpreter.
+	 * 
+	 * @param proxy the creating SSL_ConectionProxy
+	 */
+	SSLv3_Interpreter(SSL_ConnectionProxy* proxy);
+	~SSLv3_Interpreter();
+	
+	/** Delivers a 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 a 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 a 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_AlertRecord
+	 */
+	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 SSL_ConnectionProxy 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);
+	
+	/** Prints out some counters.
+	 */
+	static void printStats();
+
+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
+	TableVal* currentCipherSuites; ///< pointer to a TableVal (of BRO type: cipher_suites_list) containing the cipher suites seen in the last record 
+	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);
+	
+	/** 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 SSL_ConnectionProxy.
+ * The defragmentation and reassembling already took place in the
+ * SSL_ConnectionProxy'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);
+	~SSLv3_Endpoint();
+	
+	/** This method is invoked by this endpoint's corresponding SSL_ConnectionProxy
+	 * 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 seq  is always 0 (former: relative sequenze number (from Endpoint::start_seq))
+	 * @param len length of SSL record
+	 * @param data content of SSL record
+	 */
+	void Deliver(double t, int seq, int len, 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. The 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 <b>without</b> 
+ * 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:
+	int recordLength; ///< total length of the SSL record <b>without</b> 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
+
+	/** 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);
+
+};
+
+// ----------------------------------------------------------------------------
+
+/* 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: 
+	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)
+
+	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();
+	
+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:
+	int description; ///< holds the alert description 
+	int level; ///< holds the alert level
+
+	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);
+	
+};
+
+// ----------------------------------------------------------------------------
+
+/** 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:
+	int type; ///< holds the change cipher type
+
+	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 deliverd
+	 */
+	void Deliver(SSLv3_Interpreter* conn);
+
+};
+
+// ----------------------------------------------------------------------------
+
+/** 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
diff -uNr bro-pub-0.8a41/SSLv3Automaton.cc bro-pub-0.841-ssl/SSLv3Automaton.cc
--- bro-pub-0.8a41/SSLv3Automaton.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv3Automaton.cc	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,85 @@
+// -----------------------------------------------------
+// SSLv3/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+// ---SSLv3_Automaton----------------------------------------------------------
+
+#include "SSLv3Automaton.h"
+
+SSLv3_Automaton::SSLv3_Automaton(int num_states, int num_trans, int error_state)
+	{
+	this->num_states = num_states;
+	states = new SSLv3_State*[num_states];
+	for (int i = 0; i < num_states; i++)
+		states[i] = new SSLv3_State(num_trans, error_state);
+	}
+	
+SSLv3_Automaton::~SSLv3_Automaton()
+	{
+	for (int i = 0; i < num_states; i++)
+		delete states[i];
+	delete [] states;
+	}
+	
+void SSLv3_Automaton::Describe(ODesc* d) const
+	{
+	d->Add("sslAutomaton");
+	}
+	
+void SSLv3_Automaton::setStartState(int state)
+	{
+	if (state < num_states)
+		startState = state;
+	}
+	
+void SSLv3_Automaton::addTrans(int state1, int trans, int state2)
+	{
+	if (state1 < num_states && state2 < num_states)
+		states[state1]->addTrans(trans, state2);
+	}
+	
+int SSLv3_Automaton::getNextState(int state, int trans)
+	{
+	if (state < num_states)
+		return states[state]->getNextState(trans);
+	else
+		return 0;
+	}
+	
+int SSLv3_Automaton::getStartState()
+	{
+	if (startState >= 0)
+		return startState;
+	else return -1;
+	}
+	
+// ---SSLv3_State--------------------------------------------------------------
+	
+SSLv3_State::SSLv3_State(int num_trans, int error_state)
+	{
+	this->num_trans = num_trans;
+	transitions = new int[num_trans];
+	for (int i = 0; i < num_trans; i++)
+		transitions[i] = error_state;
+	}
+
+SSLv3_State::~SSLv3_State()
+	{
+	delete [] transitions;
+	}
+	
+void SSLv3_State::addTrans(int trans, int state)
+	{
+	if (trans < num_trans)
+		transitions[trans] = state;
+	}
+	
+int SSLv3_State::getNextState(int trans)
+	{
+	if (trans < num_trans)
+		return transitions[trans];
+	else
+		return 0;
+	}
+
diff -uNr bro-pub-0.8a41/SSLv3Automaton.h bro-pub-0.841-ssl/SSLv3Automaton.h
--- bro-pub-0.8a41/SSLv3Automaton.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/SSLv3Automaton.h	Wed Oct 15 05:19:28 2003
@@ -0,0 +1,110 @@
+// -----------------------------------------------------
+// SSLv3/TLS Implementation for Bro
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef ssl_v3_automaton_h
+#define ssl_v3_automaton_h
+#include "Obj.h"
+#include "SSLDefines.h"
+
+class SSLv3_State;
+
+/** Class SSLv3_Automaton is there for holding the transitions of a state machine.
+ * The States are simply Integer Constants >= 0. Same for the transitions.
+ * The SSLv3_Automaton holds a pointer to an array of pointers to the 
+ * states of the automaton. The array is indexed by the integer that 
+ * represents the corresponding state.
+ * By default, the automaton is initialized with every transition leading to 
+ * the error_state.
+ * By calling addTrans() (done in the SSLv3_Interpreter's BuildAutomaton()-method) 
+ * the proper transitions for the SSL automaton are created.
+ * When calling getNextState(state, trans), you get the next state of the 
+ * automaton, according to state and trans.
+ * */
+class SSLv3_Automaton : public BroObj{
+public:
+	/* The constructor initialises the states 2-dim. array 
+	 * (which's size depends on num_states and num_trans).
+	 * By default, every transition from every state leads to the error_state.
+	 * @param num_states how many states the automaton has
+	 * @param num_trans how many different transitions the automaton has
+	 * @param error_state which Integer the error_state has
+	 */
+	SSLv3_Automaton(int num_states, int num_trans, int error_state);
+	~SSLv3_Automaton();
+	void Describe(ODesc* d) const;
+	
+	/* Sets the start state of the automaton.
+	 * @param state the start state
+	 */
+	void setStartState(int state);
+	
+	/* This method is used for building up the automaton and defining
+	 * from which state you get to which state which what transition.
+	 * @param state1 the state from which the transition starts
+	 * @param trans the transition itself
+	 * @param to which state the transition leads
+	 */
+	void addTrans(int state1, int trans, int state2);
+	
+	/* Used for determinig into which state the automaton gets by using the 
+	 * given transition in the given state.
+	 * @param state the state from which the transition starts
+	 * @param trans the transition itself
+	 * @return the state to which the transition leads
+	 */
+	int getNextState(int state, int trans);
+	int getStartState();
+	int OutRef()
+		{
+		return RefCnt();
+		}
+
+protected:
+	int num_states; ///< how many states the automaton has
+	SSLv3_State** states; ///< the pointer to the array of pointers that holds the states
+	int startState; ///< the start state of the automaton
+	
+};
+
+// ----------------------------------------------------------------------------
+
+/** This class represents a state of the SSLv3_Automaton. 
+ * It holds a pointer to an array of integers, which corresponds to the 
+ * succeeding states of this state when "taking" a transition. 
+ * The transition array is indexed by the integer-values corresponding to
+ * the transitions of the automaton.
+ * */
+class SSLv3_State{
+public:
+	/* The constructor initialises the state. By default, every transition
+	 * of the automaton leads to the error_state.
+	 * @param num_trans how many different transitions the automaton has
+	 * @param error_state how many different transitions the automaton has
+	 */
+	SSLv3_State(int num_trans, int error_state);
+	~SSLv3_State();
+	
+	/* This method is used for building up the automaton and is invoked by
+	 * the SSLv3_Automaton's addTrans()-method. It defines the successing state
+	 * of the automaton by taking the transition trans in this state.
+	 * @param trans the transition,
+	 * @param that leads to the state
+	 */
+	void addTrans(int trans, int state);
+	
+	/* Used for determinig into which state the automaton gets by using the 
+	 * given transition in the this state.
+	 * @param trans which transition is to be taken
+	 * @return the resulting state of the automaton
+	 */
+	int getNextState(int trans);
+
+protected:
+	int num_trans; ///< how many transitions the automaton has
+	int* transitions; ///< the array of successing states of this state by taking the transition that indexes this array
+
+};
+
+#endif
diff -uNr bro-pub-0.8a41/Sessions.cc bro-pub-0.841-ssl/Sessions.cc
--- bro-pub-0.8a41/Sessions.cc	Sun Aug 31 02:39:30 2003
+++ bro-pub-0.841-ssl/Sessions.cc	Wed Oct 15 05:18:32 2003
@@ -46,6 +46,7 @@
 #include "SSH.h"
 #include "NTP.h"
 #include "ICMP.h"
+#include "SSLProxy.h"
 
 #include "SteppingStone.h"
 #include "BackDoor.h"
@@ -744,6 +745,25 @@
 		     netbios_session_rejected )
 			c = new TCP_NetbiosSSN(this, k, t, id, tp);
 		break;
+
+	case 443: // https
+	case 563: // nntps
+	case 585: // imap4-ssl (old, use imaps)
+	case 614: // sshell
+	case 636: // ldaps
+	case 989: // ftps-data
+	case 990: // ftps
+	case 992: // telnets
+	case 993: // imaps
+	case 994: // ircs
+	case 995: // pop3s
+		if ( ssl_certificate_seen || ssl_certificate ||
+			ssl_conn_attempt || ssl_conn_server_reply || ssl_conn_established ||
+			ssl_conn_reused || ssl_conn_alert)
+			{
+			c = new SSL_ConnectionProxy(this, k, t, id, tp);
+			}
+		break;
 	}
 
 	if ( ! c )
@@ -817,6 +837,17 @@
 	case 53:
 	case 111:
 	case 139:
+	case 443: // https
+	case 563: // nntps
+	case 585: // imap4-ssl (old, use imaps)
+	case 614: // sshell
+	case 636: // ldaps
+	case 989: // ftps-data
+	case 990: // ftps
+	case 992: // telnets
+	case 993: // imaps
+	case 994: // ircs
+	case 995: // pop3s
 		return 1;
 
 	default:
diff -uNr bro-pub-0.8a41/Sessions.h bro-pub-0.841-ssl/Sessions.h
--- bro-pub-0.8a41/Sessions.h	Sun Aug 31 02:39:30 2003
+++ bro-pub-0.841-ssl/Sessions.h	Wed Oct 15 05:17:51 2003
@@ -108,7 +108,7 @@
 
 protected:
 	Connection* NewConn(HashKey* k, double t, const ConnID* id,
-			const u_char* data, int is_tcp);
+			const u_char* data, int proto);
 
 	TCP_Connection* NewConn(HashKey* k, double t, const ConnID* id,
 			const struct tcphdr* tp);
diff -uNr bro-pub-0.8a41/TCP.cc bro-pub-0.841-ssl/TCP.cc
--- bro-pub-0.8a41/TCP.cc	Fri Oct 10 07:03:31 2003
+++ bro-pub-0.841-ssl/TCP.cc	Wed Oct 15 05:17:51 2003
@@ -416,7 +416,9 @@
 
 	t_reassem->NewBlock(t, seq, len, data);
 
-	return 1;
+	// BUG: this will always record the packet if it hasn't been skipped!
+	//return 1;
+	return 0;
 	}
 
 void TCP_EndpointContents::AckReceived(double /* t */, int seq)
diff -uNr bro-pub-0.8a41/X509.cc bro-pub-0.841-ssl/X509.cc
--- bro-pub-0.8a41/X509.cc	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/X509.cc	Wed Oct 15 05:19:31 2003
@@ -0,0 +1,238 @@
+// -----------------------------------------------------
+// Bro Support for X.509 certificates
+// Using OpenSSL
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#include "X509.h"
+
+X509_STORE*    X509_Cert::ctx    = NULL;
+X509_LOOKUP*   X509_Cert::lookup = NULL;
+X509_STORE_CTX X509_Cert::csc;
+bool X509_Cert::bInited = false;
+
+// TODO: Check if Key < 768 Bits => Weakness!
+// FIXME: Merge verify and verifyChain
+
+void X509_Cert::sslCertificateEvent( SSL_ProxyEndpoint* e, X509* pCert )
+{
+	char tmp[256];
+	EventHandlerPtr event = ssl_certificate;
+	if ( event )
+		{
+		RecordVal* pX509Cert = new RecordVal( x509_type );
+		X509_NAME_oneline( X509_get_issuer_name( pCert ), tmp, sizeof tmp );
+		pX509Cert->Assign( 0, new StringVal( tmp ) );
+		X509_NAME_oneline( X509_get_subject_name( pCert ), tmp, sizeof tmp );
+		pX509Cert->Assign( 1, new StringVal( tmp ) );
+		val_list* vl = new val_list;
+		vl->append(e->Conn()->BuildConnVal());
+		vl->append(pX509Cert);
+		if ( e->IsOrig() )
+			{
+			vl->append( new Val(0, TYPE_BOOL));
+			}
+		else
+			{
+			vl->append( new Val(1, TYPE_BOOL));
+			}
+		e->Conn()->ConnectionEvent(event, vl);
+		}
+}
+
+int X509_Cert::init()
+{
+	OpenSSL_add_all_algorithms();
+
+	ctx = X509_STORE_new();
+
+	if ( x509_trusted_cert_path &&
+		 x509_trusted_cert_path->AsString()->Len() > 0 )
+	{
+		// add the path(s) for the local CA's certificates
+		BroString* pString = x509_trusted_cert_path->AsString();
+		
+		printf( "X509: Using %s as trusted cert path.\n", (const char*) pString->Bytes() );
+		
+		int i = 0;
+		lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir());
+		if ( lookup == NULL )
+		{
+			fprintf( stderr, "X509_Cert::init(): initing lookup failed\n" );
+			return i;
+		}
+		i=X509_LOOKUP_add_dir( lookup,
+							   (const char*) pString->Bytes(),
+							   X509_FILETYPE_PEM);
+		if ( !i )
+		{
+		fprintf( stderr, "X509_Cert::init(): error adding lookup directory\n" );
+			return i;
+		}
+	}
+	else
+	{
+		printf( "X509: Using the default trusted cert path.\n" );
+		X509_STORE_set_default_paths(ctx);
+	}
+
+	bInited = true;
+	return 0;
+}
+
+int X509_Cert::verify( SSL_ProxyEndpoint* e, u_char* data, uint32 len )
+{
+	if ( !bInited )
+	{
+		init();
+	}
+
+	X509* pCert = NULL;
+	pCert = d2i_X509( NULL, &data, len );
+	if ( pCert == NULL )
+	{
+		fprintf( stderr, "X509_Cert::verify(): Error converting cert from DER to internal structure!\n" );
+		return -1;		
+	}
+
+	// throw an event
+	SSL_ConnectionProxy* conn = (SSL_ConnectionProxy*) e->Conn();
+	sslCertificateEvent( e, pCert );
+
+	X509_STORE_CTX_init(&csc,ctx,pCert,NULL);
+	X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time);
+	int i = X509_verify_cert(&csc);
+	X509_STORE_CTX_cleanup(&csc);
+	int ret = 0;
+
+	if( !i )
+	{
+		char buf[256];
+
+		X509_NAME_oneline(
+				X509_get_subject_name(csc.current_cert),buf,
+				sizeof buf);
+		//printf("error %d at %d depth lookup:%s\n",csc.error,
+		//csc.error_depth,
+		//	X509_verify_cert_error_string(csc.error));		
+	
+		// FIXME: use something like sprintfn to avoid buffer overflows
+		char output[256];
+		sprintf( output, "X509: Certificate check FAILED (%s)!", X509_verify_cert_error_string(csc.error) );
+		conn->Weak( output );
+		sprintf( output, "      Subject = %s", buf );
+		conn->Weak( output );
+
+		ret = csc.error;
+	}
+	else
+	{
+		ret = 0;
+	}
+
+	delete pCert;
+	return ret ;
+}
+
+int X509_Cert::verifyChain( SSL_ProxyEndpoint* e, u_char* data, uint32 len )
+{
+	if ( !bInited )
+	{
+		init();
+	}
+
+	// gets a ssl3x cert chain (could be one single cert, too, but in chain format)
+
+	STACK_OF(X509)* untrustedCerts = NULL; // chain of untrusted certs
+	X509* pCert = NULL; // base cert, this one is to be verified
+
+	// init the stack
+	untrustedCerts = sk_new_null();
+	if ( untrustedCerts == NULL )
+	{
+		// internal error
+		fprintf( stderr, "X509_Cert::verifyChain(): Error allocating stack of untrusted certs!" );
+		return -1;
+	}
+
+	// NOT AGAIN!!!
+	// extract certificates and put them into an OpenSSL Stack
+	uint tempLength = 0;
+	int certCount = 0;
+	while( tempLength < len )
+		{
+			certCount++;
+			uint32 certLength = (uint32) ((data[tempLength + 0] << 16) |
+										   data[tempLength + 1] << 8) |
+										   data[tempLength + 2];
+
+			u_char* pCurrentCert = &data[tempLength+3]; // points to current cert
+			X509* pTemp = d2i_X509( NULL, &pCurrentCert, certLength );
+			if ( pTemp == NULL )
+			{
+				fprintf( stderr, "X509_Cert::verify(): Error converting cert from DER to internal structure!\n" );
+				//FIXME: free ptrs
+				return -1;
+			}
+
+			if ( certCount == 1 )
+			{
+				// the first certificate goes directly into the ctx
+				pCert = pTemp;
+			}
+			else
+			{
+				// the remaining certificates (if any) are put into the list of
+				// untrusted certificates
+				sk_push( untrustedCerts, (char*) pTemp );
+			}
+
+			tempLength += certLength + 3;
+		}
+
+
+	// throw an event
+	SSL_ConnectionProxy* conn = (SSL_ConnectionProxy*) e->Conn();
+	sslCertificateEvent( e, pCert );
+
+// copied
+
+	X509_STORE_CTX_init( &csc, ctx, pCert, untrustedCerts );
+	X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time);
+	int i = X509_verify_cert(&csc);
+	X509_STORE_CTX_cleanup(&csc);
+	//X509_STORE_CTX_free(&csc);
+	int ret = 0;
+
+	if( !i )
+	{
+		char buf[256];
+
+		X509_NAME_oneline(
+				X509_get_subject_name(csc.current_cert),buf,
+				sizeof buf);
+		//printf("error %d at %d depth lookup:%s\n",csc.error,
+		//csc.error_depth,
+		//	X509_verify_cert_error_string(csc.error));		
+	
+		// FIXME: use something like sprintfn to avoid buffer overflows
+		char output[256];
+		sprintf( output, "X509: Certificate check FAILED (%s)!", X509_verify_cert_error_string(csc.error) );
+		conn->Weak( output );
+		sprintf( output, "      Subject = %s", buf );
+		conn->Weak( output );
+
+		ret = csc.error;
+	}
+	else
+	{
+		ret = 0;
+	}
+
+	// free the allocated certificate
+	delete pCert;
+	// free the stack incl. contents
+	sk_pop_free( untrustedCerts, free ); // FIXME: this could break Bro's memory tracking
+
+	return ret;
+}
diff -uNr bro-pub-0.8a41/X509.h bro-pub-0.841-ssl/X509.h
--- bro-pub-0.8a41/X509.h	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/X509.h	Wed Oct 15 05:19:31 2003
@@ -0,0 +1,39 @@
+// -----------------------------------------------------
+// Bro Support for X.509 certificates
+// Using OpenSSL
+// Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+// -----------------------------------------------------
+
+#ifndef X509_H
+#define X509_H
+
+// FIXME: Don't know where u_char is defined, so we take TCP.h :-(
+#include "TCP.h"
+#include "SSLProxy.h"
+
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+class X509_Cert
+{
+	public:
+
+	static X509_STORE*    ctx;
+	static X509_LOOKUP*   lookup;
+	static X509_STORE_CTX csc;
+	static bool bInited;
+	
+	// init's the OpenSSL library which is used for verify()
+	// has to be called once on startup
+	static int init();
+
+	// get's a DER encoded X.509 certificate
+	// returns 0 if failed, succeeded otherwise
+	static int verify( SSL_ProxyEndpoint* e, u_char* data, uint32 len );
+	static int verifyChain( SSL_ProxyEndpoint* e, u_char* data, uint32 len );
+
+	// this is a wrapper for the ssl_certificate event
+	static void sslCertificateEvent( SSL_ProxyEndpoint* e, X509* pCert );
+};
+
+#endif

diff -uNr bro-pub-0.8a41/bro.bif bro-pub-0.841-ssl/bro.bif
--- bro-pub-0.8a41/bro.bif	Fri Oct 10 05:27:26 2003
+++ bro-pub-0.841-ssl/bro.bif	Wed Oct 15 05:17:51 2003
@@ -154,6 +154,27 @@
 		}
 		break;
 
+	case 'x':
+	case 'X':
+		{
+		if ( t != TYPE_COUNT )
+			{
+			builtin_run_time("bad type for hex format", v);
+			break;
+			}
+			
+			char hex_fmt[512];
+			char buf[512];
+			
+			if ( field_width >= 0 )
+				sprintf(hex_fmt, "%%%d%c", field_width, *fmt);
+			else
+				sprintf(hex_fmt, "%%%c", *fmt);	
+			sprintf(buf, hex_fmt, v->CoerceToInt());
+			s.Add(buf);			
+		}
+		break;
+		
 	default:
 		builtin_run_time("bad format");
 	}
diff -uNr bro-pub-0.8a41/doc/manual-src/analysis.tex bro-pub-0.841-ssl/doc/manual-src/analysis.tex
--- bro-pub-0.8a41/doc/manual-src/analysis.tex	Sun Nov 17 06:05:52 2002
+++ bro-pub-0.841-ssl/doc/manual-src/analysis.tex	Wed Oct 15 05:18:49 2003
@@ -463,13 +463,13 @@
 {\tt TCP_SYN_ACK_SENT} & It has sent a SYN ACK to respond to a connection request. \\
 \hline
 {\tt TCP_PARTIAL} & The endpoint has been active, but we did not see the
-			beginning of the connection. \\
-			\hline
+                        beginning of the connection. \\
+                        \hline
 {\tt TCP_ESTABLISHED} & The two endpoints have established a connection. \\
 \hline
 {\tt TCP_CLOSED} & The endpoint has sent a FIN in order to close its end of the
-	connection. \\
-	\hline
+        connection. \\
+        \hline
 {\tt TCP_RESET} & The endpoint has sent a RST to abruptly terminate the\
 connection. \\
 \hline
@@ -864,13 +864,13 @@
 \hline
 \hline
 \verb+}+ & \indtt{S0}{connection state} &
-	Connection attempt seen, no reply. \\
+        Connection attempt seen, no reply. \\
 \hline
 \verb+>+ & \indtt{S1}{connection state} &
-	Connection established, not terminated. \\
+        Connection established, not terminated. \\
 \hline
 \verb+>+ & \indtt{SF}{connection state} &
-	Normal establishment and termination.
+        Normal establishment and termination.
     Note that this is the same symbol as for state {\tt S1}.  You can tell
     the two apart because for {\tt S1} there will not be any byte counts
     in the summary, while for {\tt SF} there will be.
@@ -881,39 +881,39 @@
 \verb+[+ & \indtt{REJ}{connection state} &   Connection attempt rejected. \\
 \hline
 \verb+}2+ & \indtt{S2}{connection state} &
-	Connection established and close attempt by originator
-			 seen (but no reply from responder). \\
+        Connection established and close attempt by originator
+                         seen (but no reply from responder). \\
 \hline
 \verb+}3+ & \indtt{S3}{connection state} &
-	Connection established and close attempt by responder
-			 seen (but no reply from originator). \\
+        Connection established and close attempt by responder
+                         seen (but no reply from originator). \\
 \hline
 \verb+>]+ & \indtt{RSTO}{connection state} &
-	Connection established, originator aborted (sent a RST). \\
+        Connection established, originator aborted (sent a RST). \\
 \hline
 \verb+>[+ & \indtt{RSTR}{connection state} &
-	Established, responder aborted. \\
+        Established, responder aborted. \\
 \hline
 \verb+}]+ & \indtt{RSTOS0}{connection state} &
-	Originator sent a SYN followed by a RST,
-		we never saw a SYN ACK from the responder. \\
+        Originator sent a SYN followed by a RST,
+                we never saw a SYN ACK from the responder. \\
 \hline
 \verb+<[+ & \indtt{RSTRH}{connection state} &
-	Responder sent a SYN ACK followed by a RST,
-		we never saw a SYN from the (purported) originator. \\
+        Responder sent a SYN ACK followed by a RST,
+                we never saw a SYN from the (purported) originator. \\
 \hline
 \verb+>h+ & \indtt{SH}{connection state} &
-	Originator sent a SYN followed by a FIN,
-		we never saw a SYN ACK from the responder (hence the
-		connection was ``half" open). \\
+        Originator sent a SYN followed by a FIN,
+                we never saw a SYN ACK from the responder (hence the
+                connection was ``half" open). \\
 \hline
 \verb+<h+ & \indtt{SHR}{connection state} &
-	Responder sent a SYN ACK followed by a FIN,
-		we never saw a SYN from the originator. \\
+        Responder sent a SYN ACK followed by a FIN,
+                we never saw a SYN from the originator. \\
 \hline
 \verb+?>?+ & \indtt{OTH}{connection state} &
-	No SYN seen, just midstream traffic (a ``partial
-				connection'' that was not later closed). \\
+        No SYN seen, just midstream traffic (a ``partial
+                                connection'' that was not later closed). \\
 \privatenote{explain what happens for partial connections that \emph{are}
 closed.}
 \hline
@@ -1611,51 +1611,51 @@
 \hline
 \hline
 \verb+CONN_ATTEMPTED+
-		& Connection attempted, no reply seen.  Note that
-			you should also use this value for scans with
-			indeterminant state, such as possible stealth scans.
-			For example,
-			\xrefevent{connection_half_finished}
-			does this.
-			\index{scanning!stealth}
-			\index{stealth scans}
-		& {\tt check_spoof}. \\
+                & Connection attempted, no reply seen.  Note that
+                        you should also use this value for scans with
+                        indeterminant state, such as possible stealth scans.
+                        For example,
+                        \xrefevent{connection_half_finished}
+                        does this.
+                        \index{scanning!stealth}
+                        \index{stealth scans}
+                & {\tt check_spoof}. \\
 \hline
 \verb+CONN_ESTABLISHED+
-		& Connection established.  Also used for connections
-			apparently established, per \xrefevent{partial_connection}.
-		& {\tt check_spoof}, {\tt flag_successful_service},
-		{\tt flag_successful_inbound_\linebreak[0]service},
-		{\tt allow_services_to},
-		{\tt terminate_successful_\linebreak[0]inbound_\linebreak[0]service}.
-		\\
+                & Connection established.  Also used for connections
+                        apparently established, per \xrefevent{partial_connection}.
+                & {\tt check_spoof}, {\tt flag_successful_service},
+                {\tt flag_successful_inbound_\linebreak[0]service},
+                {\tt allow_services_to},
+                {\tt terminate_successful_\linebreak[0]inbound_\linebreak[0]service}.
+                \\
 \hline
 \verb+APPL_ESTABLISHED+
-		& The connection has reached application-layer
-			establishment.  For example, for Telnet or Rlogin,
-			this is after the user has authenticated.
-		& {\tt allow_services_to},
-		  {\tt allow_service_pairs},
-		  {\tt allow_pairs},
-		  {\tt allow_16_net_pairs},
-		  {\tt hot_srcs},
-		  {\tt hot_dsts},
-		  {\tt hot_src_24nets},
-		  {\tt hot_\linebreak[0]dst_\linebreak[0]24nets}.
-		\\
+                & The connection has reached application-layer
+                        establishment.  For example, for Telnet or Rlogin,
+                        this is after the user has authenticated.
+                & {\tt allow_services_to},
+                  {\tt allow_service_pairs},
+                  {\tt allow_pairs},
+                  {\tt allow_16_net_pairs},
+                  {\tt hot_srcs},
+                  {\tt hot_dsts},
+                  {\tt hot_src_24nets},
+                  {\tt hot_\linebreak[0]dst_\linebreak[0]24nets}.
+                \\
 \hline
 \verb+CONN_FINISHED+
-		& The connection has finished, either cleanly or
-		  abnormally (for example,
-		  \xrefevent{connection_reset}).
-		& Same as {\tt APPL_ESTABLISHED}, if the connection
-		  exchanged non-zero amounts of data in both directions,
-		  and if the service wasn't one of the ones that generates
-		  {\tt APPL_ESTABLISHED}. \\
+                & The connection has finished, either cleanly or
+                  abnormally (for example,
+                  \xrefevent{connection_reset}).
+                & Same as {\tt APPL_ESTABLISHED}, if the connection
+                  exchanged non-zero amounts of data in both directions,
+                  and if the service wasn't one of the ones that generates
+                  {\tt APPL_ESTABLISHED}. \\
 \hline
 \verb+CONN_REJECTED+
-		& The connection attempt was rejected by the server.
-		& {\tt check_spoof}, {\tt flag_rejected_service}. \\
+                & The connection attempt was rejected by the server.
+                & {\tt check_spoof}, {\tt flag_rejected_service}. \\
 \hline
 \end{tabular}
 \end{center}
@@ -1852,10 +1852,10 @@
 \index{shell scripts!drop-connectivity@\emph{drop-connectivity}}
 Dropping connectivity requires all of the following to be true:
 \begin{itemize}
-	\item \xrefvar{can_drop_connectivity} is true.
-	\item The address is neither local
-	      nor a neighbor \pxref{neighbor-addresses}.
-	\item The address is not in \xrefvar{never_shut_down}.
+        \item \xrefvar{can_drop_connectivity} is true.
+        \item The address is neither local
+              nor a neighbor \pxref{neighbor-addresses}.
+        \item The address is not in \xrefvar{never_shut_down}.
 \end{itemize}
 If these checks succeed, then the script simply attempts to invoke
 a shell script \emph{drop-connectivity} with a single argument, the IP
@@ -3169,125 +3169,125 @@
 \indextext{excessive_typeahead}{login confusion state}
 \index{heuristics!type-ahead}
 \index{type-ahead!maximum allowed}
-		& The user has typed ahead 12~or more lines.
-		  \deficiency{ The upper bound should be adjustable. } \\
+                & The user has typed ahead 12~or more lines.
+                  \deficiency{ The upper bound should be adjustable. } \\
 \hline
 \indextext{extra_repeat_text}{login confusion state}
 \index{repeat text (VMS)}
 \index{heuristics!VMS}
 \index{VMS input editing}
-		& The user has entered more than one VMS repeat sequence
-		  (an escape followed by ``\verb+[A+'') on the same line.
-		  \note{ Bro determines that a login session involves a
-		  VMS server if the server prompts with ``\indextext{Username:}{VMS login prompt}''.
-		  It then interprets VMS repeat sequences as indicating
-		  it should replace the current line with the previous line. }
-		  \\
+                & The user has entered more than one VMS repeat sequence
+                  (an escape followed by ``\verb+[A+'') on the same line.
+                  \note{ Bro determines that a login session involves a
+                  VMS server if the server prompts with ``\indextext{Username:}{VMS login prompt}''.
+                  It then interprets VMS repeat sequences as indicating
+                  it should replace the current line with the previous line. }
+                  \\
 \hline
 \indextext{multiple_USERs}{login confusion state}
 \index{heuristics!multiple usernames}
 \index{usernames!repeated}
 \index{multiple usernames}
-		& The user has specified more than one username using
-		  the \indenv{USER} environment variable.
-		  \\
+                & The user has specified more than one username using
+                  the \indenv{USER} environment variable.
+                  \\
 \hline
 \indextext{multiple_login_prompts}{login confusion state}
 \index{heuristics!multiple login prompts}
 \index{login prompts!repeated}
 \index{multiple login prompts}
-		& The analyzer has seen several login prompts on
-		  the same line, and has not seen a corresponding
-		  number of lines typed ahead previously by the user.
-		  \\
+                & The analyzer has seen several login prompts on
+                  the same line, and has not seen a corresponding
+                  number of lines typed ahead previously by the user.
+                  \\
 \hline
 \indextext{no_login_prompt}{login confusion state}
 \index{heuristics!missing login prompt}
 \index{login prompts!missing}
 \index{missing login prompts}
-		& The analyzer has seen 50~lines sent by the server
-		  without any of them matching \xrefvar{login_prompts}.
-		  \deficiency{ The value of 50 should be adjustable. }
-		  \\
+                & The analyzer has seen 50~lines sent by the server
+                  without any of them matching \xrefvar{login_prompts}.
+                  \deficiency{ The value of 50 should be adjustable. }
+                  \\
 \hline
 \indextext{no_username}{login confusion state}
 \index{heuristics!missing username}
 \index{usernames!missing}
 \index{missing username}
-		& The analyzer is generating an event after having
-		  already seen a login failure, but the user's input
-		  has not provided another username to include with
-		  the event.  \note{ If the analyzer's heuristics indicate
-		  it's okay that no new username has been given, such
-		  as when the event is generated due to one connection
-		  endpoint closing the connection, then it instead uses
-		  the username }
-		  \protect\index{none@\verb+<none>+ username}
-		  \protect\index{usernames!none@\verb+<none>+}
-		  \verb+<none>+ .
-		  \\
+                & The analyzer is generating an event after having
+                  already seen a login failure, but the user's input
+                  has not provided another username to include with
+                  the event.  \note{ If the analyzer's heuristics indicate
+                  it's okay that no new username has been given, such
+                  as when the event is generated due to one connection
+                  endpoint closing the connection, then it instead uses
+                  the username }
+                  \protect\index{none@\verb+<none>+ username}
+                  \protect\index{usernames!none@\verb+<none>+}
+                  \verb+<none>+ .
+                  \\
 \hline
 \indextext{no_username2}{login confusion state}
 \index{heuristics!missing username}
 \index{usernames!missing}
 \index{missing username}
-		& The analyzer saw an additional password prompt
-		  without seeing an intervening username, and it has
-		  no previous username to reuse.
-		  \\
+                & The analyzer saw an additional password prompt
+                  without seeing an intervening username, and it has
+                  no previous username to reuse.
+                  \\
 \hline
 \indextext{non_empty_multi_login}{login confusion state}
 \index{heuristics!multiple login prompts}
 \index{login prompts!repeated}
 \index{multiple login prompts}
-		& The analyzer saw multiple adjacent login prompts,
-		  with an apparently ignored intervening username
-		  typed-ahead between them.
-		  \\
+                & The analyzer saw multiple adjacent login prompts,
+                  with an apparently ignored intervening username
+                  typed-ahead between them.
+                  \\
 \hline
 \indextext{possible_login_ploy}{login confusion state}
 \index{heuristics!attacker-induced confusion}
 \index{authentication dialog!evasion}
 \index{evasion!authentication dialog}
-		& The client sent text that matches one of the
-		  patterns reflecting text usually sent by the
-		  server.  This form of confusion can reflect
-		  an attacker attempting to evade the monitor.
-		  For example, the client may have sent
-		  the text ``{\tt login:}'' as a username so that
-		  when echoed back by the server, the analyzer would
-		  misinterpret it as reflecting another login prompt from
-		  the server.
-		  \\
+                & The client sent text that matches one of the
+                  patterns reflecting text usually sent by the
+                  server.  This form of confusion can reflect
+                  an attacker attempting to evade the monitor.
+                  For example, the client may have sent
+                  the text ``{\tt login:}'' as a username so that
+                  when echoed back by the server, the analyzer would
+                  misinterpret it as reflecting another login prompt from
+                  the server.
+                  \\
 \hline
 \indextext{repeat_without_username}{login confusion state}
 \index{repeat text}
 \index{heuristics!VMS}
 \index{VMS input editing}
-		& The user entered a VMS repeat sequence but there is
-		  no username to repeat.  (See {\tt extra_repeat_text}
-		  for a discussion of the analyzer's heuristics for
-		  dealing with VMS servers.)
-		  \\
+                & The user entered a VMS repeat sequence but there is
+                  no username to repeat.  (See {\tt extra_repeat_text}
+                  for a discussion of the analyzer's heuristics for
+                  dealing with VMS servers.)
+                  \\
 \hline
 \indextext{responder_environment}{login confusion state}
 \index{environment!responder}
 \index{heuristics!environment}
 \index{Telnet!options!environment}
 \index{environment!Telnet options}
-		& The responder (login server) has signaled a set
-		  of environment variables to the originator (login
-		  client).  This is in the opposite direction as to
-		  what makes sense.
-		  \\
+                & The responder (login server) has signaled a set
+                  of environment variables to the originator (login
+                  client).  This is in the opposite direction as to
+                  what makes sense.
+                  \\
 \hline
 \indextext{username_with_embedded_repeat}{login confusion state}
 \index{repeat text}
 \index{heuristics!VMS}
 \index{VMS input editing}
-		& The line repeated by a VMS server in response to
-		  a repeat sequence itself contains a repeat sequence.
-		  \\
+                & The line repeated by a VMS server in response to
+                  a repeat sequence itself contains a repeat sequence.
+                  \\
 \hline
 \end{tabular}
 \end{center}
@@ -4105,23 +4105,23 @@
 \hline
 \hline
 \indplain{NULL}{portmapper call}
-		& A do-nothing call typically provided by all RPC services. \\
+                & A do-nothing call typically provided by all RPC services. \\
 \hline
 \indplain{GETPORT}{portmapper call}
-		& Look up the port associated with a given RPC program. \\
+                & Look up the port associated with a given RPC program. \\
 \hline
 \indplain{SET}{portmapper call}
-		& Add a new port mapping (or replace an existing mapping)
-		  for an RPC program. \\
+                & Add a new port mapping (or replace an existing mapping)
+                  for an RPC program. \\
 \hline
 \indplain{UNSET}{portmapper call}
-		& Remove a port mapping. \\
+                & Remove a port mapping. \\
 \hline
 \indplain{DUMP}{portmapper call}
-		& Retrieve all of the RPC program mappings. \\
+                & Retrieve all of the RPC program mappings. \\
 \hline
 \indplain{CALLIT}{portmapper call}
-		& Both look up a program and then directly call it. \\
+                & Both look up a program and then directly call it. \\
 \hline
 \end{tabular}
 \end{center}
@@ -4300,7 +4300,7 @@
 For example:
 \begin{verbatim}
     972616255.679799 rpc: 65.174.102.21/832 > 182.7.9.47/portmapper
-	pm_getport: nfs -> 2049/udp
+        pm_getport: nfs -> 2049/udp
 \end{verbatim}
 However, it does not generate the alert if either the client host and
 service are present in \xrefvar{suppress_pm_log}, or if it already generated
@@ -4353,32 +4353,32 @@
 \hline
 \hline
 \indextext{ok}{RPC status code}
-	& The call succeeded. \\
+        & The call succeeded. \\
 \hline
 \indextext{prog unavail}{RPC status code}
-	& The call was for an RPC program that
-	has not registered with the portmapper. \\
+        & The call was for an RPC program that
+        has not registered with the portmapper. \\
 \hline
 \indextext{mismatch}{RPC status code}
-	& The call was for a version of the RPC program that
-	has not registered with the portmapper. \\
+        & The call was for a version of the RPC program that
+        has not registered with the portmapper. \\
 \hline
 \indextext{garbage args}{RPC status code}
-	& The parameters in the call did not decode correctly. \\
+        & The parameters in the call did not decode correctly. \\
 \hline
 \indextext{system err}{RPC status code}
-	& A system error (such as out-of-memory) occurred when
-	processing the call. \\
+        & A system error (such as out-of-memory) occurred when
+        processing the call. \\
 \hline
 \indextext{timeout}{RPC status code}
-	& No reply was received within 24~seconds of the request. \\
+        & No reply was received within 24~seconds of the request. \\
 \hline
 \indextext{auth error}{RPC status code}
-	& The caller failed to authenticate to the server,
-	or was not authorized to make the call. \\
+        & The caller failed to authenticate to the server,
+        or was not authorized to make the call. \\
 \hline
 \indextext{unknown}{RPC status code}
-	& An unknown error occurred. \\
+        & An unknown error occurred. \\
 \hline
 \end{tabular}
 \end{center}
@@ -4532,65 +4532,65 @@
 \hline
 \hline
 \indtt{num_pkts}{statistic} & The number of packets sent by the endpoint, as seen by
-			the monitor.  The endpoint may have sent others
-			that the network dropped upstream from the monitor. \\
+                        the monitor.  The endpoint may have sent others
+                        that the network dropped upstream from the monitor. \\
 \hline
-\indtt{num_rxmit}{statistic}	& The number of packets retransmitted by the endpoint,
-				as seen by the monitor.\\
+\indtt{num_rxmit}{statistic}    & The number of packets retransmitted by the endpoint,
+                                as seen by the monitor.\\
 \hline
-\indtt{num_rxmit_bytes}{statistic}	& The number of bytes retransmitted by the endpoint.\\
+\indtt{num_rxmit_bytes}{statistic}      & The number of bytes retransmitted by the endpoint.\\
 \hline
-\indtt{num_in_order}{statistic}	& The number of packets sent by the endpoint that
-				arrived at the monitor in order, where
-				``in order'' means in the same order
-				as sent by the endpoint, rather than
-				in sequence number.  (Thus, a retransmission
-				can arrive in order, by this definition.)
-				Bro determines if the packet arrived in
-				\index{in-order delivery}
-				\index{IP!identification field}
-				order by applying heuristics to the IP
-				identification (ID) field, which in general
-				will increase by a small amount between
-				successive packets transmitted by an
-				endpoint. \\
-\hline
-\indtt{num_OO}{statistic}	& The number of packets sent by the endpoint that arrived
-			at the monitor out of order.  See the previous
-			\index{out-of-order delivery}
-			entry for the definition of ``in order'',
-			and hence ``out of order.'' \\
-\hline
-\indtt{num_repl}{statistic}	& The number of extra copies of packets
-				\index{packets!replication}
-				\index{replication of packets}
-				sent by the endpoint that arrived at
-				the monitor.  Bro considers a packet
-				replicated if its IP ID field is the same
-				as for the previous packet it saw from
-				the endpoint.  Using this definition,
-				a replication is most likely caused by
-				a network mechanism such as duplication of
-				a packet by a router, rather than a transport
-				mechanism such as retransmission, though
-				some TCPs fully reuse packets when
-				retransmitting them, including their
-				IP ID field. \\
-\hline
-\indtt{endian_type}{statistic}	& Whether the advance of the IP ID field
-				\index{little endian}
-				\index{big endian}
-				\index{endian issues}
-				as seen by the monitor was consistent with
-				big-endian (network order) addition,
-				little-endian, or undetermined. The
-				three values are represented by the
-				Bro constants \indtt{ENDIAN_BIG}{constant},
-				\indtt{ENDIAN_LITTLE}{constant}, and
-				\indtt{ENDIAN_UNKNOWN}{constant}.  In addition,
-				the value can be \indtt{ENDIAN_CONFUSED}{constant},
-				meaning that the monitor saw conflicting
-				evidence for little- and big-endian. \\
+\indtt{num_in_order}{statistic} & The number of packets sent by the endpoint that
+                                arrived at the monitor in order, where
+                                ``in order'' means in the same order
+                                as sent by the endpoint, rather than
+                                in sequence number.  (Thus, a retransmission
+                                can arrive in order, by this definition.)
+                                Bro determines if the packet arrived in
+                                \index{in-order delivery}
+                                \index{IP!identification field}
+                                order by applying heuristics to the IP
+                                identification (ID) field, which in general
+                                will increase by a small amount between
+                                successive packets transmitted by an
+                                endpoint. \\
+\hline
+\indtt{num_OO}{statistic}       & The number of packets sent by the endpoint that arrived
+                        at the monitor out of order.  See the previous
+                        \index{out-of-order delivery}
+                        entry for the definition of ``in order'',
+                        and hence ``out of order.'' \\
+\hline
+\indtt{num_repl}{statistic}     & The number of extra copies of packets
+                                \index{packets!replication}
+                                \index{replication of packets}
+                                sent by the endpoint that arrived at
+                                the monitor.  Bro considers a packet
+                                replicated if its IP ID field is the same
+                                as for the previous packet it saw from
+                                the endpoint.  Using this definition,
+                                a replication is most likely caused by
+                                a network mechanism such as duplication of
+                                a packet by a router, rather than a transport
+                                mechanism such as retransmission, though
+                                some TCPs fully reuse packets when
+                                retransmitting them, including their
+                                IP ID field. \\
+\hline
+\indtt{endian_type}{statistic}  & Whether the advance of the IP ID field
+                                \index{little endian}
+                                \index{big endian}
+                                \index{endian issues}
+                                as seen by the monitor was consistent with
+                                big-endian (network order) addition,
+                                little-endian, or undetermined. The
+                                three values are represented by the
+                                Bro constants \indtt{ENDIAN_BIG}{constant},
+                                \indtt{ENDIAN_LITTLE}{constant}, and
+                                \indtt{ENDIAN_UNKNOWN}{constant}.  In addition,
+                                the value can be \indtt{ENDIAN_CONFUSED}{constant},
+                                meaning that the monitor saw conflicting
+                                evidence for little- and big-endian. \\
 \hline
 \end{tabular}
 \end{center}
@@ -4608,6 +4608,630 @@
 
 \end{description}
 
+%% --------------------------
+\labsectsection{{The \analyzer{SSL} Analyzer}}{\label{analyzer-ssl}}
+\index{SSL!analysis}
+The \indanalyzer{SSL} analyzer processes traffic associated with
+the SSL (Secure Socket Layer) protocol versions 2.0 \cite{sslv2}, 3.0 \cite{sslv30} and 3.1 \cite{tlsv1}.
+SSL version 3.1 is also known as TLS (Transport Layer Security) version 1.0 since from that
+version on the IETF has taken responsibility for further developement of SSL. Bro instantiates an
+{\tt SSL} analyzer for any connection with service ports {\tt 443/tcp (https), 563/tcp (nntps),
+585/tcp (imap4-ssl), 614/tcp (sshell), 636/tcp (ldaps), 989/tcp (ftps-data), 990/tcp (ftps), 992/tcp (telnets),
+993/tcp (imaps), 994/tcp (ircs), 995/tcp (pop3s)},
+providing you have loaded the {\tt SSL} analyzer, or defined a handler
+for one of the SSL events.
+
+By default, the analyzer uses the above set of ports as a capture filter \pxref{capture-filter}.
+It currently checks the SSL handshake process for consistency, tries to verify seen certificates,
+throws several events, does connection logging, tries to detect security weaknesses and generates simple statistics.
+However it does no decryption, so analysis is limited to clear text SSL records. This means 
+that analysis stops in the middle of the handshaking phase for SSLv2 and at the end of it for SSLv3.0/SSLv3.1(TLS).
+For this reason we have not implemented the SSL session caching mechanism (yet).
+
+The analyzer consists of the four files {\tt ssl.bro}, {\tt ssl-ciphers.bro}, {\tt ssl-alerts.bro} and {\tt weak.bro}.
+Usage is simple, just include {\tt ssl.bro}. The analyzer writes to {\tt weird.log}, {\tt ssl.log} and {\tt weak.log}.
+The first one receives all non conform and weird activity, {\tt ssl.log} tracks the SSL handshaking phase and 
+the last one is a place where security weaknesses are recorded.
+
+\subsection{The \indtt{x509}{record} record}
+\index{SSL!x509}
+
+\begin{figure}
+\label{fig:x509}
+\begin{verbatim}
+type x509: record {
+    issuer:  string; # issuer name of the certificate
+    subject: string; # subject name of the certificate
+};\end{verbatim}
+\caption[Definition of the {\tt x509} record]{
+Definition of the \indtt{x509}{record} record. }
+\end{figure}
+
+This record is a very simplified structure for storing X.509 \cite{x509} 
+certificate information. It currently supports only issuer and subject name, 
+which are stored in a one-line string format.
+
+\subsection{The \indtt{ssl_connection_info}{record} record}
+\index{SSL!connection information}
+
+\begin{figure}
+\label{fig:ssl-connection-info}
+\begin{verbatim}
+type ssl_connection_info: record {
+    id: count;                      # the log identifier number
+    connection_id: conn_id;         # IP connection information
+    version: count;                 # version associated with connection
+    client_certificate: x509;       # information from client certificate
+    server_certificate: x509;       # information from server certificate
+    cipherSuite: count;             # cipher suite client and server agreed upon
+    handshake_fin: bool;            # whether the handshaking process finished
+    cached_session: bool;           # true if this connection uses a cached session
+};\end{verbatim}
+\caption[Definition of the {\tt ssl_connection_info} record]{
+Definition of the \indtt{ssl_connection_info}{record} record. }
+\end{figure}
+
+The main data structure managed by the {\tt SSL} analyzer is
+a collection of {\tt ssl_connection_info} records, where the
+record type is shown in \f{fig:ssl-connection-info}.
+The corresponding fields are:
+
+\begin{description}
+\indfield{id}{ssl_connection_info}
+The unique connection identifier assigned to this connection.  Connections
+are numbered starting at~{\tt 1} and incrementing with each new connection.
+
+\indfield{connection_id}{ssl_connection_info}
+The TCP connection which this SSL connection is based on.
+
+\indfield{version}{ssl_connection_info}
+The SSL version number for this connection. Possible values are {\tt 0x0002} for SSLv2, 
+{\tt 0x0300} for SSLv30 and {\tt 0x0301} for SSLv31.
+
+\indfield{client_certificate}{ssl_connection_info}
+The information of the client certificate, if available.
+
+\indfield{server_certificate}{ssl_connection_info}
+The information of the server certificate, if available.
+
+\indfield{cipherSuite}{ssl_connection_info}
+The cipher suite client and server agreed upon. 
+\note{For SSLv2 cached sessions, this is a placeholder ({\tt 0xABCD})}.
+
+\indfield{handshake_fin}{ssl_connection_info}
+
+True if the analysis of the SSL handshaking phase has been completed.
+
+\indfield{cached_session}{ssl_connection_info}
+True if the connection is based on a cached SSL session identifier.
+
+\end{description}
+
+\subsection{{\tt SSL} variables}
+\index{analyzers!SSL!variables|(}
+
+The standard script defines the following redefinable variables:
+
+\begin{description}
+\indvartype{ssl_compare_cipherspecs}{bool}
+If true, bro stores the client and server cipher specs
+and performs additional tests.
+This costs an extra amount of memory (normaly only for a short time)
+but enables detecting of non-intersecting cipher sets, for example.
+
+Default: {\tt F}.
+
+\indvartype{ssl_analyze_certificates}{bool}
+If true, Bro will analyze certificates seen in SSL connections. 
+Analyzing includes the following steps:
+\begin{itemize}
+        \item Generating a hashsum of the certificate and check if we already saw 
+             it earlier from the current host. If so, we won't verify it, because we already
+                 did and verifying is a computational expensive process. If the certificate has changed
+                 for the current host, we throw a weird event.
+        \item Verification of the certificate.
+        \item Storing of the certificate on disk in DER format.
+\end{itemize}
+
+Default: {\tt T}.
+
+\indvartype{ssl_store_certificates}{bool}
+If certificates are analyzed, this variable determines if Bro should store them on disk in DER format.
+
+Default: {\tt F}.
+
+\indvartype{ssl_store_cert_path}{string}
+This is the path where Bro dumps the certificates into.
+If it's empty, we the current directory is used.
+\note{The path must not end with a slash!}
+
+Default: {\tt "../certs"}.
+
+
+\indvartype{ssl_verify_certificates}{bool}
+If certificates are analyzed, this variable determines if Bro should verify them.
+
+Default: {\tt F}.
+
+
+\indvartype{x509_trusted_cert_path}{string}
+This is the path where OpenSSL looks for the trusted certificates.
+If it's empty, the default OpenSSL path will be used.
+
+Default: {\tt ""}.
+
+
+\indvartype{ssl_max_cipherspec_size}{count}
+This is the max. size in bytes for a SSL cipherspec.
+If we see a packet that has bigger cipherspecs,
+we warn and won't do a comparisons of cipherspecs
+
+Default: {\tt 66}.
+
+
+\indvartype{ssl_store_key_material}{bool}
+If true, Bro stores key-material exchanged in the handshaking phase.
+\note{This is mainly for decryption purposes and currently useless.}
+
+Default: {\tt F}.
+
+
+
+\begin{figure}
+\label{fig:ssl-log}
+\begin{verbatim}
+1046778101.534846 #1 192.168.0.98/32988 > 213.61.126.124/https start
+1046778101.534846 #1 Connection attempt, Version: 3.1, cipher suite(s) seen:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4), 
+SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA (0xFEFF), 
+SSLv3x_RSA_WITH_3DES_EDE_CBC_SHA (0xA),
+SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA (0xFEFE), 
+SSLv3x_RSA_WITH_DES_CBC_SHA(0x9), 
+SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA (0x64),
+SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA (0x62),
+SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5 (0x3), 
+SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (0x6),
+1046778101.753356 #1 Server reply, Version: 3.1, cipher suite(s) seen:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4),
+1046778101.762601 #1 Certificate seen from: Server, Issuer:
+/C=DE/ST=Hamburg/L=Hamburg/O=TC TrustCenter for Security in Data Networks
+GmbH/OU=TC TrustCenter Class 3 CA/Email=certificate@trustcenter.de, 
+Subject:
+/C=DE/ST=Berlin/O=Lehmanns Fachbuchhandlung GmbH/OU=Zentrale EDV/CN=www.j
+fl.de/Email=admin@lehmanns.de
+1046778101.894567 #1 Handshake finished, Version: 3.1, cipher suite:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4)
+1046778104.877207 #1 finish
+---
+Used cipher-suites statistics:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4): 1
+
+\end{verbatim}
+\caption{ Example of SSL log file with a single SSL session. }
+\end{figure}
+
+\label{ssl-log-file}
+\label{ssl-log}
+\index{SSL!log file}
+\index{log file!SSL}
+\index{SSL session summary file@{\tt SSL} session summary file}
+In addition, {\tt ssl_log} holds the name of the SSL log file to
+which Bro writes SSL connection summaries.  It defaults to
+{\tt open_log_file("ssl")}.
+\end{description}
+
+\f{fig:ssl-log} shows an example of how entries in the SSL log file look like.
+We see a transcript of the first SSL connection seen since Bro started running.
+The first line gives its start and the participating hosts and ports.
+Next, we see a client trying to attempt a SSL (Version 3.1) connection and the 
+cipher suites he offers.
+The server replies with a SSL 3.1 {\tt SERVER-REPLY} and the cipher suite 
+he wishes to use. \note{In SSL v3.0/v3.1 this determines which cipher suite will be used 
+for the connection}.
+Following this is the certificate the server sends, including the issuer and subject.
+Finally, we see that the handshaking phase for this SSL connection is finished now, 
+and that client and server agreed on the cipher suite: {\tt RSA_WITH_RC4_128_MD5}.
+Due to encryption, the SSL analyzer skips all further data. 
+We only see the end of the connection.
+When BRO itself finishes, we get a little statistics about the cipher suites used
+in all seen SSL connections.
+
+\subsection{{\tt SSL} functions}
+\index{analyzers!ssl!functions|)}
+
+\subsection{{\tt SSL} event handlers}
+\index{analyzers!ftp!event handlers|(}
+
+The standard script handles the following events:
+
+\begin{description}
+\indeventtype{ssl_conn_attempt}{c: connection, version: count, cipherSuites: cipher_suites_list}
+
+Invoked upon the client side of connection {\tt c} when the analyzer sees a {\tt CLIENT-HELLO}
+of SSL version {\tt version} including the cipher suites the client offers {\tt cipherSuites}.
+
+The version can be {\tt 0x0002}, {\tt 0x0300} or {\tt 0x0301}.
+A new entry is generated inside the SSL connection table and the cipher suites
+are listed. Ciphers, that are known as weak (according to a corresponding table of
+weak ciphers) are logged inside the {\tt weak.log} file. This also happens to
+cipher suites that we do not know yet. {\note See the file {\tt ssl-ciphers.bro} for this}
+
+\indeventtype{ssl_conn_server_reply}{c: connection, version: count, cipherSuites: cipher_suites_list}
+
+This event is invoked upon the analyzer receiving a {\tt SERVER-REPLY} of the SSL server.
+It contains the SSL version the server wishes to use (\note {This finally determines, which SSL version
+will be used further}) and the cipher suite he offers. If it is SSL version 3.0 or 3.1, the server determines
+within this {\tt SERVER-HELLO} the cipher suite for the following connection (so it will only be one).
+But if it's a SSL version 2.0 connection, the server only announces the cipher suites he supports and
+it's up to the client to decide which one to use.
+
+Again, the cipher suites are listed and weak and unknown cipher suites are reported inside
+{\tt weak.log}.
+
+\indeventtype{ssl_certificate_seen}{ c: connection, isServer: int }
+
+Invoked whenever we see a certificate from client or server but before 
+verification of the certificate takes place.
+This may be useful, if you want to do something before certificate verification 
+(e.g. do not verify certificates of some given servers).
+
+\indeventtype{ssl_certificate}{ c: connection, cert: x509, isServer: bool}
+
+Invoked after the certificate from server or client ({\tt isServer}) has been verified. \note {We only
+verify certificates once. If we see them again, we only check if they have changed!}
+{\tt cert} holds the issuer and subject of the certificate, which gets stored
+inside this SSL connection's information record inside the SSL connection table and
+are written to {\tt ssl.log}.
+ 
+\indeventtype{ssl_conn_reused}{c: connection, session_id: string}
+
+Invoked whenever a former SSL session is reused. {\tt session_id} holds 
+the session ID as string of the reused session and is written to {\tt ssl.log}.
+Currently we don't do a session tracking, because SSL version 2.0 doesn't 
+send the session ID in cleartext, the first time this session is used. 
+ 
+\indeventtype{ssl_conn_established}{c: connection, version: count, cipher_suite: count}
+
+Invoked when the handshaking phase of an SSL connection is finished. 
+We see the used SSL version and the cipher suite that will be used for cryptography (written
+to {\tt ssl.log}) if we have SSL version 3.0 or 3.1. 
+In case of SSL version 2.0 we can't say due to encryption.
+(\note {In SSL version 3.0 and 3.1 the cipher suite to be used is already anounced 
+in the {\tt SERVER-HELLO}.}
+
+\indeventtype{ssl_conn_alert}{c: connection, version: count, level: count, description: count}
+
+Invoked when the analyzer receives a SSL alert. 
+The {\tt level} of the alert (warning or fatal) and the {\tt description} are
+written into {\tt ssl.log}. (\note {See {\tt ssl-alerts.bro}}).
+
+\indeventtype{conn_weak}{name: string, c: connection}
+
+This event is called when the analyzer sees:
+\begin{itemize}
+ \item weak ciphers (See: \xrefevent{ssl_conn_attempt}, \xrefevent{ssl_server_reply}, \xrefevent{ssl_conn_established}),
+ \item unknown ciphers (See: \xrefevent{ssl_conn_attempt}, \xrefevent{ssl_server_reply}, \xrefevent{ssl_conn_established})
+ \item or certificate verification failed
+\end{itemize}
+See {\tt weak.bro}.
+
+\end{description}
+
+%% --------------------------
+
+%% --------------------------
+\labsectsection{{The \analyzer{SSL} Analyzer}}{\label{analyzer-ssl}}
+\index{SSL!analysis}
+The \indanalyzer{SSL} analyzer processes traffic associated with
+the SSL (Secure Socket Layer) protocol versions 2.0 \cite{sslv2}, 3.0 \cite{sslv30} and 3.1 \cite{tlsv1}.
+SSL version 3.1 is also known as TLS (Transport Layer Security) version 1.0 since from that
+version on the IETF has taken responsibility for further developement of SSL. 
+
+Bro instantiates an
+{\tt SSL} analyzer for any connection with service ports {\tt 443/tcp (https), 563/tcp (nntps),
+585/tcp (imap4-ssl), 614/tcp (sshell), 636/tcp (ldaps), 989/tcp (ftps-data), 990/tcp (ftps), 992/tcp (telnets),
+993/tcp (imaps), 994/tcp (ircs), 995/tcp (pop3s)},
+providing you have loaded the {\tt SSL} analyzer, or defined a handler
+for one of the SSL events.
+
+By default, the analyzer uses the above set of ports as a capture filter \pxref{capture-filter}.
+It currently checks the SSL handshake process for consistency, tries to verify seen certificates,
+throws several events, does connection logging, tries to detect security weaknesses and generates simple statistics.
+It is also able to store seen certificates on disk.
+However, it does no decryption, so analysis is limited to clear text SSL records. This means 
+that analysis stops in the middle of the handshaking phase for SSLv2 and at the end of it for SSLv3.0/SSLv3.1(TLS).
+For this reason we have not implemented the SSL session caching mechanism (yet).
+
+The analyzer consists of the four files {\tt ssl.bro}, {\tt ssl-ciphers.bro}, {\tt ssl-alerts.bro} and {\tt weak.bro}.
+Usage is simple, just include {\tt ssl.bro}. The analyzer writes to {\tt weird.log}, {\tt ssl.log} and {\tt weak.log}.
+The first one receives all non conform and weird activity, {\tt ssl.log} tracks the SSL handshaking phase and 
+the last one is a place where security weaknesses are recorded.
+
+\subsection{The \indtt{x509}{record} record}
+\index{SSL!x509}
+
+\begin{figure}
+\label{fig:x509}
+\begin{verbatim}
+type x509: record {
+    issuer:  string; # issuer name of the certificate
+    subject: string; # subject name of the certificate
+};\end{verbatim}
+\caption[Definition of the {\tt x509} record]{
+Definition of the \indtt{x509}{record} record. }
+\end{figure}
+
+This record is a very simplified structure for storing X.509 \cite{x509} 
+certificate information. It currently supports only issuer and subject name, 
+which are stored in a one-line string format.
+
+\subsection{The \indtt{ssl_connection_info}{record} record}
+\index{SSL!connection information}
+
+\begin{figure}
+\label{fig:ssl-connection-info}
+\begin{verbatim}
+type ssl_connection_info: record {
+    id: count;                      # the log identifier number
+    connection_id: conn_id;         # IP connection information
+    version: count;                 # version associated with connection
+    client_certificate: x509;       # information from client certificate
+    server_certificate: x509;       # information from server certificate
+    cipherSuite: count;             # cipher suite client and server agreed upon
+    handshake_fin: bool;            # whether the handshaking process finished
+    cached_session: bool;           # true if this connection uses a cached session
+};\end{verbatim}
+\caption[Definition of the {\tt ssl_connection_info} record]{
+Definition of the \indtt{ssl_connection_info}{record} record. }
+\end{figure}
+
+The main data structure managed by the {\tt SSL} analyzer is
+a collection of {\tt ssl_connection_info} records, where the
+record type is shown in \f{fig:ssl-connection-info}.
+The corresponding fields are:
+
+\begin{description}
+\indfield{id}{ssl_connection_info}
+The unique connection identifier assigned to this connection.  Connections
+are numbered starting at~{\tt 1} and incrementing with each new connection.
+
+\indfield{connection_id}{ssl_connection_info}
+The TCP connection which this SSL connection is based on.
+
+\indfield{version}{ssl_connection_info}
+The SSL version number for this connection. Possible values are {\tt 0x0002} for SSLv2, 
+{\tt 0x0300} for SSLv30 and {\tt 0x0301} for SSLv31.
+
+\indfield{client_certificate}{ssl_connection_info}
+The information from the client certificate, if available.
+
+\indfield{server_certificate}{ssl_connection_info}
+The information from the server certificate, if available.
+
+\indfield{cipherSuite}{ssl_connection_info}
+The cipher suite client and server agreed upon. 
+\note{For SSLv2 cached sessions, this is a placeholder ({\tt 0xABCD})}.
+
+\indfield{handshake_fin}{ssl_connection_info}
+True if the analysis of the SSL handshaking phase has been completed.
+
+\indfield{cached_session}{ssl_connection_info}
+True if the connection is based on a cached SSL session identifier.
+
+\end{description}
+
+\subsection{{\tt SSL} variables}
+\index{analyzers!SSL!variables|(}
+
+The standard script defines the following redefinable variables:
+
+\begin{description}
+\indvartype{ssl_compare_cipherspecs}{bool}
+If true, bro remembers the client and server cipher specs
+and performs additional tests.
+This costs an extra amount of memory (normaly only for a short time)
+but enables detecting of non-intersecting cipher sets, for example.
+
+Default: {\tt F}.
+
+\indvartype{ssl_analyze_certificates}{bool}
+If true, Bro will analyze certificates seen in SSL connections. 
+Analyzing includes the following steps:
+\begin{itemize}
+        \item Generating a hashsum of the certificate and check if we already saw 
+             it earlier from the current host. If so, we won't verify it, because we already
+                 did and verifying is a computational expensive process. If the certificate has changed
+                 for the current host, we throw a weird event.
+        \item Verification of the certificate.
+        \item Storing of the certificate on disk in DER format.
+\end{itemize}
+
+Default: {\tt T}.
+
+\indvartype{ssl_store_certificates}{bool}
+If certificates are analyzed, this variable determines if Bro should store them on disk in DER format.
+
+Default: {\tt F}.
+
+\indvartype{ssl_store_cert_path}{string}
+This is the path where Bro dumps the certificates into.
+If it's empty, we the current directory is used.
+\note{The path must not end with a slash!}
+
+Default: {\tt "../certs"}.
+
+
+\indvartype{ssl_verify_certificates}{bool}
+If certificates are analyzed, this variable determines if Bro should verify them.
+
+Default: {\tt F}.
+
+
+\indvartype{x509_trusted_cert_path}{string}
+This is the path where OpenSSL looks for the trusted certificates.
+If it's empty, the default OpenSSL path will be used.
+
+Default: {\tt ""}.
+
+
+\indvartype{ssl_max_cipherspec_size}{count}
+This is the max. size in bytes for a SSL cipherspec.
+If we see a packet that has bigger cipherspecs,
+we warn and won't do a comparisons of cipherspecs
+
+Default: {\tt 66}.
+
+
+\indvartype{ssl_store_key_material}{bool}
+If true, Bro stores key-material exchanged in the handshaking phase.
+\note{This is mainly for decryption purposes and currently useless.}
+
+Default: {\tt F}.
+
+
+
+\begin{figure}
+\label{fig:ssl-log}
+\begin{verbatim}
+1046778101.534846 #1 192.168.0.98/32988 > 213.61.126.124/https start
+1046778101.534846 #1 Connection attempt, Version: 3.1, cipher suite(s) seen:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4), 
+SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA (0xFEFF), 
+SSLv3x_RSA_WITH_3DES_EDE_CBC_SHA (0xA),
+SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA (0xFEFE), 
+SSLv3x_RSA_WITH_DES_CBC_SHA(0x9), 
+SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA (0x64),
+SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA (0x62),
+SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5 (0x3), 
+SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (0x6),
+1046778101.753356 #1 Server reply, Version: 3.1, cipher suite(s) seen:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4),
+1046778101.762601 #1 Certificate seen from: Server, Issuer:
+/C=DE/ST=Hamburg/L=Hamburg/O=TC TrustCenter for Security in Data Networks
+GmbH/OU=TC TrustCenter Class 3 CA/Email=certificate@trustcenter.de, 
+Subject:
+/C=DE/ST=Berlin/O=Lehmanns Fachbuchhandlung GmbH/OU=Zentrale EDV/CN=www.j
+fl.de/Email=admin@lehmanns.de
+1046778101.894567 #1 Handshake finished, Version: 3.1, cipher suite:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4)
+1046778104.877207 #1 finish
+---
+Used cipher-suites statistics:
+SSLv3x_RSA_WITH_RC4_128_MD5 (0x4): 1
+
+\end{verbatim}
+\caption{ Example of SSL log file with a single SSL session. }
+\end{figure}
+
+\label{ssl-log-file}
+\label{ssl-log}
+\index{SSL!log file}
+\index{log file!SSL}
+\index{SSL session summary file@{\tt SSL} session summary file}
+In addition, {\tt ssl_log} holds the name of the SSL log file to
+which Bro writes SSL connection summaries.  It defaults to
+{\tt open_log_file("ssl")}.
+\end{description}
+
+\f{fig:ssl-log} shows an example of how entries in the SSL log file look like.
+We see a transcript of the first SSL connection seen since Bro started running.
+The first line gives its start and the participating hosts and ports.
+Next, we see a client trying to attempt a SSL (Version 3.1) connection and the 
+cipher suites he offers.
+The server replies with a SSL 3.1 {\tt SERVER-REPLY} and the cipher suite 
+he wishes to use. \note{In SSL v3.0/v3.1 this determines which cipher suite will be used 
+for the connection}.
+Following this is the certificate the server sends, including the issuer and subject.
+Finally, we see that the handshaking phase for this SSL connection is finished now, 
+and that client and server agreed on the cipher suite: {\tt RSA_WITH_RC4_128_MD5}.
+Due to encryption, the SSL analyzer skips all further data. 
+We only see the end of the connection.
+When BRO itself finishes, we get a little statistics about the cipher suites used
+in all seen SSL connections.
+
+\subsection{{\tt SSL} functions}
+\index{analyzers!ssl!functions|)}
+
+\subsection{{\tt SSL} event handlers}
+\index{analyzers!ftp!event handlers|(}
+
+The standard script handles the following events:
+
+\begin{description}
+\indeventtype{ssl_conn_attempt}{c: connection, version: count, cipherSuites: cipher_suites_list}
+
+Invoked upon the client side of connection {\tt c} when the analyzer sees a {\tt CLIENT-HELLO}
+of SSL version {\tt version} including the cipher suites the client offers {\tt cipherSuites}.
+
+The version can be {\tt 0x0002}, {\tt 0x0300} or {\tt 0x0301}.
+A new entry is generated inside the SSL connection table and the cipher suites
+are listed. Ciphers, that are known as weak (according to a corresponding table of
+weak ciphers) are logged inside the {\tt weak.log} file. This also happens to
+cipher suites that we do not know yet. {\note See the file {\tt ssl-ciphers.bro} for a list of known cipher suites.}
+
+\indeventtype{ssl_conn_server_reply}{c: connection, version: count, cipherSuites: cipher_suites_list}
+
+This event is invoked upon the analyzer receiving a {\tt SERVER-HELLO} of the SSL server.
+It contains the SSL version the server wishes to use (\note {This finally determines, which SSL version
+will be used further}) and the cipher suite he offers. If it is SSL version 3.0 or 3.1, the server determines
+within this {\tt SERVER-HELLO} the cipher suite for the following connection (so it will only be one).
+But if it's a SSL version 2.0 connection, the server only announces the cipher suites he supports and
+it's up to the client to decide which one to use.
+
+Again, the cipher suites are listed and weak and unknown cipher suites are reported inside
+{\tt weak.log}.
+
+\indeventtype{ssl_certificate_seen}{ c: connection, isServer: int }
+
+Invoked whenever we see a certificate from client or server but before 
+verification of the certificate takes place.
+This may be useful, if you want to do something before certificate verification 
+(e.g. do not verify certificates of some given servers).
+
+\indeventtype{ssl_certificate}{ c: connection, cert: x509, isServer: bool}
+
+Invoked after the certificate from server or client ({\tt isServer}) has been verified. \note {We only
+verify certificates once. If we see them again, we only check if they have changed!}
+{\tt cert} holds the issuer and subject of the certificate, which gets stored
+inside this SSL connection's information record inside the SSL connection table and
+are written to {\tt ssl.log}.
+ 
+\indeventtype{ssl_conn_reused}{c: connection, session_id: string}
+
+Invoked whenever a former SSL session is reused. {\tt session_id} holds 
+the session ID as string of the reused session and is written to {\tt ssl.log}.
+Currently we don't do session tracking, because SSL version 2.0 doesn't 
+send the session ID in cleartext when it's generated.
+ 
+\indeventtype{ssl_conn_established}{c: connection, version: count, cipher_suite: count}
+
+Invoked when the handshaking phase of an SSL connection is finished. 
+We see the used SSL version and the cipher suite that will be used for cryptography (written
+to {\tt ssl.log}) if we have SSL version 3.0 or 3.1. 
+In case of SSL version 2.0 we can only determine the used cipher suite for new sessions, not for reused ones.
+(\note {In SSL version 3.0 and 3.1 the cipher suite to be used is already anounced 
+in the {\tt SERVER-HELLO}.}
+
+\indeventtype{ssl_conn_alert}{c: connection, version: count, level: count, description: count}
+
+Invoked when the analyzer receives a SSL alert. 
+The {\tt level} of the alert (warning or fatal) and the {\tt description} are
+written into {\tt ssl.log}. (\note {See {\tt ssl-alerts.bro}}).
+
+\indeventtype{conn_weak}{name: string, c: connection}
+
+This event is called when the analyzer sees:
+\begin{itemize}
+ \item weak ciphers (See: \xrefevent{ssl_conn_attempt}, \xrefevent{ssl_server_reply}, \xrefevent{ssl_conn_established}),
+ \item unknown ciphers (See: \xrefevent{ssl_conn_attempt}, \xrefevent{ssl_server_reply}, \xrefevent{ssl_conn_established})
+ \item or certificate verification failed
+\end{itemize}
+See {\tt weak.bro}.
+
+\end{description}
+
+%% --------------------------
+
 \section{The \module{weird} Module}
 \index{weird events|(}
 \index{events!exceptional|(}
@@ -4671,30 +5295,30 @@
 \hline
 \indtt{WEIRD_UNSPECIFIED}{action} & No action specified. \\
 \hline
-\indtt{WEIRD_IGNORE}{action}	& Ignore the event.\\
+\indtt{WEIRD_IGNORE}{action}    & Ignore the event.\\
 \hline
-\indtt{WEIRD_FILE}{action}	& Record the event to {\tt weird_file},
-					if it has not been seen for
-					these hosts before.  (But see
-					\xrefvar{weird_do_not_ignore_repeats}.)\\
-\hline
-\indtt{WEIRD_LOG_ALWAYS}{action}	& Record the event to {\tt weird_file} and
-					generate a real-time alert each
-					time the event occurs. \\
-\hline
-\indtt{WEIRD_LOG_ONCE}{action}	& Record the event to {\tt weird_file};
-					generate a real-time alert the first
-					time the event occurs. \\
-\hline
-\indtt{WEIRD_LOG_PER_CONN}{action}	& Record the event to {\tt weird_file};
-					generate a real-time alert the
-					first time it occurs for a given
-					connection. \\
-\hline
-\indtt{WEIRD_LOG_PER_ORIG}{action}	& Record the event to {\tt weird_file};
-					generate a real-time alert the
-					first time it occurs for a given
-					originating host. \\
+\indtt{WEIRD_FILE}{action}      & Record the event to {\tt weird_file},
+                                        if it has not been seen for
+                                        these hosts before.  (But see
+                                        \xrefvar{weird_do_not_ignore_repeats}.)\\
+\hline
+\indtt{WEIRD_LOG_ALWAYS}{action}        & Record the event to {\tt weird_file} and
+                                        generate a real-time alert each
+                                        time the event occurs. \\
+\hline
+\indtt{WEIRD_LOG_ONCE}{action}  & Record the event to {\tt weird_file};
+                                        generate a real-time alert the first
+                                        time the event occurs. \\
+\hline
+\indtt{WEIRD_LOG_PER_CONN}{action}      & Record the event to {\tt weird_file};
+                                        generate a real-time alert the
+                                        first time it occurs for a given
+                                        connection. \\
+\hline
+\indtt{WEIRD_LOG_PER_ORIG}{action}      & Record the event to {\tt weird_file};
+                                        generate a real-time alert the
+                                        first time it occurs for a given
+                                        originating host. \\
 \hline
 \end{tabular}
 \end{center}
@@ -4835,133 +5459,133 @@
 
 \begin{description}
 \indweird{active_connection_reuse}
-	A new connection attempt (initial SYN)
-	was seen for an already-established connection that has not
-	yet terminated.
+        A new connection attempt (initial SYN)
+        was seen for an already-established connection that has not
+        yet terminated.
 \index{HTTP!weird events}
 \indweird{bad_HTTP_reply}
-	The first line of a reply from an HTTP
-	server did not include \verb+HTTP/+\emph{version}.
+        The first line of a reply from an HTTP
+        server did not include \verb+HTTP/+\emph{version}.
 \indweird{bad_HTTP_version}
-	The first line of a request from an HTTP
-	client did not include \verb+HTTP/+\emph{version}.
+        The first line of a request from an HTTP
+        client did not include \verb+HTTP/+\emph{version}.
 \index{ICMP!weird events}
 \index{packets!corrupted}
 \index{corrupted packets}
 \index{checksum error!ICMP}
 \index{ICMP!checksum error}
 \indweird{bad_ICMP_checksum}
-	The checksum field in an
-	ICMP packet was invalid.
+        The checksum field in an
+        ICMP packet was invalid.
 \index{Rlogin!weird events}
 \indweird{bad_rlogin_prolog}
-	The beginning of an Rlogin connection had
-	a syntactical error.
+        The beginning of an Rlogin connection had
+        a syntactical error.
 \index{RPC (Remote Procedure Call)!weird events}
 \indweird{bad_RPC}
-	A Remote Procedure Call was ill-formed.
+        A Remote Procedure Call was ill-formed.
 \indweird{bad_RPC_program}
-	A portmapper RPC call did not include the
-	correct portmapper program number.
+        A portmapper RPC call did not include the
+        correct portmapper program number.
 \indweird{bad_SYN_ack}
-	A TCP SYN acknowledgment (SYN-ack) did not acknowledge
-	the sequence number sent in the initial SYN.
+        A TCP SYN acknowledgment (SYN-ack) did not acknowledge
+        the sequence number sent in the initial SYN.
 \index{TCP!weird events}
 \index{checksum error!TCP}
 \index{TCP!checksum error}
 \indweird{bad_TCP_checksum}
-	A TCP packet had a bad checksum.
+        A TCP packet had a bad checksum.
 \index{UDP!weird events}
 \index{checksum error!UDP}
 \index{UDP!checksum error}
 \indweird{bad_UDP_checksum}
-	A UDP packet had a bad checksum.
+        A UDP packet had a bad checksum.
 \indweird{baroque_SYN}
-	A TCP SYN was seen with an unlikely
-	combination of other flags (the URGent pointer).
+        A TCP SYN was seen with an unlikely
+        combination of other flags (the URGent pointer).
 \indweird{blank_in_HTTP_request}
-	The URL in an HTTP request includes
-	an embedded blank.
+        The URL in an HTTP request includes
+        an embedded blank.
 \indweird{connection_originator_SYN_ack}
-	A TCP endpoint that originated
-	a connection by sending a SYN followed this up by sending a SYN-ack.
+        A TCP endpoint that originated
+        a connection by sending a SYN followed this up by sending a SYN-ack.
 \indweird{data_after_reset}
-	After a TCP endpoint sent a RST to terminate
-	a connection, it sent some data.
+        After a TCP endpoint sent a RST to terminate
+        a connection, it sent some data.
 \indweird{data_before_established}
-	Before the connection was fully
-	established, a TCP endpoint sent some data.
+        Before the connection was fully
+        established, a TCP endpoint sent some data.
 \indweird{excessive_RPC_len}
-	An RPC record sent over a TCP connection
-	exceeded 8 KB.
+        An RPC record sent over a TCP connection
+        exceeded 8 KB.
 \indweird{excess_RPC}
-	The sender of an RPC request or reply included
-	leftover data beyond what the RPC parameters or result value
-	themselves consumed.
+        The sender of an RPC request or reply included
+        leftover data beyond what the RPC parameters or result value
+        themselves consumed.
 \indweird{FIN_advanced_last_seq}
-	A TCP endpoint retransmitted a FIN with
-	a higher sequence number than previously.
+        A TCP endpoint retransmitted a FIN with
+        a higher sequence number than previously.
 \indweird{FIN_after_reset}
-	A TCP endpoint sent a FIN after sending a RST.
+        A TCP endpoint sent a FIN after sending a RST.
 \index{packets!storms}
 \index{storms}
 \indweird{FIN_storm}
-	The monitor saw a flurry of FIN packets all sent on
-	the same connection.  A ``flurry'' is defined as 1,000 packets that
-	arrived with less than 1~sec between successive FINs.
-	\deficiency{ Clearly, this numbers
-	should be user-controllable. }
+        The monitor saw a flurry of FIN packets all sent on
+        the same connection.  A ``flurry'' is defined as 1,000 packets that
+        arrived with less than 1~sec between successive FINs.
+        \deficiency{ Clearly, this numbers
+        should be user-controllable. }
 \indweird{HTTP_unknown_method}
-	The method in an HTTP request was
-	not GET, POST or HEAD.
+        The method in an HTTP request was
+        not GET, POST or HEAD.
 \indweird{HTTP_version_mismatch}
-	A persistent HTTP connection sent a
-	different version number for a subsequent item than it
-	did initially.
+        A persistent HTTP connection sent a
+        different version number for a subsequent item than it
+        did initially.
 \indweird{inappropriate_FIN}
-	A TCP endpoint sent a FIN before the
-	connection was fully established.
+        A TCP endpoint sent a FIN before the
+        connection was fully established.
 \indweird{multiple_HTTP_request_elements}
-	An HTTP request included multiple
-	methods.
+        An HTTP request included multiple
+        methods.
 \indweird{multiple_RPCs}
-	A TCP RPC stream included more than one
-	remote procedure call.
+        A TCP RPC stream included more than one
+        remote procedure call.
 \index{NULs}
 \indweird{NUL_in_line}
-	A NUL (ASCII 0) was seen in a text stream
-	that is expected to be free of NULs.  \updateme{ Currently,
-	the only such stream is that associated with an FTP control
-	connection. }
+        A NUL (ASCII 0) was seen in a text stream
+        that is expected to be free of NULs.  \updateme{ Currently,
+        the only such stream is that associated with an FTP control
+        connection. }
 \indweird{originator_RPC_reply}
-	The originator (and hence presumed client)
-	of an RPC connection sent an RPC reply (either instead of a request,
-	or in addition to a request).
+        The originator (and hence presumed client)
+        of an RPC connection sent an RPC reply (either instead of a request,
+        or in addition to a request).
 \index{Finger!weird events}
 \indweird{partial_finger_request}
-	When a Finger connection terminated, it
-	included a final line of unanalyzed text because the text was
-	not newline-terminated.
+        When a Finger connection terminated, it
+        included a final line of unanalyzed text because the text was
+        not newline-terminated.
 \index{FTP!weird events}
 \indweird{partial_ftp_request}
-	When an FTP connection terminated, it
-	included a final line of unanalyzed text because the text was
-	not newline-terminated.
+        When an FTP connection terminated, it
+        included a final line of unanalyzed text because the text was
+        not newline-terminated.
 \indweird{partial_ident_request}
-	When an IDENT connection terminated, it
-	included a final line of unanalyzed text because the text was
-	not newline-terminated.
+        When an IDENT connection terminated, it
+        included a final line of unanalyzed text because the text was
+        not newline-terminated.
 \indweird{partial_portmapper_request}
-	A portmapper connection terminated with
-	an unanalyzed request because the data stream was incomplete.
+        A portmapper connection terminated with
+        an unanalyzed request because the data stream was incomplete.
 \indweird{partial_RPC}
-	An RPC was missing some required header information
-	due to truncation.
+        An RPC was missing some required header information
+        due to truncation.
 \index{data!unanalyzed}
 \index{unanalyzed data}
 \indweird{pending_data_when_closed}
-	A TCP connection closed even though
-	not all of the data in it was analyzed due to a sequence hole.
+        A TCP connection closed even though
+        not all of the data in it was analyzed due to a sequence hole.
 \index{split routing}
 \index{routing!split}
 \index{vantage point}
@@ -4971,119 +5595,119 @@
 \index{scanning!stealth}
 \index{stealth scans}
 \indweird{possible_split_routing}
-	Bro appears to be seeing only one
-	direction of some bi-directional connections \pxref{split-routing}.
-	This can also occur due to certain forms of stealth-scanning.
+        Bro appears to be seeing only one
+        direction of some bi-directional connections \pxref{split-routing}.
+        This can also occur due to certain forms of stealth-scanning.
 \index{connection!reuse}
 \index{Maximum Segment Lifetime (MSL)}
 \index{MSL (Maximum Segment Lifetime)}
 \indweird{premature_connection_reuse}
-	A TCP connection tuple is being
-	reused less than 30~sec after its previous use.  (The standard
-	requires waiting $2 \cdot \mbox{MSL} = 4$ minutes \cite[p. 27]{RFC793}.)
+        A TCP connection tuple is being
+        reused less than 30~sec after its previous use.  (The standard
+        requires waiting $2 \cdot \mbox{MSL} = 4$ minutes \cite[p. 27]{RFC793}.)
 \indweird{repeated_SYN_reply_wo_ack}
-	A TCP responder that replied to an
-	initial SYN with a SYN-ack has subsequently sent a SYN \emph{without}
-	an acknowledgment.
+        A TCP responder that replied to an
+        initial SYN with a SYN-ack has subsequently sent a SYN \emph{without}
+        an acknowledgment.
 \indweird{repeated_SYN_with_ack}
-	A TCP originator that sent an
-	initial SYN has subsequently sent a SYN-ack.
+        A TCP originator that sent an
+        initial SYN has subsequently sent a SYN-ack.
 \indweird{responder_RPC_call}
-	The responder (and hence presumed server)
-	of an RPC connection sent an RPC request (either instead of a reply,
-	or in addition to a reply).
+        The responder (and hence presumed server)
+        of an RPC connection sent an RPC request (either instead of a reply,
+        or in addition to a reply).
 \indweird{rlogin_text_after_rejected}
-	An Rlogin client sent additional text
-	to an Rlogin server after the server already presumably rejected
-	the client's service request.
+        An Rlogin client sent additional text
+        to an Rlogin server after the server already presumably rejected
+        the client's service request.
 \index{retransmission!inconsistent}
 \index{inconsistent retransmission}
 \index{evasion!inconsistent RPC retransmission}
 \indweird{RPC_rexmit_inconsistency}
-	An RPC call was retransmitted, and
-	the retransmitted call differed from the original call.  This
-	could reflect an attempt by an attacker to evade the monitor.
-	\note{ This type of inconsistency checking is not available for
-	RPC replies because the transmission of the reply in general
-	marks the end of the RPC connection, and the monitor deletes
-	the connection state shortly afterward. }
+        An RPC call was retransmitted, and
+        the retransmitted call differed from the original call.  This
+        could reflect an attempt by an attacker to evade the monitor.
+        \note{ This type of inconsistency checking is not available for
+        RPC replies because the transmission of the reply in general
+        marks the end of the RPC connection, and the monitor deletes
+        the connection state shortly afterward. }
 \indweird{RST_storm}
-	The monitor saw a flurry of RST packets all sent on
-	the same connection.  See {\tt FIN_storm} for the definition of
-	``flurry.''
+        The monitor saw a flurry of RST packets all sent on
+        the same connection.  See {\tt FIN_storm} for the definition of
+        ``flurry.''
 \indweird{RST_with_data}
-	A TCP RST packet included data.  This actually
-	is allowed by the specification \cite[4.2.2.12]{RFC1122}.
-	\deficiency{ This event should include the data. }
+        A TCP RST packet included data.  This actually
+        is allowed by the specification \cite[4.2.2.12]{RFC1122}.
+        \deficiency{ This event should include the data. }
 \index{simultaneous open}
 \index{connection!simultaneous open}
-	\indweird{simultaneous_open}
-	The monitor saw a TCP simultaneous open,
-	i.e., both endpoints sent initial SYNs to one another at the same time.
-	While the specification allows this \cite[p. 30]{RFC793}, none of the
-	protocols analyzed by Bro should be using it.
+        \indweird{simultaneous_open}
+        The monitor saw a TCP simultaneous open,
+        i.e., both endpoints sent initial SYNs to one another at the same time.
+        While the specification allows this \cite[p. 30]{RFC793}, none of the
+        protocols analyzed by Bro should be using it.
 \index{transients!startup}
 \index{startup!transients}
 \index{scanning!stealth}
 \index{stealth scans}
 \indweird{spontaneous_FIN}
-	A TCP endpoint sent a FIN packet without
-	sending any previous packets.  This event can reflect stealth-scanning,
-	but can also occur when Bro has recently
-	started up and has not seen other traffic on a connection and hence does
-	not know that the connection already exists.
+        A TCP endpoint sent a FIN packet without
+        sending any previous packets.  This event can reflect stealth-scanning,
+        but can also occur when Bro has recently
+        started up and has not seen other traffic on a connection and hence does
+        not know that the connection already exists.
 \indweird{spontaneous_RST}
-	A TCP endpoint sent a RST packet without
-	sending any previous packets.  As with {\tt spontaneous_FIN}, this
-	event can reflect either stealth scanning or a Bro start-up
-	transient.
+        A TCP endpoint sent a RST packet without
+        sending any previous packets.  As with {\tt spontaneous_FIN}, this
+        event can reflect either stealth scanning or a Bro start-up
+        transient.
 \indweird{SYN_after_close}
-	A TCP endpoint sent a SYN (connection
-	initiation) after sending a FIN (connection termination),
-	but before the connection fully closed.
+        A TCP endpoint sent a SYN (connection
+        initiation) after sending a FIN (connection termination),
+        but before the connection fully closed.
 \indweird{SYN_after_partial}
-	A TCP endpoint in a ``partial'' connection
-	\pxref{partial-connection} sent a SYN.
+        A TCP endpoint in a ``partial'' connection
+        \pxref{partial-connection} sent a SYN.
 \indweird{SYN_after_reset}
-	A TCP endpoint sent a SYN after sending a
-	RST (reset connection).
+        A TCP endpoint sent a SYN after sending a
+        RST (reset connection).
 \indweird{SYN_inside_connection}
-	A TCP endpoint sent a SYN during a
-	connection (or partial connection) on which it had already
-	sent data.
+        A TCP endpoint sent a SYN during a
+        connection (or partial connection) on which it had already
+        sent data.
 \indweird{SYN_seq_jump}
-	A TCP endpoint retransmitted a SYN or a
-	SYN-ack, but with a different sequence number.
+        A TCP endpoint retransmitted a SYN or a
+        SYN-ack, but with a different sequence number.
 \index{T/TCP}
 \index{TCP!transaction}
 \index{transaction TCP}
 \indweird{SYN_with_data}
-	A TCP endpoint included data in a SYN packet
-	it sent.  Note, this can legitimately occur for T/TCP connections
-	\cite{RFC1644}.
+        A TCP endpoint included data in a SYN packet
+        it sent.  Note, this can legitimately occur for T/TCP connections
+        \cite{RFC1644}.
 \index{TCP!Christmas packet}
 \index{Christmas packet}
 \indweird{TCP_christmas}
-	A TCP endpoint sent a SYN packet that
-	included the RST flag (a nonsensical combination).  The
-	term ``Christmas packet'' has been used in this context
-	(particularly if other flags are set, too) because the
-	packet's flags are ``lit up like a Christmas tree.''
+        A TCP endpoint sent a SYN packet that
+        included the RST flag (a nonsensical combination).  The
+        term ``Christmas packet'' has been used in this context
+        (particularly if other flags are set, too) because the
+        packet's flags are ``lit up like a Christmas tree.''
 \index{length mismatch!UDP}
 \index{UDP!length mismatch}
 \index{evasion!length mismatch}
 \indweird{UDP_datagram_length_mismatch}
-	The length field in a UDP header
-	did not match the length field in the IP header.  This could
-	reflect an attempt by an attacker to evade the monitor.
+        The length field in a UDP header
+        did not match the length field in the IP header.  This could
+        reflect an attempt by an attacker to evade the monitor.
 \indweird{unpaired_RPC_response}
-	An RPC reply was seen for which no
-	request was seen.  This event could reflect a Bro start-up
-	transient (it started running after the request was sent).
+        An RPC reply was seen for which no
+        request was seen.  This event could reflect a Bro start-up
+        transient (it started running after the request was sent).
 \indweird{unsolicited_SYN_response}
-	A TCP endpoint sent a SYN-ack without
-	first receiving an initial SYN.  This event could reflect a
-	Bro start-up transient.
+        A TCP endpoint sent a SYN-ack without
+        first receiving an initial SYN.  This event could reflect a
+        Bro start-up transient.
 
 \end{description}
 
@@ -5108,14 +5732,14 @@
 \begin{description}
 \index{IDENT!weird events}
 \indweird{bad_ident_reply}
-	A reply from an IDENT server was
-	syntactically invalid.
+        A reply from an IDENT server was
+        syntactically invalid.
 \indweird{bad_ident_request}
-	A request to an IDENT server was
-	syntactically invalid.
+        A request to an IDENT server was
+        syntactically invalid.
 \indweird{ident_request_addendum}
-	An IDENT request included additional
-	text beyond that forming the request itself.
+        An IDENT request included additional
+        text beyond that forming the request itself.
 
 \end{description}
 
@@ -5138,91 +5762,91 @@
 \index{fragments!excessively large}
 \index{denial of service!excessively large fragments}
 \indweird{excessively_large_fragment}
-	A set of IP fragments reassembled
-	to a maximum size exceeding 64,000 bytes.  \note{ Sizes between
-	64,000 and 65,535 bytes are allowed, strictly speaking, but
-	are highly unlikely in legitimate traffic.  Sizes above 65,535
-	bytes generally represent attempted denial-of-service attacks,
-	due to IP implementations that crash upon receiving such
-	impossibly-large fragment sets. }
+        A set of IP fragments reassembled
+        to a maximum size exceeding 64,000 bytes.  \note{ Sizes between
+        64,000 and 65,535 bytes are allowed, strictly speaking, but
+        are highly unlikely in legitimate traffic.  Sizes above 65,535
+        bytes generally represent attempted denial-of-service attacks,
+        due to IP implementations that crash upon receiving such
+        impossibly-large fragment sets. }
 
-	Default: {\tt WEIRD_LOG_ALWAYS}.
+        Default: {\tt WEIRD_LOG_ALWAYS}.
 
 \index{fragments!excessively small}
 \index{evasion!excessively small fragments}
 \indweird{excessively_small_fragment}
-	A fragment other than the
-	last fragment in a set was less than 64 bytes in size.
-	\note{ The standard allows such small fragments, but their
-	presence may reflect an attacker attempting to evade the
-	monitor by splitting header information across multiple
-	fragments. }
+        A fragment other than the
+        last fragment in a set was less than 64 bytes in size.
+        \note{ The standard allows such small fragments, but their
+        presence may reflect an attacker attempting to evade the
+        monitor by splitting header information across multiple
+        fragments. }
 
-	Default: {\tt WEIRD_LOG_ALWAYS}.
+        Default: {\tt WEIRD_LOG_ALWAYS}.
 
 \index{fragments!inconsistent}
 \index{evasion!inconsistent fragments}
 \indweird{fragment_inconsistency}
-	A fragment overlaps with a previously
-	sent fragment, and the two disagree on data they share in common.
-	This event could reflect an attacker attempting to evade the
-	monitor; it can also occur because Bro keeps previous fragments
-	indefinitely (\deficiency{ it needs to provide a means for
-	flushing old fragments, otherwise it becomes vulnerable to
-	a state-holding attack}), and occasionally a fragment will
-	overlap with one sent much earlier and long-since forgotten
-	by the endpoints.
+        A fragment overlaps with a previously
+        sent fragment, and the two disagree on data they share in common.
+        This event could reflect an attacker attempting to evade the
+        monitor; it can also occur because Bro keeps previous fragments
+        indefinitely (\deficiency{ it needs to provide a means for
+        flushing old fragments, otherwise it becomes vulnerable to
+        a state-holding attack}), and occasionally a fragment will
+        overlap with one sent much earlier and long-since forgotten
+        by the endpoints.
 
-	Default: {\tt WEIRD_LOG_ALWAYS}.
+        Default: {\tt WEIRD_LOG_ALWAYS}.
 
 \index{fragments!overlapping}
 \indweird{fragment_overlap}
-	A fragment overlaps with a previously
-	sent fragment.  As for {\tt fragment_inconsistency}, this
-	event can occur due to Bro keeping previous fragments
-	indefinitely.  This event does not in general reflect a
-	possible attempt at evasion.
+        A fragment overlaps with a previously
+        sent fragment.  As for {\tt fragment_inconsistency}, this
+        event can occur due to Bro keeping previous fragments
+        indefinitely.  This event does not in general reflect a
+        possible attempt at evasion.
 
-	Default: {\tt WEIRD_LOG_ALWAYS}.
+        Default: {\tt WEIRD_LOG_ALWAYS}.
 
 \index{fragments!inconsistent protocols}
 \indweird{fragment_protocol_inconsistency}
-	Two fragments were seen
-	for the same flow and IP ID which differed in their transport protocol
-	(e.g., UDP, TCP).  According to the specification, this is allowed
-	\cite[p. 24]{RFC791}, but its use appears highly unlikely.
+        Two fragments were seen
+        for the same flow and IP ID which differed in their transport protocol
+        (e.g., UDP, TCP).  According to the specification, this is allowed
+        \cite[p. 24]{RFC791}, but its use appears highly unlikely.
 
-	Default: {\tt WEIRD_FILE}, because it is difficult to see how
-	an attacker can exploit this anomaly.
+        Default: {\tt WEIRD_FILE}, because it is difficult to see how
+        an attacker can exploit this anomaly.
 
 \index{fragments!inconsistent sizes}
 \index{evasion!inconsistent fragment size}
 \indweird{fragment_size_inconsistency}
-	A ``last fragment'' was
-	seen twice, and the two disagree on how large the reassembled datagram
-	should be.  This event could reflect an attacker attempting to evade
-	the monitor.
-
-	Default: {\tt WEIRD_FILE}, since it is more likely that this
-	occurs due to a high volume flow of fragments wrapping the
-	IP ID space than due to an actual attack.
+        A ``last fragment'' was
+        seen twice, and the two disagree on how large the reassembled datagram
+        should be.  This event could reflect an attacker attempting to evade
+        the monitor.
+
+        Default: {\tt WEIRD_FILE}, since it is more likely that this
+        occurs due to a high volume flow of fragments wrapping the
+        IP ID space than due to an actual attack.
 
 \indweird{fragment_with_DF}
-	A fragment was seen with the ``Don't Fragment''
-	bit set in its header.  While strictly speaking this is not illegal,
-	and not impossible (a router could have fragmented a packet and then
-	decided that the fragments should not be further fragmented), its
-	presence is highly unusual.
+        A fragment was seen with the ``Don't Fragment''
+        bit set in its header.  While strictly speaking this is not illegal,
+        and not impossible (a router could have fragmented a packet and then
+        decided that the fragments should not be further fragmented), its
+        presence is highly unusual.
 
-	Default: {\tt WEIRD_FILE}, because it's difficult to see how
-	this could reflect malicious activity.
+        Default: {\tt WEIRD_FILE}, because it's difficult to see how
+        this could reflect malicious activity.
 
 \indweird{incompletely_captured_fragment}
-	A fragment was seen whose
-	length field is larger than the fragment datagram appearing on the
-	monitored link.
+        A fragment was seen whose
+        length field is larger than the fragment datagram appearing on the
+        monitored link.
 
-	Default: {\tt WEIRD_LOG_ALWAYS}.
+        Default: {\tt WEIRD_LOG_ALWAYS}.
 
 \end{description}
 
@@ -5246,35 +5870,35 @@
 \index{checksum error!IP}
 \begin{description}
 \indweird{bad_IP_checksum}
-	A packet had a bad IP header checksum.
+        A packet had a bad IP header checksum.
 
 \index{TCP!corrupted header}
 \indweird{bad_TCP_header_len}
-	The length of the TCP header (which is
-	itself specified in the header) was smaller than the minimum
-	allowed size.
+        The length of the TCP header (which is
+        itself specified in the header) was smaller than the minimum
+        allowed size.
 
 \index{headers!truncated}
 \index{truncated headers}
 \indweird{internally_truncated_header}
-	A captured packet with a valid
-	IP length field was smaller as actually recorded, such that the
-	captured version of the packet was illegally small.  This event
-	may reflect an error in Bro's packet capture hardware or software.
+        A captured packet with a valid
+        IP length field was smaller as actually recorded, such that the
+        captured version of the packet was illegally small.  This event
+        may reflect an error in Bro's packet capture hardware or software.
 
-	Default: {\tt WEIRD_LOG_ALWAYS}, because this event can indicate
-	a basic problem with Bro's packet capture.
+        Default: {\tt WEIRD_LOG_ALWAYS}, because this event can indicate
+        a basic problem with Bro's packet capture.
 
 \indweird{truncated_IP}
-	A captured packet either was too small to
-	include a minimal IP header, or the full length as recorded by
-	the packet capture library was smaller than the length as indicated
-	by the IP header.
+        A captured packet either was too small to
+        include a minimal IP header, or the full length as recorded by
+        the packet capture library was smaller than the length as indicated
+        by the IP header.
 
 \indweird{truncated_header}
-	An IP datagram's header indicates a length
-	smaller than that required for the indicated transport type (TCP,
-	UDP, ICMP).
+        An IP datagram's header indicates a length
+        smaller than that required for the indicated transport type (TCP,
+        UDP, ICMP).
 
 \end{description}
 
@@ -5285,18 +5909,18 @@
 
 \begin{description}
 \indweird{bad_pm_port}
-	See \xrefevent{pm_bad_port}.  Handled by \xrefevent{conn_weird_addl},
-	where the extra parameter is the text
-	\verb+"port <+\emph{bad-port}\verb+>"+.
+        See \xrefevent{pm_bad_port}.  Handled by \xrefevent{conn_weird_addl},
+        where the extra parameter is the text
+        \verb+"port <+\emph{bad-port}\verb+>"+.
 
 \index{denial of service!Land attack}
 \index{Land attack}
 \indweird{Land_attack}
-	A TCP connection attempt was seen with identical
-	initiator and responder addresses and ports.  This event likely
-	reflects an attempted denial-of-service attack known as a
-	``Land'' attack.  See \xreffunc{check_spoof}.  Handled by
-	\xrefevent{conn_weird}.
+        A TCP connection attempt was seen with identical
+        initiator and responder addresses and ports.  This event likely
+        reflects an attempted denial-of-service attack known as a
+        ``Land'' attack.  See \xreffunc{check_spoof}.  Handled by
+        \xrefevent{conn_weird}.
 
 \end{description}
 
@@ -5411,3 +6035,8 @@
 % \end{description}
 % 
 % \index{analyzers!scan!event handlers|)}
+
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: t
+%%% End: 
diff -uNr bro-pub-0.8a41/doc/manual-src/bib.tex bro-pub-0.841-ssl/doc/manual-src/bib.tex
--- bro-pub-0.8a41/doc/manual-src/bib.tex	Sat Nov 16 02:03:49 2002
+++ bro-pub-0.841-ssl/doc/manual-src/bib.tex	Wed Oct 15 05:20:29 2003
@@ -146,4 +146,76 @@
 ``SSH Connection Protocol,'' Internet Draft,
 \emph{draft-ietf-secsh-connect-07.txt}, May~2000.
 
+\bibitem[SSLv2]{sslv2}
+Kipp E.B. Hickman, ``The SSL Protocol'', Netscape Communications Corp.
+\emph{http://wp.netscape.com/eng/security/SSL\_2.html}, February~1995
+
+\bibitem[SSLv30]{sslv30}
+Alan O. Freier, Philip Karlton, Paul C. Kocher,
+``The SSL Protocol Version 3.0'', INTERNET-DRAFT                                          
+\emph{draft-freier-ssl-version3-02.txt}, November~1996.
+
+\bibitem[TLSv1]{tlsv1}
+T. Dierks, C. Allen,
+`` The TLS Protocol Version 1.0'',
+RFC~2246,
+\mbox{January~1999.}
+
+\bibitem[SSL-FIPS]{ssl-fips}
+Nelson Bolyard, Wan-Teh Chang,
+``FIPS SSL CipherSuites'',
+\emph{http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html}, June~2001.
+
+\bibitem[SSL-AES]{ssl-aes}
+P. Chown, ``Advanced Encryption Standard (AES) Ciphersuites for Transport Layer Security (TLS)'',
+RFC~3268,
+\mbox{June~2002.}
+
+\bibitem[TLS-56]{tls-56}
+John Banes, Richard Harrington,
+``56-bit Export Cipher Suites For TLS'', INTERNET-DRAFT,
+\emph{draft-ietf-tls-56-bit-ciphersuites-00.txt}, April~1999.
+
+\bibitem[X509]{x509}
+R. Housley, W. Polk, W. Ford, D. Solo,
+``Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile'',
+RFC~3280,
+\mbox{June~2002.}
+
+\bibitem[SSLv2]{sslv2}
+Kipp E.B. Hickman, ``The SSL Protocol'', Netscape Communications Corp.
+\emph{http://wp.netscape.com/eng/security/SSL\_2.html}, February~1995
+
+\bibitem[SSLv30]{sslv30}
+Alan O. Freier, Philip Karlton, Paul C. Kocher,
+``The SSL Protocol Version 3.0'', INTERNET-DRAFT                                          
+\emph{draft-freier-ssl-version3-02.txt}, November~1996.
+
+\bibitem[TLSv1]{tlsv1}
+T. Dierks, C. Allen,
+`` The TLS Protocol Version 1.0'',
+RFC~2246,
+\mbox{January~1999.}
+
+\bibitem[SSL-FIPS]{ssl-fips}
+Nelson Bolyard, Wan-Teh Chang,
+``FIPS SSL CipherSuites'',
+\emph{http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html}, June~2001.
+
+\bibitem[SSL-AES]{ssl-aes}
+P. Chown, ``Advanced Encryption Standard (AES) Ciphersuites for Transport Layer Security (TLS)'',
+RFC~3268,
+\mbox{June~2002.}
+
+\bibitem[TLS-56]{tls-56}
+John Banes, Richard Harrington,
+``56-bit Export Cipher Suites For TLS'', INTERNET-DRAFT,
+\emph{draft-ietf-tls-56-bit-ciphersuites-00.txt}, April~1999.
+
+\bibitem[X509]{x509}
+R. Housley, W. Polk, W. Ford, D. Solo,
+``Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile'',
+RFC~3280,
+\mbox{June~2002.}
+
 \end{thebibliography}
diff -uNr bro-pub-0.8a41/event.bif bro-pub-0.841-ssl/event.bif
--- bro-pub-0.8a41/event.bif	Fri Oct 10 00:54:52 2003
+++ bro-pub-0.841-ssl/event.bif	Wed Oct 15 05:17:51 2003
@@ -46,6 +46,7 @@
 event net_stats_update%(t: time, ns: net_stats%);
 event conn_stats%(c: connection, os: endpoint_stats, rs: endpoint_stats%);
 event conn_weird%(name: string, c: connection%);
+event conn_weak%(name: string, c: connection%);
 event conn_weird_addl%(name: string, c: connection, addl: string%);
 event flow_weird%(name: string, src: addr, dst: addr%);
 event net_weird%(name: string%);
@@ -149,6 +150,15 @@
 
 event ssh_client_version%(c: connection, version: string%);
 event ssh_server_version%(c: connection, version: string%);
+
+event ssl_certificate_seen%(c: connection, isServer: int%);
+event ssl_certificate%(c: connection, cert: x509, isServer: bool%);
+event ssl_conn_attempt%(c: connection, version: count, cipherSuites: cipher_suites_list%);
+event ssl_conn_server_reply%(c: connection, version: count, cipherSuites: cipher_suites_list%);
+event ssl_conn_established%(c: connection, version: count, cipher_suite: count%);
+event ssl_conn_reused%(c: connection, session_id: string%);
+event ssl_conn_alert%(c: connection, version: count, level: count, description: count%);
+
 event stp_create_endp%(c: connection, e: int, is_orig: bool%);
 event stp_resume_endp%(e: int%);
 event stp_correlate_pair%(e1: int, e2: int%);
diff -uNr bro-pub-0.8a41/parse.y bro-pub-0.841-ssl/parse.y
--- bro-pub-0.8a41/parse.y	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/parse.y	Wed Oct 15 05:22:18 2003
@@ -0,0 +1,1252 @@
+%{
+// $Id: parse.in,v 1.30 2003/10/10 05:03:22 vern Exp $
+// Copyright (c) 2001, 2002
+//      The Regents of the University of California.  All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that: (1) source code distributions
+// retain the above copyright notice and this paragraph in its entirety, (2)
+// distributions including binary code include the above copyright notice and
+// this paragraph in its entirety in the documentation or other materials
+// provided with the distribution, and (3) all advertising materials mentioning
+// features or use of this software display the following acknowledgement:
+// ``This product includes software developed by the University of California,
+// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+// the University nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+%}
+
+%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
+%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
+%token TOK_BOOL TOK_BREAK TOK_CASE TOK_CONST
+%token TOK_CONSTANT TOK_COUNT TOK_COUNTER TOK_DEFAULT TOK_DELETE
+%token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FILE TOK_FOR
+%token TOK_FUNCTION TOK_GLOBAL TOK_GLOBAL_ATTR TOK_HAS_FIELD TOK_HAS_ATTR
+%token TOK_ID TOK_IF TOK_IN TOK_INT
+%token TOK_INTERVAL TOK_LIST TOK_LOCAL TOK_LOG TOK_MODULE TOK_MATCH TOK_NET
+%token TOK_NEXT TOK_NOT_IN TOK_OF TOK_ON TOK_PATTERN TOK_PATTERN_TEXT
+%token TOK_PORT TOK_PRINT TOK_RECORD TOK_REDEF
+%token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET
+%token TOK_STRING TOK_SUBNET TOK_SWITCH TOK_TABLE TOK_THIS
+%token TOK_TIME TOK_TIMER TOK_TYPE TOK_UNION
+
+%token TOK_ATTR_ADD_FUNC TOK_ATTR_ATTR TOK_ATTR_ENCRYPT TOK_ATTR_DEFAULT
+%token TOK_ATTR_OPTIONAL TOK_ATTR_REDEF TOK_ATTR_ROTATE TOK_ATTR_DEL_FUNC
+%token TOK_ATTR_EXPIRE_FUNC TOK_ATTR_EXPIRE_CREATE TOK_ATTR_EXPIRE_READ
+%token TOK_ATTR_EXPIRE_WRITE TOK_ATTR_PERSISTENT TOK_ATTR_POSTPROCESSOR
+
+%token TOK_DEBUG
+
+%left ',' '|'
+%right '='
+%right '?' ':'
+%left TOK_OR
+%left TOK_AND
+%nonassoc '<' '>' TOK_LE TOK_GE TOK_EQ TOK_NE
+%left TOK_IN TOK_NOT_IN
+%left '+' '-'
+%left '*' '/' '%'
+%left TOK_INCR TOK_DECR
+%right '!'
+%left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR
+
+%type <str> TOK_ID TOK_PATTERN_TEXT single_pattern
+%type <id> local_id global_id resolve_id begin_func
+%type <id_l> local_id_list
+%type <ic> init_class
+%type <expr> opt_init
+%type <val> TOK_CONSTANT
+%type <re> pattern
+%type <expr> expr init anonymous_function
+%type <event_expr> event
+%type <stmt> stmt stmt_list func_body for_head
+%type <type> type opt_type refined_type enum_id_list
+%type <func_type> func_hdr func_params
+%type <type_l> type_list
+%type <type_decl> type_decl formal_args_decl
+%type <type_decl_l> type_decl_list formal_args_decl_list opt_attr_attr
+%type <record> formal_args
+%type <list> expr_list opt_expr_list
+%type <c_case> case
+%type <case_l> case_list
+%type <attr> attr
+%type <attr_l> attr_list opt_attr
+%type <match_case> match
+%type <match_cases> match_list
+
+%{
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "input.h"
+#include "Expr.h"
+#include "Stmt.h"
+#include "Var.h"
+#include "DNS.h"
+#include "RE.h"
+#include "Scope.h"
+
+YYLTYPE GetCurrentLocation();
+extern int yyerror(const char[]);
+extern int brolex();
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+	Current = Rhs[N];
+
+/*
+ * Part of the module facility: while parsing, keep track of which
+ * module to put things in.
+ */
+string current_module = GLOBAL_MODULE_NAME;
+bool is_export = false; // true if in an export {} block
+
+/*
+ * When parsing an expression for the debugger, where to put the result
+ * (obviously not reentrant).
+ */
+extern Expr* g_curr_debug_expr;
+
+#define YYLTYPE yyltype
+
+Expr* bro_this = 0;
+int in_init = 0;
+bool in_debug = false;
+
+Expr* curr_match_record_expr = 0;
+
+%}
+
+%union {
+	char* str;
+	ID* id;
+	id_list* id_l;
+	init_class ic;
+	Val* val;
+	RE_Matcher* re;
+	Expr* expr;
+	CallExpr* call_expr;
+	EventExpr* event_expr;
+	Stmt* stmt;
+	ListExpr* list;
+	BroType* type;
+	RecordType* record;
+	FuncType* func_type;
+	TypeList* type_l;
+	TypeDecl* type_decl;
+	type_decl_list* type_decl_l;
+	Case* c_case;
+	case_list* case_l;
+	Attr* attr;
+	attr_list* attr_l;
+	attr_tag attrtag;
+	MatchCase* match_case;
+	MatchCases* match_cases;
+}
+
+%%
+
+bro:
+		decl_list stmt_list
+			{
+			if ( optimize )
+				$2 = $2->Simplify();
+
+			if ( stmts )
+				stmts->AsStmtList()->Stmts().append($2);
+			else
+				stmts = $2;
+
+			// Any objects creates from hereon out should not
+			// have file positions associated with them.
+			set_location(no_location);
+			}
+	|
+		/* Silly way of allowing the debugger to call yyparse()
+		 * on an expr rather than a file.
+		 */
+		TOK_DEBUG { in_debug = true; } expr
+			{
+			g_curr_debug_expr = $3;
+			in_debug = false;
+			}
+	;
+
+decl_list:
+		decl_list decl
+	|
+	;
+
+expr:
+		'(' expr ')'
+			{
+			set_location(@1, @3);
+			$$ = $2; $$->MarkParen();
+			}
+
+	|	TOK_INCR expr
+			{
+			set_location(@1, @2);
+			$$ = new IncrExpr(EXPR_INCR, $2);
+			}
+
+	|	TOK_DECR expr
+			{
+			set_location(@1, @2);
+			$$ = new IncrExpr(EXPR_DECR, $2);
+			}
+
+	|	'!' expr
+			{
+			set_location(@1, @2);
+			$$ = new NotExpr($2);
+			}
+
+	|	'-' expr	%prec '!'
+			{
+			set_location(@1, @2);
+			$$ = new NegExpr($2);
+			}
+
+	|	'+' expr	%prec '!'
+			{
+			set_location(@1, @2);
+			$$ = new PosExpr($2);
+			}
+
+	|	expr '+' expr
+			{
+			set_location(@1, @3);
+			$$ = new AddExpr($1, $3);
+			}
+
+	|	expr '-' expr
+			{
+			set_location(@1, @3);
+			$$ = new SubExpr($1, $3);
+			}
+
+	|	expr '*' expr
+			{
+			set_location(@1, @3);
+			$$ = new TimesExpr($1, $3);
+			}
+
+	|	expr '/' expr
+			{
+			set_location(@1, @3);
+			$$ = new DivideExpr($1, $3);
+			}
+
+	|	expr '%' expr
+			{
+			set_location(@1, @3);
+			$$ = new ModExpr($1, $3);
+			}
+
+	|	expr TOK_AND expr
+			{
+			set_location(@1, @3);
+			$$ = new BoolExpr(EXPR_AND, $1, $3);
+			}
+
+	|	expr TOK_OR expr
+			{
+			set_location(@1, @3);
+			$$ = new BoolExpr(EXPR_OR, $1, $3);
+			}
+
+	|	expr TOK_EQ expr
+			{
+			set_location(@1, @3);
+			$$ = new EqExpr(EXPR_EQ, $1, $3);
+			}
+
+	|	expr TOK_NE expr
+			{
+			set_location(@1, @3);
+			$$ = new EqExpr(EXPR_NE, $1, $3);
+			}
+
+	|	expr '<' expr
+			{
+			set_location(@1, @3);
+			$$ = new RelExpr(EXPR_LT, $1, $3);
+			}
+
+	|	expr TOK_LE expr
+			{
+			set_location(@1, @3);
+			$$ = new RelExpr(EXPR_LE, $1, $3);
+			}
+
+	|	expr '>' expr
+			{
+			set_location(@1, @3);
+			$$ = new RelExpr(EXPR_GT, $1, $3);
+			}
+
+	|	expr TOK_GE expr
+			{
+			set_location(@1, @3);
+			$$ = new RelExpr(EXPR_GE, $1, $3);
+			}
+
+	|	expr '?' expr ':' expr
+			{
+			set_location(@1, @5);
+			$$ = new CondExpr($1, $3, $5);
+			}
+
+	|	expr '=' expr
+			{
+			set_location(@1, @3);
+			$$ = get_assign_expr($1, $3, in_init);
+			}
+
+	|	expr '[' expr_list ']'
+			{
+			set_location(@1, @4);
+			$$ = new IndexExpr($1, $3);
+			}
+
+	|	'$' TOK_ID
+			{
+			set_location(@1, @2);
+			if ( ! curr_match_record_expr )
+				{
+				error("$field syntax may only be used in "
+					"a record match expression");
+				YYERROR;
+				}
+			else
+				$$ = new FieldExpr(curr_match_record_expr, $2);
+			}
+
+	|	expr '$' TOK_ID
+			{
+			set_location(@1, @3);
+			$$ = new FieldExpr($1, $3);
+			}
+
+	|	'$' TOK_ID '=' expr
+			{
+			set_location(@1, @4);
+			$$ = new FieldAssignExpr($2, $4);
+			}
+
+	|	expr TOK_IN expr
+			{
+			set_location(@1, @3);
+			$$ = new InExpr($1, $3);
+			}
+
+	|	expr TOK_NOT_IN expr
+			{
+			set_location(@1, @3);
+			$$ = new NotExpr(new InExpr($1, $3));
+			}
+
+	|	'[' expr_list ']'
+			{
+			// A little crufty: we peek at the type of
+			// the first expression in the list.  If it's
+			// a record or a field assignment, then this
+			// is a record constructor.  If not, then this
+			// is a list used for an initializer.
+
+			set_location(@1, @3);
+
+			Expr* e0 = $2->Exprs()[0];
+			if ( e0->Tag() == EXPR_FIELD_ASSIGN ||
+			     e0->Type()->Tag() == TYPE_RECORD )
+				$$ = new RecordConstructorExpr($2);
+			else
+				$$ = $2;
+			}
+
+	|	TOK_MATCH expr
+			{
+			if ( curr_match_record_expr )
+				{
+				curr_match_record_expr->Error("Nested match expressions not allowed");
+				YYERROR;
+				}
+			else
+				curr_match_record_expr = $2;
+			}
+		TOK_ON '{' match_list opt_comma '}'
+			{
+			curr_match_record_expr = 0;
+			set_location(@1, @7);
+			$$ = new MatchExpr($6);
+			}
+
+	|	expr '(' opt_expr_list ')'
+			{
+			set_location(@1, @4);
+			$$ = new CallExpr($1, $3);
+			}
+
+	|	expr TOK_HAS_FIELD TOK_ID
+			{
+			set_location(@1, @3);
+			$$ = new HasFieldExpr($1, $3, false);
+			}
+
+	|	expr TOK_HAS_ATTR TOK_ID
+			{
+			set_location(@1, @3);
+			$$ = new HasFieldExpr($1, $3, true);
+			}
+
+	|	anonymous_function
+
+	|	TOK_SCHEDULE expr '{' event '}'
+			{
+			set_location(@1, @5);
+			$$ = new ScheduleExpr($2, $4);
+			}
+
+	|	TOK_ID
+			{
+			set_location(@1);
+
+			ID* id = lookup_ID($1, current_module.c_str());
+			if ( ! id )
+				{
+				if ( ! in_debug )
+					{
+/*	// CHECK THAT THIS IS NOT GLOBAL.
+					id = install_ID($1, current_module.c_str(),
+							false, is_export);
+*/
+
+					yyerror(fmt("unknown identifier %s", $1));
+					YYERROR;
+					}
+				else
+					{
+					yyerror(fmt("unknown identifier %s", $1));
+					YYERROR;
+					}
+				}
+			else
+				{
+				if ( ! id->Type() )
+					{
+					id->Error("undeclared variable");
+					id->SetType(error_type());
+					$$ = new NameExpr(id);
+					}
+
+				else if ( id->IsEnumConst() )
+					{
+					EnumType* t = id->Type()->AsEnumType();
+					int intval = t->Lookup(id->ModuleName(),
+							       id->Name());
+					if ( intval < 0 )
+						internal_error("enum value not found for %s", id->Name());
+					$$ = new ConstExpr(new EnumVal(intval, t));
+					}
+				else
+					$$ = new NameExpr(id);
+				}
+			}
+
+	|	TOK_CONSTANT
+			{
+			set_location(@1);
+			$$ = new ConstExpr($1);
+			}
+
+	|	pattern
+			{
+			set_location(@1);
+			$1->Compile();
+			$$ = new ConstExpr(new PatternVal($1));
+			}
+
+	|	TOK_THIS
+			{
+			set_location(@1);
+			$$ = bro_this->Ref();
+			}
+	;
+
+expr_list:
+		expr_list ',' expr
+			{
+			set_location(@1, @3);
+			$1->Append($3);
+			}
+
+	|	expr
+			{
+			set_location(@1);
+			$$ = new ListExpr($1);
+			}
+	;
+
+opt_expr_list:
+		expr_list
+	|
+		{ $$ = new ListExpr(); }
+	;
+
+opt_comma:
+		','
+	|
+	;
+
+match_list:
+		match_list ',' match
+			{
+			set_location(@1, @3);
+			$1->insert(make_pair($3->Priority(), $3));
+			}
+	|	match
+			{
+			set_location(@1);
+			$$ = new MatchCases();
+			$$->insert(make_pair($1->Priority(), $1));
+			}
+	;
+
+match:
+		'[' TOK_CONSTANT ',' expr ',' expr ']'
+		    /* priority, yield-expr, match-expr */
+			{
+			set_location(@1, @7);
+			if ( ! IsIntegral($2->Type()->Tag()) )
+				{
+				$2->Error("Match case priority must be an integer/count");
+				YYERROR;
+				}
+
+			$$ = new MatchCase($2->CoerceToInt(), $4, $6);
+			}
+	;
+
+pattern:
+		pattern '|' single_pattern
+			{
+			$1->AddPat($3);
+			delete [] $3;
+			}
+
+	|	single_pattern
+			{
+			$$ = new RE_Matcher($1);
+			delete [] $1;
+			}
+	;
+
+single_pattern:
+		'/' { begin_RE(); } TOK_PATTERN_TEXT { end_RE(); } '/'
+			{ $$ = $3; }
+	;
+
+enum_id_list:
+		TOK_ID
+			{
+			set_location(@1);
+
+			EnumType* et = new EnumType(is_export);
+			if ( et->AddName(current_module, $1) < 0 )
+				error("identifier in enumerated type definition already exists");
+			$$ = et;
+			}
+
+	|	enum_id_list ',' TOK_ID
+			{
+			set_location(@1, @3);
+
+			if ( $1->AsEnumType()->AddName(current_module, $3) < 1 )
+				error("identifier in enumerated type definition already exists");
+			$$ = $1;
+			}
+	;
+
+type:
+		TOK_BOOL	{
+				set_location(@1);
+				$$ = base_type(TYPE_BOOL);
+				}
+
+	|	TOK_INT		{
+				set_location(@1);
+				$$ = base_type(TYPE_INT);
+				}
+
+	|	TOK_COUNT	{
+				set_location(@1);
+				$$ = base_type(TYPE_COUNT);
+				}
+
+	|	TOK_COUNTER	{
+				set_location(@1);
+				$$ = base_type(TYPE_COUNTER);
+				}
+
+	|	TOK_DOUBLE	{
+				set_location(@1);
+				$$ = base_type(TYPE_DOUBLE);
+				}
+
+	|	TOK_TIME	{
+				set_location(@1);
+				$$ = base_type(TYPE_TIME);
+				}
+
+	|	TOK_INTERVAL	{
+				set_location(@1);
+				$$ = base_type(TYPE_INTERVAL);
+				}
+
+	|	TOK_STRING	{
+				set_location(@1);
+				$$ = base_type(TYPE_STRING);
+				}
+
+	|	TOK_PATTERN	{
+				set_location(@1);
+				$$ = base_type(TYPE_PATTERN);
+				}
+
+	|	TOK_TIMER	{
+				set_location(@1);
+				$$ = base_type(TYPE_TIMER);
+				}
+
+	|	TOK_PORT	{
+				set_location(@1);
+				$$ = base_type(TYPE_PORT);
+				}
+
+	|	TOK_ADDR	{
+				set_location(@1);
+				$$ = base_type(TYPE_ADDR);
+				}
+
+	|	TOK_NET		{
+				set_location(@1);
+				$$ = base_type(TYPE_NET);
+				}
+
+	|	TOK_SUBNET	{
+				set_location(@1);
+				$$ = base_type(TYPE_SUBNET);
+				}
+
+	|	TOK_ANY		{
+				set_location(@1);
+				$$ = base_type(TYPE_ANY);
+				}
+
+	|	TOK_TABLE '[' type_list ']' TOK_OF type
+				{
+				set_location(@1, @6);
+				$$ = new TableType($3, $6);
+				}
+
+	|	TOK_SET '[' type_list ']'
+				{
+				set_location(@1,@4);
+				$$ = new SetType($3, 0);
+				}
+
+	|	TOK_SET '{' expr_list '}'
+				{
+				set_location(@1, @4);
+				$$ = new SetType((TypeList*) 0, $3);
+				}
+
+	|	TOK_RECORD '{' type_decl_list '}'
+				{
+				set_location(@1, @4);
+				$$ = new RecordType($3);
+				}
+
+	|	TOK_UNION '{' type_list '}'
+				{
+				set_location(@1, @4);
+				error("union type not implemented");
+				$$ = 0;
+				}
+
+	|	TOK_ENUM '{' enum_id_list opt_comma '}'
+				{
+				set_location(@1, @4);
+				$$ = $3;
+				}
+
+	|	TOK_LIST
+				{
+				set_location(@1);
+				// $$ = new TypeList();
+				error("list type not implemented");
+				$$ = 0;
+				}
+
+	|	TOK_LIST TOK_OF type
+				{
+				set_location(@1);
+				// $$ = new TypeList($3);
+				error("list type not implemented");
+				$$ = 0;
+				}
+
+	|	TOK_FUNCTION func_params
+				{
+				set_location(@1, @2);
+				$$ = $2;
+				}
+
+	|	TOK_EVENT '(' formal_args ')'
+				{
+				set_location(@1, @3);
+				$$ = new FuncType($3, 0, 1);
+				}
+
+	|	TOK_FILE TOK_OF type
+				{
+				set_location(@1, @3);
+				$$ = new FileType($3);
+				}
+
+	|	TOK_FILE
+				{
+				set_location(@1);
+				$$ = new FileType(base_type(TYPE_STRING));
+				}
+
+	|	resolve_id
+			{
+			if ( ! $1 || ! ($$ = $1->AsType()) )
+				{
+				if ( $1 )
+					$1->Error("not a BRO type");
+				$$ = error_type();
+				}
+			else
+				Ref($$);
+			}
+	;
+
+type_list:
+		type_list ',' type
+			{ $1->AppendEvenIfNotPure($3); }
+	|	type
+			{
+			$$ = new TypeList($1);
+			$$->Append($1);
+			}
+	;
+
+type_decl_list:
+		type_decl_list type_decl
+			{ $1->append($2); }
+	|
+			{ $$ = new type_decl_list(); }
+	;
+
+type_decl:
+		TOK_ID ':' type opt_attr ';'
+			{
+			set_location(@1, @5);
+			$$ = new TypeDecl($3, $1, $4);
+			}
+	;
+
+formal_args:	formal_args_decl_list
+			{ $$ = new RecordType($1); }
+	|	formal_args_decl_list ';'
+			{ $$ = new RecordType($1); }
+	|
+			{ $$ = new RecordType(new type_decl_list()); }
+	;
+
+formal_args_decl_list:
+		formal_args_decl_list ';' formal_args_decl
+			{ $1->append($3); }
+	|	formal_args_decl_list ',' formal_args_decl
+			{ $1->append($3); }
+	|	formal_args_decl
+			{ $$ = new type_decl_list(); $$->append($1); }
+	;
+
+formal_args_decl:
+		TOK_ID ':' type opt_attr
+			{
+			set_location(@1, @4);
+			$$ = new TypeDecl($3, $1, $4);
+			}
+	;
+
+decl:
+		TOK_MODULE TOK_ID ';'
+			{ current_module = $2; }
+
+	|	TOK_EXPORT '{' { is_export = true; } decl_list '}'
+			{ is_export = false; }
+
+	|	TOK_GLOBAL global_id opt_type init_class opt_init opt_attr ';'
+			{ add_global($2, $3, $4, $5, $6, VAR_REGULAR); }
+
+	|	TOK_CONST global_id opt_type init_class opt_init opt_attr ';'
+			{ add_global($2, $3, $4, $5, $6, VAR_CONST); }
+
+	|	TOK_REDEF global_id opt_type init_class opt_init opt_attr ';'
+			{ add_global($2, $3, $4, $5, $6, VAR_REDEF); }
+
+	|       TOK_REDEF TOK_ENUM global_id TOK_ADD_TO
+		'{' enum_id_list opt_comma '}' ';'
+			{
+			if ( ! $3->Type() )
+				$3->Error("unknown identifier");
+			else
+				{
+				EnumType* add_to = $3->Type()->AsEnumType();
+				if ( ! add_to )
+					$3->Error("not an enum");
+				else
+					add_to->AddNamesFrom(current_module,
+							     $6->AsEnumType());
+				}
+			}
+
+	|	TOK_TYPE global_id ':' refined_type opt_attr opt_attr_attr';'
+			{
+			add_type($2, $4, $5, 0);
+			if ( $6 )
+				$2->AsType()->SetAttributesType($6);
+			}
+
+	|	TOK_GLOBAL_ATTR ':' { in_global_attr_decl = true; }
+		'{' type_decl_list '}' ';' { in_global_attr_decl = false; }
+			{
+			global_attributes_type = new RecordType($5);
+			}
+
+	|	TOK_EVENT global_id ':' refined_type opt_attr ';'
+			{ add_type($2, $4, $5, 1); }
+
+	|	func_hdr func_body
+			{ }
+
+	|	conditional
+	;
+
+conditional:
+		TOK_ATIF '(' expr ')'
+			{ do_atif($3); }
+	|	TOK_ATIFDEF '(' TOK_ID ')'
+			{ do_atifdef($3); }
+	|	TOK_ATIFNDEF '(' TOK_ID ')'
+			{ do_atifndef($3); }
+	|	TOK_ATENDIF
+			{ do_atendif(); }
+	|	TOK_ATELSE
+			{ do_atelse(); }
+	;
+
+opt_attr_attr:
+		TOK_ATTR_ATTR '=' '{' type_decl_list '}'
+			{ $$ = $4; }
+	|
+			{ $$ = 0; }
+	;
+
+func_hdr:
+		TOK_FUNCTION global_id func_params
+			{
+			begin_func($2, current_module.c_str(),
+				   FUNC_FLAVOR_FUNCTION, 0, $3);
+			$$ = $3;
+			}
+	|	TOK_EVENT global_id func_params
+			{
+			begin_func($2, current_module.c_str(),
+				   FUNC_FLAVOR_EVENT, 0, $3);
+			$$ = $3;
+			}
+	|	TOK_REDEF TOK_EVENT global_id func_params
+			{
+			begin_func($3, current_module.c_str(),
+				   FUNC_FLAVOR_EVENT, 1, $4);
+			$$ = $4;
+			}
+	;
+
+func_body:
+		'{' stmt_list '}'
+			{
+			if ( optimize )
+				$2 = $2->Simplify();
+
+			end_func($2);
+			}
+	;
+
+anonymous_function:
+		TOK_FUNCTION begin_func func_body
+			{ $$ = new ConstExpr($2->ID_Val()); }
+	;
+
+begin_func:
+		func_params
+			{
+			$$ = current_scope()->GenerateTemporary("anonymous-function");
+			begin_func($$, current_module.c_str(),
+				   FUNC_FLAVOR_FUNCTION, 0, $1);
+			}
+	;
+
+func_params:
+		'(' formal_args ')' ':' type
+			{ $$ = new FuncType($2, $5, 0); }
+	|	'(' formal_args ')'
+			{ $$ = new FuncType($2, base_type(TYPE_VOID), 0); }
+	;
+
+refined_type:
+		type_list '{' type_decl_list '}'
+			{ $$ = refine_type($1, $3); }
+	|	type_list
+			{ $$ = refine_type($1, 0); }
+	;
+
+opt_type:
+		':' type
+			{ $$ = $2; }
+	|
+			{ $$ = 0; }
+	;
+
+init_class:
+				{ $$ = INIT_NONE; }
+	|	'='		{ $$ = INIT_FULL; }
+	|	TOK_ADD_TO	{ $$ = INIT_EXTRA; }
+	|	TOK_REMOVE_FROM	{ $$ = INIT_REMOVE; }
+	;
+
+opt_init:
+		{ ++in_init; } init { --in_init; }
+			{ $$ = $2; }
+	|
+			{ $$ = 0; }
+	;
+
+init:
+		'{' opt_expr_list '}'
+			{ $$ = $2; }
+	|	'{' expr_list ',' '}'
+			{ $$ = $2; }
+	|	expr
+	;
+
+opt_attr:
+		attr_list
+	|
+			{ $$ = 0; }
+	;
+
+attr_list:
+		attr_list attr
+			{ $1->append($2); }
+	|	attr
+			{
+			$$ = new attr_list;
+			$$->append($1);
+			}
+	;
+
+attr:
+		TOK_ATTR_DEFAULT '=' expr
+			{ $$ = new Attr(ATTR_DEFAULT, $3); }
+	|	TOK_ATTR_OPTIONAL
+			{ $$ = new Attr(ATTR_OPTIONAL); }
+	|	TOK_ATTR_REDEF
+			{ $$ = new Attr(ATTR_REDEF); }
+	|	TOK_ATTR_ROTATE '=' expr
+			{ $$ = new Attr(ATTR_ROTATE, $3); }
+	|	TOK_ATTR_ADD_FUNC '=' expr
+			{ $$ = new Attr(ATTR_ADD_FUNC, $3); }
+	|	TOK_ATTR_DEL_FUNC '=' expr
+			{ $$ = new Attr(ATTR_DEL_FUNC, $3); }
+	|	TOK_ATTR_POSTPROCESSOR '=' expr
+			{ $$ = new Attr(ATTR_POSTPROCESSOR, $3); }
+	|	TOK_ATTR_EXPIRE_FUNC '=' expr
+			{ $$ = new Attr(ATTR_EXPIRE_FUNC, $3); }
+	|	TOK_ATTR_EXPIRE_CREATE '=' expr
+			{ $$ = new Attr(ATTR_EXPIRE_CREATE, $3); }
+	|	TOK_ATTR_EXPIRE_READ '=' expr
+			{ $$ = new Attr(ATTR_EXPIRE_READ, $3); }
+	|	TOK_ATTR_EXPIRE_WRITE '=' expr
+			{ $$ = new Attr(ATTR_EXPIRE_WRITE, $3); }
+	|	TOK_ATTR_PERSISTENT
+			{ $$ = new Attr(ATTR_PERSISTENT); }
+	|	TOK_ATTR_ENCRYPT
+			{ $$ = new Attr(ATTR_ENCRYPT); }
+	|	TOK_ATTR_ENCRYPT '=' expr
+			{ $$ = new Attr(ATTR_ENCRYPT, $3); }
+	;
+
+stmt:
+		'{' stmt_list '}'
+			{ $$ = $2; }
+
+	|	TOK_LOG expr_list ';'
+			{
+			set_location(@1, @3);
+			$$ = new LogStmt($2);
+			}
+
+	|	TOK_PRINT expr_list ';'
+			{
+			set_location(@1, @3);
+			$$ = new PrintStmt($2);
+			}
+
+	|	TOK_EVENT event ';'
+			{
+			set_location(@1, @3);
+			$$ = new EventStmt($2);
+			}
+
+	|	TOK_IF '(' expr ')' stmt
+			{
+			set_location(@1, @4);
+			$$ = new IfStmt($3, $5, new NullStmt());
+			}
+
+	|	TOK_IF '(' expr ')' stmt TOK_ELSE stmt
+			{
+			set_location(@1, @4);
+			$$ = new IfStmt($3, $5, $7);
+			}
+
+	|	TOK_SWITCH expr '{' case_list '}'
+			{
+			set_location(@1, @2);
+			$$ = new SwitchStmt($2, $4);
+			}
+
+	|	for_head stmt
+			{ $1->AsForStmt()->AddBody($2); }
+
+	|	TOK_NEXT ';'
+			{
+			set_location(@1, @2);
+			$$ = new NextStmt;
+			}
+
+	|	TOK_BREAK ';'
+			{
+			set_location(@1, @2);
+			$$ = new BreakStmt;
+			}
+
+	|	TOK_RETURN ';'
+			{
+			set_location(@1, @2);
+			$$ = new ReturnStmt(0);
+			}
+
+	|	TOK_RETURN expr ';'
+			{
+			set_location(@1, @2);
+			$$ = new ReturnStmt($2);
+			}
+
+	|	TOK_ADD expr ';'
+			{
+			set_location(@1, @3);
+			$$ = new AddStmt($2);
+			}
+
+	|	TOK_DELETE expr ';'
+			{
+			set_location(@1, @3);
+			$$ = new DelStmt($2);
+			}
+
+	|	TOK_LOCAL local_id opt_type init_class opt_init opt_attr ';'
+			{
+			set_location(@1, @7);
+			$$ = add_local($2, $3, $4, $5, $6, VAR_REGULAR);
+			}
+
+	|	TOK_CONST local_id opt_type init_class opt_init opt_attr ';'
+			{
+			set_location(@1, @6);
+			$$ = add_local($2, $3, $4, $5, $6, VAR_CONST);
+			}
+
+	|	expr ';'
+			{
+			set_location(@1, @2);
+			$$ = new ExprStmt($1);
+			}
+
+	|	';'
+			{
+			set_location(@1, @1);
+			$$ = new NullStmt;
+			}
+
+	|	conditional
+			{ $$ = new NullStmt; }
+	;
+
+stmt_list:
+		stmt_list stmt
+			{
+			$1->AsStmtList()->Stmts().append($2);
+			assert($2->GetLocationInfo()->first_line != 0);
+			}
+	|
+			{ $$ = new StmtList(); }
+	;
+
+event:
+		TOK_ID '(' opt_expr_list ')'
+			{
+			set_location(@1, @4);
+			$$ = new EventExpr($1, $3);
+			}
+	;
+
+case_list:
+		case_list case
+			{ $1->append($2); }
+	|
+			{ $$ = new case_list; }
+	;
+
+case:
+		TOK_CASE expr_list ':' stmt_list
+			{ $$ = new Case($2, $4); }
+	|
+		TOK_DEFAULT ':' stmt_list
+			{ $$ = new Case(0, $3); }
+	;
+
+for_head:
+		TOK_FOR '(' TOK_ID TOK_IN expr ')'
+			{
+			set_location(@1, @6);
+
+			// This rule needs to be separate from the loop
+			// body so that we execute these actions - defining
+			// the local variable - prior to parsing the body,
+			// which might refer to the variable.
+			ID* loop_var = lookup_ID($3, current_module.c_str());
+
+			if ( loop_var )
+				{
+				if ( loop_var->IsGlobal() )
+					loop_var->Error("global used in for loop");
+				}
+
+			else
+				loop_var = install_ID($3, current_module.c_str(),
+						      false, false);
+
+			id_list* loop_vars = new id_list;
+			loop_vars->append(loop_var);
+
+			$$ = new ForStmt(loop_vars, $5);
+			}
+	|
+		TOK_FOR '(' '[' local_id_list ']' TOK_IN expr ')'
+			{ $$ = new ForStmt($4, $7); }
+		;
+
+local_id_list:
+		local_id_list ',' local_id
+			{ $1->append($3); }
+	|	local_id
+			{
+			$$ = new id_list;
+			$$->append($1);
+			}
+	;
+
+local_id:
+		TOK_ID
+			{
+			set_location(@1);
+
+			$$ = lookup_ID($1, current_module.c_str());
+			if ( $$ )
+				{
+				if ( $$->IsGlobal() )
+					$$->Error("already a global identifier");
+				delete [] $1;
+				}
+
+			else
+				{
+				$$ = install_ID($1, current_module.c_str(),
+						false, is_export);
+				}
+			}
+	;
+
+global_id:
+		TOK_ID
+			{
+			set_location(@1);
+
+			$$ = lookup_ID($1, current_module.c_str());
+			if ( $$ )
+				{
+				if ( ! $$->IsGlobal() )
+					$$->Error("already a local identifier");
+
+				delete [] $1;
+				}
+
+			else
+				{
+				$$ = install_ID($1, current_module.c_str(),
+						true, is_export);
+				}
+			}
+	;
+
+resolve_id:
+		TOK_ID
+			{
+			set_location(@1);
+			$$ = lookup_ID($1, current_module.c_str());
+			if ( ! $$ )
+				error("identifier not defined", $1);
+			delete [] $1;
+			}
+	;
+
+%%
+
+int yyerror(const char msg[])
+	{
+	char* msgbuf = new char[strlen(msg) + strlen(brotext) + 64];
+
+	if ( brotext[0] == '\n' )
+		sprintf(msgbuf, "%s, on previous line", msg);
+	else if ( brotext[0] == '\0' )
+		sprintf(msgbuf, "%s, at end of file", msg);
+	else
+		sprintf(msgbuf, "%s, at or near \"%s\"", msg, brotext);
+
+	error(msgbuf);
+	curr_match_record_expr = 0;
+
+	return 0;
+	}
diff -uNr bro-pub-0.8a41/policy/bro.bif.bro bro-pub-0.841-ssl/policy/bro.bif.bro
--- bro-pub-0.8a41/policy/bro.bif.bro	Fri Oct 10 07:08:46 2003
+++ bro-pub-0.841-ssl/policy/bro.bif.bro	Thu Jan  1 01:00:00 1970
@@ -1,104 +0,0 @@
-# This file was automatically generated by bifcl from bro.bif.
-
-global length: function(v: any): count;
-global clear_table: function(v: any): any;
-global cat: function(va_args: any): string;
-global string_cat: function(va_args: any): string;
-global cat_string_array: function(a: string_array): string;
-global cat_string_array_n: function(a: string_array, start: count, end: count): string;
-global sort_string_array: function(a: string_array): string_array;
-global fmt: function(va_args: any): string;
-global edit: function(arg_s: string, arg_edit_char: string): string;
-global byte_len: function(s: string): count;
-global sub_bytes: function(s: string, start: count, n: int): string;
-global split: function(str: string, re: pattern): string_array;
-global split1: function(str: string, re: pattern): string_array;
-global split_all: function(str: string, re: pattern): string_array;
-global split_n: function(str: string, re: pattern, incl_sep: bool, max_num_sep: count): string_array;
-global split_complete: function(str: string, re: pattern, other: string_set, incl_sep: bool, max_num_sep: count): string_array;
-global strcmp: function(s1: string, s2: string): int;
-global strstr: function(big: string, little: string): count;
-global subst_string: function(s: string, from: string, to: string): string;
-global to_int: function(str: string): int;
-global int_to_count: function(n: int): count;
-global to_count: function(str: string): count;
-global to_addr: function(ip: string): addr;
-global to_net: function(a: addr): net;
-global net_to_subnet: function(a: net): subnet;
-global mask_addr: function(a: addr, top_bits_to_keep: count): addr;
-global is_tcp_port: function(p: port): bool;
-global reading_live_traffic: function(): bool;
-global open: function(f: string): file;
-global open_for_append: function(f: string): file;
-global close: function(f: file): bool;
-global set_buf: function(f: file, buffered: bool): any;
-global flush_all: function(): bool;
-global mkdir: function(f: string): bool;
-global active_file: function(f: file): bool;
-global active_connection: function(id: conn_id): bool;
-global connection_record: function(cid: conn_id): connection;
-global current_time: function(): time;
-global network_time: function(): time;
-global getenv: function(var: string): string;
-global to_lower: function(str: string): string;
-global to_upper: function(str: string): string;
-global clean: function(str: string): string;
-global to_string_literal: function(str: string): string;
-global exit: function(): int;
-global system: function(str: string): int;
-global connection_exists: function(c: conn_id): bool;
-global lookup_connection: function(cid: conn_id): connection;
-global skip_further_processing: function(cid: conn_id): bool;
-global set_record_packets: function(cid: conn_id, do_record: bool): bool;
-global set_contents_file: function(cid: conn_id, direction: count, f: file): bool;
-global set_inactivity_timeout: function(cid: conn_id, timeout: interval): interval;
-global get_login_state: function(cid: conn_id): count;
-global set_login_state: function(cid: conn_id, new_state: count): bool;
-global get_orig_seq: function(cid: conn_id): count;
-global get_resp_seq: function(cid: conn_id): count;
-global ptr_name_to_addr: function(s: string): addr;
-global addr_to_ptr_name: function(a: addr): string;
-global parse_dotted_addr: function(s: string): addr;
-global parse_ftp_port: function(s: string): ftp_port;
-global parse_ftp_pasv: function(str: string): ftp_port;
-global fmt_ftp_port: function(a: addr, p: port): string;
-global skip_http_entity_data: function(c: connection, is_orig: bool): any;
-global unescape_URI: function(URI: string): string;
-global skip_smtp_data: function(c: connection): any;
-global resource_usage: function(): bro_resources;
-global get_matcher_stats: function(): matcher_stats;
-global val_size: function(v: any): count;
-global global_sizes: function(): var_sizes;
-global rewriting_trace: function(): bool;
-global preserve_prefix: function(a: addr, width: count): any;
-global preserve_subnet: function(a: subnet): any;
-global preserve_net: function(a: net): any;
-global anonymize_addr: function(a: addr, cl: IPAddrAnonymizationClass): addr;
-global get_contents_type: function(c: connection): count;
-global md5_hash: function(va_args: any): string;
-global md5_hmac: function(va_args: any): string;
-global merge_pattern: function(p1: pattern, p2: pattern): pattern;
-global convert_for_pattern: function(s: string): string;
-global string_to_pattern: function(s: string, convert: bool): pattern;
-global escape_string: function(s: string): string;
-global precompile_pcap_filter: function(id: PcapFilterID, s: string): bool;
-global install_pcap_filter: function(id: PcapFilterID): bool;
-global pcap_error: function(): string;
-global install_src_addr_filter: function(ip: addr, tcp_flags: count, prob: count): bool;
-global install_src_net_filter: function(snet: subnet, tcp_flags: count, prob: count): bool;
-global uninstall_src_addr_filter: function(ip: addr): bool;
-global uninstall_src_net_filter: function(snet: subnet): bool;
-global install_dst_addr_filter: function(ip: addr, tcp_flags: count, prob: count): bool;
-global install_dst_net_filter: function(snet: subnet, tcp_flags: count, prob: count): bool;
-global uninstall_dst_addr_filter: function(ip: addr): bool;
-global uninstall_dst_net_filter: function(snet: subnet): bool;
-global checkpoint_state: function(): bool;
-global capture_events: function(filename: string): bool;
-global connect_clear: function(ip: addr, p: port, retry: interval): bool;
-global connect_ssl: function(ip: addr, p: port, retry: interval): bool;
-global request_remote_events: function(ip: addr, p: port, handlers: pattern): bool;
-global listen_clear: function(ip: addr, p: port): bool;
-global listen_ssl: function(ip: addr, p: port): bool;
-global is_remote_event: function(): bool;
-global get_event_source: function(): event_source;
-global send_capture_filter: function(ip: addr, p: port, s: string): bool;
diff -uNr bro-pub-0.8a41/policy/bro.init bro-pub-0.841-ssl/policy/bro.init
--- bro-pub-0.8a41/policy/bro.init	Fri Oct 10 02:25:26 2003
+++ bro-pub-0.841-ssl/policy/bro.init	Wed Oct 15 05:17:51 2003
@@ -468,6 +468,14 @@
 	name: string;
 	value: string;
 };
+
+# --- ssl & x509 types ---
+type cipher_suites_list: table[count] of count;
+type x509: record {
+	issuer:  string; # issuer name of the certificate
+	subject: string; # subject name of the certificate
+};
+
 type mime_header_list: table[count] of mime_header_rec;
 global mime_segment_length = 1024 &redef;
 global mime_segment_overlap_length = 32 &redef;

diff -uNr bro-pub-0.8a41/policy/finger-rw.bif.bro bro-pub-0.841-ssl/policy/finger-rw.bif.bro
--- bro-pub-0.8a41/policy/finger-rw.bif.bro	Fri Oct 10 07:08:37 2003
+++ bro-pub-0.841-ssl/policy/finger-rw.bif.bro	Thu Jan  1 01:00:00 1970
@@ -1,4 +0,0 @@
-# This file was automatically generated by bifcl from finger-rw.bif.
-
-global rewrite_finger_request: function (c: connection, full: bool, username: string, hostpart: string);
-global rewrite_finger_reply: function (c: connection, reply: string);

diff -uNr bro-pub-0.8a41/policy/ssl-alerts.bro bro-pub-0.841-ssl/policy/ssl-alerts.bro
--- bro-pub-0.8a41/policy/ssl-alerts.bro	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/policy/ssl-alerts.bro	Wed Oct 15 05:19:45 2003
@@ -0,0 +1,105 @@
+#
+# BroSkript interface for the SSL/TLS support 
+# Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+#
+
+# --- constant definitions of the SSL/TLS alert/error records ---
+
+# --- Error descriptions for SSLv2
+
+const SSLv2_PE_NO_CIPHER:                    count = 0x0001;
+const SSLv2_PE_NO_CERTIFICATE:               count = 0x0002;
+const SSLv2_PE_BAD_CERTIFICATE:              count = 0x0004;
+const SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE: count = 0x0006;
+
+# --- Alert descriptions in SSLv3.0 and SSLv3.1
+
+const SSLv3x_ALERT_DESCR_CLOSE_NOTIFY:            count = 0;
+const SSLv3x_ALERT_DESCR_UNEXPECTED_MESSSAGE:     count = 10;
+const SSLv3x_ALERT_DESCR_BAD_RECORD_MAC:          count = 20;
+const SSLv3x_ALERT_DESCR_DECOMPRESSION_FAILURE:   count = 30;
+const SSLv3x_ALERT_DESCR_HANDSHAKE_FAILURE:       count = 40;
+const SSLv3x_ALERT_DESCR_BAD_CERTIFICATE:         count = 42;
+const SSLv3x_ALERT_DESCR_UNSUPPORTED_CERTIFICATE: count = 43;
+const SSLv3x_ALERT_DESCR_CERTIFICATE_REVOKED:     count = 44;
+const SSLv3x_ALERT_DESCR_CERTIFICATE_EXPIRED:     count = 45;
+const SSLv3x_ALERT_DESCR_CERTIFICATE_UNKNOWN:     count = 46;
+
+# --- Alert descriptions only in SSLv3.0
+
+const SSLv30_ALERT_DESCR_NO_CERTIFICATE: count = 41;
+
+# --- Alert descriptions only in SSLv3.1
+
+const SSLv31_ALERT_DESCR_DESCRYPTION_FAILED:    count = 21;
+const SSLv31_ALERT_DESCR_RECORD_OVERFLOW:       count = 22;
+const SSLv31_ALERT_DESCR_ILLEGAL_PARAMETER:     count = 47;
+const SSLv31_ALERT_DESCR_UNKNOWN_CA:            count = 48;
+const SSLv31_ALERT_DESCR_ACCESS_DENIED:         count = 49;
+const SSLv31_ALERT_DESCR_DECODE_ERROR:          count = 50;
+const SSLv31_ALERT_DESCR_DECRYPT_ERROR:         count = 51;
+const SSLv31_ALERT_DESCR_EXPORT_RESTRICTION:    count = 60;
+const SSLv31_ALERT_DESCR_PROTOCOL_VERSION:      count = 70;
+const SSLv31_ALERT_DESCR_INSUFFICIENT_SECURITY: count = 71;
+const SSLv31_ALERT_DESCR_INTERNAL_ERROR:        count = 80;
+const SSLv31_ALERT_DESCR_USER_CANCELED:         count = 90;
+const SSLv31_ALERT_DESCR_NO_RENEGOTIATION:      count = 100;
+
+# --- This is a table of all known alert descriptions.
+# --- It can be used for detecting unknown alerts and for 
+# --- converting the alert descriptions constants into a human readable format.
+
+const ssl_alert_desc: table[count] of string =
+	{ # --- SSLv2
+		[SSLv2_PE_NO_CIPHER]                    = "SSLv2_PE_NO_CIPHER",
+		[SSLv2_PE_NO_CERTIFICATE]               = "SSLv2_PE_NO_CERTIFICATE",
+		[SSLv2_PE_BAD_CERTIFICATE]              = "SSLv2_PE_BAD_CERTIFICATE",
+		[SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE] = "SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE",
+	  # --- sslv30
+		[SSLv30_ALERT_DESCR_NO_CERTIFICATE] = "SSLv30_ALERT_DESCR_NO_CERTIFICATE",
+	  # --- sslv31
+	  	[SSLv31_ALERT_DESCR_DESCRYPTION_FAILED]    = "SSLv31_ALERT_DESCR_DESCRYPTION_FAILED",
+	  	[SSLv31_ALERT_DESCR_RECORD_OVERFLOW]       = "SSLv31_ALERT_DESCR_RECORD_OVERFLOW",
+	  	[SSLv31_ALERT_DESCR_ILLEGAL_PARAMETER]     = "SSLv31_ALERT_DESCR_ILLEGAL_PARAMETER",
+	  	[SSLv31_ALERT_DESCR_UNKNOWN_CA]            = "SSLv31_ALERT_DESCR_UNKNOWN_CA",
+	  	[SSLv31_ALERT_DESCR_ACCESS_DENIED]         = "SSLv31_ALERT_DESCR_ACCESS_DENIED",
+	  	[SSLv31_ALERT_DESCR_DECODE_ERROR]          = "SSLv31_ALERT_DESCR_DECODE_ERROR",
+	  	[SSLv31_ALERT_DESCR_DECRYPT_ERROR]         = "SSLv31_ALERT_DESCR_DECRYPT_ERROR",
+	  	[SSLv31_ALERT_DESCR_EXPORT_RESTRICTION]    = "SSLv31_ALERT_DESCR_EXPORT_RESTRICTION",
+	  	[SSLv31_ALERT_DESCR_PROTOCOL_VERSION]      = "SSLv31_ALERT_DESCR_PROTOCOL_VERSION",
+	  	[SSLv31_ALERT_DESCR_INSUFFICIENT_SECURITY] = "SSLv31_ALERT_DESCR_INSUFFICIENT_SECURITY",
+	  	[SSLv31_ALERT_DESCR_INTERNAL_ERROR]        = "SSLv31_ALERT_DESCR_INTERNAL_ERROR",
+	  	[SSLv31_ALERT_DESCR_USER_CANCELED]         = "SSLv31_ALERT_DESCR_USER_CANCELED",
+	  	[SSLv31_ALERT_DESCR_NO_RENEGOTIATION]      = "SSLv31_ALERT_DESCR_NO_RENEGOTIATION",
+	  # -- sslv3.0 and sslv3.1
+	  	[SSLv3x_ALERT_DESCR_CLOSE_NOTIFY]            = "SSLv3x_ALERT_DESCR_CLOSE_NOTIFY",
+	  	[SSLv3x_ALERT_DESCR_UNEXPECTED_MESSSAGE]     = "SSLv3x_ALERT_DESCR_UNEXPECTED_MESSSAGE",
+	  	[SSLv3x_ALERT_DESCR_BAD_RECORD_MAC]          = "SSLv3x_ALERT_DESCR_BAD_RECORD_MAC",
+	  	[SSLv3x_ALERT_DESCR_DECOMPRESSION_FAILURE]   = "SSLv3x_ALERT_DESCR_DECOMPRESSION_FAILURE",
+	  	[SSLv3x_ALERT_DESCR_HANDSHAKE_FAILURE]       = "SSLv3x_ALERT_DESCR_HANDSHAKE_FAILURE",
+	  	[SSLv3x_ALERT_DESCR_BAD_CERTIFICATE]         = "SSLv3x_ALERT_DESCR_BAD_CERTIFICATE",
+	  	[SSLv3x_ALERT_DESCR_UNSUPPORTED_CERTIFICATE] = "SSLv3x_ALERT_DESCR_UNSUPPORTED_CERTIFICATE",
+	  	[SSLv3x_ALERT_DESCR_CERTIFICATE_REVOKED]     = "SSLv3x_ALERT_DESCR_CERTIFICATE_REVOKED",
+	  	[SSLv3x_ALERT_DESCR_CERTIFICATE_EXPIRED]     = "SSLv3x_ALERT_DESCR_CERTIFICATE_EXPIRED",
+	  	[SSLv3x_ALERT_DESCR_CERTIFICATE_UNKNOWN]     = "SSLv3x_ALERT_DESCR_CERTIFICATE_UNKNOWN"
+	  };
+	
+
+# --- definitions for SSLv2 error levels:
+# NOTE: We currently use the SSLv3x alert levels "WARNING" and "FATAL"
+#       for SSLv2, since SLLv2 does not support an explicit error level.
+
+# --- definitions for SSLv3.0/SSLv3.1 alert levels
+
+const SSLv3x_ALERT_LEVEL_WARNING: count = 1;
+const SSLv3x_ALERT_LEVEL_FATAL:   count = 2;
+
+# --- This is a table of all known alert levels.
+# --- It can be used for detecting unknown alert levels and for 
+# --- converting the alert level constants into a human readable format.
+
+const ssl_alert_level: table[count] of string =
+	{ 
+		[SSLv3x_ALERT_LEVEL_WARNING] = "SSLv3x_ALERT_LEVEL_WARNING",
+		[SSLv3x_ALERT_LEVEL_FATAL]   = "SSLv3x_ALERT_LEVEL_FATAL"
+	};
diff -uNr bro-pub-0.8a41/policy/ssl-ciphers.bro bro-pub-0.841-ssl/policy/ssl-ciphers.bro
--- bro-pub-0.8a41/policy/ssl-ciphers.bro	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/policy/ssl-ciphers.bro	Wed Oct 15 05:19:50 2003
@@ -0,0 +1,290 @@
+#
+# BroSkript interface for the SSL/TLS support 
+# Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+#
+
+# --- constant definitions of the cipher specs ---
+
+# --- sslv2 ---
+const SSLv20_CK_RC4_128_WITH_MD5:              count = 0x010080;
+const SSLv20_CK_RC4_128_EXPORT40_WITH_MD5:     count = 0x020080;
+const SSLv20_CK_RC2_128_CBC_WITH_MD5:          count = 0x030080;
+const SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5: count = 0x040080;
+const SSLv20_CK_IDEA_128_CBC_WITH_MD5:         count = 0x050080;
+const SSLv20_CK_DES_64_CBC_WITH_MD5:           count = 0x060040;
+const SSLv20_CK_DES_192_EDE3_CBC_WITH_MD5:     count = 0x0700C0;
+
+# --- sslv3x ---
+
+const SSLv3x_NULL_WITH_NULL_NULL : count = 0x0000;
+
+#   The following CipherSuite definitions require that the server
+#   provide an RSA certificate that can be used for key exchange.  The
+#   server may request either an RSA or a DSS signature-capable
+#   certificate in the certificate request message.
+
+const SSLv3x_RSA_WITH_NULL_MD5:              count = 0x0001;
+const SSLv3x_RSA_WITH_NULL_SHA:              count = 0x0002;
+const SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5:     count = 0x0003;
+const SSLv3x_RSA_WITH_RC4_128_MD5:           count = 0x0004;
+const SSLv3x_RSA_WITH_RC4_128_SHA:           count = 0x0005;
+const SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5: count = 0x0006;
+const SSLv3x_RSA_WITH_IDEA_CBC_SHA:          count = 0x0007;
+const SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA:  count = 0x0008;
+const SSLv3x_RSA_WITH_DES_CBC_SHA:           count = 0x0009;
+const SSLv3x_RSA_WITH_3DES_EDE_CBC_SHA:      count = 0x000A;
+
+#  The following CipherSuite definitions are used for
+#  server-authenticated (and optionally client-authenticated)
+#  Diffie-Hellman.  DH denotes cipher suites in which the server's
+#  certificate contains the Diffie-Hellman parameters signed by the
+#  certificate authority (CA).  DHE denotes ephemeral Diffie-Hellman,
+#  where the Diffie-Hellman parameters are signed by a DSS or RSA
+#  certificate, which has been signed by the CA.  The signing
+#  algorithm used is specified after the DH or DHE parameter.  In all
+#  cases, the client must have the same type of certificate, and must
+#  use the Diffie-Hellman parameters chosen by the server.
+
+const SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:  count = 0x000B;
+const SSLv3x_DH_DSS_WITH_DES_CBC_SHA:           count = 0x000C;
+const SSLv3x_DH_DSS_WITH_3DES_EDE_CBC_SHA:      count = 0x000D;
+const SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:  count = 0x000E;
+const SSLv3x_DH_RSA_WITH_DES_CBC_SHA:           count = 0x000F;
+const SSLv3x_DH_RSA_WITH_3DES_EDE_CBC_SHA:      count = 0x0010;
+const SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: count = 0x0011;
+const SSLv3x_DHE_DSS_WITH_DES_CBC_SHA:          count = 0x0012;
+const SSLv3x_DHE_DSS_WITH_3DES_EDE_CBC_SHA:     count = 0x0013;
+const SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: count = 0x0014;
+const SSLv3x_DHE_RSA_WITH_DES_CBC_SHA:          count = 0x0015;
+const SSLv3x_DHE_RSA_WITH_3DES_EDE_CBC_SHA:     count = 0x0016;
+
+#  The following cipher suites are used for completely anonymous
+#  Diffie-Hellman communications in which neither party is
+#  authenticated.  Note that this mode is vulnerable to
+#  man-in-the-middle attacks and is therefore strongly discouraged.
+
+const SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5:    count = 0x0017;
+const SSLv3x_DH_ANON_WITH_RC4_128_MD5:          count = 0x0018;
+const SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA: count = 0x0019;
+const SSLv3x_DH_ANON_WITH_DES_CBC_SHA:          count = 0x001A;
+const SSLv3x_DH_ANON_WITH_3DES_EDE_CBC_SHA:     count = 0x001B;
+
+#   The final cipher suites are for the FORTEZZA token.
+
+const SSLv3x_FORTEZZA_KEA_WITH_NULL_SHA:         count = 0x001C;
+const SSLv3x_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA: count = 0x001D;
+const SSLv3x_FORTEZZA_KEA_WITH_RC4_128_SHA:      count = 0x001E;
+
+#   Note:          All cipher suites whose first byte is 0xFF are
+#                  considered private and can be used for defining
+#                  local/experimental algorithms.  Interoperability of
+#                  such types is a local matter.
+
+#   Note:          Additional cipher suites will be considered for
+#                  implementation only with submission of notarized
+#                  letters from two independent entities.  Netscape
+#                  Communications Corp. will act as an interim
+#                  registration office, until a public standards body
+#                  assumes control of SSL.
+
+
+# Cipher specifications native to TLS can be included in Version 2.0 client
+# hello messages using the syntax below. Any V2CipherSpec element with its
+# first byte equal to zero will be ignored by Version 2.0 servers. Clients
+# sending any of the above V2CipherSpecs should also include the TLS equivalent
+# (see Appendix A.5):
+# V2CipherSpec (see TLS name) = { 0x00, CipherSuite };
+
+# --- 56-Bit Export Cipher Suites for TLS
+# --- defined in draft-ietf-tls-56-bit-ciphersuites-00.txt
+
+const SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA:     count = 0x0062;
+const SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA:      count = 0x0064;
+const SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA: count = 0x0063;
+const SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA:  count = 0x0065;
+const SSLv3x_DHE_DSS_WITH_RC4_128_SHA:            count = 0x0066;
+
+
+# --- Advanced Encryption Standard (AES) Ciphersuites
+# --- defined in RFC 3268
+
+const SSLv3x_RSA_WITH_AES_128_CBC_SHA:      count = 0x002F;
+const SSLv3x_DH_DSS_WITH_AES_128_CBC_SHA:   count = 0x0030;
+const SSLv3x_DH_RSA_WITH_AES_128_CBC_SHA:   count = 0x0031;
+const SSLv3x_DHE_DSS_WITH_AES_128_CBC_SHA:  count = 0x0032;
+const SSLv3x_DHE_RSA_WITH_AES_128_CBC_SHA:  count = 0x0033;
+const SSLv3x_DH_ANON_WITH_AES_128_CBC_SHA:  count = 0x0034;
+const SSLv3x_RSA_WITH_AES_256_CBC_SHA:      count = 0x0035;
+const SSLv3x_DH_DSS_WITH_AES_256_CBC_SHA:   count = 0x0036;
+const SSLv3x_DH_RSA_WITH_AES_256_CBC_SHA:   count = 0x0037;
+const SSLv3x_DHE_DSS_WITH_AES_256_CBC_SHA:  count = 0x0038;
+const SSLv3x_DHE_RSA_WITH_AES_256_CBC_SHA:  count = 0x0039;
+const SSLv3x_DH_ANON_WITH_AES_256_CBC_SHA:  count = 0x003A;
+
+# --- special FIPS cipher specs for SSLv3
+# --- defined in http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html
+
+const SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA:      count = 0xFEFE;
+const SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: count = 0xFEFF;
+
+
+# --- This is a table of all known cipher specs.
+# --- It can be used for detecting unknown ciphers and for
+# --- converting the cipher spec constants into a human readable format.
+
+const ssl_cipher_desc: table[count] of string =
+	{ # --- sslv20 ---
+	  [SSLv20_CK_RC4_128_EXPORT40_WITH_MD5]     = "SSLv20_CK_RC4_128_EXPORT40_WITH_MD5",
+	  [SSLv20_CK_RC4_128_WITH_MD5]              = "SSLv20_CK_RC4_128_WITH_MD5",
+	  [SSLv20_CK_RC2_128_CBC_WITH_MD5]          = "SSLv20_CK_RC2_128_CBC_WITH_MD5",
+	  [SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5] = "SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5",	    	
+	  [SSLv20_CK_IDEA_128_CBC_WITH_MD5]         = "SSLv20_CK_IDEA_128_CBC_WITH_MD5",
+	  [SSLv20_CK_DES_192_EDE3_CBC_WITH_MD5]     = "SSLv20_CK_DES_192_EDE3_CBC_WITH_MD5",
+	  [SSLv20_CK_DES_64_CBC_WITH_MD5]           = "SSLv20_CK_DES_64_CBC_WITH_MD5",
+	
+	  # --- sslv3x ---
+	  [SSLv3x_NULL_WITH_NULL_NULL]            = "SSLv3x_NULL_WITH_NULL_NULL",
+	
+	  [SSLv3x_RSA_WITH_NULL_MD5]              = "SSLv3x_RSA_WITH_NULL_MD5",
+	  [SSLv3x_RSA_WITH_NULL_SHA]              = "SSLv3x_RSA_WITH_NULL_SHA",
+	  [SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5]     = "SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5",
+	  [SSLv3x_RSA_WITH_RC4_128_MD5]           = "SSLv3x_RSA_WITH_RC4_128_MD5",
+	  [SSLv3x_RSA_WITH_RC4_128_SHA]           = "SSLv3x_RSA_WITH_RC4_128_SHA",
+	  [SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5] = "SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+	  [SSLv3x_RSA_WITH_IDEA_CBC_SHA]          = "SSLv3x_RSA_WITH_IDEA_CBC_SHA",
+	  [SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA]  = "SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_RSA_WITH_DES_CBC_SHA]           = "SSLv3x_RSA_WITH_DES_CBC_SHA",
+	  [SSLv3x_RSA_WITH_3DES_EDE_CBC_SHA]      = "SSLv3x_RSA_WITH_3DES_EDE_CBC_SHA",
+	
+	  [SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA]  = "SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_DH_DSS_WITH_DES_CBC_SHA]           = "SSLv3x_DH_DSS_WITH_DES_CBC_SHA",
+	  [SSLv3x_DH_DSS_WITH_3DES_EDE_CBC_SHA]      = "SSLv3x_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+	  [SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA]  = "SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_DH_RSA_WITH_DES_CBC_SHA]           = "SSLv3x_DH_RSA_WITH_DES_CBC_SHA",
+	  [SSLv3x_DH_RSA_WITH_3DES_EDE_CBC_SHA]      = "SSLv3x_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+	  [SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA] = "SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_DHE_DSS_WITH_DES_CBC_SHA]          = "SSLv3x_DHE_DSS_WITH_DES_CBC_SHA",
+	  [SSLv3x_DHE_DSS_WITH_3DES_EDE_CBC_SHA]     = "SSLv3x_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+	  [SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA] = "SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_DHE_RSA_WITH_DES_CBC_SHA]          = "SSLv3x_DHE_RSA_WITH_DES_CBC_SHA",
+	  [SSLv3x_DHE_RSA_WITH_3DES_EDE_CBC_SHA]     = "SSLv3x_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+	
+	  [SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5]    = "SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5",
+	  [SSLv3x_DH_ANON_WITH_RC4_128_MD5]          = "SSLv3x_DH_ANON_WITH_RC4_128_MD5",
+	  [SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA] = "SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA",
+	  [SSLv3x_DH_ANON_WITH_DES_CBC_SHA]          = "SSLv3x_DH_ANON_WITH_DES_CBC_SHA",
+	  [SSLv3x_DH_ANON_WITH_3DES_EDE_CBC_SHA]     = "SSLv3x_DH_ANON_WITH_3DES_EDE_CBC_SHA",
+	
+	  [SSLv3x_FORTEZZA_KEA_WITH_NULL_SHA]         = "SSLv3x_FORTEZZA_KEA_WITH_NULL_SHA",
+	  [SSLv3x_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA] = "SSLv3x_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA",
+	  [SSLv3x_FORTEZZA_KEA_WITH_RC4_128_SHA]      = "SSLv3x_FORTEZZA_KEA_WITH_RC4_128_SHA",
+
+	  # --- new 56 Bit export ciphers ---
+	  [SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA]     = "SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA",
+	  [SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA]      = "SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA",
+	  [SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA] = "SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",
+	  [SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA]  = "SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",
+	  [SSLv3x_DHE_DSS_WITH_RC4_128_SHA]            = "SSLv3x_DHE_DSS_WITH_RC4_128_SHA",
+
+	  # --- new AES ciphers ---
+	  [SSLv3x_RSA_WITH_AES_128_CBC_SHA]     = "SSLv3x_RSA_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_DH_DSS_WITH_AES_128_CBC_SHA]  = "SSLv3x_DH_DSS_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_DH_RSA_WITH_AES_128_CBC_SHA]  = "SSLv3x_DH_RSA_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_DHE_DSS_WITH_AES_128_CBC_SHA] = "SSLv3x_DHE_DSS_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_DHE_RSA_WITH_AES_128_CBC_SHA] = "SSLv3x_DHE_RSA_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_DH_ANON_WITH_AES_128_CBC_SHA] = "SSLv3x_DH_ANON_WITH_AES_128_CBC_SHA",
+	  [SSLv3x_RSA_WITH_AES_256_CBC_SHA]     = "SSLv3x_RSA_WITH_AES_256_CBC_SHA",
+	  [SSLv3x_DH_DSS_WITH_AES_256_CBC_SHA]  = "SSLv3x_DH_DSS_WITH_AES_256_CBC_SHA",
+	  [SSLv3x_DH_RSA_WITH_AES_256_CBC_SHA]  = "SSLv3x_DH_RSA_WITH_AES_256_CBC_SHA",
+	  [SSLv3x_DHE_DSS_WITH_AES_256_CBC_SHA] = "SSLv3x_DHE_DSS_WITH_AES_256_CBC_SHA",
+	  [SSLv3x_DHE_RSA_WITH_AES_256_CBC_SHA] = "SSLv3x_DHE_RSA_WITH_AES_256_CBC_SHA",
+	  [SSLv3x_DH_ANON_WITH_AES_256_CBC_SHA] = "SSLv3x_DH_ANON_WITH_AES_256_CBC_SHA",
+
+	  # --- special FIPS cipher specs for SSLv3
+	  [SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA]      = "SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA",
+	  [SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA] = "SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"
+	};
+
+
+# ---
+# --- the following sets are provided for convenience
+# ---
+
+# --- this set holds all EXPORT ciphers
+const ssl_cipherset_EXPORT: set[count] =
+	{ SSLv20_CK_RC4_128_EXPORT40_WITH_MD5,
+	  SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA
+	};
+	
+# --- this set holds all DES ciphers
+const ssl_cipherset_DES: set[count] =
+	{ SSLv20_CK_DES_64_CBC_WITH_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_RSA_WITH_DES_CBC_SHA,
+	  SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_DSS_WITH_DES_CBC_SHA,
+	  SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_RSA_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_DSS_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_RSA_WITH_DES_CBC_SHA,
+	  SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_ANON_WITH_DES_CBC_SHA,
+	  SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA,
+	};
+
+
+# --- this set holds all 3DES ciphers
+const ssl_cipherset_3DES: set[count] =
+	{ SSLv20_CK_DES_192_EDE3_CBC_WITH_MD5,
+	  SSLv3x_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_DH_ANON_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
+	};
+
+# --- this set holds all RC2 ciphers
+const ssl_cipherset_RC2: set[count] =
+	{ SSLv20_CK_RC2_128_CBC_WITH_MD5,
+	  SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5
+	};
+
+# --- this set holds all RC4 ciphers
+const ssl_cipherset_RC4: set[count] =
+	{ SSLv20_CK_RC4_128_WITH_MD5,
+	  SSLv20_CK_RC4_128_EXPORT40_WITH_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_RSA_WITH_RC4_128_MD5,
+	  SSLv3x_RSA_WITH_RC4_128_SHA,
+	  SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_DH_ANON_WITH_RC4_128_MD5,
+	  SSLv3x_FORTEZZA_KEA_WITH_RC4_128_SHA,
+	  SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
+	  SSLv3x_DHE_DSS_WITH_RC4_128_SHA
+	};
+	
+# --- this set holds all IDEA ciphers
+const ssl_cipherset_IDEA: set[count] =
+	{ SSLv20_CK_IDEA_128_CBC_WITH_MD5,
+	  SSLv3x_RSA_WITH_IDEA_CBC_SHA
+	};
diff -uNr bro-pub-0.8a41/policy/ssl.bro bro-pub-0.841-ssl/policy/ssl.bro
--- bro-pub-0.8a41/policy/ssl.bro	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/policy/ssl.bro	Wed Oct 15 05:19:54 2003
@@ -0,0 +1,490 @@
+#
+# BroSkript interface for the SSL/TLS support 
+# Copyright (c) by Michael Kuhn and Benedikt Ostermaier
+#
+
+# we need the pre-defined SSL cipher specs and the SSL alerts description
+@load ssl-ciphers
+@load ssl-alerts
+
+# definitions for logging of (SSL) security weaknesses
+@load weak
+
+# constants for the different SSL versions
+const SSL_VERSION_20: count = 0x0002;
+const SSL_VERSION_30: count = 0x0300;
+const SSL_VERSION_31: count = 0x0301;
+
+# constants for the handshake types
+const SSL_CLIENT_HELLO: count = 0;
+const SSL_SERVER_HELLO: count = 1;
+
+# If true, bro stores the client and server cipher specs
+# and performs additional tests.
+# This costs an extra amount of memory (normaly only for a short time)
+# but enables detecting of non-intersecting cipher sets, for example.
+const ssl_compare_cipherspecs = F &redef;
+
+# wether to analyze certificates seen in SSL connections
+const ssl_analyze_certificates = T &redef;
+
+# if we analyze SSL certificates, we can choose to store them
+const ssl_store_certificates = F &redef;
+
+# this is the path where we dump the certificates into
+# if it's empty, we use the current directory
+# the path must not end with a slash!
+const ssl_store_cert_path : string = "../certs" &redef;
+
+# if we analyze SSL certificates, we can choose to verify them
+const ssl_verify_certificates = F &redef;
+
+# this is the path where OpenSSL looks for the trusted certificates
+# if it's empty, the default path will be used
+const x509_trusted_cert_path : string = "" &redef;
+
+# this is the max. size in bytes for a SSL cipherspec
+# if we see a packet that has bigger cipherspecs,
+# we warn and won't do a comparisons of cipherspecs
+const ssl_max_cipherspec_size = 66 &redef;
+
+#whether to store key-material exchanged in the handshaking phase
+const ssl_store_key_material = F &redef;
+
+# all output is logged into a SSL log file
+global ssl_log = open_log_file("ssl") &redef;
+
+# --- well-known ports for SSL ---------
+redef capture_filters += { ["https"] = "port 443",
+						   ["nntps"] = "port 563",
+						   ["imap4-ssl"] = "port 585",
+						   ["sshell"] = "port 614",
+						   ["ldaps"] = "port 636",
+						   ["ftps-data"] = "port 989",
+						   ["ftps"] = "port 990",
+						   ["telnets"] = "port 992",
+						   ["imaps"] = "port 993",
+						   ["ircs"] = "port 994",
+						   ["pop3s"] = "port 995" };
+						   
+# --- SSL settings ---------------------
+redef ssl_compare_cipherspecs  = T;
+redef ssl_analyze_certificates = T;
+redef ssl_store_certificates   = T;
+redef ssl_verify_certificates  = T;
+redef ssl_store_key_material   = T;
+#redef x509_trusted_cert_path  = "/home/ostermai/trustedcerts";
+#redef x509_trusted_cert_path = "/usr/share/ssl/certs";
+
+# --- Weak Cipher Demo -------------
+
+const myWeakCiphers: set[count] = 
+	{ SSLv20_CK_RC4_128_EXPORT40_WITH_MD5,
+	  SSLv20_CK_RC2_128_CBC_EXPORT40_WITH_MD5,
+	  SSLv20_CK_DES_64_CBC_WITH_MD5,
+	  
+	  SSLv3x_NULL_WITH_NULL_NULL,
+	  SSLv3x_RSA_WITH_NULL_MD5,
+	  SSLv3x_RSA_WITH_NULL_SHA,
+	  SSLv3x_RSA_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
+	  SSLv3x_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_RSA_WITH_DES_CBC_SHA,
+	  
+	  SSLv3x_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_DSS_WITH_DES_CBC_SHA,
+	  SSLv3x_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_RSA_WITH_DES_CBC_SHA,	  
+	  SSLv3x_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_DSS_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DHE_RSA_WITH_DES_CBC_SHA,
+	  
+	  SSLv3x_DH_ANON_EXPORT_WITH_RC4_40_MD5,
+	  SSLv3x_DH_ANON_WITH_RC4_128_MD5,
+	  SSLv3x_DH_ANON_EXPORT_WITH_DES40_CBC_SHA,
+	  SSLv3x_DH_ANON_WITH_DES_CBC_SHA,
+	  SSLv3x_DH_ANON_WITH_3DES_EDE_CBC_SHA,
+	  SSLv3x_FORTEZZA_KEA_WITH_NULL_SHA,
+
+	  SSLv3x_RSA_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_RSA_EXPORT1024_WITH_RC4_56_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA,
+	  SSLv3x_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA,
+
+	  SSLv3x_RSA_FIPS_WITH_DES_CBC_SHA
+	};
+
+# --- Globals ----------------------
+global SSL_cipherCount: table[count] of count &default = 0;
+
+# Type for SSL connection tracking
+type ssl_connection_info: record {
+	id: count;						# the log identifier number
+	connection_id: conn_id;			# IP connection information
+	version: count;					# version associated with connection
+	client_certificate: x509;       # information from client certificate
+	server_certificate: x509;       # information from server certificate
+	cipherSuite: count;				# cipher suite client and server agreed upon
+	handshake_fin: bool;			# whether the handshaking process finished
+	cached_session: bool;			# true if this connection uses a cached session
+};
+
+# Table for connection tracking
+global ssl_connections: table[conn_id] of ssl_connection_info;
+
+# global counter for connection IDs
+global ssl_connection_id = 0;
+
+
+# --- SSL helper functions ---------
+
+function ssl_get_ciphername( cipherSuite: count ) : string
+	{
+	local cipherName = "UNKNOWN";
+	if ( cipherSuite in ssl_cipher_desc )
+		{
+		cipherName = ssl_cipher_desc[cipherSuite];
+		}
+	
+	return cipherName;
+	}
+	
+function ssl_get_alert_description( alert: count ) : string
+	{
+	local alertDescr = "UNKNOWN";
+	if ( alert in ssl_alert_desc )
+		{
+		alertDescr = ssl_alert_desc[alert];
+		}
+	return alertDescr;
+	}
+	
+function ssl_get_alert_level_description( level: count ) : string
+	{
+	local levelDescr = "UNKNOWN";
+	if ( level in ssl_alert_level ) 
+		{
+		levelDescr = ssl_alert_level[level];
+		}
+	return levelDescr;
+	}
+
+function ssl_get_versionstring( version: count ) : string
+	{
+	local versionString = "?.?";
+	
+	if ( version == SSL_VERSION_20 )
+		versionString = "2.0";
+	else if ( version == SSL_VERSION_30 )
+		versionString = "3.0";
+		else if ( version == SSL_VERSION_31 )
+			versionString = "3.1";
+			
+	return versionString;
+	}
+
+
+function ssl_con2str( c: connection ) : string
+	{
+	local connStr = fmt("%s : %s, %s : %s", 
+						c$id$orig_h,
+						c$id$orig_p,
+						c$id$resp_h,
+						c$id$resp_p);
+					 
+	return connStr;
+	}
+	
+function new_ssl_connection(c: connection): any
+	{
+	local conn = c$id;
+	local new_id = ++ssl_connection_id;
+	
+	local info: ssl_connection_info;
+	info$id = new_id;
+	info$client_certificate = [$issuer = "", $subject= ""];
+	info$server_certificate = [$issuer = "", $subject= ""];
+	info$cipherSuite = 0;
+	info$connection_id = conn;
+	info$handshake_fin = F;
+	info$cached_session = F;
+
+	ssl_connections[conn] = info;
+	c$addl = fmt("#%d", new_id);
+	print ssl_log, fmt("%.6f #%d %s start", network_time(), new_id, 
+		id_string(conn));
+	}
+
+function ssl_message(id: conn_id, msg: string): bool
+	{
+	print ssl_log, fmt("%.6f #%d %s",
+		network_time(), ssl_connections[id]$id, msg);
+	}
+
+# --- SSL events -------------------
+
+event ssl_certificate_seen( c: connection, isServer: int )
+	{
+	# this is called whenever there's an certificate to analyze
+	# we could do something here, like...
+	
+	# if (c$id$orig_h in hostsToIgnore) 
+	# 	{ 
+	# 	ssl_store_certificates  = F;
+	# 	ssl_verify_certificates = F; 
+	# 	}
+	# else
+	# 	{ 
+	# 	ssl_store_certificates  = T;
+	# 	ssl_verify_certificates = T; 
+	# 	}
+	}
+
+event ssl_certificate( c: connection, cert: x509, isServer: bool)
+	{
+	local id = c$id;
+	local certSource ="";
+
+	if ( id !in ssl_connections)
+		{
+		print ssl_log, ("Connection not found in connection table!");
+		return;
+        }
+ 
+	local conn = ssl_connections[id];
+	if ( isServer )
+		{
+		certSource = "Server";
+		conn$server_certificate = cert;
+		}
+	else
+		{
+		certSource = "Client";
+        conn$client_certificate = cert;
+		}
+
+	ssl_message(id, fmt("Certificate seen from: %s, Issuer: %s, Subject: %s",
+						certSource,
+						cert$issuer,
+						cert$subject)
+			   );
+	}
+
+event ssl_conn_attempt(c: connection, version: count, cipherSuites: cipher_suites_list)
+	{
+	local id = c$id;
+
+	if ( id !in ssl_connections)
+		{
+		new_ssl_connection(c);
+        }
+ 
+	local conn = ssl_connections[id];
+	conn$handshake_fin = F;
+	
+	local versionString = ssl_get_versionstring( version );
+	
+	local msg = fmt("Connection attempt, Version: %s, cipher suite(s) seen:", versionString);
+	
+	for ( i in cipherSuites )
+		{
+		# display a list of the cipher suites
+		msg = fmt("%s %s (0x%X),",
+	  			  msg,
+				  ssl_get_ciphername(cipherSuites[i]),
+				  cipherSuites[i] );
+				  
+		# demo: report clients who support weak ciphers
+		if ( cipherSuites[i] in myWeakCiphers )
+			{
+			event conn_weak(fmt("SSL: Client supports WEAK CIPHER: %s (0x%X)", 
+								 ssl_get_ciphername(cipherSuites[i]), 
+								 cipherSuites[i]), 
+							  c );
+			}
+		# demo: report unknown ciphers
+		if ( !(cipherSuites[i] in ssl_cipher_desc) )
+			{
+			event conn_weak(fmt("SSL: Unknown CIPHER-SPEC: %s (0x%X)", 
+								 ssl_get_ciphername(cipherSuites[i]), 
+								 cipherSuites[i]), 
+							  c );
+			}
+		}
+				
+	ssl_message(id, msg);
+	}
+
+event ssl_conn_server_reply(c: connection, version: count, cipherSuites: cipher_suites_list)
+	{
+	local id = c$id;
+
+	if ( id !in ssl_connections)
+		{
+		print ssl_log, ("Connection not found in connection table!");
+		return;
+        }
+
+	local conn = ssl_connections[id];
+	local versionString = ssl_get_versionstring( version );
+	conn$version = version;
+	
+	local msg = fmt("Server reply, Version: %s, cipher suite(s) seen:", versionString);
+	
+	for ( i in cipherSuites )
+		{
+		# display a list of the cipher suites
+		msg = fmt("%s %s (0x%X),",
+	  			  msg,
+				  ssl_get_ciphername(cipherSuites[i]),
+				  cipherSuites[i] );
+				  
+		# demo: report servers who support weak ciphers
+		if ( version == SSL_VERSION_20 &&
+			 cipherSuites[i] in myWeakCiphers )
+			{
+			event conn_weak(fmt("SSL: FATAL: SSLv2 Server supports WEAK CIPHER: %s (0x%X)", 
+								 ssl_get_ciphername(cipherSuites[i]), 
+								 cipherSuites[i]), 
+							  c );
+			}
+		# demo: report unknown ciphers
+		if ( !(cipherSuites[i] in ssl_cipher_desc) )
+			{
+			event conn_weak(fmt("SSL: Unknown CIPHER-SPEC: %s (0x%X)", 
+								 ssl_get_ciphername(cipherSuites[i]), 
+								 cipherSuites[i]), 
+							  c );
+			}
+		}
+	
+	ssl_message(id, msg);
+	}
+
+event ssl_conn_established(c: connection, version: count, cipher_suite: count)
+	{
+	local id = c$id;
+
+	if ( id !in ssl_connections)
+		{
+		print ssl_log, ("Connection not found in connection table!");
+		return;
+        }
+	local conn = ssl_connections[id];   
+	conn$handshake_fin = T;
+	local versionString = ssl_get_versionstring( version );
+	conn$cipherSuite = cipher_suite;
+
+	local actionString = "";
+	if ( version == SSL_VERSION_20 )
+		{
+			actionString = "Handshake switches to encryption (stopping analysis)";
+		}
+		else
+		{
+			actionString = "Handshake finished";
+		}
+	
+	if ( version == SSL_VERSION_20 && conn$cached_session )
+		{
+		# special workaround for cached SSLv2 sessions,
+		# since we don't store the used cipher suite (yet)
+		ssl_message(id, fmt("%s, Version: %s, cipher suite: Can't say, it's cached!",
+							actionString, versionString));
+		}
+	else
+		{
+		ssl_message(id, fmt("%s, Version: %s, cipher suite: %s (0x%X)",
+							actionString,
+							versionString,
+							ssl_get_ciphername(cipher_suite),
+							cipher_suite));
+	
+		if ( cipher_suite in myWeakCiphers )
+			{
+			event conn_weak(fmt( "SSL: Using WEAK CIPHER for communication: %s (0x%X)",
+							      ssl_get_ciphername(cipher_suite),
+							      cipher_suite),
+							 c );
+			}
+		SSL_cipherCount[cipher_suite] = SSL_cipherCount[cipher_suite] + 1;
+		}
+	}
+
+event ssl_conn_reused(c: connection, session_id: string)
+	{
+	local id = c$id;
+
+	if ( id !in ssl_connections)
+		{
+		print ssl_log, ("Connection not found in connection table!");
+		return;
+        }
+
+	local conn = ssl_connections[id];
+	conn$cached_session = T;
+	
+	ssl_message(id, fmt("Reusing former SSL session, Session ID: %s",
+						session_id));
+	}
+	
+event ssl_conn_alert(c: connection, version: count, level: count, description: count)
+	{
+	local id = c$id;
+
+	if ( id !in ssl_connections)
+		{
+		print ssl_log, ("Connection not found in connection table!");
+		return;
+        }
+    
+	local msg = "";
+	if ( level == SSLv3x_ALERT_LEVEL_FATAL )
+		{
+		msg = "FATAL SSL alert";
+		}
+	else 
+		{
+		#print ssl_log, "SSL Alert for connection:";
+		msg = "SSL Alert";
+		}
+	ssl_message(id, fmt("%s Version: %s, Level: %s, Desciption: %s",
+					msg,
+					ssl_get_versionstring(version),
+					ssl_get_alert_level_description(level),
+					ssl_get_alert_description(description))
+				   );
+	}
+
+event connection_state_remove(c: connection)
+	{
+	local id = c$id;
+	
+	if ( id in ssl_connections )
+		{
+		local conn = ssl_connections[id];
+		if ( !conn$handshake_fin )
+			{
+			#event conn_weird(fmt("SSL connection: #%d finishing while handshake",
+			#					conn$id), c
+			#				);
+			ssl_message(id, "finishing while handshake");
+			}
+		ssl_message(id, "finish");
+		delete ssl_connections[id];
+		}
+	}
+
+event bro_done()
+	{
+	print ssl_log, "---";
+	print ssl_log, "Used cipher-suites statistics: ";
+	for ( i in SSL_cipherCount )
+		{
+		print ssl_log, fmt("%s (0x%X): %d",
+							ssl_get_ciphername( i ),
+							i,
+							SSL_cipherCount[i]);
+		}
+	}
diff -uNr bro-pub-0.8a41/policy/weak.bro bro-pub-0.841-ssl/policy/weak.bro
--- bro-pub-0.8a41/policy/weak.bro	Thu Jan  1 01:00:00 1970
+++ bro-pub-0.841-ssl/policy/weak.bro	Wed Oct 15 05:20:01 2003
@@ -0,0 +1,24 @@
+# weak.bro
+@load alert
+@load conn
+
+@load alert
+@load port-name
+	
+global weak_file = open_log_file("weak") &redef;
+
+redef enum Alert += {
+	SecurityWeakness
+};
+
+function weak_id_string(id: conn_id): string
+	{
+	return fmt("%s > %s",
+		endpoint_id(id$orig_h, id$orig_p),
+		endpoint_id(id$resp_h, id$resp_p));
+	}
+
+event conn_weak(name: string, c: connection)
+	{
+	print weak_file, fmt("%.6f ?? %s: %s", network_time(), weak_id_string(c$id), name);
+	}
diff -uNr bro-pub-0.8a41/scan.l bro-pub-0.841-ssl/scan.l
--- bro-pub-0.8a41/scan.l	Fri Oct 10 07:03:33 2003
+++ bro-pub-0.841-ssl/scan.l	Wed Oct 15 05:17:52 2003
@@ -279,6 +279,8 @@
 {FLOAT}{OWS}msec(s?)	RET_CONST(new IntervalVal(atof(yytext),Milliseconds))
 {FLOAT}{OWS}usec(s?)	RET_CONST(new IntervalVal(atof(yytext),Microseconds))
 
+"0x"{HEX}+ RET_CONST(new Val (unsigned(strtol(yytext, 0, 16)), TYPE_COUNT))
+
 \"([^\\\n\"]|{ESCSEQ})*\"	{
 	const char* text = yytext;
 	int len = strlen(text) + 1;