Add public api to create token cache for QUIC NEW_TOKENS

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26517)
This commit is contained in:
Neil Horman 2025-01-15 11:40:49 -05:00
parent e73f330e99
commit b1828dc23a
6 changed files with 156 additions and 0 deletions

View File

@ -24,6 +24,12 @@ __owur SSL *ossl_quic_new_listener(SSL_CTX *ctx, uint64_t flags);
__owur SSL *ossl_quic_new_listener_from(SSL *ssl, uint64_t flags);
__owur SSL *ossl_quic_new_from_listener(SSL *ssl, uint64_t flags);
__owur SSL *ossl_quic_new_domain(SSL_CTX *ctx, uint64_t flags);
SSL_TOKEN_STORE_HANDLE *ossl_quic_new_token_store(void);
void ossl_quic_free_token_store(SSL_TOKEN_STORE_HANDLE *hdl);
SSL_TOKEN_STORE_HANDLE *ossl_quic_get_token_store(SSL_CTX *ctx);
int ossl_quic_set_token_store(SSL_CTX *ctx, SSL_TOKEN_STORE_HANDLE *hdl);
__owur int ossl_quic_init(SSL *s);
void ossl_quic_deinit(SSL *s);
void ossl_quic_free(SSL *s);

View File

@ -2307,6 +2307,10 @@ __owur int SSL_set1_initial_peer_addr(SSL *s, const BIO_ADDR *peer_addr);
__owur SSL *SSL_get0_connection(SSL *s);
__owur int SSL_is_connection(SSL *s);
typedef void SSL_TOKEN_STORE_HANDLE;
__owur SSL_TOKEN_STORE_HANDLE *SSL_CTX_get0_token_store(SSL_CTX *ctx);
__owur int SSL_CTX_set_token_store(SSL_CTX *ctx, SSL_TOKEN_STORE_HANDLE *hdl);
__owur int SSL_is_listener(SSL *ssl);
__owur SSL *SSL_get0_listener(SSL *s);
#define SSL_LISTENER_FLAG_NO_ACCEPT (1UL << 0)

View File

@ -4623,6 +4623,124 @@ err:
return NULL;
}
/*
* Token store management
*/
typedef struct quic_token_st {
uint8_t *hashkey;
size_t hashkey_len;
uint8_t *token;
size_t token_len;
} QUIC_TOKEN;
DEFINE_LHASH_OF_EX(QUIC_TOKEN);
typedef struct ssl_token_store_st {
LHASH_OF(QUIC_TOKEN) *cache;
CRYPTO_REF_COUNT references;
CRYPTO_MUTEX *mutex;
} SSL_TOKEN_STORE;
static uint64_t fnv1a_hash_token(uint8_t *key, size_t len)
{
uint64_t hash = 0xcbf29ce484222325ULL;
size_t i;
for (i = 0; i < len; i++) {
hash ^= key[i];
hash *= 0x00000100000001B3ULL;
}
return hash;
}
static unsigned long quic_token_hash(const QUIC_TOKEN *item)
{
return (unsigned long)fnv1a_hash_token(item->hashkey, item->hashkey_len);
}
static int quic_token_cmp(const QUIC_TOKEN *a, const QUIC_TOKEN *b)
{
if (a->hashkey_len != b->hashkey_len)
return 1;
return memcmp(a->hashkey, b->hashkey, a->hashkey_len);
}
SSL_TOKEN_STORE_HANDLE *ossl_quic_new_token_store(void)
{
int ok = 0;
SSL_TOKEN_STORE *newcache = OPENSSL_zalloc(sizeof(SSL_TOKEN_STORE));
if (newcache == NULL)
goto out;
newcache->cache = lh_QUIC_TOKEN_new(quic_token_hash, quic_token_cmp);
if (newcache->cache == NULL)
goto out;
#if defined(OPENSSL_THREADS)
if ((newcache->mutex = ossl_crypto_mutex_new()) == NULL)
goto out;
#endif
if (!CRYPTO_NEW_REF(&newcache->references, 1))
goto out;
ok = 1;
out:
if (!ok) {
ossl_quic_free_token_store(newcache);
newcache = NULL;
}
return (SSL_TOKEN_STORE_HANDLE *)newcache;
}
static void free_quic_token(QUIC_TOKEN *token)
{
OPENSSL_free(token);
}
void ossl_quic_free_token_store(SSL_TOKEN_STORE_HANDLE *hdl)
{
int refs;
SSL_TOKEN_STORE *c = (SSL_TOKEN_STORE *)hdl;
if (c == NULL)
return;
if (!CRYPTO_DOWN_REF(&c->references, &refs))
return;
if (refs > 0)
return;
/* last reference, we can clean up */
ossl_crypto_mutex_free(&c->mutex);
lh_QUIC_TOKEN_doall(c->cache, free_quic_token);
lh_QUIC_TOKEN_free(c->cache);
OPENSSL_free(c);
return;
}
SSL_TOKEN_STORE_HANDLE *ossl_quic_get_token_store(SSL_CTX *ctx)
{
return ctx->tokencache;
}
int ossl_quic_set_token_store(SSL_CTX *ctx, SSL_TOKEN_STORE_HANDLE *hdl)
{
SSL_TOKEN_STORE *new = hdl;
SSL_TOKEN_STORE_HANDLE *old = ctx->tokencache;
int ref;
if (!CRYPTO_UP_REF(&new->references, &ref))
return 0;
ctx->tokencache = new;
ossl_quic_free_token_store(old);
return 1;
}
/*
* SSL_get_accept_connection_queue_len
* -----------------------------------

View File

@ -4214,6 +4214,9 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
ret->num_tickets = 2;
# ifndef OPENSSL_NO_QUIC
/* only create a cache for client CTX-es */
if (meth == OSSL_QUIC_client_method())
ret->tokencache = ossl_quic_new_token_store();
ret->domain_flags = 0;
if (IS_QUIC_METHOD(meth)) {
# if defined(OPENSSL_THREADS)
@ -4418,6 +4421,10 @@ void SSL_CTX_free(SSL_CTX *a)
OPENSSL_free(a->qlog_title);
#endif
#ifndef OPENSSL_NO_QUIC
ossl_quic_free_token_store(a->tokencache);
#endif
OPENSSL_free(a);
}
@ -7979,6 +7986,24 @@ SSL *SSL_new_from_listener(SSL *ssl, uint64_t flags)
#endif
}
SSL_TOKEN_STORE_HANDLE *SSL_CTX_get0_token_store(SSL_CTX *ctx)
{
#ifndef OPENSSL_NO_QUIC
return ossl_quic_get_token_store(ctx);
#else
return NULL;
#endif
}
int SSL_CTX_set_token_store(SSL_CTX *ctx, SSL_TOKEN_STORE_HANDLE *hdl)
{
#ifndef OPENSSL_NO_QUIC
return ossl_quic_set_token_store(ctx, hdl);
#else
return 0;
#endif
}
SSL *SSL_accept_connection(SSL *ssl, uint64_t flags)
{
#ifndef OPENSSL_NO_QUIC

View File

@ -1201,6 +1201,7 @@ struct ssl_ctx_st {
# ifndef OPENSSL_NO_QUIC
uint64_t domain_flags;
SSL_TOKEN_STORE_HANDLE *tokencache;
# endif
# ifndef OPENSSL_NO_QLOG

View File

@ -605,3 +605,5 @@ SSL_CTX_set_domain_flags ? 3_5_0 EXIST::FUNCTION:
SSL_CTX_get_domain_flags ? 3_5_0 EXIST::FUNCTION:
SSL_get_domain_flags ? 3_5_0 EXIST::FUNCTION:
SSL_CTX_set_new_pending_conn_cb ? 3_5_0 EXIST::FUNCTION:
SSL_CTX_get0_token_store ? 3_5_0 EXIST::FUNCTION:
SSL_CTX_set_token_store ? 3_5_0 EXIST::FUNCTION: