Tor 0.4.9.0-alpha-dev
hs_ob.c
Go to the documentation of this file.
1/* Copyright (c) 2017-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file hs_ob.c
6 * \brief Implement Onion Balance specific code.
7 **/
8
9#define HS_OB_PRIVATE
10
12
15
16#include "lib/confmgt/confmgt.h"
18
19#include "feature/hs/hs_ob.h"
20
21/* Options config magic number. */
22#define OB_OPTIONS_MAGIC 0x631DE7EA
23
24/* Helper macros. */
25#define VAR(varname, conftype, member, initvalue) \
26 CONFIG_VAR_ETYPE(ob_options_t, varname, conftype, member, 0, initvalue)
27#define V(member,conftype,initvalue) \
28 VAR(#member, conftype, member, initvalue)
29
30/* Dummy instance of ob_options_t, used for type-checking its members with
31 * CONF_CHECK_VAR_TYPE. */
32DUMMY_TYPECHECK_INSTANCE(ob_options_t);
33
34/* Array of variables for the config file options. */
35static const config_var_t config_vars[] = {
36 V(MasterOnionAddress, LINELIST, NULL),
37
39};
40
41/* "Extra" variable in the state that receives lines we can't parse. This
42 * lets us preserve options from versions of Tor newer than us. */
43static const struct_member_t config_extra_vars = {
44 .name = "__extra",
46 .offset = offsetof(ob_options_t, ExtraLines),
47};
48
49/* Configuration format of ob_options_t. */
50static const config_format_t config_format = {
51 .size = sizeof(ob_options_t),
52 .magic = {
53 "ob_options_t",
54 OB_OPTIONS_MAGIC,
55 offsetof(ob_options_t, magic_),
56 },
57 .vars = config_vars,
58 .extra = &config_extra_vars,
59};
60
61/* Global configuration manager for the config file. */
62static config_mgr_t *config_options_mgr = NULL;
63
64/* Return the configuration manager for the config file. */
65static const config_mgr_t *
66get_config_options_mgr(void)
67{
68 if (PREDICT_UNLIKELY(config_options_mgr == NULL)) {
69 config_options_mgr = config_mgr_new(&config_format);
70 config_mgr_freeze(config_options_mgr);
71 }
72 return config_options_mgr;
73}
74
75#define ob_option_free(val) \
76 FREE_AND_NULL(ob_options_t, ob_option_free_, (val))
77
78/** Helper: Free a config options object. */
79static void
80ob_option_free_(ob_options_t *opts)
81{
82 if (opts == NULL) {
83 return;
84 }
85 config_free(get_config_options_mgr(), opts);
86}
87
88/** Return an allocated config options object. */
89static ob_options_t *
91{
92 ob_options_t *opts = config_new(get_config_options_mgr());
93 config_init(get_config_options_mgr(), opts);
94 return opts;
95}
96
97/** Helper function: From the configuration line value which is an onion
98 * address with the ".onion" extension, find the public key and put it in
99 * pkey_out.
100 *
101 * On success, true is returned. Else, false and pkey is untouched. */
102static bool
103get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
104{
105 char address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
106
107 tor_assert(value);
108 tor_assert(pkey_out);
109
110 if (strcmpend(value, ".onion")) {
111 /* Not a .onion extension, bad format. */
112 return false;
113 }
114
115 /* Length validation. The -1 is because sizeof() counts the NUL byte. */
116 if (strlen(value) >
117 (HS_SERVICE_ADDR_LEN_BASE32 + sizeof(".onion") - 1)) {
118 /* Too long, bad format. */
119 return false;
120 }
121
122 /* We don't want the .onion so we add 2 because size - 1 is copied with
123 * strlcpy() in order to accommodate the NUL byte and sizeof() counts the NUL
124 * byte so we need to remove them from the equation. */
125 strlcpy(address, value, strlen(value) - sizeof(".onion") + 2);
126
127 if (hs_parse_address_no_log(address, pkey_out, NULL, NULL, NULL) < 0) {
128 return false;
129 }
130
131 /* Success. */
132 return true;
133}
134
135/** Parse the given ob options in opts and set the service config object
136 * accordingly.
137 *
138 * Return 1 on success else 0. */
139static int
140ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
141{
142 int ret = 0;
143 config_line_t *line;
144
145 tor_assert(config);
146 tor_assert(opts);
147
148 for (line = opts->MasterOnionAddress; line; line = line->next) {
149 /* Allocate config list if need be. */
150 if (!config->ob_master_pubkeys) {
152 }
153 ed25519_public_key_t *pubkey = tor_malloc_zero(sizeof(*pubkey));
154
155 if (!get_onion_public_key(line->value, pubkey)) {
156 log_warn(LD_REND, "OnionBalance: MasterOnionAddress %s is invalid",
157 line->value);
158 tor_free(pubkey);
159 goto end;
160 }
161 smartlist_add(config->ob_master_pubkeys, pubkey);
162 log_notice(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
163 line->value);
164 }
165 /* Success. */
166 ret = 1;
167
168 end:
169 /* No keys added, we free the list since no list means no onion balance
170 * support for this tor instance. */
171 if (smartlist_len(config->ob_master_pubkeys) == 0) {
172 smartlist_free(config->ob_master_pubkeys);
173 }
174 return ret;
175}
176
177/** For the given master public key and time period, compute the subcredential
178 * and put them into subcredential. The subcredential parameter needs to be at
179 * least DIGEST256_LEN in size. */
180static void
182 hs_subcredential_t *subcredential)
183{
184 ed25519_public_key_t blinded_pubkey;
185
186 tor_assert(pkey);
187 tor_assert(subcredential);
188
189 hs_build_blinded_pubkey(pkey, NULL, 0, tp, &blinded_pubkey);
190 hs_get_subcredential(pkey, &blinded_pubkey, subcredential);
191}
192
193/*
194 * Public API.
195 */
196
197/** Return true iff the given service is configured as an onion balance
198 * instance. To satisfy that condition, there must at least be one master
199 * ed25519 public key configured. */
200bool
202{
203 if (BUG(service == NULL)) {
204 return false;
205 }
206
207 /* No list, we are not an instance. */
208 if (!service->config.ob_master_pubkeys) {
209 return false;
210 }
211
212 return smartlist_len(service->config.ob_master_pubkeys) > 0;
213}
214
215/** Read and parse the config file at fname on disk. The service config object
216 * is populated with the options if any.
217 *
218 * Return 1 on success else 0. This is to follow the "ok" convention in
219 * hs_config.c. */
220int
222{
223 static const char *fname = "ob_config";
224 int ret = 0;
225 char *content = NULL, *errmsg = NULL, *config_file_path = NULL;
226 ob_options_t *options = NULL;
227 config_line_t *lines = NULL;
228
229 tor_assert(config);
230
231 /* Read file from disk. */
232 config_file_path = hs_path_from_filename(config->directory_path, fname);
233 content = read_file_to_str(config_file_path, 0, NULL);
234 if (!content) {
235 log_warn(LD_FS, "OnionBalance: Unable to read config file %s",
236 escaped(config_file_path));
237 goto end;
238 }
239
240 /* Parse lines. */
241 if (config_get_lines(content, &lines, 0) < 0) {
242 goto end;
243 }
244
245 options = ob_option_new();
246 config_assign(get_config_options_mgr(), options, lines, 0, &errmsg);
247 if (errmsg) {
248 log_warn(LD_REND, "OnionBalance: Unable to parse config file: %s",
249 errmsg);
250 tor_free(errmsg);
251 goto end;
252 }
253
254 /* Parse the options and set the service config object with the details. */
255 ret = ob_option_parse(config, options);
256
257 end:
258 config_free_lines(lines);
259 ob_option_free(options);
260 tor_free(content);
261 tor_free(config_file_path);
262 return ret;
263}
264
265/** Compute all possible subcredentials for every onion master key in the given
266 * service config object. subcredentials_out is allocated and set as an
267 * continuous array containing all possible values.
268 *
269 * On success, return the number of subcredential put in the array which will
270 * correspond to an array of size: n * DIGEST256_LEN where DIGEST256_LEN is the
271 * length of a single subcredential.
272 *
273 * If the given configuration object has no OB master keys configured, 0 is
274 * returned and subcredentials_out is set to NULL.
275 *
276 * Otherwise, this can't fail. */
277STATIC size_t
279 hs_subcredential_t **subcredentials_out)
280{
281 unsigned int num_pkeys, idx = 0;
282 hs_subcredential_t *subcreds = NULL;
283 const int steps[3] = {0, -1, 1};
284 const unsigned int num_steps = ARRAY_LENGTH(steps);
285 const uint64_t tp = hs_get_time_period_num(0);
286
287 tor_assert(service);
288 tor_assert(subcredentials_out);
289 /* Our caller has checked these too */
290 tor_assert(service->desc_current);
291 tor_assert(service->desc_next);
292
293 /* Make sure we are an OB instance, or bail out. */
294 num_pkeys = smartlist_len(service->config.ob_master_pubkeys);
295 if (!num_pkeys) {
296 *subcredentials_out = NULL;
297 return 0;
298 }
299
300 /* Time to build all the subcredentials for each time period: two for each
301 * instance descriptor plus three for the onionbalance frontend service: the
302 * previous one (-1), the current one (0) and the next one (1) for each
303 * configured key in order to accommodate client and service consensus skew.
304 *
305 * If the client consensus after_time is at 23:00 but the service one is at
306 * 01:00, the client will be using the previous time period where the
307 * service will think it is the client next time period. Thus why we have
308 * to try them all.
309 *
310 * The normal use case works because the service gets the descriptor object
311 * that corresponds to the intro point's request, and because each
312 * descriptor corresponds to a specific subcredential, we get the right
313 * subcredential out of it, and use that to do the decryption.
314 *
315 * As a slight optimization, statistically, the current time period (0) will
316 * be the one to work first so we'll put them first in the array to maximize
317 * our chance of success. */
318
319 /* We use a flat array, not a smartlist_t, in order to minimize memory
320 * allocation.
321 *
322 * Size of array is: length of a single subcredential multiplied by the
323 * number of time period we need to compute and finally multiplied by the
324 * total number of keys we are about to process. In other words, for each
325 * key, we allocate 3 subcredential slots. Then in the end we also add two
326 * subcredentials for this instance's active descriptors. */
327 subcreds =
328 tor_calloc((num_steps * num_pkeys) + 2, sizeof(hs_subcredential_t));
329
330 /* For each master pubkey we add 3 subcredentials: */
331 for (unsigned int i = 0; i < num_steps; i++) {
333 const ed25519_public_key_t *, pkey) {
334 build_subcredential(pkey, tp + steps[i], &subcreds[idx]);
335 idx++;
336 } SMARTLIST_FOREACH_END(pkey);
337 }
338
339 /* And then in the end we add the two subcredentials of the current active
340 * instance descriptors */
341 memcpy(&subcreds[idx++], &service->desc_current->desc->subcredential,
342 sizeof(hs_subcredential_t));
343 memcpy(&subcreds[idx++], &service->desc_next->desc->subcredential,
344 sizeof(hs_subcredential_t));
345
346 log_info(LD_REND, "Refreshing %u onionbalance keys (TP #%d).",
347 idx, (int)tp);
348
349 *subcredentials_out = subcreds;
350 return idx;
351}
352
353/**
354 * If we are an Onionbalance instance, refresh our keys.
355 *
356 * If we are not an Onionbalance instance or we are not ready to do so, this
357 * is a NOP.
358 *
359 * This function is called every time we build a new descriptor. That's
360 * because we want our Onionbalance keys to always use up-to-date
361 * subcredentials both for the instance (ourselves) and for the onionbalance
362 * frontend.
363 */
364void
366{
367 hs_subcredential_t *ob_subcreds = NULL;
368 size_t num_subcreds;
369
370 tor_assert(service);
371
372 /* Don't do any of this if we are not configured as an OB instance */
373 if (!hs_ob_service_is_instance(service)) {
374 return;
375 }
376
377 /* We need both service descriptors created to make onionbalance keys.
378 *
379 * That's because we fetch our own (the instance's) subcredentials from our
380 * own descriptors which should always include the latest subcredentials that
381 * clients would use.
382 *
383 * This function is called with each descriptor build, so we will be
384 * eventually be called when both descriptors are created. */
385 if (!service->desc_current || !service->desc_next) {
386 return;
387 }
388
389 /* Get a new set of subcreds */
390 num_subcreds = compute_subcredentials(service, &ob_subcreds);
391 if (BUG(!num_subcreds)) {
392 return;
393 }
394
395 /* Delete old subcredentials if any */
396 if (service->state.ob_subcreds) {
397 tor_free(service->state.ob_subcreds);
398 }
399
400 service->state.ob_subcreds = ob_subcreds;
401 service->state.n_ob_subcreds = num_subcreds;
402}
403
404/** Free any memory allocated by the onionblance subsystem. */
405void
407{
408 config_mgr_free(config_options_mgr);
409}
#define ARRAY_LENGTH(x)
int config_get_lines(const char *string, config_line_t **result, int extended)
Definition: confline.c:200
Header for confline.c.
#define END_OF_CONFIG_VARS
Definition: confmacros.h:22
void config_init(const config_mgr_t *mgr, void *options)
Definition: confmgt.c:1158
void config_mgr_freeze(config_mgr_t *mgr)
Definition: confmgt.c:285
int config_assign(const config_mgr_t *mgr, void *options, config_line_t *list, unsigned config_assign_flags, char **msg)
Definition: confmgt.c:937
config_mgr_t * config_mgr_new(const config_format_t *toplevel_fmt)
Definition: confmgt.c:145
void * config_new(const config_mgr_t *mgr)
Definition: confmgt.c:387
Header for confmgt.c.
@ CONFIG_TYPE_LINELIST
Definition: conftypes.h:61
const char * escaped(const char *s)
Definition: escape.c:126
void hs_get_subcredential(const ed25519_public_key_t *identity_pk, const ed25519_public_key_t *blinded_pk, hs_subcredential_t *subcred_out)
Definition: hs_common.c:565
uint64_t hs_get_time_period_num(time_t now)
Definition: hs_common.c:269
void hs_build_blinded_pubkey(const ed25519_public_key_t *pk, const uint8_t *secret, size_t secret_len, uint64_t time_period_num, ed25519_public_key_t *blinded_pk_out)
Definition: hs_common.c:927
int hs_parse_address_no_log(const char *address, ed25519_public_key_t *key_out, uint8_t *checksum_out, uint8_t *version_out, const char **errmsg)
Definition: hs_common.c:800
char * hs_path_from_filename(const char *directory, const char *filename)
Definition: hs_common.c:178
#define HS_SERVICE_ADDR_LEN_BASE32
Definition: hs_common.h:80
void hs_ob_free_all(void)
Definition: hs_ob.c:406
static ob_options_t * ob_option_new(void)
Definition: hs_ob.c:90
void hs_ob_refresh_keys(hs_service_t *service)
Definition: hs_ob.c:365
bool hs_ob_service_is_instance(const hs_service_t *service)
Definition: hs_ob.c:201
static int ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
Definition: hs_ob.c:140
static void ob_option_free_(ob_options_t *opts)
Definition: hs_ob.c:80
static void build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp, hs_subcredential_t *subcredential)
Definition: hs_ob.c:181
STATIC size_t compute_subcredentials(const hs_service_t *service, hs_subcredential_t **subcredentials_out)
Definition: hs_ob.c:278
int hs_ob_parse_config_file(hs_service_config_t *config)
Definition: hs_ob.c:221
static bool get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
Definition: hs_ob.c:103
Header file for the specific code for onion balance.
Header file containing service data for the HS subsystem.
#define LD_REND
Definition: log.h:84
#define LD_FS
Definition: log.h:70
#define tor_free(p)
Definition: malloc.h:56
Header file for networkstatus.c.
Networkstatus consensus/vote structure.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
hs_subcredential_t subcredential
smartlist_t * ob_master_pubkeys
Definition: hs_service.h:276
hs_descriptor_t * desc
Definition: hs_service.h:164
hs_service_descriptor_t * desc_current
Definition: hs_service.h:334
hs_service_state_t state
Definition: hs_service.h:325
hs_service_config_t config
Definition: hs_service.h:331
hs_service_descriptor_t * desc_next
Definition: hs_service.h:336
const char * name
Definition: conftypes.h:98
#define STATIC
Definition: testsupport.h:32
#define tor_assert(expr)
Definition: util_bug.h:103
int strcmpend(const char *s1, const char *s2)
Definition: util_string.c:253