Add DTLS support.
diff --git a/.cvsignore b/.cvsignore
index 5f6ae0c..a7a20fc 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,5 +1,4 @@
 openssl.pc
-Makefile.ssl
 MINFO
 makefile.one
 tmp
@@ -16,3 +15,4 @@
 libssl.so.*
 *.flc
 semantic.cache
+Makefile
diff --git a/CHANGES b/CHANGES
index 25b0b6b..f75ddd9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
 
  Changes between 0.9.7g and 0.9.8  [xx XXX xxxx]
 
+  *) Add support for DTLS.
+     [Nagendra Modadugu <nagendra@cs.stanford.edu> and Ben Laurie]
+
   *) Add support for DER encoded private keys (SSL_FILETYPE_ASN1)
      to SSL_CTX_use_PrivateKey_file() and SSL_use_PrivateKey_file()
      [Walter Goulet]
diff --git a/Configure b/Configure
index 442e19a..316d309 100755
--- a/Configure
+++ b/Configure
@@ -515,6 +515,7 @@
 "rhapsody-ppc-cc","cc:-O3 -DB_ENDIAN::(unknown):MACOSX_RHAPSODY::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::",
 "darwin-ppc-cc","cc:-O3 -DB_ENDIAN::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::osx_ppc32.o:::::::::::darwin-shared:-fPIC -fno-common::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
 "darwin-i386-cc","cc:-O3 -fomit-frame-pointer -fno-common -DB_ENDIAN::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:${no_asm}::darwin-shared:-fPIC::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
+"debug-darwin-ppc-cc","cc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DCRYPTO_MDEBUG -DB_ENDIAN -g -Wall -O::-D_REENTRANT:MACOSX::BN_LLONG RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR::osx_ppc32.o:::::::::::darwin-shared:-fPIC::.\$(SHLIB_MAJOR).\$(SHLIB_MINOR).dylib",
 
 ##### A/UX
 "aux3-gcc","gcc:-O2 -DTERMIO::(unknown):AUX:-lbsd:RC4_CHAR RC4_CHUNK DES_UNROLL BF_PTR:::",
diff --git a/Makefile.org b/Makefile.org
index b6fbc99..528ca3b 100644
--- a/Makefile.org
+++ b/Makefile.org
@@ -111,7 +111,7 @@
 	bn ec rsa dsa ecdsa dh ecdh dso engine \
 	buffer bio stack lhash rand err \
 	evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui krb5 \
-	store
+	store pqueue
 
 # tests to perform.  "alltests" is a special word indicating that all tests
 # should be performed.
diff --git a/apps/s_apps.h b/apps/s_apps.h
index ca5caac..bb48244 100644
--- a/apps/s_apps.h
+++ b/apps/s_apps.h
@@ -148,7 +148,7 @@
 #define PORT_STR        "4433"
 #define PROTOCOL        "tcp"
 
-int do_server(int port, int *ret, int (*cb) (char *hostname, int s, unsigned char *context), char *context);
+int do_server(int port, int type, int *ret, int (*cb) (char *hostname, int s, unsigned char *context), char *context);
 #ifdef HEADER_X509_H
 int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx);
 #endif
@@ -156,7 +156,7 @@
 int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file);
 int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key);
 #endif
-int init_client(int *sock, char *server, int port);
+int init_client(int *sock, char *server, int port, int type);
 int should_retry(int i);
 int extract_port(char *str, short *port_ptr);
 int extract_host_port(char *str,char **host_ptr,unsigned char *ip,short *p);
diff --git a/apps/s_client.c b/apps/s_client.c
index d5c0a4f..2f0f568 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -135,6 +135,7 @@
 #include <openssl/pem.h>
 #include <openssl/rand.h>
 #include "s_apps.h"
+#include "timeouts.h"
 
 #ifdef OPENSSL_SYS_WINCE
 /* Windows CE incorrectly defines fileno as returning void*, so to avoid problems below... */
@@ -215,6 +216,8 @@
 	BIO_printf(bio_err," -ssl2         - just use SSLv2\n");
 	BIO_printf(bio_err," -ssl3         - just use SSLv3\n");
 	BIO_printf(bio_err," -tls1         - just use TLSv1\n");
+	BIO_printf(bio_err," -dtls1        - just use DTLSv1\n");    
+	BIO_printf(bio_err," -mtu          - set the MTU\n");
 	BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n");
 	BIO_printf(bio_err," -bugs         - Switch on all SSL implementation bug workarounds\n");
 	BIO_printf(bio_err," -serverpref   - Use server's cipher preferences (only SSLv2)\n");
@@ -260,6 +263,7 @@
 	int starttls_proto = 0;
 	int prexit = 0, vflags = 0;
 	SSL_METHOD *meth=NULL;
+	int sock_type=SOCK_STREAM;
 	BIO *sbio;
 	char *inrand=NULL;
 #ifndef OPENSSL_NO_ENGINE
@@ -270,6 +274,11 @@
 	struct timeval tv;
 #endif
 
+	struct sockaddr peer;
+	int peerlen = sizeof(peer);
+	int enable_timeouts = 0 ;
+	long mtu = 0;
+
 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
 	meth=SSLv23_client_method();
 #elif !defined(OPENSSL_NO_SSL3)
@@ -387,6 +396,20 @@
 		else if	(strcmp(*argv,"-tls1") == 0)
 			meth=TLSv1_client_method();
 #endif
+#ifndef OPENSSL_NO_DTLS1
+		else if	(strcmp(*argv,"-dtls1") == 0)
+			{
+			meth=DTLSv1_client_method();
+			sock_type=SOCK_DGRAM;
+			}
+		else if (strcmp(*argv,"-timeout") == 0)
+			enable_timeouts=1;
+		else if (strcmp(*argv,"-mtu") == 0)
+			{
+			if (--argc < 1) goto bad;
+			mtu = atol(*(++argv));
+			}
+#endif
 		else if (strcmp(*argv,"-bugs") == 0)
 			bugs=1;
 		else if	(strcmp(*argv,"-keyform") == 0)
@@ -550,6 +573,10 @@
 		SSL_CTX_set_options(ctx,SSL_OP_ALL|off);
 	else
 		SSL_CTX_set_options(ctx,off);
+	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
+	 * Setting read ahead solves this problem.
+	 */
+	if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
 
 	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
 	if (cipher != NULL)
@@ -589,7 +616,7 @@
 
 re_start:
 
-	if (init_client(&s,host,port) == 0)
+	if (init_client(&s,host,port,sock_type) == 0)
 		{
 		BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error());
 		SHUTDOWN(s);
@@ -610,7 +637,46 @@
 		}
 #endif                                              
 	if (c_Pause & 0x01) con->debug=1;
-	sbio=BIO_new_socket(s,BIO_NOCLOSE);
+
+	if ( SSL_version(con) == DTLS1_VERSION)
+		{
+		struct timeval timeout;
+
+		sbio=BIO_new_dgram(s,BIO_NOCLOSE);
+		if (getsockname(s, &peer, &peerlen) < 0)
+			{
+			BIO_printf(bio_err, "getsockname:errno=%d\n",
+				get_last_socket_error());
+			SHUTDOWN(s);
+			goto end;
+			}
+
+		BIO_ctrl_set_connected(sbio, 1, &peer);
+
+		if ( enable_timeouts)
+			{
+			timeout.tv_sec = 0;
+			timeout.tv_usec = DGRAM_RCV_TIMEOUT;
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
+			
+			timeout.tv_sec = 0;
+			timeout.tv_usec = DGRAM_SND_TIMEOUT;
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
+			}
+
+		if ( mtu > 0)
+			{
+			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
+			SSL_set_mtu(con, mtu);
+			}
+		else
+			/* want to do MTU discovery */
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
+		}
+	else
+		sbio=BIO_new_socket(s,BIO_NOCLOSE);
+
+
 
 	if (nbio_test)
 		{
diff --git a/apps/s_server.c b/apps/s_server.c
index 40d00cc..059c4a0 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -154,6 +154,7 @@
 #include <openssl/ssl.h>
 #include <openssl/rand.h>
 #include "s_apps.h"
+#include "timeouts.h"
 
 #ifdef OPENSSL_SYS_WINCE
 /* Windows CE incorrectly defines fileno as returning void*, so to avoid problems below... */
@@ -260,6 +261,11 @@
 #endif
 static const char *session_id_prefix=NULL;
 
+static int enable_timeouts = 0;
+static long mtu;
+static int cert_chain = 0;
+
+
 #ifdef MONOLITH
 static void s_server_init(void)
 	{
@@ -333,6 +339,10 @@
 	BIO_printf(bio_err," -ssl2         - Just talk SSLv2\n");
 	BIO_printf(bio_err," -ssl3         - Just talk SSLv3\n");
 	BIO_printf(bio_err," -tls1         - Just talk TLSv1\n");
+	BIO_printf(bio_err," -dtls1        - Just talk DTLSv1\n");
+	BIO_printf(bio_err," -timeout      - Enable timeouts\n");
+	BIO_printf(bio_err," -mtu          - Set MTU\n");
+	BIO_printf(bio_err," -chain        - Read a certificate chain\n");
 	BIO_printf(bio_err," -no_ssl2      - Just disable SSLv2\n");
 	BIO_printf(bio_err," -no_ssl3      - Just disable SSLv3\n");
 	BIO_printf(bio_err," -no_tls1      - Just disable TLSv1\n");
@@ -524,6 +534,7 @@
 	int no_tmp_rsa=0,no_dhe=0,no_ecdhe=0,nocert=0;
 	int state=0;
 	SSL_METHOD *meth=NULL;
+    int sock_type=SOCK_STREAM;
 #ifndef OPENSSL_NO_ENGINE
 	ENGINE *e=NULL;
 #endif
@@ -741,6 +752,22 @@
 		else if	(strcmp(*argv,"-tls1") == 0)
 			{ meth=TLSv1_server_method(); }
 #endif
+#ifndef OPENSSL_NO_DTLS1
+		else if	(strcmp(*argv,"-dtls1") == 0)
+			{ 
+			meth=DTLSv1_server_method();
+			sock_type = SOCK_DGRAM;
+			}
+		else if (strcmp(*argv,"-timeout") == 0)
+			enable_timeouts = 1;
+		else if (strcmp(*argv,"-mtu") == 0)
+			{
+			if (--argc < 1) goto bad;
+			mtu = atol(*(++argv));
+			}
+		else if (strcmp(*argv, "-chain") == 0)
+			cert_chain = 1;
+#endif
 		else if (strcmp(*argv, "-id_prefix") == 0)
 			{
 			if (--argc < 1) goto bad;
@@ -892,6 +919,10 @@
 	if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL);
 	if (hack) SSL_CTX_set_options(ctx,SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
 	SSL_CTX_set_options(ctx,off);
+	/* DTLS: partial reads end up discarding unread UDP bytes :-( 
+	 * Setting read ahead solves this problem.
+	 */
+	if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
 
 	if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
 
@@ -1046,9 +1077,9 @@
 
 	BIO_printf(bio_s_out,"ACCEPT\n");
 	if (www)
-		do_server(port,&accept_socket,www_body, context);
+		do_server(port,sock_type,&accept_socket,www_body, context);
 	else
-		do_server(port,&accept_socket,sv_body, context);
+		do_server(port,sock_type,&accept_socket,sv_body, context);
 	print_stats(bio_s_out,ctx);
 	ret=0;
 end:
@@ -1067,7 +1098,7 @@
 		OPENSSL_free(dpass);
 	if (bio_s_out != NULL)
 		{
-		BIO_free(bio_s_out);
+        BIO_free(bio_s_out);
 		bio_s_out=NULL;
 		}
 	apps_shutdown();
@@ -1146,7 +1177,39 @@
 	}
 	SSL_clear(con);
 
-	sbio=BIO_new_socket(s,BIO_NOCLOSE);
+	if (SSL_version(con) == DTLS1_VERSION)
+		{
+		struct timeval timeout;
+
+		sbio=BIO_new_dgram(s,BIO_NOCLOSE);
+
+		if ( enable_timeouts)
+			{
+			timeout.tv_sec = 0;
+			timeout.tv_usec = DGRAM_RCV_TIMEOUT;
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
+			
+			timeout.tv_sec = 0;
+			timeout.tv_usec = DGRAM_SND_TIMEOUT;
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout);
+			}
+
+		
+		if ( mtu > 0)
+			{
+			SSL_set_options(con, SSL_OP_NO_QUERY_MTU);
+			SSL_set_mtu(con, mtu);
+			}
+		else
+			/* want to do MTU discovery */
+			BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
+
+        /* turn on cookie exchange */
+        SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE);
+		}
+	else
+		sbio=BIO_new_socket(s,BIO_NOCLOSE);
+
 	if (s_nbio_test)
 		{
 		BIO *test;
@@ -1252,7 +1315,8 @@
 				if ((i <= 0) || (buf[0] == 'q'))
 					{
 					BIO_printf(bio_s_out,"DONE\n");
-					SHUTDOWN(s);
+					if (SSL_version(con) != DTLS1_VERSION)
+                        SHUTDOWN(s);
 	/*				close_accept_socket();
 					ret= -11;*/
 					goto err;
diff --git a/apps/s_socket.c b/apps/s_socket.c
index cf43301..b5dd47d 100644
--- a/apps/s_socket.c
+++ b/apps/s_socket.c
@@ -92,9 +92,9 @@
 static void ssl_sock_cleanup(void);
 #endif
 static int ssl_sock_init(void);
-static int init_client_ip(int *sock,unsigned char ip[4], int port);
-static int init_server(int *sock, int port);
-static int init_server_long(int *sock, int port,char *ip);
+static int init_client_ip(int *sock,unsigned char ip[4], int port, int type);
+static int init_server(int *sock, int port, int type);
+static int init_server_long(int *sock, int port,char *ip, int type);
 static int do_accept(int acc_sock, int *sock, char **host);
 static int host_ip(char *str, unsigned char ip[4]);
 
@@ -224,7 +224,7 @@
 	return(1);
 	}
 
-int init_client(int *sock, char *host, int port)
+int init_client(int *sock, char *host, int port, int type)
 	{
 	unsigned char ip[4];
 	short p=0;
@@ -234,10 +234,10 @@
 		return(0);
 		}
 	if (p != 0) port=p;
-	return(init_client_ip(sock,ip,port));
+	return(init_client_ip(sock,ip,port,type));
 	}
 
-static int init_client_ip(int *sock, unsigned char ip[4], int port)
+static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
 	{
 	unsigned long addr;
 	struct sockaddr_in them;
@@ -255,13 +255,20 @@
 		((unsigned long)ip[3]);
 	them.sin_addr.s_addr=htonl(addr);
 
-	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+	if (type == SOCK_STREAM)
+		s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+	else /* ( type == SOCK_DGRAM) */
+		s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
+			
 	if (s == INVALID_SOCKET) { perror("socket"); return(0); }
 
 #ifndef OPENSSL_SYS_MPE
-	i=0;
-	i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
-	if (i < 0) { perror("keepalive"); return(0); }
+	if (type == SOCK_STREAM)
+		{
+		i=0;
+		i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
+		if (i < 0) { perror("keepalive"); return(0); }
+		}
 #endif
 
 	if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
@@ -270,30 +277,36 @@
 	return(1);
 	}
 
-int do_server(int port, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), char *context)
+int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), char *context)
 	{
 	int sock;
-	char *name;
+	char *name = NULL;
 	int accept_socket;
 	int i;
 
-	if (!init_server(&accept_socket,port)) return(0);
+	if (!init_server(&accept_socket,port,type)) return(0);
 
 	if (ret != NULL)
 		{
 		*ret=accept_socket;
 		/* return(1);*/
 		}
-	for (;;)
-		{
-		if (do_accept(accept_socket,&sock,&name) == 0)
+  	for (;;)
+  		{
+		if (type==SOCK_STREAM)
 			{
-			SHUTDOWN(accept_socket);
-			return(0);
+			if (do_accept(accept_socket,&sock,&name) == 0)
+				{
+				SHUTDOWN(accept_socket);
+				return(0);
+				}
 			}
-		i=(*cb)(name,sock, (unsigned char *)context);
+		else
+			sock = accept_socket;
+		i=(*cb)(name,sock, context);
 		if (name != NULL) OPENSSL_free(name);
-		SHUTDOWN2(sock);
+		if (type==SOCK_STREAM)
+			SHUTDOWN2(sock);
 		if (i < 0)
 			{
 			SHUTDOWN2(accept_socket);
@@ -302,7 +315,7 @@
 		}
 	}
 
-static int init_server_long(int *sock, int port, char *ip)
+static int init_server_long(int *sock, int port, char *ip, int type)
 	{
 	int ret=0;
 	struct sockaddr_in server;
@@ -322,7 +335,11 @@
 #else
 		memcpy(&server.sin_addr,ip,4);
 #endif
-	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+	
+		if (type == SOCK_STREAM)
+			s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
+		else /* type == SOCK_DGRAM */
+			s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
 
 	if (s == INVALID_SOCKET) goto err;
 #if defined SOL_SOCKET && defined SO_REUSEADDR
@@ -340,7 +357,7 @@
 		goto err;
 		}
 	/* Make it 128 for linux */
-	if (listen(s,128) == -1) goto err;
+	if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
 	i=0;
 	*sock=s;
 	ret=1;
@@ -352,9 +369,9 @@
 	return(ret);
 	}
 
-static int init_server(int *sock, int port)
+static int init_server(int *sock, int port, int type)
 	{
-	return(init_server_long(sock, port, NULL));
+	return(init_server_long(sock, port, NULL, type));
 	}
 
 static int do_accept(int acc_sock, int *sock, char **host)
diff --git a/apps/timeouts.h b/apps/timeouts.h
new file mode 100644
index 0000000..89b5dc7
--- /dev/null
+++ b/apps/timeouts.h
@@ -0,0 +1,67 @@
+/* apps/timeouts.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef INCLUDED_TIMEOUTS_H
+#define INCLUDED_TIMEOUTS_H
+
+/* numbers in us */
+#define DGRAM_RCV_TIMEOUT         250000
+#define DGRAM_SND_TIMEOUT         250000
+
+#endif /* ! INCLUDED_TIMEOUTS_H */
diff --git a/crypto/Makefile b/crypto/Makefile
index c7ce69d..be7c250 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -33,7 +33,7 @@
 	bn ec rsa dsa ecdsa ecdh dh dso engine aes \
 	buffer bio stack lhash rand err \
 	evp asn1 pem x509 x509v3 conf txt_db pkcs7 pkcs12 comp ocsp ui krb5 \
-	store
+	store pqueue
 
 GENERAL=Makefile README crypto-lib.com install.com
 
diff --git a/crypto/aes/.cvsignore b/crypto/aes/.cvsignore
index 439e6d3..3d6ae11 100644
--- a/crypto/aes/.cvsignore
+++ b/crypto/aes/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+ax86-elf.s
diff --git a/crypto/bf/.cvsignore b/crypto/bf/.cvsignore
index 439e6d3..403e8f3 100644
--- a/crypto/bf/.cvsignore
+++ b/crypto/bf/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+bx86-elf.s
diff --git a/crypto/bio/Makefile b/crypto/bio/Makefile
index 976c5cd..2e52255 100644
--- a/crypto/bio/Makefile
+++ b/crypto/bio/Makefile
@@ -27,13 +27,15 @@
 	bss_mem.c bss_null.c bss_fd.c \
 	bss_file.c bss_sock.c bss_conn.c \
 	bf_null.c bf_buff.c b_print.c b_dump.c \
-	b_sock.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c
+	b_sock.c bss_acpt.c bf_nbio.c bss_log.c bss_bio.c \
+	bss_dgram.c
 #	bf_lbuf.c
 LIBOBJ= bio_lib.o bio_cb.o bio_err.o \
 	bss_mem.o bss_null.o bss_fd.o \
 	bss_file.o bss_sock.o bss_conn.o \
 	bf_null.o bf_buff.o b_print.o b_dump.o \
-	b_sock.o bss_acpt.o bf_nbio.o bss_log.o bss_bio.o
+	b_sock.o bss_acpt.o bf_nbio.o bss_log.o bss_bio.o \
+	bss_dgram.o
 #	bf_lbuf.o
 
 SRC= $(LIBSRC)
diff --git a/crypto/bio/bio.h b/crypto/bio/bio.h
index 7068b18..aaf4f66 100644
--- a/crypto/bio/bio.h
+++ b/crypto/bio/bio.h
@@ -94,6 +94,7 @@
 #define BIO_TYPE_BER		(18|0x0200)		/* BER -> bin filter */
 #define BIO_TYPE_BIO		(19|0x0400)		/* (half a) BIO pair */
 #define BIO_TYPE_LINEBUFFER	(20|0x0200)		/* filter */
+#define BIO_TYPE_DGRAM		(21|0x0400|0x0100)
 
 #define BIO_TYPE_DESCRIPTOR	0x0100	/* socket, fd, connect or accept */
 #define BIO_TYPE_FILTER		0x0200
@@ -125,6 +126,38 @@
 
 #define BIO_CTRL_SET_FILENAME	30	/* BIO_s_file special */
 
+/* dgram BIO stuff */
+#define BIO_CTRL_DGRAM_CONNECT       31  /* BIO dgram special */
+#define BIO_CTRL_DGRAM_SET_CONNECTED 32  /* allow for an externally
+										  * connected socket to be
+										  * passed in */ 
+#define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34 /* getsockopt, essentially */
+#define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36 /* getsockopt, essentially */
+
+#define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37 /* flag whether the last */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38 /* I/O operation tiemd out */
+					
+/* #ifdef IP_MTU_DISCOVER */
+#define BIO_CTRL_DGRAM_MTU_DISCOVER       39 /* set DF bit on egress packets */
+/* #endif */
+
+#define BIO_CTRL_DGRAM_QUERY_MTU          40 /* as kernel for current MTU */
+#define BIO_CTRL_DGRAM_GET_MTU            41 /* get cached value for MTU */
+#define BIO_CTRL_DGRAM_SET_MTU            42 /* set cached value for
+											  * MTU. want to use this
+                                              * if asking the kernel
+                                              * fails */
+
+#define BIO_CTRL_DGRAM_MTU_EXCEEDED       43 /* check whether the MTU
+											  * was exceed in the
+											  * previous write
+											  * operation */
+
+#define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the data */
+
+
 /* modifiers */
 #define BIO_FP_READ		0x02
 #define BIO_FP_WRITE		0x04
@@ -488,6 +521,18 @@
 size_t BIO_ctrl_get_read_request(BIO *b);
 int BIO_ctrl_reset_read_request(BIO *b);
 
+/* ctrl macros for dgram */
+#define BIO_ctrl_dgram_connect(b,peer)  \
+                     (int)BIO_ctrl(b,BIO_CTRL_DGRAM_CONNECT,0, (char *)peer)
+#define BIO_ctrl_set_connected(b, state, peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, state, (char *)peer)
+#define BIO_dgram_recv_timedout(b) \
+         (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_set_peer(b,peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)
+
 /* These two aren't currently implemented */
 /* int BIO_get_ex_num(BIO *bio); */
 /* void BIO_set_ex_free_func(BIO *bio,int idx,void (*cb)()); */
@@ -567,10 +612,16 @@
 BIO_METHOD *BIO_f_linebuffer(void);
 #endif
 BIO_METHOD *BIO_f_nbio_test(void);
+#ifndef OPENSSL_NO_DGRAM
+BIO_METHOD *BIO_s_datagram(void);
+#endif
+
 /* BIO_METHOD *BIO_f_ber(void); */
 
 int BIO_sock_should_retry(int i);
 int BIO_sock_non_fatal_error(int error);
+int BIO_dgram_non_fatal_error(int error);
+
 int BIO_fd_should_retry(int i);
 int BIO_fd_non_fatal_error(int error);
 int BIO_dump_cb(int (*cb)(const void *data, size_t len, void *u),
@@ -604,6 +655,7 @@
 int BIO_set_tcp_ndelay(int sock,int turn_on);
 
 BIO *BIO_new_socket(int sock, int close_flag);
+BIO *BIO_new_dgram(int fd, int close_flag);
 BIO *BIO_new_fd(int fd, int close_flag);
 BIO *BIO_new_connect(char *host_port);
 BIO *BIO_new_accept(char *host_port);
diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c
new file mode 100644
index 0000000..fa6d27a
--- /dev/null
+++ b/crypto/bio/bss_dgram.c
@@ -0,0 +1,479 @@
+/* crypto/bio/bio_dgram.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef OPENSSL_NO_DGRAM
+
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "cryptlib.h"
+
+#include <sys/socket.h>
+
+#include <openssl/bio.h>
+
+#define IP_MTU      14 /* linux is lame */
+
+#ifdef WATT32
+#define sock_write SockWrite  /* Watt-32 uses same names */
+#define sock_read  SockRead
+#define sock_puts  SockPuts
+#endif
+
+static int dgram_write(BIO *h, const char *buf, int num);
+static int dgram_read(BIO *h, char *buf, int size);
+static int dgram_puts(BIO *h, const char *str);
+static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2);
+static int dgram_new(BIO *h);
+static int dgram_free(BIO *data);
+static int dgram_clear(BIO *bio);
+
+int BIO_dgram_should_retry(int s);
+
+static BIO_METHOD methods_dgramp=
+	{
+	BIO_TYPE_DGRAM,
+	"datagram socket",
+	dgram_write,
+	dgram_read,
+	dgram_puts,
+	NULL, /* dgram_gets, */
+	dgram_ctrl,
+	dgram_new,
+	dgram_free,
+	NULL,
+	};
+
+typedef struct bio_dgram_data_st
+	{
+	struct sockaddr peer;
+	unsigned int connected;
+	unsigned int _errno;
+	unsigned int mtu;
+	} bio_dgram_data;
+
+BIO_METHOD *BIO_s_datagram(void)
+	{
+	return(&methods_dgramp);
+	}
+
+BIO *BIO_new_dgram(int fd, int close_flag)
+	{
+	BIO *ret;
+
+	ret=BIO_new(BIO_s_datagram());
+	if (ret == NULL) return(NULL);
+	BIO_set_fd(ret,fd,close_flag);
+	return(ret);
+	}
+
+static int dgram_new(BIO *bi)
+	{
+	bio_dgram_data *data = NULL;
+
+	bi->init=0;
+	bi->num=0;
+	data = OPENSSL_malloc(sizeof(bio_dgram_data));
+	if (data == NULL)
+		return 0;
+	memset(data, 0x00, sizeof(bio_dgram_data));
+    bi->ptr = data;
+
+	bi->flags=0;
+	return(1);
+	}
+
+static int dgram_free(BIO *a)
+	{
+	bio_dgram_data *data;
+
+	if (a == NULL) return(0);
+	if ( ! dgram_clear(a))
+		return 0;
+
+	data = (bio_dgram_data *)a->ptr;
+	if(data != NULL) OPENSSL_free(data);
+
+	return(1);
+	}
+
+static int dgram_clear(BIO *a)
+	{
+	if (a == NULL) return(0);
+	if (a->shutdown)
+		{
+		if (a->init)
+			{
+			SHUTDOWN2(a->num);
+			}
+		a->init=0;
+		a->flags=0;
+		}
+	return(1);
+	}
+	
+static int dgram_read(BIO *b, char *out, int outl)
+	{
+	int ret=0;
+	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+
+	struct sockaddr peer;
+	socklen_t peerlen = sizeof(peer);
+
+	if (out != NULL)
+		{
+		clear_socket_error();
+		memset(&peer, 0x00, peerlen);
+		ret=recvfrom(b->num,out,outl,0,&peer,&peerlen);
+
+		if ( ! data->connected  && ret > 0)
+			BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer);
+
+		BIO_clear_retry_flags(b);
+		if (ret <= 0)
+			{
+			if (BIO_dgram_should_retry(ret))
+				{
+				BIO_set_retry_read(b);
+				data->_errno = get_last_socket_error();
+				}
+			}
+		}
+	return(ret);
+	}
+
+static int dgram_write(BIO *b, const char *in, int inl)
+	{
+	int ret;
+	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
+	clear_socket_error();
+
+    if ( data->connected )
+        ret=send(b->num,in,inl,0);
+    else
+        ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer));
+
+	BIO_clear_retry_flags(b);
+	if (ret <= 0)
+		{
+		if (BIO_sock_should_retry(ret))
+			{
+			BIO_set_retry_write(b);  
+			data->_errno = get_last_socket_error();
+
+#if 0 /* higher layers are responsible for querying MTU, if necessary */
+			if ( data->_errno == EMSGSIZE)
+				/* retrieve the new MTU */
+				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+#endif
+			}
+		}
+	return(ret);
+	}
+
+static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
+	{
+	long ret=1;
+	int *ip;
+	struct sockaddr *to = NULL;
+	bio_dgram_data *data = NULL;
+	long sockopt_val = 0;
+	unsigned int sockopt_len = 0;
+
+	data = (bio_dgram_data *)b->ptr;
+
+	switch (cmd)
+		{
+	case BIO_CTRL_RESET:
+		num=0;
+	case BIO_C_FILE_SEEK:
+		ret=0;
+		break;
+	case BIO_C_FILE_TELL:
+	case BIO_CTRL_INFO:
+		ret=0;
+		break;
+	case BIO_C_SET_FD:
+		dgram_clear(b);
+		b->num= *((int *)ptr);
+		b->shutdown=(int)num;
+		b->init=1;
+		break;
+	case BIO_C_GET_FD:
+		if (b->init)
+			{
+			ip=(int *)ptr;
+			if (ip != NULL) *ip=b->num;
+			ret=b->num;
+			}
+		else
+			ret= -1;
+		break;
+	case BIO_CTRL_GET_CLOSE:
+		ret=b->shutdown;
+		break;
+	case BIO_CTRL_SET_CLOSE:
+		b->shutdown=(int)num;
+		break;
+	case BIO_CTRL_PENDING:
+	case BIO_CTRL_WPENDING:
+		ret=0;
+		break;
+	case BIO_CTRL_DUP:
+	case BIO_CTRL_FLUSH:
+		ret=1;
+		break;
+	case BIO_CTRL_DGRAM_CONNECT:
+		to = (struct sockaddr *)ptr;
+#if 0
+		if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
+			{ perror("connect"); ret = 0; }
+		else
+			{
+#endif
+			memcpy(&(data->peer),to, sizeof(struct sockaddr));
+#if 0
+			}
+#endif
+		break;
+		/* (Linux)kernel sets DF bit on outgoing IP packets */
+#ifdef IP_MTU_DISCOVER
+	case BIO_CTRL_DGRAM_MTU_DISCOVER:
+		sockopt_val = IP_PMTUDISC_DO;
+		if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
+			&sockopt_val, sizeof(sockopt_val))) < 0)
+			perror("setsockopt");
+		break;
+#endif
+	case BIO_CTRL_DGRAM_QUERY_MTU:
+         sockopt_len = sizeof(sockopt_val);
+		if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, &sockopt_val,
+			&sockopt_len)) < 0 || sockopt_val < 0)
+			{ ret = 0; }
+		else
+			{
+			data->mtu = sockopt_val;
+			ret = data->mtu;
+			}
+		break;
+	case BIO_CTRL_DGRAM_GET_MTU:
+		return data->mtu;
+		break;
+	case BIO_CTRL_DGRAM_SET_MTU:
+		data->mtu = num;
+		ret = num;
+		break;
+	case BIO_CTRL_DGRAM_SET_CONNECTED:
+		to = (struct sockaddr *)ptr;
+
+		if ( to != NULL)
+			{
+			data->connected = 1;
+			memcpy(&(data->peer),to, sizeof(struct sockaddr));
+			}
+		else
+			{
+			data->connected = 0;
+			memset(&(data->peer), 0x00, sizeof(struct sockaddr));
+			}
+		break;
+    case BIO_CTRL_DGRAM_SET_PEER:
+        to = (struct sockaddr *) ptr;
+
+        memcpy(&(data->peer), to, sizeof(struct sockaddr));
+        break;
+	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
+		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
+			sizeof(struct timeval)) < 0)
+			{ perror("setsockopt");	ret = -1; }
+		break;
+	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
+		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 
+			ptr, (socklen_t *)&ret) < 0)
+			{ perror("getsockopt"); ret = -1; }
+		break;
+	case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
+		if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
+			sizeof(struct timeval)) < 0)
+			{ perror("setsockopt");	ret = -1; }
+		break;
+	case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
+		if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 
+			ptr, (socklen_t *)&ret) < 0)
+			{ perror("getsockopt"); ret = -1; }
+		break;
+	case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
+		/* fall-through */
+	case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
+		if ( data->_errno == EAGAIN)
+			{
+			ret = 1;
+			data->_errno = 0;
+			}
+		else
+			ret = 0;
+		break;
+	case BIO_CTRL_DGRAM_MTU_EXCEEDED:
+		if ( data->_errno == EMSGSIZE)
+			{
+			ret = 1;
+			data->_errno = 0;
+			}
+		else
+			ret = 0;
+		break;
+	default:
+		ret=0;
+		break;
+		}
+	return(ret);
+	}
+
+static int dgram_puts(BIO *bp, const char *str)
+	{
+	int n,ret;
+
+	n=strlen(str);
+	ret=dgram_write(bp,str,n);
+	return(ret);
+	}
+
+int BIO_dgram_should_retry(int i)
+	{
+	int err;
+
+	if ((i == 0) || (i == -1))
+		{
+		err=get_last_socket_error();
+
+#if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */
+		if ((i == -1) && (err == 0))
+			return(1);
+#endif
+
+		return(BIO_dgram_non_fatal_error(err));
+		}
+	return(0);
+	}
+
+int BIO_dgram_non_fatal_error(int err)
+	{
+	switch (err)
+		{
+#if defined(OPENSSL_SYS_WINDOWS)
+# if defined(WSAEWOULDBLOCK)
+	case WSAEWOULDBLOCK:
+# endif
+
+# if 0 /* This appears to always be an error */
+#  if defined(WSAENOTCONN)
+	case WSAENOTCONN:
+#  endif
+# endif
+#endif
+
+#ifdef EWOULDBLOCK
+# ifdef WSAEWOULDBLOCK
+#  if WSAEWOULDBLOCK != EWOULDBLOCK
+	case EWOULDBLOCK:
+#  endif
+# else
+	case EWOULDBLOCK:
+# endif
+#endif
+
+#if defined(ENOTCONN)
+	case ENOTCONN:
+#endif
+
+#ifdef EINTR
+	case EINTR:
+#endif
+
+#ifdef EAGAIN
+#if EWOULDBLOCK != EAGAIN
+	case EAGAIN:
+# endif
+#endif
+
+#ifdef EPROTO
+	case EPROTO:
+#endif
+
+#ifdef EINPROGRESS
+	case EINPROGRESS:
+#endif
+
+#ifdef EALREADY
+	case EALREADY:
+#endif
+
+/* DF bit set, and packet larger than MTU */
+#ifdef EMSGSIZE
+	case EMSGSIZE:
+#endif
+
+		return(1);
+		/* break; */
+	default:
+		break;
+		}
+	return(0);
+	}
+#endif
diff --git a/crypto/bn/.cvsignore b/crypto/bn/.cvsignore
index 439e6d3..57df22c 100644
--- a/crypto/bn/.cvsignore
+++ b/crypto/bn/.cvsignore
@@ -2,3 +2,5 @@
 Makefile.save
 *.flc
 semantic.cache
+co86-elf.s
+bn86-elf.s
diff --git a/crypto/cast/.cvsignore b/crypto/cast/.cvsignore
index 439e6d3..e79919b 100644
--- a/crypto/cast/.cvsignore
+++ b/crypto/cast/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+cx86-elf.s
diff --git a/crypto/des/.cvsignore b/crypto/des/.cvsignore
index e5c5e37..5dcc40f 100644
--- a/crypto/des/.cvsignore
+++ b/crypto/des/.cvsignore
@@ -3,3 +3,5 @@
 des
 *.flc
 semantic.cache
+yx86-elf.s
+dx86-elf.s
diff --git a/crypto/md5/.cvsignore b/crypto/md5/.cvsignore
index 439e6d3..fe51220 100644
--- a/crypto/md5/.cvsignore
+++ b/crypto/md5/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+mx86-elf.s
diff --git a/crypto/pqueue/Makefile b/crypto/pqueue/Makefile
new file mode 100644
index 0000000..e08a3e4
--- /dev/null
+++ b/crypto/pqueue/Makefile
@@ -0,0 +1,81 @@
+#
+# SSLeay/crypto/pqueue/Makefile
+#
+
+DIR=	pqueue
+TOP=	../..
+CC=	cc
+INCLUDES=
+CFLAG=-g
+INSTALL_PREFIX=
+OPENSSLDIR=     /usr/local/ssl
+INSTALLTOP=/usr/local/ssl
+MAKE=		make
+MAKEDEPPROG=	makedepend
+MAKEDEPEND=	$(TOP)/util/domd $(TOP) -MD $(MAKEDEPPROG)
+MAKEFILE=	Makefile
+AR=		ar r
+
+CFLAGS= $(INCLUDES) $(CFLAG)
+
+GENERAL=Makefile
+TEST=
+APPS=
+
+LIB=$(TOP)/libcrypto.a
+LIBSRC=pqueue.c
+LIBOBJ=pqueue.o
+
+SRC= $(LIBSRC)
+
+EXHEADER= pqueue.h
+HEADER=	$(EXHEADER)
+
+ALL=    $(GENERAL) $(SRC) $(HEADER)
+
+top:
+	(cd ../..; $(MAKE) DIRS=crypto SDIRS=$(DIR) sub_all)
+
+all:	lib
+
+lib:	$(LIBOBJ)
+	$(AR) $(LIB) $(LIBOBJ)
+	$(RANLIB) $(LIB) || echo Never mind.
+	@touch lib
+
+files:
+	$(PERL) $(TOP)/util/files.pl Makefile >> $(TOP)/MINFO
+
+links:
+	@$(PERL) $(TOP)/util/mklink.pl ../../include/openssl $(EXHEADER)
+	@$(PERL) $(TOP)/util/mklink.pl ../../test $(TEST)
+	@$(PERL) $(TOP)/util/mklink.pl ../../apps $(APPS)
+
+install:
+	@headerlist="$(EXHEADER)"; for i in $$headerlist ; \
+	do  \
+	(cp $$i $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i; \
+	chmod 644 $(INSTALL_PREFIX)$(INSTALLTOP)/include/openssl/$$i ); \
+	done;
+
+tags:
+	ctags $(SRC)
+
+tests:
+
+lint:
+	lint -DLINT $(INCLUDES) $(SRC)>fluff
+
+depend:
+	$(MAKEDEPEND) -- $(CFLAG) $(INCLUDES) $(DEPFLAG) -- $(PROGS) $(LIBSRC)
+
+dclean:
+	$(PERL) -pe 'if (/^# DO NOT DELETE THIS LINE/) {print; exit(0);}' $(MAKEFILE) >Makefile.new
+	mv -f Makefile.new $(MAKEFILE)
+
+clean:
+	rm -f *.o *.obj lib tags core .pure .nfs* *.old *.bak fluff
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+
diff --git a/crypto/pqueue/pq_test.c b/crypto/pqueue/pq_test.c
new file mode 100644
index 0000000..8d496df
--- /dev/null
+++ b/crypto/pqueue/pq_test.c
@@ -0,0 +1,95 @@
+/* crypto/pqueue/pq_test.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "pqueue.h"
+
+int
+main(void)
+	{
+	pitem *item;
+	pqueue pq;
+
+	pq = pqueue_new();
+
+	item = pitem_new(3, NULL);
+	pqueue_insert(pq, item);
+
+	item = pitem_new(1, NULL);
+	pqueue_insert(pq, item);
+
+	item = pitem_new(2, NULL);
+	pqueue_insert(pq, item);
+
+	item = pqueue_find(pq, 1);
+	fprintf(stderr, "found %ld\n", item->priority);
+
+	item = pqueue_find(pq, 2);
+	fprintf(stderr, "found %ld\n", item->priority);
+
+	item = pqueue_find(pq, 3);
+	fprintf(stderr, "found %ld\n", item ? item->priority: 0);
+
+	pqueue_print(pq);
+
+	for(item = pqueue_pop(pq); item != NULL; item = pqueue_pop(pq))
+		pitem_free(item);
+
+	pqueue_free(pq);
+	return 0;
+	}
diff --git a/crypto/pqueue/pqueue.c b/crypto/pqueue/pqueue.c
new file mode 100644
index 0000000..4cd9987
--- /dev/null
+++ b/crypto/pqueue/pqueue.c
@@ -0,0 +1,230 @@
+/* crypto/pqueue/pqueue.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "pqueue.h"
+#include "crypto.h"
+
+typedef struct _pqueue
+	{
+	pitem *items;
+	int count;
+	} pqueue_s;
+
+pitem *
+pitem_new(unsigned long long priority, void *data)
+	{
+	pitem *item = (pitem *) OPENSSL_malloc(sizeof(pitem));
+	if (item == NULL) return NULL;
+
+	item->priority = priority;
+	item->data = data;
+	item->next = NULL;
+
+	return item;
+	}
+
+void
+pitem_free(pitem *item)
+	{
+	if (item == NULL) return;
+	
+	OPENSSL_free(item);
+	}
+
+pqueue_s *
+pqueue_new()
+	{
+	pqueue_s *pq = (pqueue_s *) OPENSSL_malloc(sizeof(pqueue_s));
+	if (pq == NULL) return NULL;
+
+	memset(pq, 0x00, sizeof(pqueue_s));
+	return pq;
+	}
+
+void
+pqueue_free(pqueue_s *pq)
+	{
+	if (pq == NULL) return;
+
+	OPENSSL_free(pq);
+	}
+
+pitem *
+pqueue_insert(pqueue_s *pq, pitem *item)
+	{
+	pitem *curr, *next;
+
+	if (pq->items == NULL)
+		{
+		pq->items = item;
+		return item;
+		}
+
+	for(curr = NULL, next = pq->items; 
+		next != NULL;
+		curr = next, next = next->next)
+		{
+		if (item->priority < next->priority)
+			{
+			item->next = next;
+
+			if (curr == NULL) 
+				pq->items = item;
+			else  
+				curr->next = item;
+
+			return item;
+			}
+		/* duplicates not allowed */
+		if (item->priority == next->priority)
+			return NULL;
+		}
+
+	item->next = NULL;
+	curr->next = item;
+
+	return item;
+	}
+
+pitem *
+pqueue_peek(pqueue_s *pq)
+	{
+	return pq->items;
+	}
+
+pitem *
+pqueue_pop(pqueue_s *pq)
+	{
+	pitem *item = pq->items;
+
+	if (pq->items != NULL)
+		pq->items = pq->items->next;
+
+	return item;
+	}
+
+pitem *
+pqueue_find(pqueue_s *pq, unsigned long long priority)
+	{
+	pitem *next, *prev = NULL;
+	pitem *found = NULL;
+
+	if ( pq->items == NULL)
+		return NULL;
+
+	for ( next = pq->items; next->next != NULL; 
+		  prev = next, next = next->next)
+		{
+		if ( next->priority == priority)
+			{
+			found = next;
+			break;
+			}
+		}
+	
+	/* check the one last node */
+	if ( next->priority == priority)
+		found = next;
+
+	if ( ! found)
+		return NULL;
+
+#if 0 /* find works in peek mode */
+	if ( prev == NULL)
+		pq->items = next->next;
+	else
+		prev->next = next->next;
+#endif
+
+	return found;
+	}
+
+void
+pqueue_print(pqueue_s *pq)
+	{
+	pitem *item = pq->items;
+
+	while(item != NULL)
+		{
+		printf("item\t%lld\n", item->priority);
+		item = item->next;
+		}
+	}
+
+pitem *
+pqueue_iterator(pqueue_s *pq)
+	{
+	return pqueue_peek(pq);
+	}
+
+pitem *
+pqueue_next(pitem **item)
+	{
+	pitem *ret;
+
+	if ( item == NULL || *item == NULL)
+		return NULL;
+
+
+	/* *item != NULL */
+	ret = *item;
+	*item = (*item)->next;
+
+	return ret;
+	}
diff --git a/crypto/pqueue/pqueue.h b/crypto/pqueue/pqueue.h
new file mode 100644
index 0000000..2245950
--- /dev/null
+++ b/crypto/pqueue/pqueue.h
@@ -0,0 +1,93 @@
+/* crypto/pqueue/pqueue.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_PQUEUE_H
+#define HEADER_PQUEUE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct _pqueue *pqueue;
+
+typedef struct _pitem
+	{
+	unsigned long long priority;
+	void *data;
+	struct _pitem *next;
+	} pitem;
+
+typedef struct _pitem *piterator;
+
+pitem *pitem_new(unsigned long long priority, void *data);
+void   pitem_free(pitem *item);
+
+pqueue pqueue_new(void);
+void   pqueue_free(pqueue pq);
+
+pitem *pqueue_insert(pqueue pq, pitem *item);
+pitem *pqueue_peek(pqueue pq);
+pitem *pqueue_pop(pqueue pq);
+pitem *pqueue_find(pqueue pq, unsigned long long priority);
+pitem *pqueue_iterator(pqueue pq);
+pitem *pqueue_next(piterator *iter);
+
+void   pqueue_print(pqueue pq);
+
+#endif /* ! HEADER_PQUEUE_H */
diff --git a/crypto/rc4/.cvsignore b/crypto/rc4/.cvsignore
index 439e6d3..6d7750c 100644
--- a/crypto/rc4/.cvsignore
+++ b/crypto/rc4/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+rx86-elf.s
diff --git a/crypto/ripemd/.cvsignore b/crypto/ripemd/.cvsignore
index 439e6d3..f7abe18 100644
--- a/crypto/ripemd/.cvsignore
+++ b/crypto/ripemd/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+rm86-elf.s
diff --git a/crypto/sha/.cvsignore b/crypto/sha/.cvsignore
index 439e6d3..b2199b1 100644
--- a/crypto/sha/.cvsignore
+++ b/crypto/sha/.cvsignore
@@ -2,3 +2,4 @@
 Makefile.save
 *.flc
 semantic.cache
+sx86-elf.s
diff --git a/ssl/Makefile b/ssl/Makefile
index 20e5bcc..a7a8a94 100644
--- a/ssl/Makefile
+++ b/ssl/Makefile
@@ -31,6 +31,8 @@
 	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c \
 	s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c          s23_pkt.c \
 	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c \
+	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  d1_pkt.c \
+	d1_both.c d1_enc.c \
 	ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
 	ssl_ciph.c ssl_stat.c ssl_rsa.c \
 	ssl_asn1.c ssl_txt.c ssl_algs.c \
@@ -40,6 +42,8 @@
 	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o \
 	s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o          s23_pkt.o \
 	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o \
+	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  d1_pkt.o \
+	d1_both.o d1_enc.o \
 	ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
 	ssl_ciph.o ssl_stat.o ssl_rsa.o \
 	ssl_asn1.o ssl_txt.o ssl_algs.o \
@@ -47,7 +51,7 @@
 
 SRC= $(LIBSRC)
 
-EXHEADER= ssl.h ssl2.h ssl3.h ssl23.h tls1.h kssl.h
+EXHEADER= ssl.h ssl2.h ssl3.h ssl23.h tls1.h dtls1.h kssl.h
 HEADER=	$(EXHEADER) ssl_locl.h kssl_lcl.h
 
 ALL=    $(GENERAL) $(SRC) $(HEADER)
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
new file mode 100644
index 0000000..6890881
--- /dev/null
+++ b/ssl/d1_both.c
@@ -0,0 +1,1248 @@
+/* ssl/d1_both.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+
+/* XDTLS:  figure out the right values */
+static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28};
+
+static unsigned int dtls1_min_mtu(void);
+static unsigned int dtls1_guess_mtu(unsigned int curr_mtu);
+static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, 
+	unsigned long frag_len);
+static unsigned char *dtls1_write_message_header(SSL *s,
+	unsigned char *p);
+static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
+	unsigned long len, unsigned short seq_num, unsigned long frag_off, 
+	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);
+
+static hm_fragment *
+dtls1_hm_fragment_new(unsigned long frag_len)
+    {
+    hm_fragment *frag = NULL;
+    unsigned char *buf = 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;
+
+    return frag;
+    }
+
+static void
+dtls1_hm_fragment_free(hm_fragment *frag)
+    {
+    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)
+	{
+	int ret;
+	int curr_mtu;
+	unsigned int len, frag_off;
+
+	/* 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);
+
+		/* I've seen the kernel return bogus numbers when it doesn't know
+		 * (initial write), so just make sure we have a reasonable number */
+		if ( s->d1->mtu < dtls1_min_mtu())
+			{
+			s->d1->mtu = 0;
+			s->d1->mtu = dtls1_guess_mtu(s->d1->mtu);
+			BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, 
+				s->d1->mtu, NULL);
+			}
+		}
+#if 0 
+	mtu = s->d1->mtu;
+
+	fprintf(stderr, "using MTU = %d\n", mtu);
+
+	mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+
+	curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s));
+
+	if ( curr_mtu > 0)
+		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));
+		if ( ret <= 0)
+			return ret;
+		mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH);
+		}
+
+	OPENSSL_assert(mtu > 0);  /* should have something reasonable now */
+
+#endif
+
+	if ( s->init_off == 0  && type == SSL3_RT_HANDSHAKE)
+		OPENSSL_assert(s->init_num == 
+			s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
+
+	frag_off = 0;
+	while( s->init_num)
+		{
+		curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - 
+			DTLS1_RT_HEADER_LENGTH;
+
+		if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
+			{
+			/* grr.. we could get an error if MTU picked was wrong */
+			ret = BIO_flush(SSL_get_wbio(s));
+			if ( ret <= 0)
+				return ret;
+			curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH;
+			}
+
+		if ( s->init_num > curr_mtu)
+			len = curr_mtu;
+		else
+			len = s->init_num;
+
+
+		/* XDTLS: this function is too long.  split out the CCS part */
+		if ( type == SSL3_RT_HANDSHAKE)
+			{
+			if ( s->init_off != 0)
+				{
+				OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
+				s->init_off -= DTLS1_HM_HEADER_LENGTH;
+				s->init_num += DTLS1_HM_HEADER_LENGTH;
+
+                /* 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);
+
+			dtls1_write_message_header(s, &s->init_buf->data[s->init_off]);
+
+			OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
+			}
+
+		ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
+			len);
+		if (ret < 0)
+			{
+			/* might need to update MTU here, but we don't know
+			 * which previous packet caused the failure -- so can't
+			 * really retransmit anything.  continue as if everything
+			 * is fine and wait for an alert to handle the
+			 * retransmit 
+			 */
+			if ( BIO_ctrl(SSL_get_wbio(s),
+				BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL))
+				s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
+					BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+			else
+				return(-1);
+			}
+		else
+			{
+			
+			/* bad if this assert fails, only part of the handshake
+			 * message got sent.  but why would this happen? */
+			OPENSSL_assert(len == 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);
+			
+			if (ret == s->init_num)
+				{
+				if (s->msg_callback)
+					s->msg_callback(1, s->version, type, s->init_buf->data, 
+						(size_t)(s->init_off + s->init_num), s, 
+						s->msg_callback_arg);
+
+				s->init_off = 0;  /* done writing this message */
+				s->init_num = 0;
+				
+				return(1);
+				}
+			s->init_off+=ret;
+			s->init_num-=ret;
+			frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
+			}
+		}
+	return(0);
+	}
+
+
+/* Obtain handshake message of message type 'mt' (any if mt == -1),
+ * maximum acceptable body length 'max'.
+ * Read an entire handshake message.  Handshake messages arrive in
+ * fragments.
+ */
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, 
+	int	*ok)
+	{
+	int i, al;
+
+	/* s3->tmp is used to store messages that are unexpected, caused
+	 * by the absence of an optional handshake message */
+	if (s->s3->tmp.reuse_message)
+		{
+		s->s3->tmp.reuse_message=0;
+		if ((mt >= 0) && (s->s3->tmp.message_type != mt))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE);
+			goto f_err;
+			}
+		*ok=1;
+		s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+		s->init_num = (int)s->s3->tmp.message_size;
+		return s->init_num;
+		}
+	
+	do
+		{
+		if ( s->d1->r_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));
+			}
+
+		i = dtls1_get_message_fragment(s, st1, stn, max, ok);
+		if ( i == DTLS1_HM_BAD_FRAGMENT ||
+            i == DTLS1_HM_FRAGMENT_RETRY)  /* bad fragment received */
+			continue;
+		else if ( i <= 0 && !*ok)
+			return i;
+
+		if (s->d1->r_msg_hdr.msg_len == s->init_num - DTLS1_HM_HEADER_LENGTH)
+			{
+			memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
+
+			s->d1->handshake_read_seq++;
+			/* we just read a handshake message from the other side:
+			 * this means that we don't need to retransmit of the
+			 * buffered messages.  
+			 * XDTLS: may be able clear out this
+			 * buffer a little sooner (i.e if an out-of-order
+			 * handshake message/record is received at the record
+			 * layer.  
+			 * XDTLS: exception is that the server needs to
+			 * know that change cipher spec and finished messages
+			 * have been received by the client before clearing this
+			 * buffer.  this can simply be done by waiting for the
+			 * 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;
+			}
+		else
+			s->d1->r_msg_hdr.frag_off = i;
+		} while(1) ;
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+	*ok = 0;
+	return -1;
+	}
+
+
+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;
+
+    frag = (hm_fragment *)item->data;
+    
+    if ( s->d1->handshake_read_seq == frag->msg_header.seq &&
+        frag->msg_header.frag_off <= 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);
+
+        *copied = frag->msg_header.frag_len - overlap;
+        return *copied;
+        }
+    else
+        return 0;
+    }
+
+
+static int
+dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr)
+{
+    hm_fragment *frag = NULL;
+    pitem *item = NULL;
+
+    frag = dtls1_hm_fragment_new(msg_hdr->frag_len);
+    if ( frag == NULL)
+        goto err;
+
+    memcpy(frag->fragment, &(s->init_buf->data[s->init_num]),
+        msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH);
+
+    memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+    item = pitem_new(msg_hdr->seq, frag);
+    if ( item == NULL)
+        goto err;
+
+    pqueue_insert(s->d1->buffered_messages, item);
+    return 1;
+
+err:
+    if ( frag != NULL) dtls1_hm_fragment_free(frag);
+    if ( item != NULL) OPENSSL_free(item);
+    return 0;
+}
+
+
+static void
+dtls1_process_handshake_fragment(SSL *s, int frag_len)
+    {
+    unsigned char *p;
+
+    p = s->init_buf->data;
+
+	ssl3_finish_mac(s, &p[s->init_num - frag_len], frag_len);
+    }
+
+
+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_SSL3_GET_MESSAGE,ERR_R_BUF_LIB);
+        goto err;
+        }
+
+    p = s->init_buf->data;
+
+    /* read the body of the fragment (header has already been read */
+    if ( msg_hdr->frag_len > 0)
+		{
+		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+            &p[s->init_num], 
+            msg_hdr->frag_len,0);
+		if (i <= 0)
+			{
+			*ok = 0;
+			return 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);
+
+    return DTLS1_HM_FRAGMENT_RETRY;
+err:
+    *ok = 0;
+    return -1;
+    }
+
+
+static long 
+dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
+	{
+	unsigned char *p;
+	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;
+
+    /* read handshake message header */
+	i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
+		DTLS1_HM_HEADER_LENGTH, 0);
+	if (i <= 0) 	/* nbio, or an error */
+		{
+		s->rwstate=SSL_READING;
+		*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);
+
+    /* 
+     * 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;
+	frag_len = msg_hdr.frag_len;
+
+    /* sanity checking */
+    if ( frag_off + frag_len > l)
+        {
+        al=SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_SSL3_GET_MESSAGE,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_SSL3_GET_MESSAGE,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 */
+		{
+		/* BUF_MEM_grow takes an 'int' parameter */
+		if (l > (INT_MAX-DTLS1_HM_HEADER_LENGTH)) 
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			SSLerr(SSL_F_SSL3_GET_MESSAGE,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_SSL3_GET_MESSAGE,ERR_R_BUF_LIB);
+			goto err;
+			}
+        /* 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)
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE);
+			goto f_err;
+			}
+
+		s->s3->tmp.message_size=l;
+		}
+
+    if ( frag_len > (unsigned long)max)
+        {
+        al=SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_SSL3_GET_MESSAGE,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_SSL3_GET_MESSAGE,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_SSL3_GET_MESSAGE,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; */
+		}
+
+	/* XDTLS:  ressurect this when restart is in place */
+	s->state=stn;
+	
+	/* next state (stn) */
+	p = s->init_buf->data;
+
+	if ( frag_len > 0)
+		{
+		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 */
+		if (i <= 0)
+			{
+			s->rwstate=SSL_READING;
+			*ok = 0;
+			return i;
+			}
+		}
+	else
+		i = 0;
+
+    /* XDTLS:  an incorrectly formatted fragment should cause the 
+     * handshake to fail */
+	OPENSSL_assert(i == 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
+     */
+
+    /* 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;
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+    s->init_num = 0;
+err:
+	*ok=0;
+	return(-1);
+	}
+
+int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen)
+	{
+	unsigned char *p,*d;
+	int i;
+	unsigned long l;
+
+	if (s->state == a)
+		{
+		d=(unsigned char *)s->init_buf->data;
+		p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+		i=s->method->ssl3_enc->final_finish_mac(s,
+			&(s->s3->finish_dgst1),
+			&(s->s3->finish_dgst2),
+			sender,slen,s->s3->tmp.finish_md);
+		s->s3->tmp.finish_md_len = i;
+		memcpy(p, s->s3->tmp.finish_md, i);
+		p+=i;
+		l=i;
+
+#ifdef OPENSSL_SYS_WIN16
+		/* MSVC 1.5 does not clear the top bytes of the word unless
+		 * I do this.
+		 */
+		l&=0xffff;
+#endif
+
+		d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l);
+		s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		
+		s->state=b;
+		}
+
+	/* SSL3_ST_SEND_xxxxxx_HELLO_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+/* for these 2 messages, we need to
+ * ssl->enc_read_ctx			re-init
+ * ssl->s3->read_sequence		zero
+ * ssl->s3->read_mac_secret		re-init
+ * ssl->session->read_sym_enc		assign
+ * ssl->session->read_compression	assign
+ * ssl->session->read_hash		assign
+ */
+int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
+	{ 
+	unsigned char *p;
+
+	if (s->state == a)
+		{
+		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;
+		s->init_off=0;
+
+		dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, 
+			s->d1->handshake_write_seq, 0, 0);
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 1);
+
+		s->state=b;
+		}
+
+	/* SSL3_ST_CW_CHANGE_B */
+	return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
+	}
+
+unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
+	{
+	unsigned char *p;
+	int n,i;
+	unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH;
+	BUF_MEM *buf;
+	X509_STORE_CTX xs_ctx;
+	X509_OBJECT obj;
+
+	/* TLSv1 sends a chain with nothing in it, instead of an alert */
+	buf=s->init_buf;
+	if (!BUF_MEM_grow_clean(buf,10))
+		{
+		SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+		return(0);
+		}
+	if (x != NULL)
+		{
+		if(!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,NULL,NULL))
+			{
+			SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
+			return(0);
+			}
+
+		for (;;)
+			{
+			n=i2d_X509(x,NULL);
+			if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
+				{
+				SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+				return(0);
+				}
+			p=(unsigned char *)&(buf->data[l]);
+			l2n3(n,p);
+			i2d_X509(x,&p);
+			l+=n+3;
+			if (X509_NAME_cmp(X509_get_subject_name(x),
+				X509_get_issuer_name(x)) == 0) break;
+
+			i=X509_STORE_get_by_subject(&xs_ctx,X509_LU_X509,
+				X509_get_issuer_name(x),&obj);
+			if (i <= 0) break;
+			x=obj.data.x509;
+			/* Count is one too high since the X509_STORE_get uped the
+			 * ref count */
+			X509_free(x);
+			}
+
+		X509_STORE_CTX_cleanup(&xs_ctx);
+		}
+
+	/* Thawte special :-) */
+	if (s->ctx->extra_certs != NULL)
+	for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
+		{
+		x=sk_X509_value(s->ctx->extra_certs,i);
+		n=i2d_X509(x,NULL);
+		if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
+			{
+			SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+			return(0);
+			}
+		p=(unsigned char *)&(buf->data[l]);
+		l2n3(n,p);
+		i2d_X509(x,&p);
+		l+=n+3;
+		}
+
+	l-= (3 + DTLS1_HM_HEADER_LENGTH);
+
+	p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
+	l2n3(l,p);
+	l+=3;
+	p=(unsigned char *)&(buf->data[0]);
+	p = dtls1_set_message_header(s, p, SSL3_MT_CERTIFICATE, l, 0, l);
+
+	l+=DTLS1_HM_HEADER_LENGTH;
+	return(l);
+	}
+
+int dtls1_read_failed(SSL *s, int code)
+    {
+    DTLS1_STATE *state;
+    BIO *bio;
+    int send_alert = 0;
+
+    if ( code > 0)
+        {
+        fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
+        return 1;
+        }
+
+    bio = SSL_get_rbio(s);
+    if ( ! BIO_dgram_recv_timedout(bio))
+        {
+        /* not a timeout, none of our business, 
+           let higher layers handle this.  in fact it's probably an error */
+        return code;
+        }
+
+    if ( ! SSL_in_init(s))  /* done, no need to send a retransmit */
+        {
+        BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
+        return code;
+        }
+
+    state = s->d1;
+    state->timeout.num_alerts++;
+    if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+        {
+        /* fail the connection, enough alerts have been sent */
+        SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED);
+        return 0;
+        }
+	
+    state->timeout.read_timeouts++;
+    if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
+        {
+        send_alert = 1;
+        state->timeout.read_timeouts = 1;
+        }
+
+	
+#if 0 /* for now, each alert contains only one record number */
+    item = pqueue_peek(state->rcvd_records);
+    if ( item )
+        {
+        /* send an alert immediately for all the missing records */
+        }
+    else
+#endif
+
+#if 0  /* no more alert sending, just retransmit the last set of messages */
+        if ( send_alert)
+            ssl3_send_alert(s,SSL3_AL_WARNING,
+                DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+#endif
+
+    return dtls1_retransmit_buffered_messages(s) ;
+    }
+
+
+static int
+dtls1_retransmit_buffered_messages(SSL *s)
+    {
+    pqueue sent = s->d1->sent_messages;
+    piterator iter;
+    pitem *item;
+    hm_fragment *frag;
+    int found = 0;
+
+    iter = pqueue_iterator(sent);
+
+    for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter))
+        {
+        frag = (hm_fragment *)item->data;
+        if ( dtls1_retransmit_message(s, frag->msg_header.seq, 0, &found) <= 0 &&
+            found)
+            {
+            fprintf(stderr, "dtls1_retransmit_message() failed\n");
+            return -1;
+            }
+        }
+
+    return 1;
+    }
+
+#if 0
+static dtls1_message_buffer *
+dtls1_message_buffer_new(unsigned int len)
+    {
+    dtls1_message_buffer *msg_buf;
+
+    msg_buf = (dtls1_message_buffer *) 
+        OPENSSL_malloc(sizeof(dtls1_message_buffer)); 
+    if ( msg_buf == NULL)
+        return NULL;
+
+    memset(msg_buf, 0x00, sizeof(dtls1_message_buffer));
+
+    msg_buf->data = (unsigned char *) OPENSSL_malloc(len);
+    if ( msg_buf->data == NULL)
+        {
+        OPENSSL_free(msg_buf);
+        return NULL;
+        }
+
+    memset(msg_buf->data, 0x00, len);
+    return msg_buf;
+    }
+#endif
+
+#if 0
+static void
+dtls1_message_buffer_free(dtls1_message_buffer *msg_buf)
+    {
+    if (msg_buf != NULL)
+        {
+        OPENSSL_free(msg_buf->data);
+        OPENSSL_free(msg_buf);
+        }
+    }
+#endif
+
+int
+dtls1_buffer_message(SSL *s, int is_ccs)
+    {
+    pitem *item;
+    hm_fragment *frag;
+
+    /* this function is called immediately after a message has 
+     * been serialized */
+    OPENSSL_assert(s->init_off == 0);
+
+    frag = dtls1_hm_fragment_new(s->init_num);
+
+    memcpy(frag->fragment, s->init_buf->data, s->init_num);
+
+    if ( is_ccs)
+        {
+        OPENSSL_assert(s->d1->w_msg_hdr.msg_len + 
+            DTLS1_CCS_HEADER_LENGTH == s->init_num);
+        }
+    else
+        {
+        OPENSSL_assert(s->d1->w_msg_hdr.msg_len + 
+            DTLS1_HM_HEADER_LENGTH == s->init_num);
+        }
+
+    frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.seq = s->d1->w_msg_hdr.seq;
+    frag->msg_header.type = s->d1->w_msg_hdr.type;
+    frag->msg_header.frag_off = 0;
+    frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.is_ccs = is_ccs;
+
+    item = pitem_new(frag->msg_header.seq, frag);
+    if ( item == NULL)
+        {
+        dtls1_hm_fragment_free(frag);
+        return 0;
+        }
+
+#if 0
+    fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type);
+    fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len);
+    fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num);
+#endif
+
+    pqueue_insert(s->d1->sent_messages, item);
+    return 1;
+    }
+
+int
+dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
+    int *found)
+    {
+    int ret;
+    /* XDTLS: for now assuming that read/writes are blocking */
+    pitem *item;
+    hm_fragment *frag ;
+    unsigned long header_length;
+
+    /*
+      OPENSSL_assert(s->init_num == 0);
+      OPENSSL_assert(s->init_off == 0);
+     */
+
+    /* XDTLS:  the requested message ought to be found, otherwise error */
+    item = pqueue_find(s->d1->sent_messages, seq);
+    if ( item == NULL)
+        {
+        fprintf(stderr, "retransmit:  message %d non-existant\n", seq);
+        *found = 0;
+        return 0;
+        }
+
+    *found = 1;
+    frag = (hm_fragment *)item->data;
+
+    if ( frag->msg_header.is_ccs)
+        header_length = DTLS1_CCS_HEADER_LENGTH;
+    else
+        header_length = DTLS1_HM_HEADER_LENGTH;
+
+    memcpy(s->init_buf->data, frag->fragment, 
+        frag->msg_header.msg_len + header_length);
+        s->init_num = frag->msg_header.msg_len + header_length;
+    
+    dtls1_set_message_header_int(s, frag->msg_header.type, 
+        frag->msg_header.msg_len, frag->msg_header.seq, 0, 
+        frag->msg_header.frag_len);
+
+    s->d1->retransmitting = 1;
+    ret = dtls1_do_write(s, frag->msg_header.is_ccs ? 
+        SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+    s->d1->retransmitting = 0;
+
+    BIO_flush(SSL_get_wbio(s));
+    return ret;
+    }
+
+/* call this function when the buffered messages are no longer needed */
+void
+dtls1_clear_record_buffer(SSL *s)
+    {
+    pitem *item;
+    
+    for(item = pqueue_pop(s->d1->sent_messages);
+        item != NULL; item = pqueue_pop(s->d1->sent_messages))
+        {
+        dtls1_hm_fragment_free((hm_fragment *)item->data);
+        pitem_free(item);
+        }
+    }
+
+
+unsigned char *
+dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt,
+    unsigned long len, unsigned long frag_off, unsigned long frag_len)
+    {
+    if ( frag_off == 0)
+        {
+        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+        s->d1->next_handshake_write_seq++;
+        }
+    
+    dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
+        frag_off, frag_len);
+    
+    return p += DTLS1_HM_HEADER_LENGTH;
+    }
+
+
+/* don't actually do the writing, wait till the MTU has been retrieved */
+static void
+dtls1_set_message_header_int(SSL *s, unsigned char mt,
+    unsigned long len, unsigned short seq_num, unsigned long frag_off, 
+    unsigned long frag_len)
+    {
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+    
+    msg_hdr->type = mt;
+    msg_hdr->msg_len = len;
+    msg_hdr->seq = seq_num;
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+}
+
+static void
+dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+	unsigned long frag_len)
+    {
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+    
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+    }
+
+static unsigned char *
+dtls1_write_message_header(SSL *s, unsigned char *p)
+    {
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+    
+    *p++ = msg_hdr->type;
+    l2n3(msg_hdr->msg_len, p);
+    
+    s2n(msg_hdr->seq, p);
+    l2n3(msg_hdr->frag_off, p);
+    l2n3(msg_hdr->frag_len, p);
+    
+    return p;
+    }
+
+static unsigned int 
+dtls1_min_mtu(void)
+    {
+    return 
+        g_probable_mtu[(sizeof(g_probable_mtu) / 
+           sizeof(g_probable_mtu[0])) - 1];
+    }
+
+static unsigned int 
+dtls1_guess_mtu(unsigned int curr_mtu)
+	{
+	int i;
+
+	if ( curr_mtu == 0 )
+		return g_probable_mtu[0] ;
+
+	for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
+		if ( curr_mtu > g_probable_mtu[i])
+			return g_probable_mtu[i];
+	
+	return curr_mtu;
+	}
+
+void
+dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
+    {
+    memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
+    msg_hdr->type = *(data++);
+    n2l3(data, msg_hdr->msg_len);
+    
+    n2s(data, msg_hdr->seq);
+    n2l3(data, msg_hdr->frag_off);
+    n2l3(data, msg_hdr->frag_len);
+    }
+
+void
+dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr)
+    {
+    memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
+    
+    ccs_hdr->type = *(data++);
+    n2s(data, ccs_hdr->seq);
+}
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
new file mode 100644
index 0000000..c53eae1
--- /dev/null
+++ b/ssl/d1_clnt.c
@@ -0,0 +1,1153 @@
+/* ssl/d1_clnt.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+static SSL_METHOD *dtls1_get_client_method(int ver);
+static int dtls1_get_hello_verify(SSL *s);
+
+static SSL_METHOD *dtls1_get_client_method(int ver)
+	{
+	if (ver == DTLS1_VERSION)
+		return(DTLSv1_client_method());
+	else
+		return(NULL);
+	}
+
+SSL_METHOD *DTLSv1_client_method(void)
+	{
+	static int init=1;
+	static SSL_METHOD DTLSv1_client_data;
+
+	if (init)
+		{
+		CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
+
+		if (init)
+			{
+			memcpy((char *)&DTLSv1_client_data,(char *)dtlsv1_base_method(),
+				sizeof(SSL_METHOD));
+			DTLSv1_client_data.ssl_connect=dtls1_connect;
+			DTLSv1_client_data.get_ssl_method=dtls1_get_client_method;
+			init=0;
+			}
+		
+		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
+		}
+	return(&DTLSv1_client_data);
+	}
+
+int dtls1_connect(SSL *s)
+	{
+	BUF_MEM *buf=NULL;
+	unsigned long Time=time(NULL),l;
+	long num1;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	int ret= -1;
+	int new_state,state,skip=0;;
+
+	RAND_add(&Time,sizeof(Time),0);
+	ERR_clear_error();
+	clear_sys_error();
+
+	if (s->info_callback != NULL)
+		cb=s->info_callback;
+	else if (s->ctx->info_callback != NULL)
+		cb=s->ctx->info_callback;
+	
+	s->in_handshake++;
+	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s); 
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch(s->state)
+			{
+		case SSL_ST_RENEGOTIATE:
+			s->new_session=1;
+			s->state=SSL_ST_CONNECT;
+			s->ctx->stats.sess_connect_renegotiate++;
+			/* break */
+		case SSL_ST_BEFORE:
+		case SSL_ST_CONNECT:
+		case SSL_ST_BEFORE|SSL_ST_CONNECT:
+		case SSL_ST_OK|SSL_ST_CONNECT:
+
+			s->server=0;
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+			if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00))
+				{
+				SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
+				ret = -1;
+				goto end;
+				}
+				
+			/* s->version=SSL3_VERSION; */
+			s->type=SSL_ST_CONNECT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				buf=NULL;
+				}
+
+			if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
+
+			/* setup buffing BIO */
+			if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
+
+			/* 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;
+			break;
+
+		case SSL3_ST_CW_CLNT_HELLO_A:
+		case SSL3_ST_CW_CLNT_HELLO_B:
+
+			s->shutdown=0;
+			ret=dtls1_client_hello(s);
+			if (ret <= 0) goto end;
+
+			if ( s->d1->send_cookie)
+				{
+				s->state=SSL3_ST_CW_FLUSH;
+				s->s3->tmp.next_state=SSL3_ST_CR_SRVR_HELLO_A;
+				}
+			else
+				s->state=SSL3_ST_CR_SRVR_HELLO_A;
+
+			s->init_num=0;
+
+			/* turn on buffering for the next lot of output */
+			if (s->bbio != s->wbio)
+				s->wbio=BIO_push(s->bbio,s->wbio);
+
+			break;
+
+		case SSL3_ST_CR_SRVR_HELLO_A:
+		case SSL3_ST_CR_SRVR_HELLO_B:
+			ret=ssl3_get_server_hello(s);
+			if (ret <= 0) goto end;
+			else
+				{
+				if (s->hit)
+					s->state=SSL3_ST_CR_FINISHED_A;
+				else
+					s->state=DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A;
+				}
+			s->init_num=0;
+			break;
+
+		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A:
+		case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B:
+
+			ret = dtls1_get_hello_verify(s);
+			if ( ret <= 0)
+				goto end;
+			if ( s->d1->send_cookie) /* start again, with a cookie */
+				s->state=SSL3_ST_CW_CLNT_HELLO_A;
+			else
+				s->state = SSL3_ST_CR_CERT_A;
+			s->init_num = 0;
+			break;
+
+		case SSL3_ST_CR_CERT_A:
+		case SSL3_ST_CR_CERT_B:
+			/* Check if it is anon DH */
+			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+				{
+				ret=ssl3_get_server_certificate(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip=1;
+			s->state=SSL3_ST_CR_KEY_EXCH_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CR_KEY_EXCH_A:
+		case SSL3_ST_CR_KEY_EXCH_B:
+			ret=ssl3_get_key_exchange(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CR_CERT_REQ_A;
+			s->init_num=0;
+
+			/* at this point we check that we have the
+			 * required stuff from the server */
+			if (!ssl3_check_cert_and_algorithm(s))
+				{
+				ret= -1;
+				goto end;
+				}
+			break;
+
+		case SSL3_ST_CR_CERT_REQ_A:
+		case SSL3_ST_CR_CERT_REQ_B:
+			ret=ssl3_get_certificate_request(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CR_SRVR_DONE_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CR_SRVR_DONE_A:
+		case SSL3_ST_CR_SRVR_DONE_B:
+			ret=ssl3_get_server_done(s);
+			if (ret <= 0) goto end;
+			if (s->s3->tmp.cert_req)
+				s->state=SSL3_ST_CW_CERT_A;
+			else
+				s->state=SSL3_ST_CW_KEY_EXCH_A;
+			s->init_num=0;
+
+			break;
+
+		case SSL3_ST_CW_CERT_A:
+		case SSL3_ST_CW_CERT_B:
+		case SSL3_ST_CW_CERT_C:
+		case SSL3_ST_CW_CERT_D:
+			ret=dtls1_send_client_certificate(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CW_KEY_EXCH_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CW_KEY_EXCH_A:
+		case SSL3_ST_CW_KEY_EXCH_B:
+			ret=dtls1_send_client_key_exchange(s);
+			if (ret <= 0) goto end;
+			l=s->s3->tmp.new_cipher->algorithms;
+			/* EAY EAY EAY need to check for DH fix cert
+			 * sent back */
+			/* For TLS, cert_req is set to 2, so a cert chain
+			 * of nothing is sent, but no verify packet is sent */
+			if (s->s3->tmp.cert_req == 1)
+				{
+				s->state=SSL3_ST_CW_CERT_VRFY_A;
+				}
+			else
+				{
+				s->state=SSL3_ST_CW_CHANGE_A;
+				s->s3->change_cipher_spec=0;
+				}
+
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CW_CERT_VRFY_A:
+		case SSL3_ST_CW_CERT_VRFY_B:
+			ret=dtls1_send_client_verify(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CW_CHANGE_A;
+			s->init_num=0;
+			s->s3->change_cipher_spec=0;
+			break;
+
+		case SSL3_ST_CW_CHANGE_A:
+		case SSL3_ST_CW_CHANGE_B:
+			ret=dtls1_send_change_cipher_spec(s,
+				SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CW_FINISHED_A;
+			s->init_num=0;
+
+			s->session->cipher=s->s3->tmp.new_cipher;
+			if (s->s3->tmp.new_compression == NULL)
+				s->session->compress_meth=0;
+			else
+				s->session->compress_meth=
+					s->s3->tmp.new_compression->id;
+			if (!s->method->ssl3_enc->setup_key_block(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			if (!s->method->ssl3_enc->change_cipher_state(s,
+				SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+				{
+				ret= -1;
+				goto end;
+				}
+			
+			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+			break;
+
+		case SSL3_ST_CW_FINISHED_A:
+		case SSL3_ST_CW_FINISHED_B:
+			ret=dtls1_send_finished(s,
+				SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
+				s->method->ssl3_enc->client_finished_label,
+				s->method->ssl3_enc->client_finished_label_len);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_CW_FLUSH;
+
+			/* clear flags */
+			s->s3->flags&= ~SSL3_FLAGS_POP_BUFFER;
+			if (s->hit)
+				{
+				s->s3->tmp.next_state=SSL_ST_OK;
+				if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)
+					{
+					s->state=SSL_ST_OK;
+					s->s3->flags|=SSL3_FLAGS_POP_BUFFER;
+					s->s3->delay_buf_pop_ret=0;
+					}
+				}
+			else
+				{
+				s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
+				}
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CR_FINISHED_A:
+		case SSL3_ST_CR_FINISHED_B:
+
+			ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
+				SSL3_ST_CR_FINISHED_B);
+			if (ret <= 0) goto end;
+
+			if (s->hit)
+				s->state=SSL3_ST_CW_CHANGE_A;
+			else
+				s->state=SSL_ST_OK;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_CW_FLUSH:
+			/* number of bytes to be flushed */
+			num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
+			if (num1 > 0)
+				{
+				s->rwstate=SSL_WRITING;
+				num1=BIO_flush(s->wbio);
+				if (num1 <= 0) { ret= -1; goto end; }
+				s->rwstate=SSL_NOTHING;
+				}
+
+			s->state=s->s3->tmp.next_state;
+			break;
+
+		case SSL_ST_OK:
+			/* clean a few things up */
+			ssl3_cleanup_key_block(s);
+
+#if 0
+			if (s->init_buf != NULL)
+				{
+				BUF_MEM_free(s->init_buf);
+				s->init_buf=NULL;
+				}
+#endif
+
+			/* If we are not 'joining' the last two packets,
+			 * remove the buffering now */
+			if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER))
+				ssl_free_wbio_buffer(s);
+			/* else do it later in ssl3_write */
+
+			s->init_num=0;
+			s->new_session=0;
+
+			ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
+			if (s->hit) s->ctx->stats.sess_hit++;
+
+			ret=1;
+			/* s->server=0; */
+			s->handshake_func=dtls1_connect;
+			s->ctx->stats.sess_connect_good++;
+
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+
+			/* done with handshaking */
+			s->d1->handshake_read_seq  = 0;
+			goto end;
+			/* break; */
+			
+		default:
+			SSLerr(SSL_F_SSL3_CONNECT,SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* break; */
+			}
+
+		/* did we do anything */
+		if (!s->s3->tmp.reuse_message && !skip)
+			{
+			if (s->debug)
+				{
+				if ((ret=BIO_flush(s->wbio)) <= 0)
+					goto end;
+				}
+
+			if ((cb != NULL) && (s->state != state))
+				{
+				new_state=s->state;
+				s->state=state;
+				cb(s,SSL_CB_CONNECT_LOOP,1);
+				s->state=new_state;
+				}
+			}
+		skip=0;
+		}
+end:
+	s->in_handshake--;
+	if (buf != NULL)
+		BUF_MEM_free(buf);
+	if (cb != NULL)
+		cb(s,SSL_CB_CONNECT_EXIT,ret);
+	return(ret);
+	}
+
+int dtls1_client_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i,j;
+	unsigned long Time,l;
+	SSL_COMP *comp;
+
+	buf=(unsigned char *)s->init_buf->data;
+	if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
+		{
+		if ((s->session == NULL) ||
+			(s->session->ssl_version != s->version) ||
+			(s->session->not_resumable))
+			{
+			if (!ssl_get_new_session(s,0))
+				goto err;
+			}
+		/* else use the pre-loaded session */
+
+		p=s->s3->client_random;
+		Time=time(NULL);			/* Time */
+		l2n(Time,p);
+		RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+
+		/* Do the message type and length last */
+		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
+
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+		s->client_version=s->version;
+
+		/* Random stuff */
+		memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
+		p+=SSL3_RANDOM_SIZE;
+
+		/* Session ID */
+		if (s->new_session)
+			i=0;
+		else
+			i=s->session->session_id_length;
+		*(p++)=i;
+		if (i != 0)
+			{
+			if (i > sizeof s->session->session_id)
+				{
+				SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			memcpy(p,s->session->session_id,i);
+			p+=i;
+			}
+		
+		/* cookie stuff */
+		if ( s->d1->cookie_len > sizeof(s->d1->cookie))
+			{
+			SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+		*(p++) = s->d1->cookie_len;
+		memcpy(p, s->d1->cookie, s->d1->cookie_len);
+		p += s->d1->cookie_len;
+
+		/* Ciphers supported */
+		i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),&(p[2]));
+		if (i == 0)
+			{
+			SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
+			goto err;
+			}
+		s2n(i,p);
+		p+=i;
+
+		/* COMPRESSION */
+		if (s->ctx->comp_methods == NULL)
+			j=0;
+		else
+			j=sk_SSL_COMP_num(s->ctx->comp_methods);
+		*(p++)=1+j;
+		for (i=0; i<j; i++)
+			{
+			comp=sk_SSL_COMP_value(s->ctx->comp_methods,i);
+			*(p++)=comp->id;
+			}
+		*(p++)=0; /* Add the NULL method */
+		
+		l=(p-d);
+		d=buf;
+
+		d = dtls1_set_message_header(s, d, SSL3_MT_CLIENT_HELLO, l, 0, l);
+
+		s->state=SSL3_ST_CW_CLNT_HELLO_B;
+		/* number of bytes to write */
+		s->init_num=p-buf;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+	return(-1);
+	}
+
+static int dtls1_get_hello_verify(SSL *s)
+	{
+	int n, al, ok = 0;
+	unsigned char *data;
+	unsigned int cookie_len;
+
+	n=s->method->ssl_get_message(s,
+		DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A,
+		DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B,
+		-1,
+		s->max_cert_list,
+		&ok);
+
+	if (!ok) return((int)n);
+
+	if (s->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST)
+		{
+		s->d1->send_cookie = 0;
+		s->s3->tmp.reuse_message=1;
+		return(1);
+		}
+
+	data = (unsigned char *)s->init_msg;
+
+	if ((data[0] != (s->version>>8)) || (data[1] != (s->version&0xff)))
+		{
+		SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION);
+		s->version=(s->version&0xff00)|data[1];
+		al = SSL_AD_PROTOCOL_VERSION;
+		goto f_err;
+		}
+	data+=2;
+
+	cookie_len = *(data++);
+	if ( cookie_len > sizeof(s->d1->cookie))
+		{
+		al=SSL_AD_ILLEGAL_PARAMETER;
+		goto f_err;
+		}
+
+	memcpy(s->d1->cookie, data, cookie_len);
+	s->d1->cookie_len = cookie_len;
+
+	s->d1->send_cookie = 1;
+	return 1;
+
+f_err:
+	ssl3_send_alert(s, SSL3_AL_FATAL, al);
+	return -1;
+	}
+
+int dtls1_send_client_key_exchange(SSL *s)
+	{
+	unsigned char *p,*d;
+	int n;
+	unsigned long l;
+#ifndef OPENSSL_NO_RSA
+	unsigned char *q;
+	EVP_PKEY *pkey=NULL;
+#endif
+#ifndef OPENSSL_NO_KRB5
+        KSSL_ERR kssl_err;
+#endif /* OPENSSL_NO_KRB5 */
+
+	if (s->state == SSL3_ST_CW_KEY_EXCH_A)
+		{
+		d=(unsigned char *)s->init_buf->data;
+		p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+		l=s->s3->tmp.new_cipher->algorithms;
+
+                /* Fool emacs indentation */
+                if (0) {}
+#ifndef OPENSSL_NO_RSA
+		else if (l & SSL_kRSA)
+			{
+			RSA *rsa;
+			unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+
+			if (s->session->sess_cert->peer_rsa_tmp != NULL)
+				rsa=s->session->sess_cert->peer_rsa_tmp;
+			else
+				{
+				pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+				if ((pkey == NULL) ||
+					(pkey->type != EVP_PKEY_RSA) ||
+					(pkey->pkey.rsa == NULL))
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+					goto err;
+					}
+				rsa=pkey->pkey.rsa;
+				EVP_PKEY_free(pkey);
+				}
+				
+			tmp_buf[0]=s->client_version>>8;
+			tmp_buf[1]=s->client_version&0xff;
+			if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
+					goto err;
+
+			s->session->master_key_length=sizeof tmp_buf;
+
+			q=p;
+			/* Fix buf for TLS and beyond */
+			if (s->version > SSL3_VERSION)
+				p+=2;
+			n=RSA_public_encrypt(sizeof tmp_buf,
+				tmp_buf,p,rsa,RSA_PKCS1_PADDING);
+#ifdef PKCS1_CHECK
+			if (s->options & SSL_OP_PKCS1_CHECK_1) p[1]++;
+			if (s->options & SSL_OP_PKCS1_CHECK_2) tmp_buf[0]=0x70;
+#endif
+			if (n <= 0)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_ENCRYPT);
+				goto err;
+				}
+
+			/* Fix buf for TLS and beyond */
+			if (s->version > SSL3_VERSION)
+				{
+				s2n(n,q);
+				n+=2;
+				}
+
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,
+					tmp_buf,sizeof tmp_buf);
+			OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
+			}
+#endif
+#ifndef OPENSSL_NO_KRB5
+		else if (l & SSL_kKRB5)
+                        {
+                        krb5_error_code	krb5rc;
+                        KSSL_CTX	*kssl_ctx = s->kssl_ctx;
+                        /*  krb5_data	krb5_ap_req;  */
+                        krb5_data	*enc_ticket;
+                        krb5_data	authenticator, *authp = NULL;
+			EVP_CIPHER_CTX	ciph_ctx;
+			EVP_CIPHER	*enc = NULL;
+			unsigned char	iv[EVP_MAX_IV_LENGTH];
+			unsigned char	tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+			unsigned char	epms[SSL_MAX_MASTER_KEY_LENGTH 
+						+ EVP_MAX_IV_LENGTH];
+			int 		padl, outl = sizeof(epms);
+
+			EVP_CIPHER_CTX_init(&ciph_ctx);
+
+#ifdef KSSL_DEBUG
+                        printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
+                                l, SSL_kKRB5);
+#endif	/* KSSL_DEBUG */
+
+			authp = NULL;
+#ifdef KRB5SENDAUTH
+			if (KRB5SENDAUTH)  authp = &authenticator;
+#endif	/* KRB5SENDAUTH */
+
+                        krb5rc = kssl_cget_tkt(kssl_ctx, &enc_ticket, authp,
+				&kssl_err);
+			enc = kssl_map_enc(kssl_ctx->enctype);
+                        if (enc == NULL)
+                            goto err;
+#ifdef KSSL_DEBUG
+                        {
+                        printf("kssl_cget_tkt rtn %d\n", krb5rc);
+                        if (krb5rc && kssl_err.text)
+			  printf("kssl_cget_tkt kssl_err=%s\n", kssl_err.text);
+                        }
+#endif	/* KSSL_DEBUG */
+
+                        if (krb5rc)
+                                {
+                                ssl3_send_alert(s,SSL3_AL_FATAL,
+						SSL_AD_HANDSHAKE_FAILURE);
+                                SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+						kssl_err.reason);
+                                goto err;
+                                }
+
+			/*  20010406 VRS - Earlier versions used KRB5 AP_REQ
+			**  in place of RFC 2712 KerberosWrapper, as in:
+			**
+                        **  Send ticket (copy to *p, set n = length)
+                        **  n = krb5_ap_req.length;
+                        **  memcpy(p, krb5_ap_req.data, krb5_ap_req.length);
+                        **  if (krb5_ap_req.data)  
+                        **    kssl_krb5_free_data_contents(NULL,&krb5_ap_req);
+                        **
+			**  Now using real RFC 2712 KerberosWrapper
+			**  (Thanks to Simon Wilkinson <sxw@sxw.org.uk>)
+			**  Note: 2712 "opaque" types are here replaced
+			**  with a 2-byte length followed by the value.
+			**  Example:
+			**  KerberosWrapper= xx xx asn1ticket 0 0 xx xx encpms
+			**  Where "xx xx" = length bytes.  Shown here with
+			**  optional authenticator omitted.
+			*/
+
+			/*  KerberosWrapper.Ticket		*/
+			s2n(enc_ticket->length,p);
+			memcpy(p, enc_ticket->data, enc_ticket->length);
+			p+= enc_ticket->length;
+			n = enc_ticket->length + 2;
+
+			/*  KerberosWrapper.Authenticator	*/
+			if (authp  &&  authp->length)  
+				{
+				s2n(authp->length,p);
+				memcpy(p, authp->data, authp->length);
+				p+= authp->length;
+				n+= authp->length + 2;
+				
+				free(authp->data);
+				authp->data = NULL;
+				authp->length = 0;
+				}
+			else
+				{
+				s2n(0,p);/*  null authenticator length	*/
+				n+=2;
+				}
+ 
+			if (RAND_bytes(tmp_buf,sizeof tmp_buf) <= 0)
+			    goto err;
+
+			/*  20010420 VRS.  Tried it this way; failed.
+			**	EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,NULL);
+			**	EVP_CIPHER_CTX_set_key_length(&ciph_ctx,
+			**				kssl_ctx->length);
+			**	EVP_EncryptInit_ex(&ciph_ctx,NULL, key,iv);
+			*/
+
+			memset(iv, 0, sizeof iv);  /* per RFC 1510 */
+			EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,
+				kssl_ctx->key,iv);
+			EVP_EncryptUpdate(&ciph_ctx,epms,&outl,tmp_buf,
+				sizeof tmp_buf);
+			EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
+			outl += padl;
+			if (outl > sizeof epms)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+			/*  KerberosWrapper.EncryptedPreMasterSecret	*/
+			s2n(outl,p);
+			memcpy(p, epms, outl);
+			p+=outl;
+			n+=outl + 2;
+
+                        s->session->master_key_length=
+                                s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,
+					tmp_buf, sizeof tmp_buf);
+
+			OPENSSL_cleanse(tmp_buf, sizeof tmp_buf);
+			OPENSSL_cleanse(epms, outl);
+                        }
+#endif
+#ifndef OPENSSL_NO_DH
+		else if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
+			{
+			DH *dh_srvr,*dh_clnt;
+
+			if (s->session->sess_cert->peer_dh_tmp != NULL)
+				dh_srvr=s->session->sess_cert->peer_dh_tmp;
+			else
+				{
+				/* we get them from the cert */
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
+				goto err;
+				}
+			
+			/* generate a new random key */
+			if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+				goto err;
+				}
+			if (!DH_generate_key(dh_clnt))
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+				goto err;
+				}
+
+			/* use the 'p' output buffer for the DH key, but
+			 * make sure to clear it out afterwards */
+
+			n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+
+			if (n <= 0)
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+				goto err;
+				}
+
+			/* generate master key from the result */
+			s->session->master_key_length=
+				s->method->ssl3_enc->generate_master_secret(s,
+					s->session->master_key,p,n);
+			/* clean up */
+			memset(p,0,n);
+
+			/* send off the data */
+			n=BN_num_bytes(dh_clnt->pub_key);
+			s2n(n,p);
+			BN_bn2bin(dh_clnt->pub_key,p);
+			n+=2;
+
+			DH_free(dh_clnt);
+
+			/* perhaps clean things up a bit EAY EAY EAY EAY*/
+			}
+#endif
+		else
+			{
+			ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+			SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+		
+		d = dtls1_set_message_header(s, d,
+		SSL3_MT_CLIENT_KEY_EXCHANGE, n, 0, n);
+		/*
+		 *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE;
+		 l2n3(n,d);
+		 l2n(s->d1->handshake_write_seq,d);
+		 s->d1->handshake_write_seq++;
+		*/
+		
+		s->state=SSL3_ST_CW_KEY_EXCH_B;
+		/* number of bytes to write */
+		s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+	
+	/* SSL3_ST_CW_KEY_EXCH_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+	return(-1);
+	}
+
+int dtls1_send_client_verify(SSL *s)
+	{
+	unsigned char *p,*d;
+	unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+	EVP_PKEY *pkey;
+#ifndef OPENSSL_NO_RSA
+	unsigned u=0;
+#endif
+	unsigned long n;
+#ifndef OPENSSL_NO_DSA
+	int j;
+#endif
+
+	if (s->state == SSL3_ST_CW_CERT_VRFY_A)
+		{
+		d=(unsigned char *)s->init_buf->data;
+		p= &(d[DTLS1_HM_HEADER_LENGTH]);
+		pkey=s->cert->key->privatekey;
+
+		s->method->ssl3_enc->cert_verify_mac(s,&(s->s3->finish_dgst2),
+			&(data[MD5_DIGEST_LENGTH]));
+
+#ifndef OPENSSL_NO_RSA
+		if (pkey->type == EVP_PKEY_RSA)
+			{
+			s->method->ssl3_enc->cert_verify_mac(s,
+				&(s->s3->finish_dgst1),&(data[0]));
+			if (RSA_sign(NID_md5_sha1, data,
+					 MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
+					&(p[2]), &u, pkey->pkey.rsa) <= 0 )
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_RSA_LIB);
+				goto err;
+				}
+			s2n(u,p);
+			n=u+2;
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_DSA
+			if (pkey->type == EVP_PKEY_DSA)
+			{
+			if (!DSA_sign(pkey->save_type,
+				&(data[MD5_DIGEST_LENGTH]),
+				SHA_DIGEST_LENGTH,&(p[2]),
+				(unsigned int *)&j,pkey->pkey.dsa))
+				{
+				SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_DSA_LIB);
+				goto err;
+				}
+			s2n(j,p);
+			n=j+2;
+			}
+		else
+#endif
+			{
+			SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
+			goto err;
+			}
+
+		d = dtls1_set_message_header(s, d,
+			SSL3_MT_CERTIFICATE_VERIFY, n, 0, n) ;
+
+		s->init_num=(int)n+DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+
+		s->state = SSL3_ST_CW_CERT_VRFY_B;
+		}
+
+	/* s->state = SSL3_ST_CW_CERT_VRFY_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+	return(-1);
+	}
+
+int dtls1_send_client_certificate(SSL *s)
+	{
+	X509 *x509=NULL;
+	EVP_PKEY *pkey=NULL;
+	int i;
+	unsigned long l;
+
+	if (s->state ==	SSL3_ST_CW_CERT_A)
+		{
+		if ((s->cert == NULL) ||
+			(s->cert->key->x509 == NULL) ||
+			(s->cert->key->privatekey == NULL))
+			s->state=SSL3_ST_CW_CERT_B;
+		else
+			s->state=SSL3_ST_CW_CERT_C;
+		}
+
+	/* We need to get a client cert */
+	if (s->state == SSL3_ST_CW_CERT_B)
+		{
+		/* If we get an error, we need to
+		 * ssl->rwstate=SSL_X509_LOOKUP; return(-1);
+		 * We then get retied later */
+		i=0;
+		if (s->ctx->client_cert_cb != NULL)
+			i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
+		if (i < 0)
+			{
+			s->rwstate=SSL_X509_LOOKUP;
+			return(-1);
+			}
+		s->rwstate=SSL_NOTHING;
+		if ((i == 1) && (pkey != NULL) && (x509 != NULL))
+			{
+			s->state=SSL3_ST_CW_CERT_B;
+			if (	!SSL_use_certificate(s,x509) ||
+				!SSL_use_PrivateKey(s,pkey))
+				i=0;
+			}
+		else if (i == 1)
+			{
+			i=0;
+			SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE,SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+			}
+
+		if (x509 != NULL) X509_free(x509);
+		if (pkey != NULL) EVP_PKEY_free(pkey);
+		if (i == 0)
+			{
+			if (s->version == SSL3_VERSION)
+				{
+				s->s3->tmp.cert_req=0;
+				ssl3_send_alert(s,SSL3_AL_WARNING,SSL_AD_NO_CERTIFICATE);
+				return(1);
+				}
+			else
+				{
+				s->s3->tmp.cert_req=2;
+				}
+			}
+
+		/* Ok, we have a cert */
+		s->state=SSL3_ST_CW_CERT_C;
+		}
+
+	if (s->state == SSL3_ST_CW_CERT_C)
+		{
+		s->state=SSL3_ST_CW_CERT_D;
+		l=dtls1_output_cert_chain(s,
+			(s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509);
+		s->init_num=(int)l;
+		s->init_off=0;
+
+		/* set header called by dtls1_output_cert_chain() */
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+	/* SSL3_ST_CW_CERT_D */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
new file mode 100644
index 0000000..7b36964
--- /dev/null
+++ b/ssl/d1_enc.c
@@ -0,0 +1,278 @@
+/* ssl/d1_enc.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/comp.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+
+
+int dtls1_enc(SSL *s, int send)
+	{
+	SSL3_RECORD *rec;
+	EVP_CIPHER_CTX *ds;
+	unsigned long l;
+	int bs,i,ii,j,k,n=0;
+	const EVP_CIPHER *enc;
+
+	if (send)
+		{
+		if (s->write_hash != NULL)
+			n=EVP_MD_size(s->write_hash);
+		ds=s->enc_write_ctx;
+		rec= &(s->s3->wrec);
+		if (s->enc_write_ctx == NULL)
+			enc=NULL;
+		else
+			{
+			enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx);
+			if ( rec->data != rec->input)
+				/* we can't write into the input stream */
+				fprintf(stderr, "%s:%d: rec->data != rec->input\n",
+					__FILE__, __LINE__);
+			else if ( EVP_CIPHER_block_size(ds->cipher) > 1)
+				RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher));
+			}
+		}
+	else
+		{
+		if (s->read_hash != NULL)
+			n=EVP_MD_size(s->read_hash);
+		ds=s->enc_read_ctx;
+		rec= &(s->s3->rrec);
+		if (s->enc_read_ctx == NULL)
+			enc=NULL;
+		else
+			enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx);
+		}
+
+#ifdef KSSL_DEBUG
+	printf("dtls1_enc(%d)\n", send);
+#endif    /* KSSL_DEBUG */
+
+	if ((s->session == NULL) || (ds == NULL) ||
+		(enc == NULL))
+		{
+		memmove(rec->data,rec->input,rec->length);
+		rec->input=rec->data;
+		}
+	else
+		{
+		l=rec->length;
+		bs=EVP_CIPHER_block_size(ds->cipher);
+
+		if ((bs != 1) && send)
+			{
+			i=bs-((int)l%bs);
+
+			/* Add weird padding of upto 256 bytes */
+
+			/* we need to add 'i' padding bytes of value j */
+			j=i-1;
+			if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG)
+				{
+				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+					j++;
+				}
+			for (k=(int)l; k<(int)(l+i); k++)
+				rec->input[k]=j;
+			l+=i;
+			rec->length+=i;
+			}
+
+#ifdef KSSL_DEBUG
+		{
+                unsigned long ui;
+		printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n",
+                        ds,rec->data,rec->input,l);
+		printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n",
+                        ds->buf_len, ds->cipher->key_len,
+                        DES_KEY_SZ, DES_SCHEDULE_SZ,
+                        ds->cipher->iv_len);
+		printf("\t\tIV: ");
+		for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]);
+		printf("\n");
+		printf("\trec->input=");
+		for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]);
+		printf("\n");
+		}
+#endif	/* KSSL_DEBUG */
+
+		if (!send)
+			{
+			if (l == 0 || l%bs != 0)
+				{
+				SSLerr(SSL_F_TLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
+				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED);
+				return 0;
+				}
+			}
+		
+		EVP_Cipher(ds,rec->data,rec->input,l);
+
+#ifdef KSSL_DEBUG
+		{
+                unsigned long i;
+                printf("\trec->data=");
+		for (i=0; i<l; i++)
+                        printf(" %02x", rec->data[i]);  printf("\n");
+                }
+#endif	/* KSSL_DEBUG */
+
+		if ((bs != 1) && !send)
+			{
+			ii=i=rec->data[l-1]; /* padding_length */
+			i++;
+			if (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG)
+				{
+				/* First packet is even in size, so check */
+				if ((memcmp(s->s3->read_sequence,
+					"\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1))
+					s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
+				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
+					i--;
+				}
+			/* TLS 1.0 does not bound the number of padding bytes by the block size.
+			 * All of them must have value 'padding_length'. */
+			if (i > (int)rec->length)
+				{
+				/* Incorrect padding. SSLerr() and ssl3_alert are done
+				 * by caller: we don't want to reveal whether this is
+				 * a decryption error or a MAC verification failure
+				 * (see http://www.openssl.org/~bodo/tls-cbc.txt) 
+				 */
+				return -1;
+				}
+			for (j=(int)(l-i); j<(int)l; j++)
+				{
+				if (rec->data[j] != ii)
+					{
+					/* Incorrect padding */
+					return -1;
+					}
+				}
+			rec->length-=i;
+
+			rec->data += bs;    /* skip the implicit IV */
+			rec->input += bs;
+			rec->length -= bs;
+			}
+		}
+	return(1);
+	}
+
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
new file mode 100644
index 0000000..d774521
--- /dev/null
+++ b/ssl/d1_lib.c
@@ -0,0 +1,208 @@
+/* ssl/d1_lib.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+const char *dtls1_version_str="DTLSv1" OPENSSL_VERSION_PTEXT;
+
+static long dtls1_default_timeout(void);
+
+static SSL3_ENC_METHOD DTLSv1_enc_data={
+    dtls1_enc,
+	tls1_mac,
+	tls1_setup_key_block,
+	tls1_generate_master_secret,
+	tls1_change_cipher_state,
+	tls1_final_finish_mac,
+	TLS1_FINISH_MAC_LENGTH,
+	tls1_cert_verify_mac,
+	TLS_MD_CLIENT_FINISH_CONST,TLS_MD_CLIENT_FINISH_CONST_SIZE,
+	TLS_MD_SERVER_FINISH_CONST,TLS_MD_SERVER_FINISH_CONST_SIZE,
+	tls1_alert_code,
+	};
+
+static SSL_METHOD DTLSv1_data= {
+	DTLS1_VERSION,
+	dtls1_new,
+	dtls1_clear,
+	dtls1_free,
+	ssl_undefined_function,
+	ssl_undefined_function,
+	ssl3_read,
+	ssl3_peek,
+	ssl3_write,
+	ssl3_shutdown,
+	ssl3_renegotiate,
+	ssl3_renegotiate_check,
+	dtls1_get_message,
+	dtls1_read_bytes,
+	dtls1_write_app_data_bytes,
+	dtls1_dispatch_alert,
+	ssl3_ctrl,
+	ssl3_ctx_ctrl,
+	ssl3_get_cipher_by_char,
+	ssl3_put_cipher_by_char,
+	ssl3_pending,
+	ssl3_num_ciphers,
+	ssl3_get_cipher,
+	ssl_bad_method,
+	dtls1_default_timeout,
+	&DTLSv1_enc_data,
+	ssl_undefined_void_function,
+	ssl3_callback_ctrl,
+	ssl3_ctx_callback_ctrl,
+	};
+
+static long dtls1_default_timeout(void)
+	{
+	/* 2 hours, the 24 hours mentioned in the DTLSv1 spec
+	 * is way too long for http, the cache would over fill */
+	return(60*60*2);
+	}
+
+SSL_METHOD *dtlsv1_base_method(void)
+	{
+	return(&DTLSv1_data);
+	}
+
+int dtls1_new(SSL *s)
+	{
+	DTLS1_STATE *d1;
+
+	if (!ssl3_new(s)) return(0);
+	if ((d1=OPENSSL_malloc(sizeof *d1)) == NULL) return (0);
+	memset(d1,0, sizeof *d1);
+
+	/* d1->handshake_epoch=0; */
+	d1->bitmap.length=sizeof(d1->bitmap.map) * 8;
+	d1->unprocessed_rcds.q=pqueue_new();
+    d1->processed_rcds.q=pqueue_new();
+    d1->buffered_messages = pqueue_new();
+	d1->sent_messages=pqueue_new();
+
+	if ( s->server)
+		{
+		d1->cookie_len = sizeof(s->d1->cookie);
+		}
+
+	if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q 
+        || ! d1->buffered_messages || ! d1->sent_messages)
+		{
+        if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
+        if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q);
+        if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
+		if ( d1->sent_messages) pqueue_free(d1->sent_messages);
+		OPENSSL_free(d1);
+		return (0);
+		}
+
+	s->d1=d1;
+	s->method->ssl_clear(s);
+	return(1);
+	}
+
+void dtls1_free(SSL *s)
+	{
+    pitem *item = NULL;
+    hm_fragment *frag = NULL;
+
+	ssl3_free(s);
+
+    while( (item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL)
+        {
+        OPENSSL_free(item->data);
+        pitem_free(item);
+        }
+    pqueue_free(s->d1->unprocessed_rcds.q);
+
+    while( (item = pqueue_pop(s->d1->processed_rcds.q)) != NULL)
+        {
+        OPENSSL_free(item->data);
+        pitem_free(item);
+        }
+    pqueue_free(s->d1->processed_rcds.q);
+
+    while( (item = pqueue_pop(s->d1->buffered_messages)) != NULL)
+        {
+        frag = (hm_fragment *)item->data;
+        OPENSSL_free(frag->fragment);
+        OPENSSL_free(frag);
+        pitem_free(item);
+        }
+    pqueue_free(s->d1->buffered_messages);
+
+    while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL)
+        {
+        frag = (hm_fragment *)item->data;
+        OPENSSL_free(frag->fragment);
+        OPENSSL_free(frag);
+        pitem_free(item);
+        }
+	pqueue_free(s->d1->sent_messages);
+
+	OPENSSL_free(s->d1);
+	}
+
+void dtls1_clear(SSL *s)
+	{
+	ssl3_clear(s);
+	s->version=DTLS1_VERSION;
+	}
diff --git a/ssl/d1_meth.c b/ssl/d1_meth.c
new file mode 100644
index 0000000..dc4c8ed
--- /dev/null
+++ b/ssl/d1_meth.c
@@ -0,0 +1,96 @@
+/* ssl/d1_meth.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+static SSL_METHOD *dtls1_get_method(int ver);
+static SSL_METHOD *dtls1_get_method(int ver)
+	{
+	if (ver == DTLS1_VERSION)
+		return(DTLSv1_method());
+	else
+		return(NULL);
+	}
+
+SSL_METHOD *DTLSv1_method(void)
+	{
+	static int init=1;
+	static SSL_METHOD DTLSv1_data;
+
+	if (init)
+		{
+		CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
+		
+		if (init)
+			{
+			memcpy((char *)&DTLSv1_data,(char *)dtlsv1_base_method(),
+				sizeof(SSL_METHOD));
+			DTLSv1_data.ssl_connect=dtls1_connect;
+			DTLSv1_data.ssl_accept=dtls1_accept;
+			DTLSv1_data.get_ssl_method=dtls1_get_method;
+			init=0;
+			}
+
+		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
+		}
+	
+	return(&DTLSv1_data);
+	}
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
new file mode 100644
index 0000000..4b3aabc
--- /dev/null
+++ b/ssl/d1_pkt.c
@@ -0,0 +1,1707 @@
+/* ssl/d1_pkt.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#define USE_SOCKETS
+#include "ssl_locl.h"
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+
+static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
+	int len, int peek);
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap,
+	unsigned long long *seq_num);
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap);
+static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, 
+    unsigned int *is_next_epoch);
+#if 0
+static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
+	unsigned short *priority, unsigned long *offset);
+#endif
+static int dtls1_buffer_record(SSL *s, record_pqueue *q,
+	unsigned long long priority);
+static int dtls1_process_record(SSL *s);
+static unsigned long long bytes_to_long_long(unsigned char *bytes);
+static void long_long_to_bytes(unsigned long long num, unsigned char *bytes);
+static void dtls1_clear_timeouts(SSL *s);
+
+
+/* copy buffered record into SSL structure */
+static int
+dtls1_copy_record(SSL *s, pitem *item)
+    {
+    DTLS1_RECORD_DATA *rdata;
+
+    rdata = (DTLS1_RECORD_DATA *)item->data;
+    
+    if (s->s3->rbuf.buf != NULL)
+        OPENSSL_free(s->s3->rbuf.buf);
+    
+    s->packet = rdata->packet;
+    s->packet_length = rdata->packet_length;
+    memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+    memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+    
+    return(1);
+    }
+
+
+static int
+dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned long long priority)
+{
+    DTLS1_RECORD_DATA *rdata;
+	pitem *item;
+
+	rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
+	item = pitem_new(priority, rdata);
+	if (rdata == NULL || item == NULL)
+		{
+		if (rdata != NULL) OPENSSL_free(rdata);
+		if (item != NULL) pitem_free(item);
+		
+		SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
+		return(0);
+		}
+	
+	rdata->packet = s->packet;
+	rdata->packet_length = s->packet_length;
+	memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER));
+	memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD));
+
+	item->data = rdata;
+
+	/* insert should not fail, since duplicates are dropped */
+	if (pqueue_insert(queue->q, item) == NULL)
+		{
+		OPENSSL_free(rdata);
+		pitem_free(item);
+		return(0);
+		}
+
+	s->packet = NULL;
+	s->packet_length = 0;
+	memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER));
+	memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD));
+	
+	ssl3_setup_buffers(s);
+	
+	return(1);
+    }
+
+
+static int
+dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue)
+    {
+    pitem *item;
+
+    item = pqueue_pop(queue->q);
+    if (item)
+        {
+        dtls1_copy_record(s, item);
+
+        OPENSSL_free(item->data);
+		pitem_free(item);
+
+        return(1);
+        }
+
+    return(0);
+    }
+
+
+/* retrieve a buffered record that belongs to the new epoch, i.e., not processed 
+ * yet */
+#define dtls1_get_unprocessed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &((s)->d1->unprocessed_rcds))
+
+/* retrieve a buffered record that belongs to the current epoch, ie, processed */
+#define dtls1_get_processed_record(s) \
+                   dtls1_retrieve_buffered_record((s), \
+                   &((s)->d1->processed_rcds))
+
+static int
+dtls1_process_buffered_records(SSL *s)
+    {
+    pitem *item;
+    
+    item = pqueue_peek(s->d1->unprocessed_rcds.q);
+    if (item)
+        {
+        DTLS1_RECORD_DATA *rdata;
+        rdata = (DTLS1_RECORD_DATA *)item->data;
+        
+        /* Check if epoch is current. */
+        if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch)
+            return(1);  /* Nothing to do. */
+        
+        /* Process all the records. */
+        while (pqueue_peek(s->d1->unprocessed_rcds.q))
+            {
+            dtls1_get_unprocessed_record(s);
+            if ( ! dtls1_process_record(s))
+                return(0);
+            dtls1_buffer_record(s, &(s->d1->processed_rcds), 
+                s->s3->rrec.seq_num);
+            }
+        }
+
+    /* sync epoch numbers once all the unprocessed records 
+     * have been processed */
+    s->d1->processed_rcds.epoch = s->d1->r_epoch;
+    s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1;
+
+    return(1);
+    }
+
+
+#if 0
+
+static int
+dtls1_get_buffered_record(SSL *s)
+	{
+	pitem *item;
+	unsigned long long priority = 
+		(((unsigned long long)s->d1->handshake_read_seq) << 32) | 
+		((unsigned long long)s->d1->r_msg_hdr.frag_off);
+	
+	if ( ! SSL_in_init(s))  /* if we're not (re)negotiating, 
+							   nothing buffered */
+		return 0;
+
+
+	item = pqueue_peek(s->d1->rcvd_records);
+	if (item && item->priority == priority)
+		{
+		/* Check if we've received the record of interest.  It must be
+		 * a handshake record, since data records as passed up without
+		 * buffering */
+		DTLS1_RECORD_DATA *rdata;
+		item = pqueue_pop(s->d1->rcvd_records);
+		rdata = (DTLS1_RECORD_DATA *)item->data;
+		
+		if (s->s3->rbuf.buf != NULL)
+			OPENSSL_free(s->s3->rbuf.buf);
+		
+		s->packet = rdata->packet;
+		s->packet_length = rdata->packet_length;
+		memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER));
+		memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD));
+		
+		OPENSSL_free(item->data);
+		pitem_free(item);
+		
+		/* s->d1->next_expected_seq_num++; */
+		return(1);
+		}
+	
+	return 0;
+	}
+
+#endif
+
+static int
+dtls1_process_record(SSL *s)
+{
+    int i,al;
+	int clear=0;
+    int enc_err;
+	SSL_SESSION *sess;
+    SSL3_RECORD *rr;
+	unsigned int mac_size;
+	unsigned char md[EVP_MAX_MD_SIZE];
+
+
+	rr= &(s->s3->rrec);
+    sess = s->session;
+
+	/* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length,
+	 * and we have that many bytes in s->packet
+	 */
+	rr->input= &(s->packet[DTLS1_RT_HEADER_LENGTH]);
+
+	/* ok, we can now read from 's->packet' data into 'rr'
+	 * rr->input points at rr->length bytes, which
+	 * need to be copied into rr->data by either
+	 * the decryption or by the decompression
+	 * When the data is 'copied' into the rr->data buffer,
+	 * rr->input will be pointed at the new buffer */ 
+
+	/* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
+	 * rr->length bytes of encrypted compressed stuff. */
+
+	/* check is not needed I believe */
+	if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	/* decrypt in place in 'rr->input' */
+	rr->data=rr->input;
+
+	enc_err = s->method->ssl3_enc->enc(s,0);
+	if (enc_err <= 0)
+		{
+		if (enc_err == 0)
+			/* SSLerr() and ssl3_send_alert() have been called */
+			goto err;
+
+		/* otherwise enc_err == -1 */
+		goto decryption_failed_or_bad_record_mac;
+		}
+
+#ifdef TLS_DEBUG
+printf("dec %d\n",rr->length);
+{ unsigned int z; for (z=0; z<rr->length; z++) printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
+printf("\n");
+#endif
+
+	/* r->length is now the compressed data plus mac */
+if (	(sess == NULL) ||
+		(s->enc_read_ctx == NULL) ||
+		(s->read_hash == NULL))
+    clear=1;
+
+	if (!clear)
+		{
+		mac_size=EVP_MD_size(s->read_hash);
+
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
+			{
+#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
+			al=SSL_AD_RECORD_OVERFLOW;
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
+			goto f_err;
+#else
+			goto decryption_failed_or_bad_record_mac;
+#endif			
+			}
+		/* check the MAC for rr->input (it's in mac_size bytes at the tail) */
+		if (rr->length < mac_size)
+			{
+#if 0 /* OK only for stream ciphers */
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
+			goto f_err;
+#else
+			goto decryption_failed_or_bad_record_mac;
+#endif
+			}
+		rr->length-=mac_size;
+		i=s->method->ssl3_enc->mac(s,md,0);
+		if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0)
+			{
+			goto decryption_failed_or_bad_record_mac;
+			}
+		}
+
+	/* r->length is now just compressed */
+	if (s->expand != NULL)
+		{
+		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH)
+			{
+			al=SSL_AD_RECORD_OVERFLOW;
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+		if (!ssl3_do_uncompress(s))
+			{
+			al=SSL_AD_DECOMPRESSION_FAILURE;
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
+			goto f_err;
+			}
+		}
+
+	if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH)
+		{
+		al=SSL_AD_RECORD_OVERFLOW;
+		SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
+		goto f_err;
+		}
+
+	rr->off=0;
+	/* So at this point the following is true
+	 * ssl->s3->rrec.type 	is the type of record
+	 * ssl->s3->rrec.length	== number of bytes in record
+	 * ssl->s3->rrec.off	== offset to first valid byte
+	 * ssl->s3->rrec.data	== where to take bytes from, increment
+	 *			   after use :-).
+	 */
+
+	/* we have pulled in a full packet so zero things */
+	s->packet_length=0;
+    dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */
+    return(1);
+
+decryption_failed_or_bad_record_mac:
+	/* Separate 'decryption_failed' alert was introduced with TLS 1.0,
+	 * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
+	 * failure is directly visible from the ciphertext anyway,
+	 * we should not reveal which kind of error occured -- this
+	 * might become visible to an attacker (e.g. via logfile) */
+	al=SSL_AD_BAD_RECORD_MAC;
+	SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(0);
+}
+
+
+/* Call this to get a new input record.
+ * It will return <= 0 if more data is needed, normally due to an error
+ * or non-blocking IO.
+ * When it finishes, one packet has been decoded and can be found in
+ * ssl->s3->rrec.type    - is the type of record
+ * ssl->s3->rrec.data, 	 - data
+ * ssl->s3->rrec.length, - number of bytes
+ */
+/* used only by dtls1_read_bytes */
+int dtls1_get_record(SSL *s)
+	{
+	int ssl_major,ssl_minor,al;
+	int i,n;
+	SSL3_RECORD *rr;
+	SSL_SESSION *sess;
+	unsigned char *p;
+	short version;
+	DTLS1_BITMAP *bitmap;
+	unsigned long long read_sequence;
+    unsigned int is_next_epoch;
+
+	rr= &(s->s3->rrec);
+	sess=s->session;
+
+    /* The epoch may have changed.  If so, process all the
+     * pending records.  This is a non-blocking operation. */
+    if ( ! dtls1_process_buffered_records(s))
+        return 0;
+
+	/* if we're renegotiating, then there may be buffered records */
+	if (dtls1_get_processed_record(s))
+		return 1;
+
+	/* get something from the wire */
+again:
+	/* check if we have the header */
+	if (	(s->rstate != SSL_ST_READ_BODY) ||
+		(s->packet_length < DTLS1_RT_HEADER_LENGTH)) 
+		{
+		n=ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
+		/* read timeout is handled by dtls1_read_bytes */
+		if (n <= 0) return(n); /* error or non-blocking */
+
+		OPENSSL_assert(s->packet_length == DTLS1_RT_HEADER_LENGTH);
+
+		s->rstate=SSL_ST_READ_BODY;
+
+		p=s->packet;
+
+		/* Pull apart the header into the DTLS1_RECORD */
+		rr->type= *(p++);
+		ssl_major= *(p++);
+		ssl_minor= *(p++);
+		version=(ssl_major<<8)|ssl_minor;
+
+        /* sequence number is 64 bits, with top 2 bytes = epoch */ 
+		n2s(p,rr->epoch);
+
+		read_sequence = 0;
+		n2l6(p, read_sequence);
+		long_long_to_bytes(read_sequence, s->s3->read_sequence);
+		n2s(p,rr->length);
+
+		/* Lets check version */
+		if (s->first_packet)
+			{
+			s->first_packet=0;
+			}
+		else
+			{
+			if (version != s->version)
+				{
+				SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
+				/* Send back error using their
+				 * version number :-) */
+				s->version=version;
+				al=SSL_AD_PROTOCOL_VERSION;
+				goto f_err;
+				}
+			}
+
+		if ((version & 0xff00) != (DTLS1_VERSION & 0xff00))
+			{
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
+			goto err;
+			}
+
+		if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
+			{
+			al=SSL_AD_RECORD_OVERFLOW;
+			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
+			goto f_err;
+			}
+
+		/* now s->rstate == SSL_ST_READ_BODY */
+		}
+
+	/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
+
+	if (rr->length > s->packet_length-DTLS1_RT_HEADER_LENGTH)
+		{
+		/* now s->packet_length == DTLS1_RT_HEADER_LENGTH */
+		i=rr->length;
+		n=ssl3_read_n(s,i,i,1);
+		if (n <= 0) return(n); /* error or non-blocking io */
+
+		/* this packet contained a partial record, dump it */
+		if ( n != i)
+			{
+			s->packet_length = 0;
+			goto again;
+			}
+
+		/* now n == rr->length,
+		 * and s->packet_length == DTLS1_RT_HEADER_LENGTH + rr->length */
+		}
+	s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
+
+	/* match epochs.  NULL means the packet is dropped on the floor */
+	bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
+	if ( bitmap == NULL)
+        {
+        s->packet_length = 0;  /* dump this record */
+        goto again;   /* get another record */
+		}
+
+	/* check whether this is a repeat, or aged record */
+	if ( ! dtls1_record_replay_check(s, bitmap, &(rr->seq_num)))
+		{
+		s->packet_length=0; /* dump this record */
+		goto again;     /* get another record */
+		}
+
+	/* just read a 0 length packet */
+	if (rr->length == 0) goto again;
+
+    /* If this record is from the next epoch (either HM or ALERT), buffer it
+     * since it cannot be processed at this time.
+     * Records from the next epoch are marked as received even though they are 
+     * not processed, so as to prevent any potential resource DoS attack */
+    if (is_next_epoch)
+        {
+        dtls1_record_bitmap_update(s, bitmap);
+        dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+        s->packet_length = 0;
+        goto again;
+        }
+
+    if ( ! dtls1_process_record(s))
+        return(0);
+
+	dtls1_clear_timeouts(s);  /* done waiting */
+	return(1);
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(0);
+	}
+
+/* Return up to 'len' payload bytes received in 'type' records.
+ * 'type' is one of the following:
+ *
+ *   -  SSL3_RT_HANDSHAKE (when ssl3_get_message calls us)
+ *   -  SSL3_RT_APPLICATION_DATA (when ssl3_read calls us)
+ *   -  0 (during a shutdown, no data has to be returned)
+ *
+ * If we don't have stored data to work from, read a SSL/TLS record first
+ * (possibly multiple records if we still don't have anything to return).
+ *
+ * This function must handle any surprises the peer may have for us, such as
+ * Alert records (e.g. close_notify), ChangeCipherSpec records (not really
+ * a surprise, but handled as if it were), or renegotiation requests.
+ * Also if record payloads contain fragments too small to process, we store
+ * them until there is enough for the respective protocol (the record protocol
+ * may use arbitrary fragmentation and even interleaving):
+ *     Change cipher spec protocol
+ *             just 1 byte needed, no need for keeping anything stored
+ *     Alert protocol
+ *             2 bytes needed (AlertLevel, AlertDescription)
+ *     Handshake protocol
+ *             4 bytes needed (HandshakeType, uint24 length) -- we just have
+ *             to detect unexpected Client Hello and Hello Request messages
+ *             here, anything else is handled by higher layers
+ *     Application data protocol
+ *             none of our business
+ */
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
+	{
+	int al,i,j,ret;
+	unsigned int n;
+	SSL3_RECORD *rr;
+	void (*cb)(const SSL *ssl,int type2,int val)=NULL;
+
+	if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
+		if (!ssl3_setup_buffers(s))
+			return(-1);
+
+    /* XXX: check what the second '&& type' is about */
+	if ((type && (type != SSL3_RT_APPLICATION_DATA) && 
+		(type != SSL3_RT_HANDSHAKE) && type) ||
+	    (peek && (type != SSL3_RT_APPLICATION_DATA)))
+		{
+		SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
+		return -1;
+		}
+
+	/* check whether there's a handshake message (client hello?) waiting */
+	if ( (ret = have_handshake_fragment(s, type, buf, len, peek)))
+		return ret;
+
+	/* Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
+
+	if (!s->in_handshake && SSL_in_init(s))
+		{
+		/* type == SSL3_RT_APPLICATION_DATA */
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+		}
+
+start:
+	s->rwstate=SSL_NOTHING;
+
+	/* s->s3->rrec.type	    - is the type of record
+	 * s->s3->rrec.data,    - data
+	 * s->s3->rrec.off,     - offset into 'data' for next read
+	 * s->s3->rrec.length,  - number of bytes. */
+	rr = &(s->s3->rrec);
+
+	/* get new packet if necessary */
+	if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
+		{
+		ret=dtls1_get_record(s);
+		if (ret <= 0) 
+			{
+			ret = dtls1_read_failed(s, ret);
+			/* anything other than a timeout is an error */
+			if (ret <= 0)  
+				return(ret);
+			else
+				goto start;
+			}
+		}
+
+	/* we now have a packet which can be read and processed */
+
+	if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
+	                               * reset by ssl3_get_finished */
+		&& (rr->type != SSL3_RT_HANDSHAKE))
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
+		goto err;
+		}
+
+	/* If the other end has shut down, throw anything we read away
+	 * (even in 'peek' mode) */
+	if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
+		{
+		rr->length=0;
+		s->rwstate=SSL_NOTHING;
+		return(0);
+		}
+
+
+	if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */
+		{
+		/* make sure that we are not getting application data when we
+		 * are doing a handshake for the first time */
+		if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&
+			(s->enc_read_ctx == NULL))
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);
+			goto f_err;
+			}
+
+		if (len <= 0) return(len);
+
+		if ((unsigned int)len > rr->length)
+			n = rr->length;
+		else
+			n = (unsigned int)len;
+
+		memcpy(buf,&(rr->data[rr->off]),n);
+		if (!peek)
+			{
+			rr->length-=n;
+			rr->off+=n;
+			if (rr->length == 0)
+				{
+				s->rstate=SSL_ST_READ_HEADER;
+				rr->off=0;
+				}
+			}
+		return(n);
+		}
+
+
+	/* If we get here, then type != rr->type; if we have a handshake
+	 * message, then it was unexpected (Hello Request or Client Hello). */
+
+	/* In case of record types for which we have 'fragment' storage,
+	 * fill that so that we can process the data at a fixed place.
+	 */
+		{
+		unsigned int i, dest_maxlen = 0;
+		unsigned char *dest = NULL;
+		unsigned int *dest_len = NULL;
+
+		if (rr->type == SSL3_RT_HANDSHAKE)
+			{
+			dest_maxlen = sizeof s->d1->handshake_fragment;
+			dest = s->d1->handshake_fragment;
+			dest_len = &s->d1->handshake_fragment_len;
+			}
+		else if (rr->type == SSL3_RT_ALERT)
+			{
+			dest_maxlen = sizeof(s->d1->alert_fragment);
+			dest = s->d1->alert_fragment;
+			dest_len = &s->d1->alert_fragment_len;
+			}
+		else	/* else it's a CCS message */
+			OPENSSL_assert(rr->type == SSL3_RT_CHANGE_CIPHER_SPEC);
+
+
+		if (dest_maxlen > 0)
+			{
+            /* XDTLS:  In a pathalogical case, the Client Hello
+             *  may be fragmented--don't always expect dest_maxlen bytes */
+			if ( rr->length < dest_maxlen)
+				{
+				s->rstate=SSL_ST_READ_HEADER;
+				rr->length = 0;
+				goto start;
+				}
+
+			/* now move 'n' bytes: */
+			for ( i = 0; i < dest_maxlen; i++)
+				{
+				dest[i] = rr->data[rr->off++];
+				rr->length--;
+				}
+			*dest_len = dest_maxlen;
+			}
+		}
+
+	/* s->d1->handshake_fragment_len == 12  iff  rr->type == SSL3_RT_HANDSHAKE;
+	 * s->d1->alert_fragment_len == 7      iff  rr->type == SSL3_RT_ALERT.
+	 * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
+
+	/* If we are a client, check for an incoming 'Hello Request': */
+	if ((!s->server) &&
+		(s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
+		(s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
+		(s->session != NULL) && (s->session->cipher != NULL))
+		{
+		s->d1->handshake_fragment_len = 0;
+
+		if ((s->d1->handshake_fragment[1] != 0) ||
+			(s->d1->handshake_fragment[2] != 0) ||
+			(s->d1->handshake_fragment[3] != 0))
+			{
+			al=SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
+			goto err;
+			}
+
+		/* no need to check sequence number on HELLO REQUEST messages */
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, 
+				s->d1->handshake_fragment, 4, s, s->msg_callback_arg);
+
+		if (SSL_is_init_finished(s) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+			!s->s3->renegotiate)
+			{
+			ssl3_renegotiate(s);
+			if (ssl3_renegotiate_check(s))
+				{
+				i=s->handshake_func(s);
+				if (i < 0) return(i);
+				if (i == 0)
+					{
+					SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+					return(-1);
+					}
+
+				if (!(s->mode & SSL_MODE_AUTO_RETRY))
+					{
+					if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+						{
+						BIO *bio;
+						/* In the case where we try to read application data,
+						 * but we trigger an SSL handshake, we return -1 with
+						 * the retry option set.  Otherwise renegotiation may
+						 * cause nasty problems in the blocking world */
+						s->rwstate=SSL_READING;
+						bio=SSL_get_rbio(s);
+						BIO_clear_retry_flags(bio);
+						BIO_set_retry_read(bio);
+						return(-1);
+						}
+					}
+				}
+			}
+		/* we either finished a handshake or ignored the request,
+		 * now try again to obtain the (application) data we were asked for */
+		goto start;
+		}
+
+	if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH)
+		{
+		int alert_level = s->d1->alert_fragment[0];
+		int alert_descr = s->d1->alert_fragment[1];
+
+		s->d1->alert_fragment_len = 0;
+
+		if (s->msg_callback)
+			s->msg_callback(0, s->version, SSL3_RT_ALERT, 
+				s->d1->alert_fragment, 2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j = (alert_level << 8) | alert_descr;
+			cb(s, SSL_CB_READ_ALERT, j);
+			}
+
+		if (alert_level == 1) /* warning */
+			{
+			s->s3->warn_alert = alert_descr;
+			if (alert_descr == SSL_AD_CLOSE_NOTIFY)
+				{
+				s->shutdown |= SSL_RECEIVED_SHUTDOWN;
+				return(0);
+				}
+#if 0
+            /* XXX: this is a possible improvement in the future */
+			/* now check if it's a missing record */
+			if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+				{
+				unsigned short seq;
+				unsigned int frag_off;
+				unsigned char *p = &(s->d1->alert_fragment[2]);
+
+				n2s(p, seq);
+				n2l3(p, frag_off);
+
+				dtls1_retransmit_message(s, seq, frag_off, &found);
+				if ( ! found  && SSL_in_init(s))
+					{
+					/* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
+					/* requested a message not yet sent, 
+					   send an alert ourselves */
+					ssl3_send_alert(s,SSL3_AL_WARNING,
+						DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+					}
+				}
+#endif
+			}
+		else if (alert_level == 2) /* fatal */
+			{
+			char tmp[16];
+
+			s->rwstate=SSL_NOTHING;
+			s->s3->fatal_alert = alert_descr;
+			SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
+			BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
+			ERR_add_error_data(2,"SSL alert number ",tmp);
+			s->shutdown|=SSL_RECEIVED_SHUTDOWN;
+			SSL_CTX_remove_session(s->ctx,s->session);
+			return(0);
+			}
+		else
+			{
+			al=SSL_AD_ILLEGAL_PARAMETER;
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
+			goto f_err;
+			}
+
+		goto start;
+		}
+
+	if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
+		{
+		s->rwstate=SSL_NOTHING;
+		rr->length=0;
+		return(0);
+		}
+
+	if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+        {
+        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 (	(rr->length != DTLS1_CCS_HEADER_LENGTH) || 
+				(rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
+				{
+				i=SSL_AD_ILLEGAL_PARAMETER;
+				SSLerr(SSL_F_SSL3_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;
+			}
+		}
+
+	/* Unexpected handshake message (Client Hello, or protocol violation) */
+	if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && 
+		!s->in_handshake)
+		{
+		struct hm_header_st msg_hdr;
+		
+		/* this may just be a stale retransmit */
+		dtls1_get_message_header(rr->data, &msg_hdr);
+		if( rr->epoch != s->d1->r_epoch)
+			{
+			rr->length = 0;
+			goto start;
+			}
+
+		if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+			{
+#if 0 /* worked only because C operator preferences are not as expected (and
+       * because this is not really needed for clients except for detecting
+       * protocol violations): */
+			s->state=SSL_ST_BEFORE|(s->server)
+				?SSL_ST_ACCEPT
+				:SSL_ST_CONNECT;
+#else
+			s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
+#endif
+			s->new_session=1;
+			}
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+			return(-1);
+			}
+
+		if (!(s->mode & SSL_MODE_AUTO_RETRY))
+			{
+			if (s->s3->rbuf.left == 0) /* no read-ahead left? */
+				{
+				BIO *bio;
+				/* In the case where we try to read application data,
+				 * but we trigger an SSL handshake, we return -1 with
+				 * the retry option set.  Otherwise renegotiation may
+				 * cause nasty problems in the blocking world */
+				s->rwstate=SSL_READING;
+				bio=SSL_get_rbio(s);
+				BIO_clear_retry_flags(bio);
+				BIO_set_retry_read(bio);
+				return(-1);
+				}
+			}
+		goto start;
+		}
+
+	switch (rr->type)
+		{
+	default:
+#ifndef OPENSSL_NO_TLS
+		/* TLS just ignores unknown message types */
+		if (s->version == TLS1_VERSION)
+			{
+			rr->length = 0;
+			goto start;
+			}
+#endif
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+		goto f_err;
+	case SSL3_RT_CHANGE_CIPHER_SPEC:
+	case SSL3_RT_ALERT:
+	case SSL3_RT_HANDSHAKE:
+		/* we already handled all of these, with the possible exception
+		 * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
+		 * should not happen when type != rr->type */
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);
+		goto f_err;
+	case SSL3_RT_APPLICATION_DATA:
+		/* At this point, we were expecting handshake data,
+		 * but have application data.  If the library was
+		 * running inside ssl3_read() (i.e. in_read_app_data
+		 * is set) and it makes sense to read application data
+		 * at this point (session renegotiation not yet started),
+		 * we will indulge it.
+		 */
+		if (s->s3->in_read_app_data &&
+			(s->s3->total_renegotiations != 0) &&
+			((
+				(s->state & SSL_ST_CONNECT) &&
+				(s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
+				(s->state <= SSL3_ST_CR_SRVR_HELLO_A)
+				) || (
+					(s->state & SSL_ST_ACCEPT) &&
+					(s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
+					(s->state >= SSL3_ST_SR_CLNT_HELLO_A)
+					)
+				))
+			{
+			s->s3->in_read_app_data=2;
+			return(-1);
+			}
+		else
+			{
+			al=SSL_AD_UNEXPECTED_MESSAGE;
+			SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
+			goto f_err;
+			}
+		}
+	/* not reached */
+
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	return(-1);
+	}
+
+int
+dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
+	{
+	unsigned int n,tot;
+	int i;
+
+	if (SSL_in_init(s) && !s->in_handshake)
+		{
+		i=s->handshake_func(s);
+		if (i < 0) return(i);
+		if (i == 0)
+			{
+			SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
+			return -1;
+			}
+		}
+
+	tot = s->s3->wnum;
+	n = len - tot;
+
+	while( n)
+		{
+		/* dtls1_write_bytes sends one record at a time, sized according to 
+		 * the currently known MTU */
+		i = dtls1_write_bytes(s, type, buf_, len);
+		if (i <= 0) return i;
+		
+		if ((i == (int)n) ||
+			(type == SSL3_RT_APPLICATION_DATA &&
+				(s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
+			{
+			/* next chunk of data should get another prepended empty fragment
+			 * in ciphersuites with known-IV weakness: */
+			s->s3->empty_fragment_done = 0;
+			return tot+i;
+			}
+
+		tot += i;
+		n-=i;
+		}
+
+	return tot;
+	}
+
+
+	/* this only happens when a client hello is received and a handshake 
+	 * is started. */
+static int
+have_handshake_fragment(SSL *s, int type, unsigned char *buf, 
+	int len, int peek)
+	{
+	
+	if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0))
+		/* (partially) satisfy request from storage */
+		{
+		unsigned char *src = s->d1->handshake_fragment;
+		unsigned char *dst = buf;
+		unsigned int k,n;
+		
+		/* peek == 0 */
+		n = 0;
+		while ((len > 0) && (s->d1->handshake_fragment_len > 0))
+			{
+			*dst++ = *src++;
+			len--; s->d1->handshake_fragment_len--;
+			n++;
+			}
+		/* move any remaining fragment bytes: */
+		for (k = 0; k < s->d1->handshake_fragment_len; k++)
+			s->d1->handshake_fragment[k] = *src++;
+		return n;
+		}
+	
+	return 0;
+	}
+
+
+
+
+/* Call this to write data in records of type 'type'
+ * It will return <= 0 if not all data has been sent or non-blocking IO.
+ */
+int dtls1_write_bytes(SSL *s, int type, const void *buf_, int len)
+	{
+	const unsigned char *buf=buf_;
+	unsigned int tot,n,nw;
+	int i;
+	unsigned int mtu;
+
+	s->rwstate=SSL_NOTHING;
+	tot=s->s3->wnum;
+
+	n=(len-tot);
+
+	/* handshake layer figures out MTU for itself, but data records
+	 * are also sent through this interface, so need to figure out MTU */
+#if 0
+	mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_MTU, 0, NULL);
+	mtu += DTLS1_HM_HEADER_LENGTH;  /* HM already inserted */
+#endif
+	mtu = s->d1->mtu;
+
+	if (mtu > SSL3_RT_MAX_PLAIN_LENGTH)
+		mtu = SSL3_RT_MAX_PLAIN_LENGTH;
+
+	if (n > mtu)
+		nw=mtu;
+	else
+		nw=n;
+	
+	i=do_dtls1_write(s, type, &(buf[tot]), nw, 0);
+	if (i <= 0)
+		{
+		s->s3->wnum=tot;
+		return i;
+		}
+
+	if ( s->s3->wnum + i == len)
+		s->s3->wnum = 0;
+	else 
+		s->s3->wnum += i;
+
+	return tot + i;
+	}
+
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+	unsigned int len, int create_empty_fragment)
+	{
+	unsigned char *p,*pseq;
+	int i,mac_size,clear=0;
+	int prefix_len = 0;
+	SSL3_RECORD *wr;
+	SSL3_BUFFER *wb;
+	SSL_SESSION *sess;
+	int bs;
+
+	/* first check if there is a SSL3_BUFFER still being written
+	 * out.  This will happen with non blocking IO */
+	if (s->s3->wbuf.left != 0)
+		{
+		OPENSSL_assert(0); /* XDTLS:  want to see if we ever get here */
+		return(ssl3_write_pending(s,type,buf,len));
+		}
+
+	/* If we have an alert to send, lets send it */
+	if (s->s3->alert_dispatch)
+		{
+		i=s->method->ssl_dispatch_alert(s);
+		if (i <= 0)
+			return(i);
+		/* if it went, fall through and send more stuff */
+		}
+
+	if (len == 0 && !create_empty_fragment)
+		return 0;
+
+	wr= &(s->s3->wrec);
+	wb= &(s->s3->wbuf);
+	sess=s->session;
+
+	if (	(sess == NULL) ||
+		(s->enc_write_ctx == NULL) ||
+		(s->write_hash == NULL))
+		clear=1;
+
+	if (clear)
+		mac_size=0;
+	else
+		mac_size=EVP_MD_size(s->write_hash);
+
+	/* DTLS implements explicit IV, so no need for empty fragments */
+#if 0
+	/* 'create_empty_fragment' is true only when this function calls itself */
+	if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
+		&& SSL_version(s) != DTLS1_VERSION)
+		{
+		/* countermeasure against known-IV weakness in CBC ciphersuites
+		 * (see http://www.openssl.org/~bodo/tls-cbc.txt) 
+		 */
+
+		if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
+			{
+			/* recursive function call with 'create_empty_fragment' set;
+			 * this prepares and buffers the data for an empty fragment
+			 * (these 'prefix_len' bytes are sent out later
+			 * together with the actual payload) */
+			prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1);
+			if (prefix_len <= 0)
+				goto err;
+
+			if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE)
+				{
+				/* insufficient space */
+				SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+			}
+		
+		s->s3->empty_fragment_done = 1;
+		}
+#endif
+
+	p = wb->buf + prefix_len;
+
+	/* write the header */
+
+	*(p++)=type&0xff;
+	wr->type=type;
+
+	*(p++)=(s->version>>8);
+	*(p++)=s->version&0xff;
+
+	/* field where we are to write out packet epoch, seq num and len */
+	pseq=p; 
+	p+=10;
+
+	/* lets setup the record stuff. */
+
+	/* Make space for the explicit IV in case of CBC.
+	 * (this is a bit of a boundary violation, but what the heck).
+	 */
+	if ( s->enc_write_ctx && 
+		(EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE))
+		bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+	else
+		bs = 0;
+
+	wr->data=p + bs;  /* make room for IV in case of CBC */
+	wr->length=(int)len;
+	wr->input=(unsigned char *)buf;
+
+	/* we now 'read' from wr->input, wr->length bytes into
+	 * wr->data */
+
+	/* first we compress */
+	if (s->compress != NULL)
+		{
+		if (!ssl3_do_compress(s))
+			{
+			SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
+			goto err;
+			}
+		}
+	else
+		{
+		memcpy(wr->data,wr->input,wr->length);
+		wr->input=wr->data;
+		}
+
+	/* we should still have the output to wr->data and the input
+	 * from wr->input.  Length should be wr->length.
+	 * wr->data still points in the wb->buf */
+
+	if (mac_size != 0)
+		{
+		s->method->ssl3_enc->mac(s,&(p[wr->length + bs]),1);
+		wr->length+=mac_size;
+		}
+
+	/* this is true regardless of mac size */
+	wr->input=p;
+	wr->data=p;
+
+
+	/* ssl3_enc can only have an error on read */
+	wr->length += bs;  /* bs != 0 in case of CBC.  The enc fn provides
+						* the randomness */ 
+	s->method->ssl3_enc->enc(s,1);
+
+	/* record length after mac and block padding */
+/*	if (type == SSL3_RT_APPLICATION_DATA ||
+	(type == SSL3_RT_ALERT && ! SSL_in_init(s))) */
+	
+	/* there's only one epoch between handshake and app data */
+	
+	s2n(s->d1->w_epoch, pseq);
+
+	/* XDTLS: ?? */
+/*	else
+	s2n(s->d1->handshake_epoch, pseq); */
+
+	l2n6(bytes_to_long_long(s->s3->write_sequence), pseq);
+	s2n(wr->length,pseq);
+
+	/* we should now have
+	 * wr->data pointing to the encrypted data, which is
+	 * wr->length long */
+	wr->type=type; /* not needed but helps for debugging */
+	wr->length+=DTLS1_RT_HEADER_LENGTH;
+
+#if 0  /* this is now done at the message layer */
+	/* buffer the record, making it easy to handle retransmits */
+	if ( type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC)
+		dtls1_buffer_record(s, wr->data, wr->length, 
+			*((unsigned long long *)&(s->s3->write_sequence[0])));
+#endif
+
+	ssl3_record_sequence_update(&(s->s3->write_sequence[0]));
+
+	if (create_empty_fragment)
+		{
+		/* we are in a recursive call;
+		 * just return the length, don't write out anything here
+		 */
+		return wr->length;
+		}
+
+	/* now let's set up wb */
+	wb->left = prefix_len + wr->length;
+	wb->offset = 0;
+
+	/* memorize arguments so that ssl3_write_pending can detect bad write retries later */
+	s->s3->wpend_tot=len;
+	s->s3->wpend_buf=buf;
+	s->s3->wpend_type=type;
+	s->s3->wpend_ret=len;
+
+	/* we now just need to write the buffer */
+	return ssl3_write_pending(s,type,buf,len);
+err:
+	return -1;
+	}
+
+
+
+static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap,
+	unsigned long long *seq_num)
+	{
+	unsigned long long mask = 0x0000000000000001LL;
+	unsigned long long rcd_num;
+
+	rcd_num = bytes_to_long_long(s->s3->read_sequence);
+	
+	if (rcd_num >= bitmap->max_seq_num)
+		{
+		*seq_num = rcd_num;
+		return 1;  /* this record is new */
+		}
+	
+	if (bitmap->max_seq_num - rcd_num > bitmap->length)
+		return 0;  /* stale, outside the window */
+
+	mask <<= (bitmap->max_seq_num - rcd_num - 1);
+	if (bitmap->map & mask)
+		return 0; /* record previously received */
+	
+	*seq_num = rcd_num;
+	return 1;
+	}
+
+
+static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap)
+	{
+	unsigned int shift;
+	unsigned long long mask = 0x0000000000000001L;
+	unsigned long long rcd_num;
+
+	rcd_num = bytes_to_long_long(s->s3->read_sequence);
+
+	if (rcd_num >= bitmap->max_seq_num)
+		{
+		shift = rcd_num - bitmap->max_seq_num + 1;
+		bitmap->max_seq_num = rcd_num + 1;
+		bitmap->map <<= shift;
+		bitmap->map |= 0x0000000000000001LL;
+		}
+	else
+		{
+		mask <<= (bitmap->max_seq_num - rcd_num - 1);
+		bitmap->map |= mask;
+		}
+	}
+
+
+int dtls1_dispatch_alert(SSL *s)
+	{
+	int i,j;
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	char buf[2 + 2 + 3]; /* alert level + alert desc + message seq +frag_off */
+	char *ptr = &buf[0];
+
+	s->s3->alert_dispatch=0;
+
+	memset(buf, 0x00, sizeof(buf));
+	*ptr++ = s->s3->send_alert[0];
+	*ptr++ = s->s3->send_alert[1];
+
+	if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+		{	
+		s2n(s->d1->handshake_read_seq, ptr);
+#if 0
+		if ( s->d1->r_msg_hdr.frag_off == 0)  /* waiting for a new msg */
+
+		else
+			s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */
+#endif
+
+#if 0
+		fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq);
+#endif
+		l2n3(s->d1->r_msg_hdr.frag_off, ptr);
+		}
+
+	i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0);
+	if (i <= 0)
+		{
+		s->s3->alert_dispatch=1;
+		/* fprintf( stderr, "not done with alert\n" ); */
+		}
+	else
+		{
+		if ( s->s3->send_alert[0] == SSL3_AL_FATAL ||
+			s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE)
+			(void)BIO_flush(s->wbio);
+
+		if (s->msg_callback)
+			s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 
+				2, s, s->msg_callback_arg);
+
+		if (s->info_callback != NULL)
+			cb=s->info_callback;
+		else if (s->ctx->info_callback != NULL)
+			cb=s->ctx->info_callback;
+
+		if (cb != NULL)
+			{
+			j=(s->s3->send_alert[0]<<8)|s->s3->send_alert[1];
+			cb(s,SSL_CB_WRITE_ALERT,j);
+			}
+		}
+	return(i);
+	}
+
+
+static DTLS1_BITMAP *
+dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch)
+    {
+    
+    *is_next_epoch = 0;
+
+    /* In current epoch, accept HM, CCS, DATA, & ALERT */
+    if (rr->epoch == s->d1->r_epoch)
+        return &s->d1->bitmap;
+
+    /* Only HM and ALERT messages can be from the next epoch */
+    else if (rr->epoch == s->d1->r_epoch + 1 &&
+        (rr->type == SSL3_RT_HANDSHAKE ||
+            rr->type == SSL3_RT_ALERT))
+        {
+        *is_next_epoch = 1;
+        return &s->d1->next_bitmap;
+        }
+
+    return NULL;
+    }
+
+#if 0
+static int
+dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority,
+	unsigned long *offset)
+	{
+
+	/* alerts are passed up immediately */
+	if ( rr->type == SSL3_RT_APPLICATION_DATA ||
+		rr->type == SSL3_RT_ALERT)
+		return 0;
+
+	/* Only need to buffer if a handshake is underway.
+	 * (this implies that Hello Request and Client Hello are passed up
+	 * immediately) */
+	if ( SSL_in_init(s))
+		{
+		unsigned char *data = rr->data;
+		/* need to extract the HM/CCS sequence number here */
+		if ( rr->type == SSL3_RT_HANDSHAKE ||
+			rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
+			{
+			unsigned short seq_num;
+			struct hm_header_st msg_hdr;
+			struct ccs_header_st ccs_hdr;
+
+			if ( rr->type == SSL3_RT_HANDSHAKE)
+				{
+				dtls1_get_message_header(data, &msg_hdr);
+				seq_num = msg_hdr.seq;
+				*offset = msg_hdr.frag_off;
+				}
+			else
+				{
+				dtls1_get_ccs_header(data, &ccs_hdr);
+				seq_num = ccs_hdr.seq;
+				*offset = 0;
+				}
+				
+			/* this is either a record we're waiting for, or a
+			 * retransmit of something we happened to previously 
+			 * receive (higher layers will drop the repeat silently */
+			if ( seq_num < s->d1->handshake_read_seq)
+				return 0;
+			if (rr->type == SSL3_RT_HANDSHAKE && 
+				seq_num == s->d1->handshake_read_seq &&
+				msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off)
+				return 0;
+			else if ( seq_num == s->d1->handshake_read_seq &&
+				(rr->type == SSL3_RT_CHANGE_CIPHER_SPEC ||
+					msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off))
+				return 0;
+			else
+				{
+				*priority = seq_num;
+				return 1;
+				}
+			}
+		else /* unknown record type */
+			return 0;
+		}
+
+	return 0;
+	}
+#endif
+
+void
+dtls1_reset_seq_numbers(SSL *s, int rw)
+	{
+	unsigned char *seq;
+	unsigned int seq_bytes = sizeof(s->s3->read_sequence);
+
+	if ( rw & SSL3_CC_READ)
+		{
+		seq = s->s3->read_sequence;
+		s->d1->r_epoch++;
+		memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP));
+		memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP));
+		}
+	else
+		{
+		seq = s->s3->write_sequence;
+		s->d1->w_epoch++;
+		}
+
+	memset(seq, 0x00, seq_bytes);
+	}
+
+
+static unsigned long long
+bytes_to_long_long(unsigned char *bytes)
+	{
+	unsigned long long num;
+
+	num = (((unsigned long long)bytes[0]) << 56) |
+		(((unsigned long long)bytes[1]) << 48) |
+		(((unsigned long long)bytes[2]) << 40) |
+		(((unsigned long long)bytes[3]) << 32) |
+		(((unsigned long long)bytes[4]) << 24) |
+		(((unsigned long long)bytes[5]) << 16) |
+		(((unsigned long long)bytes[6]) <<  8) |
+		(((unsigned long long)bytes[7])      );
+
+	return num;
+	}
+
+static void
+long_long_to_bytes(unsigned long long num, unsigned char *bytes)
+	{
+	bytes[0] = (unsigned char)((num >> 56)&0xff);
+	bytes[1] = (unsigned char)((num >> 48)&0xff);
+	bytes[2] = (unsigned char)((num >> 40)&0xff);
+	bytes[3] = (unsigned char)((num >> 32)&0xff);
+	bytes[4] = (unsigned char)((num >> 24)&0xff);
+	bytes[5] = (unsigned char)((num >> 16)&0xff);
+	bytes[6] = (unsigned char)((num >>  8)&0xff);
+	bytes[7] = (unsigned char)((num      )&0xff);
+	}
+
+static void
+dtls1_clear_timeouts(SSL *s)
+	{
+	memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st));
+	}
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
new file mode 100644
index 0000000..81c1790
--- /dev/null
+++ b/ssl/d1_srvr.c
@@ -0,0 +1,1140 @@
+/* ssl/d1_srvr.c */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/md5.h>
+
+static SSL_METHOD *dtls1_get_server_method(int ver);
+static int dtls1_send_hello_verify_request(SSL *s);
+
+static SSL_METHOD *dtls1_get_server_method(int ver)
+	{
+	if (ver == DTLS1_VERSION)
+		return(DTLSv1_server_method());
+	else
+		return(NULL);
+	}
+
+SSL_METHOD *DTLSv1_server_method(void)
+	{
+	static int init=1;
+	static SSL_METHOD DTLSv1_server_data;
+
+	if (init)
+		{
+		CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
+
+		if (init)
+			{
+			memcpy((char *)&DTLSv1_server_data,(char *)dtlsv1_base_method(),
+				sizeof(SSL_METHOD));
+			DTLSv1_server_data.ssl_accept=dtls1_accept;
+			DTLSv1_server_data.get_ssl_method=dtls1_get_server_method;
+			init=0;
+			}
+			
+		CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
+		}
+	return(&DTLSv1_server_data);
+	}
+
+int dtls1_accept(SSL *s)
+	{
+	BUF_MEM *buf;
+	unsigned long l,Time=time(NULL);
+	void (*cb)(const SSL *ssl,int type,int val)=NULL;
+	long num1;
+	int ret= -1;
+	int new_state,state,skip=0;
+
+	RAND_add(&Time,sizeof(Time),0);
+	ERR_clear_error();
+	clear_sys_error();
+
+	if (s->info_callback != NULL)
+		cb=s->info_callback;
+	else if (s->ctx->info_callback != NULL)
+		cb=s->ctx->info_callback;
+
+	/* init things to blank */
+	s->in_handshake++;
+	if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+	if (s->cert == NULL)
+		{
+		SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+		return(-1);
+		}
+
+	for (;;)
+		{
+		state=s->state;
+
+		switch (s->state)
+			{
+		case SSL_ST_RENEGOTIATE:
+			s->new_session=1;
+			/* s->state=SSL_ST_ACCEPT; */
+
+		case SSL_ST_BEFORE:
+		case SSL_ST_ACCEPT:
+		case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+		case SSL_ST_OK|SSL_ST_ACCEPT:
+
+			s->server=1;
+			if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+			if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
+				{
+				SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
+				return -1;
+				}
+			s->type=SSL_ST_ACCEPT;
+
+			if (s->init_buf == NULL)
+				{
+				if ((buf=BUF_MEM_new()) == NULL)
+					{
+					ret= -1;
+					goto end;
+					}
+				if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+					{
+					ret= -1;
+					goto end;
+					}
+				s->init_buf=buf;
+				}
+
+			if (!ssl3_setup_buffers(s))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			s->init_num=0;
+
+			if (s->state != SSL_ST_RENEGOTIATE)
+				{
+				/* Ok, we now need to push on a buffering BIO so that
+				 * the output is sent in a way that TCP likes :-)
+				 */
+				if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
+
+				ssl3_init_finished_mac(s);
+				s->state=SSL3_ST_SR_CLNT_HELLO_A;
+				s->ctx->stats.sess_accept++;
+				}
+			else
+				{
+				/* s->state == SSL_ST_RENEGOTIATE,
+				 * we will just send a HelloRequest */
+				s->ctx->stats.sess_accept_renegotiate++;
+				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:
+		case SSL3_ST_SW_HELLO_REQ_B:
+
+			s->shutdown=0;
+			ret=dtls1_send_hello_request(s);
+			if (ret <= 0) goto end;
+			s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
+			s->state=SSL3_ST_SW_FLUSH;
+			s->init_num=0;
+
+			ssl3_init_finished_mac(s);
+			break;
+
+		case SSL3_ST_SW_HELLO_REQ_C:
+			s->state=SSL_ST_OK;
+			break;
+
+		case SSL3_ST_SR_CLNT_HELLO_A:
+		case SSL3_ST_SR_CLNT_HELLO_B:
+		case SSL3_ST_SR_CLNT_HELLO_C:
+
+			s->shutdown=0;
+			ret=ssl3_get_client_hello(s);
+			if (ret <= 0) goto end;
+			s->new_session = 2;
+
+			if ( s->d1->send_cookie)
+				s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
+			else
+				s->state = SSL3_ST_SW_SRVR_HELLO_A;
+
+			s->init_num=0;
+			break;
+			
+		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
+		case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
+
+			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;
+			break;
+			
+		case SSL3_ST_SW_SRVR_HELLO_A:
+		case SSL3_ST_SW_SRVR_HELLO_B:
+			ret=dtls1_send_server_hello(s);
+			if (ret <= 0) goto end;
+
+			if (s->hit)
+				s->state=SSL3_ST_SW_CHANGE_A;
+			else
+				s->state=SSL3_ST_SW_CERT_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CERT_A:
+		case SSL3_ST_SW_CERT_B:
+			/* Check if it is anon DH */
+			if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+				{
+				ret=dtls1_send_server_certificate(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip=1;
+			s->state=SSL3_ST_SW_KEY_EXCH_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_KEY_EXCH_A:
+		case SSL3_ST_SW_KEY_EXCH_B:
+			l=s->s3->tmp.new_cipher->algorithms;
+
+			/* clear this, it may get reset by
+			 * send_server_key_exchange */
+			if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef OPENSSL_NO_KRB5
+				&& !(l & SSL_KRB5)
+#endif /* OPENSSL_NO_KRB5 */
+				)
+				/* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+				 * even when forbidden by protocol specs
+				 * (handshake may fail as clients are not required to
+				 * be able to handle this) */
+				s->s3->tmp.use_rsa_tmp=1;
+			else
+				s->s3->tmp.use_rsa_tmp=0;
+
+			/* only send if a DH key exchange, fortezza or
+			 * RSA but we have a sign only certificate */
+			if (s->s3->tmp.use_rsa_tmp
+			    || (l & (SSL_DH|SSL_kFZA))
+			    || ((l & SSL_kRSA)
+				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+				    || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+					&& EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+					)
+				    )
+				)
+			    )
+				{
+				ret=dtls1_send_server_key_exchange(s);
+				if (ret <= 0) goto end;
+				}
+			else
+				skip=1;
+
+			s->state=SSL3_ST_SW_CERT_REQ_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CERT_REQ_A:
+		case SSL3_ST_SW_CERT_REQ_B:
+			if (/* don't request cert unless asked for it: */
+				!(s->verify_mode & SSL_VERIFY_PEER) ||
+				/* if SSL_VERIFY_CLIENT_ONCE is set,
+				 * don't request cert during re-negotiation: */
+				((s->session->peer != NULL) &&
+				 (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
+				/* never request cert in anonymous ciphersuites
+				 * (see section "Certificate request" in SSL 3 drafts
+				 * and in RFC 2246): */
+				((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&
+				 /* ... except when the application insists on verification
+				  * (against the specs, but s3_clnt.c accepts this for SSL 3) */
+				 !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
+                                 /* never request cert in Kerberos ciphersuites */
+                                (s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
+				{
+				/* no cert request */
+				skip=1;
+				s->s3->tmp.cert_request=0;
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+				}
+			else
+				{
+				s->s3->tmp.cert_request=1;
+				ret=dtls1_send_certificate_request(s);
+				if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+				s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+				s->state=SSL3_ST_SW_FLUSH;
+				s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
+				s->init_num=0;
+				}
+			break;
+
+		case SSL3_ST_SW_SRVR_DONE_A:
+		case SSL3_ST_SW_SRVR_DONE_B:
+			ret=dtls1_send_server_done(s);
+			if (ret <= 0) goto end;
+			s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+			s->state=SSL3_ST_SW_FLUSH;
+			s->init_num=0;
+			break;
+		
+		case SSL3_ST_SW_FLUSH:
+			/* number of bytes to be flushed */
+			num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
+			if (num1 > 0)
+				{
+				s->rwstate=SSL_WRITING;
+				num1=BIO_flush(s->wbio);
+				if (num1 <= 0) { ret= -1; goto end; }
+				s->rwstate=SSL_NOTHING;
+				}
+
+			s->state=s->s3->tmp.next_state;
+			break;
+
+		case SSL3_ST_SR_CERT_A:
+		case SSL3_ST_SR_CERT_B:
+			/* Check for second client hello (MS SGC) */
+			ret = ssl3_check_client_hello(s);
+			if (ret <= 0)
+				goto end;
+			if (ret == 2)
+				s->state = SSL3_ST_SR_CLNT_HELLO_C;
+			else {
+				/* could be sent for a DH cert, even if we
+				 * have not asked for it :-) */
+				ret=ssl3_get_client_certificate(s);
+				if (ret <= 0) goto end;
+				s->init_num=0;
+				s->state=SSL3_ST_SR_KEY_EXCH_A;
+			}
+			break;
+
+		case SSL3_ST_SR_KEY_EXCH_A:
+		case SSL3_ST_SR_KEY_EXCH_B:
+			ret=ssl3_get_client_key_exchange(s);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_SR_CERT_VRFY_A;
+			s->init_num=0;
+
+			/* We need to get hashes here so if there is
+			 * a client cert, it can be verified */ 
+			s->method->ssl3_enc->cert_verify_mac(s,
+				&(s->s3->finish_dgst1),
+				&(s->s3->tmp.cert_verify_md[0]));
+			s->method->ssl3_enc->cert_verify_mac(s,
+				&(s->s3->finish_dgst2),
+				&(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+
+			break;
+
+		case SSL3_ST_SR_CERT_VRFY_A:
+		case SSL3_ST_SR_CERT_VRFY_B:
+
+			/* we should decide if we expected this one */
+			ret=ssl3_get_cert_verify(s);
+			if (ret <= 0) goto end;
+
+			s->state=SSL3_ST_SR_FINISHED_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SR_FINISHED_A:
+		case SSL3_ST_SR_FINISHED_B:
+			ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+				SSL3_ST_SR_FINISHED_B);
+			if (ret <= 0) goto end;
+			if (s->hit)
+				s->state=SSL_ST_OK;
+			else
+				s->state=SSL3_ST_SW_CHANGE_A;
+			s->init_num=0;
+			break;
+
+		case SSL3_ST_SW_CHANGE_A:
+		case SSL3_ST_SW_CHANGE_B:
+
+			s->session->cipher=s->s3->tmp.new_cipher;
+			if (!s->method->ssl3_enc->setup_key_block(s))
+				{ ret= -1; goto end; }
+
+			ret=dtls1_send_change_cipher_spec(s,
+				SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
+
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_SW_FINISHED_A;
+			s->init_num=0;
+
+			if (!s->method->ssl3_enc->change_cipher_state(s,
+				SSL3_CHANGE_CIPHER_SERVER_WRITE))
+				{
+				ret= -1;
+				goto end;
+				}
+
+			dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+			break;
+
+		case SSL3_ST_SW_FINISHED_A:
+		case SSL3_ST_SW_FINISHED_B:
+			ret=dtls1_send_finished(s,
+				SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
+				s->method->ssl3_enc->server_finished_label,
+				s->method->ssl3_enc->server_finished_label_len);
+			if (ret <= 0) goto end;
+			s->state=SSL3_ST_SW_FLUSH;
+			if (s->hit)
+				s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+			else
+				s->s3->tmp.next_state=SSL_ST_OK;
+			s->init_num=0;
+			break;
+
+		case SSL_ST_OK:
+			/* clean a few things up */
+			ssl3_cleanup_key_block(s);
+
+#if 0
+			BUF_MEM_free(s->init_buf);
+			s->init_buf=NULL;
+#endif
+
+			/* remove buffering on output */
+			ssl_free_wbio_buffer(s);
+
+			s->init_num=0;
+
+			if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
+				{
+				/* actually not necessarily a 'new' session unless
+				 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+				
+				s->new_session=0;
+				
+				ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+				
+				s->ctx->stats.sess_accept_good++;
+				/* s->server=1; */
+				s->handshake_func=dtls1_accept;
+
+				if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+				}
+			
+			ret = 1;
+
+			/* done handshaking, next message is client hello */
+			s->d1->handshake_read_seq = 0;
+			/* next message is server hello */
+			s->d1->handshake_write_seq = 0;
+			goto end;
+			/* break; */
+
+		default:
+			SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);
+			ret= -1;
+			goto end;
+			/* break; */
+			}
+		
+		if (!s->s3->tmp.reuse_message && !skip)
+			{
+			if (s->debug)
+				{
+				if ((ret=BIO_flush(s->wbio)) <= 0)
+					goto end;
+				}
+
+
+			if ((cb != NULL) && (s->state != state))
+				{
+				new_state=s->state;
+				s->state=state;
+				cb(s,SSL_CB_ACCEPT_LOOP,1);
+				s->state=new_state;
+				}
+			}
+		skip=0;
+		}
+end:
+	/* BIO_flush(s->wbio); */
+
+	s->in_handshake--;
+	if (cb != NULL)
+		cb(s,SSL_CB_ACCEPT_EXIT,ret);
+	return(ret);
+	}
+
+int dtls1_send_hello_request(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL3_ST_SW_HELLO_REQ_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+		p = dtls1_set_message_header(s, p, SSL3_MT_HELLO_REQUEST, 0, 0, 0);
+
+		s->state=SSL3_ST_SW_HELLO_REQ_B;
+		/* number of bytes to write */
+		s->init_num=DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* no need to buffer this message, since there are no retransmit 
+		 * requests for it */
+		}
+
+	/* SSL3_ST_SW_HELLO_REQ_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int dtls1_send_hello_verify_request(SSL *s)
+	{
+	unsigned int msg_len;
+	unsigned char *msg, *buf, *p;
+
+	if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A)
+		{
+		buf = (unsigned char *)s->init_buf->data;
+
+		msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
+		*(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)
+            {
+			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 */
+
+		memcpy(p, s->d1->cookie, s->d1->cookie_len);
+		p += s->d1->cookie_len;
+		msg_len = p - msg;
+
+		dtls1_set_message_header(s, buf,
+			DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, msg_len);
+
+		s->state=DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
+		/* number of bytes to write */
+		s->init_num=p-buf;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	/* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int dtls1_send_server_hello(SSL *s)
+	{
+	unsigned char *buf;
+	unsigned char *p,*d;
+	int i,sl;
+	unsigned long l,Time;
+
+	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+		{
+		buf=(unsigned char *)s->init_buf->data;
+		p=s->s3->server_random;
+		Time=time(NULL);			/* Time */
+		l2n(Time,p);
+		RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+		/* Do the message type and length last */
+		d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
+
+		*(p++)=s->version>>8;
+		*(p++)=s->version&0xff;
+
+		/* Random stuff */
+		memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
+		p+=SSL3_RANDOM_SIZE;
+
+		/* now in theory we have 3 options to sending back the
+		 * session id.  If it is a re-use, we send back the
+		 * old session-id, if it is a new session, we send
+		 * back the new session-id or we send back a 0 length
+		 * session-id if we want it to be single use.
+		 * Currently I will not implement the '0' length session-id
+		 * 12-Jan-98 - I'll now support the '0' length stuff.
+		 */
+		if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
+			s->session->session_id_length=0;
+
+		sl=s->session->session_id_length;
+		if (sl > sizeof s->session->session_id)
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+			return -1;
+			}
+		*(p++)=sl;
+		memcpy(p,s->session->session_id,sl);
+		p+=sl;
+
+		/* put the cipher */
+		i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
+		p+=i;
+
+		/* put the compression method */
+		if (s->s3->tmp.new_compression == NULL)
+			*(p++)=0;
+		else
+			*(p++)=s->s3->tmp.new_compression->id;
+
+		/* do the header */
+		l=(p-d);
+		d=buf;
+
+		d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l);
+
+		s->state=SSL3_ST_CW_CLNT_HELLO_B;
+		/* number of bytes to write */
+		s->init_num=p-buf;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int dtls1_send_server_done(SSL *s)
+	{
+	unsigned char *p;
+
+	if (s->state == SSL3_ST_SW_SRVR_DONE_A)
+		{
+		p=(unsigned char *)s->init_buf->data;
+
+		/* do the header */
+		p = dtls1_set_message_header(s, p, SSL3_MT_SERVER_DONE, 0, 0, 0);
+
+		s->state=SSL3_ST_SW_SRVR_DONE_B;
+		/* number of bytes to write */
+		s->init_num=DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	/* SSL3_ST_CW_CLNT_HELLO_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
+
+int dtls1_send_server_key_exchange(SSL *s)
+	{
+#ifndef OPENSSL_NO_RSA
+	unsigned char *q;
+	int j,num;
+	RSA *rsa;
+	unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+	unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+	DH *dh=NULL,*dhp;
+#endif
+	EVP_PKEY *pkey;
+	unsigned char *p,*d;
+	int al,i;
+	unsigned long type;
+	int n;
+	CERT *cert;
+	BIGNUM *r[4];
+	int nr[4],kn;
+	BUF_MEM *buf;
+	EVP_MD_CTX md_ctx;
+
+	EVP_MD_CTX_init(&md_ctx);
+	if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+		{
+		type=s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK;
+		cert=s->cert;
+
+		buf=s->init_buf;
+
+		r[0]=r[1]=r[2]=r[3]=NULL;
+		n=0;
+#ifndef OPENSSL_NO_RSA
+		if (type & SSL_kRSA)
+			{
+			rsa=cert->rsa_tmp;
+			if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+				{
+				rsa=s->cert->rsa_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+				if(rsa == NULL)
+				{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+					goto f_err;
+				}
+				RSA_up_ref(rsa);
+				cert->rsa_tmp=rsa;
+				}
+			if (rsa == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
+				goto f_err;
+				}
+			r[0]=rsa->n;
+			r[1]=rsa->e;
+			s->s3->tmp.use_rsa_tmp=1;
+			}
+		else
+#endif
+#ifndef OPENSSL_NO_DH
+			if (type & SSL_kEDH)
+			{
+			dhp=cert->dh_tmp;
+			if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+				dhp=s->cert->dh_tmp_cb(s,
+				      SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+				      SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+			if (dhp == NULL)
+				{
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+				goto f_err;
+				}
+
+			if (s->s3->tmp.dh != NULL)
+				{
+				DH_free(dh);
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+				goto err;
+				}
+
+			if ((dh=DHparams_dup(dhp)) == NULL)
+				{
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+				goto err;
+				}
+
+			s->s3->tmp.dh=dh;
+			if ((dhp->pub_key == NULL ||
+			     dhp->priv_key == NULL ||
+			     (s->options & SSL_OP_SINGLE_DH_USE)))
+				{
+				if(!DH_generate_key(dh))
+				    {
+				    SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+					   ERR_R_DH_LIB);
+				    goto err;
+				    }
+				}
+			else
+				{
+				dh->pub_key=BN_dup(dhp->pub_key);
+				dh->priv_key=BN_dup(dhp->priv_key);
+				if ((dh->pub_key == NULL) ||
+					(dh->priv_key == NULL))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+					goto err;
+					}
+				}
+			r[0]=dh->p;
+			r[1]=dh->g;
+			r[2]=dh->pub_key;
+			}
+		else 
+#endif
+			{
+			al=SSL_AD_HANDSHAKE_FAILURE;
+			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+			goto f_err;
+			}
+		for (i=0; r[i] != NULL; i++)
+			{
+			nr[i]=BN_num_bytes(r[i]);
+			n+=2+nr[i];
+			}
+
+		if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+			{
+			if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
+				== NULL)
+				{
+				al=SSL_AD_DECODE_ERROR;
+				goto f_err;
+				}
+			kn=EVP_PKEY_size(pkey);
+			}
+		else
+			{
+			pkey=NULL;
+			kn=0;
+			}
+
+		if (!BUF_MEM_grow_clean(buf,n+DTLS1_HM_HEADER_LENGTH+kn))
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
+			goto err;
+			}
+		d=(unsigned char *)s->init_buf->data;
+		p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+		for (i=0; r[i] != NULL; i++)
+			{
+			s2n(nr[i],p);
+			BN_bn2bin(r[i],p);
+			p+=nr[i];
+			}
+
+		/* not anonymous */
+		if (pkey != NULL)
+			{
+			/* n is the length of the params, they start at
+			 * &(d[DTLS1_HM_HEADER_LENGTH]) and p points to the space
+			 * at the end. */
+#ifndef OPENSSL_NO_RSA
+			if (pkey->type == EVP_PKEY_RSA)
+				{
+				q=md_buf;
+				j=0;
+				for (num=2; num > 0; num--)
+					{
+					EVP_DigestInit_ex(&md_ctx,(num == 2)
+						?s->ctx->md5:s->ctx->sha1, NULL);
+					EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+					EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+					EVP_DigestUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+					EVP_DigestFinal_ex(&md_ctx,q,
+						(unsigned int *)&i);
+					q+=i;
+					j+=i;
+					}
+				if (RSA_sign(NID_md5_sha1, md_buf, j,
+					&(p[2]), &u, pkey->pkey.rsa) <= 0)
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+					goto err;
+					}
+				s2n(u,p);
+				n+=u+2;
+				}
+			else
+#endif
+#if !defined(OPENSSL_NO_DSA)
+				if (pkey->type == EVP_PKEY_DSA)
+				{
+				/* lets do DSS */
+				EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
+				EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+				EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+				if (!EVP_SignFinal(&md_ctx,&(p[2]),
+					(unsigned int *)&i,pkey))
+					{
+					SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
+					goto err;
+					}
+				s2n(i,p);
+				n+=i+2;
+				}
+			else
+#endif
+				{
+				/* Is this error check actually needed? */
+				al=SSL_AD_HANDSHAKE_FAILURE;
+				SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
+				goto f_err;
+				}
+			}
+
+		d = dtls1_set_message_header(s, d,
+			SSL3_MT_SERVER_KEY_EXCHANGE, n, 0, n);
+
+		/* we should now have things packed up, so lets send
+		 * it off */
+		s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	s->state = SSL3_ST_SW_KEY_EXCH_B;
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+f_err:
+	ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+	EVP_MD_CTX_cleanup(&md_ctx);
+	return(-1);
+	}
+
+int dtls1_send_certificate_request(SSL *s)
+	{
+	unsigned char *p,*d;
+	int i,j,nl,off,n;
+	STACK_OF(X509_NAME) *sk=NULL;
+	X509_NAME *name;
+	BUF_MEM *buf;
+
+	if (s->state == SSL3_ST_SW_CERT_REQ_A)
+		{
+		buf=s->init_buf;
+
+		d=p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
+
+		/* get the list of acceptable cert types */
+		p++;
+		n=ssl3_get_req_cert_type(s,p);
+		d[0]=n;
+		p+=n;
+		n++;
+
+		off=n;
+		p+=2;
+		n+=2;
+
+		sk=SSL_get_client_CA_list(s);
+		nl=0;
+		if (sk != NULL)
+			{
+			for (i=0; i<sk_X509_NAME_num(sk); i++)
+				{
+				name=sk_X509_NAME_value(sk,i);
+				j=i2d_X509_NAME(name,NULL);
+				if (!BUF_MEM_grow_clean(buf,DTLS1_HM_HEADER_LENGTH+n+j+2))
+					{
+					SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+					goto err;
+					}
+				p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+n]);
+				if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+					{
+					s2n(j,p);
+					i2d_X509_NAME(name,&p);
+					n+=2+j;
+					nl+=2+j;
+					}
+				else
+					{
+					d=p;
+					i2d_X509_NAME(name,&p);
+					j-=2; s2n(j,d); j+=2;
+					n+=j;
+					nl+=j;
+					}
+				}
+			}
+		/* else no CA names */
+		p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+off]);
+		s2n(nl,p);
+
+		d=(unsigned char *)buf->data;
+		*(d++)=SSL3_MT_CERTIFICATE_REQUEST;
+		l2n3(n,d);
+		l2n(s->d1->handshake_write_seq,d);
+		s->d1->handshake_write_seq++;
+
+		/* we should now have things packed up, so lets send
+		 * it off */
+
+		s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+		s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+/* XXX: what to do about this? */
+		p=(unsigned char *)s->init_buf->data + s->init_num;
+
+		/* do the header */
+		*(p++)=SSL3_MT_SERVER_DONE;
+		*(p++)=0;
+		*(p++)=0;
+		*(p++)=0;
+		s->init_num += 4;
+#endif
+
+		/* XDTLS:  set message header ? */
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+
+		s->state = SSL3_ST_SW_CERT_REQ_B;
+		}
+
+	/* SSL3_ST_SW_CERT_REQ_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+	return(-1);
+	}
+
+int dtls1_send_server_certificate(SSL *s)
+	{
+	unsigned long l;
+	X509 *x;
+
+	if (s->state == SSL3_ST_SW_CERT_A)
+		{
+		x=ssl_get_server_send_cert(s);
+		if (x == NULL &&
+                        /* VRS: allow null cert if auth == KRB5 */
+                        (s->s3->tmp.new_cipher->algorithms
+                                & (SSL_MKEY_MASK|SSL_AUTH_MASK))
+                        != (SSL_aKRB5|SSL_kKRB5))
+			{
+			SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
+			return(0);
+			}
+
+		l=dtls1_output_cert_chain(s,x);
+		s->state=SSL3_ST_SW_CERT_B;
+		s->init_num=(int)l;
+		s->init_off=0;
+
+		/* buffer the message to handle re-xmits */
+		dtls1_buffer_message(s, 0);
+		}
+
+	/* SSL3_ST_SW_CERT_B */
+	return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+	}
diff --git a/ssl/dtls1.h b/ssl/dtls1.h
new file mode 100644
index 0000000..e3b6ad5
--- /dev/null
+++ b/ssl/dtls1.h
@@ -0,0 +1,244 @@
+/* ssl/dtls1.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DTLS1_H 
+#define HEADER_DTLS1_H 
+
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES	1
+
+#define DTLS1_VERSION			0x0100
+#define DTLS1_VERSION_MAJOR		0x01
+#define DTLS1_VERSION_MINOR		0x00
+
+#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH                     32
+
+#define DTLS1_RT_HEADER_LENGTH                  13
+
+#define DTLS1_HM_HEADER_LENGTH                  12
+
+#define DTLS1_HM_BAD_FRAGMENT                   -2
+#define DTLS1_HM_FRAGMENT_RETRY                 -3
+
+#define DTLS1_CCS_HEADER_LENGTH                  3
+
+#define DTLS1_AL_HEADER_LENGTH                   7
+
+
+typedef struct dtls1_bitmap_st
+	{
+	unsigned long long map;
+	unsigned long length;     /* sizeof the bitmap in bits */
+	unsigned long long max_seq_num;  /* max record number seen so far */
+	} DTLS1_BITMAP;
+
+struct hm_header_st
+	{
+	unsigned char type;
+	unsigned long msg_len;
+	unsigned short seq;
+	unsigned long frag_off;
+	unsigned long frag_len;
+    unsigned int is_ccs;
+	};
+
+struct ccs_header_st
+	{
+	unsigned char type;
+	unsigned short seq;
+	};
+
+struct dtls1_timeout_st
+	{
+	/* Number of read timeouts so far */
+	unsigned int read_timeouts;
+	
+	/* Number of write timeouts so far */
+	unsigned int write_timeouts;
+	
+	/* Number of alerts received so far */
+	unsigned int num_alerts;
+	};
+
+typedef struct record_pqueue_st
+    {
+    unsigned short epoch;
+    pqueue q;
+    } record_pqueue;
+
+typedef struct hm_fragment_st
+    {
+    struct hm_header_st msg_header;
+    unsigned char *fragment;
+    } hm_fragment;
+
+typedef struct dtls1_state_st
+	{
+	unsigned int send_cookie;
+	unsigned char cookie[DTLS1_COOKIE_LENGTH];
+	unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
+	unsigned int cookie_len;
+
+	/* 
+	 * The current data and handshake epoch.  This is initially
+	 * undefined, and starts at zero once the initial handshake is
+	 * completed 
+	 */
+	unsigned short r_epoch;
+	unsigned short w_epoch;
+
+	/* records being received in the current epoch */
+	DTLS1_BITMAP bitmap;
+
+	/* renegotiation starts a new set of sequence numbers */
+	DTLS1_BITMAP next_bitmap;
+
+	/* handshake message numbers */
+	unsigned short handshake_write_seq;
+	unsigned short next_handshake_write_seq;
+
+	unsigned short handshake_read_seq;
+
+    /* only matters for handshake messages */  
+	unsigned long long next_expected_seq_num; 
+
+	/* Received handshake records (processed and unprocessed) */
+	record_pqueue unprocessed_rcds;
+    record_pqueue processed_rcds;
+
+    /* Buffered handshake messages */
+    pqueue buffered_messages;
+
+	/* Buffered (sent) handshake records */
+	pqueue sent_messages;
+
+	unsigned int mtu; /* max wire packet size */
+
+	struct hm_header_st w_msg_hdr;
+	struct hm_header_st r_msg_hdr;
+
+	struct dtls1_timeout_st timeout;
+	
+	/* storage for Alert/Handshake protocol data received but not
+	 * yet processed by ssl3_read_bytes: */
+	unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
+	unsigned int alert_fragment_len;
+	unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
+	unsigned int handshake_fragment_len;
+
+	unsigned int retransmitting;
+
+	} DTLS1_STATE;
+
+typedef struct dtls1_record_data_st
+	{
+	unsigned char *packet;
+	unsigned int   packet_length;
+	SSL3_BUFFER    rbuf;
+	SSL3_RECORD    rrec;
+	} DTLS1_RECORD_DATA;
+
+/* client methods */
+int dtls1_client_hello(SSL *s);
+int dtls1_send_client_certificate(SSL *s);
+int dtls1_send_client_key_exchange(SSL *s);
+int dtls1_send_client_verify(SSL *s);
+
+
+/* server methods */
+int dtls1_send_hello_request(SSL *s);
+int dtls1_send_server_hello(SSL *s);
+int dtls1_send_server_certificate(SSL *s);
+int dtls1_send_server_key_exchange(SSL *s);
+int dtls1_send_certificate_request(SSL *s);
+int dtls1_send_server_done(SSL *s);
+
+/* common methods */
+int dtls1_send_change_cipher_spec(SSL *s, int a, int b);
+int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen);
+unsigned long dtls1_output_cert_chain(SSL *s, X509 *x);
+int dtls1_read_failed(SSL *s, int code);
+int dtls1_buffer_message(SSL *s, int ccs);
+int dtls1_retransmit_message(SSL *s, unsigned short seq, 
+	unsigned long frag_off, int *found);
+void dtls1_clear_record_buffer(SSL *s);
+void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr);
+void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
+void dtls1_reset_seq_numbers(SSL *s, int rw);
+
+/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
+#define DTLS1_TMO_READ_COUNT                      2
+#define DTLS1_TMO_WRITE_COUNT                     2
+
+#define DTLS1_TMO_ALERT_COUNT                     12
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
diff --git a/ssl/s23_lib.c b/ssl/s23_lib.c
index bcfda91..2c51298 100644
--- a/ssl/s23_lib.c
+++ b/ssl/s23_lib.c
@@ -83,6 +83,10 @@
 	ssl_undefined_function,
 	ssl_undefined_function,
 	ssl_ok,
+	ssl3_get_message,
+	ssl3_read_bytes,
+	ssl3_write_bytes,
+	ssl3_dispatch_alert,
 	ssl3_ctrl,
 	ssl3_ctx_ctrl,
 	ssl23_get_cipher_by_char,
diff --git a/ssl/s2_lib.c b/ssl/s2_lib.c
index 6f7d11f..a454d73 100644
--- a/ssl/s2_lib.c
+++ b/ssl/s2_lib.c
@@ -224,6 +224,10 @@
 	ssl2_shutdown,
 	ssl_ok,	/* NULL - renegotiate */
 	ssl_ok,	/* NULL - check renegotiate */
+	NULL, /* NULL - ssl_get_message */
+	NULL, /* NULL - ssl_get_record */
+	NULL, /* NULL - ssl_write_bytes */
+	NULL, /* NULL - dispatch_alert */
 	ssl2_ctrl,	/* local */
 	ssl2_ctx_ctrl,	/* local */
 	ssl2_get_cipher_by_char,
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index b26fbe3..2ecfbb7 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -197,7 +197,7 @@
 	 * change cipher spec message and is in s->s3->tmp.peer_finish_md
 	 */ 
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		a,
 		b,
 		SSL3_MT_FINISHED,
@@ -391,8 +391,8 @@
 			{
 			while (s->init_num < 4)
 				{
-				i=ssl3_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
-					4 - s->init_num, 0);
+				i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+					&p[s->init_num],4 - s->init_num, 0);
 				if (i <= 0)
 					{
 					s->rwstate=SSL_READING;
@@ -472,7 +472,7 @@
 	n = s->s3->tmp.message_size - s->init_num;
 	while (n > 0)
 		{
-		i=ssl3_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],n,0);
+		i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],n,0);
 		if (i <= 0)
 			{
 			s->rwstate=SSL_READING;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index e6a83fb..07546dc 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -134,17 +134,7 @@
 #include <openssl/bn.h>
 
 static SSL_METHOD *ssl3_get_client_method(int ver);
-static int ssl3_client_hello(SSL *s);
-static int ssl3_get_server_hello(SSL *s);
-static int ssl3_get_certificate_request(SSL *s);
 static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
-static int ssl3_get_server_done(SSL *s);
-static int ssl3_send_client_verify(SSL *s);
-static int ssl3_send_client_certificate(SSL *s);
-static int ssl3_send_client_key_exchange(SSL *s);
-static int ssl3_get_key_exchange(SSL *s);
-static int ssl3_get_server_certificate(SSL *s);
-static int ssl3_check_cert_and_algorithm(SSL *s);
 
 #ifndef OPENSSL_NO_ECDH
 static int curve_id2nid(int curve_id);
@@ -539,7 +529,7 @@
 	}
 
 
-static int ssl3_client_hello(SSL *s)
+int ssl3_client_hello(SSL *s)
 	{
 	unsigned char *buf;
 	unsigned char *p,*d;
@@ -632,7 +622,7 @@
 	return(-1);
 	}
 
-static int ssl3_get_server_hello(SSL *s)
+int ssl3_get_server_hello(SSL *s)
 	{
 	STACK_OF(SSL_CIPHER) *sk;
 	SSL_CIPHER *c;
@@ -642,14 +632,41 @@
 	long n;
 	SSL_COMP *comp;
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_SRVR_HELLO_A,
 		SSL3_ST_CR_SRVR_HELLO_B,
-		SSL3_MT_SERVER_HELLO,
+		-1,
 		300, /* ?? */
 		&ok);
 
 	if (!ok) return((int)n);
+
+	if ( SSL_version(s) == DTLS1_VERSION)
+		{
+		if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
+			{
+			if ( s->d1->send_cookie == 0)
+				{
+				s->s3->tmp.reuse_message = 1;
+				return 1;
+				}
+			else /* already sent a cookie */
+				{
+				al=SSL_AD_UNEXPECTED_MESSAGE;
+				SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+					SSL_R_BAD_MESSAGE_TYPE);
+				goto f_err;
+				}
+			}
+		}
+	
+	if ( s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO)
+		{
+		al=SSL_AD_UNEXPECTED_MESSAGE;
+		SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
+		goto f_err;
+		}
+
 	d=p=(unsigned char *)s->init_msg;
 
 	if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
@@ -777,7 +794,7 @@
 	return(-1);
 	}
 
-static int ssl3_get_server_certificate(SSL *s)
+int ssl3_get_server_certificate(SSL *s)
 	{
 	int al,i,ok,ret= -1;
 	unsigned long n,nc,llen,l;
@@ -789,7 +806,7 @@
 	EVP_PKEY *pkey=NULL;
 	int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_CERT_A,
 		SSL3_ST_CR_CERT_B,
 		-1,
@@ -961,7 +978,7 @@
 	return(ret);
 	}
 
-static int ssl3_get_key_exchange(SSL *s)
+int ssl3_get_key_exchange(SSL *s)
 	{
 #ifndef OPENSSL_NO_RSA
 	unsigned char *q,md_buf[EVP_MAX_MD_SIZE*2];
@@ -987,7 +1004,7 @@
 
 	/* use same message size as in ssl3_get_certificate_request()
 	 * as ServerKeyExchange message may be skipped */
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_KEY_EXCH_A,
 		SSL3_ST_CR_KEY_EXCH_B,
 		-1,
@@ -1405,7 +1422,7 @@
 	return(-1);
 	}
 
-static int ssl3_get_certificate_request(SSL *s)
+int ssl3_get_certificate_request(SSL *s)
 	{
 	int ok,ret=0;
 	unsigned long n,nc,l;
@@ -1415,7 +1432,7 @@
 	unsigned char *d;
 	STACK_OF(X509_NAME) *ca_sk=NULL;
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_CERT_REQ_A,
 		SSL3_ST_CR_CERT_REQ_B,
 		-1,
@@ -1553,12 +1570,12 @@
 	return(X509_NAME_cmp(*a,*b));
 	}
 
-static int ssl3_get_server_done(SSL *s)
+int ssl3_get_server_done(SSL *s)
 	{
 	int ok,ret=0;
 	long n;
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_CR_SRVR_DONE_A,
 		SSL3_ST_CR_SRVR_DONE_B,
 		SSL3_MT_SERVER_DONE,
@@ -1592,7 +1609,7 @@
 #endif
 	}
 
-static int ssl3_send_client_key_exchange(SSL *s)
+int ssl3_send_client_key_exchange(SSL *s)
 	{
 	unsigned char *p,*d;
 	int n;
@@ -2087,7 +2104,7 @@
 	return(-1);
 	}
 
-static int ssl3_send_client_verify(SSL *s)
+int ssl3_send_client_verify(SSL *s)
 	{
 	unsigned char *p,*d;
 	unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
@@ -2175,7 +2192,7 @@
 	return(-1);
 	}
 
-static int ssl3_send_client_certificate(SSL *s)
+int ssl3_send_client_certificate(SSL *s)
 	{
 	X509 *x509=NULL;
 	EVP_PKEY *pkey=NULL;
@@ -2254,7 +2271,7 @@
 
 #define has_bits(i,m)	(((i)&(m)) == (m))
 
-static int ssl3_check_cert_and_algorithm(SSL *s)
+int ssl3_check_cert_and_algorithm(SSL *s)
 	{
 	int i,idx;
 	long algs;
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index 5d133ee..6d92050 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -569,7 +569,7 @@
 	const EVP_MD *hash;
 	unsigned char *p,rec_char;
 	unsigned int md_size;
-	int npad,i;
+	int npad;
 
 	if (send)
 		{
@@ -612,13 +612,19 @@
 
 	EVP_MD_CTX_cleanup(&md_ctx);
 
+	ssl3_record_sequence_update(seq);
+	return(md_size);
+	}
+
+void ssl3_record_sequence_update(unsigned char *seq)
+	{
+	int i;
+
 	for (i=7; i>=0; i--)
 		{
 		++seq[i];
 		if (seq[i] != 0) break; 
 		}
-
-	return(md_size);
 	}
 
 int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 345f74b..08d2724 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -1381,6 +1381,10 @@
 	ssl3_shutdown,
 	ssl3_renegotiate,
 	ssl3_renegotiate_check,
+	ssl3_get_message,
+	ssl3_read_bytes,
+	ssl3_write_bytes,
+	ssl3_dispatch_alert,
 	ssl3_ctrl,
 	ssl3_ctx_ctrl,
 	ssl3_get_cipher_by_char,
@@ -2141,13 +2145,13 @@
 		{
 		/* resend it if not sent */
 #if 1
-		ssl3_dispatch_alert(s);
+		s->method->ssl_dispatch_alert(s);
 #endif
 		}
 	else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
 		{
 		/* If we are waiting for a close from our peer, we are closed */
-		ssl3_read_bytes(s,0,NULL,0,0);
+		s->method->ssl_read_bytes(s,0,NULL,0,0);
 		}
 
 	if ((s->shutdown == (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) &&
@@ -2202,8 +2206,8 @@
 		}
 	else
 		{
-		ret=ssl3_write_bytes(s,SSL3_RT_APPLICATION_DATA,
-				     buf,len);
+		ret=s->method->ssl_write_bytes(s,SSL3_RT_APPLICATION_DATA,
+			buf,len);
 		if (ret <= 0) return(ret);
 		}
 
@@ -2217,7 +2221,7 @@
 	clear_sys_error();
 	if (s->s3->renegotiate) ssl3_renegotiate_check(s);
 	s->s3->in_read_app_data=1;
-	ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+	ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
 	if ((ret == -1) && (s->s3->in_read_app_data == 2))
 		{
 		/* ssl3_read_bytes decided to call s->handshake_func, which
@@ -2226,7 +2230,7 @@
 		 * and thinks that application data makes sense here; so disable
 		 * handshake processing and try to read application data again. */
 		s->in_handshake++;
-		ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+		ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
 		s->in_handshake--;
 		}
 	else
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 1f89e8c..f92ec59 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -118,15 +118,9 @@
 
 static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
 			 unsigned int len, int create_empty_fragment);
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
-			      unsigned int len);
 static int ssl3_get_record(SSL *s);
-static int do_compress(SSL *ssl);
-static int do_uncompress(SSL *ssl);
-static int do_change_cipher_spec(SSL *ssl);
 
-/* used only by ssl3_get_record */
-static int ssl3_read_n(SSL *s, int n, int max, int extend)
+int ssl3_read_n(SSL *s, int n, int max, int extend)
 	{
 	/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
 	 * packet by another n bytes.
@@ -147,6 +141,14 @@
 		/* ... now we can act as if 'extend' was set */
 		}
 
+	/* extend reads should not span multiple packets for DTLS */
+	if ( SSL_version(s) == DTLS1_VERSION &&
+		extend)
+		{
+		if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
+			n = s->s3->rbuf.left;
+		}
+
 	/* if there is enough in the buffer from a previous read, take some */
 	if (s->s3->rbuf.left >= (int)n)
 		{
@@ -434,7 +436,7 @@
 			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
 			goto f_err;
 			}
-		if (!do_uncompress(s))
+		if (!ssl3_do_uncompress(s))
 			{
 			al=SSL_AD_DECOMPRESSION_FAILURE;
 			SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
@@ -472,7 +474,7 @@
 	return(ret);
 	}
 
-static int do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl)
 	{
 	int i;
 	SSL3_RECORD *rr;
@@ -489,7 +491,7 @@
 	return(1);
 	}
 
-static int do_compress(SSL *ssl)
+int ssl3_do_compress(SSL *ssl)
 	{
 	int i;
 	SSL3_RECORD *wr;
@@ -580,7 +582,7 @@
 	/* If we have an alert to send, lets send it */
 	if (s->s3->alert_dispatch)
 		{
-		i=ssl3_dispatch_alert(s);
+		i=s->method->ssl_dispatch_alert(s);
 		if (i <= 0)
 			return(i);
 		/* if it went, fall through and send more stuff */
@@ -655,7 +657,7 @@
 	/* first we compress */
 	if (s->compress != NULL)
 		{
-		if (!do_compress(s))
+		if (!ssl3_do_compress(s))
 			{
 			SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
 			goto err;
@@ -716,8 +718,8 @@
 	}
 
 /* if s->s3->wbuf.left != 0, we need to call this */
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
-			      unsigned int len)
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+	unsigned int len)
 	{
 	int i;
 
@@ -1091,7 +1093,7 @@
 			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 (!do_change_cipher_spec(s))
+		if (!ssl3_do_change_cipher_spec(s))
 			goto err;
 		else
 			goto start;
@@ -1203,7 +1205,7 @@
 	return(-1);
 	}
 
-static int do_change_cipher_spec(SSL *s)
+int ssl3_do_change_cipher_spec(SSL *s)
 	{
 	int i;
 	const char *sender;
@@ -1260,7 +1262,7 @@
 	s->s3->send_alert[0]=level;
 	s->s3->send_alert[1]=desc;
 	if (s->s3->wbuf.left == 0) /* data still being written out? */
-		ssl3_dispatch_alert(s);
+		s->method->ssl_dispatch_alert(s);
 	/* else data is still being written out, we will get written
 	 * some time in the future */
 	}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 62a6cf7..ff2fd30 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -56,7 +56,7 @@
  * [including the GNU Public Licence.]
  */
 /* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -141,16 +141,6 @@
 #include <openssl/md5.h>
 
 static SSL_METHOD *ssl3_get_server_method(int ver);
-static int ssl3_get_client_hello(SSL *s);
-static int ssl3_check_client_hello(SSL *s);
-static int ssl3_send_server_hello(SSL *s);
-static int ssl3_send_server_key_exchange(SSL *s);
-static int ssl3_send_certificate_request(SSL *s);
-static int ssl3_send_server_done(SSL *s);
-static int ssl3_get_client_key_exchange(SSL *s);
-static int ssl3_get_client_certificate(SSL *s);
-static int ssl3_get_cert_verify(SSL *s);
-static int ssl3_send_hello_request(SSL *s);
 
 #ifndef OPENSSL_NO_ECDH
 static int nid2curve_id(int nid);
@@ -629,7 +619,7 @@
 	return(ret);
 	}
 
-static int ssl3_send_hello_request(SSL *s)
+int ssl3_send_hello_request(SSL *s)
 	{
 	unsigned char *p;
 
@@ -651,14 +641,14 @@
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 	}
 
-static int ssl3_check_client_hello(SSL *s)
+int ssl3_check_client_hello(SSL *s)
 	{
 	int ok;
 	long n;
 
 	/* this function is called when we really expect a Certificate message,
 	 * so permit appropriate message length */
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_CERT_A,
 		SSL3_ST_SR_CERT_B,
 		-1,
@@ -684,9 +674,10 @@
 	return 1;
 }
 
-static int ssl3_get_client_hello(SSL *s)
+int ssl3_get_client_hello(SSL *s)
 	{
 	int i,j,ok,al,ret= -1;
+	int cookie_len;
 	long n;
 	unsigned long id;
 	unsigned char *p,*d,*q;
@@ -705,7 +696,7 @@
 		s->first_packet=1;
 		s->state=SSL3_ST_SR_CLNT_HELLO_B;
 		}
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_CLNT_HELLO_B,
 		SSL3_ST_SR_CLNT_HELLO_C,
 		SSL3_MT_CLIENT_HELLO,
@@ -770,6 +761,68 @@
 		}
 
 	p+=j;
+
+	if (SSL_version(s) == DTLS1_VERSION)
+		{
+		/* 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
+         * does not cause an overflow.
+         */
+		if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+			{
+			/* too much data */
+            al = SSL_AD_DECODE_ERROR;
+			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+			goto f_err;
+			}
+
+        /* verify the cookie if appropriate option is set. */
+        if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+            cookie_len > 0)
+            {
+            memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+            if ( s->ctx->app_verify_cookie_cb != NULL)
+                {
+                if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+                    cookie_len) == 0)
+                    {
+                    al=SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+                        SSL_R_COOKIE_MISMATCH);
+                    goto f_err;
+                    }
+                /* else cookie verification succeeded */
+                }
+            else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie, 
+                          s->d1->cookie_len) != 0) /* default verification */
+                {
+                    al=SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, 
+                        SSL_R_COOKIE_MISMATCH);
+                    goto f_err;
+                }
+            }
+
+        p += cookie_len;
+		}
+
 	n2s(p,i);
 	if ((i == 0) && (j != 0))
 		{
@@ -983,7 +1036,7 @@
 	return(ret);
 	}
 
-static int ssl3_send_server_hello(SSL *s)
+int ssl3_send_server_hello(SSL *s)
 	{
 	unsigned char *buf;
 	unsigned char *p,*d;
@@ -1054,7 +1107,7 @@
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 	}
 
-static int ssl3_send_server_done(SSL *s)
+int ssl3_send_server_done(SSL *s)
 	{
 	unsigned char *p;
 
@@ -1078,7 +1131,7 @@
 	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
 	}
 
-static int ssl3_send_server_key_exchange(SSL *s)
+int ssl3_send_server_key_exchange(SSL *s)
 	{
 #ifndef OPENSSL_NO_RSA
 	unsigned char *q;
@@ -1497,7 +1550,7 @@
 	return(-1);
 	}
 
-static int ssl3_send_certificate_request(SSL *s)
+int ssl3_send_certificate_request(SSL *s)
 	{
 	unsigned char *p,*d;
 	int i,j,nl,off,n;
@@ -1601,7 +1654,7 @@
 #endif
 	}
 
-static int ssl3_get_client_key_exchange(SSL *s)
+int ssl3_get_client_key_exchange(SSL *s)
 	{
 	int i,al,ok;
 	long n;
@@ -1626,7 +1679,7 @@
 	BN_CTX *bn_ctx = NULL; 
 #endif
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_KEY_EXCH_A,
 		SSL3_ST_SR_KEY_EXCH_B,
 		SSL3_MT_CLIENT_KEY_EXCHANGE,
@@ -2138,7 +2191,7 @@
 	return(-1);
 	}
 
-static int ssl3_get_cert_verify(SSL *s)
+int ssl3_get_cert_verify(SSL *s)
 	{
 	EVP_PKEY *pkey=NULL;
 	unsigned char *p;
@@ -2147,7 +2200,7 @@
 	int type=0,i,j;
 	X509 *peer;
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_CERT_VRFY_A,
 		SSL3_ST_SR_CERT_VRFY_B,
 		-1,
@@ -2293,7 +2346,7 @@
 	return(ret);
 	}
 
-static int ssl3_get_client_certificate(SSL *s)
+int ssl3_get_client_certificate(SSL *s)
 	{
 	int i,ok,al,ret= -1;
 	X509 *x=NULL;
@@ -2302,7 +2355,7 @@
 	unsigned char *d;
 	STACK_OF(X509) *sk=NULL;
 
-	n=ssl3_get_message(s,
+	n=s->method->ssl_get_message(s,
 		SSL3_ST_SR_CERT_A,
 		SSL3_ST_SR_CERT_B,
 		-1,
diff --git a/ssl/ssl.h b/ssl/ssl.h
index df9acf9..8d33ca6 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -376,6 +376,14 @@
 	int (*ssl_shutdown)(SSL *s);
 	int (*ssl_renegotiate)(SSL *s);
 	int (*ssl_renegotiate_check)(SSL *s);
+	/* -- begin DTLS -- */
+	long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
+		max, int *ok);
+	int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len, 
+		int peek);
+	int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
+	int (*ssl_dispatch_alert)(SSL *s);
+	/* -- end DTLS -- */
 	long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
 	long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
 	SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
@@ -490,6 +498,11 @@
  *             This used to be 0x000FFFFFL before 0.9.7. */
 #define SSL_OP_ALL					0x00000FFFL
 
+/* DTLS options */
+#define SSL_OP_NO_QUERY_MTU                 0x00001000L
+/* Turn on Cookie Exchange (on relevant for servers) */
+#define SSL_OP_COOKIE_EXCHANGE              0x00002000L
+
 /* As server, disallow session resumption on renegotiation */
 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
 /* If set, always create a new key when using tmp_ecdh parameters */
@@ -555,6 +568,8 @@
 	SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
 #define SSL_get_mode(ssl) \
         SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mtu(ssl, mtu) \
+        SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
 
 
 void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
@@ -679,6 +694,14 @@
 	/* get client cert callback */
 	int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
 
+    /* cookie generate callback */
+    int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int *cookie_len);
+
+    /* verify cookie callback */
+    int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int cookie_len);
+
 	CRYPTO_EX_DATA ex_data;
 
 	const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
@@ -775,6 +798,8 @@
 #define SSL_CTX_get_info_callback(ctx)		((ctx)->info_callback)
 #define SSL_CTX_set_client_cert_cb(ctx,cb)	((ctx)->client_cert_cb=(cb))
 #define SSL_CTX_get_client_cert_cb(ctx)		((ctx)->client_cert_cb)
+#define SSL_CTX_set_cookie_generate_cb(ctx,cb) ((ctx)->app_gen_cookie_cb=(cb))
+#define SSL_CTX_set_cookie_verify_cb(ctx,cb) ((ctx)->app_verify_cookie_cb=(cb))
 
 #define SSL_NOTHING	1
 #define SSL_WRITING	2
@@ -790,7 +815,7 @@
 struct ssl_st
 	{
 	/* protocol version
-	 * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION)
+	 * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
 	 */
 	int version;
 	int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
@@ -854,6 +879,7 @@
 
 	struct ssl2_state_st *s2; /* SSLv2 variables */
 	struct ssl3_state_st *s3; /* SSLv3 variables */
+	struct dtls1_state_st *d1; /* DTLSv1 variables */
 
 	int read_ahead;		/* Read as many input bytes as possible
 	               	 	 * (for non-blocking reads) */
@@ -953,6 +979,7 @@
 #include <openssl/ssl2.h>
 #include <openssl/ssl3.h>
 #include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
+#include <openssl/dtls1.h> /* Datagram TLS */
 #include <openssl/ssl23.h>
 
 #ifdef  __cplusplus
@@ -1118,6 +1145,8 @@
 #define SSL_CTRL_SET_MSG_CALLBACK               15
 #define SSL_CTRL_SET_MSG_CALLBACK_ARG           16
 
+/* only applies to datagram connections */
+#define SSL_CTRL_SET_MTU                17
 /* Stats */
 #define SSL_CTRL_SESS_NUMBER			20
 #define SSL_CTRL_SESS_CONNECT			21
@@ -1362,6 +1391,10 @@
 SSL_METHOD *TLSv1_server_method(void);	/* TLSv1.0 */
 SSL_METHOD *TLSv1_client_method(void);	/* TLSv1.0 */
 
+SSL_METHOD *DTLSv1_method(void);		/* DTLSv1.0 */
+SSL_METHOD *DTLSv1_server_method(void);	/* DTLSv1.0 */
+SSL_METHOD *DTLSv1_client_method(void);	/* DTLSv1.0 */
+
 STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
 
 int SSL_do_handshake(SSL *s);
@@ -1657,6 +1690,9 @@
 #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
 #define SSL_F_WRITE_PENDING				 212
 
+#define SSL_F_DTLS1_READ_FAILED          1001
+#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST    1002
+
 /* Reason codes. */
 #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
 #define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
@@ -1895,6 +1931,9 @@
 #define SSL_R_X509_LIB					 268
 #define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS		 269
 
+#define SSL_R_READ_TIMEOUT_EXPIRED              2001
+#define SSL_R_COOKIE_MISMATCH                   2002
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 796dcbc..f1580d2 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -294,6 +294,8 @@
 /*rw*/	unsigned char *data;    /* pointer to the record data */
 /*rw*/	unsigned char *input;   /* where the decode bytes are */
 /*r */	unsigned char *comp;    /* only used with decompression - malloc()ed */
+/*r */  unsigned long epoch;    /* epoch number, needed by DTLS1 */
+/*r */  unsigned long long seq_num; /* sequence number, needed by DTLS1 */
 	} SSL3_RECORD;
 
 typedef struct ssl3_buffer_st
@@ -435,6 +437,35 @@
 
 	} SSL3_STATE;
 
+
+/* client methods */
+int ssl3_client_hello(SSL *s);
+int ssl3_get_server_hello(SSL *s);
+int ssl3_get_certificate_request(SSL *s);
+int ssl3_get_server_done(SSL *s);
+int ssl3_send_client_verify(SSL *s);
+int ssl3_send_client_certificate(SSL *s);
+int ssl3_send_client_key_exchange(SSL *s);
+int ssl3_get_key_exchange(SSL *s);
+int ssl3_get_server_certificate(SSL *s);
+int ssl3_check_cert_and_algorithm(SSL *s);
+
+/* server methods */
+int ssl3_get_client_hello(SSL *s);
+int ssl3_send_server_hello(SSL *s);
+int ssl3_send_hello_request(SSL *s);
+int ssl3_send_server_key_exchange(SSL *s);
+int ssl3_send_certificate_request(SSL *s);
+int ssl3_send_server_done(SSL *s);
+int ssl3_check_client_hello(SSL *s);
+int ssl3_get_client_certificate(SSL *s);
+int ssl3_get_client_key_exchange(SSL *s);
+int ssl3_get_cert_verify(SSL *s);
+
+/* utility functions */
+void ssl3_record_sequence_update(unsigned char *seq);
+int ssl3_do_change_cipher_spec(SSL *ssl);
+
 /* SSLv3 */
 /*client */
 /* extra state */
@@ -445,6 +476,8 @@
 /* read from server */
 #define SSL3_ST_CR_SRVR_HELLO_A		(0x120|SSL_ST_CONNECT)
 #define SSL3_ST_CR_SRVR_HELLO_B		(0x121|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
 #define SSL3_ST_CR_CERT_A		(0x130|SSL_ST_CONNECT)
 #define SSL3_ST_CR_CERT_B		(0x131|SSL_ST_CONNECT)
 #define SSL3_ST_CR_KEY_EXCH_A		(0x140|SSL_ST_CONNECT)
@@ -481,6 +514,8 @@
 #define SSL3_ST_SR_CLNT_HELLO_B		(0x111|SSL_ST_ACCEPT)
 #define SSL3_ST_SR_CLNT_HELLO_C		(0x112|SSL_ST_ACCEPT)
 /* write to client */
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_HELLO_REQ_A		(0x120|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_HELLO_REQ_B		(0x121|SSL_ST_ACCEPT)
 #define SSL3_ST_SW_HELLO_REQ_C		(0x122|SSL_ST_ACCEPT)
@@ -521,6 +556,8 @@
 #define SSL3_MT_CERTIFICATE_VERIFY		15
 #define SSL3_MT_CLIENT_KEY_EXCHANGE		16
 #define SSL3_MT_FINISHED			20
+#define DTLS1_MT_HELLO_VERIFY_REQUEST    3
+
 
 #define SSL3_MT_CCS				1
 
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index fc45728..56e7864 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -456,6 +456,8 @@
 {ERR_REASON(SSL_R_WRONG_VERSION_NUMBER)  ,"wrong version number"},
 {ERR_REASON(SSL_R_X509_LIB)              ,"x509 lib"},
 {ERR_REASON(SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),"x509 verification setup problems"},
+{ERR_REASON(SSL_R_READ_TIMEOUT_EXPIRED)  ,"read timeout expired"},
+{ERR_REASON(SSL_R_COOKIE_MISMATCH)       ,"cookie mismatch"},
 {0,NULL}
 	};
 
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7d40632..fbcfc52 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -957,6 +957,13 @@
 		l=s->max_cert_list;
 		s->max_cert_list=larg;
 		return(l);
+	case SSL_CTRL_SET_MTU:
+		if (SSL_version(s) == DTLS1_VERSION)
+			{
+			s->d1->mtu = larg;
+			return larg;
+			}
+		return 0;
 	default:
 		return(s->method->ssl_ctrl(s,cmd,larg,parg));
 		}
@@ -1368,6 +1375,8 @@
 	ret->default_passwd_callback=0;
 	ret->default_passwd_callback_userdata=NULL;
 	ret->client_cert_cb=0;
+    ret->app_gen_cookie_cb=0;
+    ret->app_verify_cookie_cb=0;
 
 	ret->sessions=lh_new(LHASH_HASH_FN(SSL_SESSION_hash),
 			LHASH_COMP_FN(SSL_SESSION_cmp));
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 8ff2021..21d43b4 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -176,6 +176,20 @@
 			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
 			 *((c)++)=(unsigned char)(((l)    )&0xff))
 
+#define l2n6(l,c)	(*((c)++)=(unsigned char)(((l)>>40)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+			 *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+			 *((c)++)=(unsigned char)(((l)    )&0xff))
+
+#define n2l6(c,l)	(l =((unsigned long long)(*((c)++)))<<40, \
+			 l|=((unsigned long long)(*((c)++)))<<32, \
+			 l|=((unsigned long long)(*((c)++)))<<24, \
+			 l|=((unsigned long long)(*((c)++)))<<16, \
+			 l|=((unsigned long long)(*((c)++)))<< 8, \
+			 l|=((unsigned long long)(*((c)++))))
+
 /* NOTE - c is not incremented as per l2c */
 #define l2cn(l1,l2,c,n)	{ \
 			c+=n; \
@@ -608,6 +622,21 @@
 long	ssl3_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)(void));
 int	ssl3_pending(const SSL *s);
 
+/* -- begin DTLS -- */
+int dtls1_do_write(SSL *s,int type);
+int ssl3_read_n(SSL *s, int n, int max, int extend);
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
+int ssl3_do_compress(SSL *ssl);
+int ssl3_do_uncompress(SSL *ssl);
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+	unsigned int len);
+unsigned char *dtls1_set_message_header(SSL *s, 
+	unsigned char *p, unsigned char mt,	unsigned long len, 
+	unsigned long frag_off, unsigned long frag_len);
+int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len);
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
+/* -- end DTLS -- */
+
 int ssl23_accept(SSL *s);
 int ssl23_connect(SSL *s);
 int ssl23_read_bytes(SSL *s, int n);
@@ -620,6 +649,23 @@
 long tls1_callback_ctrl(SSL *s,int cmd, void (*fp)(void));
 SSL_METHOD *tlsv1_base_method(void );
 
+/* -- start DTLS functions -- */
+int dtls1_new(SSL *s);
+int	dtls1_accept(SSL *s);
+int	dtls1_connect(SSL *s);
+void dtls1_free(SSL *s);
+void dtls1_clear(SSL *s);
+long dtls1_ctrl(SSL *s,int cmd, long larg, void *parg);
+SSL_METHOD *dtlsv1_base_method(void );
+
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+int dtls1_get_record(SSL *s);
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+	unsigned int len, int create_empty_fragement);
+int dtls1_dispatch_alert(SSL *s);
+int dtls1_enc(SSL *s, int snd);
+/* -- end DTLS functions -- */
+
 int ssl_init_wbio_buffer(SSL *s, int push);
 void ssl_free_wbio_buffer(SSL *s);
 
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index cf49fde..6ca8083 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -204,6 +204,11 @@
 			ss->ssl_version=TLS1_VERSION;
 			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
 			}
+		else if (s->version == DTLS1_VERSION)
+			{
+			ss->ssl_version=DTLS1_VERSION;
+			ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+			}
 		else
 			{
 			SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index bfcd7d9..cfcfeda 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -284,7 +284,9 @@
 			if (s->s3->rrec.comp == NULL)
 				goto err;
 			}
-		memset(&(s->s3->read_sequence[0]),0,8);
+		/* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ 		if (s->version != DTLS1_VERSION)
+			memset(&(s->s3->read_sequence[0]),0,8);
 		mac_secret= &(s->s3->read_mac_secret[0]);
 		}
 	else
@@ -313,7 +315,9 @@
 				goto err2;
 				}
 			}
-		memset(&(s->s3->write_sequence[0]),0,8);
+		/* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ 		if (s->version != DTLS1_VERSION)
+			memset(&(s->s3->write_sequence[0]),0,8);
 		mac_secret= &(s->s3->write_mac_secret[0]);
 		}
 
@@ -742,10 +746,13 @@
 {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
 #endif
 
-	for (i=7; i>=0; i--)
-		{
-		++seq[i];
-		if (seq[i] != 0) break; 
+    if ( SSL_version(ssl) != DTLS1_VERSION)
+	    {
+		for (i=7; i>=0; i--)
+			{
+			++seq[i];
+			if (seq[i] != 0) break; 
+			}
 		}
 
 #ifdef TLS_DEBUG
@@ -808,6 +815,8 @@
 	case SSL_AD_INTERNAL_ERROR:	return(TLS1_AD_INTERNAL_ERROR);
 	case SSL_AD_USER_CANCELLED:	return(TLS1_AD_USER_CANCELLED);
 	case SSL_AD_NO_RENEGOTIATION:	return(TLS1_AD_NO_RENEGOTIATION);
+	case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return 
+					  (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
 	default:			return(-1);
 		}
 	}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 447fc0d..6f95fc1 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -91,6 +91,10 @@
 	ssl3_shutdown,
 	ssl3_renegotiate,
 	ssl3_renegotiate_check,
+	ssl3_get_message,
+	ssl3_read_bytes,
+	ssl3_write_bytes,
+	ssl3_dispatch_alert,
 	ssl3_ctrl,
 	ssl3_ctx_ctrl,
 	ssl3_get_cipher_by_char,