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