aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/feature/hs/hs_cache.c39
-rw-r--r--src/feature/hs/hs_client.c13
-rw-r--r--src/feature/hs/hs_client.h2
-rw-r--r--src/feature/hs/hs_descriptor.c6
-rw-r--r--src/feature/hs/hs_descriptor.h26
-rw-r--r--src/test/test_hs_descriptor.c4
6 files changed, 70 insertions, 20 deletions
diff --git a/src/feature/hs/hs_cache.c b/src/feature/hs/hs_cache.c
index 395839fce0..39c2267462 100644
--- a/src/feature/hs/hs_cache.c
+++ b/src/feature/hs/hs_cache.c
@@ -397,6 +397,7 @@ 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 ret;
hs_descriptor_t *desc = NULL;
hs_cache_client_descriptor_t *client_desc = NULL;
@@ -404,10 +405,24 @@ cache_client_desc_new(const char *desc_str,
tor_assert(service_identity_pk);
/* Decode the descriptor we just fetched. */
- if (hs_client_decode_descriptor(desc_str, service_identity_pk, &desc) < 0) {
+ ret = hs_client_decode_descriptor(desc_str, service_identity_pk, &desc);
+ if (ret != HS_DESC_DECODE_OK &&
+ ret != HS_DESC_DECODE_NEED_CLIENT_AUTH &&
+ ret != HS_DESC_DECODE_BAD_CLIENT_AUTH) {
+ /* In the case of a missing or bad client authorization, we'll keep the
+ * descriptor in the cache because those credentials can arrive later. */
goto end;
}
- tor_assert(desc);
+ /* Make sure we do have a descriptor if decoding was successful. */
+ if (ret == HS_DESC_DECODE_OK) {
+ tor_assert(desc);
+ } else {
+ if (BUG(desc != NULL)) {
+ /* We are not suppose to have a descriptor if the decoding code is not
+ * indicating success. Just in case, bail early to recover. */
+ goto end;
+ }
+ }
/* All is good: make a cache object for this descriptor */
client_desc = tor_malloc_zero(sizeof(hs_cache_client_descriptor_t));
@@ -635,9 +650,19 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
tor_assert(client_desc);
/* Check if we already have a descriptor from this HS in cache. If we do,
- * check if this descriptor is newer than the cached one */
+ * check if this descriptor is newer than the cached one only if we have a
+ * decoded descriptor. We do keep non-decoded descriptor that requires
+ * client authorization. */
cache_entry = lookup_v3_desc_as_client(client_desc->key.pubkey);
if (cache_entry != NULL) {
+ /* Signalling an undecrypted descriptor. We'll always replace the one we
+ * have with the new one just fetched. */
+ if (cache_entry->desc == NULL) {
+ remove_v3_desc_as_client(cache_entry);
+ cache_client_desc_free(cache_entry);
+ goto store;
+ }
+
/* If we have an entry in our cache that has a revision counter greater
* than the one we just fetched, discard the one we fetched. */
if (cache_entry->desc->plaintext_data.revision_counter >
@@ -657,6 +682,7 @@ cache_store_as_client(hs_cache_client_descriptor_t *client_desc)
cache_client_desc_free(cache_entry);
}
+ store:
/* Store descriptor in cache */
store_v3_desc_as_client(client_desc);
@@ -752,7 +778,9 @@ hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
}
/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
- * its HS descriptor if it's stored in our cache, or NULL if not. */
+ * its HS descriptor if it's stored in our cache, or NULL if not or if the
+ * descriptor was never decrypted. The later can happen if we are waiting for
+ * client authorization to be added. */
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key)
{
@@ -761,8 +789,7 @@ hs_cache_lookup_as_client(const ed25519_public_key_t *key)
tor_assert(key);
cached_desc = lookup_v3_desc_as_client(key->pubkey);
- if (cached_desc) {
- tor_assert(cached_desc->desc);
+ if (cached_desc && cached_desc->desc) {
return cached_desc->desc;
}
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index 4f6686143f..491c52a047 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -1286,13 +1286,15 @@ hs_client_note_connection_attempt_succeeded(const edge_connection_t *conn)
* service_identity_pk, decode the descriptor and set the desc pointer with a
* newly allocated descriptor object.
*
- * Return 0 on success else a negative value and desc is set to NULL. */
-int
+ * On success, HS_DESC_DECODE_OK is returned and desc is set to the decoded
+ * descriptor. On error, desc is set to NULL and a decoding error status is
+ * returned depending on what was the issue. */
+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)
{
- int ret;
+ hs_desc_decode_status_t ret;
uint8_t subcredential[DIGEST256_LEN];
ed25519_public_key_t blinded_pubkey;
hs_client_service_authorization_t *client_auth = NULL;
@@ -1333,12 +1335,13 @@ hs_client_decode_descriptor(const char *desc_str,
log_warn(LD_GENERAL, "Descriptor signing key certificate signature "
"doesn't validate with computed blinded key: %s",
tor_cert_describe_signature_status(cert));
+ ret = HS_DESC_DECODE_GENERIC_ERROR;
goto err;
}
- return 0;
+ return HS_DESC_DECODE_OK;
err:
- return -1;
+ return ret;
}
/** Return true iff there are at least one usable intro point in the service
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 69e48ca31b..0e22a2e044 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -48,7 +48,7 @@ void hs_client_launch_v3_desc_fetch(
const ed25519_public_key_t *onion_identity_pk,
const smartlist_t *hsdirs);
-int hs_client_decode_descriptor(
+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);
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index 056dc81a61..65a6f94802 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -2277,12 +2277,14 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
* authorization is failing. */
log_warn(LD_REND, "Client authorization for requested onion address "
"is invalid. Can't decrypt the descriptor.");
+ ret = HS_DESC_DECODE_BAD_CLIENT_AUTH;
} else {
/* Inform at notice level that the onion address requested can't be
* reached without client authorization most likely. */
log_notice(LD_REND, "Fail to decrypt descriptor for requested onion "
"address. It is likely requiring client "
"authorization.");
+ ret = HS_DESC_DECODE_NEED_CLIENT_AUTH;
}
goto err;
}
@@ -2810,7 +2812,9 @@ hs_desc_encrypted_obj_size(const hs_desc_encrypted_data_t *data)
size_t
hs_desc_obj_size(const hs_descriptor_t *data)
{
- tor_assert(data);
+ if (data == NULL) {
+ return 0;
+ }
return (hs_desc_plaintext_obj_size(&data->plaintext_data) +
hs_desc_encrypted_obj_size(&data->encrypted_data) +
sizeof(data->subcredential));
diff --git a/src/feature/hs/hs_descriptor.h b/src/feature/hs/hs_descriptor.h
index 8d9dac1747..4f726f8c97 100644
--- a/src/feature/hs/hs_descriptor.h
+++ b/src/feature/hs/hs_descriptor.h
@@ -71,11 +71,27 @@ typedef enum {
/** Error code when decoding a descriptor. */
typedef enum {
- HS_DESC_DECODE_ENCRYPTED_ERROR = -4,
- HS_DESC_DECODE_SUPERENC_ERROR = -3,
- HS_DESC_DECODE_PLAINTEXT_ERROR = -2,
- HS_DESC_DECODE_GENERIC_ERROR = -1,
- HS_DESC_DECODE_OK = 0,
+ /* The configured client authorization for the requested .onion address
+ * failed to decode the descriptor. */
+ HS_DESC_DECODE_BAD_CLIENT_AUTH = -6,
+
+ /* The requested .onion address requires a client authorization. */
+ HS_DESC_DECODE_NEED_CLIENT_AUTH = -5,
+
+ /* Error during decryption of the encrypted layer. */
+ HS_DESC_DECODE_ENCRYPTED_ERROR = -4,
+
+ /* Error during decryption of the super encrypted layer. */
+ HS_DESC_DECODE_SUPERENC_ERROR = -3,
+
+ /* Error while decoding the plaintext section. */
+ HS_DESC_DECODE_PLAINTEXT_ERROR = -2,
+
+ /* Generic error. */
+ HS_DESC_DECODE_GENERIC_ERROR = -1,
+
+ /* Decoding a descriptor was successful. */
+ HS_DESC_DECODE_OK = 0,
} hs_desc_decode_status_t;
/** Introduction point information located in a descriptor. */
diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c
index 3d6d8e67d8..9587cae85a 100644
--- a/src/test/test_hs_descriptor.c
+++ b/src/test/test_hs_descriptor.c
@@ -317,14 +317,14 @@ test_decode_descriptor(void *arg)
hs_descriptor_free(decoded);
ret = hs_desc_decode_descriptor(encoded, subcredential,
NULL, &decoded);
- tt_int_op(ret, OP_EQ, HS_DESC_DECODE_ENCRYPTED_ERROR);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_NEED_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have an invalid client secret key, the decoding must fail. */
hs_descriptor_free(decoded);
ret = hs_desc_decode_descriptor(encoded, subcredential,
&invalid_client_kp.seckey, &decoded);
- tt_int_op(ret, OP_EQ, HS_DESC_DECODE_ENCRYPTED_ERROR);
+ tt_int_op(ret, OP_EQ, HS_DESC_DECODE_BAD_CLIENT_AUTH);
tt_assert(!decoded);
/* If we have the client secret key, the decoding must succeed and the