mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-23 20:03:31 +01:00
hs: Descriptor support for PoW
Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
parent
51ce0bb6ef
commit
26957b47ac
@ -173,6 +173,7 @@ typedef enum {
|
||||
R3_DESC_AUTH_CLIENT,
|
||||
R3_ENCRYPTED,
|
||||
R3_FLOW_CONTROL,
|
||||
R3_POW_PARAMS,
|
||||
|
||||
R_IPO_IDENTIFIER,
|
||||
R_IPO_IP_ADDRESS,
|
||||
|
@ -68,6 +68,7 @@
|
||||
#include "feature/dirparse/parsecommon.h"
|
||||
#include "feature/hs/hs_cache.h"
|
||||
#include "feature/hs/hs_config.h"
|
||||
#include "feature/hs/hs_pow.h"
|
||||
#include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */
|
||||
#include "lib/memarea/memarea.h"
|
||||
#include "lib/crypt_ops/crypto_format.h"
|
||||
@ -96,6 +97,7 @@
|
||||
#define str_ip_legacy_key_cert "legacy-key-cert"
|
||||
#define str_intro_point_start "\n" str_intro_point " "
|
||||
#define str_flow_control "flow-control"
|
||||
#define str_pow_params "pow-params"
|
||||
/* Constant string value for the construction to encrypt the encrypted data
|
||||
* section. */
|
||||
#define str_enc_const_superencryption "hsdir-superencrypted-data"
|
||||
@ -117,6 +119,16 @@ static const struct {
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** PoW supported types. */
|
||||
static const struct {
|
||||
hs_pow_desc_type_t type;
|
||||
const char *identifier;
|
||||
} pow_types[] = {
|
||||
{ HS_POW_DESC_V1, "v1"},
|
||||
/* Indicate end of array. */
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/** Descriptor ruleset. */
|
||||
static token_rule_t hs_desc_v3_token_table[] = {
|
||||
T1_START(str_hs_desc, R_HS_DESCRIPTOR, EQ(1), NO_OBJ),
|
||||
@ -143,6 +155,7 @@ static token_rule_t hs_desc_encrypted_v3_token_table[] = {
|
||||
T01(str_intro_auth_required, R3_INTRO_AUTH_REQUIRED, GE(1), NO_OBJ),
|
||||
T01(str_single_onion, R3_SINGLE_ONION_SERVICE, ARGS, NO_OBJ),
|
||||
T01(str_flow_control, R3_FLOW_CONTROL, GE(2), NO_OBJ),
|
||||
T01(str_pow_params, R3_POW_PARAMS, GE(3), NO_OBJ),
|
||||
END_OF_TABLE
|
||||
};
|
||||
|
||||
@ -777,6 +790,31 @@ get_inner_encrypted_layer_plaintext(const hs_descriptor_t *desc)
|
||||
protover_get_supported(PRT_FLOWCTRL),
|
||||
congestion_control_sendme_inc());
|
||||
}
|
||||
|
||||
/* Add PoW parameters if present. */
|
||||
if (desc->encrypted_data.pow_params) {
|
||||
/* Base64 the seed */
|
||||
size_t seed_b64_len = base64_encode_size(HS_POW_SEED_LEN, 0) + 1;
|
||||
char *seed_b64 = tor_malloc_zero(seed_b64_len);
|
||||
int ret = base64_encode(seed_b64, seed_b64_len,
|
||||
(char *)desc->encrypted_data.pow_params->seed,
|
||||
HS_POW_SEED_LEN, 0);
|
||||
/* Return length doesn't count the NUL byte. */
|
||||
tor_assert((size_t) ret == (seed_b64_len - 1));
|
||||
|
||||
/* Convert the expiration time to space-less ISO format. */
|
||||
char time_buf[ISO_TIME_LEN + 1];
|
||||
format_iso_time_nospace(time_buf,
|
||||
desc->encrypted_data.pow_params->expiration_time);
|
||||
|
||||
/* Add "pow-params" line to descriptor encoding. */
|
||||
smartlist_add_asprintf(lines, "%s %s %s %u %s\n", str_pow_params,
|
||||
pow_types[desc->encrypted_data.pow_params->type].identifier,
|
||||
seed_b64,
|
||||
desc->encrypted_data.pow_params->suggested_effort,
|
||||
time_buf);
|
||||
tor_free(seed_b64);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build the introduction point(s) section. */
|
||||
@ -2053,6 +2091,70 @@ desc_sig_is_valid(const char *b64_sig,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Given the token tok for PoW params, decode it as hs_pow_desc_params_t.
|
||||
* tok->args MUST contain at least 4 elements Return 0 on success else -1 on
|
||||
* failure. */
|
||||
static int
|
||||
decode_pow_params(const directory_token_t *tok,
|
||||
hs_pow_desc_params_t *pow_params)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
tor_assert(tok);
|
||||
tor_assert(tok->n_args >= 4);
|
||||
tor_assert(pow_params);
|
||||
|
||||
/* Find the type of PoW system being used. */
|
||||
int match = 0;
|
||||
for (int idx = 0; pow_types[idx].identifier; idx++) {
|
||||
if (!strncmp(tok->args[0], pow_types[idx].identifier,
|
||||
strlen(pow_types[idx].identifier))) {
|
||||
pow_params->type = pow_types[idx].type;
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
log_warn(LD_REND, "Unknown PoW type from descriptor.");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (base64_decode((char *)pow_params->seed, sizeof(pow_params->seed),
|
||||
tok->args[1], strlen(tok->args[1])) !=
|
||||
sizeof(pow_params->seed)) {
|
||||
log_warn(LD_REND, "Unparseable seed %s in PoW params",
|
||||
escaped(tok->args[1]));
|
||||
goto done;
|
||||
}
|
||||
|
||||
int ok;
|
||||
unsigned long effort =
|
||||
tor_parse_ulong(tok->args[2], 10, 1, UINT32_MAX, &ok, NULL);
|
||||
if (!ok) {
|
||||
log_warn(LD_REND, "Unparseable suggested effort %s in PoW params",
|
||||
escaped(tok->args[2]));
|
||||
goto done;
|
||||
}
|
||||
pow_params->suggested_effort = effort;
|
||||
|
||||
/* Parse the expiration time of the PoW params. */
|
||||
time_t expiration_time = 0;
|
||||
if (parse_iso_time_nospace(tok->args[3], &expiration_time)) {
|
||||
log_warn(LD_REND, "Unparseable expiration time %s in PoW params",
|
||||
escaped(tok->args[3]));
|
||||
goto done;
|
||||
}
|
||||
/* Validation of this time is done in client_desc_has_arrived() so we can
|
||||
* trigger a fetch if expired. */
|
||||
pow_params->expiration_time = expiration_time;
|
||||
|
||||
/* Success. */
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Decode descriptor plaintext data for version 3. Given a list of tokens, an
|
||||
* allocated plaintext object that will be populated and the encoded
|
||||
* descriptor with its length. The last one is needed for signature
|
||||
@ -2364,6 +2466,18 @@ desc_decode_encrypted_v3(const hs_descriptor_t *desc,
|
||||
desc_encrypted_out->sendme_inc = sendme_inc;
|
||||
}
|
||||
|
||||
/* Get PoW if any. */
|
||||
tok = find_opt_by_keyword(tokens, R3_POW_PARAMS);
|
||||
if (tok) {
|
||||
hs_pow_desc_params_t *pow_params =
|
||||
tor_malloc_zero(sizeof(hs_pow_desc_params_t));
|
||||
if (decode_pow_params(tok, pow_params)) {
|
||||
tor_free(pow_params);
|
||||
goto err;
|
||||
}
|
||||
desc_encrypted_out->pow_params = pow_params;
|
||||
}
|
||||
|
||||
/* Initialize the descriptor's introduction point list before we start
|
||||
* decoding. Having 0 intro point is valid. Then decode them all. */
|
||||
desc_encrypted_out->intro_points = smartlist_new();
|
||||
@ -2775,6 +2889,7 @@ hs_desc_encrypted_data_free_contents(hs_desc_encrypted_data_t *desc)
|
||||
smartlist_free(desc->intro_points);
|
||||
}
|
||||
tor_free(desc->flow_control_pv);
|
||||
tor_free(desc->pow_params);
|
||||
memwipe(desc, 0, sizeof(*desc));
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,9 @@ typedef struct hs_desc_encrypted_data_t {
|
||||
char *flow_control_pv;
|
||||
uint8_t sendme_inc;
|
||||
|
||||
/** PoW parameters. If NULL, it is not present. */
|
||||
hs_pow_desc_params_t *pow_params;
|
||||
|
||||
/** A list of intro points. Contains hs_desc_intro_point_t objects. */
|
||||
smartlist_t *intro_points;
|
||||
} hs_desc_encrypted_data_t;
|
||||
|
@ -37,10 +37,15 @@ typedef unsigned __int128 uint128_t;
|
||||
#define HS_POW_CHALLENGE_LEN \
|
||||
(HS_POW_SEED_LEN + HS_POW_NONCE_LEN + HS_POW_EFFORT_LEN)
|
||||
|
||||
/** Type of PoW in the descriptor. */
|
||||
typedef enum {
|
||||
HS_POW_DESC_V1 = 1,
|
||||
} hs_pow_desc_type_t;
|
||||
|
||||
/** Proof-of-Work parameters for DoS defense located in a descriptor. */
|
||||
typedef struct hs_pow_desc_params_t {
|
||||
/** Type of PoW system being used, for example "v1". */
|
||||
char *type;
|
||||
/** Type of PoW system being used. */
|
||||
hs_pow_desc_type_t type;
|
||||
|
||||
/** Random 32-byte seed used as input the the PoW hash function. Decoded? */
|
||||
uint8_t seed[HS_POW_SEED_LEN];
|
||||
|
Loading…
Reference in New Issue
Block a user