diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-oauth2/oauth2-key-cache.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/lib-oauth2/oauth2-key-cache.c b/src/lib-oauth2/oauth2-key-cache.c new file mode 100644 index 0000000..e85c210 --- /dev/null +++ b/src/lib-oauth2/oauth2-key-cache.c @@ -0,0 +1,158 @@ +/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "llist.h" +#include "buffer.h" +#include "hash.h" +#include "dcrypt.h" +#include "oauth2.h" +#include "oauth2-private.h" + +struct oauth2_key_cache_entry { + const char *key_id; + struct dcrypt_public_key *pubkey; + buffer_t *hmac_key; + struct oauth2_key_cache_entry *prev, *next; +}; + +HASH_TABLE_DEFINE_TYPE(oauth2_key_cache, const char *, + struct oauth2_key_cache_entry *); + +struct oauth2_validation_key_cache { + pool_t pool; + HASH_TABLE_TYPE(oauth2_key_cache) keys; + struct oauth2_key_cache_entry *list_start; +}; + +struct oauth2_validation_key_cache *oauth2_validation_key_cache_init(void) +{ + pool_t pool = pool_alloconly_create( + MEMPOOL_GROWING"oauth2 key cache", 128); + struct oauth2_validation_key_cache *cache = + p_new(pool, struct oauth2_validation_key_cache, 1); + + cache->pool = pool; + hash_table_create(&cache->keys, pool, 8, str_hash, strcmp); + return cache; +} + +void oauth2_validation_key_cache_deinit( + struct oauth2_validation_key_cache **_cache) +{ + struct oauth2_validation_key_cache *cache = *_cache; + *_cache = NULL; + if (cache == NULL) + return; + + /* free resources */ + struct oauth2_key_cache_entry *entry = cache->list_start; + while (entry != NULL) { + if (entry->pubkey != NULL) + dcrypt_key_unref_public(&entry->pubkey); + entry = entry->next; + } + hash_table_destroy(&cache->keys); + pool_unref(&cache->pool); +} + +int oauth2_validation_key_cache_lookup_pubkey( + struct oauth2_validation_key_cache *cache, const char *key_id, + struct dcrypt_public_key **pubkey_r) +{ + if (cache == NULL) + return -1; + + struct oauth2_key_cache_entry *entry = + hash_table_lookup(cache->keys, key_id); + if (entry == NULL || entry->pubkey == NULL) + return -1; + + *pubkey_r = entry->pubkey; + return 0; +} + +int oauth2_validation_key_cache_lookup_hmac_key( + struct oauth2_validation_key_cache *cache, const char *key_id, + const buffer_t **hmac_key_r) +{ + if (cache == NULL) + return -1; + + struct oauth2_key_cache_entry *entry = + hash_table_lookup(cache->keys, key_id); + if (entry == NULL || entry->hmac_key == NULL || + entry->hmac_key->used == 0) + return -1; + + *hmac_key_r = entry->hmac_key; + return 0; +} + +void oauth2_validation_key_cache_insert_pubkey( + struct oauth2_validation_key_cache *cache, const char *key_id, + struct dcrypt_public_key *pubkey) +{ + if (cache == NULL) + return; + + struct oauth2_key_cache_entry *entry = + hash_table_lookup(cache->keys, key_id); + if (entry != NULL) { + dcrypt_key_unref_public(&entry->pubkey); + entry->pubkey = pubkey; + if (entry->hmac_key != NULL) + buffer_set_used_size(entry->hmac_key, 0); + return; + } + entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1); + entry->key_id = p_strdup(cache->pool, key_id); + entry->pubkey = pubkey; + DLLIST_PREPEND(&cache->list_start, entry); + hash_table_insert(cache->keys, entry->key_id, entry); +} + +void oauth2_validation_key_cache_insert_hmac_key( + struct oauth2_validation_key_cache *cache, const char *key_id, + const buffer_t *hmac_key) +{ + if (cache == NULL) + return; + + struct oauth2_key_cache_entry *entry = + hash_table_lookup(cache->keys, key_id); + if (entry != NULL) { + dcrypt_key_unref_public(&entry->pubkey); + if (entry->hmac_key == NULL) { + entry->hmac_key = buffer_create_dynamic( + cache->pool, hmac_key->used); + } else { + buffer_set_used_size(entry->hmac_key, 0); + } + buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used); + return; + } + entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1); + entry->key_id = p_strdup(cache->pool, key_id); + entry->hmac_key = buffer_create_dynamic(cache->pool, hmac_key->used); + buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used); + DLLIST_PREPEND(&cache->list_start, entry); + hash_table_insert(cache->keys, entry->key_id, entry); +} + +int oauth2_validation_key_cache_evict(struct oauth2_validation_key_cache *cache, + const char *key_id) +{ + if (cache == NULL) + return -1; + + struct oauth2_key_cache_entry *entry = + hash_table_lookup(cache->keys, key_id); + if (entry == NULL) + return -1; + if (entry->pubkey != NULL) + dcrypt_key_unref_public(&entry->pubkey); + DLLIST_REMOVE(&cache->list_start, entry); + hash_table_remove(cache->keys, key_id); + return 0; +} |