1 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "llist.h"
6 #include "buffer.h"
7 #include "hash.h"
8 #include "dcrypt.h"
9 #include "oauth2.h"
10 #include "oauth2-private.h"
11 
12 struct oauth2_key_cache_entry {
13 	const char *key_id;
14 	struct dcrypt_public_key *pubkey;
15 	buffer_t *hmac_key;
16 	struct oauth2_key_cache_entry *prev, *next;
17 };
18 
19 HASH_TABLE_DEFINE_TYPE(oauth2_key_cache, const char *,
20 		       struct oauth2_key_cache_entry *);
21 
22 struct oauth2_validation_key_cache {
23 	pool_t pool;
24 	HASH_TABLE_TYPE(oauth2_key_cache) keys;
25 	struct oauth2_key_cache_entry *list_start;
26 };
27 
oauth2_validation_key_cache_init(void)28 struct oauth2_validation_key_cache *oauth2_validation_key_cache_init(void)
29 {
30 	pool_t pool = pool_alloconly_create(
31 		MEMPOOL_GROWING"oauth2 key cache", 128);
32 	struct oauth2_validation_key_cache *cache =
33 		p_new(pool, struct oauth2_validation_key_cache, 1);
34 
35 	cache->pool = pool;
36 	hash_table_create(&cache->keys, pool, 8, str_hash, strcmp);
37 	return cache;
38 }
39 
oauth2_validation_key_cache_deinit(struct oauth2_validation_key_cache ** _cache)40 void oauth2_validation_key_cache_deinit(
41 	struct oauth2_validation_key_cache **_cache)
42 {
43 	struct oauth2_validation_key_cache *cache = *_cache;
44 	*_cache = NULL;
45 	if (cache == NULL)
46 		return;
47 
48 	/* free resources */
49 	struct oauth2_key_cache_entry *entry = cache->list_start;
50 	while (entry != NULL) {
51 		if (entry->pubkey != NULL)
52 			dcrypt_key_unref_public(&entry->pubkey);
53 		entry = entry->next;
54 	}
55 	hash_table_destroy(&cache->keys);
56 	pool_unref(&cache->pool);
57 }
58 
oauth2_validation_key_cache_lookup_pubkey(struct oauth2_validation_key_cache * cache,const char * key_id,struct dcrypt_public_key ** pubkey_r)59 int oauth2_validation_key_cache_lookup_pubkey(
60 	struct oauth2_validation_key_cache *cache, const char *key_id,
61 	struct dcrypt_public_key **pubkey_r)
62 {
63 	if (cache == NULL)
64 		return -1;
65 
66 	struct oauth2_key_cache_entry *entry =
67 		hash_table_lookup(cache->keys, key_id);
68 	if (entry == NULL || entry->pubkey == NULL)
69 		return -1;
70 
71 	*pubkey_r = entry->pubkey;
72 	return 0;
73 }
74 
oauth2_validation_key_cache_lookup_hmac_key(struct oauth2_validation_key_cache * cache,const char * key_id,const buffer_t ** hmac_key_r)75 int oauth2_validation_key_cache_lookup_hmac_key(
76 	struct oauth2_validation_key_cache *cache, const char *key_id,
77 	const buffer_t **hmac_key_r)
78 {
79 	if (cache == NULL)
80 		return -1;
81 
82 	struct oauth2_key_cache_entry *entry =
83 		hash_table_lookup(cache->keys, key_id);
84 	if (entry == NULL || entry->hmac_key == NULL ||
85 	    entry->hmac_key->used == 0)
86 		return -1;
87 
88 	*hmac_key_r = entry->hmac_key;
89 	return 0;
90 }
91 
oauth2_validation_key_cache_insert_pubkey(struct oauth2_validation_key_cache * cache,const char * key_id,struct dcrypt_public_key * pubkey)92 void oauth2_validation_key_cache_insert_pubkey(
93 	struct oauth2_validation_key_cache *cache, const char *key_id,
94 	struct dcrypt_public_key *pubkey)
95 {
96 	if (cache == NULL)
97 		return;
98 
99 	struct oauth2_key_cache_entry *entry =
100 		hash_table_lookup(cache->keys, key_id);
101 	if (entry != NULL) {
102 		dcrypt_key_unref_public(&entry->pubkey);
103 		entry->pubkey = pubkey;
104 		if (entry->hmac_key != NULL)
105 			buffer_set_used_size(entry->hmac_key, 0);
106 		return;
107 	}
108 	entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1);
109 	entry->key_id = p_strdup(cache->pool, key_id);
110 	entry->pubkey = pubkey;
111 	DLLIST_PREPEND(&cache->list_start, entry);
112 	hash_table_insert(cache->keys, entry->key_id, entry);
113 }
114 
oauth2_validation_key_cache_insert_hmac_key(struct oauth2_validation_key_cache * cache,const char * key_id,const buffer_t * hmac_key)115 void oauth2_validation_key_cache_insert_hmac_key(
116 	struct oauth2_validation_key_cache *cache, const char *key_id,
117 	const buffer_t *hmac_key)
118 {
119 	if (cache == NULL)
120 		return;
121 
122 	struct oauth2_key_cache_entry *entry =
123 		hash_table_lookup(cache->keys, key_id);
124 	if (entry != NULL) {
125 		dcrypt_key_unref_public(&entry->pubkey);
126 		if (entry->hmac_key == NULL) {
127 			entry->hmac_key = buffer_create_dynamic(
128 				cache->pool, hmac_key->used);
129 		} else {
130 			buffer_set_used_size(entry->hmac_key, 0);
131 		}
132 		buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used);
133 		return;
134 	}
135 	entry = p_new(cache->pool, struct oauth2_key_cache_entry, 1);
136 	entry->key_id = p_strdup(cache->pool, key_id);
137 	entry->hmac_key = buffer_create_dynamic(cache->pool, hmac_key->used);
138 	buffer_append(entry->hmac_key, hmac_key->data, hmac_key->used);
139 	DLLIST_PREPEND(&cache->list_start, entry);
140 	hash_table_insert(cache->keys, entry->key_id, entry);
141 }
142 
oauth2_validation_key_cache_evict(struct oauth2_validation_key_cache * cache,const char * key_id)143 int oauth2_validation_key_cache_evict(struct oauth2_validation_key_cache *cache,
144 				      const char *key_id)
145 {
146 	if (cache == NULL)
147 		return -1;
148 
149 	struct oauth2_key_cache_entry *entry =
150 		hash_table_lookup(cache->keys, key_id);
151 	if (entry == NULL)
152 		return -1;
153 	if (entry->pubkey != NULL)
154 		dcrypt_key_unref_public(&entry->pubkey);
155 	DLLIST_REMOVE(&cache->list_start, entry);
156 	hash_table_remove(cache->keys, key_id);
157 	return 0;
158 }
159