diff options
author | David Goulet <dgoulet@torproject.org> | 2020-01-09 15:18:32 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2020-01-21 10:31:29 -0500 |
commit | 02f1caa583ca0e09e4c75ff6d9399f5d53931d2b (patch) | |
tree | c1a116c32e627e0199349d8ea059b27f9a32781e /src/feature/hs/hs_ob.c | |
parent | ef28afa2551a6827d85ceb00d8fe2a69d1605795 (diff) | |
download | tor-02f1caa583ca0e09e4c75ff6d9399f5d53931d2b.tar.gz tor-02f1caa583ca0e09e4c75ff6d9399f5d53931d2b.zip |
hs-v3: Validate INTRO2 cells for onion balance
Closes #32709
Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/feature/hs/hs_ob.c')
-rw-r--r-- | src/feature/hs/hs_ob.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c index 633b157a09..7e84af3d99 100644 --- a/src/feature/hs/hs_ob.c +++ b/src/feature/hs/hs_ob.c @@ -158,6 +158,8 @@ ob_option_parse(hs_service_config_t *config, const ob_options_t *opts) goto end; } smartlist_add(config->ob_master_pubkeys, pubkey); + log_info(LD_REND, "OnionBalance: MasterOnionAddress %s registered", + line->value); } /* Success. */ ret = 1; @@ -171,6 +173,26 @@ ob_option_parse(hs_service_config_t *config, const ob_options_t *opts) return ret; } +/** For the given master public key and time period, compute the subcredential + * and put them into subcredential. The subcredential parameter needs to be at + * least DIGEST256_LEN in size. */ +static void +build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp, + uint8_t *subcredential) +{ + ed25519_public_key_t blinded_pubkey; + + tor_assert(pkey); + tor_assert(subcredential); + + hs_build_blinded_pubkey(pkey, NULL, 0, tp, &blinded_pubkey); + hs_get_subcredential(pkey, &blinded_pubkey, subcredential); +} + +/* + * Public API. + */ + /** Read and parse the config file at fname on disk. The service config object * is populated with the options if any. * @@ -220,3 +242,78 @@ hs_ob_parse_config_file(hs_service_config_t *config) tor_free(config_file_path); return ret; } + +/** Compute all possible subcredentials for every onion master key in the + * given service config object. The subcredentials is allocated and set as an + * continous array containing all possible values. + * + * On success, return the number of subcredential put in the array which will + * correspond to an arry of size: n * DIGEST256_LEN where DIGEST256_LEN is the + * length of a single subcredential. + * + * If the given configuration object has no OB master keys configured, 0 is + * returned and subcredentials is set to NULL. + * + * Otherwise, this can't fail. */ +size_t +hs_ob_get_subcredentials(const hs_service_config_t *config, + uint8_t **subcredentials) +{ + unsigned int num_pkeys, idx = 0; + uint8_t *subcreds = NULL; + const int steps[3] = {0, -1, 1}; + const unsigned int num_steps = ARRAY_LENGTH(steps); + const size_t subcred_len = DIGEST256_LEN; + const uint64_t tp = hs_get_time_period_num(0); + + tor_assert(config); + tor_assert(subcredentials); + + num_pkeys = smartlist_len(config->ob_master_pubkeys); + if (!num_pkeys) { + goto end; + } + + /* Time to build all the subcredentials for each time period: the previous + * one (-1), the current one (0) and the next one (1) for each configured + * key in order to accomodate client and service consensus skew. + * + * If the client consensus after_time is at 23:00 but the service one is at + * 01:00, the client will be using the previous time period where the + * service will think it is the client next time period. Thus why we have + * to try them all. + * + * The normal use case works because the service gets the descriptor object + * that corresponds to the intro point's request, and because each + * descriptor corresponds to a specific subcredential, we get the right + * subcredential out of it, and use that to do the decryption. + * + * As a slight optimization, statistically, the current time period (0) will + * be the one to work first so we'll put them first in the array to maximize + * our chance of success. */ + + /* We use a flat array, not a smartlist_t, in order to minimize memory + * allocation. This function is called for _each_ INTRODUCE2 cell arriving + * on this instance and thus the less we allocate small chunks often, + * usually the healthier our overall memory will be. + * + * Size of array is: length of a single subcredential multiplied by the + * number of time period we need to compute and finally multiplied by the + * total number of keys we are about to process. In other words, for each + * key, we allocate 3 subcredential slots. */ + subcreds = tor_malloc_zero(subcred_len * num_steps * num_pkeys); + + /* For each time period step. */ + for (unsigned int i = 0; i < num_steps; i++) { + SMARTLIST_FOREACH_BEGIN(config->ob_master_pubkeys, + const ed25519_public_key_t *, pkey) { + build_subcredential(pkey, tp + steps[i], + &(subcreds[idx * subcred_len])); + idx++; + } SMARTLIST_FOREACH_END(pkey); + } + + end: + *subcredentials = subcreds; + return idx; +} |