NCBI C++ ToolKit
ssl_cache.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * SSL session cache implementation
3  *
4  * Copyright The Mbed TLS Contributors
5  * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 /*
8  * These session callbacks use a simple chained list
9  * to store and retrieve the session information.
10  */
11 
12 #include "common.h"
13 
14 #if defined(MBEDTLS_SSL_CACHE_C)
15 
16 #include "mbedtls/platform.h"
17 
18 #include "mbedtls/ssl_cache.h"
19 #include "ssl_misc.h"
20 #include "mbedtls/error.h"
21 
22 #include <string.h>
23 
25 {
26  memset(cache, 0, sizeof(mbedtls_ssl_cache_context));
27 
28  cache->timeout = MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT;
29  cache->max_entries = MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES;
30 
31 #if defined(MBEDTLS_THREADING_C)
32  mbedtls_mutex_init(&cache->mutex);
33 #endif
34 }
35 
37 static int ssl_cache_find_entry(mbedtls_ssl_cache_context *cache,
38  unsigned char const *session_id,
39  size_t session_id_len,
41 {
43 #if defined(MBEDTLS_HAVE_TIME)
45 #endif
47 
48  for (cur = cache->chain; cur != NULL; cur = cur->next) {
49 #if defined(MBEDTLS_HAVE_TIME)
50  if (cache->timeout != 0 &&
51  (int) (t - cur->timestamp) > cache->timeout) {
52  continue;
53  }
54 #endif
55 
56  if (session_id_len != cur->session_id_len ||
57  memcmp(session_id, cur->session_id,
58  cur->session_id_len) != 0) {
59  continue;
60  }
61 
62  break;
63  }
64 
65  if (cur != NULL) {
66  *dst = cur;
67  ret = 0;
68  }
69 
70  return ret;
71 }
72 
73 
74 int mbedtls_ssl_cache_get(void *data,
75  unsigned char const *session_id,
76  size_t session_id_len,
77  mbedtls_ssl_session *session)
78 {
82 
83 #if defined(MBEDTLS_THREADING_C)
84  if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
85  return ret;
86  }
87 #endif
88 
89  ret = ssl_cache_find_entry(cache, session_id, session_id_len, &entry);
90  if (ret != 0) {
91  goto exit;
92  }
93 
94  ret = mbedtls_ssl_session_load(session,
95  entry->session,
96  entry->session_len);
97  if (ret != 0) {
98  goto exit;
99  }
100 
101  ret = 0;
102 
103 exit:
104 #if defined(MBEDTLS_THREADING_C)
105  if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
107  }
108 #endif
109 
110  return ret;
111 }
112 
113 /* zeroize a cache entry */
114 static void ssl_cache_entry_zeroize(mbedtls_ssl_cache_entry *entry)
115 {
116  if (entry == NULL) {
117  return;
118  }
119 
120  /* zeroize and free session structure */
121  if (entry->session != NULL) {
122  mbedtls_zeroize_and_free(entry->session, entry->session_len);
123  }
124 
125  /* zeroize the whole entry structure */
127 }
128 
130 static int ssl_cache_pick_writing_slot(mbedtls_ssl_cache_context *cache,
131  unsigned char const *session_id,
132  size_t session_id_len,
134 {
135 #if defined(MBEDTLS_HAVE_TIME)
136  mbedtls_time_t t = mbedtls_time(NULL), oldest = 0;
137 #endif /* MBEDTLS_HAVE_TIME */
138 
140  int count = 0;
142 
143  /* Check 1: Is there already an entry with the given session ID?
144  *
145  * If yes, overwrite it.
146  *
147  * If not, `count` will hold the size of the session cache
148  * at the end of this loop, and `last` will point to the last
149  * entry, both of which will be used later. */
150 
151  last = NULL;
152  for (cur = cache->chain; cur != NULL; cur = cur->next) {
153  count++;
154  if (session_id_len == cur->session_id_len &&
155  memcmp(session_id, cur->session_id, cur->session_id_len) == 0) {
156  goto found;
157  }
158  last = cur;
159  }
160 
161  /* Check 2: Is there an outdated entry in the cache?
162  *
163  * If so, overwrite it.
164  *
165  * If not, remember the oldest entry in `old` for later.
166  */
167 
168 #if defined(MBEDTLS_HAVE_TIME)
169  for (cur = cache->chain; cur != NULL; cur = cur->next) {
170  if (cache->timeout != 0 &&
171  (int) (t - cur->timestamp) > cache->timeout) {
172  goto found;
173  }
174 
175  if (oldest == 0 || cur->timestamp < oldest) {
176  oldest = cur->timestamp;
177  old = cur;
178  }
179  }
180 #endif /* MBEDTLS_HAVE_TIME */
181 
182  /* Check 3: Is there free space in the cache? */
183 
184  if (count < cache->max_entries) {
185  /* Create new entry */
186  cur = mbedtls_calloc(1, sizeof(mbedtls_ssl_cache_entry));
187  if (cur == NULL) {
189  }
190 
191  /* Append to the end of the linked list. */
192  if (last == NULL) {
193  cache->chain = cur;
194  } else {
195  last->next = cur;
196  }
197 
198  goto found;
199  }
200 
201  /* Last resort: The cache is full and doesn't contain any outdated
202  * elements. In this case, we evict the oldest one, judged by timestamp
203  * (if present) or cache-order. */
204 
205 #if defined(MBEDTLS_HAVE_TIME)
206  if (old == NULL) {
207  /* This should only happen on an ill-configured cache
208  * with max_entries == 0. */
210  }
211 #else /* MBEDTLS_HAVE_TIME */
212  /* Reuse first entry in chain, but move to last place. */
213  if (cache->chain == NULL) {
214  /* This should never happen */
216  }
217 
218  old = cache->chain;
219  cache->chain = old->next;
220  old->next = NULL;
221  last->next = old;
222 #endif /* MBEDTLS_HAVE_TIME */
223 
224  /* Now `old` points to the oldest entry to be overwritten. */
225  cur = old;
226 
227 found:
228 
229  /* If we're reusing an entry, free it first. */
230  if (cur->session != NULL) {
231  /* `ssl_cache_entry_zeroize` would break the chain,
232  * so we reuse `old` to record `next` temporarily. */
233  old = cur->next;
234  ssl_cache_entry_zeroize(cur);
235  cur->next = old;
236  }
237 
238 #if defined(MBEDTLS_HAVE_TIME)
239  cur->timestamp = t;
240 #endif
241 
242  *dst = cur;
243  return 0;
244 }
245 
246 int mbedtls_ssl_cache_set(void *data,
247  unsigned char const *session_id,
248  size_t session_id_len,
249  const mbedtls_ssl_session *session)
250 {
254 
255  size_t session_serialized_len = 0;
256  unsigned char *session_serialized = NULL;
257 
258 #if defined(MBEDTLS_THREADING_C)
259  if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
260  return ret;
261  }
262 #endif
263 
264  ret = ssl_cache_pick_writing_slot(cache,
265  session_id, session_id_len,
266  &cur);
267  if (ret != 0) {
268  goto exit;
269  }
270 
271  /* Check how much space we need to serialize the session
272  * and allocate a sufficiently large buffer. */
273  ret = mbedtls_ssl_session_save(session, NULL, 0, &session_serialized_len);
275  goto exit;
276  }
277 
278  session_serialized = mbedtls_calloc(1, session_serialized_len);
279  if (session_serialized == NULL) {
281  goto exit;
282  }
283 
284  /* Now serialize the session into the allocated buffer. */
285  ret = mbedtls_ssl_session_save(session,
286  session_serialized,
287  session_serialized_len,
288  &session_serialized_len);
289  if (ret != 0) {
290  goto exit;
291  }
292 
293  if (session_id_len > sizeof(cur->session_id)) {
295  goto exit;
296  }
297  cur->session_id_len = session_id_len;
298  memcpy(cur->session_id, session_id, session_id_len);
299 
300  cur->session = session_serialized;
301  cur->session_len = session_serialized_len;
302  session_serialized = NULL;
303 
304  ret = 0;
305 
306 exit:
307 #if defined(MBEDTLS_THREADING_C)
308  if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
310  }
311 #endif
312 
313  if (session_serialized != NULL) {
314  mbedtls_zeroize_and_free(session_serialized, session_serialized_len);
315  session_serialized = NULL;
316  }
317 
318  return ret;
319 }
320 
322  unsigned char const *session_id,
323  size_t session_id_len)
324 {
329 
330 #if defined(MBEDTLS_THREADING_C)
331  if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
332  return ret;
333  }
334 #endif
335 
336  ret = ssl_cache_find_entry(cache, session_id, session_id_len, &entry);
337  /* No valid entry found, exit with success */
338  if (ret != 0) {
339  ret = 0;
340  goto exit;
341  }
342 
343  /* Now we remove the entry from the chain */
344  if (entry == cache->chain) {
345  cache->chain = entry->next;
346  goto free;
347  }
348  for (prev = cache->chain; prev->next != NULL; prev = prev->next) {
349  if (prev->next == entry) {
350  prev->next = entry->next;
351  break;
352  }
353  }
354 
355 free:
356  ssl_cache_entry_zeroize(entry);
357  mbedtls_free(entry);
358  ret = 0;
359 
360 exit:
361 #if defined(MBEDTLS_THREADING_C)
362  if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
364  }
365 #endif
366 
367  return ret;
368 }
369 
370 #if defined(MBEDTLS_HAVE_TIME)
372 {
373  if (timeout < 0) {
374  timeout = 0;
375  }
376 
377  cache->timeout = timeout;
378 }
379 #endif /* MBEDTLS_HAVE_TIME */
380 
382 {
383  if (max < 0) {
384  max = 0;
385  }
386 
387  cache->max_entries = max;
388 }
389 
391 {
392  mbedtls_ssl_cache_entry *cur, *prv;
393 
394  cur = cache->chain;
395 
396  while (cur != NULL) {
397  prv = cur;
398  cur = cur->next;
399 
400  ssl_cache_entry_zeroize(prv);
401  mbedtls_free(prv);
402  }
403 
404 #if defined(MBEDTLS_THREADING_C)
405  mbedtls_mutex_free(&cache->mutex);
406 #endif
407  cache->chain = NULL;
408 }
409 
410 #endif /* MBEDTLS_SSL_CACHE_C */
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
char data[12]
Definition: iconv.c:80
#define NULL
Definition: ncbistd.hpp:225
exit(2)
EIPRangeType t
Definition: ncbi_localip.c:101
#define mbedtls_platform_zeroize
#define mbedtls_mutex_init
#define mbedtls_zeroize_and_free
#define mbedtls_mutex_free
#define mbedtls_ssl_cache_set_timeout
#define mbedtls_mutex_lock
#define mbedtls_mutex_unlock
T max(T x_, T y_)
This file contains the definitions and functions of the Mbed TLS platform abstraction layer.
#define mbedtls_free
Definition: platform.h:166
#define mbedtls_calloc
Definition: platform.h:167
#define mbedtls_time
Definition: platform_time.h:71
time_t mbedtls_time_t
Definition: platform_time.h:27
#define MBEDTLS_CHECK_RETURN_CRITICAL
Critical-failure function.
Definition: platform_util.h:77
Error to string translation.
#define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
This is a bug in the library.
Definition: error.h:100
int mbedtls_ssl_session_save(const mbedtls_ssl_session *session, unsigned char *buf, size_t buf_len, size_t *olen)
Save session structure as serialized data in a buffer.
int mbedtls_ssl_session_load(mbedtls_ssl_session *session, const unsigned char *buf, size_t len)
Load serialized session data into a session structure.
#define MBEDTLS_ERR_SSL_BAD_INPUT_DATA
Bad input parameters to function.
Definition: ssl.h:51
#define MBEDTLS_ERR_SSL_ALLOC_FAILED
Memory allocation failed.
Definition: ssl.h:112
#define MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND
Cache entry not found.
Definition: ssl.h:110
#define MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL
A buffer is too small to receive or write a message.
Definition: ssl.h:136
#define MBEDTLS_ERR_SSL_INTERNAL_ERROR
Internal error (eg, unexpected failure in lower-level module)
Definition: ssl.h:128
SSL session cache implementation.
#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT
Definition: ssl_cache.h:31
#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES
Definition: ssl_cache.h:35
int mbedtls_ssl_cache_set(void *data, unsigned char const *session_id, size_t session_id_len, const mbedtls_ssl_session *session)
Cache set callback implementation (Thread-safe if MBEDTLS_THREADING_C is enabled)
int mbedtls_ssl_cache_remove(void *data, unsigned char const *session_id, size_t session_id_len)
Remove the cache entry by the session ID (Thread-safe if MBEDTLS_THREADING_C is enabled)
void mbedtls_ssl_cache_init(mbedtls_ssl_cache_context *cache)
Initialize an SSL cache context.
void mbedtls_ssl_cache_free(mbedtls_ssl_cache_context *cache)
Free referenced items in a cache context and clear memory.
int mbedtls_ssl_cache_get(void *data, unsigned char const *session_id, size_t session_id_len, mbedtls_ssl_session *session)
Cache get callback implementation (Thread-safe if MBEDTLS_THREADING_C is enabled)
void mbedtls_ssl_cache_set_max_entries(mbedtls_ssl_cache_context *cache, int max)
Set the maximum number of cache entries (Default: MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES (50))
Internal functions shared by the SSL modules.
Cache context.
Definition: ssl_cache.h:67
This structure is used for storing cache entries.
Definition: ssl_cache.h:50
#define MBEDTLS_ERR_THREADING_MUTEX_ERROR
Locking / unlocking / free failed with error code.
Definition: threading.h:25
void free(voidpf ptr)
Modified on Mon Jul 15 05:33:54 2024 by modify_doxy.py rev. 669887