summaryrefslogtreecommitdiffstats
path: root/src/lib-oauth2/oauth2-key-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-oauth2/oauth2-key-cache.c')
-rw-r--r--src/lib-oauth2/oauth2-key-cache.c158
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;
+}