--- apps/s_apps.h	22 Dec 2008 14:05:42 -0000	1.21
+++ apps/s_apps.h	3 Sep 2009 08:38:04 -0000
@@ -171,3 +171,6 @@
 					unsigned char *data, int len,
 					void *arg);
 #endif
+
+int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len);
+int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len);

--- apps/s_cb.c	2 Sep 2009 12:45:19 -0000	1.27.2.2
+++ apps/s_cb.c	3 Sep 2009 08:38:04 -0000
@@ -121,9 +121,13 @@
 #include <openssl/ssl.h>
 #include "s_apps.h"
 
+#define	COOKIE_SECRET_LENGTH	16
+
 int verify_depth=0;
 int verify_error=X509_V_OK;
 int verify_return_error=0;
+unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
+int cookie_initialized=0;
 
 int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx)
 	{
@@ -682,3 +686,93 @@
 	BIO_dump(bio, (char *)data, len);
 	(void)BIO_flush(bio);
 	}
+
+int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
+	{
+	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
+	unsigned int length, resultlength;
+	struct sockaddr_in peer;
+	
+	/* Initialize a random secret */
+	if (!cookie_initialized)
+		{
+		if (!RAND_bytes((unsigned char*) cookie_secret, COOKIE_SECRET_LENGTH))
+			{
+			BIO_printf(bio_err,"error setting random cookie secret\n");
+			return 0;
+			}
+		cookie_initialized = 1;
+		}
+
+	/* Read peer information */
+	BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
+
+	/* Create buffer with peer's address and port */
+	length = sizeof(peer.sin_addr);
+	length += sizeof(peer.sin_port);
+	buffer = OPENSSL_malloc(length);
+
+	if (buffer == NULL)
+		{
+		BIO_printf(bio_err,"out of memory\n");
+		return 0;
+		}
+	
+	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
+	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));
+
+	/* Calculate HMAC of buffer using the secret */
+	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer,
+	     length, (unsigned char*) &result, &resultlength);
+	OPENSSL_free(buffer);
+
+	memcpy(cookie, result, resultlength);
+	*cookie_len = resultlength;
+
+	return 1;
+	}
+
+int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)
+	{
+	unsigned char *buffer, result[EVP_MAX_MD_SIZE];
+	unsigned int length, resultlength;
+	struct sockaddr_in peer;
+	
+	/* Initialize a random secret */
+	if (!cookie_initialized)
+		{
+		if (!RAND_bytes((unsigned char*) cookie_secret, COOKIE_SECRET_LENGTH))
+			{
+			BIO_printf(bio_err,"error setting random cookie secret\n");
+			return 0;
+			}
+		cookie_initialized = 1;
+		}
+
+	/* Read peer information */
+	BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer);
+
+	/* Create buffer with peer's address and port */
+	length = sizeof(peer.sin_addr);
+	length += sizeof(peer.sin_port);
+	buffer = OPENSSL_malloc(length);
+	
+	if (buffer == NULL)
+		{
+		BIO_printf(bio_err,"out of memory\n");
+		return 0;
+		}
+	
+	memcpy(buffer, &peer.sin_addr, sizeof(peer.sin_addr));
+	memcpy(buffer + sizeof(peer.sin_addr), &peer.sin_port, sizeof(peer.sin_port));
+
+	/* Calculate HMAC of buffer using the secret */
+	HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, buffer,
+	     length, (unsigned char*) &result, &resultlength);
+	OPENSSL_free(buffer);
+	
+	if (cookie_len == resultlength && memcmp(&result, cookie, resultlength) == 0)
+		return 1;
+
+	return 0;
+	}

--- apps/s_server.c	18 Aug 2009 11:14:12 -0000	1.136.2.7
+++ apps/s_server.c	3 Sep 2009 08:38:04 -0000
@@ -1654,6 +1654,10 @@
 	SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,
 		sizeof s_server_session_id_context);
 
+	/* Set DTLS cookie generation and verification callbacks */
+	SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback);
+	SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback);
+
 #ifndef OPENSSL_NO_TLSEXT
 	if (ctx2)
 		{

--- crypto/bio/bio.h	24 Jul 2009 11:24:45 -0000	1.76.2.4
+++ crypto/bio/bio.h	3 Sep 2009 08:38:04 -0000
@@ -157,6 +157,7 @@
 					      * previous write
 					      * operation */
 
+#define BIO_CTRL_DGRAM_GET_PEER           46
 #define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the data */
 
 #define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   45 /* Next DTLS handshake timeout to
@@ -538,6 +539,8 @@
          (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
 #define BIO_dgram_send_timedout(b) \
          (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
+#define BIO_dgram_get_peer(b,peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)peer)
 #define BIO_dgram_set_peer(b,peer) \
          (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)
 

--- crypto/bio/bss_dgram.c	26 Aug 2009 15:13:43 -0000	1.7.2.16
+++ crypto/bio/bss_dgram.c	3 Sep 2009 08:38:04 -0000
@@ -290,11 +290,11 @@
 		ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen);
 		dgram_reset_rcv_timeout(b);
 
-		if ( ! data->connected  && ret > 0)
-			BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer);
+		if ( ! data->connected  && ret >= 0)
+			BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
 
 		BIO_clear_retry_flags(b);
-		if (ret <= 0)
+		if (ret < 0)
 			{
 			if (BIO_dgram_should_retry(ret))
 				{
@@ -518,6 +518,12 @@
 			memset(&(data->peer), 0x00, sizeof(struct sockaddr));
 			}
 		break;
+    case BIO_CTRL_DGRAM_GET_PEER:
+        to = (struct sockaddr *) ptr;
+
+        memcpy(to, &(data->peer), sizeof(struct sockaddr));
+		ret = sizeof(struct sockaddr);
+        break;
     case BIO_CTRL_DGRAM_SET_PEER:
         to = (struct sockaddr *) ptr;
 

--- ssl/d1_srvr.c	5 Jun 2009 14:46:49 -0000	1.20.2.6
+++ ssl/d1_srvr.c	3 Sep 2009 08:38:06 -0000
@@ -238,11 +238,6 @@
 				s->state=SSL3_ST_SW_HELLO_REQ_A;
 				}
 
-			if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
-				s->d1->send_cookie = 1;
-			else
-				s->d1->send_cookie = 0;
-			
 			break;
 
 		case SSL3_ST_SW_HELLO_REQ_A:
@@ -273,7 +268,7 @@
 			dtls1_stop_timer(s);
 			s->new_session = 2;
 
-			if (s->d1->send_cookie)
+			if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
 				s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
 			else
 				s->state = SSL3_ST_SW_SRVR_HELLO_A;
@@ -287,7 +282,6 @@
 			dtls1_start_timer(s);
 			ret = dtls1_send_hello_verify_request(s);
 			if ( ret <= 0) goto end;
-			s->d1->send_cookie = 0;
 			s->state=SSL3_ST_SW_FLUSH;
 			s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
 
@@ -670,15 +664,13 @@
 		*(p++) = s->version >> 8;
 		*(p++) = s->version & 0xFF;
 
-		if (s->ctx->app_gen_cookie_cb != NULL &&
-		    s->ctx->app_gen_cookie_cb(s, s->d1->cookie, 
-			&(s->d1->cookie_len)) == 0)
+		if (s->ctx->app_gen_cookie_cb == NULL ||
+		     s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+			 &(s->d1->cookie_len)) == 0)
 			{
 			SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
 			return 0;
 			}
-		/* 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);

--- ssl/dtls1.h	25 Aug 2009 07:10:09 -0000	1.12.2.13
+++ ssl/dtls1.h	3 Sep 2009 08:38:06 -0000
@@ -88,7 +88,7 @@
 #endif
 
 /* lengths of messages */
-#define DTLS1_COOKIE_LENGTH                     32
+#define DTLS1_COOKIE_LENGTH                     256
 
 #define DTLS1_RT_HEADER_LENGTH                  13
 

--- ssl/s3_srvr.c	26 Jun 2009 15:04:22 -0000	1.171.2.7
+++ ssl/s3_srvr.c	3 Sep 2009 08:38:06 -0000
@@ -816,6 +816,21 @@
 		goto f_err;
 		}
 
+	/* If we require cookies and this ClientHello doesn't
+	 * contain one, just return since we do not want to
+	 * allocate any memory yet. So check cookie length...
+	 */
+	if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
+		{
+		unsigned int session_length, cookie_length;
+		
+		session_length = *(p + SSL3_RANDOM_SIZE);
+		cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
+
+		if (cookie_len == 0)
+			return 1;
+		}
+
 	/* load the client random */
 	memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
 	p+=SSL3_RANDOM_SIZE;
@@ -855,23 +870,11 @@
 
 	p+=j;
 
-	if (s->version == DTLS1_VERSION)
+	if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
 		{
 		/* cookie stuff */
 		cookie_len = *(p++);
 
-		if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
-			s->d1->send_cookie == 0)
-			{
-			/* HelloVerifyMessage has already been sent */
-			if ( cookie_len != s->d1->cookie_len)
-				{
-				al = SSL_AD_HANDSHAKE_FAILURE;
-				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
-				goto f_err;
-				}
-			}
-
 		/* 
 		 * The ClientHello may contain a cookie even if the
 		 * HelloVerify message has not been sent--make sure that it
@@ -886,7 +889,7 @@
 			}
 
 		/* verify the cookie if appropriate option is set. */
-		if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+		if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
 			cookie_len > 0)
 			{
 			memcpy(s->d1->rcvd_cookie, p, cookie_len);
@@ -911,6 +914,8 @@
 						SSL_R_COOKIE_MISMATCH);
 					goto f_err;
 				}
+
+			ret = 2;
 			}
 
 		p += cookie_len;
@@ -1185,7 +1190,7 @@
 	 * s->tmp.new_cipher	- the new cipher to use.
 	 */
 
-	ret=1;
+	if (ret < 0) ret=1;
 	if (0)
 		{
 f_err:

--- ssl/t1_lib.c	28 Apr 2009 22:01:53 -0000	1.64.2.1
+++ ssl/t1_lib.c	3 Sep 2009 08:38:06 -0000
@@ -1444,6 +1444,14 @@
 		return 1;
 	if (p >= limit)
 		return -1;
+	/* Skip past DTLS cookie */
+	if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+		{
+		i = *(p++);
+		p+= i;
+		if (p >= limit)
+			return -1;
+		}
 	/* Skip past cipher list */
 	n2s(p, i);
 	p+= i;
