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