openssl.pc
-Makefile.ssl
MINFO
makefile.one
tmp
libssl.so.*
*.flc
semantic.cache
+Makefile
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]
"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:::",
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.
#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
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);
#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... */
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");
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
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)
#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;
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)
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);
}
#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)
{
#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... */
#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)
{
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");
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
#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)
{
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);
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:
OPENSSL_free(dpass);
if (bio_s_out != NULL)
{
- BIO_free(bio_s_out);
+ BIO_free(bio_s_out);
bio_s_out=NULL;
}
apps_shutdown();
}
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;
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;
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]);
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;
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;
((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)
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);
}
}
-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;
#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
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;
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)
--- /dev/null
+/* 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 */
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
Makefile.save
*.flc
semantic.cache
+ax86-elf.s
Makefile.save
*.flc
semantic.cache
+bx86-elf.s
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)
#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
#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
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)()); */
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),
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);
--- /dev/null
+/* 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
Makefile.save
*.flc
semantic.cache
+co86-elf.s
+bn86-elf.s
Makefile.save
*.flc
semantic.cache
+cx86-elf.s
des
*.flc
semantic.cache
+yx86-elf.s
+dx86-elf.s
Makefile.save
*.flc
semantic.cache
+mx86-elf.s
--- /dev/null
+#
+# 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.
+
+
--- /dev/null
+/* 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;
+ }
--- /dev/null
+/* 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;
+ }
--- /dev/null
+/* 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 */
Makefile.save
*.flc
semantic.cache
+rx86-elf.s
Makefile.save
*.flc
semantic.cache
+rm86-elf.s
Makefile.save
*.flc
semantic.cache
+sx86-elf.s
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 \
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 \
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)
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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));
+ }
+
+
--- /dev/null
+/* 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);
+ }
+
--- /dev/null
+/* 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;
+ }
--- /dev/null
+/* 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);
+ }
--- /dev/null
+/* 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));
+ }
--- /dev/null
+/* ssl/d1_srvr.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include "ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/md5.h>
+
+static SSL_METHOD *dtls1_get_server_method(int ver);
+static int dtls1_send_hello_verify_request(SSL *s);
+
+static SSL_METHOD *dtls1_get_server_method(int ver)
+ {
+ if (ver == DTLS1_VERSION)
+ return(DTLSv1_server_method());
+ else
+ return(NULL);
+ }
+
+SSL_METHOD *DTLSv1_server_method(void)
+ {
+ static int init=1;
+ static SSL_METHOD DTLSv1_server_data;
+
+ if (init)
+ {
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
+
+ if (init)
+ {
+ memcpy((char *)&DTLSv1_server_data,(char *)dtlsv1_base_method(),
+ sizeof(SSL_METHOD));
+ DTLSv1_server_data.ssl_accept=dtls1_accept;
+ DTLSv1_server_data.get_ssl_method=dtls1_get_server_method;
+ init=0;
+ }
+
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
+ }
+ return(&DTLSv1_server_data);
+ }
+
+int dtls1_accept(SSL *s)
+ {
+ BUF_MEM *buf;
+ unsigned long l,Time=time(NULL);
+ void (*cb)(const SSL *ssl,int type,int val)=NULL;
+ long num1;
+ int ret= -1;
+ int new_state,state,skip=0;
+
+ RAND_add(&Time,sizeof(Time),0);
+ ERR_clear_error();
+ clear_sys_error();
+
+ if (s->info_callback != NULL)
+ cb=s->info_callback;
+ else if (s->ctx->info_callback != NULL)
+ cb=s->ctx->info_callback;
+
+ /* init things to blank */
+ s->in_handshake++;
+ if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+
+ if (s->cert == NULL)
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_NO_CERTIFICATE_SET);
+ return(-1);
+ }
+
+ for (;;)
+ {
+ state=s->state;
+
+ switch (s->state)
+ {
+ case SSL_ST_RENEGOTIATE:
+ s->new_session=1;
+ /* s->state=SSL_ST_ACCEPT; */
+
+ case SSL_ST_BEFORE:
+ case SSL_ST_ACCEPT:
+ case SSL_ST_BEFORE|SSL_ST_ACCEPT:
+ case SSL_ST_OK|SSL_ST_ACCEPT:
+
+ s->server=1;
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
+
+ if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00))
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->type=SSL_ST_ACCEPT;
+
+ if (s->init_buf == NULL)
+ {
+ if ((buf=BUF_MEM_new()) == NULL)
+ {
+ ret= -1;
+ goto end;
+ }
+ if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
+ {
+ ret= -1;
+ goto end;
+ }
+ s->init_buf=buf;
+ }
+
+ if (!ssl3_setup_buffers(s))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ s->init_num=0;
+
+ if (s->state != SSL_ST_RENEGOTIATE)
+ {
+ /* Ok, we now need to push on a buffering BIO so that
+ * the output is sent in a way that TCP likes :-)
+ */
+ if (!ssl_init_wbio_buffer(s,1)) { ret= -1; goto end; }
+
+ ssl3_init_finished_mac(s);
+ s->state=SSL3_ST_SR_CLNT_HELLO_A;
+ s->ctx->stats.sess_accept++;
+ }
+ else
+ {
+ /* s->state == SSL_ST_RENEGOTIATE,
+ * we will just send a HelloRequest */
+ s->ctx->stats.sess_accept_renegotiate++;
+ s->state=SSL3_ST_SW_HELLO_REQ_A;
+ }
+
+ if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
+ s->d1->send_cookie = 1;
+ else
+ s->d1->send_cookie = 0;
+
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_A:
+ case SSL3_ST_SW_HELLO_REQ_B:
+
+ s->shutdown=0;
+ ret=dtls1_send_hello_request(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+
+ ssl3_init_finished_mac(s);
+ break;
+
+ case SSL3_ST_SW_HELLO_REQ_C:
+ s->state=SSL_ST_OK;
+ break;
+
+ case SSL3_ST_SR_CLNT_HELLO_A:
+ case SSL3_ST_SR_CLNT_HELLO_B:
+ case SSL3_ST_SR_CLNT_HELLO_C:
+
+ s->shutdown=0;
+ ret=ssl3_get_client_hello(s);
+ if (ret <= 0) goto end;
+ s->new_session = 2;
+
+ if ( s->d1->send_cookie)
+ s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
+ else
+ s->state = SSL3_ST_SW_SRVR_HELLO_A;
+
+ s->init_num=0;
+ break;
+
+ case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
+ case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
+
+ ret = dtls1_send_hello_verify_request(s);
+ if ( ret <= 0) goto end;
+ s->d1->send_cookie = 0;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
+ break;
+
+ case SSL3_ST_SW_SRVR_HELLO_A:
+ case SSL3_ST_SW_SRVR_HELLO_B:
+ ret=dtls1_send_server_hello(s);
+ if (ret <= 0) goto end;
+
+ if (s->hit)
+ s->state=SSL3_ST_SW_CHANGE_A;
+ else
+ s->state=SSL3_ST_SW_CERT_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_A:
+ case SSL3_ST_SW_CERT_B:
+ /* Check if it is anon DH */
+ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+ {
+ ret=dtls1_send_server_certificate(s);
+ if (ret <= 0) goto end;
+ }
+ else
+ skip=1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_KEY_EXCH_A:
+ case SSL3_ST_SW_KEY_EXCH_B:
+ l=s->s3->tmp.new_cipher->algorithms;
+
+ /* clear this, it may get reset by
+ * send_server_key_exchange */
+ if ((s->options & SSL_OP_EPHEMERAL_RSA)
+#ifndef OPENSSL_NO_KRB5
+ && !(l & SSL_KRB5)
+#endif /* OPENSSL_NO_KRB5 */
+ )
+ /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
+ * even when forbidden by protocol specs
+ * (handshake may fail as clients are not required to
+ * be able to handle this) */
+ s->s3->tmp.use_rsa_tmp=1;
+ else
+ s->s3->tmp.use_rsa_tmp=0;
+
+ /* only send if a DH key exchange, fortezza or
+ * RSA but we have a sign only certificate */
+ if (s->s3->tmp.use_rsa_tmp
+ || (l & (SSL_DH|SSL_kFZA))
+ || ((l & SSL_kRSA)
+ && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+ || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+ && EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+ )
+ )
+ )
+ )
+ {
+ ret=dtls1_send_server_key_exchange(s);
+ if (ret <= 0) goto end;
+ }
+ else
+ skip=1;
+
+ s->state=SSL3_ST_SW_CERT_REQ_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_REQ_A:
+ case SSL3_ST_SW_CERT_REQ_B:
+ if (/* don't request cert unless asked for it: */
+ !(s->verify_mode & SSL_VERIFY_PEER) ||
+ /* if SSL_VERIFY_CLIENT_ONCE is set,
+ * don't request cert during re-negotiation: */
+ ((s->session->peer != NULL) &&
+ (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
+ /* never request cert in anonymous ciphersuites
+ * (see section "Certificate request" in SSL 3 drafts
+ * and in RFC 2246): */
+ ((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&
+ /* ... except when the application insists on verification
+ * (against the specs, but s3_clnt.c accepts this for SSL 3) */
+ !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) ||
+ /* never request cert in Kerberos ciphersuites */
+ (s->s3->tmp.new_cipher->algorithms & SSL_aKRB5))
+ {
+ /* no cert request */
+ skip=1;
+ s->s3->tmp.cert_request=0;
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+ }
+ else
+ {
+ s->s3->tmp.cert_request=1;
+ ret=dtls1_send_certificate_request(s);
+ if (ret <= 0) goto end;
+#ifndef NETSCAPE_HANG_BUG
+ s->state=SSL3_ST_SW_SRVR_DONE_A;
+#else
+ s->state=SSL3_ST_SW_FLUSH;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+#endif
+ s->init_num=0;
+ }
+ break;
+
+ case SSL3_ST_SW_SRVR_DONE_A:
+ case SSL3_ST_SW_SRVR_DONE_B:
+ ret=dtls1_send_server_done(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_FLUSH:
+ /* number of bytes to be flushed */
+ num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
+ if (num1 > 0)
+ {
+ s->rwstate=SSL_WRITING;
+ num1=BIO_flush(s->wbio);
+ if (num1 <= 0) { ret= -1; goto end; }
+ s->rwstate=SSL_NOTHING;
+ }
+
+ s->state=s->s3->tmp.next_state;
+ break;
+
+ case SSL3_ST_SR_CERT_A:
+ case SSL3_ST_SR_CERT_B:
+ /* Check for second client hello (MS SGC) */
+ ret = ssl3_check_client_hello(s);
+ if (ret <= 0)
+ goto end;
+ if (ret == 2)
+ s->state = SSL3_ST_SR_CLNT_HELLO_C;
+ else {
+ /* could be sent for a DH cert, even if we
+ * have not asked for it :-) */
+ ret=ssl3_get_client_certificate(s);
+ if (ret <= 0) goto end;
+ s->init_num=0;
+ s->state=SSL3_ST_SR_KEY_EXCH_A;
+ }
+ break;
+
+ case SSL3_ST_SR_KEY_EXCH_A:
+ case SSL3_ST_SR_KEY_EXCH_B:
+ ret=ssl3_get_client_key_exchange(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+
+ /* We need to get hashes here so if there is
+ * a client cert, it can be verified */
+ s->method->ssl3_enc->cert_verify_mac(s,
+ &(s->s3->finish_dgst1),
+ &(s->s3->tmp.cert_verify_md[0]));
+ s->method->ssl3_enc->cert_verify_mac(s,
+ &(s->s3->finish_dgst2),
+ &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
+
+ break;
+
+ case SSL3_ST_SR_CERT_VRFY_A:
+ case SSL3_ST_SR_CERT_VRFY_B:
+
+ /* we should decide if we expected this one */
+ ret=ssl3_get_cert_verify(s);
+ if (ret <= 0) goto end;
+
+ s->state=SSL3_ST_SR_FINISHED_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SR_FINISHED_A:
+ case SSL3_ST_SR_FINISHED_B:
+ ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
+ SSL3_ST_SR_FINISHED_B);
+ if (ret <= 0) goto end;
+ if (s->hit)
+ s->state=SSL_ST_OK;
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CHANGE_A:
+ case SSL3_ST_SW_CHANGE_B:
+
+ s->session->cipher=s->s3->tmp.new_cipher;
+ if (!s->method->ssl3_enc->setup_key_block(s))
+ { ret= -1; goto end; }
+
+ ret=dtls1_send_change_cipher_spec(s,
+ SSL3_ST_SW_CHANGE_A,SSL3_ST_SW_CHANGE_B);
+
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FINISHED_A;
+ s->init_num=0;
+
+ if (!s->method->ssl3_enc->change_cipher_state(s,
+ SSL3_CHANGE_CIPHER_SERVER_WRITE))
+ {
+ ret= -1;
+ goto end;
+ }
+
+ dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+ break;
+
+ case SSL3_ST_SW_FINISHED_A:
+ case SSL3_ST_SW_FINISHED_B:
+ ret=dtls1_send_finished(s,
+ SSL3_ST_SW_FINISHED_A,SSL3_ST_SW_FINISHED_B,
+ s->method->ssl3_enc->server_finished_label,
+ s->method->ssl3_enc->server_finished_label_len);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_FLUSH;
+ if (s->hit)
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+ else
+ s->s3->tmp.next_state=SSL_ST_OK;
+ s->init_num=0;
+ break;
+
+ case SSL_ST_OK:
+ /* clean a few things up */
+ ssl3_cleanup_key_block(s);
+
+#if 0
+ BUF_MEM_free(s->init_buf);
+ s->init_buf=NULL;
+#endif
+
+ /* remove buffering on output */
+ ssl_free_wbio_buffer(s);
+
+ s->init_num=0;
+
+ if (s->new_session == 2) /* skipped if we just sent a HelloRequest */
+ {
+ /* actually not necessarily a 'new' session unless
+ * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+
+ s->new_session=0;
+
+ ssl_update_cache(s,SSL_SESS_CACHE_SERVER);
+
+ s->ctx->stats.sess_accept_good++;
+ /* s->server=1; */
+ s->handshake_func=dtls1_accept;
+
+ if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_DONE,1);
+ }
+
+ ret = 1;
+
+ /* done handshaking, next message is client hello */
+ s->d1->handshake_read_seq = 0;
+ /* next message is server hello */
+ s->d1->handshake_write_seq = 0;
+ goto end;
+ /* break; */
+
+ default:
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_UNKNOWN_STATE);
+ ret= -1;
+ goto end;
+ /* break; */
+ }
+
+ if (!s->s3->tmp.reuse_message && !skip)
+ {
+ if (s->debug)
+ {
+ if ((ret=BIO_flush(s->wbio)) <= 0)
+ goto end;
+ }
+
+
+ if ((cb != NULL) && (s->state != state))
+ {
+ new_state=s->state;
+ s->state=state;
+ cb(s,SSL_CB_ACCEPT_LOOP,1);
+ s->state=new_state;
+ }
+ }
+ skip=0;
+ }
+end:
+ /* BIO_flush(s->wbio); */
+
+ s->in_handshake--;
+ if (cb != NULL)
+ cb(s,SSL_CB_ACCEPT_EXIT,ret);
+ return(ret);
+ }
+
+int dtls1_send_hello_request(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_HELLO_REQ_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+ p = dtls1_set_message_header(s, p, SSL3_MT_HELLO_REQUEST, 0, 0, 0);
+
+ s->state=SSL3_ST_SW_HELLO_REQ_B;
+ /* number of bytes to write */
+ s->init_num=DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* no need to buffer this message, since there are no retransmit
+ * requests for it */
+ }
+
+ /* SSL3_ST_SW_HELLO_REQ_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_hello_verify_request(SSL *s)
+ {
+ unsigned int msg_len;
+ unsigned char *msg, *buf, *p;
+
+ if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A)
+ {
+ buf = (unsigned char *)s->init_buf->data;
+
+ msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
+ *(p++) = s->version >> 8;
+ *(p++) = s->version & 0xFF;
+
+ *(p++) = (unsigned char) s->d1->cookie_len;
+ if ( s->ctx->app_gen_cookie_cb != NULL &&
+ s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+ &(s->d1->cookie_len)) == 0)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ /* else the cookie is assumed to have
+ * been initialized by the application */
+
+ memcpy(p, s->d1->cookie, s->d1->cookie_len);
+ p += s->d1->cookie_len;
+ msg_len = p - msg;
+
+ dtls1_set_message_header(s, buf,
+ DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, msg_len);
+
+ s->state=DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_hello(SSL *s)
+ {
+ unsigned char *buf;
+ unsigned char *p,*d;
+ int i,sl;
+ unsigned long l,Time;
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ buf=(unsigned char *)s->init_buf->data;
+ p=s->s3->server_random;
+ Time=time(NULL); /* Time */
+ l2n(Time,p);
+ RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
+ /* Do the message type and length last */
+ d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
+
+ *(p++)=s->version>>8;
+ *(p++)=s->version&0xff;
+
+ /* Random stuff */
+ memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
+ p+=SSL3_RANDOM_SIZE;
+
+ /* now in theory we have 3 options to sending back the
+ * session id. If it is a re-use, we send back the
+ * old session-id, if it is a new session, we send
+ * back the new session-id or we send back a 0 length
+ * session-id if we want it to be single use.
+ * Currently I will not implement the '0' length session-id
+ * 12-Jan-98 - I'll now support the '0' length stuff.
+ */
+ if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER))
+ s->session->session_id_length=0;
+
+ sl=s->session->session_id_length;
+ if (sl > sizeof s->session->session_id)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ *(p++)=sl;
+ memcpy(p,s->session->session_id,sl);
+ p+=sl;
+
+ /* put the cipher */
+ i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
+ p+=i;
+
+ /* put the compression method */
+ if (s->s3->tmp.new_compression == NULL)
+ *(p++)=0;
+ else
+ *(p++)=s->s3->tmp.new_compression->id;
+
+ /* do the header */
+ l=(p-d);
+ d=buf;
+
+ d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l);
+
+ s->state=SSL3_ST_CW_CLNT_HELLO_B;
+ /* number of bytes to write */
+ s->init_num=p-buf;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_CW_CLNT_HELLO_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_done(SSL *s)
+ {
+ unsigned char *p;
+
+ if (s->state == SSL3_ST_SW_SRVR_DONE_A)
+ {
+ p=(unsigned char *)s->init_buf->data;
+
+ /* do the header */
+ p = dtls1_set_message_header(s, p, SSL3_MT_SERVER_DONE, 0, 0, 0);
+
+ s->state=SSL3_ST_SW_SRVR_DONE_B;
+ /* number of bytes to write */
+ s->init_num=DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_CW_CLNT_HELLO_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
+int dtls1_send_server_key_exchange(SSL *s)
+ {
+#ifndef OPENSSL_NO_RSA
+ unsigned char *q;
+ int j,num;
+ RSA *rsa;
+ unsigned char md_buf[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
+ unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+ DH *dh=NULL,*dhp;
+#endif
+ EVP_PKEY *pkey;
+ unsigned char *p,*d;
+ int al,i;
+ unsigned long type;
+ int n;
+ CERT *cert;
+ BIGNUM *r[4];
+ int nr[4],kn;
+ BUF_MEM *buf;
+ EVP_MD_CTX md_ctx;
+
+ EVP_MD_CTX_init(&md_ctx);
+ if (s->state == SSL3_ST_SW_KEY_EXCH_A)
+ {
+ type=s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK;
+ cert=s->cert;
+
+ buf=s->init_buf;
+
+ r[0]=r[1]=r[2]=r[3]=NULL;
+ n=0;
+#ifndef OPENSSL_NO_RSA
+ if (type & SSL_kRSA)
+ {
+ rsa=cert->rsa_tmp;
+ if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL))
+ {
+ rsa=s->cert->rsa_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if(rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ RSA_up_ref(rsa);
+ cert->rsa_tmp=rsa;
+ }
+ if (rsa == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_RSA_KEY);
+ goto f_err;
+ }
+ r[0]=rsa->n;
+ r[1]=rsa->e;
+ s->s3->tmp.use_rsa_tmp=1;
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_DH
+ if (type & SSL_kEDH)
+ {
+ dhp=cert->dh_tmp;
+ if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+ dhp=s->cert->dh_tmp_cb(s,
+ SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
+ SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher));
+ if (dhp == NULL)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
+ goto f_err;
+ }
+
+ if (s->s3->tmp.dh != NULL)
+ {
+ DH_free(dh);
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if ((dh=DHparams_dup(dhp)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+
+ s->s3->tmp.dh=dh;
+ if ((dhp->pub_key == NULL ||
+ dhp->priv_key == NULL ||
+ (s->options & SSL_OP_SINGLE_DH_USE)))
+ {
+ if(!DH_generate_key(dh))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,
+ ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ else
+ {
+ dh->pub_key=BN_dup(dhp->pub_key);
+ dh->priv_key=BN_dup(dhp->priv_key);
+ if ((dh->pub_key == NULL) ||
+ (dh->priv_key == NULL))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
+ goto err;
+ }
+ }
+ r[0]=dh->p;
+ r[1]=dh->g;
+ r[2]=dh->pub_key;
+ }
+ else
+#endif
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+ goto f_err;
+ }
+ for (i=0; r[i] != NULL; i++)
+ {
+ nr[i]=BN_num_bytes(r[i]);
+ n+=2+nr[i];
+ }
+
+ if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
+ {
+ if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher))
+ == NULL)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ kn=EVP_PKEY_size(pkey);
+ }
+ else
+ {
+ pkey=NULL;
+ kn=0;
+ }
+
+ if (!BUF_MEM_grow_clean(buf,n+DTLS1_HM_HEADER_LENGTH+kn))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
+ goto err;
+ }
+ d=(unsigned char *)s->init_buf->data;
+ p= &(d[DTLS1_HM_HEADER_LENGTH]);
+
+ for (i=0; r[i] != NULL; i++)
+ {
+ s2n(nr[i],p);
+ BN_bn2bin(r[i],p);
+ p+=nr[i];
+ }
+
+ /* not anonymous */
+ if (pkey != NULL)
+ {
+ /* n is the length of the params, they start at
+ * &(d[DTLS1_HM_HEADER_LENGTH]) and p points to the space
+ * at the end. */
+#ifndef OPENSSL_NO_RSA
+ if (pkey->type == EVP_PKEY_RSA)
+ {
+ q=md_buf;
+ j=0;
+ for (num=2; num > 0; num--)
+ {
+ EVP_DigestInit_ex(&md_ctx,(num == 2)
+ ?s->ctx->md5:s->ctx->sha1, NULL);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+ EVP_DigestFinal_ex(&md_ctx,q,
+ (unsigned int *)&i);
+ q+=i;
+ j+=i;
+ }
+ if (RSA_sign(NID_md5_sha1, md_buf, j,
+ &(p[2]), &u, pkey->pkey.rsa) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+ goto err;
+ }
+ s2n(u,p);
+ n+=u+2;
+ }
+ else
+#endif
+#if !defined(OPENSSL_NO_DSA)
+ if (pkey->type == EVP_PKEY_DSA)
+ {
+ /* lets do DSS */
+ EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL);
+ EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
+ if (!EVP_SignFinal(&md_ctx,&(p[2]),
+ (unsigned int *)&i,pkey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA);
+ goto err;
+ }
+ s2n(i,p);
+ n+=i+2;
+ }
+ else
+#endif
+ {
+ /* Is this error check actually needed? */
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
+ goto f_err;
+ }
+ }
+
+ d = dtls1_set_message_header(s, d,
+ SSL3_MT_SERVER_KEY_EXCHANGE, n, 0, n);
+
+ /* we should now have things packed up, so lets send
+ * it off */
+ s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ s->state = SSL3_ST_SW_KEY_EXCH_B;
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return(-1);
+ }
+
+int dtls1_send_certificate_request(SSL *s)
+ {
+ unsigned char *p,*d;
+ int i,j,nl,off,n;
+ STACK_OF(X509_NAME) *sk=NULL;
+ X509_NAME *name;
+ BUF_MEM *buf;
+
+ if (s->state == SSL3_ST_SW_CERT_REQ_A)
+ {
+ buf=s->init_buf;
+
+ d=p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]);
+
+ /* get the list of acceptable cert types */
+ p++;
+ n=ssl3_get_req_cert_type(s,p);
+ d[0]=n;
+ p+=n;
+ n++;
+
+ off=n;
+ p+=2;
+ n+=2;
+
+ sk=SSL_get_client_CA_list(s);
+ nl=0;
+ if (sk != NULL)
+ {
+ for (i=0; i<sk_X509_NAME_num(sk); i++)
+ {
+ name=sk_X509_NAME_value(sk,i);
+ j=i2d_X509_NAME(name,NULL);
+ if (!BUF_MEM_grow_clean(buf,DTLS1_HM_HEADER_LENGTH+n+j+2))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
+ goto err;
+ }
+ p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+n]);
+ if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
+ {
+ s2n(j,p);
+ i2d_X509_NAME(name,&p);
+ n+=2+j;
+ nl+=2+j;
+ }
+ else
+ {
+ d=p;
+ i2d_X509_NAME(name,&p);
+ j-=2; s2n(j,d); j+=2;
+ n+=j;
+ nl+=j;
+ }
+ }
+ }
+ /* else no CA names */
+ p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+off]);
+ s2n(nl,p);
+
+ d=(unsigned char *)buf->data;
+ *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
+ l2n3(n,d);
+ l2n(s->d1->handshake_write_seq,d);
+ s->d1->handshake_write_seq++;
+
+ /* we should now have things packed up, so lets send
+ * it off */
+
+ s->init_num=n+DTLS1_HM_HEADER_LENGTH;
+ s->init_off=0;
+#ifdef NETSCAPE_HANG_BUG
+/* XXX: what to do about this? */
+ p=(unsigned char *)s->init_buf->data + s->init_num;
+
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+ s->init_num += 4;
+#endif
+
+ /* XDTLS: set message header ? */
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+
+ s->state = SSL3_ST_SW_CERT_REQ_B;
+ }
+
+ /* SSL3_ST_SW_CERT_REQ_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+err:
+ return(-1);
+ }
+
+int dtls1_send_server_certificate(SSL *s)
+ {
+ unsigned long l;
+ X509 *x;
+
+ if (s->state == SSL3_ST_SW_CERT_A)
+ {
+ x=ssl_get_server_send_cert(s);
+ if (x == NULL &&
+ /* VRS: allow null cert if auth == KRB5 */
+ (s->s3->tmp.new_cipher->algorithms
+ & (SSL_MKEY_MASK|SSL_AUTH_MASK))
+ != (SSL_aKRB5|SSL_kKRB5))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
+ return(0);
+ }
+
+ l=dtls1_output_cert_chain(s,x);
+ s->state=SSL3_ST_SW_CERT_B;
+ s->init_num=(int)l;
+ s->init_off=0;
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_CERT_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
--- /dev/null
+/* ssl/dtls1.h */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DTLS1_H
+#define HEADER_DTLS1_H
+
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DTLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 1
+
+#define DTLS1_VERSION 0x0100
+#define DTLS1_VERSION_MAJOR 0x01
+#define DTLS1_VERSION_MINOR 0x00
+
+#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH 32
+
+#define DTLS1_RT_HEADER_LENGTH 13
+
+#define DTLS1_HM_HEADER_LENGTH 12
+
+#define DTLS1_HM_BAD_FRAGMENT -2
+#define DTLS1_HM_FRAGMENT_RETRY -3
+
+#define DTLS1_CCS_HEADER_LENGTH 3
+
+#define DTLS1_AL_HEADER_LENGTH 7
+
+
+typedef struct dtls1_bitmap_st
+ {
+ unsigned long long map;
+ unsigned long length; /* sizeof the bitmap in bits */
+ unsigned long long max_seq_num; /* max record number seen so far */
+ } DTLS1_BITMAP;
+
+struct hm_header_st
+ {
+ unsigned char type;
+ unsigned long msg_len;
+ unsigned short seq;
+ unsigned long frag_off;
+ unsigned long frag_len;
+ unsigned int is_ccs;
+ };
+
+struct ccs_header_st
+ {
+ unsigned char type;
+ unsigned short seq;
+ };
+
+struct dtls1_timeout_st
+ {
+ /* Number of read timeouts so far */
+ unsigned int read_timeouts;
+
+ /* Number of write timeouts so far */
+ unsigned int write_timeouts;
+
+ /* Number of alerts received so far */
+ unsigned int num_alerts;
+ };
+
+typedef struct record_pqueue_st
+ {
+ unsigned short epoch;
+ pqueue q;
+ } record_pqueue;
+
+typedef struct hm_fragment_st
+ {
+ struct hm_header_st msg_header;
+ unsigned char *fragment;
+ } hm_fragment;
+
+typedef struct dtls1_state_st
+ {
+ unsigned int send_cookie;
+ unsigned char cookie[DTLS1_COOKIE_LENGTH];
+ unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
+ unsigned int cookie_len;
+
+ /*
+ * The current data and handshake epoch. This is initially
+ * undefined, and starts at zero once the initial handshake is
+ * completed
+ */
+ unsigned short r_epoch;
+ unsigned short w_epoch;
+
+ /* records being received in the current epoch */
+ DTLS1_BITMAP bitmap;
+
+ /* renegotiation starts a new set of sequence numbers */
+ DTLS1_BITMAP next_bitmap;
+
+ /* handshake message numbers */
+ unsigned short handshake_write_seq;
+ unsigned short next_handshake_write_seq;
+
+ unsigned short handshake_read_seq;
+
+ /* only matters for handshake messages */
+ unsigned long long next_expected_seq_num;
+
+ /* Received handshake records (processed and unprocessed) */
+ record_pqueue unprocessed_rcds;
+ record_pqueue processed_rcds;
+
+ /* Buffered handshake messages */
+ pqueue buffered_messages;
+
+ /* Buffered (sent) handshake records */
+ pqueue sent_messages;
+
+ unsigned int mtu; /* max wire packet size */
+
+ struct hm_header_st w_msg_hdr;
+ struct hm_header_st r_msg_hdr;
+
+ struct dtls1_timeout_st timeout;
+
+ /* storage for Alert/Handshake protocol data received but not
+ * yet processed by ssl3_read_bytes: */
+ unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
+ unsigned int alert_fragment_len;
+ unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
+ unsigned int handshake_fragment_len;
+
+ unsigned int retransmitting;
+
+ } DTLS1_STATE;
+
+typedef struct dtls1_record_data_st
+ {
+ unsigned char *packet;
+ unsigned int packet_length;
+ SSL3_BUFFER rbuf;
+ SSL3_RECORD rrec;
+ } DTLS1_RECORD_DATA;
+
+/* client methods */
+int dtls1_client_hello(SSL *s);
+int dtls1_send_client_certificate(SSL *s);
+int dtls1_send_client_key_exchange(SSL *s);
+int dtls1_send_client_verify(SSL *s);
+
+
+/* server methods */
+int dtls1_send_hello_request(SSL *s);
+int dtls1_send_server_hello(SSL *s);
+int dtls1_send_server_certificate(SSL *s);
+int dtls1_send_server_key_exchange(SSL *s);
+int dtls1_send_certificate_request(SSL *s);
+int dtls1_send_server_done(SSL *s);
+
+/* common methods */
+int dtls1_send_change_cipher_spec(SSL *s, int a, int b);
+int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen);
+unsigned long dtls1_output_cert_chain(SSL *s, X509 *x);
+int dtls1_read_failed(SSL *s, int code);
+int dtls1_buffer_message(SSL *s, int ccs);
+int dtls1_retransmit_message(SSL *s, unsigned short seq,
+ unsigned long frag_off, int *found);
+void dtls1_clear_record_buffer(SSL *s);
+void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr);
+void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
+void dtls1_reset_seq_numbers(SSL *s, int rw);
+
+/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
+#define DTLS1_TMO_READ_COUNT 2
+#define DTLS1_TMO_WRITE_COUNT 2
+
+#define DTLS1_TMO_ALERT_COUNT 12
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
ssl_undefined_function,
ssl_undefined_function,
ssl_ok,
+ ssl3_get_message,
+ ssl3_read_bytes,
+ ssl3_write_bytes,
+ ssl3_dispatch_alert,
ssl3_ctrl,
ssl3_ctx_ctrl,
ssl23_get_cipher_by_char,
ssl2_shutdown,
ssl_ok, /* NULL - renegotiate */
ssl_ok, /* NULL - check renegotiate */
+ NULL, /* NULL - ssl_get_message */
+ NULL, /* NULL - ssl_get_record */
+ NULL, /* NULL - ssl_write_bytes */
+ NULL, /* NULL - dispatch_alert */
ssl2_ctrl, /* local */
ssl2_ctx_ctrl, /* local */
ssl2_get_cipher_by_char,
* change cipher spec message and is in s->s3->tmp.peer_finish_md
*/
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
a,
b,
SSL3_MT_FINISHED,
{
while (s->init_num < 4)
{
- i=ssl3_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
- 4 - s->init_num, 0);
+ i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
+ &p[s->init_num],4 - s->init_num, 0);
if (i <= 0)
{
s->rwstate=SSL_READING;
n = s->s3->tmp.message_size - s->init_num;
while (n > 0)
{
- i=ssl3_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],n,0);
+ i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],n,0);
if (i <= 0)
{
s->rwstate=SSL_READING;
#include <openssl/bn.h>
static SSL_METHOD *ssl3_get_client_method(int ver);
-static int ssl3_client_hello(SSL *s);
-static int ssl3_get_server_hello(SSL *s);
-static int ssl3_get_certificate_request(SSL *s);
static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
-static int ssl3_get_server_done(SSL *s);
-static int ssl3_send_client_verify(SSL *s);
-static int ssl3_send_client_certificate(SSL *s);
-static int ssl3_send_client_key_exchange(SSL *s);
-static int ssl3_get_key_exchange(SSL *s);
-static int ssl3_get_server_certificate(SSL *s);
-static int ssl3_check_cert_and_algorithm(SSL *s);
#ifndef OPENSSL_NO_ECDH
static int curve_id2nid(int curve_id);
}
-static int ssl3_client_hello(SSL *s)
+int ssl3_client_hello(SSL *s)
{
unsigned char *buf;
unsigned char *p,*d;
return(-1);
}
-static int ssl3_get_server_hello(SSL *s)
+int ssl3_get_server_hello(SSL *s)
{
STACK_OF(SSL_CIPHER) *sk;
SSL_CIPHER *c;
long n;
SSL_COMP *comp;
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_CR_SRVR_HELLO_A,
SSL3_ST_CR_SRVR_HELLO_B,
- SSL3_MT_SERVER_HELLO,
+ -1,
300, /* ?? */
&ok);
if (!ok) return((int)n);
+
+ if ( SSL_version(s) == DTLS1_VERSION)
+ {
+ if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
+ {
+ if ( s->d1->send_cookie == 0)
+ {
+ s->s3->tmp.reuse_message = 1;
+ return 1;
+ }
+ else /* already sent a cookie */
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,
+ SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+ }
+ }
+
+ if ( s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+
d=p=(unsigned char *)s->init_msg;
if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
return(-1);
}
-static int ssl3_get_server_certificate(SSL *s)
+int ssl3_get_server_certificate(SSL *s)
{
int al,i,ok,ret= -1;
unsigned long n,nc,llen,l;
EVP_PKEY *pkey=NULL;
int need_cert = 1; /* VRS: 0=> will allow null cert if auth == KRB5 */
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_CR_CERT_A,
SSL3_ST_CR_CERT_B,
-1,
return(ret);
}
-static int ssl3_get_key_exchange(SSL *s)
+int ssl3_get_key_exchange(SSL *s)
{
#ifndef OPENSSL_NO_RSA
unsigned char *q,md_buf[EVP_MAX_MD_SIZE*2];
/* use same message size as in ssl3_get_certificate_request()
* as ServerKeyExchange message may be skipped */
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_CR_KEY_EXCH_A,
SSL3_ST_CR_KEY_EXCH_B,
-1,
return(-1);
}
-static int ssl3_get_certificate_request(SSL *s)
+int ssl3_get_certificate_request(SSL *s)
{
int ok,ret=0;
unsigned long n,nc,l;
unsigned char *d;
STACK_OF(X509_NAME) *ca_sk=NULL;
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_CR_CERT_REQ_A,
SSL3_ST_CR_CERT_REQ_B,
-1,
return(X509_NAME_cmp(*a,*b));
}
-static int ssl3_get_server_done(SSL *s)
+int ssl3_get_server_done(SSL *s)
{
int ok,ret=0;
long n;
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_CR_SRVR_DONE_A,
SSL3_ST_CR_SRVR_DONE_B,
SSL3_MT_SERVER_DONE,
#endif
}
-static int ssl3_send_client_key_exchange(SSL *s)
+int ssl3_send_client_key_exchange(SSL *s)
{
unsigned char *p,*d;
int n;
return(-1);
}
-static int ssl3_send_client_verify(SSL *s)
+int ssl3_send_client_verify(SSL *s)
{
unsigned char *p,*d;
unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
return(-1);
}
-static int ssl3_send_client_certificate(SSL *s)
+int ssl3_send_client_certificate(SSL *s)
{
X509 *x509=NULL;
EVP_PKEY *pkey=NULL;
#define has_bits(i,m) (((i)&(m)) == (m))
-static int ssl3_check_cert_and_algorithm(SSL *s)
+int ssl3_check_cert_and_algorithm(SSL *s)
{
int i,idx;
long algs;
const EVP_MD *hash;
unsigned char *p,rec_char;
unsigned int md_size;
- int npad,i;
+ int npad;
if (send)
{
EVP_MD_CTX_cleanup(&md_ctx);
+ ssl3_record_sequence_update(seq);
+ return(md_size);
+ }
+
+void ssl3_record_sequence_update(unsigned char *seq)
+ {
+ int i;
+
for (i=7; i>=0; i--)
{
++seq[i];
if (seq[i] != 0) break;
}
-
- return(md_size);
}
int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
ssl3_shutdown,
ssl3_renegotiate,
ssl3_renegotiate_check,
+ ssl3_get_message,
+ ssl3_read_bytes,
+ ssl3_write_bytes,
+ ssl3_dispatch_alert,
ssl3_ctrl,
ssl3_ctx_ctrl,
ssl3_get_cipher_by_char,
{
/* resend it if not sent */
#if 1
- ssl3_dispatch_alert(s);
+ s->method->ssl_dispatch_alert(s);
#endif
}
else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
{
/* If we are waiting for a close from our peer, we are closed */
- ssl3_read_bytes(s,0,NULL,0,0);
+ s->method->ssl_read_bytes(s,0,NULL,0,0);
}
if ((s->shutdown == (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) &&
}
else
{
- ret=ssl3_write_bytes(s,SSL3_RT_APPLICATION_DATA,
- buf,len);
+ ret=s->method->ssl_write_bytes(s,SSL3_RT_APPLICATION_DATA,
+ buf,len);
if (ret <= 0) return(ret);
}
clear_sys_error();
if (s->s3->renegotiate) ssl3_renegotiate_check(s);
s->s3->in_read_app_data=1;
- ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+ ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
if ((ret == -1) && (s->s3->in_read_app_data == 2))
{
/* ssl3_read_bytes decided to call s->handshake_func, which
* and thinks that application data makes sense here; so disable
* handshake processing and try to read application data again. */
s->in_handshake++;
- ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+ ret=s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
s->in_handshake--;
}
else
static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
unsigned int len, int create_empty_fragment);
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
- unsigned int len);
static int ssl3_get_record(SSL *s);
-static int do_compress(SSL *ssl);
-static int do_uncompress(SSL *ssl);
-static int do_change_cipher_spec(SSL *ssl);
-/* used only by ssl3_get_record */
-static int ssl3_read_n(SSL *s, int n, int max, int extend)
+int ssl3_read_n(SSL *s, int n, int max, int extend)
{
/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
* packet by another n bytes.
/* ... now we can act as if 'extend' was set */
}
+ /* extend reads should not span multiple packets for DTLS */
+ if ( SSL_version(s) == DTLS1_VERSION &&
+ extend)
+ {
+ if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
+ n = s->s3->rbuf.left;
+ }
+
/* if there is enough in the buffer from a previous read, take some */
if (s->s3->rbuf.left >= (int)n)
{
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
goto f_err;
}
- if (!do_uncompress(s))
+ if (!ssl3_do_uncompress(s))
{
al=SSL_AD_DECOMPRESSION_FAILURE;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
return(ret);
}
-static int do_uncompress(SSL *ssl)
+int ssl3_do_uncompress(SSL *ssl)
{
int i;
SSL3_RECORD *rr;
return(1);
}
-static int do_compress(SSL *ssl)
+int ssl3_do_compress(SSL *ssl)
{
int i;
SSL3_RECORD *wr;
/* If we have an alert to send, lets send it */
if (s->s3->alert_dispatch)
{
- i=ssl3_dispatch_alert(s);
+ i=s->method->ssl_dispatch_alert(s);
if (i <= 0)
return(i);
/* if it went, fall through and send more stuff */
/* first we compress */
if (s->compress != NULL)
{
- if (!do_compress(s))
+ if (!ssl3_do_compress(s))
{
SSLerr(SSL_F_DO_SSL3_WRITE,SSL_R_COMPRESSION_FAILURE);
goto err;
}
/* if s->s3->wbuf.left != 0, we need to call this */
-static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
- unsigned int len)
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+ unsigned int len)
{
int i;
s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
s->s3->change_cipher_spec=1;
- if (!do_change_cipher_spec(s))
+ if (!ssl3_do_change_cipher_spec(s))
goto err;
else
goto start;
return(-1);
}
-static int do_change_cipher_spec(SSL *s)
+int ssl3_do_change_cipher_spec(SSL *s)
{
int i;
const char *sender;
s->s3->send_alert[0]=level;
s->s3->send_alert[1]=desc;
if (s->s3->wbuf.left == 0) /* data still being written out? */
- ssl3_dispatch_alert(s);
+ s->method->ssl_dispatch_alert(s);
/* else data is still being written out, we will get written
* some time in the future */
}
* [including the GNU Public Licence.]
*/
/* ====================================================================
- * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved.
+ * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include <openssl/md5.h>
static SSL_METHOD *ssl3_get_server_method(int ver);
-static int ssl3_get_client_hello(SSL *s);
-static int ssl3_check_client_hello(SSL *s);
-static int ssl3_send_server_hello(SSL *s);
-static int ssl3_send_server_key_exchange(SSL *s);
-static int ssl3_send_certificate_request(SSL *s);
-static int ssl3_send_server_done(SSL *s);
-static int ssl3_get_client_key_exchange(SSL *s);
-static int ssl3_get_client_certificate(SSL *s);
-static int ssl3_get_cert_verify(SSL *s);
-static int ssl3_send_hello_request(SSL *s);
#ifndef OPENSSL_NO_ECDH
static int nid2curve_id(int nid);
return(ret);
}
-static int ssl3_send_hello_request(SSL *s)
+int ssl3_send_hello_request(SSL *s)
{
unsigned char *p;
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
-static int ssl3_check_client_hello(SSL *s)
+int ssl3_check_client_hello(SSL *s)
{
int ok;
long n;
/* this function is called when we really expect a Certificate message,
* so permit appropriate message length */
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_A,
SSL3_ST_SR_CERT_B,
-1,
return 1;
}
-static int ssl3_get_client_hello(SSL *s)
+int ssl3_get_client_hello(SSL *s)
{
int i,j,ok,al,ret= -1;
+ int cookie_len;
long n;
unsigned long id;
unsigned char *p,*d,*q;
s->first_packet=1;
s->state=SSL3_ST_SR_CLNT_HELLO_B;
}
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_SR_CLNT_HELLO_B,
SSL3_ST_SR_CLNT_HELLO_C,
SSL3_MT_CLIENT_HELLO,
}
p+=j;
+
+ if (SSL_version(s) == DTLS1_VERSION)
+ {
+ /* cookie stuff */
+ cookie_len = *(p++);
+
+ if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+ s->d1->send_cookie == 0)
+ {
+ /* HelloVerifyMessage has already been sent */
+ if ( cookie_len != s->d1->cookie_len)
+ {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+ }
+
+ /*
+ * The ClientHello may contain a cookie even if the
+ * HelloVerify message has not been sent--make sure that it
+ * does not cause an overflow.
+ */
+ if ( cookie_len > sizeof(s->d1->rcvd_cookie))
+ {
+ /* too much data */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+
+ /* verify the cookie if appropriate option is set. */
+ if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+ cookie_len > 0)
+ {
+ memcpy(s->d1->rcvd_cookie, p, cookie_len);
+
+ if ( s->ctx->app_verify_cookie_cb != NULL)
+ {
+ if ( s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
+ cookie_len) == 0)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+ SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+ /* else cookie verification succeeded */
+ }
+ else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie,
+ s->d1->cookie_len) != 0) /* default verification */
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+ SSL_R_COOKIE_MISMATCH);
+ goto f_err;
+ }
+ }
+
+ p += cookie_len;
+ }
+
n2s(p,i);
if ((i == 0) && (j != 0))
{
return(ret);
}
-static int ssl3_send_server_hello(SSL *s)
+int ssl3_send_server_hello(SSL *s)
{
unsigned char *buf;
unsigned char *p,*d;
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
-static int ssl3_send_server_done(SSL *s)
+int ssl3_send_server_done(SSL *s)
{
unsigned char *p;
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
-static int ssl3_send_server_key_exchange(SSL *s)
+int ssl3_send_server_key_exchange(SSL *s)
{
#ifndef OPENSSL_NO_RSA
unsigned char *q;
return(-1);
}
-static int ssl3_send_certificate_request(SSL *s)
+int ssl3_send_certificate_request(SSL *s)
{
unsigned char *p,*d;
int i,j,nl,off,n;
#endif
}
-static int ssl3_get_client_key_exchange(SSL *s)
+int ssl3_get_client_key_exchange(SSL *s)
{
int i,al,ok;
long n;
BN_CTX *bn_ctx = NULL;
#endif
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_SR_KEY_EXCH_A,
SSL3_ST_SR_KEY_EXCH_B,
SSL3_MT_CLIENT_KEY_EXCHANGE,
return(-1);
}
-static int ssl3_get_cert_verify(SSL *s)
+int ssl3_get_cert_verify(SSL *s)
{
EVP_PKEY *pkey=NULL;
unsigned char *p;
int type=0,i,j;
X509 *peer;
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_VRFY_A,
SSL3_ST_SR_CERT_VRFY_B,
-1,
return(ret);
}
-static int ssl3_get_client_certificate(SSL *s)
+int ssl3_get_client_certificate(SSL *s)
{
int i,ok,al,ret= -1;
X509 *x=NULL;
unsigned char *d;
STACK_OF(X509) *sk=NULL;
- n=ssl3_get_message(s,
+ n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_A,
SSL3_ST_SR_CERT_B,
-1,
int (*ssl_shutdown)(SSL *s);
int (*ssl_renegotiate)(SSL *s);
int (*ssl_renegotiate_check)(SSL *s);
+ /* -- begin DTLS -- */
+ long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
+ max, int *ok);
+ int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len,
+ int peek);
+ int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
+ int (*ssl_dispatch_alert)(SSL *s);
+ /* -- end DTLS -- */
long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
* This used to be 0x000FFFFFL before 0.9.7. */
#define SSL_OP_ALL 0x00000FFFL
+/* DTLS options */
+#define SSL_OP_NO_QUERY_MTU 0x00001000L
+/* Turn on Cookie Exchange (on relevant for servers) */
+#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
+
/* As server, disallow session resumption on renegotiation */
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
/* If set, always create a new key when using tmp_ecdh parameters */
SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
#define SSL_get_mode(ssl) \
SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mtu(ssl, mtu) \
+ SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
/* get client cert callback */
int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+ /* cookie generate callback */
+ int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie,
+ unsigned int *cookie_len);
+
+ /* verify cookie callback */
+ int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie,
+ unsigned int cookie_len);
+
CRYPTO_EX_DATA ex_data;
const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
#define SSL_CTX_get_info_callback(ctx) ((ctx)->info_callback)
#define SSL_CTX_set_client_cert_cb(ctx,cb) ((ctx)->client_cert_cb=(cb))
#define SSL_CTX_get_client_cert_cb(ctx) ((ctx)->client_cert_cb)
+#define SSL_CTX_set_cookie_generate_cb(ctx,cb) ((ctx)->app_gen_cookie_cb=(cb))
+#define SSL_CTX_set_cookie_verify_cb(ctx,cb) ((ctx)->app_verify_cookie_cb=(cb))
#define SSL_NOTHING 1
#define SSL_WRITING 2
struct ssl_st
{
/* protocol version
- * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION)
+ * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
*/
int version;
int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
struct ssl2_state_st *s2; /* SSLv2 variables */
struct ssl3_state_st *s3; /* SSLv3 variables */
+ struct dtls1_state_st *d1; /* DTLSv1 variables */
int read_ahead; /* Read as many input bytes as possible
* (for non-blocking reads) */
#include <openssl/ssl2.h>
#include <openssl/ssl3.h>
#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
+#include <openssl/dtls1.h> /* Datagram TLS */
#include <openssl/ssl23.h>
#ifdef __cplusplus
#define SSL_CTRL_SET_MSG_CALLBACK 15
#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16
+/* only applies to datagram connections */
+#define SSL_CTRL_SET_MTU 17
/* Stats */
#define SSL_CTRL_SESS_NUMBER 20
#define SSL_CTRL_SESS_CONNECT 21
SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */
+SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */
+SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */
+SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */
+
STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
int SSL_do_handshake(SSL *s);
#define SSL_F_TLS1_SETUP_KEY_BLOCK 211
#define SSL_F_WRITE_PENDING 212
+#define SSL_F_DTLS1_READ_FAILED 1001
+#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 1002
+
/* Reason codes. */
#define SSL_R_APP_DATA_IN_HANDSHAKE 100
#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
#define SSL_R_X509_LIB 268
#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269
+#define SSL_R_READ_TIMEOUT_EXPIRED 2001
+#define SSL_R_COOKIE_MISMATCH 2002
+
#ifdef __cplusplus
}
#endif
/*rw*/ unsigned char *data; /* pointer to the record data */
/*rw*/ unsigned char *input; /* where the decode bytes are */
/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
+/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
+/*r */ unsigned long long seq_num; /* sequence number, needed by DTLS1 */
} SSL3_RECORD;
typedef struct ssl3_buffer_st
} SSL3_STATE;
+
+/* client methods */
+int ssl3_client_hello(SSL *s);
+int ssl3_get_server_hello(SSL *s);
+int ssl3_get_certificate_request(SSL *s);
+int ssl3_get_server_done(SSL *s);
+int ssl3_send_client_verify(SSL *s);
+int ssl3_send_client_certificate(SSL *s);
+int ssl3_send_client_key_exchange(SSL *s);
+int ssl3_get_key_exchange(SSL *s);
+int ssl3_get_server_certificate(SSL *s);
+int ssl3_check_cert_and_algorithm(SSL *s);
+
+/* server methods */
+int ssl3_get_client_hello(SSL *s);
+int ssl3_send_server_hello(SSL *s);
+int ssl3_send_hello_request(SSL *s);
+int ssl3_send_server_key_exchange(SSL *s);
+int ssl3_send_certificate_request(SSL *s);
+int ssl3_send_server_done(SSL *s);
+int ssl3_check_client_hello(SSL *s);
+int ssl3_get_client_certificate(SSL *s);
+int ssl3_get_client_key_exchange(SSL *s);
+int ssl3_get_cert_verify(SSL *s);
+
+/* utility functions */
+void ssl3_record_sequence_update(unsigned char *seq);
+int ssl3_do_change_cipher_spec(SSL *ssl);
+
/* SSLv3 */
/*client */
/* extra state */
/* read from server */
#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT)
#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT)
#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT)
#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT)
#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT)
#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT)
/* write to client */
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT)
#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT)
#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT)
#define SSL3_MT_CERTIFICATE_VERIFY 15
#define SSL3_MT_CLIENT_KEY_EXCHANGE 16
#define SSL3_MT_FINISHED 20
+#define DTLS1_MT_HELLO_VERIFY_REQUEST 3
+
#define SSL3_MT_CCS 1
{ERR_REASON(SSL_R_WRONG_VERSION_NUMBER) ,"wrong version number"},
{ERR_REASON(SSL_R_X509_LIB) ,"x509 lib"},
{ERR_REASON(SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),"x509 verification setup problems"},
+{ERR_REASON(SSL_R_READ_TIMEOUT_EXPIRED) ,"read timeout expired"},
+{ERR_REASON(SSL_R_COOKIE_MISMATCH) ,"cookie mismatch"},
{0,NULL}
};
l=s->max_cert_list;
s->max_cert_list=larg;
return(l);
+ case SSL_CTRL_SET_MTU:
+ if (SSL_version(s) == DTLS1_VERSION)
+ {
+ s->d1->mtu = larg;
+ return larg;
+ }
+ return 0;
default:
return(s->method->ssl_ctrl(s,cmd,larg,parg));
}
ret->default_passwd_callback=0;
ret->default_passwd_callback_userdata=NULL;
ret->client_cert_cb=0;
+ ret->app_gen_cookie_cb=0;
+ ret->app_verify_cookie_cb=0;
ret->sessions=lh_new(LHASH_HASH_FN(SSL_SESSION_hash),
LHASH_COMP_FN(SSL_SESSION_cmp));
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff))
+#define l2n6(l,c) (*((c)++)=(unsigned char)(((l)>>40)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>32)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+#define n2l6(c,l) (l =((unsigned long long)(*((c)++)))<<40, \
+ l|=((unsigned long long)(*((c)++)))<<32, \
+ l|=((unsigned long long)(*((c)++)))<<24, \
+ l|=((unsigned long long)(*((c)++)))<<16, \
+ l|=((unsigned long long)(*((c)++)))<< 8, \
+ l|=((unsigned long long)(*((c)++))))
+
/* NOTE - c is not incremented as per l2c */
#define l2cn(l1,l2,c,n) { \
c+=n; \
long ssl3_ctx_callback_ctrl(SSL_CTX *s,int cmd, void (*fp)(void));
int ssl3_pending(const SSL *s);
+/* -- begin DTLS -- */
+int dtls1_do_write(SSL *s,int type);
+int ssl3_read_n(SSL *s, int n, int max, int extend);
+int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
+int ssl3_do_compress(SSL *ssl);
+int ssl3_do_uncompress(SSL *ssl);
+int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
+ unsigned int len);
+unsigned char *dtls1_set_message_header(SSL *s,
+ unsigned char *p, unsigned char mt, unsigned long len,
+ unsigned long frag_off, unsigned long frag_len);
+int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len);
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len);
+/* -- end DTLS -- */
+
int ssl23_accept(SSL *s);
int ssl23_connect(SSL *s);
int ssl23_read_bytes(SSL *s, int n);
long tls1_callback_ctrl(SSL *s,int cmd, void (*fp)(void));
SSL_METHOD *tlsv1_base_method(void );
+/* -- start DTLS functions -- */
+int dtls1_new(SSL *s);
+int dtls1_accept(SSL *s);
+int dtls1_connect(SSL *s);
+void dtls1_free(SSL *s);
+void dtls1_clear(SSL *s);
+long dtls1_ctrl(SSL *s,int cmd, long larg, void *parg);
+SSL_METHOD *dtlsv1_base_method(void );
+
+long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok);
+int dtls1_get_record(SSL *s);
+int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
+ unsigned int len, int create_empty_fragement);
+int dtls1_dispatch_alert(SSL *s);
+int dtls1_enc(SSL *s, int snd);
+/* -- end DTLS functions -- */
+
int ssl_init_wbio_buffer(SSL *s, int push);
void ssl_free_wbio_buffer(SSL *s);
ss->ssl_version=TLS1_VERSION;
ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
}
+ else if (s->version == DTLS1_VERSION)
+ {
+ ss->ssl_version=DTLS1_VERSION;
+ ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+ }
else
{
SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION);
if (s->s3->rrec.comp == NULL)
goto err;
}
- memset(&(s->s3->read_sequence[0]),0,8);
+ /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ if (s->version != DTLS1_VERSION)
+ memset(&(s->s3->read_sequence[0]),0,8);
mac_secret= &(s->s3->read_mac_secret[0]);
}
else
goto err2;
}
}
- memset(&(s->s3->write_sequence[0]),0,8);
+ /* this is done by dtls1_reset_seq_numbers for DTLS1_VERSION */
+ if (s->version != DTLS1_VERSION)
+ memset(&(s->s3->write_sequence[0]),0,8);
mac_secret= &(s->s3->write_mac_secret[0]);
}
{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
#endif
- for (i=7; i>=0; i--)
- {
- ++seq[i];
- if (seq[i] != 0) break;
+ if ( SSL_version(ssl) != DTLS1_VERSION)
+ {
+ for (i=7; i>=0; i--)
+ {
+ ++seq[i];
+ if (seq[i] != 0) break;
+ }
}
#ifdef TLS_DEBUG
case SSL_AD_INTERNAL_ERROR: return(TLS1_AD_INTERNAL_ERROR);
case SSL_AD_USER_CANCELLED: return(TLS1_AD_USER_CANCELLED);
case SSL_AD_NO_RENEGOTIATION: return(TLS1_AD_NO_RENEGOTIATION);
+ case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return
+ (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
default: return(-1);
}
}
ssl3_shutdown,
ssl3_renegotiate,
ssl3_renegotiate_check,
+ ssl3_get_message,
+ ssl3_read_bytes,
+ ssl3_write_bytes,
+ ssl3_dispatch_alert,
ssl3_ctrl,
ssl3_ctx_ctrl,
ssl3_get_cipher_by_char,