Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / lib / gnutls_dtls.h
1 /*
2  * Copyright (C) 2009-2012 Free Software Foundation, Inc.
3  *
4  * Author: Jonathan Bastien-Filiatrault
5  *
6  * This file is part of GNUTLS.
7  *
8  * The GNUTLS library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 #ifndef DTLS_H
24 #define DTLS_H
25
26 #include <config.h>
27 #include <gnutls_int.h>
28 #include <gnutls_buffers.h>
29 #include <gnutls_mbuffers.h>
30 #include <gnutls_constate.h>
31
32 int _dtls_transmit(gnutls_session_t session);
33 int _dtls_record_check(struct record_parameters_st *rp, uint64 * _seq);
34 void _dtls_reset_hsk_state(gnutls_session_t session);
35
36 #define MAX_DTLS_TIMEOUT 60000
37
38
39 #define RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, r) { \
40   struct timespec now; \
41   unsigned int diff; \
42   gettime(&now); \
43    \
44   diff = timespec_sub_ms(&now, &session->internals.dtls.handshake_start_time); \
45   if (diff > session->internals.dtls.total_timeout_ms) \
46     { \
47       _gnutls_dtls_log("Session timeout: %u ms\n", diff); \
48       return gnutls_assert_val(GNUTLS_E_TIMEDOUT); \
49     } \
50   else \
51     { \
52       int rr; \
53       if (r != GNUTLS_E_INTERRUPTED) rr = GNUTLS_E_AGAIN; \
54       else rr = r; \
55       if (session->internals.dtls.blocking != 0) \
56         millisleep(50); \
57       return gnutls_assert_val(rr); \
58     } \
59   }
60
61
62 int _dtls_wait_and_retransmit(gnutls_session_t session);
63
64 /* returns true or false depending on whether we need to
65  * handle asynchronously handshake data.
66  */
67 inline static int _dtls_is_async(gnutls_session_t session)
68 {
69         if ((session->security_parameters.entity == GNUTLS_SERVER
70              && session->internals.resumed == RESUME_FALSE)
71             || (session->security_parameters.entity == GNUTLS_CLIENT
72                 && session->internals.resumed == RESUME_TRUE))
73                 return 1;
74         else
75                 return 0;
76 }
77
78 inline static void _dtls_async_timer_init(gnutls_session_t session)
79 {
80         if (_dtls_is_async(session)) {
81                 _gnutls_dtls_log
82                     ("DTLS[%p]: Initializing timer for handshake state.\n",
83                      session);
84                 session->internals.dtls.async_term =
85                     gnutls_time(0) + MAX_DTLS_TIMEOUT / 1000;
86         } else {
87                 _dtls_reset_hsk_state(session);
88                 _gnutls_handshake_io_buffer_clear(session);
89                 _gnutls_epoch_gc(session);
90                 session->internals.dtls.async_term = 0;
91         }
92 }
93
94 void _dtls_async_timer_delete(gnutls_session_t session);
95
96 /* Checks whether it is time to terminate the timer
97  */
98 inline static void _dtls_async_timer_check(gnutls_session_t session)
99 {
100         if (!IS_DTLS(session))
101                 return;
102
103         if (session->internals.dtls.async_term != 0) {
104                 time_t now = time(0);
105
106                 /* check if we need to expire the queued handshake data */
107                 if (now > session->internals.dtls.async_term) {
108                         _dtls_async_timer_delete(session);
109                 }
110         }
111 }
112
113 /* Returns non-zero if the async timer is active */
114 inline static int _dtls_async_timer_active(gnutls_session_t session)
115 {
116         if (!IS_DTLS(session))
117                 return 0;
118
119         return session->internals.dtls.async_term;
120 }
121
122 /* This function is to be called from record layer once
123  * a handshake replay is detected. It will make sure
124  * it transmits only once per few seconds. Otherwise
125  * it is the same as _dtls_transmit().
126  */
127 inline static int _dtls_retransmit(gnutls_session_t session)
128 {
129         return _dtls_transmit(session);
130 }
131
132 #endif