Coverage Report

Created: 2023-03-26 07:33

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