Tor  0.4.6.0-alpha-dev
hs_ob.c
Go to the documentation of this file.
1 /* Copyright (c) 2017-2020, 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 
11 #include "feature/hs/hs_service.h"
12 
15 
16 #include "lib/confmgt/confmgt.h"
17 #include "lib/encoding/confline.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. */
32 DUMMY_TYPECHECK_INSTANCE(ob_options_t);
33 
34 /* Array of variables for the config file options. */
35 static 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. */
43 static const struct_member_t config_extra_vars = {
44  .name = "__extra",
45  .type = CONFIG_TYPE_LINELIST,
46  .offset = offsetof(ob_options_t, ExtraLines),
47 };
48 
49 /* Configuration format of ob_options_t. */
50 static 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. */
62 static config_mgr_t *config_options_mgr = NULL;
63 
64 /* Return the configuration manager for the config file. */
65 static const config_mgr_t *
66 get_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. */
79 static void
80 ob_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. */
89 static 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. */
102 static bool
103 get_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. */
139 static int
140 ob_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) {
151  config->ob_master_pubkeys = smartlist_new();
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. */
180 static void
181 build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp,
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. */
200 bool
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. */
220 int
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. */
277 STATIC 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  */
364 void
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. */
405 void
407 {
408  config_mgr_free(config_options_mgr);
409 }
hs_service_t::config
hs_service_config_t config
Definition: hs_service.h:316
tor_free
#define tor_free(p)
Definition: malloc.h:52
hs_service.h
Header file containing service data for the HS subsystem.
hs_service_t::desc_next
hs_service_descriptor_t * desc_next
Definition: hs_service.h:321
tor_assert
#define tor_assert(expr)
Definition: util_bug.h:102
confmgt.h
Header for confmgt.c.
config_mgr_t
Definition: confmgt.c:107
smartlist_add
void smartlist_add(smartlist_t *sl, void *element)
Definition: smartlist_core.c:117
hs_service_config_t::ob_master_pubkeys
smartlist_t * ob_master_pubkeys
Definition: hs_service.h:265
config_var_t
Definition: conftypes.h:226
smartlist_new
smartlist_t * smartlist_new(void)
Definition: smartlist_core.c:26
ob_option_free_
static void ob_option_free_(ob_options_t *opts)
Definition: hs_ob.c:80
hs_service_descriptor_t::desc
hs_descriptor_t * desc
Definition: hs_service.h:155
strcmpend
int strcmpend(const char *s1, const char *s2)
Definition: util_string.c:251
hs_service_t::state
hs_service_state_t state
Definition: hs_service.h:310
hs_ob_parse_config_file
int hs_ob_parse_config_file(hs_service_config_t *config)
Definition: hs_ob.c:221
networkstatus.h
Header file for networkstatus.c.
config_format_t
Definition: conftypes.h:347
hs_service_config_t::directory_path
char * directory_path
Definition: hs_service.h:218
config_mgr_new
config_mgr_t * config_mgr_new(const config_format_t *toplevel_fmt)
Definition: confmgt.c:145
hs_ob_refresh_keys
void hs_ob_refresh_keys(hs_service_t *service)
Definition: hs_ob.c:365
struct_member_t::name
const char * name
Definition: conftypes.h:98
LD_FS
#define LD_FS
Definition: log.h:70
hs_path_from_filename
char * hs_path_from_filename(const char *directory, const char *filename)
Definition: hs_common.c:179
config_assign
int config_assign(const config_mgr_t *mgr, void *options, config_line_t *list, unsigned config_assign_flags, char **msg)
Definition: confmgt.c:937
hs_ob_service_is_instance
bool hs_ob_service_is_instance(const hs_service_t *service)
Definition: hs_ob.c:201
ed25519_public_key_t
Definition: crypto_ed25519.h:23
config_format_t::size
size_t size
Definition: conftypes.h:348
LD_REND
#define LD_REND
Definition: log.h:84
escaped
const char * escaped(const char *s)
Definition: escape.c:126
hs_service_config_t
Definition: hs_service.h:205
get_onion_public_key
static bool get_onion_public_key(const char *value, ed25519_public_key_t *pkey_out)
Definition: hs_ob.c:103
hs_ob_free_all
void hs_ob_free_all(void)
Definition: hs_ob.c:406
ARRAY_LENGTH
#define ARRAY_LENGTH(x)
Definition: compat_compiler.h:222
CONFIG_TYPE_LINELIST
@ CONFIG_TYPE_LINELIST
Definition: conftypes.h:61
hs_service_t
Definition: hs_service.h:300
struct_member_t
Definition: conftypes.h:96
ob_option_new
static ob_options_t * ob_option_new(void)
Definition: hs_ob.c:90
confline.h
Header for confline.c.
hs_subcredential_t
Definition: hs_ntor.h:43
hs_get_time_period_num
uint64_t hs_get_time_period_num(time_t now)
Definition: hs_common.c:270
SMARTLIST_FOREACH_BEGIN
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
Definition: smartlist_foreach.h:78
hs_ob.h
Header file for the specific code for onion balance.
hs_service_t::desc_current
hs_service_descriptor_t * desc_current
Definition: hs_service.h:319
hs_build_blinded_pubkey
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:1047
config_init
void config_init(const config_mgr_t *mgr, void *options)
Definition: confmgt.c:1158
config_line_t
Definition: confline.h:29
compute_subcredentials
STATIC size_t compute_subcredentials(const hs_service_t *service, hs_subcredential_t **subcredentials_out)
Definition: hs_ob.c:278
hs_descriptor_t::subcredential
hs_subcredential_t subcredential
Definition: hs_descriptor.h:242
hs_parse_address_no_log
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:920
config_get_lines
int config_get_lines(const char *string, config_line_t **result, int extended)
Definition: confline.c:200
config_new
void * config_new(const config_mgr_t *mgr)
Definition: confmgt.c:387
ob_option_parse
static int ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
Definition: hs_ob.c:140
STATIC
#define STATIC
Definition: testsupport.h:32
networkstatus_st.h
Networkstatus consensus/vote structure.
hs_get_subcredential
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:816
config_mgr_freeze
void config_mgr_freeze(config_mgr_t *mgr)
Definition: confmgt.c:285
HS_SERVICE_ADDR_LEN_BASE32
#define HS_SERVICE_ADDR_LEN_BASE32
Definition: hs_common.h:83
END_OF_CONFIG_VARS
#define END_OF_CONFIG_VARS
Definition: confmacros.h:22
build_subcredential
static void build_subcredential(const ed25519_public_key_t *pkey, uint64_t tp, hs_subcredential_t *subcredential)
Definition: hs_ob.c:181