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