/* Copyright (c) 2016-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file hs_cache.c
* \brief Handle hidden service descriptor caches.
**/
/* For unit tests.*/
#define HS_CACHE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
#include "lib/crypt_ops/crypto_format.h"
#include "lib/crypt_ops/crypto_util.h"
#include "feature/hs/hs_ident.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_client.h"
#include "feature/hs/hs_descriptor.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/rend/rendcache.h"
#include "feature/hs/hs_cache.h"
#include "feature/nodelist/networkstatus_st.h"
static int cached_client_descriptor_has_expired(time_t now,
const hs_cache_client_descriptor_t *cached_desc);
/** Helper function: Return true iff the cache entry has a decrypted
* descriptor.
*
* A NULL desc object in the entry means that we were not able to decrypt the
* descriptor because we are likely lacking client authorization. It is still
* a valid entry but some operations can't be done without the decrypted
* descriptor thus this function MUST be used to safe guard access to the
* decrypted desc object. */
static inline bool
entry_has_decrypted_descriptor(const hs_cache_client_descriptor_t *entry)
{
tor_assert(entry);
return (entry->desc != NULL);
}
/********************** Directory HS cache ******************/
/** Directory descriptor cache. Map indexed by blinded key. */
static digest256map_t *hs_cache_v3_dir;
/** Remove a given descriptor from our cache. */
static void
remove_v3_desc_as_dir(const hs_cache_dir_descriptor_t *desc)
{
tor_assert(desc);
digest256map_remove(hs_cache_v3_dir, desc->key);
}
/** Store a given descriptor in our cache. */
static void
store_v3_desc_as_dir(hs_cache_dir_descriptor_t *desc)
{
tor_assert(desc);
digest256map_set(hs_cache_v3_dir, desc->key, desc);
}
/** Query our cache and return the entry or NULL if not found. */
static hs_cache_dir_descriptor_t *
lookup_v3_desc_as_dir(const uint8_t *key)
{
tor_assert(key);
return digest256map_get(hs_cache_v3_dir, key);
}
#define cache_dir_desc_free(val) \
FREE_AND_NULL(hs_cache_dir_descriptor_t, cache_dir_desc_free_, (val))
/** Free a directory descriptor object. */
static void
cache_dir_desc_free_(hs_cache_dir_descriptor_t *desc)
{
if (desc == NULL) {
return;
}
hs_desc_plaintext_data_free(desc->plaintext_data);
tor_free(desc->encoded_desc);
tor_free(desc);
}
/** Helper function: Use by the free all function using the digest256map
* interface to cache entries. */
static void
cache_dir_desc_free_void(void *ptr)
{
cache_dir_desc_free_(ptr);
}
/** Create a new directory cache descriptor object from a encoded descriptor.
* On success, return the heap-allocated cache object, otherwise return NULL if
* we can't decode the descriptor. */
static hs_cache_dir_descriptor_t *
cache_dir_desc_new(const char *desc)
{
hs_cache_dir_descriptor_t *dir_desc;
tor_assert(desc);
dir_desc = tor_malloc_zero(sizeof(hs_cache_dir_descriptor_t));
dir_desc->plaintext_data =
tor_malloc_zero(sizeof(hs_desc_plaintext_data_t));
dir_desc->encoded_desc = tor_strdup(desc);
if (hs_desc_decode_plaintext(desc, dir_desc->plaintext_data) < 0) {
log_debug(LD_DIR, "Unable to decode descriptor. Rejecting.");
goto err;
}
/* The blinded pubkey is the indexed key. */
dir_desc->key = dir_desc->plaintext_data->blinded_pubkey.pubkey;
dir_desc->created_ts = time(NULL);
return dir_desc;
err:
cache_dir_desc_free(dir_desc);
return NULL;
}
/** Return the size of a cache entry in bytes. */
static size_t
cache_get_dir_entry_size(const hs_cache_dir_descriptor_t *entry)
{
return (sizeof(*entry) + hs_desc_plaintext_obj_size(entry->plaintext_data)
+