LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - dtls.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 328 377 87.0 %
Date: 2020-10-30 04:50:48 Functions: 19 21 90.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2009-2012 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2013 Nikos Mavrogiannopoulos
       4             :  *
       5             :  * Authors: Jonathan Bastien-Filiatrault
       6             :  *        Nikos Mavrogiannopoulos
       7             :  *
       8             :  * This file is part of GNUTLS.
       9             :  *
      10             :  * The GNUTLS library is free software; you can redistribute it and/or
      11             :  * modify it under the terms of the GNU Lesser General Public License
      12             :  * as published by the Free Software Foundation; either version 2.1 of
      13             :  * the License, or (at your option) any later version.
      14             :  *
      15             :  * This library is distributed in the hope that it will be useful, but
      16             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :  * Lesser General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU Lesser General Public License
      21             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      22             :  *
      23             :  */
      24             : 
      25             : /* Functions that relate to DTLS retransmission and reassembly.
      26             :  */
      27             : 
      28             : #include "gnutls_int.h"
      29             : #include "errors.h"
      30             : #include "debug.h"
      31             : #include "dtls.h"
      32             : #include "record.h"
      33             : #include <mbuffers.h>
      34             : #include <buffers.h>
      35             : #include <constate.h>
      36             : #include <state.h>
      37             : #include <gnutls/dtls.h>
      38             : #include <algorithms.h>
      39             : 
      40     3173430 : void _dtls_async_timer_delete(gnutls_session_t session)
      41             : {
      42     3173430 :         if (session->internals.dtls.async_term != 0) {
      43         136 :                 _gnutls_dtls_log
      44             :                     ("DTLS[%p]: Deinitializing previous handshake state.\n",
      45             :                      session);
      46         136 :                 session->internals.dtls.async_term = 0;      /* turn off "timer" */
      47             : 
      48         136 :                 _dtls_reset_hsk_state(session);
      49         136 :                 _gnutls_handshake_io_buffer_clear(session);
      50         136 :                 _gnutls_epoch_gc(session);
      51             :         }
      52     3173430 : }
      53             : 
      54             : /* This function fragments and transmits a previously buffered
      55             :  * outgoing message. It accepts mtu_data which is a buffer to
      56             :  * be reused (should be set to NULL initially).
      57             :  */
      58             : static inline int
      59        3813 : transmit_message(gnutls_session_t session,
      60             :                  mbuffer_st * bufel, uint8_t ** buf)
      61             : {
      62        3813 :         uint8_t *data, *mtu_data;
      63        3813 :         int ret = 0;
      64        3813 :         unsigned int offset, frag_len, data_size;
      65        3813 :         unsigned int mtu =
      66        3813 :             gnutls_dtls_get_data_mtu(session);
      67             : 
      68        3813 :         if (session->security_parameters.max_record_send_size < mtu)
      69           9 :                 mtu = session->security_parameters.max_record_send_size;
      70             : 
      71        3813 :         mtu -= DTLS_HANDSHAKE_HEADER_SIZE;
      72             : 
      73        3813 :         if (bufel->type == GNUTLS_CHANGE_CIPHER_SPEC) {
      74         791 :                 _gnutls_dtls_log
      75             :                     ("DTLS[%p]: Sending Packet[%u] fragment %s(%d), mtu %u\n",
      76             :                      session, bufel->handshake_sequence,
      77             :                      _gnutls_handshake2str(bufel->htype), bufel->htype, mtu);
      78             : 
      79         791 :                 return _gnutls_send_int(session, bufel->type, -1,
      80         791 :                                         bufel->epoch,
      81         791 :                                         _mbuffer_get_uhead_ptr(bufel),
      82             :                                         _mbuffer_get_uhead_size(bufel), 0);
      83             :         }
      84             : 
      85        3022 :         if (*buf == NULL)
      86        1403 :                 *buf = gnutls_malloc(mtu + DTLS_HANDSHAKE_HEADER_SIZE);
      87        3022 :         if (*buf == NULL)
      88           0 :                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
      89             : 
      90        3022 :         mtu_data = *buf;
      91             : 
      92        3022 :         data = _mbuffer_get_udata_ptr(bufel);
      93        3022 :         data_size = _mbuffer_get_udata_size(bufel);
      94             : 
      95             :         /* Write fixed headers
      96             :          */
      97             : 
      98             :         /* Handshake type */
      99        3022 :         mtu_data[0] = (uint8_t) bufel->htype;
     100             : 
     101             :         /* Total length */
     102        3022 :         _gnutls_write_uint24(data_size, &mtu_data[1]);
     103             : 
     104             :         /* Handshake sequence */
     105        3022 :         _gnutls_write_uint16(bufel->handshake_sequence, &mtu_data[4]);
     106             : 
     107             :         /* Chop up and send handshake message into mtu-size pieces. */
     108        6238 :         for (offset = 0; offset <= data_size; offset += mtu) {
     109             :                 /* Calculate fragment length */
     110        3217 :                 if (offset + mtu > data_size)
     111        3022 :                         frag_len = data_size - offset;
     112             :                 else
     113             :                         frag_len = mtu;
     114             : 
     115             :                 /* we normally allow fragments of zero length, to allow
     116             :                  * the packets which have zero size. On the others don't
     117             :                  * send such fragments */
     118        3217 :                 if (frag_len == 0 && data_size > 0) {
     119             :                         ret = 0;
     120             :                         break;
     121             :                 }
     122             : 
     123             :                 /* Fragment offset */
     124        3216 :                 _gnutls_write_uint24(offset, &mtu_data[6]);
     125             : 
     126             :                 /* Fragment length */
     127        3216 :                 _gnutls_write_uint24(frag_len, &mtu_data[9]);
     128             : 
     129        3216 :                 memcpy(&mtu_data[DTLS_HANDSHAKE_HEADER_SIZE],
     130        3216 :                        data + offset, frag_len);
     131             : 
     132        3216 :                 _gnutls_dtls_log
     133             :                     ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
     134             :                      "length: %u, offset: %u, fragment length: %u, mtu: %u\n",
     135             :                      session, bufel->handshake_sequence,
     136             :                      _gnutls_handshake2str(bufel->htype), bufel->htype,
     137             :                      data_size, offset, frag_len, mtu);
     138             : 
     139        6432 :                 ret = _gnutls_send_int(session, bufel->type, bufel->htype,
     140        3216 :                                        bufel->epoch, mtu_data,
     141        3216 :                                        DTLS_HANDSHAKE_HEADER_SIZE +
     142             :                                        frag_len, 0);
     143        3216 :                 if (ret < 0) {
     144           0 :                         gnutls_assert();
     145             :                         break;
     146             :                 }
     147             :         }
     148             : 
     149             :         return ret;
     150             : }
     151             : 
     152        1032 : static int drop_usage_count(gnutls_session_t session,
     153             :                             mbuffer_head_st * const send_buffer)
     154             : {
     155        1032 :         int ret;
     156        1032 :         mbuffer_st *cur;
     157             : 
     158        3663 :         for (cur = send_buffer->head; cur != NULL; cur = cur->next) {
     159        2631 :                 ret = _gnutls_epoch_refcount_dec(session, cur->epoch);
     160        2631 :                 if (ret < 0)
     161           0 :                         return gnutls_assert_val(ret);
     162             :         }
     163             : 
     164             :         return 0;
     165             : }
     166             : 
     167             : 
     168             : /* Checks whether the received packet contains a handshake
     169             :  * packet with sequence higher that the previously received.
     170             :  * It must be called only when an actual packet has been
     171             :  * received.
     172             :  *
     173             :  * Returns: 0 if expected, negative value otherwise.
     174             :  */
     175      566309 : static int is_next_hpacket_expected(gnutls_session_t session)
     176             : {
     177      566309 :         int ret;
     178             : 
     179             :         /* htype is arbitrary */
     180     1132620 :         ret =
     181      566309 :             _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE,
     182             :                                     GNUTLS_HANDSHAKE_FINISHED, 0);
     183      566309 :         if (ret < 0)
     184      565689 :                 return gnutls_assert_val(ret);
     185             : 
     186         620 :         ret = _gnutls_parse_record_buffered_msgs(session);
     187         620 :         if (ret < 0)
     188           0 :                 return gnutls_assert_val(ret);
     189             : 
     190         620 :         if (session->internals.handshake_recv_buffer_size > 0)
     191             :                 return 0;
     192             :         else
     193          22 :                 return
     194          22 :                     gnutls_assert_val
     195             :                     (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
     196             : }
     197             : 
     198        1032 : void _dtls_reset_hsk_state(gnutls_session_t session)
     199             : {
     200        1032 :         session->internals.dtls.flight_init = 0;
     201        1032 :         drop_usage_count(session,
     202             :                          &session->internals.handshake_send_buffer);
     203        1032 :         _mbuffer_head_clear(&session->internals.handshake_send_buffer);
     204        1032 : }
     205             : 
     206             : 
     207             : #define UPDATE_TIMER { \
     208             :       session->internals.dtls.actual_retrans_timeout_ms *= 2; \
     209             :       session->internals.dtls.actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; \
     210             :     }
     211             : 
     212             : #define RESET_TIMER \
     213             :       session->internals.dtls.actual_retrans_timeout_ms = session->internals.dtls.retrans_timeout_ms
     214             : 
     215             : #define TIMER_WINDOW session->internals.dtls.actual_retrans_timeout_ms
     216             : 
     217             : /* This function transmits the flight that has been previously
     218             :  * buffered.
     219             :  *
     220             :  * This function is called from the handshake layer and calls the
     221             :  * record layer.
     222             :  */
     223     7546340 : int _dtls_transmit(gnutls_session_t session)
     224             : {
     225     7546340 :         int ret;
     226     7546340 :         uint8_t *buf = NULL;
     227     7546340 :         unsigned int timeout;
     228             : 
     229             :         /* PREPARING -> SENDING state transition */
     230     7546340 :         mbuffer_head_st *const send_buffer =
     231             :             &session->internals.handshake_send_buffer;
     232     7546340 :         mbuffer_st *cur;
     233     7546340 :         gnutls_handshake_description_t last_type = 0;
     234     7546340 :         unsigned int diff;
     235     7546340 :         struct timespec now;
     236             : 
     237     7546340 :         gnutls_gettime(&now);
     238             : 
     239             :         /* If we have already sent a flight and we are operating in a 
     240             :          * non blocking way, check if it is time to retransmit or just
     241             :          * return.
     242             :          */
     243     7546340 :         if (session->internals.dtls.flight_init != 0
     244     7545140 :             && (session->internals.flags & GNUTLS_NONBLOCK)) {
     245             :                 /* just in case previous run was interrupted */
     246     7544910 :                 ret = _gnutls_io_write_flush(session);
     247     7544910 :                 if (ret < 0) {
     248           2 :                         gnutls_assert();
     249           2 :                         goto cleanup;
     250             :                 }
     251             : 
     252     7544900 :                 if (session->internals.dtls.last_flight == 0
     253     7546460 :                     || !_dtls_is_async(session)) {
     254             :                         /* check for ACK */
     255     7544900 :                         ret = _gnutls_io_check_recv(session, 0);
     256     7544900 :                         if (ret == GNUTLS_E_TIMEDOUT) {
     257             :                                 /* if no retransmission is required yet just return 
     258             :                                  */
     259     6978980 :                                 if (timespec_sub_ms
     260             :                                     (&now,
     261             :                                      &session->internals.dtls.
     262     6978980 :                                      last_retransmit) < TIMER_WINDOW) {
     263     6978980 :                                         gnutls_assert();
     264     6978980 :                                         goto nb_timeout;
     265             :                                 }
     266             :                         } else {        /* received something */
     267             : 
     268      565920 :                                 if (ret == 0) {
     269      565920 :                                         ret =
     270      565920 :                                             is_next_hpacket_expected
     271             :                                             (session);
     272      565920 :                                         if (ret == GNUTLS_E_AGAIN
     273      565920 :                                             || ret == GNUTLS_E_INTERRUPTED)
     274      565665 :                                                 goto nb_timeout;
     275         255 :                                         if (ret < 0
     276         255 :                                             && ret !=
     277             :                                             GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET)
     278             :                                         {
     279           0 :                                                 gnutls_assert();
     280           0 :                                                 goto cleanup;
     281             :                                         }
     282         255 :                                         if (ret == 0)
     283         255 :                                                 goto end_flight;
     284             :                                         /* if ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET retransmit */
     285             :                                 } else
     286           0 :                                         goto nb_timeout;
     287             :                         }
     288             :                 }
     289             :         }
     290             : 
     291        1559 :         do {
     292        1559 :                 timeout = TIMER_WINDOW;
     293             : 
     294        1559 :                 diff =
     295        1559 :                     timespec_sub_ms(&now,
     296             :                                     &session->internals.handshake_start_time);
     297        1559 :                 if (diff >= session->internals.handshake_timeout_ms) {
     298           1 :                         _gnutls_dtls_log("Session timeout: %u ms\n", diff);
     299           1 :                         ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
     300           1 :                         goto end_flight;
     301             :                 }
     302             : 
     303        1558 :                 diff =
     304        1558 :                     timespec_sub_ms(&now,
     305             :                                     &session->internals.dtls.
     306             :                                     last_retransmit);
     307        1558 :                 if (session->internals.dtls.flight_init == 0
     308         358 :                     || diff >= TIMER_WINDOW) {
     309        1472 :                         _gnutls_dtls_log
     310             :                             ("DTLS[%p]: %sStart of flight transmission.\n",
     311             :                              session,
     312             :                              (session->internals.dtls.flight_init ==
     313             :                               0) ? "" : "re-");
     314        5285 :                         for (cur = send_buffer->head; cur != NULL;
     315        3813 :                              cur = cur->next) {
     316        3813 :                                 ret = transmit_message(session, cur, &buf);
     317        3813 :                                 if (ret < 0) {
     318           0 :                                         gnutls_assert();
     319           0 :                                         goto end_flight;
     320             :                                 }
     321             : 
     322        3813 :                                 last_type = cur->htype;
     323             :                         }
     324        1472 :                         gnutls_gettime(&session->internals.dtls.last_retransmit);
     325             : 
     326        1472 :                         if (session->internals.dtls.flight_init == 0) {
     327        1200 :                                 session->internals.dtls.flight_init = 1;
     328        1200 :                                 RESET_TIMER;
     329        1200 :                                 timeout = TIMER_WINDOW;
     330             : 
     331        1200 :                                 if (last_type == GNUTLS_HANDSHAKE_FINISHED) {
     332             :                                         /* On the last flight we cannot ensure retransmission
     333             :                                          * from here. _dtls_wait_and_retransmit() is being called
     334             :                                          * by handshake.
     335             :                                          */
     336         599 :                                         session->internals.dtls.
     337         599 :                                             last_flight = 1;
     338             :                                 } else
     339         601 :                                         session->internals.dtls.
     340         601 :                                             last_flight = 0;
     341             :                         } else {
     342         272 :                                 UPDATE_TIMER;
     343             :                         }
     344             :                 }
     345             : 
     346        1558 :                 ret = _gnutls_io_write_flush(session);
     347        1558 :                 if (ret < 0) {
     348           2 :                         ret = gnutls_assert_val(ret);
     349           2 :                         goto cleanup;
     350             :                 }
     351             : 
     352             :                 /* last message in handshake -> no ack */
     353        1556 :                 if (session->internals.dtls.last_flight != 0) {
     354             :                         /* we don't wait here. We just return 0 and
     355             :                          * if a retransmission occurs because peer didn't receive it
     356             :                          * we rely on the record or handshake
     357             :                          * layer calling this function again.
     358             :                          */
     359         814 :                         ret = 0;
     360         814 :                         goto cleanup;
     361             :                 } else {        /* all other messages -> implicit ack (receive of next flight) */
     362             : 
     363         742 :                         if (!(session->internals.flags & GNUTLS_NONBLOCK))
     364         485 :                                 ret =
     365         485 :                                     _gnutls_io_check_recv(session,
     366             :                                                           timeout);
     367             :                         else {
     368         257 :                                 ret = _gnutls_io_check_recv(session, 0);
     369         257 :                                 if (ret == GNUTLS_E_TIMEDOUT) {
     370         248 :                                         goto nb_timeout;
     371             :                                 }
     372             :                         }
     373             : 
     374         494 :                         if (ret == 0) {
     375         389 :                                 ret = is_next_hpacket_expected(session);
     376         389 :                                 if (ret == GNUTLS_E_AGAIN
     377         389 :                                     || ret == GNUTLS_E_INTERRUPTED)
     378          24 :                                         goto nb_timeout;
     379             : 
     380         365 :                                 if (ret ==
     381             :                                     GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET) {
     382          22 :                                         ret = GNUTLS_E_TIMEDOUT;
     383          22 :                                         goto keep_up;
     384             :                                 }
     385         343 :                                 if (ret < 0) {
     386           0 :                                         gnutls_assert();
     387           0 :                                         goto cleanup;
     388             :                                 }
     389         343 :                                 goto end_flight;
     390             :                         }
     391             :                 }
     392             : 
     393         105 :               keep_up:
     394         127 :                 gnutls_gettime(&now);
     395         127 :         } while (ret == GNUTLS_E_TIMEDOUT);
     396             : 
     397           0 :         if (ret < 0) {
     398           0 :                 ret = gnutls_assert_val(ret);
     399           0 :                 goto end_flight;
     400             :         }
     401             : 
     402             :         ret = 0;
     403             : 
     404         599 :       end_flight:
     405         599 :         _gnutls_dtls_log("DTLS[%p]: End of flight transmission.\n",
     406             :                          session);
     407         599 :         _dtls_reset_hsk_state(session);
     408             : 
     409        1417 :       cleanup:
     410        1417 :         if (buf != NULL)
     411        1133 :                 gnutls_free(buf);
     412             : 
     413             :         /* SENDING -> WAITING state transition */
     414             :         return ret;
     415             : 
     416     7544920 :       nb_timeout:
     417     7544920 :         if (buf != NULL)
     418         270 :                 gnutls_free(buf);
     419             : 
     420     7544930 :         RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, ret);
     421             : }
     422             : 
     423             : /* Waits for the last flight or retransmits
     424             :  * the previous on timeout. Returns 0 on success.
     425             :  */
     426      518366 : int _dtls_wait_and_retransmit(gnutls_session_t session)
     427             : {
     428      518366 :         int ret;
     429             : 
     430      518366 :         if (!(session->internals.flags & GNUTLS_NONBLOCK))
     431         721 :                 ret = _gnutls_io_check_recv(session, TIMER_WINDOW);
     432             :         else
     433      517645 :                 ret = _gnutls_io_check_recv(session, 0);
     434             : 
     435      518366 :         if (ret == GNUTLS_E_TIMEDOUT) {
     436         247 :                 ret = _dtls_retransmit(session);
     437         247 :                 if (ret == 0) {
     438         280 :                         RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
     439             :                 } else
     440         107 :                         return gnutls_assert_val(ret);
     441             :         }
     442             : 
     443      518119 :         RESET_TIMER;
     444      518119 :         return 0;
     445             : }
     446             : 
     447             : /**
     448             :  * gnutls_dtls_set_timeouts:
     449             :  * @session: is a #gnutls_session_t type.
     450             :  * @retrans_timeout: The time at which a retransmission will occur in milliseconds
     451             :  * @total_timeout: The time at which the connection will be aborted, in milliseconds.
     452             :  *
     453             :  * This function will set the timeouts required for the DTLS handshake
     454             :  * protocol. The retransmission timeout is the time after which a
     455             :  * message from the peer is not received, the previous messages will
     456             :  * be retransmitted. The total timeout is the time after which the
     457             :  * handshake will be aborted with %GNUTLS_E_TIMEDOUT.
     458             :  *
     459             :  * The DTLS protocol recommends the values of 1 sec and 60 seconds
     460             :  * respectively, and these are the default values.
     461             :  *
     462             :  * To disable retransmissions set a @retrans_timeout larger than the @total_timeout.
     463             :  *
     464             :  * Since: 3.0
     465             :  **/
     466        1316 : void gnutls_dtls_set_timeouts(gnutls_session_t session,
     467             :                               unsigned int retrans_timeout,
     468             :                               unsigned int total_timeout)
     469             : {
     470        1316 :         if (total_timeout == GNUTLS_INDEFINITE_TIMEOUT)
     471           0 :                 session->internals.handshake_timeout_ms = 0;
     472             :         else
     473        1316 :                 session->internals.handshake_timeout_ms = total_timeout;
     474             : 
     475        1316 :         session->internals.dtls.retrans_timeout_ms = retrans_timeout;
     476        1316 : }
     477             : 
     478             : /**
     479             :  * gnutls_dtls_set_mtu:
     480             :  * @session: is a #gnutls_session_t type.
     481             :  * @mtu: The maximum transfer unit of the transport
     482             :  *
     483             :  * This function will set the maximum transfer unit of the transport
     484             :  * that DTLS packets are sent over. Note that this should exclude
     485             :  * the IP (or IPv6) and UDP headers. So for DTLS over IPv6 on an
     486             :  * Ethernet device with MTU 1500, the DTLS MTU set with this function
     487             :  * would be 1500 - 40 (IPV6 header) - 8 (UDP header) = 1452.
     488             :  *
     489             :  * Since: 3.0
     490             :  **/
     491         426 : void gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mtu)
     492             : {
     493         426 :         session->internals.dtls.mtu = MIN(mtu, DEFAULT_MAX_RECORD_SIZE);
     494         426 : }
     495             : 
     496             : /* when max is non-zero this function will return the maximum
     497             :  * overhead that this ciphersuite may introduce, e.g., the maximum
     498             :  * amount of padding required */
     499      438820 : unsigned _gnutls_record_overhead(const version_entry_st *ver,
     500             :                                  const cipher_entry_st *cipher,
     501             :                                  const mac_entry_st *mac,
     502             :                                  unsigned max)
     503             : {
     504      438820 :         int total = 0;
     505      438820 :         int ret;
     506      438820 :         int hash_len = 0;
     507             : 
     508      438820 :         if (unlikely(cipher == NULL))
     509             :                 return 0;
     510             : 
     511             :         /* 1 octet content type in the unencrypted content */
     512      438820 :         if (ver->tls13_sem)
     513      420101 :                 total++;
     514             : 
     515      438820 :         if (mac->id == GNUTLS_MAC_AEAD) {
     516      434185 :                 if (!ver->tls13_sem)
     517       14084 :                         total += _gnutls_cipher_get_explicit_iv_size(cipher);
     518             : 
     519      434185 :                 total += _gnutls_cipher_get_tag_size(cipher);
     520             :         } else {
     521             :                 /* STREAM + BLOCK have a MAC appended */
     522        4635 :                 ret = _gnutls_mac_get_algo_len(mac);
     523        4635 :                 if (unlikely(ret < 0))
     524             :                         return 0;
     525             : 
     526        4635 :                 hash_len = ret;
     527        4635 :                 total += hash_len;
     528             :         }
     529             : 
     530             :         /* Block ciphers have padding + IV */
     531      438820 :         if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) {
     532        4441 :                 int exp_iv;
     533             : 
     534        4441 :                 exp_iv = _gnutls_cipher_get_explicit_iv_size(cipher);
     535             : 
     536        4441 :                 if (max)
     537        4440 :                         total += 2*exp_iv; /* block == iv size */
     538             :                 else
     539           1 :                         total += exp_iv + 1;
     540             :         }
     541             : 
     542      438820 :         return total;
     543             : }
     544             : 
     545             : /**
     546             :  * gnutls_est_record_overhead_size:
     547             :  * @version: is a #gnutls_protocol_t value
     548             :  * @cipher: is a #gnutls_cipher_algorithm_t value
     549             :  * @mac: is a #gnutls_mac_algorithm_t value
     550             :  * @comp: is a #gnutls_compression_method_t value (ignored)
     551             :  * @flags: must be zero
     552             :  *
     553             :  * This function will return the set size in bytes of the overhead
     554             :  * due to TLS (or DTLS) per record.
     555             :  *
     556             :  * Note that this function may provide inaccurate values when TLS
     557             :  * extensions that modify the record format are negotiated. In these
     558             :  * cases a more accurate value can be obtained using gnutls_record_overhead_size() 
     559             :  * after a completed handshake.
     560             :  *
     561             :  * Since: 3.2.2
     562             :  **/
     563           0 : size_t gnutls_est_record_overhead_size(gnutls_protocol_t version,
     564             :                                        gnutls_cipher_algorithm_t cipher,
     565             :                                        gnutls_mac_algorithm_t mac,
     566             :                                        gnutls_compression_method_t comp,
     567             :                                        unsigned int flags)
     568             : {
     569           0 :         const cipher_entry_st *c;
     570           0 :         const mac_entry_st *m;
     571           0 :         const version_entry_st *v;
     572           0 :         size_t total = 0;
     573             : 
     574           0 :         c = cipher_to_entry(cipher);
     575           0 :         if (c == NULL)
     576             :                 return 0;
     577             : 
     578           0 :         m = mac_to_entry(mac);
     579           0 :         if (m == NULL)
     580             :                 return 0;
     581             : 
     582           0 :         v = version_to_entry(version);
     583           0 :         if (v == NULL)
     584             :                 return 0;
     585             : 
     586           0 :         if (v->transport == GNUTLS_STREAM)
     587             :                 total = TLS_RECORD_HEADER_SIZE;
     588             :         else
     589           0 :                 total = DTLS_RECORD_HEADER_SIZE;
     590             : 
     591           0 :         total += _gnutls_record_overhead(v, c, m, 1);
     592             : 
     593           0 :         return total;
     594             : }
     595             : 
     596             : /* returns overhead imposed by the record layer (encryption/compression)
     597             :  * etc. It does not include the record layer headers, since the caller
     598             :  * needs to cope with rounding to multiples of blocksize, and the header
     599             :  * is outside that.
     600             :  *
     601             :  * blocksize: will contain the block size when padding may be required or 1
     602             :  *
     603             :  * It may return a negative error code on error.
     604             :  */
     605      420288 : static int record_overhead_rt(gnutls_session_t session)
     606             : {
     607      420288 :         record_parameters_st *params;
     608      420288 :         int ret;
     609             : 
     610      420288 :         if (session->internals.initial_negotiation_completed == 0)
     611             :                 return GNUTLS_E_INVALID_REQUEST;
     612      420152 :         ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, &params);
     613      420152 :         if (ret < 0)
     614           0 :                 return gnutls_assert_val(ret);
     615             : 
     616      420152 :         return _gnutls_record_overhead(get_version(session), params->cipher, params->mac, 1);
     617             : }
     618             : 
     619             : /**
     620             :  * gnutls_record_overhead_size:
     621             :  * @session: is #gnutls_session_t
     622             :  *
     623             :  * This function will return the size in bytes of the overhead
     624             :  * due to TLS (or DTLS) per record. On certain occasions
     625             :  * (e.g., CBC ciphers) the returned value is the maximum
     626             :  * possible overhead.
     627             :  *
     628             :  * Since: 3.2.2
     629             :  **/
     630      420235 : size_t gnutls_record_overhead_size(gnutls_session_t session)
     631             : {
     632      420235 :         const version_entry_st *v = get_version(session);
     633      420235 :         int ret;
     634      420235 :         size_t total;
     635             : 
     636      420235 :         if (v->transport == GNUTLS_STREAM)
     637             :                 total = TLS_RECORD_HEADER_SIZE;
     638             :         else
     639           0 :                 total = DTLS_RECORD_HEADER_SIZE;
     640             : 
     641      420235 :         ret = record_overhead_rt(session);
     642      420235 :         if (ret >= 0)
     643      420099 :                 total += ret;
     644             : 
     645      420235 :         return total;
     646             : }
     647             : 
     648             : 
     649             : 
     650             : /**
     651             :  * gnutls_dtls_get_data_mtu:
     652             :  * @session: is a #gnutls_session_t type.
     653             :  *
     654             :  * This function will return the actual maximum transfer unit for
     655             :  * application data. I.e. DTLS headers are subtracted from the
     656             :  * actual MTU which is set using gnutls_dtls_set_mtu().
     657             :  *
     658             :  * Returns: the maximum allowed transfer unit.
     659             :  *
     660             :  * Since: 3.0
     661             :  **/
     662       24195 : unsigned int gnutls_dtls_get_data_mtu(gnutls_session_t session)
     663             : {
     664       24195 :         int mtu = session->internals.dtls.mtu;
     665       24195 :         record_parameters_st *params;
     666       24195 :         int ret, k, hash_size, block;
     667             : 
     668       24195 :         mtu -= RECORD_HEADER_SIZE(session);
     669             : 
     670       24195 :         if (session->internals.initial_negotiation_completed == 0)
     671       11485 :                 return mtu;
     672             : 
     673       12710 :         ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, &params);
     674       12710 :         if (ret < 0)
     675           0 :                 return mtu;
     676             : 
     677       12710 :         if (params->cipher->type == CIPHER_AEAD || params->cipher->type == CIPHER_STREAM)
     678        9239 :                 return mtu-_gnutls_record_overhead(get_version(session), params->cipher, params->mac, 0);
     679             : 
     680             :         /* CIPHER_BLOCK: in CBC ciphers guess the data MTU as it depends on residues
     681             :          */
     682        3471 :         hash_size = _gnutls_mac_get_algo_len(params->mac);
     683        3471 :         block = _gnutls_cipher_get_explicit_iv_size(params->cipher);
     684        6942 :         assert(_gnutls_cipher_get_block_size(params->cipher) == block);
     685             : 
     686        3471 :         if (params->etm) {
     687             :                 /* the maximum data mtu satisfies:
     688             :                  * data mtu (mod block) = block-1
     689             :                  * or data mtu = (k+1)*(block) - 1
     690             :                  *
     691             :                  * and data mtu + block + hash size + 1 = link_mtu
     692             :                  *     (k+2) * (block) + hash size = link_mtu
     693             :                  *
     694             :                  *     We try to find k, and thus data mtu
     695             :                  */
     696        1342 :                 k = ((mtu-hash_size)/block) - 2;
     697             : 
     698        1342 :                 return (k+1)*block - 1;
     699             :         } else {
     700             :                 /* the maximum data mtu satisfies:
     701             :                  * data mtu + hash size (mod block) = block-1
     702             :                  * or data mtu = (k+1)*(block) - hash size - 1
     703             :                  *
     704             :                  * and data mtu + block + hash size + 1 = link_mtu
     705             :                  *     (k+2) * (block) = link_mtu
     706             :                  *
     707             :                  *     We try to find k, and thus data mtu
     708             :                  */
     709        2129 :                 k = ((mtu)/block) - 2;
     710             : 
     711        2129 :                 return (k+1)*block - hash_size - 1;
     712             :         }
     713             : }
     714             : 
     715             : /**
     716             :  * gnutls_dtls_set_data_mtu:
     717             :  * @session: is a #gnutls_session_t type.
     718             :  * @mtu: The maximum unencrypted transfer unit of the session
     719             :  *
     720             :  * This function will set the maximum size of the *unencrypted* records
     721             :  * which will be sent over a DTLS session. It is equivalent to calculating
     722             :  * the DTLS packet overhead with the current encryption parameters, and
     723             :  * calling gnutls_dtls_set_mtu() with that value. In particular, this means
     724             :  * that you may need to call this function again after any negotiation or
     725             :  * renegotiation, in order to ensure that the MTU is still sufficient to
     726             :  * account for the new protocol overhead.
     727             :  *
     728             :  * In most cases you only need to call gnutls_dtls_set_mtu() with
     729             :  * the maximum MTU of your transport layer.
     730             :  *
     731             :  * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.
     732             :  *
     733             :  * Since: 3.1
     734             :  **/
     735          53 : int gnutls_dtls_set_data_mtu(gnutls_session_t session, unsigned int mtu)
     736             : {
     737          53 :         int overhead;
     738             : 
     739          53 :         overhead = record_overhead_rt(session);
     740             : 
     741             :         /* You can't call this until the session is actually running */
     742          53 :         if (overhead < 0)
     743             :                 return GNUTLS_E_INVALID_SESSION;
     744             : 
     745             :         /* Add the overhead inside the encrypted part */
     746          53 :         mtu += overhead;
     747             : 
     748             :         /* Add the *unencrypted header size */
     749          53 :         mtu += RECORD_HEADER_SIZE(session);
     750             : 
     751          53 :         gnutls_dtls_set_mtu(session, mtu);
     752          53 :         return GNUTLS_E_SUCCESS;
     753             : }
     754             : 
     755             : /**
     756             :  * gnutls_dtls_get_mtu:
     757             :  * @session: is a #gnutls_session_t type.
     758             :  *
     759             :  * This function will return the MTU size as set with
     760             :  * gnutls_dtls_set_mtu(). This is not the actual MTU
     761             :  * of data you can transmit. Use gnutls_dtls_get_data_mtu()
     762             :  * for that reason.
     763             :  *
     764             :  * Returns: the set maximum transfer unit.
     765             :  *
     766             :  * Since: 3.0
     767             :  **/
     768       20208 : unsigned int gnutls_dtls_get_mtu(gnutls_session_t session)
     769             : {
     770       20208 :         return session->internals.dtls.mtu;
     771             : }
     772             : 
     773             : /**
     774             :  * gnutls_dtls_get_timeout:
     775             :  * @session: is a #gnutls_session_t type.
     776             :  *
     777             :  * This function will return the milliseconds remaining
     778             :  * for a retransmission of the previously sent handshake
     779             :  * message. This function is useful when DTLS is used in
     780             :  * non-blocking mode, to estimate when to call gnutls_handshake()
     781             :  * if no packets have been received.
     782             :  *
     783             :  * Returns: the remaining time in milliseconds.
     784             :  *
     785             :  * Since: 3.0
     786             :  **/
     787         380 : unsigned int gnutls_dtls_get_timeout(gnutls_session_t session)
     788             : {
     789         380 :         struct timespec now;
     790         380 :         unsigned int diff;
     791             : 
     792         380 :         gnutls_gettime(&now);
     793             : 
     794         380 :         diff =
     795         380 :             timespec_sub_ms(&now,
     796             :                             &session->internals.dtls.last_retransmit);
     797         380 :         if (diff >= TIMER_WINDOW)
     798             :                 return 0;
     799             :         else
     800         211 :                 return TIMER_WINDOW - diff;
     801             : }
     802             : 
     803             : #define COOKIE_SIZE 16
     804             : #define COOKIE_MAC_SIZE 16
     805             : 
     806             : /*   MAC
     807             :  * 16 bytes
     808             :  *
     809             :  * total 19 bytes
     810             :  */
     811             : 
     812             : #define C_HASH GNUTLS_MAC_SHA1
     813             : #define C_HASH_SIZE 20
     814             : 
     815             : /**
     816             :  * gnutls_dtls_cookie_send:
     817             :  * @key: is a random key to be used at cookie generation
     818             :  * @client_data: contains data identifying the client (i.e. address)
     819             :  * @client_data_size: The size of client's data
     820             :  * @prestate: The previous cookie returned by gnutls_dtls_cookie_verify()
     821             :  * @ptr: A transport pointer to be used by @push_func
     822             :  * @push_func: A function that will be used to reply
     823             :  *
     824             :  * This function can be used to prevent denial of service
     825             :  * attacks to a DTLS server by requiring the client to
     826             :  * reply using a cookie sent by this function. That way
     827             :  * it can be ensured that a client we allocated resources
     828             :  * for (i.e. #gnutls_session_t) is the one that the 
     829             :  * original incoming packet was originated from.
     830             :  *
     831             :  * This function must be called at the first incoming packet,
     832             :  * prior to allocating any resources and must be succeeded
     833             :  * by gnutls_dtls_cookie_verify().
     834             :  *
     835             :  * Returns: the number of bytes sent, or a negative error code.  
     836             :  *
     837             :  * Since: 3.0
     838             :  **/
     839          49 : int gnutls_dtls_cookie_send(gnutls_datum_t * key, void *client_data,
     840             :                             size_t client_data_size,
     841             :                             gnutls_dtls_prestate_st * prestate,
     842             :                             gnutls_transport_ptr_t ptr,
     843             :                             gnutls_push_func push_func)
     844             : {
     845          49 :         uint8_t hvr[20 + DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE];
     846          49 :         int hvr_size = 0, ret;
     847          49 :         uint8_t digest[C_HASH_SIZE];
     848             : 
     849          49 :         if (key == NULL || key->data == NULL || key->size == 0)
     850           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     851             : 
     852             : /* send
     853             :  *  struct {
     854             :  *    ContentType type - 1 byte GNUTLS_HANDSHAKE;
     855             :  *    ProtocolVersion version; - 2 bytes (254,255)
     856             :  *    uint16 epoch; - 2 bytes (0, 0)
     857             :  *    uint48 sequence_number; - 4 bytes (0,0,0,0)
     858             :  *    uint16 length; - 2 bytes (COOKIE_SIZE+1+2)+DTLS_HANDSHAKE_HEADER_SIZE
     859             :  *    uint8_t fragment[DTLSPlaintext.length];
     860             :  *  } DTLSPlaintext;
     861             :  *
     862             :  *
     863             :  * struct {
     864             :  *    HandshakeType msg_type; 1 byte - GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST
     865             :  *    uint24 length; - COOKIE_SIZE+3
     866             :  *    uint16 message_seq; - 2 bytes (0,0)
     867             :  *    uint24 fragment_offset; - 3 bytes (0,0,0)
     868             :  *    uint24 fragment_length; - same as length
     869             :  * }
     870             :  *
     871             :  * struct {
     872             :  *   ProtocolVersion server_version;
     873             :  *   uint8_t cookie<0..32>;
     874             :  * } HelloVerifyRequest;
     875             :  */
     876             : 
     877          49 :         hvr[hvr_size++] = GNUTLS_HANDSHAKE;
     878             :         /* version */
     879          49 :         hvr[hvr_size++] = 254;
     880          49 :         hvr[hvr_size++] = 255;
     881             : 
     882             :         /* epoch + seq */
     883          49 :         memset(&hvr[hvr_size], 0, 8);
     884          49 :         hvr_size += 7;
     885          49 :         hvr[hvr_size++] = prestate->record_seq;
     886             : 
     887             :         /* length */
     888          49 :         _gnutls_write_uint16(DTLS_HANDSHAKE_HEADER_SIZE + COOKIE_SIZE + 3,
     889             :                              &hvr[hvr_size]);
     890          49 :         hvr_size += 2;
     891             : 
     892             :         /* now handshake headers */
     893          49 :         hvr[hvr_size++] = GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST;
     894          49 :         _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
     895          49 :         hvr_size += 3;
     896             : 
     897             :         /* handshake seq */
     898          49 :         hvr[hvr_size++] = 0;
     899          49 :         hvr[hvr_size++] = prestate->hsk_write_seq;
     900             : 
     901          49 :         _gnutls_write_uint24(0, &hvr[hvr_size]);
     902          49 :         hvr_size += 3;
     903             : 
     904          49 :         _gnutls_write_uint24(COOKIE_SIZE + 3, &hvr[hvr_size]);
     905          49 :         hvr_size += 3;
     906             : 
     907             :         /* version */
     908          49 :         hvr[hvr_size++] = 254;
     909          49 :         hvr[hvr_size++] = 255;
     910          49 :         hvr[hvr_size++] = COOKIE_SIZE;
     911             : 
     912          49 :         ret =
     913          49 :             _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
     914             :                              client_data_size, digest);
     915          49 :         if (ret < 0)
     916           0 :                 return gnutls_assert_val(ret);
     917             : 
     918          49 :         memcpy(&hvr[hvr_size], digest, COOKIE_MAC_SIZE);
     919          49 :         hvr_size += COOKIE_MAC_SIZE;
     920             : 
     921          49 :         ret = push_func(ptr, hvr, hvr_size);
     922          49 :         if (ret < 0)
     923           0 :                 ret = GNUTLS_E_PUSH_ERROR;
     924             : 
     925             :         return ret;
     926             : }
     927             : 
     928             : /**
     929             :  * gnutls_dtls_cookie_verify:
     930             :  * @key: is a random key to be used at cookie generation
     931             :  * @client_data: contains data identifying the client (i.e. address)
     932             :  * @client_data_size: The size of client's data
     933             :  * @_msg: An incoming message that initiates a connection.
     934             :  * @msg_size: The size of the message.
     935             :  * @prestate: The cookie of this client.
     936             :  *
     937             :  * This function will verify the received message for
     938             :  * a valid cookie. If a valid cookie is returned then
     939             :  * it should be associated with the session using
     940             :  * gnutls_dtls_prestate_set();
     941             :  *
     942             :  * This function must be called after gnutls_dtls_cookie_send().
     943             :  *
     944             :  * Returns: %GNUTLS_E_SUCCESS (0) on success, or a negative error code.  
     945             :  *
     946             :  * Since: 3.0
     947             :  **/
     948          97 : int gnutls_dtls_cookie_verify(gnutls_datum_t * key,
     949             :                               void *client_data, size_t client_data_size,
     950             :                               void *_msg, size_t msg_size,
     951             :                               gnutls_dtls_prestate_st * prestate)
     952             : {
     953          97 :         gnutls_datum_t cookie;
     954          97 :         int ret;
     955          97 :         unsigned int pos, sid_size;
     956          97 :         uint8_t *msg = _msg;
     957          97 :         uint8_t digest[C_HASH_SIZE];
     958             : 
     959          97 :         if (key == NULL || key->data == NULL || key->size == 0)
     960           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     961             : 
     962             :         /* format:
     963             :          * version - 2 bytes
     964             :          * random - 32 bytes
     965             :          * session_id - 1 byte length + content
     966             :          * cookie - 1 byte length + content
     967             :          */
     968             : 
     969          97 :         pos = 34 + DTLS_RECORD_HEADER_SIZE + DTLS_HANDSHAKE_HEADER_SIZE;
     970             : 
     971          97 :         if (msg_size < pos + 1)
     972           0 :                 return
     973           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     974             : 
     975          97 :         sid_size = msg[pos++];
     976             : 
     977          97 :         if (sid_size > 32 || msg_size < pos + sid_size + 1)
     978           0 :                 return
     979           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     980             : 
     981          97 :         pos += sid_size;
     982          97 :         cookie.size = msg[pos++];
     983             : 
     984          97 :         if (msg_size < pos + cookie.size + 1)
     985           0 :                 return
     986           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     987             : 
     988          97 :         cookie.data = &msg[pos];
     989          97 :         if (cookie.size != COOKIE_SIZE) {
     990          49 :                 if (cookie.size > 0)
     991           0 :                         _gnutls_audit_log(NULL,
     992             :                                           "Received cookie with illegal size %d. Expected %d\n",
     993             :                                           (int) cookie.size, COOKIE_SIZE);
     994          49 :                 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
     995             :         }
     996             : 
     997          48 :         ret =
     998          48 :             _gnutls_mac_fast(C_HASH, key->data, key->size, client_data,
     999             :                              client_data_size, digest);
    1000          48 :         if (ret < 0)
    1001           0 :                 return gnutls_assert_val(ret);
    1002             : 
    1003          48 :         if (memcmp(digest, cookie.data, COOKIE_MAC_SIZE) != 0)
    1004           0 :                 return gnutls_assert_val(GNUTLS_E_BAD_COOKIE);
    1005             : 
    1006          48 :         prestate->record_seq = msg[10];      /* client's record seq */
    1007          48 :         prestate->hsk_read_seq = msg[DTLS_RECORD_HEADER_SIZE + 5];   /* client's hsk seq */
    1008          48 :         prestate->hsk_write_seq = 0; /* we always send zero for this msg */
    1009             : 
    1010          48 :         return 0;
    1011             : }
    1012             : 
    1013             : /**
    1014             :  * gnutls_dtls_prestate_set:
    1015             :  * @session: a new session
    1016             :  * @prestate: contains the client's prestate
    1017             :  *
    1018             :  * This function will associate the prestate acquired by
    1019             :  * the cookie authentication with the client, with the newly 
    1020             :  * established session.
    1021             :  *
    1022             :  * This functions must be called after a successful gnutls_dtls_cookie_verify()
    1023             :  * and should be succeeded by the actual DTLS handshake using gnutls_handshake().
    1024             :  *
    1025             :  * Since: 3.0
    1026             :  **/
    1027          48 : void gnutls_dtls_prestate_set(gnutls_session_t session,
    1028             :                               gnutls_dtls_prestate_st * prestate)
    1029             : {
    1030          48 :         record_parameters_st *params;
    1031          48 :         int ret;
    1032             : 
    1033          48 :         if (prestate == NULL)
    1034           0 :                 return;
    1035             : 
    1036             :         /* we do not care about read_params, since we accept anything
    1037             :          * the peer sends.
    1038             :          */
    1039          48 :         ret = _gnutls_epoch_get(session, EPOCH_WRITE_CURRENT, &params);
    1040          48 :         if (ret < 0)
    1041             :                 return;
    1042             : 
    1043          48 :         params->write.sequence_number = prestate->record_seq;
    1044             : 
    1045          48 :         session->internals.dtls.hsk_read_seq = prestate->hsk_read_seq;
    1046          48 :         session->internals.dtls.hsk_write_seq =
    1047          48 :             prestate->hsk_write_seq + 1;
    1048             : }
    1049             : 
    1050             : /**
    1051             :  * gnutls_record_get_discarded:
    1052             :  * @session: is a #gnutls_session_t type.
    1053             :  *
    1054             :  * Returns the number of discarded packets in a
    1055             :  * DTLS connection.
    1056             :  *
    1057             :  * Returns: The number of discarded packets.
    1058             :  *
    1059             :  * Since: 3.0
    1060             :  **/
    1061           0 : unsigned int gnutls_record_get_discarded(gnutls_session_t session)
    1062             : {
    1063           0 :         return session->internals.dtls.packets_dropped;
    1064             : }

Generated by: LCOV version 1.14