From 5414fd525e903fe65e372735f106dcdc19109aad Mon Sep 17 00:00:00 2001 From: Thomas Pornin Date: Wed, 26 Jul 2017 15:52:38 +0200 Subject: [PATCH] Added function to forget saved session parameters (for tests). --- inc/bearssl_ssl.h | 13 ++++++++++++ src/ssl/ssl_lru.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/inc/bearssl_ssl.h b/inc/bearssl_ssl.h index d15cf55..45ac599 100644 --- a/inc/bearssl_ssl.h +++ b/inc/bearssl_ssl.h @@ -3220,6 +3220,19 @@ typedef struct { void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, unsigned char *store, size_t store_len); +/** + * \brief Forget an entry in an LRU session cache. + * + * The session cache context must have been initialised. The entry + * with the provided session ID (of exactly 32 bytes) is looked for + * in the cache; if located, it is disabled. + * + * \param cc session cache context. + * \param id session ID to forget. + */ +void br_ssl_session_cache_lru_forget( + br_ssl_session_cache_lru *cc, const unsigned char *id); + /** * \brief Context structure for a SSL server. * diff --git a/src/ssl/ssl_lru.c b/src/ssl/ssl_lru.c index 4ddc97a..7a2036b 100644 --- a/src/ssl/ssl_lru.c +++ b/src/ssl/ssl_lru.c @@ -54,6 +54,10 @@ * tree left child 4 bytes (big endian) * tree right child 4 bytes (big endian) * + * If an entry has a protocol version set to 0, then it is "disabled": + * it was a session pushed to the cache at some point, but it has + * been explicitly removed. + * * We need to keep the tree balanced because an attacker could make * handshakes, selecting some specific sessions (by reusing them) to * try to make us make an imbalanced tree that makes lookups expensive @@ -437,8 +441,18 @@ lru_load(const br_ssl_session_cache_class **ctx, mask_id(cc, params->session_id, id); x = find_node(cc, id, NULL); if (x != ADDR_NULL) { - params->version = br_dec16be( - cc->store + x + VERSION_OFF); + unsigned version; + + version = br_dec16be(cc->store + x + VERSION_OFF); + if (version == 0) { + /* + * Entry is disabled, we pretend we did not find it. + * Notably, we don't move it to the front of the + * LRU list. + */ + return 0; + } + params->version = version; params->cipher_suite = br_dec16be( cc->store + x + CIPHER_SUITE_OFF); memcpy(params->master_secret, @@ -489,3 +503,35 @@ br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, cc->tail = ADDR_NULL; cc->root = ADDR_NULL; } + +/* see bearssl_ssl.h */ +void br_ssl_session_cache_lru_forget( + br_ssl_session_cache_lru *cc, const unsigned char *id) +{ + unsigned char mid[SESSION_ID_LEN]; + uint32_t addr; + + /* + * If the cache is not initialised yet, then it is empty, and + * there is nothing to forget. + */ + if (!cc->init_done) { + return; + } + + /* + * Look for the node in the tree. If found, the entry is marked + * as "disabled"; it will be reused in due course, as it ages + * through the list. + * + * We do not go through the complex moves of actually releasing + * the entry right away because explicitly forgetting sessions + * should be a rare event, meant mostly for testing purposes, + * so this is not worth the extra code size. + */ + mask_id(cc, id, mid); + addr = find_node(cc, id, NULL); + if (addr != ADDR_NULL) { + br_enc16be(cc->store + addr + VERSION_OFF, 0); + } +}