Tor  0.4.7.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"
17 #include "feature/hs/hs_common.h"
18 #include "feature/hs/hs_client.h"
22 #include "feature/stats/rephist.h"
23 
24 #include "feature/hs/hs_cache.h"
25 
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 entry_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. */
52 static digest256map_t *hs_cache_v3_dir;
53 
54 /** Remove a given descriptor from our cache. */
55 static 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. */
63 static 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. */
72 lookup_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. */
82 static void
84 {
85  if (desc == NULL) {
86  return;
87  }
88  hs_desc_plaintext_data_free(desc->plaintext_data);
89  tor_free(desc->encoded_desc);
90  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
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. */
105 cache_dir_desc_new(const char *desc)
106 {
107  hs_cache_dir_descriptor_t *dir_desc;
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. */
132 static 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. */
143 static 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. */
175  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. */
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. */
197 static int
198 cache_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. */
231 STATIC size_t
232 cache_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. */
264  hs_cache_decrement_allocation(entry_size);
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. */
280 int
281 hs_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. */
317 int
318 hs_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. */
338 void
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. */
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 cache_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 */
374 static 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. */
382 static size_t
383 cache_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 
396  if (entry_has_decrypted_descriptor(entry)) {
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. */
405 static void
406 remove_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. */
415 static void
416 store_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. */
436 STATIC hs_cache_client_descriptor_t *
437 lookup_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. */
463 static hs_cache_client_descriptor_t *
464 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 {
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. */
513 static hs_cache_intro_state_t *
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. */
525 static void
527 {
528  tor_free(state);
529 }
530 
531 /** Helper function: used by the free all function. */
532 static 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. */
553 static 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. */
564 static 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. */
574 static int
576  const ed25519_public_key_t *auth_key,
577  hs_cache_intro_state_t **entry)
578 {
579  hs_cache_intro_state_t *state;
581 
582  tor_assert(service_pk);
583  tor_assert(auth_key);
584 
585  /* Lookup the intro state cache for this service key. */
586  cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
587  if (cache == NULL) {
588  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  state = digest256map_get(cache->intro_points, auth_key->pubkey);
594  if (state == NULL) {
595  goto not_found;
596  }
597  if (entry) {
598  *entry = state;
599  }
600  return 1;
601  not_found:
602  return 0;
603 }
604 
605 /** Note the given failure in state. */
606 static void
608  rend_intro_point_failure_t failure)
609 {
610  tor_assert(state);
611  switch (failure) {
612  case INTRO_POINT_FAILURE_GENERIC:
613  state->error = 1;
614  break;
615  case INTRO_POINT_FAILURE_TIMEOUT:
616  state->timed_out = 1;
617  break;
618  case INTRO_POINT_FAILURE_UNREACHABLE:
619  state->unreachable_count++;
620  break;
621  default:
623  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
633  const ed25519_public_key_t *auth_key,
634  hs_cache_intro_state_t **state)
635 {
636  hs_cache_intro_state_t *entry, *old_entry;
638 
639  tor_assert(service_pk);
640  tor_assert(auth_key);
641 
642  /* Lookup the state cache for this service key. */
643  cache = digest256map_get(hs_cache_client_intro_state, service_pk->pubkey);
644  if (cache == NULL) {
646  digest256map_set(hs_cache_client_intro_state, service_pk->pubkey, cache);
647  }
648 
649  entry = cache_intro_state_new();
650  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  tor_assert_nonfatal(old_entry == NULL);
654  tor_free(old_entry);
655 
656  if (state) {
657  *state = entry;
658  }
659 }
660 
661 /** Remove every intro point state entry from cache that has been created
662  * before or at the cutoff. */
663 static void
666 {
667  tor_assert(cache);
668 
669  DIGEST256MAP_FOREACH_MODIFY(cache->intro_points, key,
670  hs_cache_intro_state_t *, entry) {
671  if (entry->created_ts <= cutoff) {
672  cache_intro_state_free(entry);
673  MAP_DEL_CURRENT(key);
674  }
675  } DIGEST256MAP_FOREACH_END;
676 }
677 
678 /** Return true iff no intro points are in this cache. */
679 static int
681 {
682  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 cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
690 {
691  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  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  cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
703  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  if (!entry_has_decrypted_descriptor(cache_entry) ||
709  !entry_has_decrypted_descriptor(client_desc)) {
710  remove_v3_desc_as_client(cache_entry);
711  cache_client_desc_free(cache_entry);
712  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  if (cache_entry->desc->plaintext_data.revision_counter >
721  client_desc->desc->plaintext_data.revision_counter) {
722  cache_client_desc_free(client_desc);
723  goto done;
724  }
725  /* Remove old entry. Make space for the new one! */
726  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  hs_client_close_intro_circuits_from_desc(cache_entry->desc);
732 
733  /* Free it. */
734  cache_client_desc_free(cache_entry);
735  }
736 
737  store:
738  /* Store descriptor in cache */
739  store_v3_desc_as_client(client_desc);
740 
741  done:
742  return 0;
743 }
744 
745 /** Return true iff the cached client descriptor at <b>cached_desc</b> has
746  * expired. */
747 static int
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  const networkstatus_t *ns =
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  if (!ns) {
760  return 1;
761  }
762 
763  if (cached_desc->expiration_ts <= ns->valid_after) {
764  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
774 {
775  size_t bytes_removed = 0;
776 
777  if (!hs_cache_v3_client) { /* No cache to clean. Just return. */
778  return 0;
779  }
780 
781  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
782  hs_cache_client_descriptor_t *, entry) {
783  size_t entry_size;
784 
785  /* If the entry has not expired, continue to the next cached entry */
786  if (!cached_client_descriptor_has_expired(now, entry)) {
787  continue;
788  }
789  /* Here, our entry has expired, remove and free. */
790  MAP_DEL_CURRENT(key);
791  entry_size = cache_get_client_entry_size(entry);
792  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  if (entry_has_decrypted_descriptor(entry)) {
801  }
802  /* Entry is not in the cache anymore, destroy it. */
803  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  hs_cache_decrement_allocation(entry_size);
807  /* Logging. */
808  {
809  char key_b64[BASE64_DIGEST256_LEN + 1];
810  digest256_to_base64(key_b64, (const char *) key);
811  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 *
824 {
825  hs_cache_client_descriptor_t *cached_desc = NULL;
826 
827  tor_assert(key);
828 
829  cached_desc = lookup_v3_desc_as_client(key->pubkey);
830  if (cached_desc) {
831  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 *
844 {
845  hs_cache_client_descriptor_t *cached_desc = NULL;
846 
847  tor_assert(key);
848 
849  cached_desc = lookup_v3_desc_as_client(key->pubkey);
850  if (cached_desc && entry_has_decrypted_descriptor(cached_desc)) {
851  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. */
874 hs_cache_store_as_client(const char *desc_str,
875  const ed25519_public_key_t *identity_pk)
876 {
878  hs_cache_client_descriptor_t *client_desc = NULL;
879 
880  tor_assert(desc_str);
881  tor_assert(identity_pk);
882 
883  /* Create client cache descriptor object */
884  client_desc = cache_client_desc_new(desc_str, identity_pk, &ret);
885  if (!client_desc) {
886  log_warn(LD_GENERAL, "HSDesc parsing failed!");
887  log_debug(LD_GENERAL, "Failed to parse HSDesc: %s.", escaped(desc_str));
888  goto err;
889  }
890 
891  /* Push it to the cache */
892  if (cache_store_as_client(client_desc) < 0) {
893  ret = HS_DESC_DECODE_GENERIC_ERROR;
894  goto err;
895  }
896 
897  return ret;
898 
899  err:
900  cache_client_desc_free(client_desc);
901  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
911 {
912  hs_cache_client_descriptor_t *cached_desc = NULL;
913 
914  tor_assert(key);
915 
916  cached_desc = lookup_v3_desc_as_client(key->pubkey);
917  if (!cached_desc) {
918  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  if (entry_has_decrypted_descriptor(cached_desc)) {
924  hs_client_close_intro_circuits_from_desc(cached_desc->desc);
925  }
926  /* Remove and free. */
927  remove_v3_desc_as_client(cached_desc);
928  cache_client_desc_free(cached_desc);
929 
930  /* Logging. */
931  {
932  char key_b64[BASE64_DIGEST256_LEN + 1];
933  digest256_to_base64(key_b64, (const char *) key);
934  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
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. */
947 }
948 
949 /** Purge the client descriptor cache. */
950 void
952 {
953  DIGEST256MAP_FOREACH_MODIFY(hs_cache_v3_client, key,
954  hs_cache_client_descriptor_t *, entry) {
955  size_t entry_size = cache_get_client_entry_size(entry);
956  MAP_DEL_CURRENT(key);
957  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  hs_cache_decrement_allocation(entry_size);
961  } DIGEST256MAP_FOREACH_END;
962 
963  log_info(LD_REND, "Hidden service client descriptor cache purged.");
964 }
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
970  const ed25519_public_key_t *auth_key,
971  rend_intro_point_failure_t failure)
972 {
973  int found;
974  hs_cache_intro_state_t *entry;
975 
976  tor_assert(service_pk);
977  tor_assert(auth_key);
978 
979  found = cache_client_intro_state_lookup(service_pk, auth_key, &entry);
980  if (!found) {
981  /* Create a new entry and add it to the cache. */
982  cache_client_intro_state_add(service_pk, auth_key, &entry);
983  }
984  /* Note down the entry. */
985  cache_client_intro_state_note(entry, failure);
986 }
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. */
992  const ed25519_public_key_t *auth_key)
993 {
994  hs_cache_intro_state_t *state = NULL;
995  cache_client_intro_state_lookup(service_pk, auth_key, &state);
996  return state;
997 }
998 
999 /** Cleanup the client introduction state cache. */
1000 void
1002 {
1003  time_t cutoff = now - HS_CACHE_CLIENT_INTRO_STATE_MAX_AGE;
1004 
1005  DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
1006  hs_cache_client_intro_state_t *, cache) {
1007  /* Cleanup intro points failure. */
1008  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  if (cache_client_intro_state_is_empty(cache)) {
1013  cache_client_intro_state_free(cache);
1014  MAP_DEL_CURRENT(key);
1015  }
1016  } DIGEST256MAP_FOREACH_END;
1017 }
1018 
1019 /** Purge the client introduction state cache. */
1020 void
1022 {
1023  DIGEST256MAP_FOREACH_MODIFY(hs_cache_client_intro_state, key,
1024  hs_cache_client_intro_state_t *, cache) {
1025  MAP_DEL_CURRENT(key);
1026  cache_client_intro_state_free(cache);
1027  } DIGEST256MAP_FOREACH_END;
1028 
1029  log_info(LD_REND, "Hidden service client introduction point state "
1030  "cache purged.");
1031 }
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 hs_cache_client_new_auth_parse(const ed25519_public_key_t *service_pk)
1039 {
1040  bool ret = false;
1041  hs_cache_client_descriptor_t *cached_desc = NULL;
1042 
1043  tor_assert(service_pk);
1044 
1045  if (!hs_cache_v3_client) {
1046  return false;
1047  }
1048 
1049  cached_desc = lookup_v3_desc_as_client(service_pk->pubkey);
1050  if (cached_desc == NULL || entry_has_decrypted_descriptor(cached_desc)) {
1051  /* No entry for that service or the descriptor is already decoded. */
1052  goto end;
1053  }
1054 
1055  /* Attempt a decode. If we are successful, inform the caller. */
1056  if (hs_client_decode_descriptor(cached_desc->encoded_desc, service_pk,
1057  &cached_desc->desc) == HS_DESC_DECODE_OK) {
1058  ret = true;
1059  }
1060 
1061  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 hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
1073 {
1074  time_t k;
1075  size_t bytes_removed = 0;
1076 
1077  /* Our OOM handler called with 0 bytes to remove is a code flow error. */
1078  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  k = hs_cache_max_entry_lifetime();
1092 
1093  do {
1094  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  if (k < 0) {
1099  break;
1100  }
1101  /* Compute a cutoff value with K and the current time. */
1102  cutoff = now - k;
1103 
1104  if (bytes_removed < min_remove_bytes) {
1105  /* We haven't remove enough bytes so clean v3 cache. */
1106  bytes_removed += cache_clean_v3_as_dir(now, cutoff);
1107  /* Decrement K by a post period to shorten the cutoff. */
1108  k -= get_options()->RendPostPeriod;
1109  }
1110  } while (bytes_removed < min_remove_bytes);
1111 
1112  return bytes_removed;
1113 }
1114 
1115 /** Return the maximum size of a v3 HS descriptor. */
1116 unsigned int
1118 {
1119  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
1127 {
1128  /* Calling this twice is very wrong code flow. */
1130  hs_cache_v3_dir = digest256map_new();
1131 
1133  hs_cache_v3_client = digest256map_new();
1134 
1136  hs_cache_client_intro_state = digest256map_new();
1137 }
1138 
1139 /** Cleanup the hidden service cache subsystem. */
1140 void
1142 {
1143  digest256map_free(hs_cache_v3_dir, cache_dir_desc_free_void);
1144  hs_cache_v3_dir = NULL;
1145 
1146  digest256map_free(hs_cache_v3_client, cache_client_desc_free_void);
1147  hs_cache_v3_client = NULL;
1148 
1149  digest256map_free(hs_cache_client_intro_state,
1152  hs_cache_total_allocation = 0;
1153 }
1154 
1155 /* Return total size of the cache. */
1156 size_t
1157 hs_cache_get_total_allocation(void)
1158 {
1159  return hs_cache_total_allocation;
1160 }
1161 
1162 /** Decrement the total bytes attributed to the rendezvous cache by n. */
1163 void
1165 {
1166  static int have_underflowed = 0;
1167 
1168  if (hs_cache_total_allocation >= n) {
1169  hs_cache_total_allocation -= n;
1170  } else {
1171  hs_cache_total_allocation = 0;
1172  if (! have_underflowed) {
1173  have_underflowed = 1;
1174  log_warn(LD_BUG, "Underflow in hs_cache_decrement_allocation");
1175  }
1176  }
1177 }
1178 
1179 /** Increase the total bytes attributed to the rendezvous cache by n. */
1180 void
1182 {
1183  static int have_overflowed = 0;
1184  if (hs_cache_total_allocation <= SIZE_MAX - n) {
1185  hs_cache_total_allocation += n;
1186  } else {
1187  hs_cache_total_allocation = SIZE_MAX;
1188  if (! have_overflowed) {
1189  have_overflowed = 1;
1190  log_warn(LD_BUG, "Overflow in hs_cache_increment_allocation");
1191  }
1192  }
1193 }
time_t approx_time(void)
Definition: approx_time.c:32
const or_options_t * get_options(void)
Definition: config.c:919
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)
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 hs_cache_intro_state_t * cache_intro_state_new(void)
Definition: hs_cache.c:514
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:1001
void hs_cache_clean_as_client(time_t now)
Definition: hs_cache.c:942
size_t hs_cache_handle_oom(time_t now, size_t min_remove_bytes)
Definition: hs_cache.c:1072
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:632
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:1021
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:874
static int cache_client_intro_state_is_empty(const hs_cache_client_intro_state_t *cache)
Definition: hs_cache.c:680
void hs_cache_remove_as_client(const ed25519_public_key_t *key)
Definition: hs_cache.c:910
static size_t cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
Definition: hs_cache.c:133
static void cache_client_intro_state_free_(hs_cache_client_intro_state_t *cache)
Definition: hs_cache.c:554
const char * hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
Definition: hs_cache.c:823
static hs_cache_client_intro_state_t * cache_client_intro_state_new(void)
Definition: hs_cache.c:541
void hs_cache_free_all(void)
Definition: hs_cache.c:1141
int hs_cache_lookup_as_dir(uint32_t version, const char *query, const char **desc_out)
Definition: hs_cache.c:318
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:664
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:748
const hs_descriptor_t * hs_cache_lookup_as_client(const ed25519_public_key_t *key)
Definition: hs_cache.c:843
void hs_cache_decrement_allocation(size_t n)
Definition: hs_cache.c:1164
static hs_cache_dir_descriptor_t * cache_dir_desc_new(const char *desc)
Definition: hs_cache.c:105
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 hs_cache_dir_descriptor_t * lookup_v3_desc_as_dir(const uint8_t *key)
Definition: hs_cache.c:72
static int cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
Definition: hs_cache.c:689
STATIC hs_cache_client_descriptor_t * lookup_v3_desc_as_client(const uint8_t *key)
Definition: hs_cache.c:437
unsigned int hs_cache_get_max_descriptor_size(void)
Definition: hs_cache.c:1117
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:969
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:991
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:951
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:773
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:1181
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:1126
static void cache_client_desc_free_(hs_cache_client_descriptor_t *desc)
Definition: hs_cache.c:361
static void cache_client_intro_state_note(hs_cache_intro_state_t *state, rend_intro_point_failure_t failure)
Definition: hs_cache.c:607
static void cache_client_intro_state_free_void(void *entry)
Definition: hs_cache.c:565
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:2522
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:1957
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:74
static int hs_desc_is_supported_version(uint32_t version)
#define HS_DESC_MAX_LEN
Definition: hs_descriptor.h:49
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:52
#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:2220
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:176
#define tor_assert(expr)
Definition: util_bug.h:102