Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/db.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS 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 <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
/* This file contains functions that manipulate a database backend for
24
 * resumed sessions.
25
 */
26
27
#include "gnutls_int.h"
28
#include "errors.h"
29
#include "db.h"
30
#include "session_pack.h"
31
#include "datum.h"
32
#include "ext/server_name.h"
33
#include <intprops.h>
34
35
/**
36
 * gnutls_db_set_retrieve_function:
37
 * @session: is a #gnutls_session_t type.
38
 * @retr_func: is the function.
39
 *
40
 * Sets the function that will be used to retrieve data from the
41
 * resumed sessions database.  This function must return a
42
 * gnutls_datum_t containing the data on success, or a gnutls_datum_t
43
 * containing null and 0 on failure.
44
 *
45
 * The datum's data must be allocated using the function
46
 * gnutls_malloc().
47
 *
48
 * The first argument to @retr_func will be null unless
49
 * gnutls_db_set_ptr() has been called.
50
 **/
51
void gnutls_db_set_retrieve_function(gnutls_session_t session,
52
             gnutls_db_retr_func retr_func)
53
0
{
54
0
  session->internals.db_retrieve_func = retr_func;
55
0
}
56
57
/**
58
 * gnutls_db_set_remove_function:
59
 * @session: is a #gnutls_session_t type.
60
 * @rem_func: is the function.
61
 *
62
 * Sets the function that will be used to remove data from the
63
 * resumed sessions database. This function must return 0 on success.
64
 *
65
 * The first argument to @rem_func will be null unless
66
 * gnutls_db_set_ptr() has been called.
67
 **/
68
void gnutls_db_set_remove_function(gnutls_session_t session,
69
           gnutls_db_remove_func rem_func)
70
0
{
71
0
  session->internals.db_remove_func = rem_func;
72
0
}
73
74
/**
75
 * gnutls_db_set_store_function:
76
 * @session: is a #gnutls_session_t type.
77
 * @store_func: is the function
78
 *
79
 * Sets the function that will be used to store data in the resumed
80
 * sessions database. This function must return 0 on success.
81
 *
82
 * The first argument to @store_func will be null unless
83
 * gnutls_db_set_ptr() has been called.
84
 **/
85
void gnutls_db_set_store_function(gnutls_session_t session,
86
          gnutls_db_store_func store_func)
87
0
{
88
0
  session->internals.db_store_func = store_func;
89
0
}
90
91
/**
92
 * gnutls_db_set_ptr:
93
 * @session: is a #gnutls_session_t type.
94
 * @ptr: is the pointer
95
 *
96
 * Sets the pointer that will be provided to db store, retrieve and
97
 * delete functions, as the first argument.
98
 **/
99
void gnutls_db_set_ptr(gnutls_session_t session, void *ptr)
100
0
{
101
0
  session->internals.db_ptr = ptr;
102
0
}
103
104
/**
105
 * gnutls_db_get_ptr:
106
 * @session: is a #gnutls_session_t type.
107
 *
108
 * Get db function pointer.
109
 *
110
 * Returns: the pointer that will be sent to db store, retrieve and
111
 *   delete functions, as the first argument.
112
 **/
113
void *gnutls_db_get_ptr(gnutls_session_t session)
114
0
{
115
0
  return session->internals.db_ptr;
116
0
}
117
118
/**
119
 * gnutls_db_set_cache_expiration:
120
 * @session: is a #gnutls_session_t type.
121
 * @seconds: is the number of seconds.
122
 *
123
 * Set the expiration time for resumed sessions. The default is 21600
124
 * (6 hours) at the time of writing.
125
 *
126
 * The maximum value that can be set using this function is 604800
127
 * (7 days).
128
 *
129
 **/
130
void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds)
131
0
{
132
0
  session->internals.expire_time = seconds;
133
0
  if (session->internals.expire_time > 604800)
134
0
    session->internals.expire_time = 604800;
135
0
}
136
137
/**
138
 * gnutls_db_get_default_cache_expiration:
139
 *
140
 * Returns the expiration time (in seconds) of stored sessions for resumption. 
141
 **/
142
unsigned gnutls_db_get_default_cache_expiration(void)
143
0
{
144
0
  return DEFAULT_EXPIRE_TIME;
145
0
}
146
147
/**
148
 * gnutls_db_check_entry:
149
 * @session: is a #gnutls_session_t type.
150
 * @session_entry: is the session data (not key)
151
 *
152
 * This function has no effect. 
153
 *
154
 * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
155
 *   expired or 0 otherwise.
156
 *
157
 * Deprecated: This function is deprecated.
158
 **/
159
int gnutls_db_check_entry(gnutls_session_t session,
160
        gnutls_datum_t session_entry)
161
0
{
162
0
  return 0;
163
0
}
164
165
/**
166
 * gnutls_db_check_entry_time:
167
 * @entry: is a pointer to a #gnutls_datum_t type.
168
 *
169
 * This function returns the time that this entry was active.
170
 * It can be used for database entry expiration.
171
 *
172
 * Returns: The time this entry was created, or zero on error.
173
 **/
174
time_t gnutls_db_check_entry_time(gnutls_datum_t *entry)
175
0
{
176
0
  uint32_t t;
177
0
  uint32_t magic;
178
179
0
  if (entry->size < 8)
180
0
    return gnutls_assert_val(0);
181
182
0
  magic = _gnutls_read_uint32(entry->data);
183
184
0
  if (magic != PACKED_SESSION_MAGIC)
185
0
    return gnutls_assert_val(0);
186
187
0
  t = _gnutls_read_uint32(&entry->data[4]);
188
189
0
  return t;
190
0
}
191
192
/**
193
 * gnutls_db_check_entry_expire_time:
194
 * @entry: is a pointer to a #gnutls_datum_t type.
195
 *
196
 * This function returns the time that this entry will expire.
197
 * It can be used for database entry expiration.
198
 *
199
 * Returns: The time this entry will expire, or zero on error.
200
 *
201
 * Since: 3.6.5
202
 **/
203
time_t gnutls_db_check_entry_expire_time(gnutls_datum_t *entry)
204
0
{
205
0
  uint32_t t;
206
0
  uint32_t e;
207
0
  uint32_t magic;
208
209
0
  if (entry->size < 12)
210
0
    return gnutls_assert_val(0);
211
212
0
  magic = _gnutls_read_uint32(entry->data);
213
214
0
  if (magic != PACKED_SESSION_MAGIC)
215
0
    return gnutls_assert_val(0);
216
217
0
  t = _gnutls_read_uint32(&entry->data[4]);
218
0
  e = _gnutls_read_uint32(&entry->data[8]);
219
220
0
  if (INT_ADD_OVERFLOW(t, e))
221
0
    return gnutls_assert_val(0);
222
223
0
  return t + e;
224
0
}
225
226
/* Checks if both db_store and db_retrieve functions have
227
 * been set up.
228
 */
229
static int db_func_is_ok(gnutls_session_t session)
230
0
{
231
0
  if (session->internals.db_store_func != NULL &&
232
0
      session->internals.db_retrieve_func != NULL)
233
0
    return 0;
234
0
  else
235
0
    return GNUTLS_E_DB_ERROR;
236
0
}
237
238
/* Stores session data to the db backend.
239
 */
240
static int store_session(gnutls_session_t session, gnutls_datum_t session_id,
241
       gnutls_datum_t session_data)
242
0
{
243
0
  int ret = 0;
244
245
0
  if (db_func_is_ok(session) != 0) {
246
0
    return GNUTLS_E_DB_ERROR;
247
0
  }
248
249
0
  if (session_data.data == NULL || session_data.size == 0) {
250
0
    gnutls_assert();
251
0
    return GNUTLS_E_INVALID_SESSION;
252
0
  }
253
254
  /* if we can't read why bother writing? */
255
0
  ret = session->internals.db_store_func(session->internals.db_ptr,
256
0
                 session_id, session_data);
257
258
0
  return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
259
0
}
260
261
int _gnutls_server_register_current_session(gnutls_session_t session)
262
0
{
263
0
  gnutls_datum_t key;
264
0
  gnutls_datum_t content;
265
0
  int ret = 0;
266
267
0
  key.data = session->security_parameters.session_id;
268
0
  key.size = session->security_parameters.session_id_size;
269
270
0
  if (!session->internals.resumable) {
271
0
    gnutls_assert();
272
0
    return GNUTLS_E_INVALID_SESSION;
273
0
  }
274
275
0
  if (session->security_parameters.session_id_size == 0) {
276
0
    gnutls_assert();
277
0
    return GNUTLS_E_INVALID_SESSION;
278
0
  }
279
280
0
  ret = _gnutls_session_pack(session, &content);
281
0
  if (ret < 0) {
282
0
    gnutls_assert();
283
0
    return ret;
284
0
  }
285
286
0
  ret = store_session(session, key, content);
287
0
  _gnutls_free_datum(&content);
288
289
0
  return ret;
290
0
}
291
292
int _gnutls_check_resumed_params(gnutls_session_t session)
293
0
{
294
0
  time_t timestamp = gnutls_time(0);
295
0
  const version_entry_st *vers;
296
297
  /* check whether the session is expired */
298
0
  if (timestamp - session->internals.resumed_security_parameters.timestamp >
299
0
        session->internals.expire_time ||
300
0
      session->internals.resumed_security_parameters.timestamp >
301
0
        timestamp)
302
0
    return gnutls_assert_val(GNUTLS_E_EXPIRED);
303
304
  /* check various parameters applicable to resumption in TLS1.2 or earlier
305
   */
306
0
  vers = get_version(session);
307
0
  if (!vers || !vers->tls13_sem) {
308
0
    if (session->internals.resumed_security_parameters
309
0
          .ext_master_secret !=
310
0
        session->security_parameters.ext_master_secret)
311
0
      return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
312
313
0
    if (!_gnutls_server_name_matches_resumed(session))
314
0
      return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
315
0
  }
316
317
0
  return 0;
318
0
}
319
320
int _gnutls_server_restore_session(gnutls_session_t session,
321
           uint8_t *session_id, int session_id_size)
322
0
{
323
0
  gnutls_datum_t data;
324
0
  gnutls_datum_t key;
325
0
  int ret;
326
327
0
  if (session_id == NULL || session_id_size == 0) {
328
0
    gnutls_assert();
329
0
    return GNUTLS_E_INVALID_REQUEST;
330
0
  }
331
332
0
  if (session->internals.premaster_set !=
333
0
      0) { /* hack for CISCO's DTLS-0.9 */
334
0
    if (session_id_size ==
335
0
          session->internals.resumed_security_parameters
336
0
            .session_id_size &&
337
0
        memcmp(session_id,
338
0
         session->internals.resumed_security_parameters
339
0
           .session_id,
340
0
         session_id_size) == 0)
341
0
      return 0;
342
0
  }
343
344
0
  key.data = session_id;
345
0
  key.size = session_id_size;
346
347
0
  if (db_func_is_ok(session) != 0) {
348
0
    gnutls_assert();
349
0
    return GNUTLS_E_INVALID_SESSION;
350
0
  }
351
352
0
  data = session->internals.db_retrieve_func(session->internals.db_ptr,
353
0
               key);
354
355
0
  if (data.data == NULL) {
356
0
    gnutls_assert();
357
0
    return GNUTLS_E_INVALID_SESSION;
358
0
  }
359
360
0
  ret = gnutls_session_set_data(session, data.data, data.size);
361
0
  gnutls_free(data.data);
362
363
0
  if (ret < 0) {
364
0
    gnutls_assert();
365
0
    return ret;
366
0
  }
367
368
  /* expiration check is performed inside */
369
0
  ret = _gnutls_check_resumed_params(session);
370
0
  if (ret < 0)
371
0
    return gnutls_assert_val(ret);
372
373
0
  return 0;
374
0
}
375
376
/**
377
 * gnutls_db_remove_session:
378
 * @session: is a #gnutls_session_t type.
379
 *
380
 * This function will remove the current session data from the
381
 * session database.  This will prevent future handshakes reusing
382
 * these session data.  This function should be called if a session
383
 * was terminated abnormally, and before gnutls_deinit() is called.
384
 *
385
 * Normally gnutls_deinit() will remove abnormally terminated
386
 * sessions.
387
 **/
388
void gnutls_db_remove_session(gnutls_session_t session)
389
0
{
390
0
  gnutls_datum_t session_id;
391
0
  int ret = 0;
392
393
0
  session_id.data = session->security_parameters.session_id;
394
0
  session_id.size = session->security_parameters.session_id_size;
395
396
0
  if (session->internals.db_remove_func == NULL) {
397
0
    gnutls_assert();
398
0
    return /* GNUTLS_E_DB_ERROR */;
399
0
  }
400
401
0
  if (session_id.data == NULL || session_id.size == 0) {
402
0
    gnutls_assert();
403
0
    return /* GNUTLS_E_INVALID_SESSION */;
404
0
  }
405
406
  /* if we can't read why bother writing? */
407
0
  ret = session->internals.db_remove_func(session->internals.db_ptr,
408
0
            session_id);
409
0
  if (ret != 0)
410
0
    gnutls_assert();
411
0
}