Home | History | Annotate | Download | only in ssl
      1 /*
      2  * DTLS implementation written by Nagendra Modadugu
      3  * (nagendra (at) cs.stanford.edu) for the OpenSSL project 2005.
      4  */
      5 /* ====================================================================
      6  * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in
     17  *    the documentation and/or other materials provided with the
     18  *    distribution.
     19  *
     20  * 3. All advertising materials mentioning features or use of this
     21  *    software must display the following acknowledgment:
     22  *    "This product includes software developed by the OpenSSL Project
     23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
     24  *
     25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     26  *    endorse or promote products derived from this software without
     27  *    prior written permission. For written permission, please contact
     28  *    openssl-core (at) OpenSSL.org.
     29  *
     30  * 5. Products derived from this software may not be called "OpenSSL"
     31  *    nor may "OpenSSL" appear in their names without prior written
     32  *    permission of the OpenSSL Project.
     33  *
     34  * 6. Redistributions of any form whatsoever must retain the following
     35  *    acknowledgment:
     36  *    "This product includes software developed by the OpenSSL Project
     37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
     38  *
     39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     50  * OF THE POSSIBILITY OF SUCH DAMAGE.
     51  * ====================================================================
     52  *
     53  * This product includes cryptographic software written by Eric Young
     54  * (eay (at) cryptsoft.com).  This product includes software written by Tim
     55  * Hudson (tjh (at) cryptsoft.com). */
     56 
     57 #include <openssl/ssl.h>
     58 
     59 #include <assert.h>
     60 #include <limits.h>
     61 #include <string.h>
     62 
     63 #include <openssl/err.h>
     64 #include <openssl/mem.h>
     65 #include <openssl/nid.h>
     66 
     67 #include "../crypto/internal.h"
     68 #include "internal.h"
     69 
     70 
     71 
     72 /* DTLS1_MTU_TIMEOUTS is the maximum number of timeouts to expire
     73  * before starting to decrease the MTU. */
     74 #define DTLS1_MTU_TIMEOUTS                     2
     75 
     76 /* DTLS1_MAX_TIMEOUTS is the maximum number of timeouts to expire
     77  * before failing the DTLS handshake. */
     78 #define DTLS1_MAX_TIMEOUTS                     12
     79 
     80 int dtls1_new(SSL *ssl) {
     81   if (!ssl3_new(ssl)) {
     82     return 0;
     83   }
     84   DTLS1_STATE *d1 = (DTLS1_STATE *)OPENSSL_malloc(sizeof *d1);
     85   if (d1 == NULL) {
     86     ssl3_free(ssl);
     87     return 0;
     88   }
     89   OPENSSL_memset(d1, 0, sizeof *d1);
     90 
     91   ssl->d1 = d1;
     92 
     93   /* Set the version to the highest supported version.
     94    *
     95    * TODO(davidben): Move this field into |s3|, have it store the normalized
     96    * protocol version, and implement this pre-negotiation quirk in |SSL_version|
     97    * at the API boundary rather than in internal state. */
     98   ssl->version = DTLS1_2_VERSION;
     99   return 1;
    100 }
    101 
    102 void dtls1_free(SSL *ssl) {
    103   ssl3_free(ssl);
    104 
    105   if (ssl == NULL || ssl->d1 == NULL) {
    106     return;
    107   }
    108 
    109   dtls_clear_incoming_messages(ssl);
    110   dtls_clear_outgoing_messages(ssl);
    111 
    112   OPENSSL_free(ssl->d1);
    113   ssl->d1 = NULL;
    114 }
    115 
    116 void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) {
    117   ssl->initial_timeout_duration_ms = duration_ms;
    118 }
    119 
    120 void dtls1_start_timer(SSL *ssl) {
    121   /* If timer is not set, initialize duration (by default, 1 second) */
    122   if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
    123     ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
    124   }
    125 
    126   /* Set timeout to current time */
    127   ssl_get_current_time(ssl, &ssl->d1->next_timeout);
    128 
    129   /* Add duration to current time */
    130   ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration_ms / 1000;
    131   ssl->d1->next_timeout.tv_usec += (ssl->d1->timeout_duration_ms % 1000) * 1000;
    132   if (ssl->d1->next_timeout.tv_usec >= 1000000) {
    133     ssl->d1->next_timeout.tv_sec++;
    134     ssl->d1->next_timeout.tv_usec -= 1000000;
    135   }
    136 }
    137 
    138 int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out) {
    139   if (!SSL_is_dtls(ssl)) {
    140     return 0;
    141   }
    142 
    143   /* If no timeout is set, just return NULL */
    144   if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
    145     return 0;
    146   }
    147 
    148   struct OPENSSL_timeval timenow;
    149   ssl_get_current_time(ssl, &timenow);
    150 
    151   /* If timer already expired, set remaining time to 0 */
    152   if (ssl->d1->next_timeout.tv_sec < timenow.tv_sec ||
    153       (ssl->d1->next_timeout.tv_sec == timenow.tv_sec &&
    154        ssl->d1->next_timeout.tv_usec <= timenow.tv_usec)) {
    155     OPENSSL_memset(out, 0, sizeof(*out));
    156     return 1;
    157   }
    158 
    159   /* Calculate time left until timer expires */
    160   struct OPENSSL_timeval ret;
    161   OPENSSL_memcpy(&ret, &ssl->d1->next_timeout, sizeof(ret));
    162   ret.tv_sec -= timenow.tv_sec;
    163   if (ret.tv_usec >= timenow.tv_usec) {
    164     ret.tv_usec -= timenow.tv_usec;
    165   } else {
    166     ret.tv_usec = 1000000 + ret.tv_usec - timenow.tv_usec;
    167     ret.tv_sec--;
    168   }
    169 
    170   /* If remaining time is less than 15 ms, set it to 0 to prevent issues
    171    * because of small divergences with socket timeouts. */
    172   if (ret.tv_sec == 0 && ret.tv_usec < 15000) {
    173     OPENSSL_memset(&ret, 0, sizeof(ret));
    174   }
    175 
    176   /* Clamp the result in case of overflow. */
    177   if (ret.tv_sec > INT_MAX) {
    178     assert(0);
    179     out->tv_sec = INT_MAX;
    180   } else {
    181     out->tv_sec = ret.tv_sec;
    182   }
    183 
    184   out->tv_usec = ret.tv_usec;
    185   return 1;
    186 }
    187 
    188 int dtls1_is_timer_expired(SSL *ssl) {
    189   struct timeval timeleft;
    190 
    191   /* Get time left until timeout, return false if no timer running */
    192   if (!DTLSv1_get_timeout(ssl, &timeleft)) {
    193     return 0;
    194   }
    195 
    196   /* Return false if timer is not expired yet */
    197   if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) {
    198     return 0;
    199   }
    200 
    201   /* Timer expired, so return true */
    202   return 1;
    203 }
    204 
    205 void dtls1_double_timeout(SSL *ssl) {
    206   ssl->d1->timeout_duration_ms *= 2;
    207   if (ssl->d1->timeout_duration_ms > 60000) {
    208     ssl->d1->timeout_duration_ms = 60000;
    209   }
    210   dtls1_start_timer(ssl);
    211 }
    212 
    213 void dtls1_stop_timer(SSL *ssl) {
    214   /* Reset everything */
    215   ssl->d1->num_timeouts = 0;
    216   OPENSSL_memset(&ssl->d1->next_timeout, 0, sizeof(ssl->d1->next_timeout));
    217   ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
    218 
    219   /* Clear retransmission buffer */
    220   dtls_clear_outgoing_messages(ssl);
    221 }
    222 
    223 int dtls1_check_timeout_num(SSL *ssl) {
    224   ssl->d1->num_timeouts++;
    225 
    226   /* Reduce MTU after 2 unsuccessful retransmissions */
    227   if (ssl->d1->num_timeouts > DTLS1_MTU_TIMEOUTS &&
    228       !(SSL_get_options(ssl) & SSL_OP_NO_QUERY_MTU)) {
    229     long mtu = BIO_ctrl(ssl->wbio, BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL);
    230     if (mtu >= 0 && mtu <= (1 << 30) && (unsigned)mtu >= dtls1_min_mtu()) {
    231       ssl->d1->mtu = (unsigned)mtu;
    232     }
    233   }
    234 
    235   if (ssl->d1->num_timeouts > DTLS1_MAX_TIMEOUTS) {
    236     /* fail the connection, enough alerts have been sent */
    237     OPENSSL_PUT_ERROR(SSL, SSL_R_READ_TIMEOUT_EXPIRED);
    238     return -1;
    239   }
    240 
    241   return 0;
    242 }
    243 
    244 int DTLSv1_handle_timeout(SSL *ssl) {
    245   ssl_reset_error_state(ssl);
    246 
    247   if (!SSL_is_dtls(ssl)) {
    248     return -1;
    249   }
    250 
    251   /* if no timer is expired, don't do anything */
    252   if (!dtls1_is_timer_expired(ssl)) {
    253     return 0;
    254   }
    255 
    256   dtls1_double_timeout(ssl);
    257 
    258   if (dtls1_check_timeout_num(ssl) < 0) {
    259     return -1;
    260   }
    261 
    262   dtls1_start_timer(ssl);
    263   return dtls1_retransmit_outgoing_messages(ssl);
    264 }
    265