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 - 28, 512 - 28, 256 - 28};
+static const unsigned int g_probable_mtu[] = {1500, 512, 256};
-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,
return frag;
}
-static void
-dtls1_hm_fragment_free(hm_fragment *frag)
+void dtls1_hm_fragment_free(hm_fragment *frag)
{
if (frag->msg_header.is_ccs)
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, mac_size, blocksize;
+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() && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
+ if (s->d1->mtu < dtls1_min_mtu(s))
{
- 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())
+ if(!(SSL_get_options(s) & SSL_OP_NO_QUERY_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);
+ 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;
}
-#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));
+ return 1;
+}
- if ( curr_mtu > 0)
- mtu = curr_mtu;
- else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
- return ret;
+/* 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 ( 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);
- }
-#endif
+ if(!dtls1_query_mtu(s))
+ return -1;
- OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* should have something reasonable now */
+ 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 ==
blocksize = 0;
frag_off = 0;
- while( s->init_num)
+ /* s->init_num shouldn't ever be < 0...but just in case */
+ while(s->init_num > 0)
{
- curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) -
- DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
+ 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)
{
ret = BIO_flush(SSL_get_wbio(s));
if ( ret <= 0)
return ret;
- curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
- mac_size - blocksize;
+ 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;
+ }
}
- if ( s->init_num > curr_mtu)
+ /* 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)
s->init_off -= DTLS1_HM_HEADER_LENGTH;
s->init_num += DTLS1_HM_HEADER_LENGTH;
- if ( s->init_num > curr_mtu)
+ /* 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]);
-
- OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH);
}
ret=dtls1_write_bytes(s,type,&s->init_buf->data[s->init_off],
* is fine and wait for an alert to handle the
* retransmit
*/
- if ( BIO_ctrl(SSL_get_wbio(s),
+ if ( retry && BIO_ctrl(SSL_get_wbio(s),
BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
- s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+ {
+ 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
{
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 */
+ 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;
static int
dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
{
- /* (0) check whether the desired fragment is available
+ /*-
+ * (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
return(-1);
}
-/* for these 2 messages, we need to
+/*-
+ * 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
}
#ifndef OPENSSL_NO_HEARTBEATS
- if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */
+ /* done, no need to send a retransmit */
+ if (!SSL_in_init(s) && !s->tlsext_hb_pending)
#else
- if (!SSL_in_init(s)) /* done, no need to send a retransmit */
+ /* done, no need to send a retransmit */
+ if (!SSL_in_init(s))
#endif
{
BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
struct dtls1_retransmit_state saved_state;
unsigned char save_write_sequence[8];
- /*
+ /*-
OPENSSL_assert(s->init_num == 0);
OPENSSL_assert(s->init_off == 0);
*/
return p;
}
-unsigned int
-dtls1_min_mtu(void)
+unsigned int
+dtls1_link_min_mtu(void)
{
return (g_probable_mtu[(sizeof(g_probable_mtu) /
sizeof(g_probable_mtu[0])) - 1]);
}
-static unsigned int
-dtls1_guess_mtu(unsigned int curr_mtu)
+unsigned int
+dtls1_min_mtu(SSL *s)
{
- unsigned int i;
-
- if ( curr_mtu == 0 )
- return g_probable_mtu[0] ;
-
- for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++)
- if ( curr_mtu > g_probable_mtu[i])
- return g_probable_mtu[i];
-
- return curr_mtu;
+ return dtls1_link_min_mtu()-BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
}
+
void
dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
{
/* Read type and payload length first */
if (1 + 2 + 16 > s->s3->rrec.length)
return 0; /* silently discard */
+ if (s->s3->rrec.length > SSL3_RT_MAX_PLAIN_LENGTH)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+
hbtype = *p++;
n2s(p, payload);
if (1 + 2 + payload + 16 > s->s3->rrec.length)
* payload, plus padding
*/
buffer = OPENSSL_malloc(write_length);
+ if (buffer == NULL)
+ return -1;
bp = buffer;
/* Enter response type, length and copy payload */
*/
OPENSSL_assert(payload + padding <= 16381);
- /* Create HeartBeat message, we just use a sequence number
+ /*-
+ * Create HeartBeat message, we just use a sequence number
* as payload to distuingish different messages and add
* some random stuff.
* - Message Type, 1 byte
* - Padding
*/
buf = OPENSSL_malloc(1 + 2 + payload + padding);
+ if (buf == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
p = buf;
/* Message Type */
*p++ = TLS1_HB_REQUEST;