X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fd1_lib.c;h=d3f681ba4109606daf0a69040418c3debc599117;hp=6c594a268606d7fa6194ee866767f22e2ef51c37;hb=f0e4a860d0b350e10a1ee3898445cac85af8ea16;hpb=07016a8a3174db5caf07182930533cf88ad9b0ad diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 6c594a2686..d3f681ba41 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -1,7 +1,7 @@ /* - * Copyright 2005-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2005-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -13,12 +13,6 @@ #include #include "ssl_locl.h" -#if defined(OPENSSL_SYS_VXWORKS) -# include -#elif !defined(OPENSSL_SYS_WIN32) -# include -#endif - static void get_current_time(struct timeval *t); static int dtls1_handshake_write(SSL *s); static size_t dtls1_link_min_mtu(void); @@ -167,6 +161,8 @@ int dtls1_clear(SSL *s) DTLS_RECORD_LAYER_clear(&s->rlayer); if (s->d1) { + DTLS_timer_cb timer_cb = s->d1->timer_cb; + buffered_messages = s->d1->buffered_messages; sent_messages = s->d1->sent_messages; mtu = s->d1->mtu; @@ -176,6 +172,9 @@ int dtls1_clear(SSL *s) memset(s->d1, 0, sizeof(*s->d1)); + /* Restore the timer callback from previous state */ + s->d1->timer_cb = timer_cb; + if (s->server) { s->d1->cookie_len = sizeof(s->d1->cookie); } @@ -193,7 +192,7 @@ int dtls1_clear(SSL *s) return 0; if (s->method->version == DTLS_ANY_VERSION) - s->version = DTLS_MAX_VERSION; + s->version = DTLS_MAX_VERSION_INTERNAL; #ifndef OPENSSL_NO_DTLS1_METHOD else if (s->options & SSL_OP_CISCO_ANYCONNECT) s->client_version = s->version = DTLS1_BAD_VER; @@ -237,11 +236,13 @@ long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) ret = ssl3_ctrl(s, cmd, larg, parg); break; } - return (ret); + return ret; } void dtls1_start_timer(SSL *s) { + unsigned int sec, usec; + #ifndef OPENSSL_NO_SCTP /* Disable timer for SCTP */ if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { @@ -250,16 +251,34 @@ void dtls1_start_timer(SSL *s) } #endif - /* If timer is not set, initialize duration with 1 second */ + /* + * If timer is not set, initialize duration with 1 second or + * a user-specified value if the timer callback is installed. + */ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { - s->d1->timeout_duration = 1; + + if (s->d1->timer_cb != NULL) + s->d1->timeout_duration_us = s->d1->timer_cb(s, 0); + else + s->d1->timeout_duration_us = 1000000; } /* Set timeout to current time */ get_current_time(&(s->d1->next_timeout)); /* Add duration to current time */ - s->d1->next_timeout.tv_sec += s->d1->timeout_duration; + + sec = s->d1->timeout_duration_us / 1000000; + usec = s->d1->timeout_duration_us - (sec * 1000000); + + s->d1->next_timeout.tv_sec += sec; + s->d1->next_timeout.tv_usec += usec; + + if (s->d1->next_timeout.tv_usec >= 1000000) { + s->d1->next_timeout.tv_sec++; + s->d1->next_timeout.tv_usec -= 1000000; + } + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); } @@ -324,9 +343,9 @@ int dtls1_is_timer_expired(SSL *s) void dtls1_double_timeout(SSL *s) { - s->d1->timeout_duration *= 2; - if (s->d1->timeout_duration > 60) - s->d1->timeout_duration = 60; + s->d1->timeout_duration_us *= 2; + if (s->d1->timeout_duration_us > 60000000) + s->d1->timeout_duration_us = 60000000; dtls1_start_timer(s); } @@ -335,7 +354,7 @@ void dtls1_stop_timer(SSL *s) /* Reset everything */ memset(&s->d1->timeout, 0, sizeof(s->d1->timeout)); memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout)); - s->d1->timeout_duration = 1; + s->d1->timeout_duration_us = 1000000; BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); /* Clear retransmission buffer */ @@ -359,7 +378,8 @@ int dtls1_check_timeout_num(SSL *s) if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) { /* fail the connection, enough alerts have been sent */ - SSLerr(SSL_F_DTLS1_CHECK_TIMEOUT_NUM, SSL_R_READ_TIMEOUT_EXPIRED); + SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_DTLS1_CHECK_TIMEOUT_NUM, + SSL_R_READ_TIMEOUT_EXPIRED); return -1; } @@ -373,10 +393,15 @@ int dtls1_handle_timeout(SSL *s) return 0; } - dtls1_double_timeout(s); + if (s->d1->timer_cb != NULL) + s->d1->timeout_duration_us = s->d1->timer_cb(s, s->d1->timeout_duration_us); + else + dtls1_double_timeout(s); - if (dtls1_check_timeout_num(s) < 0) + if (dtls1_check_timeout_num(s) < 0) { + /* SSLfatal() already called */ return -1; + } s->d1->timeout.read_timeouts++; if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) { @@ -384,6 +409,7 @@ int dtls1_handle_timeout(SSL *s) } dtls1_start_timer(s); + /* Calls SSLfatal() if required */ return dtls1_retransmit_buffered_messages(s); } @@ -419,15 +445,14 @@ static void get_current_time(struct timeval *t) #ifndef OPENSSL_NO_SOCK int DTLSv1_listen(SSL *s, BIO_ADDR *client) { - int next, n, ret = 0, clearpkt = 0; + int next, n, ret = 0; unsigned char cookie[DTLS1_COOKIE_LENGTH]; unsigned char seq[SEQ_NUM_SIZE]; const unsigned char *data; - unsigned char *buf; - size_t fragoff, fraglen, msglen; + unsigned char *buf, *wbuf; + size_t fragoff, fraglen, msglen, reclen, align = 0; unsigned int rectype, versmajor, msgseq, msgtype, clientvers, cookielen; BIO *rbio, *wbio; - BUF_MEM *bufm; BIO_ADDR *tmpclient = NULL; PACKET pkt, msgpkt, msgpayload, session, cookiepkt; @@ -450,13 +475,6 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) return -1; } - /* - * We only peek at incoming ClientHello's until we're sure we are going to - * to respond with a HelloVerifyRequest. If its a ClientHello with a valid - * cookie then we leave it in the BIO for accept to handle. - */ - BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); - /* * Note: This check deliberately excludes DTLS1_BAD_VER because that version * requires the MAC to be calculated *including* the first ClientHello @@ -469,35 +487,32 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) return -1; } - if (s->init_buf == NULL) { - if ((bufm = BUF_MEM_new()) == NULL) { - SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); - return -1; - } - - if (!BUF_MEM_grow(bufm, SSL3_RT_MAX_PLAIN_LENGTH)) { - BUF_MEM_free(bufm); - SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_MALLOC_FAILURE); - return -1; - } - s->init_buf = bufm; + if (!ssl3_setup_buffers(s)) { + /* SSLerr already called */ + return -1; } - buf = (unsigned char *)s->init_buf->data; + buf = RECORD_LAYER_get_rbuf(&s->rlayer)->buf; + wbuf = RECORD_LAYER_get_wbuf(&s->rlayer)[0].buf; +#if defined(SSL3_ALIGN_PAYLOAD) +# if SSL3_ALIGN_PAYLOAD != 0 + /* + * Using SSL3_RT_HEADER_LENGTH here instead of DTLS1_RT_HEADER_LENGTH for + * consistency with ssl3_read_n. In practice it should make no difference + * for sensible values of SSL3_ALIGN_PAYLOAD because the difference between + * SSL3_RT_HEADER_LENGTH and DTLS1_RT_HEADER_LENGTH is exactly 8 + */ + align = (size_t)buf + SSL3_RT_HEADER_LENGTH; + align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD); +# endif +#endif + buf += align; do { /* Get a packet */ clear_sys_error(); - /* - * Technically a ClientHello could be SSL3_RT_MAX_PLAIN_LENGTH - * + DTLS1_RT_HEADER_LENGTH bytes long. Normally init_buf does not store - * the record header as well, but we do here. We've set up init_buf to - * be the standard size for simplicity. In practice we shouldn't ever - * receive a ClientHello as long as this. If we do it will get dropped - * in the record length check below. - */ - n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); - + n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH + + DTLS1_RT_HEADER_LENGTH); if (n <= 0) { if (BIO_should_retry(rbio)) { /* Non-blocking IO */ @@ -506,9 +521,6 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) return -1; } - /* If we hit any problems we need to clear this packet from the BIO */ - clearpkt = 1; - if (!PACKET_buf_init(&pkt, buf, n)) { SSLerr(SSL_F_DTLSV1_LISTEN, ERR_R_INTERNAL_ERROR); return -1; @@ -561,6 +573,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) SSLerr(SSL_F_DTLSV1_LISTEN, SSL_R_LENGTH_MISMATCH); goto end; } + reclen = PACKET_remaining(&msgpkt); /* * We allow data remaining at the end of the packet because there could * be a second record (but we ignore it) @@ -680,14 +693,6 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) * to resend, we just drop it. */ - /* - * Dump the read packet, we don't need it any more. Ignore return - * value - */ - BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); - BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); - BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 1, NULL); - /* Generate the cookie */ if (s->ctx->app_gen_cookie_cb == NULL || s->ctx->app_gen_cookie_cb(s, cookie, &cookielen) == 0 || @@ -706,7 +711,11 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) : s->version; /* Construct the record and message headers */ - if (!WPACKET_init(&wpkt, s->init_buf) + if (!WPACKET_init_static_len(&wpkt, + wbuf, + ssl_get_max_send_fragment(s) + + DTLS1_RT_HEADER_LENGTH, + 0) || !WPACKET_put_bytes_u8(&wpkt, SSL3_RT_HANDSHAKE) || !WPACKET_put_bytes_u16(&wpkt, version) /* @@ -764,8 +773,8 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) * plus one byte for the message content type. The source is the * last 3 bytes of the message header */ - memcpy(&buf[DTLS1_RT_HEADER_LENGTH + 1], - &buf[DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH - 3], + memcpy(&wbuf[DTLS1_RT_HEADER_LENGTH + 1], + &wbuf[DTLS1_RT_HEADER_LENGTH + DTLS1_HM_HEADER_LENGTH - 3], 3); if (s->msg_callback) @@ -789,7 +798,7 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) tmpclient = NULL; /* TODO(size_t): convert this call */ - if (BIO_write(wbio, buf, wreclen) < (int)wreclen) { + if (BIO_write(wbio, wbuf, wreclen) < (int)wreclen) { if (BIO_should_retry(wbio)) { /* * Non-blocking IO...but we're stateless, so we're just @@ -839,15 +848,13 @@ int DTLSv1_listen(SSL *s, BIO_ADDR *client) if (BIO_dgram_get_peer(rbio, client) <= 0) BIO_ADDR_clear(client); + /* Buffer the record in the processed_rcds queue */ + if (!dtls_buffer_listen_record(s, reclen, seq, align)) + return -1; + ret = 1; - clearpkt = 0; end: BIO_ADDR_free(tmpclient); - BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_PEEK_MODE, 0, NULL); - if (clearpkt) { - /* Dump this packet. Ignore return value */ - BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH); - } return ret; } #endif @@ -958,3 +965,8 @@ size_t DTLS_get_data_mtu(const SSL *s) return mtu; } + +void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb) +{ + s->d1->timer_cb = cb; +}