diff options
Diffstat (limited to 'ssl/d1_both.c')
-rw-r--r-- | ssl/d1_both.c | 2647 |
1 files changed, 1313 insertions, 1334 deletions
diff --git a/ssl/d1_both.c b/ssl/d1_both.c index b70192b442..a47d528434 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -1,7 +1,7 @@ /* ssl/d1_both.c */ -/* +/* * DTLS implementation written by Nagendra Modadugu - * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */ /* ==================================================================== * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. @@ -11,7 +11,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * 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 @@ -62,21 +62,21 @@ * 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: @@ -91,10 +91,10 @@ * 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 + * 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 @@ -106,7 +106,7 @@ * 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 @@ -126,1425 +126,1404 @@ #define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8) #define RSMBLY_BITMASK_MARK(bitmask, start, end) { \ - if ((end) - (start) <= 8) { \ - long ii; \ - for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \ - } else { \ - long ii; \ - bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \ - for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \ - bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \ - } } + if ((end) - (start) <= 8) { \ + long ii; \ + for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \ + } else { \ + long ii; \ + bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \ + for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \ + bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \ + } } #define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \ - long ii; \ - OPENSSL_assert((msg_len) > 0); \ - is_complete = 1; \ - if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \ - if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \ - if (bitmask[ii] != 0xff) { is_complete = 0; break; } } + long ii; \ + OPENSSL_assert((msg_len) > 0); \ + is_complete = 1; \ + if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \ + if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \ + if (bitmask[ii] != 0xff) { is_complete = 0; break; } } #if 0 -#define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \ - long ii; \ - printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \ - printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \ - printf("\n"); } +# define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \ + long ii; \ + printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \ + printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \ + printf("\n"); } #endif -static unsigned char bitmask_start_values[] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; -static unsigned char bitmask_end_values[] = {0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f}; +static unsigned char bitmask_start_values[] = + { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 }; +static unsigned char bitmask_end_values[] = + { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; /* XDTLS: figure out the right values */ -static const unsigned int g_probable_mtu[] = {1500, 512, 256}; +static const unsigned int g_probable_mtu[] = { 1500, 512, 256 }; -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_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 long dtls1_get_message_fragment(SSL *s, int st1, int stn, - long max, int *ok); - -static hm_fragment * -dtls1_hm_fragment_new(unsigned long frag_len, int reassembly) - { - hm_fragment *frag = NULL; - unsigned char *buf = NULL; - unsigned char *bitmask = NULL; - - frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); - if ( frag == NULL) - return NULL; - - if (frag_len) - { - buf = (unsigned char *)OPENSSL_malloc(frag_len); - if ( buf == NULL) - { - OPENSSL_free(frag); - return NULL; - } - } - - /* zero length fragment gets zero frag->fragment */ - frag->fragment = buf; - - /* Initialize reassembly bitmask if necessary */ - if (reassembly) - { - bitmask = (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len)); - if (bitmask == NULL) - { - if (buf != NULL) OPENSSL_free(buf); - OPENSSL_free(frag); - return NULL; - } - memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len)); - } - - frag->reassembly = bitmask; - - return frag; - } + unsigned long len, + unsigned short seq_num, + unsigned long frag_off, + unsigned long frag_len); +static long dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, + int *ok); + +static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, + int reassembly) +{ + hm_fragment *frag = NULL; + unsigned char *buf = NULL; + unsigned char *bitmask = NULL; + + frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); + if (frag == NULL) + return NULL; + + if (frag_len) { + buf = (unsigned char *)OPENSSL_malloc(frag_len); + if (buf == NULL) { + OPENSSL_free(frag); + return NULL; + } + } + + /* zero length fragment gets zero frag->fragment */ + frag->fragment = buf; + + /* Initialize reassembly bitmask if necessary */ + if (reassembly) { + bitmask = + (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len)); + if (bitmask == NULL) { + if (buf != NULL) + OPENSSL_free(buf); + OPENSSL_free(frag); + return NULL; + } + memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len)); + } + + frag->reassembly = bitmask; + + return frag; +} void dtls1_hm_fragment_free(hm_fragment *frag) - { - - if (frag->msg_header.is_ccs) - { - EVP_CIPHER_CTX_free(frag->msg_header.saved_retransmit_state.enc_write_ctx); - EVP_MD_CTX_destroy(frag->msg_header.saved_retransmit_state.write_hash); - } - if (frag->fragment) OPENSSL_free(frag->fragment); - if (frag->reassembly) OPENSSL_free(frag->reassembly); - OPENSSL_free(frag); - } +{ + + if (frag->msg_header.is_ccs) { + EVP_CIPHER_CTX_free(frag->msg_header. + saved_retransmit_state.enc_write_ctx); + EVP_MD_CTX_destroy(frag->msg_header. + saved_retransmit_state.write_hash); + } + if (frag->fragment) + OPENSSL_free(frag->fragment); + if (frag->reassembly) + OPENSSL_free(frag->reassembly); + OPENSSL_free(frag); +} static int dtls1_query_mtu(SSL *s) { - if(s->d1->link_mtu) - { - s->d1->mtu = s->d1->link_mtu-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); - s->d1->link_mtu = 0; - } - - /* AHA! Figure out the MTU, and stick to the right size */ - if (s->d1->mtu < dtls1_min_mtu(s)) - { - 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)) - { - /* Set to min mtu */ - s->d1->mtu = dtls1_min_mtu(s); - BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, - s->d1->mtu, NULL); - } - } - else - return 0; - } - return 1; + if (s->d1->link_mtu) { + s->d1->mtu = + s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); + s->d1->link_mtu = 0; + } + + /* AHA! Figure out the MTU, and stick to the right size */ + if (s->d1->mtu < dtls1_min_mtu(s)) { + 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)) { + /* Set to min mtu */ + s->d1->mtu = dtls1_min_mtu(s); + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, + s->d1->mtu, NULL); + } + } else + return 0; + } + return 1; } -/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ +/* + * 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; - unsigned int curr_mtu; - int retry = 1; - unsigned int len, frag_off, mac_size, blocksize, used_len; - - if(!dtls1_query_mtu(s)) - return -1; - - OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something reasonable now */ - - if ( s->init_off == 0 && type == SSL3_RT_HANDSHAKE) - OPENSSL_assert(s->init_num == - (int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH); - - if (s->write_hash) - { - if (s->enc_write_ctx && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) - mac_size = 0; - else - mac_size = EVP_MD_CTX_size(s->write_hash); - } - else - mac_size = 0; - - if (s->enc_write_ctx && - (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) - blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher); - else - blocksize = 0; - - frag_off = 0; - /* s->init_num shouldn't ever be < 0...but just in case */ - while(s->init_num > 0) - { - used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH - + mac_size + blocksize; - if(s->d1->mtu > used_len) - curr_mtu = s->d1->mtu - used_len; - else - curr_mtu = 0; - - 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; - used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize; - if(s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) - { - curr_mtu = s->d1->mtu - used_len; - } - else - { - /* Shouldn't happen */ - return -1; - } - } - - /* We just checked that s->init_num > 0 so this cast should be safe */ - if (((unsigned int)s->init_num) > curr_mtu) - len = curr_mtu; - else - len = s->init_num; - - /* Shouldn't ever happen */ - if(len > INT_MAX) - len = INT_MAX; - - /* 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; - - /* We just checked that s->init_num > 0 so this cast should be safe */ - if (((unsigned int)s->init_num) > curr_mtu) - len = curr_mtu; - else - len = s->init_num; - } - - /* Shouldn't ever happen */ - if(len > INT_MAX) - len = INT_MAX; - - if ( len < DTLS1_HM_HEADER_LENGTH ) - { - /* - * len is so small that we really can't do anything sensible - * so fail - */ - return -1; - } - dtls1_fix_message_header(s, frag_off, - len - DTLS1_HM_HEADER_LENGTH); - - dtls1_write_message_header(s, (unsigned char *)&s->init_buf->data[s->init_off]); - } - - 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 ( retry && BIO_ctrl(SSL_get_wbio(s), - BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 ) - { - if(!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) - { - if(!dtls1_query_mtu(s)) - return -1; - /* Have one more go */ - retry = 0; - } - else - return -1; - } - 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 == (unsigned int)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 */ - unsigned char *p = (unsigned char *)&s->init_buf->data[s->init_off]; - const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; - int xlen; - - if (frag_off == 0 && s->version != DTLS1_BAD_VER) - { - /* reconstruct message header is if it - * is being sent in single fragment */ - *p++ = msg_hdr->type; - l2n3(msg_hdr->msg_len,p); - s2n (msg_hdr->seq,p); - l2n3(0,p); - l2n3(msg_hdr->msg_len,p); - p -= DTLS1_HM_HEADER_LENGTH; - xlen = ret; - } - else - { - p += DTLS1_HM_HEADER_LENGTH; - xlen = ret - DTLS1_HM_HEADER_LENGTH; - } - - ssl3_finish_mac(s, p, xlen); - } - - 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. +{ + int ret; + unsigned int curr_mtu; + int retry = 1; + unsigned int len, frag_off, mac_size, blocksize, used_len; + + if (!dtls1_query_mtu(s)) + return -1; + + OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something + * reasonable now */ + + if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE) + OPENSSL_assert(s->init_num == + (int)s->d1->w_msg_hdr.msg_len + + DTLS1_HM_HEADER_LENGTH); + + if (s->write_hash) { + if (s->enc_write_ctx + && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) + mac_size = 0; + else + mac_size = EVP_MD_CTX_size(s->write_hash); + } else + mac_size = 0; + + if (s->enc_write_ctx && + (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) + blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher); + else + blocksize = 0; + + frag_off = 0; + /* s->init_num shouldn't ever be < 0...but just in case */ + while (s->init_num > 0) { + used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH + + mac_size + blocksize; + if (s->d1->mtu > used_len) + curr_mtu = s->d1->mtu - used_len; + else + curr_mtu = 0; + + 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; + used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize; + if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) { + curr_mtu = s->d1->mtu - used_len; + } else { + /* Shouldn't happen */ + return -1; + } + } + + /* + * We just checked that s->init_num > 0 so this cast should be safe + */ + if (((unsigned int)s->init_num) > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + + /* Shouldn't ever happen */ + if (len > INT_MAX) + len = INT_MAX; + + /* + * 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; + + /* + * We just checked that s->init_num > 0 so this cast should + * be safe + */ + if (((unsigned int)s->init_num) > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + } + + /* Shouldn't ever happen */ + if (len > INT_MAX) + len = INT_MAX; + + if (len < DTLS1_HM_HEADER_LENGTH) { + /* + * len is so small that we really can't do anything sensible + * so fail + */ + return -1; + } + dtls1_fix_message_header(s, frag_off, + len - DTLS1_HM_HEADER_LENGTH); + + dtls1_write_message_header(s, + (unsigned char *)&s->init_buf-> + data[s->init_off]); + } + + 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 (retry && BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) { + if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { + if (!dtls1_query_mtu(s)) + return -1; + /* Have one more go */ + retry = 0; + } else + return -1; + } 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 == (unsigned int)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 + */ + unsigned char *p = + (unsigned char *)&s->init_buf->data[s->init_off]; + const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + int xlen; + + if (frag_off == 0 && s->version != DTLS1_BAD_VER) { + /* + * reconstruct message header is if it is being sent in + * single fragment + */ + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_hdr->msg_len, p); + p -= DTLS1_HM_HEADER_LENGTH; + xlen = ret; + } else { + p += DTLS1_HM_HEADER_LENGTH; + xlen = ret - DTLS1_HM_HEADER_LENGTH; + } + + ssl3_finish_mac(s, p, xlen); + } + + 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; - struct hm_header_st *msg_hdr; - unsigned char *p; - unsigned long msg_len; - - /* 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_DTLS1_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; - } - - msg_hdr = &s->d1->r_msg_hdr; - memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); - -again: - i = dtls1_get_message_fragment(s, st1, stn, max, ok); - if ( i == DTLS1_HM_BAD_FRAGMENT || - i == DTLS1_HM_FRAGMENT_RETRY) - { - /* bad fragment received */ - goto again; - } - else if ( i <= 0 && !*ok) - { - return i; - } - - p = (unsigned char *)s->init_buf->data; - msg_len = msg_hdr->msg_len; - - /* reconstruct message header */ - *(p++) = msg_hdr->type; - l2n3(msg_len,p); - s2n (msg_hdr->seq,p); - l2n3(0,p); - l2n3(msg_len,p); - if (s->version != DTLS1_BAD_VER) { - p -= DTLS1_HM_HEADER_LENGTH; - msg_len += DTLS1_HM_HEADER_LENGTH; - } - - ssl3_finish_mac(s, p, msg_len); - if (s->msg_callback) - s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, - p, msg_len, - s, s->msg_callback_arg); - - memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); - - /* Don't change sequence numbers while listening */ - if (!s->d1->listen) - s->d1->handshake_read_seq++; - - s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; - return s->init_num; - -f_err: - ssl3_send_alert(s,SSL3_AL_FATAL,al); - *ok = 0; - return -1; - } - - -static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max) - { - size_t frag_off,frag_len,msg_len; - - msg_len = msg_hdr->msg_len; - frag_off = msg_hdr->frag_off; - frag_len = msg_hdr->frag_len; - - /* sanity checking */ - if ( (frag_off+frag_len) > msg_len) - { - SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; - } - - if ( (frag_off+frag_len) > (unsigned long)max) - { - SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; - } - - if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */ - { - /* msg_len is limited to 2^24, but is effectively checked - * against max above */ - if (!BUF_MEM_grow_clean(s->init_buf,msg_len+DTLS1_HM_HEADER_LENGTH)) - { - SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB); - return SSL_AD_INTERNAL_ERROR; - } - - s->s3->tmp.message_size = msg_len; - s->d1->r_msg_hdr.msg_len = msg_len; - s->s3->tmp.message_type = msg_hdr->type; - s->d1->r_msg_hdr.type = msg_hdr->type; - s->d1->r_msg_hdr.seq = msg_hdr->seq; - } - else if (msg_len != s->d1->r_msg_hdr.msg_len) - { - /* They must be playing with us! BTW, failure to enforce - * upper limit would open possibility for buffer overrun. */ - SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE); - return SSL_AD_ILLEGAL_PARAMETER; - } - - return 0; /* no error */ - } +{ + int i, al; + struct hm_header_st *msg_hdr; + unsigned char *p; + unsigned long msg_len; + + /* + * 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_DTLS1_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; + } + + msg_hdr = &s->d1->r_msg_hdr; + memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); + + again: + i = dtls1_get_message_fragment(s, st1, stn, max, ok); + if (i == DTLS1_HM_BAD_FRAGMENT || i == DTLS1_HM_FRAGMENT_RETRY) { + /* bad fragment received */ + goto again; + } else if (i <= 0 && !*ok) { + return i; + } + + p = (unsigned char *)s->init_buf->data; + msg_len = msg_hdr->msg_len; + + /* reconstruct message header */ + *(p++) = msg_hdr->type; + l2n3(msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_len, p); + if (s->version != DTLS1_BAD_VER) { + p -= DTLS1_HM_HEADER_LENGTH; + msg_len += DTLS1_HM_HEADER_LENGTH; + } + + ssl3_finish_mac(s, p, msg_len); + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, msg_len, s, s->msg_callback_arg); + + memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); + + /* Don't change sequence numbers while listening */ + if (!s->d1->listen) + s->d1->handshake_read_seq++; + + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + return s->init_num; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + *ok = 0; + return -1; +} +static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr, + int max) +{ + size_t frag_off, frag_len, msg_len; + + msg_len = msg_hdr->msg_len; + frag_off = msg_hdr->frag_off; + frag_len = msg_hdr->frag_len; + + /* sanity checking */ + if ((frag_off + frag_len) > msg_len) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + if ((frag_off + frag_len) > (unsigned long)max) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */ + /* + * msg_len is limited to 2^24, but is effectively checked against max + * above + */ + if (!BUF_MEM_grow_clean + (s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB); + return SSL_AD_INTERNAL_ERROR; + } + + s->s3->tmp.message_size = msg_len; + s->d1->r_msg_hdr.msg_len = msg_len; + s->s3->tmp.message_type = msg_hdr->type; + s->d1->r_msg_hdr.type = msg_hdr->type; + s->d1->r_msg_hdr.seq = msg_hdr->seq; + } else if (msg_len != s->d1->r_msg_hdr.msg_len) { + /* + * They must be playing with us! BTW, failure to enforce upper limit + * would open possibility for buffer overrun. + */ + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + return 0; /* no error */ +} -static int -dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) - { - /*- - * (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; - int al; - - *ok = 0; - item = pqueue_peek(s->d1->buffered_messages); - if ( item == NULL) - return 0; - - frag = (hm_fragment *)item->data; - - /* Don't return if reassembly still in progress */ - if (frag->reassembly != NULL) - return 0; - - if ( s->d1->handshake_read_seq == frag->msg_header.seq) - { - unsigned long frag_len = frag->msg_header.frag_len; - pqueue_pop(s->d1->buffered_messages); - - al=dtls1_preprocess_fragment(s,&frag->msg_header,max); - - if (al==0) /* no alert */ - { - unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH; - memcpy(&p[frag->msg_header.frag_off], - frag->fragment,frag->msg_header.frag_len); - } - - dtls1_hm_fragment_free(frag); - pitem_free(item); - - if (al==0) - { - *ok = 1; - return frag_len; - } - - ssl3_send_alert(s,SSL3_AL_FATAL,al); - s->init_num = 0; - *ok = 0; - return -1; - } - else - return 0; - } - -/* dtls1_max_handshake_message_len returns the maximum number of bytes - * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but may - * be greater if the maximum certificate list size requires it. */ +static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) +{ + /*- + * (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; + int al; + + *ok = 0; + item = pqueue_peek(s->d1->buffered_messages); + if (item == NULL) + return 0; + + frag = (hm_fragment *)item->data; + + /* Don't return if reassembly still in progress */ + if (frag->reassembly != NULL) + return 0; + + if (s->d1->handshake_read_seq == frag->msg_header.seq) { + unsigned long frag_len = frag->msg_header.frag_len; + pqueue_pop(s->d1->buffered_messages); + + al = dtls1_preprocess_fragment(s, &frag->msg_header, max); + + if (al == 0) { /* no alert */ + unsigned char *p = + (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + memcpy(&p[frag->msg_header.frag_off], frag->fragment, + frag->msg_header.frag_len); + } + + dtls1_hm_fragment_free(frag); + pitem_free(item); + + if (al == 0) { + *ok = 1; + return frag_len; + } + + |