Blob Blame History Raw
diff -up openssl-fips-0.9.8f-dev/ssl/dtls1.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/dtls1.h
--- openssl-fips-0.9.8f-dev/ssl/dtls1.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
+++ openssl-fips-0.9.8f-dev/ssl/dtls1.h	2008-07-15 21:01:29.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-fips-0.9.8f-dev/ssl/d1_lib.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_lib.c
--- openssl-fips-0.9.8f-dev/ssl/d1_lib.c.dtls-fixes	2007-01-21 17:07:25.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/d1_lib.c	2008-07-15 21:01:29.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-fips-0.9.8f-dev/ssl/d1_srvr.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_srvr.c
--- openssl-fips-0.9.8f-dev/ssl/d1_srvr.c.dtls-fixes	2007-09-19 02:02:49.000000000 +0200
+++ openssl-fips-0.9.8f-dev/ssl/d1_srvr.c	2008-07-15 21:01:29.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);
diff -up openssl-fips-0.9.8f-dev/ssl/s3_srvr.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/s3_srvr.c
--- openssl-fips-0.9.8f-dev/ssl/s3_srvr.c.dtls-fixes	2007-03-22 01:39:14.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/s3_srvr.c	2008-07-15 21:01:29.000000000 +0200
@@ -699,7 +699,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) 
@@ -750,7 +751,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++);
@@ -1713,8 +1714,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-fips-0.9.8f-dev/ssl/ssl_locl.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl_locl.h
--- openssl-fips-0.9.8f-dev/ssl/ssl_locl.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
+++ openssl-fips-0.9.8f-dev/ssl/ssl_locl.h	2008-07-15 21:01:29.000000000 +0200
@@ -680,7 +680,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, \
@@ -845,6 +845,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-fips-0.9.8f-dev/ssl/t1_enc.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/t1_enc.c
--- openssl-fips-0.9.8f-dev/ssl/t1_enc.c.dtls-fixes	2007-03-22 01:39:15.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/t1_enc.c	2008-07-15 21:01:29.000000000 +0200
@@ -740,15 +740,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);
@@ -765,8 +785,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-fips-0.9.8f-dev/ssl/ssl.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl.h
--- openssl-fips-0.9.8f-dev/ssl/ssl.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
+++ openssl-fips-0.9.8f-dev/ssl/ssl.h	2008-07-15 21:01:29.000000000 +0200
@@ -1554,6 +1554,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-fips-0.9.8f-dev/ssl/d1_pkt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_pkt.c
--- openssl-fips-0.9.8f-dev/ssl/d1_pkt.c.dtls-fixes	2006-11-29 15:45:13.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/d1_pkt.c	2008-07-15 21:01:29.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);
@@ -535,7 +536,7 @@ again:
 		/* Lets check version */
 		if (!s->first_packet)
 			{
-			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
@@ -546,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;
@@ -559,6 +561,7 @@ again:
 			goto f_err;
 			}
 
+		s->client_version = version;
 		/* now s->rstate == SSL_ST_READ_BODY */
 		}
 
@@ -973,47 +976,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);
+
+		if (s->client_version == DTLS1_BAD_VER)
+			s->d1->handshake_read_seq++;
+
+		goto start;
 		}
 
 	/* Unexpected handshake message (Client Hello, or protocol violation) */
@@ -1341,8 +1337,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; 
@@ -1397,8 +1397,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-fips-0.9.8f-dev/ssl/ssl_err.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl_err.c
--- openssl-fips-0.9.8f-dev/ssl/ssl_err.c.dtls-fixes	2006-11-21 21:14:46.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/ssl_err.c	2008-07-15 21:01:29.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-fips-0.9.8f-dev/ssl/s3_clnt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/s3_clnt.c
--- openssl-fips-0.9.8f-dev/ssl/s3_clnt.c.dtls-fixes	2007-03-22 01:39:14.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/s3_clnt.c	2008-07-15 21:08:43.000000000 +0200
@@ -1847,6 +1847,13 @@ int ssl3_send_client_key_exchange(SSL *s
 			{
 			DH *dh_srvr,*dh_clnt;
 
+                        if (s->session->sess_cert == NULL) 
+                                {
+                                ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
+                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
+                                goto err;
+                                }
+
 			if (s->session->sess_cert->peer_dh_tmp != NULL)
 				dh_srvr=s->session->sess_cert->peer_dh_tmp;
 			else
diff -up openssl-fips-0.9.8f-dev/ssl/d1_both.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_both.c
--- openssl-fips-0.9.8f-dev/ssl/d1_both.c.dtls-fixes	2007-06-22 14:17:52.000000000 +0200
+++ openssl-fips-0.9.8f-dev/ssl/d1_both.c	2008-07-15 21:01:29.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;
 		}
 
@@ -815,10 +777,15 @@ int dtls1_send_change_cipher_spec(SSL *s
 		p=(unsigned char *)s->init_buf->data;
 		*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)
+			{
+			s->d1->next_handshake_write_seq++;
+			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, 
@@ -1044,6 +1011,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
     pitem *item;
     hm_fragment *frag;
 	PQ_64BIT seq64;
+	unsigned int epoch = s->d1->w_epoch;
 
     /* this function is called immediately after a message has 
      * been serialized */
@@ -1056,7 +1024,8 @@ 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);
+	epoch++;
         }
     else
         {
@@ -1072,7 +1041,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
     frag->msg_header.is_ccs = is_ccs;
 
     pq_64bit_init(&seq64);
-    pq_64bit_assign_word(&seq64, frag->msg_header.seq);
+    pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq);
 
     item = pitem_new(seq64, frag);
     pq_64bit_free(&seq64);
@@ -1259,5 +1228,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-fips-0.9.8f-dev/ssl/d1_clnt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_clnt.c
--- openssl-fips-0.9.8f-dev/ssl/d1_clnt.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
+++ openssl-fips-0.9.8f-dev/ssl/d1_clnt.c	2008-07-15 21:01:29.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]);