diff options
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/Makefile | 6 | ||||
-rw-r--r-- | ssl/d1_both.c | 1248 | ||||
-rw-r--r-- | ssl/d1_clnt.c | 1153 | ||||
-rw-r--r-- | ssl/d1_enc.c | 278 | ||||
-rw-r--r-- | ssl/d1_lib.c | 208 | ||||
-rw-r--r-- | ssl/d1_meth.c | 96 | ||||
-rw-r--r-- | ssl/d1_pkt.c | 1707 | ||||
-rw-r--r-- | ssl/d1_srvr.c | 1140 | ||||
-rw-r--r-- | ssl/dtls1.h | 244 | ||||
-rw-r--r-- | ssl/s23_lib.c | 4 | ||||
-rw-r--r-- | ssl/s2_lib.c | 4 | ||||
-rw-r--r-- | ssl/s3_both.c | 8 | ||||
-rw-r--r-- | ssl/s3_clnt.c | 69 | ||||
-rw-r--r-- | ssl/s3_enc.c | 12 | ||||
-rw-r--r-- | ssl/s3_lib.c | 16 | ||||
-rw-r--r-- | ssl/s3_pkt.c | 36 | ||||
-rw-r--r-- | ssl/s3_srvr.c | 105 | ||||
-rw-r--r-- | ssl/ssl.h | 41 | ||||
-rw-r--r-- | ssl/ssl3.h | 37 | ||||
-rw-r--r-- | ssl/ssl_err.c | 2 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 9 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 46 | ||||
-rw-r--r-- | ssl/ssl_sess.c | 5 | ||||
-rw-r--r-- | ssl/t1_enc.c | 21 | ||||
-rw-r--r-- | ssl/t1_lib.c | 4 |
25 files changed, 6409 insertions, 90 deletions
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 <limits.h> +#include <string.h> +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + + +/* XDTLS: figure out the right values */ +static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28}; + +static unsigned int dtls1_min_mtu(void); +static unsigned int dtls1_guess_mtu(unsigned int curr_mtu); +static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, + unsigned long frag_len); +static unsigned char *dtls1_write_message_header(SSL *s, + unsigned char *p); +static void dtls1_set_message_header_int(SSL *s, unsigned char mt, + unsigned long len, unsigned short seq_num, unsigned long frag_off, + unsigned long frag_len); +static int dtls1_retransmit_buffered_messages(SSL *s); +static long dtls1_get_message_fragment(SSL *s, int st1, int stn, + long max, int *ok); +static void dtls1_process_handshake_fragment(SSL *s, int frag_len); + +static hm_fragment * +dtls1_hm_fragment_new(unsigned long frag_len) + { + hm_fragment *frag = NULL; + unsigned char *buf = NULL; + + frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); + if ( frag == NULL) + return NULL; + + buf = (unsigned char *)OPENSSL_malloc(frag_len + + DTLS1_HM_HEADER_LENGTH); + if ( buf == NULL) + { + OPENSSL_free(frag); + return NULL; + } + + frag->fragment = buf; + + return frag; + } + +static void +dtls1_hm_fragment_free(hm_fragment *frag) + { + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + } + +/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ +int dtls1_do_write(SSL *s, int type) + { + int ret; + int curr_mtu; + unsigned int len, frag_off; + + /* AHA! Figure out the MTU, and stick to the right size */ + if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) + { + s->d1->mtu = + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); + + /* I've seen the kernel return bogus numbers when it doesn't know + * (initial write), so just make sure we have a reasonable number */ + if ( s->d1->mtu < dtls1_min_mtu()) + { + s->d1->mtu = 0; + s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, + s->d1->mtu, NULL); + } + } +#if 0 + mtu = s->d1->mtu; + + fprintf(stderr, "using MTU = %d\n", mtu); + + mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); + + curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s)); + + if ( curr_mtu > 0) + mtu = curr_mtu; + else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0) + return ret; + + if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu) + { + ret = BIO_flush(SSL_get_wbio(s)); + if ( ret <= 0) + return ret; + mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); + } + + OPENSSL_assert(mtu > 0); /* should have something reasonable now */ + +#endif + + if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) + OPENSSL_assert(s->init_num == + s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); + + frag_off = 0; + while( s->init_num) + { + curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - + DTLS1_RT_HEADER_LENGTH; + + if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH) + { + /* grr.. we could get an error if MTU picked was wrong */ + ret = BIO_flush(SSL_get_wbio(s)); + if ( ret <= 0) + return ret; + curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH; + } + + if ( s->init_num > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + + + /* XDTLS: this function is too long. split out the CCS part */ + if ( type == SSL3_RT_HANDSHAKE) + { + if ( s->init_off != 0) + { + OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH); + s->init_off -= DTLS1_HM_HEADER_LENGTH; + s->init_num += DTLS1_HM_HEADER_LENGTH; + + /* write atleast DTLS1_HM_HEADER_LENGTH bytes */ + if ( len <= DTLS1_HM_HEADER_LENGTH) + len += DTLS1_HM_HEADER_LENGTH; + } + + dtls1_fix_message_header(s, frag_off, + len - DTLS1_HM_HEADER_LENGTH); + + dtls1_write_message_header(s, &s->init_buf->data[s->init_off]); + + OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH); + } + + ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off], + len); + if (ret < 0) + { + /* might need to update MTU here, but we don't know + * which previous packet caused the failure -- so can't + * really retransmit anything. continue as if everything + * is fine and wait for an alert to handle the + * retransmit + */ + if ( BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL)) + s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); + else + return(-1); + } + else + { + + /* bad if this assert fails, only part of the handshake + * message got sent. but why would this happen? */ + OPENSSL_assert(len == ret); + + if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting) + /* should not be done for 'Hello Request's, but in that case + * we'll ignore the result anyway */ + ssl3_finish_mac(s, + (unsigned char *)&s->init_buf->data[s->init_off + + DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH); + + if (ret == s->init_num) + { + if (s->msg_callback) + s->msg_callback(1, s->version, type, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + + s->init_off = 0; /* done writing this message */ + s->init_num = 0; + + return(1); + } + s->init_off+=ret; + s->init_num-=ret; + frag_off += (ret -= DTLS1_HM_HEADER_LENGTH); + } + } + return(0); + } + + +/* Obtain handshake message of message type 'mt' (any if mt == -1), + * maximum acceptable body length 'max'. + * Read an entire handshake message. Handshake messages arrive in + * fragments. + */ +long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, + int *ok) + { + int i, al; + + /* s3->tmp is used to store messages that are unexpected, caused + * by the absence of an optional handshake message */ + if (s->s3->tmp.reuse_message) + { + s->s3->tmp.reuse_message=0; + if ((mt >= 0) && (s->s3->tmp.message_type != mt)) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + *ok=1; + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->init_num = (int)s->s3->tmp.message_size; + return s->init_num; + } + + do + { + if ( s->d1->r_msg_hdr.frag_off == 0) + { + /* s->d1->r_message_header.msg_len = 0; */ + memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st)); + } + + i = dtls1_get_message_fragment(s, st1, stn, max, ok); + if ( i == DTLS1_HM_BAD_FRAGMENT || + i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */ + continue; + else if ( i <= 0 && !*ok) + return i; + + if (s->d1->r_msg_hdr.msg_len == s->init_num - DTLS1_HM_HEADER_LENGTH) + { + memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st)); + + s->d1->handshake_read_seq++; + /* we just read a handshake message from the other side: + * this means that we don't need to retransmit of the + * buffered messages. + * XDTLS: may be able clear out this + * buffer a little sooner (i.e if an out-of-order + * handshake message/record is received at the record + * layer. + * XDTLS: exception is that the server needs to + * know that change cipher spec and finished messages + * have been received by the client before clearing this + * buffer. this can simply be done by waiting for the + * first data segment, but is there a better way? */ + dtls1_clear_record_buffer(s); + + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + return s->init_num - DTLS1_HM_HEADER_LENGTH; + } + else + s->d1->r_msg_hdr.frag_off = i; + } while(1) ; + +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + *ok = 0; + return -1; + } + + +static int +dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied) + { + /* (0) check whether the desired fragment is available + * if so: + * (1) copy over the fragment to s->init_buf->data[] + * (2) update s->init_num + */ + pitem *item; + hm_fragment *frag; + unsigned long overlap; + unsigned char *p; + + item = pqueue_peek(s->d1->buffered_messages); + if ( item == NULL) + return 0; + + frag = (hm_fragment *)item->data; + + if ( s->d1->handshake_read_seq == frag->msg_header.seq && + frag->msg_header.frag_off <= s->init_num - DTLS1_HM_HEADER_LENGTH) + { + pqueue_pop(s->d1->buffered_messages); + overlap = s->init_num - DTLS1_HM_HEADER_LENGTH + - frag->msg_header.frag_off; + + p = frag->fragment; + + memcpy(&s->init_buf->data[s->init_num], + p + DTLS1_HM_HEADER_LENGTH + overlap, + frag->msg_header.frag_len - overlap); + + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + pitem_free(item); + + *copied = frag->msg_header.frag_len - overlap; + return *copied; + } + else + return 0; + } + + +static int +dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr) +{ + hm_fragment *frag = NULL; + pitem *item = NULL; + + frag = dtls1_hm_fragment_new(msg_hdr->frag_len); + if ( frag == NULL) + goto err; + + memcpy(frag->fragment, &(s->init_buf->data[s->init_num]), + msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH); + + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + + item = pitem_new(msg_hdr->seq, frag); + if ( item == NULL) + goto err; + + pqueue_insert(s->d1->buffered_messages, item); + return 1; + +err: + if ( frag != NULL) dtls1_hm_fragment_free(frag); + if ( item != NULL) OPENSSL_free(item); + return 0; +} + + +static void +dtls1_process_handshake_fragment(SSL *s, int frag_len) + { + unsigned char *p; + + p = s->init_buf->data; + + ssl3_finish_mac(s, &p[s->init_num - frag_len], frag_len); + } + + +static int +dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st *msg_hdr, int *ok) + { + int i; + unsigned char *p; + + /* make sure there's enough room to read this fragment */ + if ( (int)msg_hdr->frag_len && !BUF_MEM_grow_clean(s->init_buf, + (int)msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH + s->init_num)) + { + SSLerr(SSL_F_SSL3_GET_MESSAGE,ERR_R_BUF_LIB); + goto err; + } + + p = s->init_buf->data; + + /* read the body of the fragment (header has already been read */ + if ( msg_hdr->frag_len > 0) + { + i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, + &p[s->init_num], + msg_hdr->frag_len,0); + if (i <= 0) + { + *ok = 0; + return i; + } + } + + if ( msg_hdr->seq > s->d1->handshake_read_seq) + dtls1_buffer_handshake_fragment(s, msg_hdr); + else + OPENSSL_assert(msg_hdr->seq < s->d1->handshake_read_seq); + + return DTLS1_HM_FRAGMENT_RETRY; +err: + *ok = 0; + return -1; + } + + +static long +dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok) + { + unsigned char *p; + unsigned long l, frag_off, frag_len; + int i,al; + struct hm_header_st msg_hdr; + unsigned long overlap; + + /* see if we have the required fragment already */ + if (dtls1_retrieve_buffered_fragment(s, &l)) + { + /* compute MAC, remove fragment headers */ + dtls1_process_handshake_fragment(s, l); + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->state = stn; + return 1; + } + + /* get a handshake fragment from the record layer */ + p = (unsigned char *)s->init_buf->data; + + /* read handshake message header */ + i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num], + DTLS1_HM_HEADER_LENGTH, 0); + if (i <= 0) /* nbio, or an error */ + { + s->rwstate=SSL_READING; + *ok = 0; + return i; + } + + OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH); + + p += s->init_num; + /* parse the message fragment header */ + + dtls1_get_message_header(p, &msg_hdr); + + /* + * if this is a future (or stale) message it gets buffered + * (or dropped)--no further processing at this time + */ + if ( msg_hdr.seq != s->d1->handshake_read_seq) + return dtls1_process_out_of_seq_message(s, &msg_hdr, ok); + + l = msg_hdr.msg_len; + frag_off = msg_hdr.frag_off; + frag_len = msg_hdr.frag_len; + + /* sanity checking */ + if ( frag_off + frag_len > l) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + + if (!s->server && s->d1->r_msg_hdr.frag_off == 0 && + p[0] == SSL3_MT_HELLO_REQUEST) + { + /* The server may always send 'Hello Request' messages -- + * we are doing a handshake anyway now, so ignore them + * if their format is correct. Does not count for + * 'Finished' MAC. */ + if (p[1] == 0 && p[2] == 0 &&p[3] == 0) + { + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, DTLS1_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + + s->init_num = 0; + return dtls1_get_message_fragment(s, st1, stn, + max, ok); + } + else /* Incorrectly formated Hello request */ + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + } + + /* XDTLS: do a sanity check on the fragment */ + + s->init_num += i; + + if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */ + { + /* BUF_MEM_grow takes an 'int' parameter */ + if (l > (INT_MAX-DTLS1_HM_HEADER_LENGTH)) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + if (l && !BUF_MEM_grow_clean(s->init_buf,(int)l + + DTLS1_HM_HEADER_LENGTH)) + { + SSLerr(SSL_F_SSL3_GET_MESSAGE,ERR_R_BUF_LIB); + goto err; + } + /* Only do this test when we're reading the expected message. + * Stale messages will be dropped and future messages will be buffered */ + if ( l > (unsigned long)max) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + + s->s3->tmp.message_size=l; + } + + if ( frag_len > (unsigned long)max) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + if ( frag_len + s->init_num > (INT_MAX - DTLS1_HM_HEADER_LENGTH)) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE,SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + + if ( frag_len & !BUF_MEM_grow_clean(s->init_buf, (int)frag_len + + DTLS1_HM_HEADER_LENGTH + s->init_num)) + { + SSLerr(SSL_F_SSL3_GET_MESSAGE,ERR_R_BUF_LIB); + goto err; + } + + if ( s->d1->r_msg_hdr.frag_off == 0) + { + s->s3->tmp.message_type = msg_hdr.type; + s->d1->r_msg_hdr.type = msg_hdr.type; + s->d1->r_msg_hdr.msg_len = l; + /* s->d1->r_msg_hdr.seq = seq_num; */ + } + + /* XDTLS: ressurect this when restart is in place */ + s->state=stn; + + /* next state (stn) */ + p = s->init_buf->data; + + if ( frag_len > 0) + { + i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, + &p[s->init_num], + frag_len,0); + /* XDTLS: fix this--message fragments cannot span multiple packets */ + if (i <= 0) + { + s->rwstate=SSL_READING; + *ok = 0; + return i; + } + } + else + i = 0; + + /* XDTLS: an incorrectly formatted fragment should cause the + * handshake to fail */ + OPENSSL_assert(i == frag_len); + +#if 0 + /* Successfully read a fragment. + * It may be (1) out of order, or + * (2) it's a repeat, in which case we dump it + * (3) the one we are expecting next (maybe with overlap) + * If it is next one, it may overlap with previously read bytes + */ + + /* case (1): buffer the future fragment + * (we can treat fragments from a future message the same + * as future fragments from the message being currently read, since + * they are sematically simply out of order. + */ + if ( msg_hdr.seq > s->d1->handshake_read_seq || + frag_off > s->init_num - DTLS1_HM_HEADER_LENGTH) + { + dtls1_buffer_handshake_fragment(s, &msg_hdr); + return DTLS1_HM_FRAGMENT_RETRY; + } + + /* case (2): drop the entire fragment, and try again */ + if ( msg_hdr.seq < s->d1->handshake_read_seq || + frag_off + frag_len < s->init_num - DTLS1_HM_HEADER_LENGTH) + { + s->init_num -= DTLS1_HM_HEADER_LENGTH; + return DTLS1_HM_FRAGMENT_RETRY; + } +#endif + + /* case (3): received a immediately useful fragment. Determine the + * possible overlap and copy the fragment. + */ + overlap = (s->init_num - DTLS1_HM_HEADER_LENGTH) - frag_off; + + /* retain the header for the first fragment */ + if ( s->init_num > DTLS1_HM_HEADER_LENGTH) + { + memmove(&(s->init_buf->data[s->init_num]), + &(s->init_buf->data[s->init_num + DTLS1_HM_HEADER_LENGTH + overlap]), + frag_len - overlap); + + s->init_num += frag_len - overlap; + } + else + s->init_num += frag_len; + + dtls1_process_handshake_fragment(s, frag_len - overlap); + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, + (size_t)s->init_num, s, + s->msg_callback_arg); + *ok=1; + + return s->init_num; + +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + s->init_num = 0; +err: + *ok=0; + return(-1); + } + +int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen) + { + unsigned char *p,*d; + int i; + unsigned long l; + + if (s->state == a) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[DTLS1_HM_HEADER_LENGTH]); + + i=s->method->ssl3_enc->final_finish_mac(s, + &(s->s3->finish_dgst1), + &(s->s3->finish_dgst2), + sender,slen,s->s3->tmp.finish_md); + s->s3->tmp.finish_md_len = i; + memcpy(p, s->s3->tmp.finish_md, i); + p+=i; + l=i; + +#ifdef OPENSSL_SYS_WIN16 + /* MSVC 1.5 does not clear the top bytes of the word unless + * I do this. + */ + l&=0xffff; +#endif + + d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l); + s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + + s->state=b; + } + + /* SSL3_ST_SEND_xxxxxx_HELLO_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +/* for these 2 messages, we need to + * ssl->enc_read_ctx re-init + * ssl->s3->read_sequence zero + * ssl->s3->read_mac_secret re-init + * ssl->session->read_sym_enc assign + * ssl->session->read_compression assign + * ssl->session->read_hash assign + */ +int dtls1_send_change_cipher_spec(SSL *s, int a, int b) + { + unsigned char *p; + + if (s->state == a) + { + p=(unsigned char *)s->init_buf->data; + *p++=SSL3_MT_CCS; + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->d1->next_handshake_write_seq++; + s2n(s->d1-> |