Line data Source code
1 : /* Copyright (c) 2016-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file hs_cache.c
6 : * \brief Handle hidden service descriptor caches.
7 : **/
8 :
9 : /* For unit tests.*/
10 : #define HS_CACHE_PRIVATE
11 :
12 : #include "core/or/or.h"
13 : #include "app/config/config.h"
14 : #include "lib/crypt_ops/crypto_format.h"
15 : #include "lib/crypt_ops/crypto_util.h"
16 : #include "feature/hs/hs_ident.h"
17 : #include "feature/hs/hs_common.h"
18 : #include "feature/hs/hs_client.h"
19 : #include "feature/hs/hs_descriptor.h"
20 : #include "feature/nodelist/microdesc.h"
21 : #include "feature/nodelist/networkstatus.h"
22 : #include "feature/stats/rephist.h"
23 :
24 : #include "feature/hs/hs_cache.h"
25 :
26 : #include "feature/nodelist/networkstatus_st.h"
27 :
28 : /* Total counter of the cache size. */
29 : static size_t hs_cache_total_allocation = 0;
30 :
31 : static int cached_client_descriptor_has_expired(time_t now,
32 : const hs_cache_client_descriptor_t *cached_desc);
33 :
34 : /** Helper function: Return true iff the cache entry has a decrypted
35 : * descriptor.
36 : *
37 : * A NULL desc object in the entry means that we were not able to decrypt the
38 : * descriptor because we are likely lacking client authorization. It is still
39 : * a valid entry but some operations can't be done without the decrypted
40 : * descriptor thus this function MUST be used to safe guard access to the
41 : * decrypted desc object. */
42 : static inline bool
43 116 : entry_has_decrypted_descriptor(const hs_cache_client_descriptor_t *entry)
44 : {
45 116 : tor_assert(entry);
46 116 : return (entry->desc != NULL);
47 : }
48 :
49 : /********************** Directory HS cache ******************/
50 :
51 : /** Directory descriptor cache. Map indexed by blinded key. */
52 : static digest256map_t *hs_cache_v3_dir;
53 :
54 : /** Remove a given descriptor from our cache. */
55 : static void
56 3 : remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
57 : {
58 3 : tor_assert(desc);
59 3 : digest256map_remove(hs_cache_v3_dir, desc->key);
60 3 : }
61 :
62 : /** Store a given descriptor in our cache. */
63 : static void
64 13 : store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
65 : {
66 13 : tor_assert(desc);
67 13 : digest256map_set(hs_cache_v3_dir, desc->key, desc);
68 13 : }
69 :
70 : /** Query our cache and return the entry or NULL if not found. */
71 : static hs_cache_dir_descriptor_t *
72 30 : lookup_v3_desc_as_dir(const uint8_t *key)
73 : {
74 30 : tor_assert(key);
75 30 : return digest256map_get(hs_cache_v3_dir, key);
76 : }
77 :
78 : #define cache_dir_desc_free(val) \
79 : FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
80 :
81 : /** Free a directory descriptor object. */
82 : static void
83 14 : cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
84 : {
85 14 : if (desc == NULL) {
86 : return;
87 : }
88 12 : hs_desc_plaintext_data_free(desc->plaintext_data);
89 12 : tor_free(desc->encoded_desc);
90 12 : tor_free(desc);
91 : }
92 :
93 : /** Helper function: Use by the free all function using the digest256map
94 : * interface to cache entries. */
95 : static void
96 0 : cache_dir_desc_free_void(void *ptr)
97 : {
98 0 : cache_dir_desc_free_(ptr);
99 0 : }
100 :
101 : /** Create a new directory cache descriptor object from a encoded descriptor.
102 : * On success, return the heap-allocated cache object, otherwise return NULL if
103 : * we can't decode the descriptor. */
104 : static hs_cache_dir_descriptor_t *
105 18 : cache_dir_desc_new(const char *desc)
106 : {
107 18 : hs_cache_dir_descriptor_t *dir_desc;
108 :
109 18 : tor_assert(desc);
110 :
111 18 : dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t));
112 36 : dir_desc->plaintext_data =
113 18 : tor_malloc_zero(sizeof(hs_desc_plaintext_data_t));
114 18 : dir_desc->encoded_desc = tor_strdup(desc);
115 :
116 18 : if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) {
117 2 : log_debug(LD_DIR, "Unable to decode descriptor. Rejecting.");
118 2 : goto err;
119 : }
120 :
121 : /* The blinded pubkey is the indexed key. */
122 16 : dir_desc->key = dir_desc->plaintext_data->blinded_pubkey.pubkey;
123 16 : dir_desc->created_ts = time(NULL);
124 16 : return dir_desc;
125 :
126 2 : err:
127 2 : cache_dir_desc_free(dir_desc);
128 2 : return NULL;
129 : }
130 :
131 : /** Return the size of a cache entry in bytes. */
132 : static size_t
133 20 : cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
134 : {
135 20 : return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data)
136 20 : + strlen(entry->encoded_desc));
137 : }
138 :
139 : /** Try to store a valid version 3 descriptor in the directory cache. Return 0
140 : * on success else a negative value is returned indicating that we have a
141 : * newer version in our cache. On error, caller is responsible to free the
142 : * given descriptor desc. */
143 : static int
144 16 : cache_store_v3_as_dir(hs_cache_dir_descriptor_t *desc)
145 : {
146 16 : hs_cache_dir_descriptor_t *cache_entry;
147 :
148 16 : tor_assert(desc);
149 :
150 : /* Verify if we have an entry in the cache for that key and if yes, check
151 : * if we should replace it? */
152 16 : cache_entry = lookup_v3_desc_as_dir(desc->key);
153 16 : if (cache_entry != NULL) {
154 : /* Only replace descriptor if revision-counter is greater than the one
155 : * in our cache */
156 6 : if (cache_entry->plaintext_data->revision_counter >=
157 6 : desc->plaintext_data->revision_counter) {
158 3 : log_info(LD_REND, "Descriptor revision counter in our cache is "
159 : "greater or equal than the one we received (%d/%d). "
160 : "Rejecting!",
161 : (int)cache_entry->plaintext_data->revision_counter,
162 : (int)desc->plaintext_data->revision_counter);
163 3 : goto err;
164 : }
165 : /* We now know that the descriptor we just received is a new one so
166 : * remove the entry we currently have from our cache so we can then
167 : * store the new one. */
168 3 : remove_v3_desc_as_dir(cache_entry);
169 3 : hs_cache_decrement_allocation(cache_get_dir_entry_size(cache_entry));
170 3 : cache_dir_desc_free(cache_entry);
171 : }
172 : /* Store the descriptor we just got. We are sure here that either we
173 : * don't have the entry or we have a newer descriptor and the old one
174 : * has been removed from the cache. */
175 13 : store_v3_desc_as_dir(desc);
176 :
177 : /* Update our total cache size with this entry for the OOM. This uses the
178 : * old HS protocol cache subsystem for which we are tied with. */
179 13 : hs_cache_increment_allocation(cache_get_dir_entry_size(desc));
180 :
181 : /* Update HSv3 statistics */
182 13 : if (get_options()->HiddenServiceStatistics) {
183 4 : rep_hist_hsdir_stored_maybe_new_v3_onion(desc->key);
184 : }
185 :
186 : return 0;
187 :
188 3 : err:
189 3 : return -1;
190 : }
191 :
192 : /** Using the query which is the base64 encoded blinded key of a version 3
193 : * descriptor, lookup in our directory cache the entry. If found, 1 is
194 : * returned and desc_out is populated with a newly allocated string being the
195 : * encoded descriptor. If not found, 0 is returned and desc_out is untouched.
196 : * On error, a negative value is returned and desc_out is untouched. */
197 : static int
198 16 : cache_lookup_v3_as_dir(const char *query, const char **desc_out)
199 : {
200 16 : int found = 0;
201 16 : ed25519_public_key_t blinded_key;
202 16 : const hs_cache_dir_descriptor_t *entry;
203 :
204 16 : tor_assert(query);
205 :
206 : /* Decode blinded key using the given query value. */
207 16 : if (ed25519_public_from_base64(&blinded_key, query) < 0) {
208 2 : log_info(LD_REND, "Unable to decode the v3 HSDir query %s.",
209 : safe_str_client(query));
210 2 : goto err;
211 : }
212 :
213 14 : entry = lookup_v3_desc_as_dir(blinded_key.pubkey);
214 14 : if (entry != NULL) {
215 9 : found = 1;
216 9 : if (desc_out) {
217 7 : *desc_out = entry->encoded_desc;
218 : }
219 : }
220 :
221 : return found;
222 :
223 2 : err:
224 2 : return -1;
225 : }
226 :
227 : /** Clean the v3 cache by removing any entry that has expired using the
228 : * <b>global_cutoff</b> value. If <b>global_cutoff</b> is 0, the cleaning
229 : * process will use the lifetime found in the plaintext data section. Return
230 : * the number of bytes cleaned. */
231 : STATIC size_t
232 151 : cache_clean_v3_as_dir(time_t now, time_t global_cutoff)
233 : {
234 151 : size_t bytes_removed = 0;
235 :
236 : /* Code flow error if this ever happens. */
237 151 : tor_assert(global_cutoff >= 0);
238 :
239 151 : if (!hs_cache_v3_dir) { /* No cache to clean. Just return. */
240 : return 0;
241 : }
242 :
243 307 : DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_dir, key,
244 : hs_cache_dir_descriptor_t *, entry) {
245 152 : size_t entry_size;
246 152 : time_t cutoff = global_cutoff;
247 152 : if (!cutoff) {
248 : /* Cutoff is the lifetime of the entry found in the descriptor. */
249 4 : cutoff = now - entry->plaintext_data->lifetime_sec;
250 : }
251 :
252 : /* If the entry has been created _after_ the cutoff, not expired so
253 : * continue to the next entry in our v3 cache. */
254 152 : if (entry->created_ts > cutoff) {
255 148 : continue;
256 : }
257 : /* Here, our entry has expired, remove and free. */
258 4 : MAP_DEL_CURRENT(key);
259 4 : entry_size = cache_get_dir_entry_size(entry);
260 4 : bytes_removed += entry_size;
261 : /* Entry is not in the cache anymore, destroy it. */
262 4 : cache_dir_desc_free(entry);
263 : /* Update our cache entry allocation size for the OOM. */
264 4 : hs_cache_decrement_allocation(entry_size);
265 : /* Logging. */
266 : {
267 4 : char key_b64[BASE64_DIGEST256_LEN + 1];
268 4 : digest256_to_base64(key_b64, (const char *) key);
269 4 : log_info(LD_REND, "Removing v3 descriptor '%s' from HSDir cache",
270 : safe_str_client(key_b64));
271 : }
272 : } DIGEST256MAP_FOREACH_END;
273 :
274 : return bytes_removed;
275 : }
276 :
277 : /** Given an encoded descriptor, store it in the directory cache depending on
278 : * which version it is. Return a negative value on error. On success, 0 is
279 : * returned. */
280 : int
281 18 : hs_cache_store_as_dir(const char *desc)
282 : {
283 18 : hs_cache_dir_descriptor_t *dir_desc = NULL;
284 :
285 18 : tor_assert(desc);
286 :
287 : /* Create a new cache object. This can fail if the descriptor plaintext data
288 : * is unparseable which in this case a log message will be triggered. */
289 18 : dir_desc = cache_dir_desc_new(desc);
290 18 : if (dir_desc == NULL) {
291 2 : goto err;
292 : }
293 :
294 : /* Call the right function against the descriptor version. At this point,
295 : * we are sure that the descriptor's version is supported else the
296 : * decoding would have failed. */
297 16 : switch (dir_desc->plaintext_data->version) {
298 : case HS_VERSION_THREE:
299 : default:
300 16 : if (cache_store_v3_as_dir(dir_desc) < 0) {
301 3 : goto err;
302 : }
303 : break;
304 : }
305 : return 0;
306 :
307 5 : err:
308 5 : cache_dir_desc_free(dir_desc);
309 5 : return -1;
310 : }
311 :
312 : /** Using the query, lookup in our directory cache the entry. If found, 1 is
313 : * returned and desc_out is populated with a newly allocated string being
314 : * the encoded descriptor. If not found, 0 is returned and desc_out is
315 : * untouched. On error, a negative value is returned and desc_out is
316 : * untouched. */
317 : int
318 16 : hs_cache_lookup_as_dir(uint32_t version, const char *query,
319 : const char **desc_out)
320 : {
321 16 : int found;
322 :
323 16 : tor_assert(query);
324 : /* This should never be called with an unsupported version. */
325 16 : tor_assert(hs_desc_is_supported_version(version));
326 :
327 16 : switch (version) {
328 : case HS_VERSION_THREE:
329 : default:
330 16 : found = cache_lookup_v3_as_dir(query, desc_out);
331 16 : break;
332 : }
333 :
334 16 : return found;
335 : }
336 :
337 : /** Clean all directory caches using the current time now. */
338 : void
339 2 : hs_cache_clean_as_dir(time_t now)
340 : {
341 : /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
342 : * to compute the cutoff by itself using the lifetime value. */
343 2 : cache_clean_v3_as_dir(now, 0);
344 2 : }
345 :
346 : /********************** Client-side HS cache ******************/
347 :
348 : /** Client-side HS descriptor cache. Map indexed by service identity key. */
349 : static digest256map_t *hs_cache_v3_client;
350 :
351 : /** Client-side introduction point state cache. Map indexed by service public
352 : * identity key (onion address). It contains hs_cache_client_intro_state_t
353 : * objects all related to a specific service. */
354 : static digest256map_t *hs_cache_client_intro_state;
355 :
356 : #define cache_client_desc_free(val) \
357 : FREE_AND_NULL(hs_cache_client_descriptor_t, cache_client_desc_free_, (val))
358 :
359 : /** Free memory allocated by <b>desc</b>. */
360 : static void
361 12 : cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
362 : {
363 12 : if (desc == NULL) {
364 : return;
365 : }
366 12 : hs_descriptor_free(desc->desc);
367 12 : memwipe(&desc->key, 0, sizeof(desc->key));
368 12 : memwipe(desc->encoded_desc, 0, strlen(desc->encoded_desc));
369 12 : tor_free(desc->encoded_desc);
370 12 : tor_free(desc);
371 : }
372 :
373 : /** Helper function: Use by the free all function to clear the client cache */
374 : static void
375 4 : cache_client_desc_free_void(void *ptr)
376 : {
377 4 : hs_cache_client_descriptor_t *desc = ptr;
378 4 : cache_client_desc_free(desc);
379 4 : }
380 :
381 : /** Return the size of a client cache entry in bytes. */
382 : static size_t
383 22 : cache_get_client_entry_size(const hs_cache_client_descriptor_t *entry)
384 : {
385 22 : size_t size = 0;
386 :
387 22 : if (entry == NULL) {
388 0 : goto end;
389 : }
390 22 : size += sizeof(*entry);
391 :
392 22 : if (entry->encoded_desc) {
393 22 : size += strlen(entry->encoded_desc);
394 : }
395 :
396 22 : if (entry_has_decrypted_descriptor(entry)) {
397 16 : size += hs_desc_obj_size(entry->desc);
398 : }
399 :
400 6 : end:
401 22 : return size;
402 : }
403 :
404 : /** Remove a given descriptor from our cache. */
405 : static void
406 5 : remove_v3_desc_as_client(const hs_cache_client_descriptor_t *desc)
407 : {
408 5 : tor_assert(desc);
409 5 : digest256map_remove(hs_cache_v3_client, desc->key.pubkey);
410 : /* Update cache size with this entry for the OOM handler. */
411 5 : hs_cache_decrement_allocation(cache_get_client_entry_size(desc));
412 5 : }
413 :
414 : /** Store a given descriptor in our cache. */
415 : static void
416 14 : store_v3_desc_as_client(hs_cache_client_descriptor_t *desc)
417 : {
418 14 : hs_cache_client_descriptor_t *cached_desc;
419 :
420 14 : tor_assert(desc);
421 :
422 : /* Because the lookup function doesn't return an expired entry, it can linger
423 : * in the cache until we clean it up or a new descriptor is stored. So,
424 : * before adding, we'll make sure we are not overwriting an old descriptor
425 : * (which is OK in terms of semantic) but leads to memory leak. */
426 14 : cached_desc = digest256map_get(hs_cache_v3_client, desc->key.pubkey);
427 14 : if (cached_desc) {
428 0 : cache_client_desc_free(cached_desc);
429 : }
430 14 : digest256map_set(hs_cache_v3_client, desc->key.pubkey, desc);
431 : /* Update cache size with this entry for the OOM handler. */
432 14 : hs_cache_increment_allocation(cache_get_client_entry_size(desc));
433 14 : }
434 :
435 : /** Query our cache and return the entry or NULL if not found or if expired. */
436 : STATIC hs_cache_client_descriptor_t *
437 119 : lookup_v3_desc_as_client(const uint8_t *key)
438 : {
439 119 : time_t now = approx_time();
440 119 : hs_cache_client_descriptor_t *cached_desc;
441 :
442 119 : tor_assert(key);
443 :
444 : /* Do the lookup */
445 119 : cached_desc = digest256map_get(hs_cache_v3_client, key);
446 119 : if (!cached_desc) {
447 : return NULL;
448 : }
449 :
450 : /* Don't return expired entries */
451 93 : if (cached_client_descriptor_has_expired(now, cached_desc)) {
452 1 : return NULL;
453 : }
454 :
455 : return cached_desc;
456 : }
457 :
458 : /** Parse the encoded descriptor in <b>desc_str</b> using
459 : * <b>service_identity_pk</b> to decrypt it first.
460 : *
461 : * If everything goes well, allocate and return a new
462 : * hs_cache_client_descriptor_t object. In case of error, return NULL. */
463 : static hs_cache_client_descriptor_t *
464 14 : cache_client_desc_new(const char *desc_str,
465 : const ed25519_public_key_t *service_identity_pk,
466 : hs_desc_decode_status_t *decode_status_out)
467 : {
468 14 : hs_desc_decode_status_t ret;
469 14 : hs_descriptor_t *desc = NULL;
470 14 : hs_cache_client_descriptor_t *client_desc = NULL;
471 :
472 14 : tor_assert(desc_str);
473 14 : tor_assert(service_identity_pk);
474 :
475 : /* Decode the descriptor we just fetched. */
476 14 : ret = hs_client_decode_descriptor(desc_str, service_identity_pk, &desc);
477 14 : if (ret != HS_DESC_DECODE_OK &&
478 14 : ret != HS_DESC_DECODE_NEED_CLIENT_AUTH &&
479 : ret != HS_DESC_DECODE_BAD_CLIENT_AUTH) {
480 : /* In the case of a missing or bad client authorization, we'll keep the
481 : * descriptor in the cache because those credentials can arrive later. */
482 0 : goto end;
483 : }
484 : /* Make sure we do have a descriptor if decoding was successful. */
485 14 : if (ret == HS_DESC_DECODE_OK) {
486 10 : tor_assert(desc);
487 : } else {
488 4 : if (BUG(desc != NULL)) {
489 : /* We are not suppose to have a descriptor if the decoding code is not
490 : * indicating success. Just in case, bail early to recover. */
491 0 : goto end;
492 : }
493 : }
494 :
495 : /* All is good: make a cache object for this descriptor */
496 14 : client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t));
497 14 : ed25519_pubkey_copy(&client_desc->key, service_identity_pk);
498 : /* Set expiration time for this cached descriptor to be the start of the next
499 : * time period since that's when clients need to start using the next blinded
500 : * pk of the service (and hence will need its next descriptor). */
501 14 : client_desc->expiration_ts = hs_get_start_time_of_next_time_period(0);
502 14 : client_desc->desc = desc;
503 14 : client_desc->encoded_desc = tor_strdup(desc_str);
504 :
505 14 : end:
506 14 : if (decode_status_out) {
507 14 : *decode_status_out = ret;
508 : }
509 14 : return client_desc;
510 : }
511 :
512 : /** Return a newly allocated and initialized hs_cache_intro_state_t object. */
513 : static hs_cache_intro_state_t *
514 14 : cache_intro_state_new(void)
515 : {
516 14 : hs_cache_intro_state_t *state = tor_malloc_zero(sizeof(*state));
517 14 : state->created_ts = approx_time();
518 14 : return state;
519 : }
520 :
521 : #define cache_intro_state_free(val) \
522 : FREE_AND_NULL(hs_cache_intro_state_t, cache_intro_state_free_, (val))
523 :
524 : /** Free an hs_cache_intro_state_t object. */
525 : static void
526 14 : cache_intro_state_free_(hs_cache_intro_state_t *state)
527 : {
528 14 : tor_free(state);
529 14 : }
530 :
531 : /** Helper function: used by the free all function. */
532 : static void
533 10 : cache_intro_state_free_void(void *state)
534 : {
535 10 : cache_intro_state_free_(state);
536 10 : }
537 :
538 : /** Return a newly allocated and initialized hs_cache_client_intro_state_t
539 : * object. */
540 : static hs_cache_client_intro_state_t *
541 5 : cache_client_intro_state_new(void)
542 : {
543 5 : hs_cache_client_intro_state_t *cache = tor_malloc_zero(sizeof(*cache));
544 5 : cache->intro_points = digest256map_new();
545 5 : return cache;
546 : }
547 :
548 : #define cache_client_intro_state_free(val) \
549 : FREE_AND_NULL(hs_cache_client_intro_state_t, \
550 : cache_client_intro_state_free_, (val))
551 :
552 : /** Free a cache_client_intro_state object. */
553 : static void
554 5 : cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
555 : {
556 5 : if (cache == NULL) {
557 : return;
558 : }
559 5 : digest256map_free(cache->intro_points, cache_intro_state_free_void);
560 5 : tor_free(cache);
561 : }
562 :
563 : /** Helper function: used by the free all function. */
564 : static void
565 1 : cache_client_intro_state_free_void(void *entry)
566 : {
567 1 : cache_client_intro_state_free_(entry);
568 1 : }
569 :
570 : /** For the given service identity key service_pk and an introduction
571 : * authentication key auth_key, lookup the intro state object. Return 1 if
572 : * found and put it in entry if not NULL. Return 0 if not found and entry is
573 : * untouched. */
574 : static int
575 283 : cache_client_intro_state_lookup(const ed25519_public_key_t *service_pk,
576 : const ed25519_public_key_t *auth_key,
577 : hs_cache_intro_state_t **entry)
578 : {
579 283 : hs_cache_intro_state_t *state;
580 283 : hs_cache_client_intro_state_t *cache;
581 :
582 283 : tor_assert(service_pk);
583 283 : tor_assert(auth_key);
584 :
585 : /* Lookup the intro state cache for this service key. */
586 283 : cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
587 283 : if (cache == NULL) {
588 16 : goto not_found;
589 : }
590 :
591 : /* From the cache we just found for the service, lookup in the introduction
592 : * points map for the given authentication key. */
593 267 : state = digest256map_get(cache->intro_points, auth_key->pubkey);
594 267 : if (state == NULL) {
595 137 : goto not_found;
596 : }
597 130 : if (entry) {
598 130 : *entry = state;
599 : }
600 : return 1;
601 : not_found:
602 : return 0;
603 : }
604 :
605 : /** Note the given failure in state. */
606 : static void
607 18 : cache_client_intro_state_note(hs_cache_intro_state_t *state,
608 : rend_intro_point_failure_t failure)
609 : {
610 18 : tor_assert(state);
611 18 : switch (failure) {
612 11 : case INTRO_POINT_FAILURE_GENERIC:
613 11 : state->error = 1;
614 11 : break;
615 6 : case INTRO_POINT_FAILURE_TIMEOUT:
616 6 : state->timed_out = 1;
617 6 : break;
618 1 : case INTRO_POINT_FAILURE_UNREACHABLE:
619 1 : state->unreachable_count++;
620 1 : break;
621 0 : default:
622 0 : tor_assert_nonfatal_unreached();
623 0 : return;
624 : }
625 : }
626 :
627 : /** For the given service identity key service_pk and an introduction
628 : * authentication key auth_key, add an entry in the client intro state cache
629 : * If no entry exists for the service, it will create one. If state is non
630 : * NULL, it will point to the new intro state entry. */
631 : static void
632 14 : cache_client_intro_state_add(const ed25519_public_key_t *service_pk,
633 : const ed25519_public_key_t *auth_key,
634 : hs_cache_intro_state_t **state)
635 : {
636 14 : hs_cache_intro_state_t *entry, *old_entry;
637 14 : hs_cache_client_intro_state_t *cache;
638 :
639 14 : tor_assert(service_pk);
640 14 : tor_assert(auth_key);
641 :
642 : /* Lookup the state cache for this service key. */
643 14 : cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
644 14 : if (cache == NULL) {
645 5 : cache = cache_client_intro_state_new();
646 5 : digest256map_set(hs_cache_client_intro_state, service_pk->pubkey, cache);
647 : }
648 :
649 14 : entry = cache_intro_state_new();
650 14 : old_entry = digest256map_set(cache->intro_points, auth_key->pubkey, entry);
651 : /* This should never happened because the code flow is to lookup the entry
652 : * before adding it. But, just in case, non fatal assert and free it. */
653 14 : tor_assert_nonfatal(old_entry == NULL);
654 14 : tor_free(old_entry);
655 :
656 14 : if (state) {
657 14 : *state = entry;
658 : }
659 14 : }
660 :
661 : /** Remove every intro point state entry from cache that has been created
662 : * before or at the cutoff. */
663 : static void
664 1 : cache_client_intro_state_clean(time_t cutoff,
665 : hs_cache_client_intro_state_t *cache)
666 : {
667 1 : tor_assert(cache);
668 :
669 5 : DIGEST256MAP_FOREACH_MODIFY(cache->intro_points, key,
670 : hs_cache_intro_state_t *, entry) {
671 4 : if (entry->created_ts <= cutoff) {
672 4 : cache_intro_state_free(entry);
673 4 : MAP_DEL_CURRENT(key);
674 : }
675 1 : } DIGEST256MAP_FOREACH_END;
676 1 : }
677 :
678 : /** Return true iff no intro points are in this cache. */
679 : static int
680 1 : cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache)
681 : {
682 1 : return digest256map_isempty(cache->intro_points);
683 : }
684 :
685 : /** Check whether <b>client_desc</b> is useful for us, and store it in the
686 : * client-side HS cache if so. The client_desc is freed if we already have a
687 : * fresher (higher revision counter count) in the cache. */
688 : static int
689 14 : cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
690 : {
691 14 : hs_cache_client_descriptor_t *cache_entry;
692 :
693 : /* TODO: Heavy code duplication with cache_store_as_dir(). Consider
694 : * refactoring and uniting! */
695 :
696 14 : tor_assert(client_desc);
697 :
698 : /* Check if we already have a descriptor from this HS in cache. If we do,
699 : * check if this descriptor is newer than the cached one only if we have a
700 : * decoded descriptor. We do keep non-decoded descriptor that requires
701 : * client authorization. */
702 14 : cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
703 14 : if (cache_entry != NULL) {
704 : /* If the current or the new cache entry don't have a decrypted descriptor
705 : * (missing client authorization), we always replace the current one with
706 : * the new one. Reason is that we can't inspect the revision counter
707 : * within the plaintext data so we blindly replace. */
708 6 : if (!entry_has_decrypted_descriptor(cache_entry) ||
709 2 : !entry_has_decrypted_descriptor(client_desc)) {
710 2 : remove_v3_desc_as_client(cache_entry);
711 2 : cache_client_desc_free(cache_entry);
712 2 : goto store;
713 : }
714 :
715 : /* From this point on, we know that the decrypted descriptor is in the
716 : * current entry and new object thus safe to access. */
717 :
718 : /* If we have an entry in our cache that has a revision counter greater
719 : * than the one we just fetched, discard the one we fetched. */
720 2 : if (cache_entry->desc->plaintext_data.revision_counter >
721 2 : client_desc->desc->plaintext_data.revision_counter) {
722 0 : cache_client_desc_free(client_desc);
723 0 : goto done;
724 : }
725 : /* Remove old entry. Make space for the new one! */
726 2 : remove_v3_desc_as_client(cache_entry);
727 :
728 : /* We just removed an old descriptor and will replace it. We'll close all
729 : * intro circuits related to this old one so we don't have leftovers. We
730 : * leave the rendezvous circuits opened because they could be in use. */
731 2 : hs_client_close_intro_circuits_from_desc(cache_entry->desc);
732 :
733 : /* Free it. */
734 2 : cache_client_desc_free(cache_entry);
735 : }
736 :
737 10 : store:
738 : /* Store descriptor in cache */
739 14 : store_v3_desc_as_client(client_desc);
740 :
741 14 : done:
742 14 : return 0;
743 : }
744 :
745 : /** Return true iff the cached client descriptor at <b>cached_desc</b> has
746 : * expired. */
747 : static int
748 95 : cached_client_descriptor_has_expired(time_t now,
749 : const hs_cache_client_descriptor_t *cached_desc)
750 : {
751 : /* We use the current consensus time to see if we should expire this
752 : * descriptor since we use consensus time for all other parts of the protocol
753 : * as well (e.g. to build the blinded key and compute time periods). */
754 95 : const networkstatus_t *ns =
755 95 : networkstatus_get_reasonably_live_consensus(now,
756 : usable_consensus_flavor());
757 : /* If we don't have a recent consensus, consider this entry expired since we
758 : * will want to fetch a new HS desc when we get a live consensus. */
759 95 : if (!ns) {
760 : return 1;
761 : }
762 :
763 95 : if (cached_desc->expiration_ts <= ns->valid_after) {
764 2 : return 1;
765 : }
766 :
767 : return 0;
768 : }
769 :
770 : /** clean the client cache using now as the current time. Return the total size
771 : * of removed bytes from the cache. */
772 : static size_t
773 2 : cache_clean_v3_as_client(time_t now)
774 : {
775 2 : size_t bytes_removed = 0;
776 :
777 2 : if (!hs_cache_v3_client) { /* No cache to clean. Just return. */
778 : return 0;
779 : }
780 :
781 5 : DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
782 : hs_cache_client_descriptor_t *, entry) {
783 2 : size_t entry_size;
784 :
785 : /* If the entry has not expired, continue to the next cached entry */
786 2 : if (!cached_client_descriptor_has_expired(now, entry)) {
787 1 : continue;
788 : }
789 : /* Here, our entry has expired, remove and free. */
790 1 : MAP_DEL_CURRENT(key);
791 1 : entry_size = cache_get_client_entry_size(entry);
792 1 : bytes_removed += entry_size;
793 :
794 : /* We just removed an old descriptor. We need to close all intro circuits
795 : * if the descriptor is decrypted so we don't have leftovers that can be
796 : * selected while lacking a descriptor. Circuits are selected by intro
797 : * authentication key thus we need the descriptor. We leave the rendezvous
798 : * circuits opened because they could be in use. */
799 1 : if (entry_has_decrypted_descriptor(entry)) {
800 1 : hs_client_close_intro_circuits_from_desc(entry->desc);
801 : }
802 : /* Entry is not in the cache anymore, destroy it. */
803 1 : cache_client_desc_free(entry);
804 : /* Update our OOM. We didn't use the remove() function because we are in
805 : * a loop so we have to explicitly decrement. */
806 1 : hs_cache_decrement_allocation(entry_size);
807 : /* Logging. */
808 : {
809 1 : char key_b64[BASE64_DIGEST256_LEN + 1];
810 1 : digest256_to_base64(key_b64, (const char *) key);
811 1 : log_info(LD_REND, "Removing hidden service v3 descriptor '%s' "
812 : "from client cache",
813 : safe_str_client(key_b64));
814 : }
815 : } DIGEST256MAP_FOREACH_END;
816 :
817 : return bytes_removed;
818 : }
819 :
820 : /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
821 : * its HS encoded descriptor if it's stored in our cache, or NULL if not. */
822 : const char *
823 1 : hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
824 : {
825 1 : hs_cache_client_descriptor_t *cached_desc = NULL;
826 :
827 1 : tor_assert(key);
828 :
829 1 : cached_desc = lookup_v3_desc_as_client(key->pubkey);
830 1 : if (cached_desc) {
831 1 : tor_assert(cached_desc->encoded_desc);
832 : return cached_desc->encoded_desc;
833 : }
834 :
835 : return NULL;
836 : }
837 :
838 : /** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
839 : * its HS descriptor if it's stored in our cache, or NULL if not or if the
840 : * descriptor was never decrypted. The later can happen if we are waiting for
841 : * client authorization to be added. */
842 : const hs_descriptor_t *
843 90 : hs_cache_lookup_as_client(const ed25519_public_key_t *key)
844 : {
845 90 : hs_cache_client_descriptor_t *cached_desc = NULL;
846 :
847 90 : tor_assert(key);
848 :
849 90 : cached_desc = lookup_v3_desc_as_client(key->pubkey);
850 90 : if (cached_desc && entry_has_decrypted_descriptor(cached_desc)) {
851 83 : return cached_desc->desc;
852 : }
853 :
854 : return NULL;
855 : }
856 :
857 : /** Public API: Given an encoded descriptor, store it in the client HS cache.
858 : * Return a decode status which changes how we handle the SOCKS connection
859 : * depending on its value:
860 : *
861 : * HS_DESC_DECODE_OK: Returned on success. Descriptor was properly decoded
862 : * and is now stored.
863 : *
864 : * HS_DESC_DECODE_NEED_CLIENT_AUTH: Client authorization is needed but the
865 : * descriptor was still stored.
866 : *
867 : * HS_DESC_DECODE_BAD_CLIENT_AUTH: Client authorization for this descriptor
868 : * was not usable but the descriptor was
869 : * still stored.
870 : *
871 : * Any other codes means indicate where the error occurred and the descriptor
872 : * was not stored. */
873 : hs_desc_decode_status_t
874 14 : hs_cache_store_as_client(const char *desc_str,
875 : const ed25519_public_key_t *identity_pk)
876 : {
877 14 : hs_desc_decode_status_t ret;
878 14 : hs_cache_client_descriptor_t *client_desc = NULL;
879 :
880 14 : tor_assert(desc_str);
881 14 : tor_assert(identity_pk);
882 :
883 : /* Create client cache descriptor object */
884 14 : client_desc = cache_client_desc_new(desc_str, identity_pk, &ret);
885 14 : if (!client_desc) {
886 0 : log_warn(LD_GENERAL, "HSDesc parsing failed!");
887 0 : log_debug(LD_GENERAL, "Failed to parse HSDesc: %s.", escaped(desc_str));
888 0 : goto err;
889 : }
890 :
891 : /* Push it to the cache */
892 14 : if (cache_store_as_client(client_desc) < 0) {
893 0 : ret = HS_DESC_DECODE_GENERIC_ERROR;
894 0 : goto err;
895 : }
896 :
897 14 : return ret;
898 :
899 0 : err:
900 0 : cache_client_desc_free(client_desc);
901 0 : return ret;
902 : }
903 :
904 : /** Remove and free a client cache descriptor entry for the given onion
905 : * service ed25519 public key. If the descriptor is decoded, the intro
906 : * circuits are closed if any.
907 : *
908 : * This does nothing if no descriptor exists for the given key. */
909 : void
910 5 : hs_cache_remove_as_client(const ed25519_public_key_t *key)
911 : {
912 5 : hs_cache_client_descriptor_t *cached_desc = NULL;
913 :
914 5 : tor_assert(key);
915 :
916 5 : cached_desc = lookup_v3_desc_as_client(key->pubkey);
917 5 : if (!cached_desc) {
918 5 : return;
919 : }
920 : /* If we have a decrypted/decoded descriptor, attempt to close its
921 : * introduction circuit(s). We shouldn't have circuit(s) without a
922 : * descriptor else it will lead to a failure. */
923 1 : if (entry_has_decrypted_descriptor(cached_desc)) {
924 1 : hs_client_close_intro_circuits_from_desc(cached_desc->desc);
925 : }
926 : /* Remove and free. */
927 1 : remove_v3_desc_as_client(cached_desc);
928 1 : cache_client_desc_free(cached_desc);
929 :
930 : /* Logging. */
931 : {
932 1 : char key_b64[BASE64_DIGEST256_LEN + 1];
933 1 : digest256_to_base64(key_b64, (const char *) key);
934 1 : log_info(LD_REND, "Onion service v3 descriptor '%s' removed "
935 : "from client cache",
936 : safe_str_client(key_b64));
937 : }
938 : }
939 :
940 : /** Clean all client caches using the current time now. */
941 : void
942 2 : hs_cache_clean_as_client(time_t now)
943 : {
944 : /* Now, clean the v3 cache. Set the cutoff to 0 telling the cleanup function
945 : * to compute the cutoff by itself using the lifetime value. */
946 2 : cache_clean_v3_as_client(now);
947 2 : }
948 :
949 : /** Purge the client descriptor cache. */
950 : void
951 2 : hs_cache_purge_as_client(void)
952 : {
953 4 : DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
954 : hs_cache_client_descriptor_t *, entry) {
955 2 : size_t entry_size = cache_get_client_entry_size(entry);
956 2 : MAP_DEL_CURRENT(key);
957 2 : cache_client_desc_free(entry);
958 : /* Update our OOM. We didn't use the remove() function because we are in
959 : * a loop so we have to explicitly decrement. */
960 2 : hs_cache_decrement_allocation(entry_size);
961 2 : } DIGEST256MAP_FOREACH_END;
962 :
963 2 : log_info(LD_REND, "Hidden service client descriptor cache purged.");
964 2 : }
965 :
966 : /** For a given service identity public key and an introduction authentication
967 : * key, note the given failure in the client intro state cache. */
968 : void
969 18 : hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk,
970 : const ed25519_public_key_t *auth_key,
971 : rend_intro_point_failure_t failure)
972 : {
973 18 : int found;
974 18 : hs_cache_intro_state_t *entry;
975 :
976 18 : tor_assert(service_pk);
977 18 : tor_assert(auth_key);
978 :
979 18 : found = cache_client_intro_state_lookup(service_pk, auth_key, &entry);
980 18 : if (!found) {
981 : /* Create a new entry and add it to the cache. */
982 14 : cache_client_intro_state_add(service_pk, auth_key, &entry);
983 : }
984 : /* Note down the entry. */
985 18 : cache_client_intro_state_note(entry, failure);
986 18 : }
987 :
988 : /** For a given service identity public key and an introduction authentication
989 : * key, return true iff it is present in the failure cache. */
990 : const hs_cache_intro_state_t *
991 265 : hs_cache_client_intro_state_find(const ed25519_public_key_t *service_pk,
992 : const ed25519_public_key_t *auth_key)
993 : {
994 265 : hs_cache_intro_state_t *state = NULL;
995 265 : cache_client_intro_state_lookup(service_pk, auth_key, &state);
996 265 : return state;
997 : }
998 :
999 : /** Cleanup the client introduction state cache. */
1000 : void
1001 1 : hs_cache_client_intro_state_clean(time_t now)
1002 : {
1003 1 : time_t cutoff = now - HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE;
1004 :
1005 2 : DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
1006 : hs_cache_client_intro_state_t *, cache) {
1007 : /* Cleanup intro points failure. */
1008 1 : cache_client_intro_state_clean(cutoff, cache);
1009 :
1010 : /* Is this cache empty for this service key? If yes, remove it from the
1011 : * cache. Else keep it. */
1012 1 : if (cache_client_intro_state_is_empty(cache)) {
1013 1 : cache_client_intro_state_free(cache);
1014 1 : MAP_DEL_CURRENT(key);
1015 : }
1016 1 : } DIGEST256MAP_FOREACH_END;
1017 1 : }
1018 :
1019 : /** Purge the client introduction state cache. */
1020 : void
1021 3 : hs_cache_client_intro_state_purge(void)
1022 : {
1023 6 : DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
1024 : hs_cache_client_intro_state_t *, cache) {
1025 3 : MAP_DEL_CURRENT(key);
1026 3 : cache_client_intro_state_free(cache);
1027 3 : } DIGEST256MAP_FOREACH_END;
1028 :
1029 3 : log_info(LD_REND, "Hidden service client introduction point state "
1030 : "cache purged.");
1031 3 : }
1032 :
1033 : /* This is called when new client authorization was added to the global state.
1034 : * It attempts to decode the descriptor of the given service identity key.
1035 : *
1036 : * Return true if decoding was successful else false. */
1037 : bool
1038 9 : hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk)
1039 : {
1040 9 : bool ret = false;
1041 9 : hs_cache_client_descriptor_t *cached_desc = NULL;
1042 :
1043 9 : tor_assert(service_pk);
1044 :
1045 9 : if (!hs_cache_v3_client) {
1046 : return false;
1047 : }
1048 :
1049 9 : cached_desc = lookup_v3_desc_as_client(service_pk->pubkey);
1050 9 : if (cached_desc == NULL || entry_has_decrypted_descriptor(cached_desc)) {
1051 : /* No entry for that service or the descriptor is already decoded. */
1052 7 : goto end;
1053 : }
1054 :
1055 : /* Attempt a decode. If we are successful, inform the caller. */
1056 2 : if (hs_client_decode_descriptor(cached_desc->encoded_desc, service_pk,
1057 : &cached_desc->desc) == HS_DESC_DECODE_OK) {
1058 1 : ret = true;
1059 : }
1060 :
1061 1 : end:
1062 : return ret;
1063 : }
1064 :
1065 : /**************** Generics *********************************/
1066 :
1067 : /** Do a round of OOM cleanup on all directory caches. Return the amount of
1068 : * removed bytes. It is possible that the returned value is lower than
1069 : * min_remove_bytes if the caches get emptied out so the caller should be
1070 : * aware of this. */
1071 : size_t
1072 2 : hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
1073 : {
1074 2 : time_t k;
1075 2 : size_t bytes_removed = 0;
1076 :
1077 : /* Our OOM handler called with 0 bytes to remove is a code flow error. */
1078 2 : tor_assert(min_remove_bytes != 0);
1079 :
1080 : /* The algorithm is as follow. K is the oldest expected descriptor age.
1081 : *
1082 : * 1) Deallocate all entries from v3 cache that are older than K hours
1083 : * 2.1) If the amount of remove bytes has been reached, stop.
1084 : * 2) Set K = K - RendPostPeriod and repeat process until K is < 0.
1085 : *
1086 : * This ends up being O(Kn).
1087 : */
1088 :
1089 : /* Set K to the oldest expected age in seconds which is the maximum
1090 : * lifetime of a cache entry. */
1091 2 : k = hs_cache_max_entry_lifetime();
1092 :
1093 146 : do {
1094 146 : time_t cutoff;
1095 :
1096 : /* If K becomes negative, it means we've empty the caches so stop and
1097 : * return what we were able to cleanup. */
1098 146 : if (k < 0) {
1099 : break;
1100 : }
1101 : /* Compute a cutoff value with K and the current time. */
1102 146 : cutoff = now - k;
1103 :
1104 146 : if (bytes_removed < min_remove_bytes) {
1105 : /* We haven't remove enough bytes so clean v3 cache. */
1106 146 : bytes_removed += cache_clean_v3_as_dir(now, cutoff);
1107 : /* Decrement K by a post period to shorten the cutoff. */
1108 146 : k -= get_options()->RendPostPeriod;
1109 : }
1110 146 : } while (bytes_removed < min_remove_bytes);
1111 :
1112 2 : return bytes_removed;
1113 : }
1114 :
1115 : /** Return the maximum size of a v3 HS descriptor. */
1116 : unsigned int
1117 161 : hs_cache_get_max_descriptor_size(void)
1118 : {
1119 161 : return (unsigned) networkstatus_get_param(NULL,
1120 : "HSV3MaxDescriptorSize",
1121 : HS_DESC_MAX_LEN, 1, INT32_MAX);
1122 : }
1123 :
1124 : /** Initialize the hidden service cache subsystem. */
1125 : void
1126 290 : hs_cache_init(void)
1127 : {
1128 : /* Calling this twice is very wrong code flow. */
1129 290 : tor_assert(!hs_cache_v3_dir);
1130 290 : hs_cache_v3_dir = digest256map_new();
1131 :
1132 290 : tor_assert(!hs_cache_v3_client);
1133 290 : hs_cache_v3_client = digest256map_new();
1134 :
1135 290 : tor_assert(!hs_cache_client_intro_state);
1136 290 : hs_cache_client_intro_state = digest256map_new();
1137 290 : }
1138 :
1139 : /** Cleanup the hidden service cache subsystem. */
1140 : void
1141 278 : hs_cache_free_all(void)
1142 : {
1143 278 : digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
1144 278 : hs_cache_v3_dir = NULL;
1145 :
1146 278 : digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
1147 278 : hs_cache_v3_client = NULL;
1148 :
1149 278 : digest256map_free(hs_cache_client_intro_state,
1150 : cache_client_intro_state_free_void);
1151 278 : hs_cache_client_intro_state = NULL;
1152 278 : hs_cache_total_allocation = 0;
1153 278 : }
1154 :
1155 : /* Return total size of the cache. */
1156 : size_t
1157 19 : hs_cache_get_total_allocation(void)
1158 : {
1159 19 : return hs_cache_total_allocation;
1160 : }
1161 :
1162 : /** Decrement the total bytes attributed to the rendezvous cache by n. */
1163 : void
1164 15 : hs_cache_decrement_allocation(size_t n)
1165 : {
1166 15 : static int have_underflowed = 0;
1167 :
1168 15 : if (hs_cache_total_allocation >= n) {
1169 15 : hs_cache_total_allocation -= n;
1170 : } else {
1171 0 : hs_cache_total_allocation = 0;
1172 0 : if (! have_underflowed) {
1173 0 : have_underflowed = 1;
1174 0 : log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation");
1175 : }
1176 : }
1177 15 : }
1178 :
1179 : /** Increase the total bytes attributed to the rendezvous cache by n. */
1180 : void
1181 27 : hs_cache_increment_allocation(size_t n)
1182 : {
1183 27 : static int have_overflowed = 0;
1184 27 : if (hs_cache_total_allocation <= SIZE_MAX - n) {
1185 27 : hs_cache_total_allocation += n;
1186 : } else {
1187 0 : hs_cache_total_allocation = SIZE_MAX;
1188 0 : if (! have_overflowed) {
1189 0 : have_overflowed = 1;
1190 0 : log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation");
1191 : }
1192 : }
1193 27 : }
|