summaryrefslogtreecommitdiffstats
path: root/thirdparty/mbedtls/library/ssl_cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/mbedtls/library/ssl_cache.c')
-rw-r--r--thirdparty/mbedtls/library/ssl_cache.c423
1 files changed, 258 insertions, 165 deletions
diff --git a/thirdparty/mbedtls/library/ssl_cache.c b/thirdparty/mbedtls/library/ssl_cache.c
index 21e38cd86a..772cb8fdfe 100644
--- a/thirdparty/mbedtls/library/ssl_cache.c
+++ b/thirdparty/mbedtls/library/ssl_cache.c
@@ -14,10 +14,10 @@
#if defined(MBEDTLS_SSL_CACHE_C)
#include "mbedtls/platform.h"
-#include "mbedtls/error.h"
#include "mbedtls/ssl_cache.h"
-#include "mbedtls/ssl_internal.h"
+#include "ssl_misc.h"
+#include "mbedtls/error.h"
#include <string.h>
@@ -33,76 +33,73 @@ void mbedtls_ssl_cache_init(mbedtls_ssl_cache_context *cache)
#endif
}
-int mbedtls_ssl_cache_get(void *data, mbedtls_ssl_session *session)
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_cache_find_entry(mbedtls_ssl_cache_context *cache,
+ unsigned char const *session_id,
+ size_t session_id_len,
+ mbedtls_ssl_cache_entry **dst)
{
int ret = MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND;
#if defined(MBEDTLS_HAVE_TIME)
mbedtls_time_t t = mbedtls_time(NULL);
#endif
- mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
- mbedtls_ssl_cache_entry *cur, *entry;
-
-#if defined(MBEDTLS_THREADING_C)
- if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
- return ret;
- }
-#endif
-
- cur = cache->chain;
- entry = NULL;
-
- while (cur != NULL) {
- entry = cur;
- cur = cur->next;
+ mbedtls_ssl_cache_entry *cur;
+ for (cur = cache->chain; cur != NULL; cur = cur->next) {
#if defined(MBEDTLS_HAVE_TIME)
if (cache->timeout != 0 &&
- (int) (t - entry->timestamp) > cache->timeout) {
+ (int) (t - cur->timestamp) > cache->timeout) {
continue;
}
#endif
- if (session->id_len != entry->session.id_len ||
- memcmp(session->id, entry->session.id,
- entry->session.id_len) != 0) {
+ if (session_id_len != cur->session_id_len ||
+ memcmp(session_id, cur->session_id,
+ cur->session_id_len) != 0) {
continue;
}
- ret = mbedtls_ssl_session_copy(session, &entry->session);
- if (ret != 0) {
- goto exit;
- }
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
- defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- /*
- * Restore peer certificate (without rest of the original chain)
- */
- if (entry->peer_cert.p != NULL) {
- /* `session->peer_cert` is NULL after the call to
- * mbedtls_ssl_session_copy(), because cache entries
- * have the `peer_cert` field set to NULL. */
-
- if ((session->peer_cert = mbedtls_calloc(1,
- sizeof(mbedtls_x509_crt))) == NULL) {
- ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
- goto exit;
- }
-
- mbedtls_x509_crt_init(session->peer_cert);
- if ((ret = mbedtls_x509_crt_parse(session->peer_cert, entry->peer_cert.p,
- entry->peer_cert.len)) != 0) {
- mbedtls_free(session->peer_cert);
- session->peer_cert = NULL;
- goto exit;
- }
- }
-#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ break;
+ }
+ if (cur != NULL) {
+ *dst = cur;
ret = 0;
+ }
+
+ return ret;
+}
+
+
+int mbedtls_ssl_cache_get(void *data,
+ unsigned char const *session_id,
+ size_t session_id_len,
+ mbedtls_ssl_session *session)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
+ mbedtls_ssl_cache_entry *entry;
+
+#if defined(MBEDTLS_THREADING_C)
+ if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
+ return ret;
+ }
+#endif
+
+ ret = ssl_cache_find_entry(cache, session_id, session_id_len, &entry);
+ if (ret != 0) {
goto exit;
}
+ ret = mbedtls_ssl_session_load(session,
+ entry->session,
+ entry->session_len);
+ if (ret != 0) {
+ goto exit;
+ }
+
+ ret = 0;
+
exit:
#if defined(MBEDTLS_THREADING_C)
if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
@@ -113,149 +110,251 @@ exit:
return ret;
}
-int mbedtls_ssl_cache_set(void *data, const mbedtls_ssl_session *session)
+/* zeroize a cache entry */
+static void ssl_cache_entry_zeroize(mbedtls_ssl_cache_entry *entry)
+{
+ if (entry == NULL) {
+ return;
+ }
+
+ /* zeroize and free session structure */
+ if (entry->session != NULL) {
+ mbedtls_zeroize_and_free(entry->session, entry->session_len);
+ }
+
+ /* zeroize the whole entry structure */
+ mbedtls_platform_zeroize(entry, sizeof(mbedtls_ssl_cache_entry));
+}
+
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_cache_pick_writing_slot(mbedtls_ssl_cache_context *cache,
+ unsigned char const *session_id,
+ size_t session_id_len,
+ mbedtls_ssl_cache_entry **dst)
{
- int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_HAVE_TIME)
mbedtls_time_t t = mbedtls_time(NULL), oldest = 0;
+#endif /* MBEDTLS_HAVE_TIME */
+
mbedtls_ssl_cache_entry *old = NULL;
-#endif
- mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
- mbedtls_ssl_cache_entry *cur, *prv;
int count = 0;
-
-#if defined(MBEDTLS_THREADING_C)
- if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
- return ret;
+ mbedtls_ssl_cache_entry *cur, *last;
+
+ /* Check 1: Is there already an entry with the given session ID?
+ *
+ * If yes, overwrite it.
+ *
+ * If not, `count` will hold the size of the session cache
+ * at the end of this loop, and `last` will point to the last
+ * entry, both of which will be used later. */
+
+ last = NULL;
+ for (cur = cache->chain; cur != NULL; cur = cur->next) {
+ count++;
+ if (session_id_len == cur->session_id_len &&
+ memcmp(session_id, cur->session_id, cur->session_id_len) == 0) {
+ goto found;
+ }
+ last = cur;
}
-#endif
- cur = cache->chain;
- prv = NULL;
-
- while (cur != NULL) {
- count++;
+ /* Check 2: Is there an outdated entry in the cache?
+ *
+ * If so, overwrite it.
+ *
+ * If not, remember the oldest entry in `old` for later.
+ */
#if defined(MBEDTLS_HAVE_TIME)
+ for (cur = cache->chain; cur != NULL; cur = cur->next) {
if (cache->timeout != 0 &&
(int) (t - cur->timestamp) > cache->timeout) {
- cur->timestamp = t;
- break; /* expired, reuse this slot, update timestamp */
+ goto found;
}
-#endif
-
- if (memcmp(session->id, cur->session.id, cur->session.id_len) == 0) {
- break; /* client reconnected, keep timestamp for session id */
- }
-#if defined(MBEDTLS_HAVE_TIME)
if (oldest == 0 || cur->timestamp < oldest) {
oldest = cur->timestamp;
old = cur;
}
-#endif
+ }
+#endif /* MBEDTLS_HAVE_TIME */
- prv = cur;
- cur = cur->next;
+ /* Check 3: Is there free space in the cache? */
+
+ if (count < cache->max_entries) {
+ /* Create new entry */
+ cur = mbedtls_calloc(1, sizeof(mbedtls_ssl_cache_entry));
+ if (cur == NULL) {
+ return MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ }
+
+ /* Append to the end of the linked list. */
+ if (last == NULL) {
+ cache->chain = cur;
+ } else {
+ last->next = cur;
+ }
+
+ goto found;
}
- if (cur == NULL) {
+ /* Last resort: The cache is full and doesn't contain any outdated
+ * elements. In this case, we evict the oldest one, judged by timestamp
+ * (if present) or cache-order. */
+
#if defined(MBEDTLS_HAVE_TIME)
- /*
- * Reuse oldest entry if max_entries reached
- */
- if (count >= cache->max_entries) {
- if (old == NULL) {
- /* This should only happen on an ill-configured cache
- * with max_entries == 0. */
- ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
- goto exit;
- }
-
- cur = old;
- }
+ if (old == NULL) {
+ /* This should only happen on an ill-configured cache
+ * with max_entries == 0. */
+ return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
+ }
#else /* MBEDTLS_HAVE_TIME */
- /*
- * Reuse first entry in chain if max_entries reached,
- * but move to last place
- */
- if (count >= cache->max_entries) {
- if (cache->chain == NULL) {
- ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
- goto exit;
- }
-
- cur = cache->chain;
- cache->chain = cur->next;
- cur->next = NULL;
- prv->next = cur;
- }
+ /* Reuse first entry in chain, but move to last place. */
+ if (cache->chain == NULL) {
+ /* This should never happen */
+ return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ }
+
+ old = cache->chain;
+ cache->chain = old->next;
+ old->next = NULL;
+ last->next = old;
#endif /* MBEDTLS_HAVE_TIME */
- else {
- /*
- * max_entries not reached, create new entry
- */
- cur = mbedtls_calloc(1, sizeof(mbedtls_ssl_cache_entry));
- if (cur == NULL) {
- ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
- goto exit;
- }
-
- if (prv == NULL) {
- cache->chain = cur;
- } else {
- prv->next = cur;
- }
- }
+
+ /* Now `old` points to the oldest entry to be overwritten. */
+ cur = old;
+
+found:
+
+ /* If we're reusing an entry, free it first. */
+ if (cur->session != NULL) {
+ /* `ssl_cache_entry_zeroize` would break the chain,
+ * so we reuse `old` to record `next` temporarily. */
+ old = cur->next;
+ ssl_cache_entry_zeroize(cur);
+ cur->next = old;
+ }
#if defined(MBEDTLS_HAVE_TIME)
- cur->timestamp = t;
+ cur->timestamp = t;
+#endif
+
+ *dst = cur;
+ return 0;
+}
+
+int mbedtls_ssl_cache_set(void *data,
+ unsigned char const *session_id,
+ size_t session_id_len,
+ const mbedtls_ssl_session *session)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
+ mbedtls_ssl_cache_entry *cur;
+
+ size_t session_serialized_len = 0;
+ unsigned char *session_serialized = NULL;
+
+#if defined(MBEDTLS_THREADING_C)
+ if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
+ return ret;
+ }
#endif
+
+ ret = ssl_cache_pick_writing_slot(cache,
+ session_id, session_id_len,
+ &cur);
+ if (ret != 0) {
+ goto exit;
}
-#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
- defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- /*
- * If we're reusing an entry, free its certificate first
- */
- if (cur->peer_cert.p != NULL) {
- mbedtls_free(cur->peer_cert.p);
- memset(&cur->peer_cert, 0, sizeof(mbedtls_x509_buf));
+ /* Check how much space we need to serialize the session
+ * and allocate a sufficiently large buffer. */
+ ret = mbedtls_ssl_session_save(session, NULL, 0, &session_serialized_len);
+ if (ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) {
+ goto exit;
+ }
+
+ session_serialized = mbedtls_calloc(1, session_serialized_len);
+ if (session_serialized == NULL) {
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto exit;
}
-#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-
- /* Copy the entire session; this temporarily makes a copy of the
- * X.509 CRT structure even though we only want to store the raw CRT.
- * This inefficiency will go away as soon as we implement on-demand
- * parsing of CRTs, in which case there's no need for the `peer_cert`
- * field anymore in the first place, and we're done after this call. */
- ret = mbedtls_ssl_session_copy(&cur->session, session);
+
+ /* Now serialize the session into the allocated buffer. */
+ ret = mbedtls_ssl_session_save(session,
+ session_serialized,
+ session_serialized_len,
+ &session_serialized_len);
if (ret != 0) {
goto exit;
}
-#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
- defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- /* If present, free the X.509 structure and only store the raw CRT data. */
- if (cur->session.peer_cert != NULL) {
- cur->peer_cert.p =
- mbedtls_calloc(1, cur->session.peer_cert->raw.len);
- if (cur->peer_cert.p == NULL) {
- ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
- goto exit;
- }
+ if (session_id_len > sizeof(cur->session_id)) {
+ ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+ goto exit;
+ }
+ cur->session_id_len = session_id_len;
+ memcpy(cur->session_id, session_id, session_id_len);
+
+ cur->session = session_serialized;
+ cur->session_len = session_serialized_len;
+ session_serialized = NULL;
- memcpy(cur->peer_cert.p,
- cur->session.peer_cert->raw.p,
- cur->session.peer_cert->raw.len);
- cur->peer_cert.len = session->peer_cert->raw.len;
+ ret = 0;
- mbedtls_x509_crt_free(cur->session.peer_cert);
- mbedtls_free(cur->session.peer_cert);
- cur->session.peer_cert = NULL;
+exit:
+#if defined(MBEDTLS_THREADING_C)
+ if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
+ ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
+ }
+#endif
+
+ if (session_serialized != NULL) {
+ mbedtls_zeroize_and_free(session_serialized, session_serialized_len);
+ session_serialized = NULL;
}
-#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ return ret;
+}
+
+int mbedtls_ssl_cache_remove(void *data,
+ unsigned char const *session_id,
+ size_t session_id_len)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
+ mbedtls_ssl_cache_entry *entry;
+ mbedtls_ssl_cache_entry *prev;
+
+#if defined(MBEDTLS_THREADING_C)
+ if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
+ return ret;
+ }
+#endif
+
+ ret = ssl_cache_find_entry(cache, session_id, session_id_len, &entry);
+ /* No valid entry found, exit with success */
+ if (ret != 0) {
+ ret = 0;
+ goto exit;
+ }
+
+ /* Now we remove the entry from the chain */
+ if (entry == cache->chain) {
+ cache->chain = entry->next;
+ goto free;
+ }
+ for (prev = cache->chain; prev->next != NULL; prev = prev->next) {
+ if (prev->next == entry) {
+ prev->next = entry->next;
+ break;
+ }
+ }
+
+free:
+ ssl_cache_entry_zeroize(entry);
+ mbedtls_free(entry);
ret = 0;
exit:
@@ -298,13 +397,7 @@ void mbedtls_ssl_cache_free(mbedtls_ssl_cache_context *cache)
prv = cur;
cur = cur->next;
- mbedtls_ssl_session_free(&prv->session);
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
- defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- mbedtls_free(prv->peer_cert.p);
-#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-
+ ssl_cache_entry_zeroize(prv);
mbedtls_free(prv);
}