Blame SOURCES/openssl-fips-0.9.8e-dtls-fixes.patch

5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/dtls1.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/dtls1.h
5820f5
--- openssl-fips-0.9.8f-dev/ssl/dtls1.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/dtls1.h	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -67,9 +67,8 @@
5820f5
 extern "C" {
5820f5
 #endif
5820f5
 
5820f5
-#define DTLS1_VERSION			0x0100
5820f5
-#define DTLS1_VERSION_MAJOR		0x01
5820f5
-#define DTLS1_VERSION_MINOR		0x00
5820f5
+#define DTLS1_VERSION			0xFEFF
5820f5
+#define DTLS1_BAD_VER			0x0100
5820f5
 
5820f5
 #define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
5820f5
 
5820f5
@@ -83,7 +82,7 @@ extern "C" {
5820f5
 #define DTLS1_HM_BAD_FRAGMENT                   -2
5820f5
 #define DTLS1_HM_FRAGMENT_RETRY                 -3
5820f5
 
5820f5
-#define DTLS1_CCS_HEADER_LENGTH                  3
5820f5
+#define DTLS1_CCS_HEADER_LENGTH                  1
5820f5
 
5820f5
 #define DTLS1_AL_HEADER_LENGTH                   7
5820f5
 
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/d1_lib.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_lib.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/d1_lib.c.dtls-fixes	2007-01-21 17:07:25.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/d1_lib.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -188,3 +188,23 @@ void dtls1_clear(SSL *s)
5820f5
 	ssl3_clear(s);
5820f5
 	s->version=DTLS1_VERSION;
5820f5
 	}
5820f5
+
5820f5
+/*
5820f5
+ * As it's impossible to use stream ciphers in "datagram" mode, this
5820f5
+ * simple filter is designed to disengage them in DTLS. Unfortunately
5820f5
+ * there is no universal way to identify stream SSL_CIPHER, so we have
5820f5
+ * to explicitly list their SSL_* codes. Currently RC4 is the only one
5820f5
+ * available, but if new ones emerge, they will have to be added...
5820f5
+ */
5820f5
+SSL_CIPHER *dtls1_get_cipher(unsigned int u)
5820f5
+	{
5820f5
+	SSL_CIPHER *ciph = ssl3_get_cipher(u);
5820f5
+
5820f5
+	if (ciph != NULL)
5820f5
+		{
5820f5
+		if ((ciph->algorithms&SSL_ENC_MASK) == SSL_RC4)
5820f5
+			return NULL;
5820f5
+		}
5820f5
+
5820f5
+	return ciph;
5820f5
+	}
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/d1_srvr.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_srvr.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/d1_srvr.c.dtls-fixes	2007-09-19 02:02:49.000000000 +0200
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/d1_srvr.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -285,6 +285,10 @@ int dtls1_accept(SSL *s)
5820f5
 			s->d1->send_cookie = 0;
5820f5
 			s->state=SSL3_ST_SW_FLUSH;
5820f5
 			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
5820f5
+
5820f5
+			/* HelloVerifyRequests resets Finished MAC */
5820f5
+			if (s->client_version != DTLS1_BAD_VER)
5820f5
+				ssl3_init_finished_mac(s);
5820f5
 			break;
5820f5
 			
5820f5
 		case SSL3_ST_SW_SRVR_HELLO_A:
5820f5
@@ -620,10 +624,13 @@ int dtls1_send_hello_verify_request(SSL 
5820f5
 		buf = (unsigned char *)s->init_buf->data;
5820f5
 
5820f5
 		msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
5820f5
-		*(p++) = s->version >> 8;
5820f5
-		*(p++) = s->version & 0xFF;
5820f5
+		if (s->client_version == DTLS1_BAD_VER)
5820f5
+			*(p++) = DTLS1_BAD_VER>>8,
5820f5
+			*(p++) = DTLS1_BAD_VER&0xff;
5820f5
+		else
5820f5
+			*(p++) = s->version >> 8,
5820f5
+			*(p++) = s->version & 0xFF;
5820f5
 
5820f5
-		*(p++) = (unsigned char) s->d1->cookie_len;
5820f5
         if ( s->ctx->app_gen_cookie_cb != NULL &&
5820f5
             s->ctx->app_gen_cookie_cb(s, s->d1->cookie, 
5820f5
                 &(s->d1->cookie_len)) == 0)
5820f5
@@ -634,6 +641,7 @@ int dtls1_send_hello_verify_request(SSL 
5820f5
         /* else the cookie is assumed to have 
5820f5
          * been initialized by the application */
5820f5
 
5820f5
+		*(p++) = (unsigned char) s->d1->cookie_len;
5820f5
 		memcpy(p, s->d1->cookie, s->d1->cookie_len);
5820f5
 		p += s->d1->cookie_len;
5820f5
 		msg_len = p - msg;
5820f5
@@ -672,8 +680,12 @@ int dtls1_send_server_hello(SSL *s)
5820f5
 		/* Do the message type and length last */
5820f5
 		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
5820f5
 
5820f5
-		*(p++)=s->version>>8;
5820f5
-		*(p++)=s->version&0xff;
5820f5
+		if (s->client_version == DTLS1_BAD_VER)
5820f5
+			*(p++)=DTLS1_BAD_VER>>8,
5820f5
+			*(p++)=DTLS1_BAD_VER&0xff;
5820f5
+		else
5820f5
+			*(p++)=s->version>>8,
5820f5
+			*(p++)=s->version&0xff;
5820f5
 
5820f5
 		/* Random stuff */
5820f5
 		memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/s3_srvr.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/s3_srvr.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/s3_srvr.c.dtls-fixes	2007-03-22 01:39:14.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/s3_srvr.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -699,7 +699,8 @@ int ssl3_get_client_hello(SSL *s)
5820f5
 	s->client_version=(((int)p[0])<<8)|(int)p[1];
5820f5
 	p+=2;
5820f5
 
5820f5
-	if (s->client_version < s->version)
5820f5
+	if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
5820f5
+	    (s->version != DTLS1_VERSION && s->client_version < s->version))
5820f5
 		{
5820f5
 		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
5820f5
 		if ((s->client_version>>8) == SSL3_VERSION_MAJOR) 
5820f5
@@ -750,7 +751,7 @@ int ssl3_get_client_hello(SSL *s)
5820f5
 
5820f5
 	p+=j;
5820f5
 
5820f5
-	if (SSL_version(s) == DTLS1_VERSION)
5820f5
+	if (s->version == DTLS1_VERSION)
5820f5
 		{
5820f5
 		/* cookie stuff */
5820f5
 		cookie_len = *(p++);
5820f5
@@ -1713,8 +1714,9 @@ int ssl3_get_client_key_exchange(SSL *s)
5820f5
 			rsa=pkey->pkey.rsa;
5820f5
 			}
5820f5
 
5820f5
-		/* TLS */
5820f5
-		if (s->version > SSL3_VERSION)
5820f5
+		/* TLS and [incidentally] DTLS, including pre-0.9.8f */
5820f5
+		if (s->version > SSL3_VERSION &&
5820f5
+		    s->client_version != DTLS1_BAD_VER)
5820f5
 			{
5820f5
 			n2s(p,i);
5820f5
 			if (n != i+2)
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/ssl_locl.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl_locl.h
5820f5
--- openssl-fips-0.9.8f-dev/ssl/ssl_locl.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/ssl_locl.h	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -680,7 +680,7 @@ SSL_METHOD *func_name(void)  \
5820f5
 		ssl3_put_cipher_by_char, \
5820f5
 		ssl3_pending, \
5820f5
 		ssl3_num_ciphers, \
5820f5
-		ssl3_get_cipher, \
5820f5
+		dtls1_get_cipher, \
5820f5
 		s_get_meth, \
5820f5
 		dtls1_default_timeout, \
5820f5
 		&DTLSv1_enc_data, \
5820f5
@@ -845,6 +845,8 @@ void dtls1_get_message_header(unsigned c
5820f5
 void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
5820f5
 void dtls1_reset_seq_numbers(SSL *s, int rw);
5820f5
 long dtls1_default_timeout(void);
5820f5
+SSL_CIPHER *dtls1_get_cipher(unsigned int u);
5820f5
+
5820f5
 
5820f5
 
5820f5
 /* some client-only functions */
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/t1_enc.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/t1_enc.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/t1_enc.c.dtls-fixes	2007-03-22 01:39:15.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/t1_enc.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -740,15 +740,35 @@ int tls1_mac(SSL *ssl, unsigned char *md
5820f5
 	md_size=EVP_MD_size(hash);
5820f5
 
5820f5
 	buf[0]=rec->type;
5820f5
-	buf[1]=TLS1_VERSION_MAJOR;
5820f5
-	buf[2]=TLS1_VERSION_MINOR;
5820f5
+	if (ssl->version == DTLS1_VERSION && ssl->client_version == DTLS1_BAD_VER)
5820f5
+		{
5820f5
+		buf[1]=TLS1_VERSION_MAJOR;
5820f5
+		buf[2]=TLS1_VERSION_MINOR;
5820f5
+		}
5820f5
+	else	{
5820f5
+		buf[1]=(unsigned char)(ssl->version>>8);
5820f5
+		buf[2]=(unsigned char)(ssl->version);
5820f5
+		}
5820f5
+
5820f5
 	buf[3]=rec->length>>8;
5820f5
 	buf[4]=rec->length&0xff;
5820f5
 
5820f5
 	/* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
5820f5
 	HMAC_CTX_init(&hmac);
5820f5
 	HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL);
5820f5
-	HMAC_Update(&hmac,seq,8);
5820f5
+
5820f5
+	if (ssl->version == DTLS1_VERSION && ssl->client_version != DTLS1_BAD_VER)
5820f5
+		{
5820f5
+		unsigned char dtlsseq[8],*p=dtlsseq;
5820f5
+
5820f5
+		s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
5820f5
+		memcpy (p,&seq[2],6);
5820f5
+
5820f5
+		HMAC_Update(&hmac,dtlsseq,8);
5820f5
+		}
5820f5
+	else
5820f5
+		HMAC_Update(&hmac,seq,8);
5820f5
+
5820f5
 	HMAC_Update(&hmac,buf,5);
5820f5
 	HMAC_Update(&hmac,rec->input,rec->length);
5820f5
 	HMAC_Final(&hmac,md,&md_size);
5820f5
@@ -765,8 +785,8 @@ printf("rec=");
5820f5
 {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
5820f5
 #endif
5820f5
 
5820f5
-    if ( SSL_version(ssl) != DTLS1_VERSION)
5820f5
-	    {
5820f5
+	if ( SSL_version(ssl) != DTLS1_VERSION)
5820f5
+		{
5820f5
 		for (i=7; i>=0; i--)
5820f5
 			{
5820f5
 			++seq[i];
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/ssl.h.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl.h
5820f5
--- openssl-fips-0.9.8f-dev/ssl/ssl.h.dtls-fixes	2008-07-15 21:01:29.000000000 +0200
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/ssl.h	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -1554,6 +1554,7 @@ void ERR_load_SSL_strings(void);
5820f5
 #define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT		 253
5820f5
 #define SSL_F_DTLS1_GET_RECORD				 254
5820f5
 #define SSL_F_DTLS1_OUTPUT_CERT_CHAIN			 255
5820f5
+#define SSL_F_DTLS1_PREPROCESS_FRAGMENT			 277
5820f5
 #define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE		 256
5820f5
 #define SSL_F_DTLS1_PROCESS_RECORD			 257
5820f5
 #define SSL_F_DTLS1_READ_BYTES				 258
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/d1_pkt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_pkt.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/d1_pkt.c.dtls-fixes	2006-11-29 15:45:13.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/d1_pkt.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -120,6 +120,7 @@
5820f5
 #include <openssl/evp.h>
5820f5
 #include <openssl/buffer.h>
5820f5
 #include <openssl/pqueue.h>
5820f5
+#include <openssl/rand.h>
5820f5
 
5820f5
 static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
5820f5
 	int len, int peek);
5820f5
@@ -486,9 +487,9 @@ int dtls1_get_record(SSL *s)
5820f5
 	SSL3_RECORD *rr;
5820f5
 	SSL_SESSION *sess;
5820f5
 	unsigned char *p;
5820f5
-	short version;
5820f5
+	unsigned short version;
5820f5
 	DTLS1_BITMAP *bitmap;
5820f5
-    unsigned int is_next_epoch;
5820f5
+	unsigned int is_next_epoch;
5820f5
 
5820f5
 	rr= &(s->s3->rrec);
5820f5
 	sess=s->session;
5820f5
@@ -524,7 +525,7 @@ again:
5820f5
 		ssl_minor= *(p++);
5820f5
 		version=(ssl_major<<8)|ssl_minor;
5820f5
 
5820f5
-        /* sequence number is 64 bits, with top 2 bytes = epoch */ 
5820f5
+		/* sequence number is 64 bits, with top 2 bytes = epoch */ 
5820f5
 		n2s(p,rr->epoch);
5820f5
 
5820f5
 		memcpy(&(s->s3->read_sequence[2]), p, 6);
5820f5
@@ -535,7 +536,7 @@ again:
5820f5
 		/* Lets check version */
5820f5
 		if (!s->first_packet)
5820f5
 			{
5820f5
-			if (version != s->version)
5820f5
+			if (version != s->version && version != DTLS1_BAD_VER)
5820f5
 				{
5820f5
 				SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
5820f5
 				/* Send back error using their
5820f5
@@ -546,7 +547,8 @@ again:
5820f5
 				}
5820f5
 			}
5820f5
 
5820f5
-		if ((version & 0xff00) != (DTLS1_VERSION & 0xff00))
5820f5
+		if ((version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
5820f5
+		    (version & 0xff00) != (DTLS1_BAD_VER & 0xff00))
5820f5
 			{
5820f5
 			SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
5820f5
 			goto err;
5820f5
@@ -559,6 +561,7 @@ again:
5820f5
 			goto f_err;
5820f5
 			}
5820f5
 
5820f5
+		s->client_version = version;
5820f5
 		/* now s->rstate == SSL_ST_READ_BODY */
5820f5
 		}
5820f5
 
5820f5
@@ -973,47 +976,40 @@ start:
5820f5
 		}
5820f5
 
5820f5
 	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
5820f5
-        {
5820f5
-        struct ccs_header_st ccs_hdr;
5820f5
+		{
5820f5
+		struct ccs_header_st ccs_hdr;
5820f5
 
5820f5
 		dtls1_get_ccs_header(rr->data, &ccs_hdr);
5820f5
 
5820f5
-		if ( ccs_hdr.seq == s->d1->handshake_read_seq)
5820f5
+		/* 'Change Cipher Spec' is just a single byte, so we know
5820f5
+		 * exactly what the record payload has to look like */
5820f5
+		/* XDTLS: check that epoch is consistent */
5820f5
+		if (	(s->client_version == DTLS1_BAD_VER && rr->length != 3) ||
5820f5
+			(s->client_version != DTLS1_BAD_VER && rr->length != DTLS1_CCS_HEADER_LENGTH) || 
5820f5
+			(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
5820f5
 			{
5820f5
-			/* 'Change Cipher Spec' is just a single byte, so we know
5820f5
-			 * exactly what the record payload has to look like */
5820f5
-			/* XDTLS: check that epoch is consistent */
5820f5
-			if (	(rr->length != DTLS1_CCS_HEADER_LENGTH) || 
5820f5
-				(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
5820f5
-				{
5820f5
-				i=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-				SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
5820f5
-				goto err;
5820f5
-				}
5820f5
-			
5820f5
-			rr->length=0;
5820f5
-			
5820f5
-			if (s->msg_callback)
5820f5
-				s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, 
5820f5
-					rr->data, 1, s, s->msg_callback_arg);
5820f5
-			
5820f5
-			s->s3->change_cipher_spec=1;
5820f5
-			if (!ssl3_do_change_cipher_spec(s))
5820f5
-				goto err;
5820f5
-			
5820f5
-			/* do this whenever CCS is processed */
5820f5
-			dtls1_reset_seq_numbers(s, SSL3_CC_READ);
5820f5
-			
5820f5
-			/* handshake read seq is reset upon handshake completion */
5820f5
-			s->d1->handshake_read_seq++;
5820f5
-			
5820f5
-			goto start;
5820f5
-			}
5820f5
-		else
5820f5
-			{
5820f5
-			rr->length = 0;
5820f5
-			goto start;
5820f5
+			i=SSL_AD_ILLEGAL_PARAMETER;
5820f5
+			SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
5820f5
+			goto err;
5820f5
 			}
5820f5
+
5820f5
+		rr->length=0;
5820f5
+
5820f5
+		if (s->msg_callback)
5820f5
+			s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, 
5820f5
+				rr->data, 1, s, s->msg_callback_arg);
5820f5
+
5820f5
+		s->s3->change_cipher_spec=1;
5820f5
+		if (!ssl3_do_change_cipher_spec(s))
5820f5
+			goto err;
5820f5
+
5820f5
+		/* do this whenever CCS is processed */
5820f5
+		dtls1_reset_seq_numbers(s, SSL3_CC_READ);
5820f5
+
5820f5
+		if (s->client_version == DTLS1_BAD_VER)
5820f5
+			s->d1->handshake_read_seq++;
5820f5
+
5820f5
+		goto start;
5820f5
 		}
5820f5
 
5820f5
 	/* Unexpected handshake message (Client Hello, or protocol violation) */
5820f5
@@ -1341,8 +1337,12 @@ int do_dtls1_write(SSL *s, int type, con
5820f5
 	*(p++)=type&0xff;
5820f5
 	wr->type=type;
5820f5
 
5820f5
-	*(p++)=(s->version>>8);
5820f5
-	*(p++)=s->version&0xff;
5820f5
+	if (s->client_version == DTLS1_BAD_VER)
5820f5
+		*(p++) = DTLS1_BAD_VER>>8,
5820f5
+		*(p++) = DTLS1_BAD_VER&0xff;
5820f5
+	else
5820f5
+		*(p++)=(s->version>>8),
5820f5
+		*(p++)=s->version&0xff;
5820f5
 
5820f5
 	/* field where we are to write out packet epoch, seq num and len */
5820f5
 	pseq=p; 
5820f5
@@ -1397,8 +1397,14 @@ int do_dtls1_write(SSL *s, int type, con
5820f5
 
5820f5
 
5820f5
 	/* ssl3_enc can only have an error on read */
5820f5
-	wr->length += bs;  /* bs != 0 in case of CBC.  The enc fn provides
5820f5
-						* the randomness */ 
5820f5
+	if (bs)	/* bs != 0 in case of CBC */
5820f5
+		{
5820f5
+		RAND_pseudo_bytes(p,bs);
5820f5
+		/* master IV and last CBC residue stand for
5820f5
+		 * the rest of randomness */
5820f5
+		wr->length += bs;
5820f5
+		}
5820f5
+
5820f5
 	s->method->ssl3_enc->enc(s,1);
5820f5
 
5820f5
 	/* record length after mac and block padding */
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/ssl_err.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/ssl_err.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/ssl_err.c.dtls-fixes	2006-11-21 21:14:46.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/ssl_err.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -87,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
5820f5
 {ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT),	"DTLS1_GET_MESSAGE_FRAGMENT"},
5820f5
 {ERR_FUNC(SSL_F_DTLS1_GET_RECORD),	"DTLS1_GET_RECORD"},
5820f5
 {ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN),	"DTLS1_OUTPUT_CERT_CHAIN"},
5820f5
+{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT),	"DTLS1_PREPROCESS_FRAGMENT"},
5820f5
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE),	"DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
5820f5
 {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD),	"DTLS1_PROCESS_RECORD"},
5820f5
 {ERR_FUNC(SSL_F_DTLS1_READ_BYTES),	"DTLS1_READ_BYTES"},
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/s3_clnt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/s3_clnt.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/s3_clnt.c.dtls-fixes	2007-03-22 01:39:14.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/s3_clnt.c	2008-07-15 21:08:43.000000000 +0200
5820f5
@@ -1847,6 +1847,13 @@ int ssl3_send_client_key_exchange(SSL *s
5820f5
 			{
5820f5
 			DH *dh_srvr,*dh_clnt;
5820f5
 
5820f5
+                        if (s->session->sess_cert == NULL) 
5820f5
+                                {
5820f5
+                                ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
5820f5
+                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
5820f5
+                                goto err;
5820f5
+                                }
5820f5
+
5820f5
 			if (s->session->sess_cert->peer_dh_tmp != NULL)
5820f5
 				dh_srvr=s->session->sess_cert->peer_dh_tmp;
5820f5
 			else
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/d1_both.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_both.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/d1_both.c.dtls-fixes	2007-06-22 14:17:52.000000000 +0200
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/d1_both.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -138,38 +138,40 @@ static void dtls1_set_message_header_int
5820f5
 	unsigned long frag_len);
5820f5
 static int dtls1_retransmit_buffered_messages(SSL *s);
5820f5
 static long dtls1_get_message_fragment(SSL *s, int st1, int stn, 
5820f5
-    long max, int *ok);
5820f5
-static void dtls1_process_handshake_fragment(SSL *s, int frag_len);
5820f5
+	long max, int *ok);
5820f5
 
5820f5
 static hm_fragment *
5820f5
 dtls1_hm_fragment_new(unsigned long frag_len)
5820f5
-    {
5820f5
-    hm_fragment *frag = NULL;
5820f5
-    unsigned char *buf = NULL;
5820f5
+	{
5820f5
+	hm_fragment *frag = NULL;
5820f5
+	unsigned char *buf = NULL;
5820f5
 
5820f5
-    frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
5820f5
-    if ( frag == NULL)
5820f5
-        return NULL;
5820f5
+	frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
5820f5
+	if ( frag == NULL)
5820f5
+		return NULL;
5820f5
 
5820f5
-    buf = (unsigned char *)OPENSSL_malloc(frag_len 
5820f5
-        + DTLS1_HM_HEADER_LENGTH);
5820f5
-    if ( buf == NULL)
5820f5
-        {
5820f5
-        OPENSSL_free(frag);
5820f5
-        return NULL;
5820f5
-        }
5820f5
-    
5820f5
-    frag->fragment = buf;
5820f5
+	if (frag_len)
5820f5
+		{
5820f5
+		buf = (unsigned char *)OPENSSL_malloc(frag_len);
5820f5
+		if ( buf == NULL)
5820f5
+			{
5820f5
+			OPENSSL_free(frag);
5820f5
+			return NULL;
5820f5
+			}
5820f5
+		}
5820f5
 
5820f5
-    return frag;
5820f5
-    }
5820f5
+	/* zero length fragment gets zero frag->fragment */
5820f5
+	frag->fragment = buf;
5820f5
+
5820f5
+	return frag;
5820f5
+	}
5820f5
 
5820f5
 static void
5820f5
 dtls1_hm_fragment_free(hm_fragment *frag)
5820f5
-    {
5820f5
-    OPENSSL_free(frag->fragment);
5820f5
-    OPENSSL_free(frag);
5820f5
-    }
5820f5
+	{
5820f5
+	if (frag->fragment) OPENSSL_free(frag->fragment);
5820f5
+	OPENSSL_free(frag);
5820f5
+	}
5820f5
 
5820f5
 /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
5820f5
 int dtls1_do_write(SSL *s, int type)
5820f5
@@ -180,7 +182,7 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 
5820f5
 	/* AHA!  Figure out the MTU, and stick to the right size */
5820f5
 	if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
5820f5
-        {
5820f5
+		{
5820f5
 		s->d1->mtu = 
5820f5
 			BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
5820f5
 
5820f5
@@ -207,7 +209,7 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 		mtu = curr_mtu;
5820f5
 	else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
5820f5
 		return ret;
5820f5
-		
5820f5
+
5820f5
 	if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
5820f5
 		{
5820f5
 		ret = BIO_flush(SSL_get_wbio(s));
5820f5
@@ -254,11 +256,11 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 				s->init_off -= DTLS1_HM_HEADER_LENGTH;
5820f5
 				s->init_num += DTLS1_HM_HEADER_LENGTH;
5820f5
 
5820f5
-                /* write atleast DTLS1_HM_HEADER_LENGTH bytes */
5820f5
+				/* write atleast DTLS1_HM_HEADER_LENGTH bytes */
5820f5
 				if ( len <= DTLS1_HM_HEADER_LENGTH)  
5820f5
 					len += DTLS1_HM_HEADER_LENGTH;
5820f5
 				}
5820f5
-			
5820f5
+
5820f5
 			dtls1_fix_message_header(s, frag_off, 
5820f5
 				len - DTLS1_HM_HEADER_LENGTH);
5820f5
 
5820f5
@@ -286,18 +288,40 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 			}
5820f5
 		else
5820f5
 			{
5820f5
-			
5820f5
+
5820f5
 			/* bad if this assert fails, only part of the handshake
5820f5
 			 * message got sent.  but why would this happen? */
5820f5
-			OPENSSL_assert(len == (unsigned int)ret); 
5820f5
-			
5820f5
+			OPENSSL_assert(len == (unsigned int)ret);
5820f5
+
5820f5
 			if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
5820f5
+				{
5820f5
 				/* should not be done for 'Hello Request's, but in that case
5820f5
 				 * we'll ignore the result anyway */
5820f5
-				ssl3_finish_mac(s, 
5820f5
-					(unsigned char *)&s->init_buf->data[s->init_off + 
5820f5
-						DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH);
5820f5
-			
5820f5
+				unsigned char *p = &s->init_buf->data[s->init_off];
5820f5
+				const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
5820f5
+				int len;
5820f5
+
5820f5
+				if (frag_off == 0 && s->client_version != DTLS1_BAD_VER)
5820f5
+					{
5820f5
+					/* reconstruct message header is if it
5820f5
+					 * is being sent in single fragment */
5820f5
+					*p++ = msg_hdr->type;
5820f5
+					l2n3(msg_hdr->msg_len,p);
5820f5
+					s2n (msg_hdr->seq,p);
5820f5
+					l2n3(0,p);
5820f5
+					l2n3(msg_hdr->msg_len,p);
5820f5
+					p  -= DTLS1_HM_HEADER_LENGTH;
5820f5
+					len = ret;
5820f5
+					}
5820f5
+				else
5820f5
+					{
5820f5
+					p  += DTLS1_HM_HEADER_LENGTH;
5820f5
+					len = ret - DTLS1_HM_HEADER_LENGTH;
5820f5
+					}
5820f5
+
5820f5
+				ssl3_finish_mac(s, p, len);
5820f5
+				}
5820f5
+
5820f5
 			if (ret == s->init_num)
5820f5
 				{
5820f5
 				if (s->msg_callback)
5820f5
@@ -307,7 +331,7 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 
5820f5
 				s->init_off = 0;  /* done writing this message */
5820f5
 				s->init_num = 0;
5820f5
-				
5820f5
+
5820f5
 				return(1);
5820f5
 				}
5820f5
 			s->init_off+=ret;
5820f5
@@ -327,6 +351,7 @@ int dtls1_do_write(SSL *s, int type)
5820f5
 long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
5820f5
 	{
5820f5
 	int i, al;
5820f5
+	struct hm_header_st *msg_hdr;
5820f5
 
5820f5
 	/* s3->tmp is used to store messages that are unexpected, caused
5820f5
 	 * by the absence of an optional handshake message */
5820f5
@@ -344,25 +369,56 @@ long dtls1_get_message(SSL *s, int st1, 
5820f5
 		s->init_num = (int)s->s3->tmp.message_size;
5820f5
 		return s->init_num;
5820f5
 		}
5820f5
-	
5820f5
+
5820f5
+	msg_hdr = &s->d1->r_msg_hdr;
5820f5
 	do
5820f5
 		{
5820f5
-		if ( s->d1->r_msg_hdr.frag_off == 0)
5820f5
+		if ( msg_hdr->frag_off == 0)
5820f5
 			{
5820f5
 			/* s->d1->r_message_header.msg_len = 0; */
5820f5
-			memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
5820f5
+			memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
5820f5
 			}
5820f5
 
5820f5
 		i = dtls1_get_message_fragment(s, st1, stn, max, ok);
5820f5
 		if ( i == DTLS1_HM_BAD_FRAGMENT ||
5820f5
-            i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
5820f5
+			i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
5820f5
 			continue;
5820f5
 		else if ( i <= 0 && !*ok)
5820f5
 			return i;
5820f5
 
5820f5
-		if (s->d1->r_msg_hdr.msg_len == (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
5820f5
+		/* Note that s->init_sum is used as a counter summing
5820f5
+		 * up fragments' lengths: as soon as they sum up to
5820f5
+		 * handshake packet length, we assume we have got all
5820f5
+		 * the fragments. Overlapping fragments would cause
5820f5
+		 * premature termination, so we don't expect overlaps.
5820f5
+		 * Well, handling overlaps would require something more
5820f5
+		 * drastic. Indeed, as it is now there is no way to
5820f5
+		 * tell if out-of-order fragment from the middle was
5820f5
+		 * the last. '>=' is the best/least we can do to control
5820f5
+		 * the potential damage caused by malformed overlaps. */
5820f5
+		if ((unsigned int)s->init_num >= msg_hdr->msg_len)
5820f5
 			{
5820f5
-			memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
5820f5
+			unsigned char *p = s->init_buf->data;
5820f5
+			unsigned long msg_len = msg_hdr->msg_len;
5820f5
+
5820f5
+			/* reconstruct message header as if it was
5820f5
+			 * sent in single fragment */
5820f5
+			*(p++) = msg_hdr->type;
5820f5
+			l2n3(msg_len,p);
5820f5
+			s2n (msg_hdr->seq,p);
5820f5
+			l2n3(0,p);
5820f5
+			l2n3(msg_len,p);
5820f5
+			if (s->client_version != DTLS1_BAD_VER)
5820f5
+				p       -= DTLS1_HM_HEADER_LENGTH,
5820f5
+				msg_len += DTLS1_HM_HEADER_LENGTH;
5820f5
+
5820f5
+			ssl3_finish_mac(s, p, msg_len);
5820f5
+			if (s->msg_callback)
5820f5
+				s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
5820f5
+					p, msg_len,
5820f5
+					s, s->msg_callback_arg);
5820f5
+
5820f5
+			memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
5820f5
 
5820f5
 			s->d1->handshake_read_seq++;
5820f5
 			/* we just read a handshake message from the other side:
5820f5
@@ -379,11 +435,11 @@ long dtls1_get_message(SSL *s, int st1, 
5820f5
 			 * first data  segment, but is there a better way?  */
5820f5
 			dtls1_clear_record_buffer(s);
5820f5
 
5820f5
-            s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
5820f5
-			return s->init_num - DTLS1_HM_HEADER_LENGTH;
5820f5
+			s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
5820f5
+			return s->init_num;
5820f5
 			}
5820f5
 		else
5820f5
-			s->d1->r_msg_hdr.frag_off = i;
5820f5
+			msg_hdr->frag_off = i;
5820f5
 		} while(1) ;
5820f5
 
5820f5
 f_err:
5820f5
@@ -393,161 +449,183 @@ f_err:
5820f5
 	}
5820f5
 
5820f5
 
5820f5
-static int
5820f5
-dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied)
5820f5
-    {
5820f5
-    /* (0) check whether the desired fragment is available
5820f5
-     * if so:
5820f5
-     * (1) copy over the fragment to s->init_buf->data[]
5820f5
-     * (2) update s->init_num
5820f5
-     */
5820f5
-    pitem *item;
5820f5
-    hm_fragment *frag;
5820f5
-    unsigned long overlap;
5820f5
-    unsigned char *p;
5820f5
-
5820f5
-    item = pqueue_peek(s->d1->buffered_messages);
5820f5
-    if ( item == NULL)
5820f5
-        return 0;
5820f5
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
5820f5
+	{
5820f5
+	size_t frag_off,frag_len,msg_len;
5820f5
 
5820f5
-    frag = (hm_fragment *)item->data;
5820f5
-    
5820f5
-    if ( s->d1->handshake_read_seq == frag->msg_header.seq &&
5820f5
-        frag->msg_header.frag_off <= (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
5820f5
-        {
5820f5
-        pqueue_pop(s->d1->buffered_messages);
5820f5
-        overlap = s->init_num - DTLS1_HM_HEADER_LENGTH 
5820f5
-            - frag->msg_header.frag_off;
5820f5
-
5820f5
-        p = frag->fragment;
5820f5
-
5820f5
-        memcpy(&s->init_buf->data[s->init_num],
5820f5
-            p + DTLS1_HM_HEADER_LENGTH + overlap,
5820f5
-            frag->msg_header.frag_len - overlap);
5820f5
-    
5820f5
-        OPENSSL_free(frag->fragment);
5820f5
-        OPENSSL_free(frag);
5820f5
-        pitem_free(item);
5820f5
+	msg_len  = msg_hdr->msg_len;
5820f5
+	frag_off = msg_hdr->frag_off;
5820f5
+	frag_len = msg_hdr->frag_len;
5820f5
 
5820f5
-        *copied = frag->msg_header.frag_len - overlap;
5820f5
-        return *copied;
5820f5
-        }
5820f5
-    else
5820f5
-        return 0;
5820f5
-    }
5820f5
+	/* sanity checking */
5820f5
+	if ( (frag_off+frag_len) > msg_len)
5820f5
+		{
5820f5
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
+		return SSL_AD_ILLEGAL_PARAMETER;
5820f5
+		}
5820f5
 
5820f5
+	if ( (frag_off+frag_len) > (unsigned long)max)
5820f5
+		{
5820f5
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
+		return SSL_AD_ILLEGAL_PARAMETER;
5820f5
+		}
5820f5
 
5820f5
-static int
5820f5
-dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr)
5820f5
-{
5820f5
-    hm_fragment *frag = NULL;
5820f5
-    pitem *item = NULL;
5820f5
-	PQ_64BIT seq64;
5820f5
+	if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
5820f5
+		{
5820f5
+		/* msg_len is limited to 2^24, but is effectively checked
5820f5
+		 * against max above */
5820f5
+		if (!BUF_MEM_grow_clean(s->init_buf,(int)msg_len+DTLS1_HM_HEADER_LENGTH))
5820f5
+			{
5820f5
+			SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
5820f5
+			return SSL_AD_INTERNAL_ERROR;
5820f5
+			}
5820f5
 
5820f5
-    frag = dtls1_hm_fragment_new(msg_hdr->frag_len);
5820f5
-    if ( frag == NULL)
5820f5
-        goto err;
5820f5
+		s->s3->tmp.message_size  = msg_len;
5820f5
+		s->d1->r_msg_hdr.msg_len = msg_len;
5820f5
+		s->s3->tmp.message_type  = msg_hdr->type;
5820f5
+		s->d1->r_msg_hdr.type    = msg_hdr->type;
5820f5
+		s->d1->r_msg_hdr.seq     = msg_hdr->seq;
5820f5
+		}
5820f5
+	else if (msg_len != s->d1->r_msg_hdr.msg_len)
5820f5
+		{
5820f5
+		/* They must be playing with us! BTW, failure to enforce
5820f5
+		 * upper limit would open possibility for buffer overrun. */
5820f5
+		SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
+		return SSL_AD_ILLEGAL_PARAMETER;
5820f5
+		}
5820f5
 
5820f5
-    memcpy(frag->fragment, &(s->init_buf->data[s->init_num]),
5820f5
-        msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH);
5820f5
+	return 0; /* no error */
5820f5
+	}
5820f5
 
5820f5
-    memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
5820f5
 
5820f5
-    pq_64bit_init(&seq64);
5820f5
-    pq_64bit_assign_word(&seq64, msg_hdr->seq);
5820f5
+static int
5820f5
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
5820f5
+	{
5820f5
+	/* (0) check whether the desired fragment is available
5820f5
+	 * if so:
5820f5
+	 * (1) copy over the fragment to s->init_buf->data[]
5820f5
+	 * (2) update s->init_num
5820f5
+	 */
5820f5
+	pitem *item;
5820f5
+	hm_fragment *frag;
5820f5
+	int al;
5820f5
 
5820f5
-    item = pitem_new(seq64, frag);
5820f5
-    if ( item == NULL)
5820f5
-        goto err;
5820f5
+	*ok = 0;
5820f5
+	item = pqueue_peek(s->d1->buffered_messages);
5820f5
+	if ( item == NULL)
5820f5
+		return 0;
5820f5
 
5820f5
-    pq_64bit_free(&seq64);
5820f5
+	frag = (hm_fragment *)item->data;
5820f5
 
5820f5
-    pqueue_insert(s->d1->buffered_messages, item);
5820f5
-    return 1;
5820f5
+	if ( s->d1->handshake_read_seq == frag->msg_header.seq)
5820f5
+		{
5820f5
+		pqueue_pop(s->d1->buffered_messages);
5820f5
 
5820f5
-err:
5820f5
-    if ( frag != NULL) dtls1_hm_fragment_free(frag);
5820f5
-    if ( item != NULL) OPENSSL_free(item);
5820f5
-    return 0;
5820f5
-}
5820f5
+		al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
5820f5
 
5820f5
+		if (al==0) /* no alert */
5820f5
+			{
5820f5
+			unsigned char *p = s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
5820f5
+			memcpy(&p[frag->msg_header.frag_off],
5820f5
+				frag->fragment,frag->msg_header.frag_len);
5820f5
+			}
5820f5
 
5820f5
-static void
5820f5
-dtls1_process_handshake_fragment(SSL *s, int frag_len)
5820f5
-    {
5820f5
-    unsigned char *p;
5820f5
+		dtls1_hm_fragment_free(frag);
5820f5
+		pitem_free(item);
5820f5
 
5820f5
-    p = (unsigned char *)s->init_buf->data;
5820f5
+		if (al==0)
5820f5
+			{
5820f5
+			*ok = 1;
5820f5
+			return frag->msg_header.frag_len;
5820f5
+			}
5820f5
 
5820f5
-	ssl3_finish_mac(s, &p[s->init_num - frag_len], frag_len);
5820f5
-    }
5820f5
+		ssl3_send_alert(s,SSL3_AL_FATAL,al);
5820f5
+		s->init_num = 0;
5820f5
+		*ok = 0;
5820f5
+		return -1;
5820f5
+		}
5820f5
+	else
5820f5
+		return 0;
5820f5
+	}
5820f5
 
5820f5
 
5820f5
 static int
5820f5
-dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st *msg_hdr, int *ok)
5820f5
-    {
5820f5
-    int i;
5820f5
-    unsigned char *p;
5820f5
-
5820f5
-    /* make sure there's enough room to read this fragment */
5820f5
-    if ( (int)msg_hdr->frag_len && !BUF_MEM_grow_clean(s->init_buf, 
5820f5
-             (int)msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH + s->init_num))
5820f5
-        {
5820f5
-        SSLerr(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE,ERR_R_BUF_LIB);
5820f5
-        goto err;
5820f5
-        }
5820f5
+dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
5820f5
+{
5820f5
+	int i=-1;
5820f5
+	hm_fragment *frag = NULL;
5820f5
+	pitem *item = NULL;
5820f5
+	PQ_64BIT seq64;
5820f5
+	unsigned long frag_len = msg_hdr->frag_len;
5820f5
 
5820f5
-    p = (unsigned char *)s->init_buf->data;
5820f5
+	if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
5820f5
+		goto err;
5820f5
 
5820f5
-    /* read the body of the fragment (header has already been read */
5820f5
-    if ( msg_hdr->frag_len > 0)
5820f5
+	if (msg_hdr->seq <= s->d1->handshake_read_seq)
5820f5
 		{
5820f5
-		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
5820f5
-            &p[s->init_num], 
5820f5
-            msg_hdr->frag_len,0);
5820f5
-		if (i <= 0)
5820f5
+		unsigned char devnull [256];
5820f5
+
5820f5
+		while (frag_len)
5820f5
 			{
5820f5
-			*ok = 0;
5820f5
-			return i;
5820f5
+			i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
5820f5
+				devnull,
5820f5
+				frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
5820f5
+			if (i<=0) goto err;
5820f5
+			frag_len -= i;
5820f5
 			}
5820f5
 		}
5820f5
 
5820f5
-    if ( msg_hdr->seq > s->d1->handshake_read_seq)
5820f5
-        dtls1_buffer_handshake_fragment(s, msg_hdr);
5820f5
-    else
5820f5
-        OPENSSL_assert(msg_hdr->seq < s->d1->handshake_read_seq);
5820f5
+	frag = dtls1_hm_fragment_new(frag_len);
5820f5
+	if ( frag == NULL)
5820f5
+		goto err;
5820f5
+
5820f5
+	memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
5820f5
+
5820f5
+	if (frag_len)
5820f5
+		{
5820f5
+		/* read the body of the fragment (header has already been read */
5820f5
+		i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
5820f5
+			frag->fragment,frag_len,0);
5820f5
+		if (i<=0 || i!=frag_len)
5820f5
+			goto err;
5820f5
+		}
5820f5
+
5820f5
+	pq_64bit_init(&seq64);
5820f5
+	pq_64bit_assign_word(&seq64, msg_hdr->seq);
5820f5
+
5820f5
+	item = pitem_new(seq64, frag);
5820f5
+	pq_64bit_free(&seq64);
5820f5
+	if ( item == NULL)
5820f5
+		goto err;
5820f5
+
5820f5
+	pqueue_insert(s->d1->buffered_messages, item);
5820f5
+	return DTLS1_HM_FRAGMENT_RETRY;
5820f5
 
5820f5
-    return DTLS1_HM_FRAGMENT_RETRY;
5820f5
 err:
5820f5
-    *ok = 0;
5820f5
-    return -1;
5820f5
-    }
5820f5
+	if ( frag != NULL) dtls1_hm_fragment_free(frag);
5820f5
+	if ( item != NULL) OPENSSL_free(item);
5820f5
+	*ok = 0;
5820f5
+	return i;
5820f5
+	}
5820f5
 
5820f5
 
5820f5
 static long
5820f5
 dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
5820f5
 	{
5820f5
-	unsigned char *p;
5820f5
+	unsigned char wire[DTLS1_HM_HEADER_LENGTH];
5820f5
 	unsigned long l, frag_off, frag_len;
5820f5
 	int i,al;
5820f5
 	struct hm_header_st msg_hdr;
5820f5
-    unsigned long overlap;
5820f5
-    
5820f5
-    /* see if we have the required fragment already */
5820f5
-    if (dtls1_retrieve_buffered_fragment(s, &l))
5820f5
-    {
5820f5
-        /* compute MAC, remove fragment headers */
5820f5
-        dtls1_process_handshake_fragment(s, l);
5820f5
-        s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
5820f5
-        s->state = stn;
5820f5
-        return 1;
5820f5
-    }
5820f5
 
5820f5
-    /* get a handshake fragment from the record layer */
5820f5
-	p = (unsigned char *)s->init_buf->data;
5820f5
+	/* see if we have the required fragment already */
5820f5
+	if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
5820f5
+		{
5820f5
+		if (*ok)	s->init_num += frag_len;
5820f5
+		return frag_len;
5820f5
+		}
5820f5
 
5820f5
-    /* read handshake message header */
5820f5
-	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
5820f5
+	/* read handshake message header */
5820f5
+	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
5820f5
 		DTLS1_HM_HEADER_LENGTH, 0);
5820f5
 	if (i <= 0) 	/* nbio, or an error */
5820f5
 		{
5820f5
@@ -555,130 +633,61 @@ dtls1_get_message_fragment(SSL *s, int s
5820f5
 		*ok = 0;
5820f5
 		return i;
5820f5
 		}
5820f5
-
5820f5
 	OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH);
5820f5
 
5820f5
-	p += s->init_num;
5820f5
-    /* parse the message fragment header */
5820f5
-    
5820f5
-    dtls1_get_message_header(p, &msg_hdr);
5820f5
+	/* parse the message fragment header */
5820f5
+	dtls1_get_message_header(wire, &msg_hdr);
5820f5
 
5820f5
-    /* 
5820f5
-     * if this is a future (or stale) message it gets buffered
5820f5
-     * (or dropped)--no further processing at this time 
5820f5
-     */
5820f5
-    if ( msg_hdr.seq != s->d1->handshake_read_seq)
5820f5
-        return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
5820f5
+	/* 
5820f5
+	 * if this is a future (or stale) message it gets buffered
5820f5
+	 * (or dropped)--no further processing at this time 
5820f5
+	 */
5820f5
+	if ( msg_hdr.seq != s->d1->handshake_read_seq)
5820f5
+		return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
5820f5
 
5820f5
-    l = msg_hdr.msg_len;
5820f5
-    frag_off = msg_hdr.frag_off;
5820f5
+	l = msg_hdr.msg_len;
5820f5
+	frag_off = msg_hdr.frag_off;
5820f5
 	frag_len = msg_hdr.frag_len;
5820f5
 
5820f5
-    /* sanity checking */
5820f5
-    if ( frag_off + frag_len > l)
5820f5
-        {
5820f5
-        al=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
-        goto f_err;
5820f5
-        }
5820f5
-
5820f5
 	if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
5820f5
-        p[0] == SSL3_MT_HELLO_REQUEST)
5820f5
-        {
5820f5
-        /* The server may always send 'Hello Request' messages --
5820f5
-         * we are doing a handshake anyway now, so ignore them
5820f5
-         * if their format is correct. Does not count for
5820f5
-         * 'Finished' MAC. */
5820f5
-        if (p[1] == 0 && p[2] == 0 &&p[3] == 0)
5820f5
-            {
5820f5
-            if (s->msg_callback)
5820f5
-                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
5820f5
-                    p, DTLS1_HM_HEADER_LENGTH, s, 
5820f5
-                    s->msg_callback_arg);
5820f5
-            
5820f5
-            s->init_num = 0;
5820f5
-            return dtls1_get_message_fragment(s, st1, stn,
5820f5
-                max, ok);
5820f5
-            }
5820f5
-        else /* Incorrectly formated Hello request */
5820f5
-            {
5820f5
-            al=SSL_AD_UNEXPECTED_MESSAGE;
5820f5
-            SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
5820f5
-            goto f_err;
5820f5
-            }
5820f5
-        }
5820f5
-
5820f5
-    /* XDTLS: do a sanity check on the fragment */
5820f5
-
5820f5
-    s->init_num += i;
5820f5
-
5820f5
-	if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
5820f5
+		wire[0] == SSL3_MT_HELLO_REQUEST)
5820f5
 		{
5820f5
-		/* BUF_MEM_grow takes an 'int' parameter */
5820f5
-		if (l > (INT_MAX-DTLS1_HM_HEADER_LENGTH)) 
5820f5
+		/* The server may always send 'Hello Request' messages --
5820f5
+		 * we are doing a handshake anyway now, so ignore them
5820f5
+		 * if their format is correct. Does not count for
5820f5
+		 * 'Finished' MAC. */
5820f5
+		if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
5820f5
 			{
5820f5
-			al=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
-			goto f_err;
5820f5
-			}
5820f5
-		if (l && !BUF_MEM_grow_clean(s->init_buf,(int)l
5820f5
-			+ DTLS1_HM_HEADER_LENGTH))
5820f5
-			{
5820f5
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
5820f5
-			goto err;
5820f5
+			if (s->msg_callback)
5820f5
+				s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
5820f5
+					wire, DTLS1_HM_HEADER_LENGTH, s, 
5820f5
+					s->msg_callback_arg);
5820f5
+			
5820f5
+			s->init_num = 0;
5820f5
+			return dtls1_get_message_fragment(s, st1, stn,
5820f5
+				max, ok);
5820f5
 			}
5820f5
-        /* Only do this test when we're reading the expected message.
5820f5
-         * Stale messages will be dropped and future messages will be buffered */
5820f5
-        if ( l > (unsigned long)max)
5820f5
+		else /* Incorrectly formated Hello request */
5820f5
 			{
5820f5
-			al=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
+			al=SSL_AD_UNEXPECTED_MESSAGE;
5820f5
+			SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
5820f5
 			goto f_err;
5820f5
 			}
5820f5
-
5820f5
-		s->s3->tmp.message_size=l;
5820f5
 		}
5820f5
 
5820f5
-    if ( frag_len > (unsigned long)max)
5820f5
-        {
5820f5
-        al=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
-        goto f_err;
5820f5
-        }
5820f5
-    if ( frag_len + s->init_num > (INT_MAX - DTLS1_HM_HEADER_LENGTH))
5820f5
-        {
5820f5
-        al=SSL_AD_ILLEGAL_PARAMETER;
5820f5
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
5820f5
-        goto f_err;
5820f5
-        }
5820f5
-
5820f5
-    if ( frag_len & !BUF_MEM_grow_clean(s->init_buf, (int)frag_len 
5820f5
-             + DTLS1_HM_HEADER_LENGTH + s->init_num))
5820f5
-        {
5820f5
-        SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
5820f5
-        goto err;
5820f5
-        }
5820f5
-
5820f5
-	if ( s->d1->r_msg_hdr.frag_off == 0)
5820f5
-		{
5820f5
-		s->s3->tmp.message_type = msg_hdr.type;
5820f5
-		s->d1->r_msg_hdr.type = msg_hdr.type;
5820f5
-		s->d1->r_msg_hdr.msg_len = l;
5820f5
-		/* s->d1->r_msg_hdr.seq = seq_num; */
5820f5
-		}
5820f5
+	if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
5820f5
+		goto f_err;
5820f5
 
5820f5
 	/* XDTLS:  ressurect this when restart is in place */
5820f5
 	s->state=stn;
5820f5
-	
5820f5
-	/* next state (stn) */
5820f5
-	p = (unsigned char *)s->init_buf->data;
5820f5
 
5820f5
 	if ( frag_len > 0)
5820f5
 		{
5820f5
+		unsigned char *p=s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
5820f5
+
5820f5
 		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
5820f5
-            &p[s->init_num], 
5820f5
-            frag_len,0);
5820f5
-        /* XDTLS:  fix this--message fragments cannot span multiple packets */
5820f5
+			&p[frag_off],frag_len,0);
5820f5
+		/* XDTLS:  fix this--message fragments cannot span multiple packets */
5820f5
 		if (i <= 0)
5820f5
 			{
5820f5
 			s->rwstate=SSL_READING;
5820f5
@@ -689,70 +698,23 @@ dtls1_get_message_fragment(SSL *s, int s
5820f5
 	else
5820f5
 		i = 0;
5820f5
 
5820f5
-    /* XDTLS:  an incorrectly formatted fragment should cause the 
5820f5
-     * handshake to fail */
5820f5
+	/* XDTLS:  an incorrectly formatted fragment should cause the 
5820f5
+	 * handshake to fail */
5820f5
 	OPENSSL_assert(i == (int)frag_len);
5820f5
 
5820f5
-#if 0
5820f5
-    /* Successfully read a fragment.
5820f5
-     * It may be (1) out of order, or
5820f5
-     *           (2) it's a repeat, in which case we dump it
5820f5
-     *           (3) the one we are expecting next (maybe with overlap)
5820f5
-     * If it is next one, it may overlap with previously read bytes
5820f5
-     */
5820f5
+	*ok = 1;
5820f5
 
5820f5
-    /* case (1): buffer the future fragment 
5820f5
-     * (we can treat fragments from a future message the same
5820f5
-     * as future fragments from the message being currently read, since
5820f5
-     * they are sematically simply out of order.
5820f5
-     */
5820f5
-    if ( msg_hdr.seq > s->d1->handshake_read_seq ||
5820f5
-        frag_off > s->init_num - DTLS1_HM_HEADER_LENGTH)
5820f5
-    {
5820f5
-        dtls1_buffer_handshake_fragment(s, &msg_hdr);
5820f5
-        return DTLS1_HM_FRAGMENT_RETRY;
5820f5
-    }
5820f5
-
5820f5
-    /* case (2):  drop the entire fragment, and try again */
5820f5
-    if ( msg_hdr.seq < s->d1->handshake_read_seq ||
5820f5
-        frag_off + frag_len < s->init_num - DTLS1_HM_HEADER_LENGTH)
5820f5
-        {
5820f5
-        s->init_num -= DTLS1_HM_HEADER_LENGTH;
5820f5
-        return DTLS1_HM_FRAGMENT_RETRY;
5820f5
-        }
5820f5
-#endif
5820f5
-
5820f5
-    /* case (3): received a immediately useful fragment.  Determine the 
5820f5
-     * possible overlap and copy the fragment.
5820f5
-     */
5820f5
-    overlap = (s->init_num - DTLS1_HM_HEADER_LENGTH) - frag_off;
5820f5
-        
5820f5
-    /* retain the header for the first fragment */
5820f5
-    if ( s->init_num > DTLS1_HM_HEADER_LENGTH)
5820f5
-        {
5820f5
-        memmove(&(s->init_buf->data[s->init_num]),
5820f5
-            &(s->init_buf->data[s->init_num + DTLS1_HM_HEADER_LENGTH + overlap]),
5820f5
-            frag_len - overlap);
5820f5
-
5820f5
-        s->init_num += frag_len - overlap;
5820f5
-        }
5820f5
-    else
5820f5
-        s->init_num += frag_len;
5820f5
-
5820f5
-    dtls1_process_handshake_fragment(s, frag_len - overlap);
5820f5
-
5820f5
-	if (s->msg_callback)
5820f5
-		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, 
5820f5
-			(size_t)s->init_num, s, 
5820f5
-			s->msg_callback_arg);
5820f5
-	*ok=1;
5820f5
-
5820f5
-	return s->init_num;
5820f5
+	/* Note that s->init_num is *not* used as current offset in
5820f5
+	 * s->init_buf->data, but as a counter summing up fragments'
5820f5
+	 * lengths: as soon as they sum up to handshake packet
5820f5
+	 * length, we assume we have got all the fragments. */
5820f5
+	s->init_num += frag_len;
5820f5
+	return frag_len;
5820f5
 
5820f5
 f_err:
5820f5
 	ssl3_send_alert(s,SSL3_AL_FATAL,al);
5820f5
-    s->init_num = 0;
5820f5
-err:
5820f5
+	s->init_num = 0;
5820f5
+
5820f5
 	*ok=0;
5820f5
 	return(-1);
5820f5
 	}
5820f5
@@ -790,7 +752,7 @@ int dtls1_send_finished(SSL *s, int a, i
5820f5
 
5820f5
 		/* buffer the message to handle re-xmits */
5820f5
 		dtls1_buffer_message(s, 0);
5820f5
-		
5820f5
+
5820f5
 		s->state=b;
5820f5
 		}
5820f5
 
5820f5
@@ -815,10 +777,15 @@ int dtls1_send_change_cipher_spec(SSL *s
5820f5
 		p=(unsigned char *)s->init_buf->data;
5820f5
 		*p++=SSL3_MT_CCS;
5820f5
 		s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
5820f5
-		s->d1->next_handshake_write_seq++;
5820f5
-		s2n(s->d1->handshake_write_seq,p);
5820f5
-
5820f5
 		s->init_num=DTLS1_CCS_HEADER_LENGTH;
5820f5
+
5820f5
+		if (s->client_version == DTLS1_BAD_VER)
5820f5
+			{
5820f5
+			s->d1->next_handshake_write_seq++;
5820f5
+			s2n(s->d1->handshake_write_seq,p);
5820f5
+			s->init_num+=2;
5820f5
+			}
5820f5
+
5820f5
 		s->init_off=0;
5820f5
 
5820f5
 		dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, 
5820f5
@@ -1044,6 +1011,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
5820f5
     pitem *item;
5820f5
     hm_fragment *frag;
5820f5
 	PQ_64BIT seq64;
5820f5
+	unsigned int epoch = s->d1->w_epoch;
5820f5
 
5820f5
     /* this function is called immediately after a message has 
5820f5
      * been serialized */
5820f5
@@ -1056,7 +1024,8 @@ dtls1_buffer_message(SSL *s, int is_ccs)
5820f5
     if ( is_ccs)
5820f5
         {
5820f5
         OPENSSL_assert(s->d1->w_msg_hdr.msg_len + 
5820f5
-            DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num);
5820f5
+            DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num);
5820f5
+	epoch++;
5820f5
         }
5820f5
     else
5820f5
         {
5820f5
@@ -1072,7 +1041,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
5820f5
     frag->msg_header.is_ccs = is_ccs;
5820f5
 
5820f5
     pq_64bit_init(&seq64);
5820f5
-    pq_64bit_assign_word(&seq64, frag->msg_header.seq);
5820f5
+    pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq);
5820f5
 
5820f5
     item = pitem_new(seq64, frag);
5820f5
     pq_64bit_free(&seq64);
5820f5
@@ -1259,5 +1228,4 @@ dtls1_get_ccs_header(unsigned char *data
5820f5
     memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
5820f5
     
5820f5
     ccs_hdr->type = *(data++);
5820f5
-    n2s(data, ccs_hdr->seq);
5820f5
 }
5820f5
diff -up openssl-fips-0.9.8f-dev/ssl/d1_clnt.c.dtls-fixes openssl-fips-0.9.8f-dev/ssl/d1_clnt.c
5820f5
--- openssl-fips-0.9.8f-dev/ssl/d1_clnt.c.dtls-fixes	2005-12-05 18:32:19.000000000 +0100
5820f5
+++ openssl-fips-0.9.8f-dev/ssl/d1_clnt.c	2008-07-15 21:01:29.000000000 +0200
5820f5
@@ -214,17 +214,21 @@ int dtls1_connect(SSL *s)
5820f5
 
5820f5
 			/* don't push the buffering BIO quite yet */
5820f5
 
5820f5
-			ssl3_init_finished_mac(s);
5820f5
-
5820f5
 			s->state=SSL3_ST_CW_CLNT_HELLO_A;
5820f5
 			s->ctx->stats.sess_connect++;
5820f5
 			s->init_num=0;
5820f5
+			/* mark client_random uninitialized */
5820f5
+			memset(s->s3->client_random,0,sizeof(s->s3->client_random));
5820f5
 			break;
5820f5
 
5820f5
 		case SSL3_ST_CW_CLNT_HELLO_A:
5820f5
 		case SSL3_ST_CW_CLNT_HELLO_B:
5820f5
 
5820f5
 			s->shutdown=0;
5820f5
+
5820f5
+			/* every DTLS ClientHello resets Finished MAC */
5820f5
+			ssl3_init_finished_mac(s);
5820f5
+
5820f5
 			ret=dtls1_client_hello(s);
5820f5
 			if (ret <= 0) goto end;
5820f5
 
5820f5
@@ -422,6 +426,9 @@ int dtls1_connect(SSL *s)
5820f5
 				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
5820f5
 				}
5820f5
 			s->init_num=0;
5820f5
+			/* mark client_random uninitialized */
5820f5
+			memset (s->s3->client_random,0,sizeof(s->s3->client_random));
5820f5
+
5820f5
 			break;
5820f5
 
5820f5
 		case SSL3_ST_CR_FINISHED_A:
5820f5
@@ -544,9 +551,15 @@ int dtls1_client_hello(SSL *s)
5820f5
 		/* else use the pre-loaded session */
5820f5
 
5820f5
 		p=s->s3->client_random;
5820f5
-		Time=(unsigned long)time(NULL);			/* Time */
5820f5
-		l2n(Time,p);
5820f5
-		RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
5820f5
+		/* if client_random is initialized, reuse it, we are
5820f5
+		 * required to use same upon reply to HelloVerify */
5820f5
+		for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) ;
5820f5
+		if (i==sizeof(s->s3->client_random))
5820f5
+			{
5820f5
+			Time=(unsigned long)time(NULL);	/* Time */
5820f5
+			l2n(Time,p);
5820f5
+			RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4);
5820f5
+			}
5820f5
 
5820f5
 		/* Do the message type and length last */
5820f5
 		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);