Add DTLS support.
authorBen Laurie <ben@openssl.org>
Tue, 26 Apr 2005 16:02:40 +0000 (16:02 +0000)
committerBen Laurie <ben@openssl.org>
Tue, 26 Apr 2005 16:02:40 +0000 (16:02 +0000)
51 files changed:
.cvsignore
CHANGES
Configure
Makefile.org
apps/s_apps.h
apps/s_client.c
apps/s_server.c
apps/s_socket.c
apps/timeouts.h [new file with mode: 0644]
crypto/Makefile
crypto/aes/.cvsignore
crypto/bf/.cvsignore
crypto/bio/Makefile
crypto/bio/bio.h
crypto/bio/bss_dgram.c [new file with mode: 0644]
crypto/bn/.cvsignore
crypto/cast/.cvsignore
crypto/des/.cvsignore
crypto/md5/.cvsignore
crypto/pqueue/Makefile [new file with mode: 0644]
crypto/pqueue/pq_test.c [new file with mode: 0644]
crypto/pqueue/pqueue.c [new file with mode: 0644]
crypto/pqueue/pqueue.h [new file with mode: 0644]
crypto/rc4/.cvsignore
crypto/ripemd/.cvsignore
crypto/sha/.cvsignore
ssl/Makefile
ssl/d1_both.c [new file with mode: 0644]
ssl/d1_clnt.c [new file with mode: 0644]
ssl/d1_enc.c [new file with mode: 0644]
ssl/d1_lib.c [new file with mode: 0644]
ssl/d1_meth.c [new file with mode: 0644]
ssl/d1_pkt.c [new file with mode: 0644]
ssl/d1_srvr.c [new file with mode: 0644]
ssl/dtls1.h [new file with mode: 0644]
ssl/s23_lib.c
ssl/s2_lib.c
ssl/s3_both.c
ssl/s3_clnt.c
ssl/s3_enc.c
ssl/s3_lib.c
ssl/s3_pkt.c
ssl/s3_srvr.c
ssl/ssl.h
ssl/ssl3.h
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/ssl_sess.c
ssl/t1_enc.c
ssl/t1_lib.c

index 5f6ae0c..a7a20fc 100644 (file)
@@ -1,5 +1,4 @@
 openssl.pc
-Makefile.ssl
 MINFO
 makefile.one
 tmp
@@ -16,3 +15,4 @@ libcrypto.so.*
 libssl.so.*
 *.flc
 semantic.cache
+Makefile
diff --git a/CHANGES b/CHANGES
index 25b0b6b..f75ddd9 100644 (file)
--- 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]
index 442e19a..316d309 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -515,6 +515,7 @@ my %table=(
 "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:::",
index b6fbc99..528ca3b 100644 (file)
@@ -111,7 +111,7 @@ SDIRS=  \
        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.
index ca5caac..bb48244 100644 (file)
@@ -148,7 +148,7 @@ typedef fd_mask fd_set;
 #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 MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx);
 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);
index d5c0a4f..2f0f568 100644 (file)
@@ -135,6 +135,7 @@ typedef unsigned int u_int;
 #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 @@ static void sc_usage(void)
        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 MAIN(int argc, char **argv)
        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 @@ int MAIN(int argc, char **argv)
        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)
@@ -386,6 +395,20 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_TLS1
                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;
@@ -550,6 +573,10 @@ bad:
                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 @@ bad:
 
 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 @@ re_start:
                }
 #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)
                {
index 40d00cc..059c4a0 100644 (file)
@@ -154,6 +154,7 @@ typedef unsigned int u_int;
 #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 @@ static char *engine_id=NULL;
 #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 @@ static void sv_usage(void)
        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 MAIN(int argc, char *argv[])
        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
@@ -740,6 +751,22 @@ int MAIN(int argc, char *argv[])
 #ifndef OPENSSL_NO_TLS1
                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)
                        {
@@ -892,6 +919,10 @@ bad:
        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 @@ bad:
 
        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 @@ end:
                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 @@ static int sv_body(char *hostname, int s, unsigned char *context)
        }
        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 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                                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;
index cf43301..b5dd47d 100644 (file)
@@ -92,9 +92,9 @@ static struct hostent *GetHostByName(char *name);
 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 @@ static int ssl_sock_init(void)
        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 @@ int init_client(int *sock, char *host, int port)
                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 @@ static int init_client_ip(int *sock, unsigned char ip[4], int port)
                ((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 @@ static int init_client_ip(int *sock, unsigned char ip[4], int port)
        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 @@ int do_server(int port, int *ret, int (*cb)(char *hostname, int s, unsigned char
                }
        }
 
-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 @@ static int init_server_long(int *sock, int port, char *ip)
 #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 @@ static int init_server_long(int *sock, int port, char *ip)
                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 @@ err:
        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 (file)
index 0000000..89b5dc7
--- /dev/null
@@ -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 */
index c7ce69d..be7c250 100644 (file)
@@ -33,7 +33,7 @@ SDIRS=        objects \
        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
 
index 439e6d3..3d6ae11 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+ax86-elf.s
index 439e6d3..403e8f3 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+bx86-elf.s
index 976c5cd..2e52255 100644 (file)
@@ -27,13 +27,15 @@ LIBSRC= bio_lib.c bio_cb.c bio_err.c \
        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)
index 7068b18..aaf4f66 100644 (file)
@@ -94,6 +94,7 @@ extern "C" {
 #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 @@ extern "C" {
 
 #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_write_guarantee(BIO *b);
 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_buffer(void);
 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 @@ void BIO_sock_cleanup(void);
 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 (file)
index 0000000..fa6d27a
--- /dev/null
@@ -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
index 439e6d3..57df22c 100644 (file)
@@ -2,3 +2,5 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+co86-elf.s
+bn86-elf.s
index 439e6d3..e79919b 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+cx86-elf.s
index e5c5e37..5dcc40f 100644 (file)
@@ -3,3 +3,5 @@ Makefile.save
 des
 *.flc
 semantic.cache
+yx86-elf.s
+dx86-elf.s
index 439e6d3..fe51220 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+mx86-elf.s
diff --git a/crypto/pqueue/Makefile b/crypto/pqueue/Makefile
new file mode 100644 (file)
index 0000000..e08a3e4
--- /dev/null
@@ -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 (file)
index 0000000..8d496df
--- /dev/null
@@ -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 (file)
index 0000000..4cd9987
--- /dev/null
@@ -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 (file)
index 0000000..2245950
--- /dev/null
@@ -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 */
index 439e6d3..6d7750c 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+rx86-elf.s
index 439e6d3..f7abe18 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+rm86-elf.s
index 439e6d3..b2199b1 100644 (file)
@@ -2,3 +2,4 @@ lib
 Makefile.save
 *.flc
 semantic.cache
+sx86-elf.s
index 20e5bcc..a7a8a94 100644 (file)
@@ -31,6 +31,8 @@ LIBSRC=       \
        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 @@ LIBOBJ= \
        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 @@ LIBOBJ= \
 
 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 (file)
index 0000000..6890881
--- /dev/null
@@ -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 (file)
index 0000000..c53eae1
--- /dev/null
@@ -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 (file)
index 0000000..7b36964
--- /dev/null
@@ -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 (file)
index 0000000..d774521
--- /dev/null
@@ -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 (file)
index 0000000..dc4c8ed
--- /dev/null
@@ -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 (file)
index 0000000..4b3aabc
--- /dev/null
@@ -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 (file)
index 0000000..81c1790
--- /dev/null
@@ -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);
+