sl@0: /* ssl/d1_both.c */ sl@0: /* sl@0: * DTLS implementation written by Nagendra Modadugu sl@0: * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. sl@0: */ sl@0: /* ==================================================================== sl@0: * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in sl@0: * the documentation and/or other materials provided with the sl@0: * distribution. sl@0: * sl@0: * 3. All advertising materials mentioning features or use of this sl@0: * software must display the following acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" sl@0: * sl@0: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to sl@0: * endorse or promote products derived from this software without sl@0: * prior written permission. For written permission, please contact sl@0: * openssl-core@openssl.org. sl@0: * sl@0: * 5. Products derived from this software may not be called "OpenSSL" sl@0: * nor may "OpenSSL" appear in their names without prior written sl@0: * permission of the OpenSSL Project. sl@0: * sl@0: * 6. Redistributions of any form whatsoever must retain the following sl@0: * acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit (http://www.openssl.org/)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY sl@0: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR sl@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR sl@0: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, sl@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT sl@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; sl@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) sl@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED sl@0: * OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: * ==================================================================== sl@0: * sl@0: * This product includes cryptographic software written by Eric Young sl@0: * (eay@cryptsoft.com). This product includes software written by Tim sl@0: * Hudson (tjh@cryptsoft.com). sl@0: * sl@0: */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: /* sl@0: © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include "ssl_locl.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: sl@0: /* XDTLS: figure out the right values */ sl@0: #ifdef EMULATOR sl@0: static const unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28}; sl@0: #else sl@0: static unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28}; sl@0: #endif sl@0: sl@0: static unsigned int dtls1_min_mtu(void); sl@0: static unsigned int dtls1_guess_mtu(unsigned int curr_mtu); sl@0: static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, sl@0: unsigned long frag_len); sl@0: static unsigned char *dtls1_write_message_header(SSL *s, sl@0: unsigned char *p); sl@0: static void dtls1_set_message_header_int(SSL *s, unsigned char mt, sl@0: unsigned long len, unsigned short seq_num, unsigned long frag_off, sl@0: unsigned long frag_len); sl@0: static int dtls1_retransmit_buffered_messages(SSL *s); sl@0: static long dtls1_get_message_fragment(SSL *s, int st1, int stn, sl@0: long max, int *ok); sl@0: sl@0: static hm_fragment * sl@0: dtls1_hm_fragment_new(unsigned long frag_len) sl@0: { sl@0: hm_fragment *frag = NULL; sl@0: unsigned char *buf = NULL; sl@0: sl@0: frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); sl@0: if ( frag == NULL) sl@0: return NULL; sl@0: sl@0: if (frag_len) sl@0: { sl@0: buf = (unsigned char *)OPENSSL_malloc(frag_len); sl@0: if ( buf == NULL) sl@0: { sl@0: OPENSSL_free(frag); sl@0: return NULL; sl@0: } sl@0: } sl@0: sl@0: /* zero length fragment gets zero frag->fragment */ sl@0: frag->fragment = buf; sl@0: sl@0: return frag; sl@0: } sl@0: sl@0: static void sl@0: dtls1_hm_fragment_free(hm_fragment *frag) sl@0: { sl@0: if (frag->fragment) OPENSSL_free(frag->fragment); sl@0: OPENSSL_free(frag); sl@0: } sl@0: sl@0: /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ sl@0: int dtls1_do_write(SSL *s, int type) sl@0: { sl@0: int ret; sl@0: int curr_mtu; sl@0: unsigned int len, frag_off; sl@0: sl@0: /* AHA! Figure out the MTU, and stick to the right size */ sl@0: if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) sl@0: { sl@0: s->d1->mtu = sl@0: BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); sl@0: sl@0: /* I've seen the kernel return bogus numbers when it doesn't know sl@0: * (initial write), so just make sure we have a reasonable number */ sl@0: if ( s->d1->mtu < dtls1_min_mtu()) sl@0: { sl@0: s->d1->mtu = 0; sl@0: s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); sl@0: BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, sl@0: s->d1->mtu, NULL); sl@0: } sl@0: } sl@0: #if 0 sl@0: mtu = s->d1->mtu; sl@0: sl@0: fprintf(stderr, "using MTU = %d\n", mtu); sl@0: sl@0: mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); sl@0: sl@0: curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s)); sl@0: sl@0: if ( curr_mtu > 0) sl@0: mtu = curr_mtu; sl@0: else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0) sl@0: return ret; sl@0: sl@0: if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu) sl@0: { sl@0: ret = BIO_flush(SSL_get_wbio(s)); sl@0: if ( ret <= 0) sl@0: return ret; sl@0: mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); sl@0: } sl@0: sl@0: OPENSSL_assert(mtu > 0); /* should have something reasonable now */ sl@0: sl@0: #endif sl@0: sl@0: if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) sl@0: OPENSSL_assert(s->init_num == sl@0: (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); sl@0: sl@0: frag_off = 0; sl@0: while( s->init_num) sl@0: { sl@0: curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - sl@0: DTLS1_RT_HEADER_LENGTH; sl@0: sl@0: if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH) sl@0: { sl@0: /* grr.. we could get an error if MTU picked was wrong */ sl@0: ret = BIO_flush(SSL_get_wbio(s)); sl@0: if ( ret <= 0) sl@0: return ret; sl@0: curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH; sl@0: } sl@0: sl@0: if ( s->init_num > curr_mtu) sl@0: len = curr_mtu; sl@0: else sl@0: len = s->init_num; sl@0: sl@0: sl@0: /* XDTLS: this function is too long. split out the CCS part */ sl@0: if ( type == SSL3_RT_HANDSHAKE) sl@0: { sl@0: if ( s->init_off != 0) sl@0: { sl@0: OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH); sl@0: s->init_off -= DTLS1_HM_HEADER_LENGTH; sl@0: s->init_num += DTLS1_HM_HEADER_LENGTH; sl@0: sl@0: /* write atleast DTLS1_HM_HEADER_LENGTH bytes */ sl@0: if ( len <= DTLS1_HM_HEADER_LENGTH) sl@0: len += DTLS1_HM_HEADER_LENGTH; sl@0: } sl@0: sl@0: dtls1_fix_message_header(s, frag_off, sl@0: len - DTLS1_HM_HEADER_LENGTH); sl@0: sl@0: dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]); sl@0: sl@0: OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH); sl@0: } sl@0: sl@0: ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off], sl@0: len); sl@0: if (ret < 0) sl@0: { sl@0: /* might need to update MTU here, but we don't know sl@0: * which previous packet caused the failure -- so can't sl@0: * really retransmit anything. continue as if everything sl@0: * is fine and wait for an alert to handle the sl@0: * retransmit sl@0: */ sl@0: if ( BIO_ctrl(SSL_get_wbio(s), sl@0: BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL)) sl@0: s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), sl@0: BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); sl@0: else sl@0: return(-1); sl@0: } sl@0: else sl@0: { sl@0: sl@0: /* bad if this assert fails, only part of the handshake sl@0: * message got sent. but why would this happen? */ sl@0: OPENSSL_assert(len == (unsigned int)ret); sl@0: sl@0: if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting) sl@0: { sl@0: /* should not be done for 'Hello Request's, but in that case sl@0: * we'll ignore the result anyway */ sl@0: unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off]; sl@0: const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; sl@0: int xlen; sl@0: sl@0: if (frag_off == 0 && s->client_version != DTLS1_BAD_VER) sl@0: { sl@0: /* reconstruct message header is if it sl@0: * is being sent in single fragment */ sl@0: *p++ = msg_hdr->type; sl@0: l2n3(msg_hdr->msg_len,p); sl@0: s2n (msg_hdr->seq,p); sl@0: l2n3(0,p); sl@0: l2n3(msg_hdr->msg_len,p); sl@0: p -= DTLS1_HM_HEADER_LENGTH; sl@0: xlen = ret; sl@0: } sl@0: else sl@0: { sl@0: p += DTLS1_HM_HEADER_LENGTH; sl@0: xlen = ret - DTLS1_HM_HEADER_LENGTH; sl@0: } sl@0: sl@0: ssl3_finish_mac(s, p, xlen); sl@0: } sl@0: sl@0: if (ret == s->init_num) sl@0: { sl@0: if (s->msg_callback) sl@0: s->msg_callback(1, s->version, type, s->init_buf->data, sl@0: (size_t)(s->init_off + s->init_num), s, sl@0: s->msg_callback_arg); sl@0: sl@0: s->init_off = 0; /* done writing this message */ sl@0: s->init_num = 0; sl@0: sl@0: return(1); sl@0: } sl@0: s->init_off+=ret; sl@0: s->init_num-=ret; sl@0: frag_off += (ret -= DTLS1_HM_HEADER_LENGTH); sl@0: } sl@0: } sl@0: return(0); sl@0: } sl@0: sl@0: sl@0: /* Obtain handshake message of message type 'mt' (any if mt == -1), sl@0: * maximum acceptable body length 'max'. sl@0: * Read an entire handshake message. Handshake messages arrive in sl@0: * fragments. sl@0: */ sl@0: long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok) sl@0: { sl@0: int i, al; sl@0: struct hm_header_st *msg_hdr; sl@0: sl@0: /* s3->tmp is used to store messages that are unexpected, caused sl@0: * by the absence of an optional handshake message */ sl@0: if (s->s3->tmp.reuse_message) sl@0: { sl@0: s->s3->tmp.reuse_message=0; sl@0: if ((mt >= 0) && (s->s3->tmp.message_type != mt)) sl@0: { sl@0: al=SSL_AD_UNEXPECTED_MESSAGE; sl@0: SSLerr(SSL_F_DTLS1_GET_MESSAGE,SSL_R_UNEXPECTED_MESSAGE); sl@0: goto f_err; sl@0: } sl@0: *ok=1; sl@0: s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; sl@0: s->init_num = (int)s->s3->tmp.message_size; sl@0: return s->init_num; sl@0: } sl@0: sl@0: msg_hdr = &s->d1->r_msg_hdr; sl@0: do sl@0: { sl@0: if ( msg_hdr->frag_off == 0) sl@0: { sl@0: /* s->d1->r_message_header.msg_len = 0; */ sl@0: memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); sl@0: } sl@0: sl@0: i = dtls1_get_message_fragment(s, st1, stn, max, ok); sl@0: if ( i == DTLS1_HM_BAD_FRAGMENT || sl@0: i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */ sl@0: continue; sl@0: else if ( i <= 0 && !*ok) sl@0: return i; sl@0: sl@0: /* Note that s->init_sum is used as a counter summing sl@0: * up fragments' lengths: as soon as they sum up to sl@0: * handshake packet length, we assume we have got all sl@0: * the fragments. Overlapping fragments would cause sl@0: * premature termination, so we don't expect overlaps. sl@0: * Well, handling overlaps would require something more sl@0: * drastic. Indeed, as it is now there is no way to sl@0: * tell if out-of-order fragment from the middle was sl@0: * the last. '>=' is the best/least we can do to control sl@0: * the potential damage caused by malformed overlaps. */ sl@0: if ((unsigned int)s->init_num >= msg_hdr->msg_len) sl@0: { sl@0: unsigned char *p = (unsigned char *)s->init_buf->data; sl@0: unsigned long msg_len = msg_hdr->msg_len; sl@0: sl@0: /* reconstruct message header as if it was sl@0: * sent in single fragment */ sl@0: *(p++) = msg_hdr->type; sl@0: l2n3(msg_len,p); sl@0: s2n (msg_hdr->seq,p); sl@0: l2n3(0,p); sl@0: l2n3(msg_len,p); sl@0: if (s->client_version != DTLS1_BAD_VER) sl@0: p -= DTLS1_HM_HEADER_LENGTH, sl@0: msg_len += DTLS1_HM_HEADER_LENGTH; sl@0: sl@0: ssl3_finish_mac(s, p, msg_len); sl@0: if (s->msg_callback) sl@0: s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, sl@0: p, msg_len, sl@0: s, s->msg_callback_arg); sl@0: sl@0: memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); sl@0: sl@0: s->d1->handshake_read_seq++; sl@0: /* we just read a handshake message from the other side: sl@0: * this means that we don't need to retransmit of the sl@0: * buffered messages. sl@0: * XDTLS: may be able clear out this sl@0: * buffer a little sooner (i.e if an out-of-order sl@0: * handshake message/record is received at the record sl@0: * layer. sl@0: * XDTLS: exception is that the server needs to sl@0: * know that change cipher spec and finished messages sl@0: * have been received by the client before clearing this sl@0: * buffer. this can simply be done by waiting for the sl@0: * first data segment, but is there a better way? */ sl@0: dtls1_clear_record_buffer(s); sl@0: sl@0: s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; sl@0: return s->init_num; sl@0: } sl@0: else sl@0: msg_hdr->frag_off = i; sl@0: } while(1) ; sl@0: sl@0: f_err: sl@0: ssl3_send_alert(s,SSL3_AL_FATAL,al); sl@0: *ok = 0; sl@0: return -1; sl@0: } sl@0: sl@0: sl@0: static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max) sl@0: { sl@0: size_t frag_off,frag_len,msg_len; sl@0: sl@0: msg_len = msg_hdr->msg_len; sl@0: frag_off = msg_hdr->frag_off; sl@0: frag_len = msg_hdr->frag_len; sl@0: sl@0: /* sanity checking */ sl@0: if ( (frag_off+frag_len) > msg_len) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); sl@0: return SSL_AD_ILLEGAL_PARAMETER; sl@0: } sl@0: sl@0: if ( (frag_off+frag_len) > (unsigned long)max) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); sl@0: return SSL_AD_ILLEGAL_PARAMETER; sl@0: } sl@0: sl@0: if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */ sl@0: { sl@0: /* msg_len is limited to 2^24, but is effectively checked sl@0: * against max above */ sl@0: if (!BUF_MEM_grow_clean(s->init_buf,(int)msg_len+DTLS1_HM_HEADER_LENGTH)) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB); sl@0: return SSL_AD_INTERNAL_ERROR; sl@0: } sl@0: sl@0: s->s3->tmp.message_size = msg_len; sl@0: s->d1->r_msg_hdr.msg_len = msg_len; sl@0: s->s3->tmp.message_type = msg_hdr->type; sl@0: s->d1->r_msg_hdr.type = msg_hdr->type; sl@0: s->d1->r_msg_hdr.seq = msg_hdr->seq; sl@0: } sl@0: else if (msg_len != s->d1->r_msg_hdr.msg_len) sl@0: { sl@0: /* They must be playing with us! BTW, failure to enforce sl@0: * upper limit would open possibility for buffer overrun. */ sl@0: SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); sl@0: return SSL_AD_ILLEGAL_PARAMETER; sl@0: } sl@0: sl@0: return 0; /* no error */ sl@0: } sl@0: sl@0: sl@0: static int sl@0: dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) sl@0: { sl@0: /* (0) check whether the desired fragment is available sl@0: * if so: sl@0: * (1) copy over the fragment to s->init_buf->data[] sl@0: * (2) update s->init_num sl@0: */ sl@0: pitem *item; sl@0: hm_fragment *frag; sl@0: int al; sl@0: sl@0: *ok = 0; sl@0: item = pqueue_peek(s->d1->buffered_messages); sl@0: if ( item == NULL) sl@0: return 0; sl@0: sl@0: frag = (hm_fragment *)item->data; sl@0: sl@0: if ( s->d1->handshake_read_seq == frag->msg_header.seq) sl@0: { sl@0: pqueue_pop(s->d1->buffered_messages); sl@0: sl@0: al=dtls1_preprocess_fragment(s,&frag->msg_header,max); sl@0: sl@0: if (al==0) /* no alert */ sl@0: { sl@0: unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH; sl@0: memcpy(&p[frag->msg_header.frag_off], sl@0: frag->fragment,frag->msg_header.frag_len); sl@0: } sl@0: sl@0: dtls1_hm_fragment_free(frag); sl@0: pitem_free(item); sl@0: sl@0: if (al==0) sl@0: { sl@0: *ok = 1; sl@0: return frag->msg_header.frag_len; sl@0: } sl@0: sl@0: ssl3_send_alert(s,SSL3_AL_FATAL,al); sl@0: s->init_num = 0; sl@0: *ok = 0; sl@0: return -1; sl@0: } sl@0: else sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: static int sl@0: dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok) sl@0: { sl@0: int i=-1; sl@0: hm_fragment *frag = NULL; sl@0: pitem *item = NULL; sl@0: PQ_64BIT seq64; sl@0: unsigned long frag_len = msg_hdr->frag_len; sl@0: sl@0: if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) sl@0: goto err; sl@0: sl@0: if (msg_hdr->seq <= s->d1->handshake_read_seq) sl@0: { sl@0: unsigned char devnull [256]; sl@0: sl@0: while (frag_len) sl@0: { sl@0: i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, sl@0: devnull, sl@0: frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0); sl@0: if (i<=0) goto err; sl@0: frag_len -= i; sl@0: } sl@0: } sl@0: frag = dtls1_hm_fragment_new(frag_len); sl@0: if ( frag == NULL) sl@0: goto err; sl@0: sl@0: sl@0: memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); sl@0: sl@0: if (frag_len) sl@0: { sl@0: /* read the body of the fragment (header has already been read */ sl@0: i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, sl@0: frag->fragment,frag_len,0); sl@0: if (i<=0 || (unsigned long)i!=frag_len) sl@0: goto err; sl@0: } sl@0: pq_64bit_init(&seq64); sl@0: pq_64bit_assign_word(&seq64, msg_hdr->seq); sl@0: sl@0: item = pitem_new(seq64, frag); sl@0: pq_64bit_free(&seq64); sl@0: if ( item == NULL) sl@0: goto err; sl@0: sl@0: pqueue_insert(s->d1->buffered_messages, item); sl@0: return DTLS1_HM_FRAGMENT_RETRY; sl@0: sl@0: err: sl@0: if ( frag != NULL) dtls1_hm_fragment_free(frag); sl@0: if ( item != NULL) OPENSSL_free(item); sl@0: *ok = 0; sl@0: return i; sl@0: } sl@0: sl@0: sl@0: static long sl@0: dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok) sl@0: { sl@0: unsigned char wire[DTLS1_HM_HEADER_LENGTH]; sl@0: unsigned long l, frag_off, frag_len; sl@0: int i,al; sl@0: struct hm_header_st msg_hdr; sl@0: sl@0: /* see if we have the required fragment already */ sl@0: if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok) sl@0: { sl@0: if (*ok) s->init_num += frag_len; sl@0: return frag_len; sl@0: } sl@0: sl@0: /* read handshake message header */ sl@0: i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire, sl@0: DTLS1_HM_HEADER_LENGTH, 0); sl@0: if (i <= 0) /* nbio, or an error */ sl@0: { sl@0: s->rwstate=SSL_READING; sl@0: *ok = 0; sl@0: return i; sl@0: } sl@0: sl@0: OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH); sl@0: sl@0: /* parse the message fragment header */ sl@0: sl@0: dtls1_get_message_header(wire, &msg_hdr); sl@0: sl@0: /* sl@0: * if this is a future (or stale) message it gets buffered sl@0: * (or dropped)--no further processing at this time sl@0: */ sl@0: if ( msg_hdr.seq != s->d1->handshake_read_seq) sl@0: return dtls1_process_out_of_seq_message(s, &msg_hdr, ok); sl@0: sl@0: l = msg_hdr.msg_len; sl@0: frag_off = msg_hdr.frag_off; sl@0: frag_len = msg_hdr.frag_len; sl@0: sl@0: if (!s->server && s->d1->r_msg_hdr.frag_off == 0 && sl@0: wire[0] == SSL3_MT_HELLO_REQUEST) sl@0: { sl@0: /* The server may always send 'Hello Request' messages -- sl@0: * we are doing a handshake anyway now, so ignore them sl@0: * if their format is correct. Does not count for sl@0: * 'Finished' MAC. */ sl@0: if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) sl@0: { sl@0: if (s->msg_callback) sl@0: s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, sl@0: wire, DTLS1_HM_HEADER_LENGTH, s, sl@0: s->msg_callback_arg); sl@0: sl@0: s->init_num = 0; sl@0: return dtls1_get_message_fragment(s, st1, stn, sl@0: max, ok); sl@0: } sl@0: else /* Incorrectly formated Hello request */ sl@0: { sl@0: al=SSL_AD_UNEXPECTED_MESSAGE; sl@0: SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE); sl@0: goto f_err; sl@0: } sl@0: } sl@0: sl@0: if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max))) sl@0: goto f_err; sl@0: sl@0: /* XDTLS: ressurect this when restart is in place */ sl@0: s->state=stn; sl@0: sl@0: if ( frag_len > 0) sl@0: { sl@0: unsigned char *p=(unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH; sl@0: sl@0: i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE, sl@0: &p[frag_off],frag_len,0); sl@0: /* XDTLS: fix this--message fragments cannot span multiple packets */ sl@0: if (i <= 0) sl@0: { sl@0: s->rwstate=SSL_READING; sl@0: *ok = 0; sl@0: return i; sl@0: } sl@0: } sl@0: else sl@0: i = 0; sl@0: sl@0: /* XDTLS: an incorrectly formatted fragment should cause the sl@0: * handshake to fail */ sl@0: OPENSSL_assert(i == (int)frag_len); sl@0: sl@0: *ok = 1; sl@0: sl@0: /* Note that s->init_num is *not* used as current offset in sl@0: * s->init_buf->data, but as a counter summing up fragments' sl@0: * lengths: as soon as they sum up to handshake packet sl@0: * length, we assume we have got all the fragments. */ sl@0: s->init_num += frag_len; sl@0: return frag_len; sl@0: sl@0: f_err: sl@0: ssl3_send_alert(s,SSL3_AL_FATAL,al); sl@0: s->init_num = 0; sl@0: sl@0: *ok=0; sl@0: return(-1); sl@0: } sl@0: sl@0: int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen) sl@0: { sl@0: unsigned char *p,*d; sl@0: int i; sl@0: unsigned long l; sl@0: sl@0: if (s->state == a) sl@0: { sl@0: d=(unsigned char *)s->init_buf->data; sl@0: p= &(d[DTLS1_HM_HEADER_LENGTH]); sl@0: sl@0: i=s->method->ssl3_enc->final_finish_mac(s, sl@0: &(s->s3->finish_dgst1), sl@0: &(s->s3->finish_dgst2), sl@0: sender,slen,s->s3->tmp.finish_md); sl@0: s->s3->tmp.finish_md_len = i; sl@0: memcpy(p, s->s3->tmp.finish_md, i); sl@0: p+=i; sl@0: l=i; sl@0: sl@0: #ifdef OPENSSL_SYS_WIN16 sl@0: /* MSVC 1.5 does not clear the top bytes of the word unless sl@0: * I do this. sl@0: */ sl@0: l&=0xffff; sl@0: #endif sl@0: sl@0: d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l); sl@0: s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH; sl@0: s->init_off=0; sl@0: sl@0: /* buffer the message to handle re-xmits */ sl@0: dtls1_buffer_message(s, 0); sl@0: sl@0: s->state=b; sl@0: } sl@0: sl@0: /* SSL3_ST_SEND_xxxxxx_HELLO_B */ sl@0: return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); sl@0: } sl@0: sl@0: /* for these 2 messages, we need to sl@0: * ssl->enc_read_ctx re-init sl@0: * ssl->s3->read_sequence zero sl@0: * ssl->s3->read_mac_secret re-init sl@0: * ssl->session->read_sym_enc assign sl@0: * ssl->session->read_compression assign sl@0: * ssl->session->read_hash assign sl@0: */ sl@0: int dtls1_send_change_cipher_spec(SSL *s, int a, int b) sl@0: { sl@0: unsigned char *p; sl@0: sl@0: if (s->state == a) sl@0: { sl@0: p=(unsigned char *)s->init_buf->data; sl@0: *p++=SSL3_MT_CCS; sl@0: s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; sl@0: s->init_num=DTLS1_CCS_HEADER_LENGTH; sl@0: sl@0: if (s->client_version == DTLS1_BAD_VER) sl@0: { sl@0: s->d1->next_handshake_write_seq++; sl@0: s2n(s->d1->handshake_write_seq,p); sl@0: s->init_num+=2; sl@0: } sl@0: sl@0: s->init_off=0; sl@0: sl@0: dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, sl@0: s->d1->handshake_write_seq, 0, 0); sl@0: sl@0: /* buffer the message to handle re-xmits */ sl@0: dtls1_buffer_message(s, 1); sl@0: sl@0: s->state=b; sl@0: } sl@0: sl@0: /* SSL3_ST_CW_CHANGE_B */ sl@0: return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC)); sl@0: } sl@0: sl@0: unsigned long dtls1_output_cert_chain(SSL *s, X509 *x) sl@0: { sl@0: unsigned char *p; sl@0: int n,i; sl@0: unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH; sl@0: BUF_MEM *buf; sl@0: X509_STORE_CTX xs_ctx; sl@0: X509_OBJECT obj; sl@0: sl@0: /* TLSv1 sends a chain with nothing in it, instead of an alert */ sl@0: buf=s->init_buf; sl@0: if (!BUF_MEM_grow_clean(buf,10)) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB); sl@0: return(0); sl@0: } sl@0: if (x != NULL) sl@0: { sl@0: if(!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,NULL,NULL)) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB); sl@0: return(0); sl@0: } sl@0: sl@0: for (;;) sl@0: { sl@0: n=i2d_X509(x,NULL); sl@0: if (!BUF_MEM_grow_clean(buf,(int)(n+l+3))) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB); sl@0: return(0); sl@0: } sl@0: p=(unsigned char *)&(buf->data[l]); sl@0: l2n3(n,p); sl@0: i2d_X509(x,&p); sl@0: l+=n+3; sl@0: if (X509_NAME_cmp(X509_get_subject_name(x), sl@0: X509_get_issuer_name(x)) == 0) break; sl@0: sl@0: i=X509_STORE_get_by_subject(&xs_ctx,X509_LU_X509, sl@0: X509_get_issuer_name(x),&obj); sl@0: if (i <= 0) break; sl@0: x=obj.data.x509; sl@0: /* Count is one too high since the X509_STORE_get uped the sl@0: * ref count */ sl@0: X509_free(x); sl@0: } sl@0: sl@0: X509_STORE_CTX_cleanup(&xs_ctx); sl@0: } sl@0: sl@0: /* Thawte special :-) */ sl@0: if (s->ctx->extra_certs != NULL) sl@0: for (i=0; ictx->extra_certs); i++) sl@0: { sl@0: x=sk_X509_value(s->ctx->extra_certs,i); sl@0: n=i2d_X509(x,NULL); sl@0: if (!BUF_MEM_grow_clean(buf,(int)(n+l+3))) sl@0: { sl@0: SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB); sl@0: return(0); sl@0: } sl@0: p=(unsigned char *)&(buf->data[l]); sl@0: l2n3(n,p); sl@0: i2d_X509(x,&p); sl@0: l+=n+3; sl@0: } sl@0: sl@0: l-= (3 + DTLS1_HM_HEADER_LENGTH); sl@0: sl@0: p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]); sl@0: l2n3(l,p); sl@0: l+=3; sl@0: p=(unsigned char *)&(buf->data[0]); sl@0: p = dtls1_set_message_header(s, p, SSL3_MT_CERTIFICATE, l, 0, l); sl@0: sl@0: l+=DTLS1_HM_HEADER_LENGTH; sl@0: return(l); sl@0: } sl@0: sl@0: int dtls1_read_failed(SSL *s, int code) sl@0: { sl@0: DTLS1_STATE *state; sl@0: BIO *bio; sl@0: int send_alert = 0; sl@0: sl@0: if ( code > 0) sl@0: { sl@0: fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__); sl@0: return 1; sl@0: } sl@0: sl@0: bio = SSL_get_rbio(s); sl@0: if ( ! BIO_dgram_recv_timedout(bio)) sl@0: { sl@0: /* not a timeout, none of our business, sl@0: let higher layers handle this. in fact it's probably an error */ sl@0: return code; sl@0: } sl@0: sl@0: if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */ sl@0: { sl@0: BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); sl@0: return code; sl@0: } sl@0: sl@0: state = s->d1; sl@0: state->timeout.num_alerts++; sl@0: if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) sl@0: { sl@0: /* fail the connection, enough alerts have been sent */ sl@0: SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED); sl@0: return 0; sl@0: } sl@0: sl@0: state->timeout.read_timeouts++; sl@0: if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) sl@0: { sl@0: send_alert = 1; sl@0: state->timeout.read_timeouts = 1; sl@0: } sl@0: sl@0: sl@0: #if 0 /* for now, each alert contains only one record number */ sl@0: item = pqueue_peek(state->rcvd_records); sl@0: if ( item ) sl@0: { sl@0: /* send an alert immediately for all the missing records */ sl@0: } sl@0: else sl@0: #endif sl@0: sl@0: #if 0 /* no more alert sending, just retransmit the last set of messages */ sl@0: if ( send_alert) sl@0: ssl3_send_alert(s,SSL3_AL_WARNING, sl@0: DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); sl@0: #endif sl@0: sl@0: return dtls1_retransmit_buffered_messages(s) ; sl@0: } sl@0: sl@0: sl@0: static int sl@0: dtls1_retransmit_buffered_messages(SSL *s) sl@0: { sl@0: pqueue sent = s->d1->sent_messages; sl@0: piterator iter; sl@0: pitem *item; sl@0: hm_fragment *frag; sl@0: int found = 0; sl@0: sl@0: iter = pqueue_iterator(sent); sl@0: sl@0: for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) sl@0: { sl@0: frag = (hm_fragment *)item->data; sl@0: if ( dtls1_retransmit_message(s, frag->msg_header.seq, 0, &found) <= 0 && sl@0: found) sl@0: { sl@0: fprintf(stderr, "dtls1_retransmit_message() failed\n"); sl@0: return -1; sl@0: } sl@0: } sl@0: sl@0: return 1; sl@0: } sl@0: sl@0: sl@0: int sl@0: dtls1_buffer_message(SSL *s, int is_ccs) sl@0: { sl@0: pitem *item; sl@0: hm_fragment *frag; sl@0: PQ_64BIT seq64; sl@0: unsigned int epoch = s->d1->w_epoch; sl@0: sl@0: /* this function is called immediately after a message has sl@0: * been serialized */ sl@0: OPENSSL_assert(s->init_off == 0); sl@0: sl@0: frag = dtls1_hm_fragment_new(s->init_num); sl@0: sl@0: memcpy(frag->fragment, s->init_buf->data, s->init_num); sl@0: sl@0: if ( is_ccs) sl@0: { sl@0: OPENSSL_assert(s->d1->w_msg_hdr.msg_len + sl@0: DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num); sl@0: epoch++; sl@0: } sl@0: else sl@0: { sl@0: OPENSSL_assert(s->d1->w_msg_hdr.msg_len + sl@0: DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num); sl@0: } sl@0: sl@0: frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; sl@0: frag->msg_header.seq = s->d1->w_msg_hdr.seq; sl@0: frag->msg_header.type = s->d1->w_msg_hdr.type; sl@0: frag->msg_header.frag_off = 0; sl@0: frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; sl@0: frag->msg_header.is_ccs = is_ccs; sl@0: sl@0: pq_64bit_init(&seq64); sl@0: pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq); sl@0: sl@0: item = pitem_new(seq64, frag); sl@0: pq_64bit_free(&seq64); sl@0: if ( item == NULL) sl@0: { sl@0: dtls1_hm_fragment_free(frag); sl@0: return 0; sl@0: } sl@0: sl@0: #if 0 sl@0: fprintf( stderr, "buffered messge: \ttype = %xx\n", msg_buf->type); sl@0: fprintf( stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len); sl@0: fprintf( stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num); sl@0: #endif sl@0: sl@0: pqueue_insert(s->d1->sent_messages, item); sl@0: return 1; sl@0: } sl@0: sl@0: int sl@0: dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, sl@0: int *found) sl@0: { sl@0: int ret; sl@0: /* XDTLS: for now assuming that read/writes are blocking */ sl@0: pitem *item; sl@0: hm_fragment *frag ; sl@0: unsigned long header_length; sl@0: PQ_64BIT seq64; sl@0: sl@0: /* sl@0: OPENSSL_assert(s->init_num == 0); sl@0: OPENSSL_assert(s->init_off == 0); sl@0: */ sl@0: sl@0: /* XDTLS: the requested message ought to be found, otherwise error */ sl@0: pq_64bit_init(&seq64); sl@0: pq_64bit_assign_word(&seq64, seq); sl@0: sl@0: item = pqueue_find(s->d1->sent_messages, seq64); sl@0: pq_64bit_free(&seq64); sl@0: if ( item == NULL) sl@0: { sl@0: fprintf(stderr, "retransmit: message %d non-existant\n", seq); sl@0: *found = 0; sl@0: return 0; sl@0: } sl@0: sl@0: *found = 1; sl@0: frag = (hm_fragment *)item->data; sl@0: sl@0: if ( frag->msg_header.is_ccs) sl@0: header_length = DTLS1_CCS_HEADER_LENGTH; sl@0: else sl@0: header_length = DTLS1_HM_HEADER_LENGTH; sl@0: sl@0: memcpy(s->init_buf->data, frag->fragment, sl@0: frag->msg_header.msg_len + header_length); sl@0: s->init_num = frag->msg_header.msg_len + header_length; sl@0: sl@0: dtls1_set_message_header_int(s, frag->msg_header.type, sl@0: frag->msg_header.msg_len, frag->msg_header.seq, 0, sl@0: frag->msg_header.frag_len); sl@0: sl@0: s->d1->retransmitting = 1; sl@0: ret = dtls1_do_write(s, frag->msg_header.is_ccs ? sl@0: SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); sl@0: s->d1->retransmitting = 0; sl@0: sl@0: (void)BIO_flush(SSL_get_wbio(s)); sl@0: return ret; sl@0: } sl@0: sl@0: /* call this function when the buffered messages are no longer needed */ sl@0: void sl@0: dtls1_clear_record_buffer(SSL *s) sl@0: { sl@0: pitem *item; sl@0: sl@0: for(item = pqueue_pop(s->d1->sent_messages); sl@0: item != NULL; item = pqueue_pop(s->d1->sent_messages)) sl@0: { sl@0: dtls1_hm_fragment_free((hm_fragment *)item->data); sl@0: pitem_free(item); sl@0: } sl@0: } sl@0: sl@0: sl@0: unsigned char * sl@0: dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt, sl@0: unsigned long len, unsigned long frag_off, unsigned long frag_len) sl@0: { sl@0: if ( frag_off == 0) sl@0: { sl@0: s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; sl@0: s->d1->next_handshake_write_seq++; sl@0: } sl@0: sl@0: dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq, sl@0: frag_off, frag_len); sl@0: sl@0: return p += DTLS1_HM_HEADER_LENGTH; sl@0: } sl@0: sl@0: sl@0: /* don't actually do the writing, wait till the MTU has been retrieved */ sl@0: static void sl@0: dtls1_set_message_header_int(SSL *s, unsigned char mt, sl@0: unsigned long len, unsigned short seq_num, unsigned long frag_off, sl@0: unsigned long frag_len) sl@0: { sl@0: struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; sl@0: sl@0: msg_hdr->type = mt; sl@0: msg_hdr->msg_len = len; sl@0: msg_hdr->seq = seq_num; sl@0: msg_hdr->frag_off = frag_off; sl@0: msg_hdr->frag_len = frag_len; sl@0: } sl@0: sl@0: static void sl@0: dtls1_fix_message_header(SSL *s, unsigned long frag_off, sl@0: unsigned long frag_len) sl@0: { sl@0: struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; sl@0: sl@0: msg_hdr->frag_off = frag_off; sl@0: msg_hdr->frag_len = frag_len; sl@0: } sl@0: sl@0: static unsigned char * sl@0: dtls1_write_message_header(SSL *s, unsigned char *p) sl@0: { sl@0: struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; sl@0: sl@0: *p++ = msg_hdr->type; sl@0: l2n3(msg_hdr->msg_len, p); sl@0: sl@0: s2n(msg_hdr->seq, p); sl@0: l2n3(msg_hdr->frag_off, p); sl@0: l2n3(msg_hdr->frag_len, p); sl@0: sl@0: return p; sl@0: } sl@0: sl@0: static unsigned int sl@0: dtls1_min_mtu(void) sl@0: { sl@0: return (g_probable_mtu[(sizeof(g_probable_mtu) / sl@0: sizeof(g_probable_mtu[0])) - 1]); sl@0: } sl@0: sl@0: static unsigned int sl@0: dtls1_guess_mtu(unsigned int curr_mtu) sl@0: { sl@0: size_t i; sl@0: sl@0: if ( curr_mtu == 0 ) sl@0: return g_probable_mtu[0] ; sl@0: sl@0: for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++) sl@0: if ( curr_mtu > g_probable_mtu[i]) sl@0: return g_probable_mtu[i]; sl@0: sl@0: return curr_mtu; sl@0: } sl@0: sl@0: void sl@0: dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr) sl@0: { sl@0: memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); sl@0: msg_hdr->type = *(data++); sl@0: n2l3(data, msg_hdr->msg_len); sl@0: sl@0: n2s(data, msg_hdr->seq); sl@0: n2l3(data, msg_hdr->frag_off); sl@0: n2l3(data, msg_hdr->frag_len); sl@0: } sl@0: sl@0: void sl@0: dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr) sl@0: { sl@0: memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st)); sl@0: sl@0: ccs_hdr->type = *(data++); sl@0: }