Blob Blame History Raw
Fix DTLS implementation to be RFC 4347 compliant. This makes the new client
incompatible with the old openssl DTLS servers. However the older openssl client
will still be able to connect to the new server code. This change also
resolves buffer overrun when out-of-order fragments are received during
the handshake.
CVE-2007-4995
diff -up openssl-0.9.8b/ssl/dtls1.h.dtls-fixes openssl-0.9.8b/ssl/dtls1.h
--- openssl-0.9.8b/ssl/dtls1.h.dtls-fixes	2007-10-08 17:55:22.000000000 +0200
+++ openssl-0.9.8b/ssl/dtls1.h	2007-10-08 17:55:22.000000000 +0200
@@ -67,9 +67,8 @@
 extern "C" {
 #endif
 
-#define DTLS1_VERSION			0x0100
-#define DTLS1_VERSION_MAJOR		0x01
-#define DTLS1_VERSION_MINOR		0x00
+#define DTLS1_VERSION			0xFEFF
+#define DTLS1_BAD_VER			0x0100
 
 #define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
 
@@ -83,7 +82,7 @@ extern "C" {
 #define DTLS1_HM_BAD_FRAGMENT                   -2
 #define DTLS1_HM_FRAGMENT_RETRY                 -3
 
-#define DTLS1_CCS_HEADER_LENGTH                  3
+#define DTLS1_CCS_HEADER_LENGTH                  1
 
 #define DTLS1_AL_HEADER_LENGTH                   7
 
diff -up openssl-0.9.8b/ssl/d1_lib.c.dtls-fixes openssl-0.9.8b/ssl/d1_lib.c
--- openssl-0.9.8b/ssl/d1_lib.c.dtls-fixes	2005-08-08 21:26:35.000000000 +0200
+++ openssl-0.9.8b/ssl/d1_lib.c	2007-10-08 17:55:22.000000000 +0200
@@ -188,3 +188,23 @@ void dtls1_clear(SSL *s)
 	ssl3_clear(s);
 	s->version=DTLS1_VERSION;
 	}
+
+/*
+ * As it's impossible to use stream ciphers in "datagram" mode, this
+ * simple filter is designed to disengage them in DTLS. Unfortunately
+ * there is no universal way to identify stream SSL_CIPHER, so we have
+ * to explicitly list their SSL_* codes. Currently RC4 is the only one
+ * available, but if new ones emerge, they will have to be added...
+ */
+SSL_CIPHER *dtls1_get_cipher(unsigned int u)
+	{
+	SSL_CIPHER *ciph = ssl3_get_cipher(u);
+
+	if (ciph != NULL)
+		{
+		if ((ciph->algorithms&SSL_ENC_MASK) == SSL_RC4)
+			return NULL;
+		}
+
+	return ciph;
+	}
diff -up openssl-0.9.8b/ssl/d1_srvr.c.dtls-fixes openssl-0.9.8b/ssl/d1_srvr.c
--- openssl-0.9.8b/ssl/d1_srvr.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
+++ openssl-0.9.8b/ssl/d1_srvr.c	2007-10-10 14:21:49.000000000 +0200
@@ -285,6 +285,10 @@ int dtls1_accept(SSL *s)
 			s->d1->send_cookie = 0;
 			s->state=SSL3_ST_SW_FLUSH;
 			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
+
+			/* HelloVerifyRequests resets Finished MAC */
+			if (s->client_version != DTLS1_BAD_VER)
+				ssl3_init_finished_mac(s);
 			break;
 			
 		case SSL3_ST_SW_SRVR_HELLO_A:
@@ -620,10 +624,13 @@ int dtls1_send_hello_verify_request(SSL 
 		buf = (unsigned char *)s->init_buf->data;
 
 		msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
-		*(p++) = s->version >> 8;
-		*(p++) = s->version & 0xFF;
+		if (s->client_version == DTLS1_BAD_VER)
+			*(p++) = DTLS1_BAD_VER>>8,
+			*(p++) = DTLS1_BAD_VER&0xff;
+		else
+			*(p++) = s->version >> 8,
+			*(p++) = s->version & 0xFF;
 
-		*(p++) = (unsigned char) s->d1->cookie_len;
         if ( s->ctx->app_gen_cookie_cb != NULL &&
             s->ctx->app_gen_cookie_cb(s, s->d1->cookie, 
                 &(s->d1->cookie_len)) == 0)
@@ -634,6 +641,7 @@ int dtls1_send_hello_verify_request(SSL 
         /* else the cookie is assumed to have 
          * been initialized by the application */
 
+		*(p++) = (unsigned char) s->d1->cookie_len;
 		memcpy(p, s->d1->cookie, s->d1->cookie_len);
 		p += s->d1->cookie_len;
 		msg_len = p - msg;
@@ -672,8 +680,12 @@ int dtls1_send_server_hello(SSL *s)
 		/* Do the message type and length last */
 		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
 
-		*(p++)=s->version>>8;
-		*(p++)=s->version&0xff;
+		if (s->client_version == DTLS1_BAD_VER)
+			*(p++)=DTLS1_BAD_VER>>8,
+			*(p++)=DTLS1_BAD_VER&0xff;
+		else
+			*(p++)=s->version>>8,
+			*(p++)=s->version&0xff;
 
 		/* Random stuff */
 		memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
@@ -1009,6 +1021,7 @@ int dtls1_send_certificate_request(SSL *
 	STACK_OF(X509_NAME) *sk=NULL;
 	X509_NAME *name;
 	BUF_MEM *buf;
+	unsigned int msg_len;
 
 	if (s->state == SSL3_ST_SW_CERT_REQ_A)
 		{
@@ -1086,6 +1099,10 @@ int dtls1_send_certificate_request(SSL *
 #endif
 
 		/* XDTLS:  set message header ? */
+		msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
+		dtls1_set_message_header(s, (void *)s->init_buf->data,
+			SSL3_MT_CERTIFICATE_REQUEST, msg_len, 0, msg_len);
+
 		/* buffer the message to handle re-xmits */
 		dtls1_buffer_message(s, 0);
 
diff -up openssl-0.9.8b/ssl/s3_srvr.c.dtls-fixes openssl-0.9.8b/ssl/s3_srvr.c
--- openssl-0.9.8b/ssl/s3_srvr.c.dtls-fixes	2007-10-08 17:55:22.000000000 +0200
+++ openssl-0.9.8b/ssl/s3_srvr.c	2007-10-08 17:55:22.000000000 +0200
@@ -679,9 +679,9 @@ int ssl3_get_client_hello(SSL *s)
 	 */
 	if (s->state == SSL3_ST_SR_CLNT_HELLO_A)
 		{
-		s->first_packet=1;
 		s->state=SSL3_ST_SR_CLNT_HELLO_B;
 		}
+	s->first_packet=1;
 	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_CLNT_HELLO_B,
 		SSL3_ST_SR_CLNT_HELLO_C,
@@ -690,6 +690,7 @@ int ssl3_get_client_hello(SSL *s)
 		&ok);
 
 	if (!ok) return((int)n);
+	s->first_packet=0;
 	d=p=(unsigned char *)s->init_msg;
 
 	/* use version from inside client hello, not from record header
@@ -697,7 +698,8 @@ int ssl3_get_client_hello(SSL *s)
 	s->client_version=(((int)p[0])<<8)|(int)p[1];
 	p+=2;
 
-	if (s->client_version < s->version)
+	if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
+	    (s->version != DTLS1_VERSION && s->client_version < s->version))
 		{
 		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
 		if ((s->client_version>>8) == SSL3_VERSION_MAJOR) 
@@ -748,7 +750,7 @@ int ssl3_get_client_hello(SSL *s)
 
 	p+=j;
 
-	if (SSL_version(s) == DTLS1_VERSION)
+	if (s->version == DTLS1_VERSION)
 		{
 		/* cookie stuff */
 		cookie_len = *(p++);
@@ -1709,8 +1711,9 @@ int ssl3_get_client_key_exchange(SSL *s)
 			rsa=pkey->pkey.rsa;
 			}
 
-		/* TLS */
-		if (s->version > SSL3_VERSION)
+		/* TLS and [incidentally] DTLS, including pre-0.9.8f */
+		if (s->version > SSL3_VERSION &&
+		    s->client_version != DTLS1_BAD_VER)
 			{
 			n2s(p,i);
 			if (n != i+2)
diff -up openssl-0.9.8b/ssl/ssl_locl.h.dtls-fixes openssl-0.9.8b/ssl/ssl_locl.h
--- openssl-0.9.8b/ssl/ssl_locl.h.dtls-fixes	2007-10-08 17:55:22.000000000 +0200
+++ openssl-0.9.8b/ssl/ssl_locl.h	2007-10-08 17:55:22.000000000 +0200
@@ -677,7 +677,7 @@ SSL_METHOD *func_name(void)  \
 		ssl3_put_cipher_by_char, \
 		ssl3_pending, \
 		ssl3_num_ciphers, \
-		ssl3_get_cipher, \
+		dtls1_get_cipher, \
 		s_get_meth, \
 		dtls1_default_timeout, \
 		&DTLSv1_enc_data, \
@@ -842,6 +842,8 @@ void dtls1_get_message_header(unsigned c
 void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
 void dtls1_reset_seq_numbers(SSL *s, int rw);
 long dtls1_default_timeout(void);
+SSL_CIPHER *dtls1_get_cipher(unsigned int u);
+
 
 
 /* some client-only functions */
diff -up openssl-0.9.8b/ssl/t1_enc.c.dtls-fixes openssl-0.9.8b/ssl/t1_enc.c
--- openssl-0.9.8b/ssl/t1_enc.c.dtls-fixes	2007-10-08 17:55:22.000000000 +0200
+++ openssl-0.9.8b/ssl/t1_enc.c	2007-10-10 14:24:52.000000000 +0200
@@ -737,15 +737,35 @@ int tls1_mac(SSL *ssl, unsigned char *md
 	md_size=EVP_MD_size(hash);
 
 	buf[0]=rec->type;
-	buf[1]=TLS1_VERSION_MAJOR;
-	buf[2]=TLS1_VERSION_MINOR;
+	if (ssl->version == DTLS1_VERSION && ssl->client_version == DTLS1_BAD_VER)
+		{
+		buf[1]=TLS1_VERSION_MAJOR;
+		buf[2]=TLS1_VERSION_MINOR;
+		}
+	else	{
+		buf[1]=(unsigned char)(ssl->version>>8);
+		buf[2]=(unsigned char)(ssl->version);
+		}
+
 	buf[3]=rec->length>>8;
 	buf[4]=rec->length&0xff;
 
 	/* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
 	HMAC_CTX_init(&hmac);
 	HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL);
-	HMAC_Update(&hmac,seq,8);
+
+	if (ssl->version == DTLS1_VERSION && ssl->client_version != DTLS1_BAD_VER)
+		{
+		unsigned char dtlsseq[8],*p=dtlsseq;
+
+		s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
+		memcpy (p,&seq[2],6);
+
+		HMAC_Update(&hmac,dtlsseq,8);
+		}
+	else
+		HMAC_Update(&hmac,seq,8);
+
 	HMAC_Update(&hmac,buf,5);
 	HMAC_Update(&hmac,rec->input,rec->length);
 	HMAC_Final(&hmac,md,&md_size);
@@ -762,8 +782,8 @@ printf("rec=");
 {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
 #endif
 
-    if ( SSL_version(ssl) != DTLS1_VERSION)
-	    {
+	if ( SSL_version(ssl) != DTLS1_VERSION)
+		{
 		for (i=7; i>=0; i--)
 			{
 			++seq[i];
diff -up openssl-0.9.8b/ssl/ssl.h.dtls-fixes openssl-0.9.8b/ssl/ssl.h
--- openssl-0.9.8b/ssl/ssl.h.dtls-fixes	2007-10-08 17:55:22.000000000 +0200
+++ openssl-0.9.8b/ssl/ssl.h	2007-10-08 17:55:22.000000000 +0200
@@ -315,7 +315,7 @@ extern "C" {
 /* The following cipher list is used by default.
  * It also is substituted when an application-defined cipher list string
  * starts with 'DEFAULT'. */
-#define SSL_DEFAULT_CIPHER_LIST	"ALL:!ADH:+RC4:@STRENGTH" /* low priority for RC4 */
+#define SSL_DEFAULT_CIPHER_LIST	"AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" /* low priority for RC4 */
 
 /* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
 #define SSL_SENT_SHUTDOWN	1
@@ -1551,6 +1551,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT		 253
 #define SSL_F_DTLS1_GET_RECORD				 254
 #define SSL_F_DTLS1_OUTPUT_CERT_CHAIN			 255
+#define SSL_F_DTLS1_PREPROCESS_FRAGMENT			 277
 #define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE		 256
 #define SSL_F_DTLS1_PROCESS_RECORD			 257
 #define SSL_F_DTLS1_READ_BYTES				 258
diff -up openssl-0.9.8b/ssl/d1_pkt.c.dtls-fixes openssl-0.9.8b/ssl/d1_pkt.c
--- openssl-0.9.8b/ssl/d1_pkt.c.dtls-fixes	2006-02-08 20:16:32.000000000 +0100
+++ openssl-0.9.8b/ssl/d1_pkt.c	2007-10-08 17:55:22.000000000 +0200
@@ -120,6 +120,7 @@
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
 #include <openssl/pqueue.h>
+#include <openssl/rand.h>
 
 static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
 	int len, int peek);
@@ -486,9 +487,9 @@ int dtls1_get_record(SSL *s)
 	SSL3_RECORD *rr;
 	SSL_SESSION *sess;
 	unsigned char *p;
-	short version;
+	unsigned short version;
 	DTLS1_BITMAP *bitmap;
-    unsigned int is_next_epoch;
+	unsigned int is_next_epoch;
 
 	rr= &(s->s3->rrec);
 	sess=s->session;
@@ -524,7 +525,7 @@ again:
 		ssl_minor= *(p++);
 		version=(ssl_major<<8)|ssl_minor;
 
-        /* sequence number is 64 bits, with top 2 bytes = epoch */ 
+		/* sequence number is 64 bits, with top 2 bytes = epoch */ 
 		n2s(p,rr->epoch);
 
 		memcpy(&(s->s3->read_sequence[2]), p, 6);
@@ -533,13 +534,9 @@ again:
 		n2s(p,rr->length);
 
 		/* Lets check version */
-		if (s->first_packet)
+		if (!s->first_packet)
 			{
-			s->first_packet=0;
-			}
-		else
-			{
-			if (version != s->version)
+			if (version != s->version && version != DTLS1_BAD_VER)
 				{
 				SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
 				/* Send back error using their
@@ -550,7 +547,8 @@ again:
 				}
 			}
 
-		if ((version & 0xff00) != (DTLS1_VERSION & 0xff00))
+		if ((version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
+		    (version & 0xff00) != (DTLS1_BAD_VER & 0xff00))
 			{
 			SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
 			goto err;
@@ -796,8 +794,14 @@ start:
 			dest = s->d1->alert_fragment;
 			dest_len = &s->d1->alert_fragment_len;
 			}
-		else	/* else it's a CCS message */
-			OPENSSL_assert(rr->type == SSL3_RT_CHANGE_CIPHER_SPEC);
+                /* else it's a CCS message, or it's wrong */
+                else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
+                        {
+                          /* Not certain if this is the right error handling */
+                          al=SSL_AD_UNEXPECTED_MESSAGE;
+                          SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+                          goto f_err;
+                        }
 
 
 		if (dest_maxlen > 0)
@@ -971,47 +975,40 @@ start:
 		}
 
 	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
-        {
-        struct ccs_header_st ccs_hdr;
+		{
+		struct ccs_header_st ccs_hdr;
 
 		dtls1_get_ccs_header(rr->data, &ccs_hdr);
 
-		if ( ccs_hdr.seq == s->d1->handshake_read_seq)
+		/* 'Change Cipher Spec' is just a single byte, so we know
+		 * exactly what the record payload has to look like */
+		/* XDTLS: check that epoch is consistent */
+		if (	(s->client_version == DTLS1_BAD_VER && rr->length != 3) ||
+			(s->client_version != DTLS1_BAD_VER && rr->length != DTLS1_CCS_HEADER_LENGTH) || 
+			(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
 			{
-			/* 'Change Cipher Spec' is just a single byte, so we know
-			 * exactly what the record payload has to look like */
-			/* XDTLS: check that epoch is consistent */
-			if (	(rr->length != DTLS1_CCS_HEADER_LENGTH) || 
-				(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
-				{
-				i=SSL_AD_ILLEGAL_PARAMETER;
-				SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
-				goto err;
-				}
-			
-			rr->length=0;
-			
-			if (s->msg_callback)
-				s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, 
-					rr->data, 1, s, s->msg_callback_arg);
-			
-			s->s3->change_cipher_spec=1;
-			if (!ssl3_do_change_cipher_spec(s))
-				goto err;
-			
-			/* do this whenever CCS is processed */
-			dtls1_reset_seq_numbers(s, SSL3_CC_READ);
-			
-			/* handshake read seq is reset upon handshake completion */
-			s->d1->handshake_read_seq++;
-			
-			goto start;
-			}
-		else
-			{
-			rr->length = 0;
-			goto start;
+			i=SSL_AD_ILLEGAL_PARAMETER;
+			SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
+			goto err;
 			}
+
+		rr->length=0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, 
+				rr->data, 1, s, s->msg_callback_arg);
+
+		s->s3->change_cipher_spec=1;
+		if (!ssl3_do_change_cipher_spec(s))
+			goto err;
+
+		/* do this whenever CCS is processed */
+		dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+		/* handshake read seq is reset upon handshake completion */
+		s->d1->handshake_read_seq++;
+
+		goto start;
 		}
 
 	/* Unexpected handshake message (Client Hello, or protocol violation) */
@@ -1339,8 +1336,12 @@ int do_dtls1_write(SSL *s, int type, con
 	*(p++)=type&0xff;
 	wr->type=type;
 
-	*(p++)=(s->version>>8);
-	*(p++)=s->version&0xff;
+	if (s->client_version == DTLS1_BAD_VER)
+		*(p++) = DTLS1_BAD_VER>>8,
+		*(p++) = DTLS1_BAD_VER&0xff;
+	else
+		*(p++)=(s->version>>8),
+		*(p++)=s->version&0xff;
 
 	/* field where we are to write out packet epoch, seq num and len */
 	pseq=p; 
@@ -1395,8 +1396,14 @@ int do_dtls1_write(SSL *s, int type, con
 
 
 	/* ssl3_enc can only have an error on read */
-	wr->length += bs;  /* bs != 0 in case of CBC.  The enc fn provides
-						* the randomness */ 
+	if (bs)	/* bs != 0 in case of CBC */
+		{
+		RAND_pseudo_bytes(p,bs);
+		/* master IV and last CBC residue stand for
+		 * the rest of randomness */
+		wr->length += bs;
+		}
+
 	s->method->ssl3_enc->enc(s,1);
 
 	/* record length after mac and block padding */
diff -up openssl-0.9.8b/ssl/ssl_err.c.dtls-fixes openssl-0.9.8b/ssl/ssl_err.c
--- openssl-0.9.8b/ssl/ssl_err.c.dtls-fixes	2006-01-08 22:52:46.000000000 +0100
+++ openssl-0.9.8b/ssl/ssl_err.c	2007-10-08 17:55:22.000000000 +0200
@@ -87,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT),	"DTLS1_GET_MESSAGE_FRAGMENT"},
 {ERR_FUNC(SSL_F_DTLS1_GET_RECORD),	"DTLS1_GET_RECORD"},
 {ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN),	"DTLS1_OUTPUT_CERT_CHAIN"},
+{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT),	"DTLS1_PREPROCESS_FRAGMENT"},
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),	"DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD),	"DTLS1_PROCESS_RECORD"},
 {ERR_FUNC(SSL_F_DTLS1_READ_BYTES),	"DTLS1_READ_BYTES"},
diff -up openssl-0.9.8b/ssl/s3_pkt.c.dtls-fixes openssl-0.9.8b/ssl/s3_pkt.c
--- openssl-0.9.8b/ssl/s3_pkt.c.dtls-fixes	2005-10-01 01:38:20.000000000 +0200
+++ openssl-0.9.8b/ssl/s3_pkt.c	2007-10-08 17:55:22.000000000 +0200
@@ -277,11 +277,7 @@ again:
 		n2s(p,rr->length);
 
 		/* Lets check version */
-		if (s->first_packet)
-			{
-			s->first_packet=0;
-			}
-		else
+		if (!s->first_packet)
 			{
 			if (version != s->version)
 				{
diff -up openssl-0.9.8b/ssl/s23_srvr.c.dtls-fixes openssl-0.9.8b/ssl/s23_srvr.c
--- openssl-0.9.8b/ssl/s23_srvr.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
+++ openssl-0.9.8b/ssl/s23_srvr.c	2007-10-08 17:55:22.000000000 +0200
@@ -565,7 +565,6 @@ int ssl23_get_client_hello(SSL *s)
 	s->init_num=0;
 
 	if (buf != buf_space) OPENSSL_free(buf);
-	s->first_packet=1;
 	return(SSL_accept(s));
 err:
 	if (buf != buf_space) OPENSSL_free(buf);
diff -up openssl-0.9.8b/ssl/s23_clnt.c.dtls-fixes openssl-0.9.8b/ssl/s23_clnt.c
--- openssl-0.9.8b/ssl/s23_clnt.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
+++ openssl-0.9.8b/ssl/s23_clnt.c	2007-10-08 17:55:22.000000000 +0200
@@ -574,7 +574,6 @@ static int ssl23_get_server_hello(SSL *s
 	if (!ssl_get_new_session(s,0))
 		goto err;
 
-	s->first_packet=1;
 	return(SSL_connect(s));
 err:
 	return(-1);
diff -up openssl-0.9.8b/ssl/s3_lib.c.dtls-fixes openssl-0.9.8b/ssl/s3_lib.c
--- openssl-0.9.8b/ssl/s3_lib.c.dtls-fixes	2006-01-15 08:14:38.000000000 +0100
+++ openssl-0.9.8b/ssl/s3_lib.c	2007-10-08 17:55:22.000000000 +0200
@@ -903,7 +903,8 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]
 	},
 
 #if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES
-	/* New TLS Export CipherSuites */
+	/* New TLS Export CipherSuites from expired ID */
+#if 0
 	/* Cipher 60 */
 	    {
 	    1,
@@ -930,6 +931,7 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]
 	    SSL_ALL_CIPHERS,
 	    SSL_ALL_STRENGTHS,
 	    },
+#endif
 	/* Cipher 62 */
 	    {
 	    1,
diff -up openssl-0.9.8b/ssl/s2_lib.c.dtls-fixes openssl-0.9.8b/ssl/s2_lib.c
--- openssl-0.9.8b/ssl/s2_lib.c.dtls-fixes	2005-08-27 14:05:23.000000000 +0200
+++ openssl-0.9.8b/ssl/s2_lib.c	2007-10-08 17:55:22.000000000 +0200
@@ -178,7 +178,7 @@ OPENSSL_GLOBAL SSL_CIPHER ssl2_ciphers[]
 	SSL_ALL_STRENGTHS,
 	},
 /* RC4_64_WITH_MD5 */
-#if 1
+#if 0
 	{
 	1,
 	SSL2_TXT_RC4_64_WITH_MD5,
diff -up openssl-0.9.8b/ssl/d1_both.c.dtls-fixes openssl-0.9.8b/ssl/d1_both.c
--- openssl-0.9.8b/ssl/d1_both.c.dtls-fixes	2005-08-29 01:20:52.000000000 +0200
+++ openssl-0.9.8b/ssl/d1_both.c	2007-10-08 17:55:22.000000000 +0200
@@ -138,38 +138,40 @@ static void dtls1_set_message_header_int
 	unsigned long frag_len);
 static int dtls1_retransmit_buffered_messages(SSL *s);
 static long dtls1_get_message_fragment(SSL *s, int st1, int stn, 
-    long max, int *ok);
-static void dtls1_process_handshake_fragment(SSL *s, int frag_len);
+	long max, int *ok);
 
 static hm_fragment *
 dtls1_hm_fragment_new(unsigned long frag_len)
-    {
-    hm_fragment *frag = NULL;
-    unsigned char *buf = NULL;
+	{
+	hm_fragment *frag = NULL;
+	unsigned char *buf = NULL;
 
-    frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
-    if ( frag == NULL)
-        return NULL;
+	frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
+	if ( frag == NULL)
+		return NULL;
 
-    buf = (unsigned char *)OPENSSL_malloc(frag_len 
-        + DTLS1_HM_HEADER_LENGTH);
-    if ( buf == NULL)
-        {
-        OPENSSL_free(frag);
-        return NULL;
-        }
-    
-    frag->fragment = buf;
+	if (frag_len)
+		{
+		buf = (unsigned char *)OPENSSL_malloc(frag_len);
+		if ( buf == NULL)
+			{
+			OPENSSL_free(frag);
+			return NULL;
+			}
+		}
 
-    return frag;
-    }
+	/* zero length fragment gets zero frag->fragment */
+	frag->fragment = buf;
+
+	return frag;
+	}
 
 static void
 dtls1_hm_fragment_free(hm_fragment *frag)
-    {
-    OPENSSL_free(frag->fragment);
-    OPENSSL_free(frag);
-    }
+	{
+	if (frag->fragment) OPENSSL_free(frag->fragment);
+	OPENSSL_free(frag);
+	}
 
 /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
 int dtls1_do_write(SSL *s, int type)
@@ -180,7 +182,7 @@ int dtls1_do_write(SSL *s, int type)
 
 	/* AHA!  Figure out the MTU, and stick to the right size */
 	if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
-        {
+		{
 		s->d1->mtu = 
 			BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
 
@@ -207,7 +209,7 @@ int dtls1_do_write(SSL *s, int type)
 		mtu = curr_mtu;
 	else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
 		return ret;
-		
+
 	if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
 		{
 		ret = BIO_flush(SSL_get_wbio(s));
@@ -254,11 +256,11 @@ int dtls1_do_write(SSL *s, int type)
 				s->init_off -= DTLS1_HM_HEADER_LENGTH;
 				s->init_num += DTLS1_HM_HEADER_LENGTH;
 
-                /* write atleast DTLS1_HM_HEADER_LENGTH bytes */
+				/* write atleast DTLS1_HM_HEADER_LENGTH bytes */
 				if ( len <= DTLS1_HM_HEADER_LENGTH)  
 					len += DTLS1_HM_HEADER_LENGTH;
 				}
-			
+
 			dtls1_fix_message_header(s, frag_off, 
 				len - DTLS1_HM_HEADER_LENGTH);
 
@@ -286,18 +288,40 @@ int dtls1_do_write(SSL *s, int type)
 			}
 		else
 			{
-			
+
 			/* bad if this assert fails, only part of the handshake
 			 * message got sent.  but why would this happen? */
-			OPENSSL_assert(len == (unsigned int)ret); 
-			
+			OPENSSL_assert(len == (unsigned int)ret);
+
 			if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
+				{
 				/* should not be done for 'Hello Request's, but in that case
 				 * we'll ignore the result anyway */
-				ssl3_finish_mac(s, 
-					(unsigned char *)&s->init_buf->data[s->init_off + 
-						DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH);
-			
+				unsigned char *p = &s->init_buf->data[s->init_off];
+				const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+				int len;
+
+				if (frag_off == 0 && s->client_version != DTLS1_BAD_VER)
+					{
+					/* reconstruct message header is if it
+					 * is being sent in single fragment */
+					*p++ = msg_hdr->type;
+					l2n3(msg_hdr->msg_len,p);
+					s2n (msg_hdr->seq,p);
+					l2n3(0,p);
+					l2n3(msg_hdr->msg_len,p);
+					p  -= DTLS1_HM_HEADER_LENGTH;
+					len = ret;
+					}
+				else
+					{
+					p  += DTLS1_HM_HEADER_LENGTH;
+					len = ret - DTLS1_HM_HEADER_LENGTH;
+					}
+
+				ssl3_finish_mac(s, p, len);
+				}
+
 			if (ret == s->init_num)
 				{
 				if (s->msg_callback)
@@ -307,7 +331,7 @@ int dtls1_do_write(SSL *s, int type)
 
 				s->init_off = 0;  /* done writing this message */
 				s->init_num = 0;
-				
+
 				return(1);
 				}
 			s->init_off+=ret;
@@ -327,6 +351,7 @@ int dtls1_do_write(SSL *s, int type)
 long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
 	{
 	int i, al;
+	struct hm_header_st *msg_hdr;
 
 	/* s3->tmp is used to store messages that are unexpected, caused
 	 * by the absence of an optional handshake message */
@@ -344,25 +369,56 @@ long dtls1_get_message(SSL *s, int st1, 
 		s->init_num = (int)s->s3->tmp.message_size;
 		return s->init_num;
 		}
-	
+
+	msg_hdr = &s->d1->r_msg_hdr;
 	do
 		{
-		if ( s->d1->r_msg_hdr.frag_off == 0)
+		if ( msg_hdr->frag_off == 0)
 			{
 			/* s->d1->r_message_header.msg_len = 0; */
-			memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
+			memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
 			}
 
 		i = dtls1_get_message_fragment(s, st1, stn, max, ok);
 		if ( i == DTLS1_HM_BAD_FRAGMENT ||
-            i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
+			i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
 			continue;
 		else if ( i <= 0 && !*ok)
 			return i;
 
-		if (s->d1->r_msg_hdr.msg_len == (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
+		/* Note that s->init_sum is used as a counter summing
+		 * up fragments' lengths: as soon as they sum up to
+		 * handshake packet length, we assume we have got all
+		 * the fragments. Overlapping fragments would cause
+		 * premature termination, so we don't expect overlaps.
+		 * Well, handling overlaps would require something more
+		 * drastic. Indeed, as it is now there is no way to
+		 * tell if out-of-order fragment from the middle was
+		 * the last. '>=' is the best/least we can do to control
+		 * the potential damage caused by malformed overlaps. */
+		if ((unsigned int)s->init_num >= msg_hdr->msg_len)
 			{
-			memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
+			unsigned char *p = s->init_buf->data;
+			unsigned long msg_len = msg_hdr->msg_len;
+
+			/* reconstruct message header as if it was
+			 * sent in single fragment */
+			*(p++) = msg_hdr->type;
+			l2n3(msg_len,p);
+			s2n (msg_hdr->seq,p);
+			l2n3(0,p);
+			l2n3(msg_len,p);
+			if (s->client_version != DTLS1_BAD_VER)
+				p       -= DTLS1_HM_HEADER_LENGTH,
+				msg_len += DTLS1_HM_HEADER_LENGTH;
+
+			ssl3_finish_mac(s, p, msg_len);
+			if (s->msg_callback)
+				s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+					p, msg_len,
+					s, s->msg_callback_arg);
+
+			memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
 
 			s->d1->handshake_read_seq++;
 			/* we just read a handshake message from the other side:
@@ -379,11 +435,11 @@ long dtls1_get_message(SSL *s, int st1, 
 			 * first data  segment, but is there a better way?  */
 			dtls1_clear_record_buffer(s);
 
-            s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-			return s->init_num - DTLS1_HM_HEADER_LENGTH;
+			s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+			return s->init_num;
 			}
 		else
-			s->d1->r_msg_hdr.frag_off = i;
+			msg_hdr->frag_off = i;
 		} while(1) ;
 
 f_err:
@@ -393,161 +449,183 @@ f_err:
 	}
 
 
-static int
-dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied)
-    {
-    /* (0) check whether the desired fragment is available
-     * if so:
-     * (1) copy over the fragment to s->init_buf->data[]
-     * (2) update s->init_num
-     */
-    pitem *item;
-    hm_fragment *frag;
-    unsigned long overlap;
-    unsigned char *p;
-
-    item = pqueue_peek(s->d1->buffered_messages);
-    if ( item == NULL)
-        return 0;
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
+	{
+	size_t frag_off,frag_len,msg_len;
 
-    frag = (hm_fragment *)item->data;
-    
-    if ( s->d1->handshake_read_seq == frag->msg_header.seq &&
-        frag->msg_header.frag_off <= (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
-        {
-        pqueue_pop(s->d1->buffered_messages);
-        overlap = s->init_num - DTLS1_HM_HEADER_LENGTH 
-            - frag->msg_header.frag_off;
-
-        p = frag->fragment;
-
-        memcpy(&s->init_buf->data[s->init_num],
-            p + DTLS1_HM_HEADER_LENGTH + overlap,
-            frag->msg_header.frag_len - overlap);
-    
-        OPENSSL_free(frag->fragment);
-        OPENSSL_free(frag);
-        pitem_free(item);
+	msg_len  = msg_hdr->msg_len;
+	frag_off = msg_hdr->frag_off;
+	frag_len = msg_hdr->frag_len;
 
-        *copied = frag->msg_header.frag_len - overlap;
-        return *copied;
-        }
-    else
-        return 0;
-    }
+	/* sanity checking */
+	if ( (frag_off+frag_len) > msg_len)
+		{
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+		return SSL_AD_ILLEGAL_PARAMETER;
+		}
 
+	if ( (frag_off+frag_len) > (unsigned long)max)
+		{
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+		return SSL_AD_ILLEGAL_PARAMETER;
+		}
 
-static int
-dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr)
-{
-    hm_fragment *frag = NULL;
-    pitem *item = NULL;
-	PQ_64BIT seq64;
+	if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
+		{
+		/* msg_len is limited to 2^24, but is effectively checked
+		 * against max above */
+		if (!BUF_MEM_grow_clean(s->init_buf,(int)msg_len+DTLS1_HM_HEADER_LENGTH))
+			{
+			SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
+			return SSL_AD_INTERNAL_ERROR;
+			}
 
-    frag = dtls1_hm_fragment_new(msg_hdr->frag_len);
-    if ( frag == NULL)
-        goto err;
+		s->s3->tmp.message_size  = msg_len;
+		s->d1->r_msg_hdr.msg_len = msg_len;
+		s->s3->tmp.message_type  = msg_hdr->type;
+		s->d1->r_msg_hdr.type    = msg_hdr->type;
+		s->d1->r_msg_hdr.seq     = msg_hdr->seq;
+		}
+	else if (msg_len != s->d1->r_msg_hdr.msg_len)
+		{
+		/* They must be playing with us! BTW, failure to enforce
+		 * upper limit would open possibility for buffer overrun. */
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+		return SSL_AD_ILLEGAL_PARAMETER;
+		}
 
-    memcpy(frag->fragment, &(s->init_buf->data[s->init_num]),
-        msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH);
+	return 0; /* no error */
+	}
 
-    memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
 
-    pq_64bit_init(&seq64);
-    pq_64bit_assign_word(&seq64, msg_hdr->seq);
+static int
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
+	{
+	/* (0) check whether the desired fragment is available
+	 * if so:
+	 * (1) copy over the fragment to s->init_buf->data[]
+	 * (2) update s->init_num
+	 */
+	pitem *item;
+	hm_fragment *frag;
+	int al;
 
-    item = pitem_new(seq64, frag);
-    if ( item == NULL)
-        goto err;
+	*ok = 0;
+	item = pqueue_peek(s->d1->buffered_messages);
+	if ( item == NULL)
+		return 0;
 
-    pq_64bit_free(&seq64);
+	frag = (hm_fragment *)item->data;
 
-    pqueue_insert(s->d1->buffered_messages, item);
-    return 1;
+	if ( s->d1->handshake_read_seq == frag->msg_header.seq)
+		{
+		pqueue_pop(s->d1->buffered_messages);
 
-err:
-    if ( frag != NULL) dtls1_hm_fragment_free(frag);
-    if ( item != NULL) OPENSSL_free(item);
-    return 0;
-}
+		al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
 
+		if (al==0) /* no alert */
+			{
+			unsigned char *p = s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+			memcpy(&p[frag->msg_header.frag_off],
+				frag->fragment,frag->msg_header.frag_len);
+			}
 
-static void
-dtls1_process_handshake_fragment(SSL *s, int frag_len)
-    {
-    unsigned char *p;
+		dtls1_hm_fragment_free(frag);
+		pitem_free(item);
 
-    p = (unsigned char *)s->init_buf->data;
+		if (al==0)
+			{
+			*ok = 1;
+			return frag->msg_header.frag_len;
+			}
 
-	ssl3_finish_mac(s, &p[s->init_num - frag_len], frag_len);
-    }
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
+		s->init_num = 0;
+		*ok = 0;
+		return -1;
+		}
+	else
+		return 0;
+	}
 
 
 static int
-dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st *msg_hdr, int *ok)
-    {
-    int i;
-    unsigned char *p;
-
-    /* make sure there's enough room to read this fragment */
-    if ( (int)msg_hdr->frag_len && !BUF_MEM_grow_clean(s->init_buf, 
-             (int)msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH + s->init_num))
-        {
-        SSLerr(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE,ERR_R_BUF_LIB);
-        goto err;
-        }
+dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
+{
+	int i=-1;
+	hm_fragment *frag = NULL;
+	pitem *item = NULL;
+	PQ_64BIT seq64;
+	unsigned long frag_len = msg_hdr->frag_len;
 
-    p = (unsigned char *)s->init_buf->data;
+	if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
+		goto err;
 
-    /* read the body of the fragment (header has already been read */
-    if ( msg_hdr->frag_len > 0)
+	if (msg_hdr->seq <= s->d1->handshake_read_seq)
 		{
-		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
-            &p[s->init_num], 
-            msg_hdr->frag_len,0);
-		if (i <= 0)
+		unsigned char devnull [256];
+
+		while (frag_len)
 			{
-			*ok = 0;
-			return i;
+			i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+				devnull,
+				frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
+			if (i<=0) goto err;
+			frag_len -= i;
 			}
 		}
 
-    if ( msg_hdr->seq > s->d1->handshake_read_seq)
-        dtls1_buffer_handshake_fragment(s, msg_hdr);
-    else
-        OPENSSL_assert(msg_hdr->seq < s->d1->handshake_read_seq);
+	frag = dtls1_hm_fragment_new(frag_len);
+	if ( frag == NULL)
+		goto err;
+
+	memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+	if (frag_len)
+		{
+		/* read the body of the fragment (header has already been read */
+		i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+			frag->fragment,frag_len,0);
+		if (i<=0 || i!=frag_len)
+			goto err;
+		}
+
+	pq_64bit_init(&seq64);
+	pq_64bit_assign_word(&seq64, msg_hdr->seq);
+
+	item = pitem_new(seq64, frag);
+	pq_64bit_free(&seq64);
+	if ( item == NULL)
+		goto err;
+
+	pqueue_insert(s->d1->buffered_messages, item);
+	return DTLS1_HM_FRAGMENT_RETRY;
 
-    return DTLS1_HM_FRAGMENT_RETRY;
 err:
-    *ok = 0;
-    return -1;
-    }
+	if ( frag != NULL) dtls1_hm_fragment_free(frag);
+	if ( item != NULL) OPENSSL_free(item);
+	*ok = 0;
+	return i;
+	}
 
 
 static long
 dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
 	{
-	unsigned char *p;
+	unsigned char wire[DTLS1_HM_HEADER_LENGTH];
 	unsigned long l, frag_off, frag_len;
 	int i,al;
 	struct hm_header_st msg_hdr;
-    unsigned long overlap;
-    
-    /* see if we have the required fragment already */
-    if (dtls1_retrieve_buffered_fragment(s, &l))
-    {
-        /* compute MAC, remove fragment headers */
-        dtls1_process_handshake_fragment(s, l);
-        s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-        s->state = stn;
-        return 1;
-    }
 
-    /* get a handshake fragment from the record layer */
-	p = (unsigned char *)s->init_buf->data;
+	/* see if we have the required fragment already */
+	if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
+		{
+		if (*ok)	s->init_num += frag_len;
+		return frag_len;
+		}
 
-    /* read handshake message header */
-	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
+	/* read handshake message header */
+	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
 		DTLS1_HM_HEADER_LENGTH, 0);
 	if (i <= 0) 	/* nbio, or an error */
 		{
@@ -555,130 +633,61 @@ dtls1_get_message_fragment(SSL *s, int s
 		*ok = 0;
 		return i;
 		}
-
 	OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH);
 
-	p += s->init_num;
-    /* parse the message fragment header */
-    
-    dtls1_get_message_header(p, &msg_hdr);
+	/* parse the message fragment header */
+	dtls1_get_message_header(wire, &msg_hdr);
 
-    /* 
-     * if this is a future (or stale) message it gets buffered
-     * (or dropped)--no further processing at this time 
-     */
-    if ( msg_hdr.seq != s->d1->handshake_read_seq)
-        return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
+	/* 
+	 * if this is a future (or stale) message it gets buffered
+	 * (or dropped)--no further processing at this time 
+	 */
+	if ( msg_hdr.seq != s->d1->handshake_read_seq)
+		return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
 
-    l = msg_hdr.msg_len;
-    frag_off = msg_hdr.frag_off;
+	l = msg_hdr.msg_len;
+	frag_off = msg_hdr.frag_off;
 	frag_len = msg_hdr.frag_len;
 
-    /* sanity checking */
-    if ( frag_off + frag_len > l)
-        {
-        al=SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        goto f_err;
-        }
-
 	if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
-        p[0] == SSL3_MT_HELLO_REQUEST)
-        {
-        /* The server may always send 'Hello Request' messages --
-         * we are doing a handshake anyway now, so ignore them
-         * if their format is correct. Does not count for
-         * 'Finished' MAC. */
-        if (p[1] == 0 && p[2] == 0 &&p[3] == 0)
-            {
-            if (s->msg_callback)
-                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
-                    p, DTLS1_HM_HEADER_LENGTH, s, 
-                    s->msg_callback_arg);
-            
-            s->init_num = 0;
-            return dtls1_get_message_fragment(s, st1, stn,
-                max, ok);
-            }
-        else /* Incorrectly formated Hello request */
-            {
-            al=SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-            }
-        }
-
-    /* XDTLS: do a sanity check on the fragment */
-
-    s->init_num += i;
-
-	if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
+		wire[0] == SSL3_MT_HELLO_REQUEST)
 		{
-		/* BUF_MEM_grow takes an 'int' parameter */
-		if (l > (INT_MAX-DTLS1_HM_HEADER_LENGTH)) 
+		/* The server may always send 'Hello Request' messages --
+		 * we are doing a handshake anyway now, so ignore them
+		 * if their format is correct. Does not count for
+		 * 'Finished' MAC. */
+		if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
 			{
-			al=SSL_AD_ILLEGAL_PARAMETER;
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
-			goto f_err;
-			}
-		if (l && !BUF_MEM_grow_clean(s->init_buf,(int)l
-			+ DTLS1_HM_HEADER_LENGTH))
-			{
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
-			goto err;
+			if (s->msg_callback)
+				s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
+					wire, DTLS1_HM_HEADER_LENGTH, s, 
+					s->msg_callback_arg);
+			
+			s->init_num = 0;
+			return dtls1_get_message_fragment(s, st1, stn,
+				max, ok);
 			}
-        /* Only do this test when we're reading the expected message.
-         * Stale messages will be dropped and future messages will be buffered */
-        if ( l > (unsigned long)max)
+		else /* Incorrectly formated Hello request */
 			{
-			al=SSL_AD_ILLEGAL_PARAMETER;
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
 			goto f_err;
 			}
-
-		s->s3->tmp.message_size=l;
 		}
 
-    if ( frag_len > (unsigned long)max)
-        {
-        al=SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        goto f_err;
-        }
-    if ( frag_len + s->init_num > (INT_MAX - DTLS1_HM_HEADER_LENGTH))
-        {
-        al=SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        goto f_err;
-        }
-
-    if ( frag_len & !BUF_MEM_grow_clean(s->init_buf, (int)frag_len 
-             + DTLS1_HM_HEADER_LENGTH + s->init_num))
-        {
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
-        goto err;
-        }
-
-	if ( s->d1->r_msg_hdr.frag_off == 0)
-		{
-		s->s3->tmp.message_type = msg_hdr.type;
-		s->d1->r_msg_hdr.type = msg_hdr.type;
-		s->d1->r_msg_hdr.msg_len = l;
-		/* s->d1->r_msg_hdr.seq = seq_num; */
-		}
+	if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
+		goto f_err;
 
 	/* XDTLS:  ressurect this when restart is in place */
 	s->state=stn;
-	
-	/* next state (stn) */
-	p = (unsigned char *)s->init_buf->data;
 
 	if ( frag_len > 0)
 		{
+		unsigned char *p=s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
+
 		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
-            &p[s->init_num], 
-            frag_len,0);
-        /* XDTLS:  fix this--message fragments cannot span multiple packets */
+			&p[frag_off],frag_len,0);
+		/* XDTLS:  fix this--message fragments cannot span multiple packets */
 		if (i <= 0)
 			{
 			s->rwstate=SSL_READING;
@@ -689,70 +698,23 @@ dtls1_get_message_fragment(SSL *s, int s
 	else
 		i = 0;
 
-    /* XDTLS:  an incorrectly formatted fragment should cause the 
-     * handshake to fail */
+	/* XDTLS:  an incorrectly formatted fragment should cause the 
+	 * handshake to fail */
 	OPENSSL_assert(i == (int)frag_len);
 
-#if 0
-    /* Successfully read a fragment.
-     * It may be (1) out of order, or
-     *           (2) it's a repeat, in which case we dump it
-     *           (3) the one we are expecting next (maybe with overlap)
-     * If it is next one, it may overlap with previously read bytes
-     */
+	*ok = 1;
 
-    /* case (1): buffer the future fragment 
-     * (we can treat fragments from a future message the same
-     * as future fragments from the message being currently read, since
-     * they are sematically simply out of order.
-     */
-    if ( msg_hdr.seq > s->d1->handshake_read_seq ||
-        frag_off > s->init_num - DTLS1_HM_HEADER_LENGTH)
-    {
-        dtls1_buffer_handshake_fragment(s, &msg_hdr);
-        return DTLS1_HM_FRAGMENT_RETRY;
-    }
-
-    /* case (2):  drop the entire fragment, and try again */
-    if ( msg_hdr.seq < s->d1->handshake_read_seq ||
-        frag_off + frag_len < s->init_num - DTLS1_HM_HEADER_LENGTH)
-        {
-        s->init_num -= DTLS1_HM_HEADER_LENGTH;
-        return DTLS1_HM_FRAGMENT_RETRY;
-        }
-#endif
-
-    /* case (3): received a immediately useful fragment.  Determine the 
-     * possible overlap and copy the fragment.
-     */
-    overlap = (s->init_num - DTLS1_HM_HEADER_LENGTH) - frag_off;
-        
-    /* retain the header for the first fragment */
-    if ( s->init_num > DTLS1_HM_HEADER_LENGTH)
-        {
-        memmove(&(s->init_buf->data[s->init_num]),
-            &(s->init_buf->data[s->init_num + DTLS1_HM_HEADER_LENGTH + overlap]),
-            frag_len - overlap);
-
-        s->init_num += frag_len - overlap;
-        }
-    else
-        s->init_num += frag_len;
-
-    dtls1_process_handshake_fragment(s, frag_len - overlap);
-
-	if (s->msg_callback)
-		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, 
-			(size_t)s->init_num, s, 
-			s->msg_callback_arg);
-	*ok=1;
-
-	return s->init_num;
+	/* Note that s->init_num is *not* used as current offset in
+	 * s->init_buf->data, but as a counter summing up fragments'
+	 * lengths: as soon as they sum up to handshake packet
+	 * length, we assume we have got all the fragments. */
+	s->init_num += frag_len;
+	return frag_len;
 
 f_err:
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
-    s->init_num = 0;
-err:
+	s->init_num = 0;
+
 	*ok=0;
 	return(-1);
 	}
@@ -790,7 +752,7 @@ int dtls1_send_finished(SSL *s, int a, i
 
 		/* buffer the message to handle re-xmits */
 		dtls1_buffer_message(s, 0);
-		
+
 		s->state=b;
 		}
 
@@ -816,9 +778,14 @@ int dtls1_send_change_cipher_spec(SSL *s
 		*p++=SSL3_MT_CCS;
 		s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
 		s->d1->next_handshake_write_seq++;
-		s2n(s->d1->handshake_write_seq,p);
-
 		s->init_num=DTLS1_CCS_HEADER_LENGTH;
+
+		if (s->client_version == DTLS1_BAD_VER)
+			{
+			s2n(s->d1->handshake_write_seq,p);
+			s->init_num+=2;
+			}
+
 		s->init_off=0;
 
 		dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, 
@@ -1056,7 +1023,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
     if ( is_ccs)
         {
         OPENSSL_assert(s->d1->w_msg_hdr.msg_len + 
-            DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num);
+            DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num);
         }
     else
         {
@@ -1259,5 +1226,4 @@ dtls1_get_ccs_header(unsigned char *data
     memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
     
     ccs_hdr->type = *(data++);
-    n2s(data, ccs_hdr->seq);
 }
diff -up openssl-0.9.8b/ssl/d1_clnt.c.dtls-fixes openssl-0.9.8b/ssl/d1_clnt.c
--- openssl-0.9.8b/ssl/d1_clnt.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
+++ openssl-0.9.8b/ssl/d1_clnt.c	2007-10-08 17:55:22.000000000 +0200
@@ -214,17 +214,21 @@ int dtls1_connect(SSL *s)
 
 			/* don't push the buffering BIO quite yet */
 
-			ssl3_init_finished_mac(s);
-
 			s->state=SSL3_ST_CW_CLNT_HELLO_A;
 			s->ctx->stats.sess_connect++;
 			s->init_num=0;
+			/* mark client_random uninitialized */
+			memset(s->s3->client_random,0,sizeof(s->s3->client_random));
 			break;
 
 		case SSL3_ST_CW_CLNT_HELLO_A:
 		case SSL3_ST_CW_CLNT_HELLO_B:
 
 			s->shutdown=0;
+
+			/* every DTLS ClientHello resets Finished MAC */
+			ssl3_init_finished_mac(s);
+
 			ret=dtls1_client_hello(s);
 			if (ret <= 0) goto end;
 
@@ -422,6 +426,9 @@ int dtls1_connect(SSL *s)
 				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
 				}
 			s->init_num=0;
+			/* mark client_random uninitialized */
+			memset (s->s3->client_random,0,sizeof(s->s3->client_random));
+
 			break;
 
 		case SSL3_ST_CR_FINISHED_A:
@@ -544,9 +551,15 @@ int dtls1_client_hello(SSL *s)
 		/* else use the pre-loaded session */
 
 		p=s->s3->client_random;
-		Time=(unsigned long)time(NULL);			/* Time */
-		l2n(Time,p);
-		RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+		/* if client_random is initialized, reuse it, we are
+		 * required to use same upon reply to HelloVerify */
+		for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) ;
+		if (i==sizeof(s->s3->client_random))
+			{
+			Time=(unsigned long)time(NULL);	/* Time */
+			l2n(Time,p);
+			RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4);
+			}
 
 		/* Do the message type and length last */
 		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);