1 /* Copyright (c) 2020-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Test hidden service onion balance functionality.
10 #define HS_SERVICE_PRIVATE
13 #include "test/test.h"
14 #include "test/test_helpers.h"
15 #include "test/log_test_helpers.h"
17 #include "app/config/config.h"
18 #include "feature/hs/hs_config.h"
19 #include "feature/hs/hs_ob.h"
20 #include "feature/hs/hs_service.h"
21 #include "feature/nodelist/networkstatus.h"
22 #include "feature/nodelist/networkstatus_st.h"
24 static ed25519_keypair_t onion_addr_kp_1
;
25 static char onion_addr_1
[HS_SERVICE_ADDR_LEN_BASE32
+ 1];
27 static ed25519_keypair_t onion_addr_kp_2
;
28 static char onion_addr_2
[HS_SERVICE_ADDR_LEN_BASE32
+ 1];
30 static bool config_is_good
= true;
33 helper_tor_config(const char *conf
)
36 or_options_t
*options
= helper_parse_options(conf
);
38 ret
= hs_config_service_all(options
, 0);
40 or_options_free(options
);
44 static networkstatus_t mock_ns
;
46 static networkstatus_t
*
47 mock_networkstatus_get_live_consensus(time_t now
)
54 mock_read_file_to_str(const char *filename
, int flags
, struct stat
*stat_out
)
61 if (!strcmp(filename
, get_fname("hs3" PATH_SEPARATOR
"ob_config"))) {
63 tor_asprintf(&ret
, "MasterOnionAddress %s.onion\n"
64 "MasterOnionAddress %s.onion\n",
65 onion_addr_1
, onion_addr_2
);
67 tor_asprintf(&ret
, "MasterOnionAddress JUNKJUNKJUNK.onion\n"
68 "UnknownOption BLAH\n");
78 test_parse_config_file(void *arg
)
82 const ed25519_public_key_t
*pkey
;
88 MOCK(read_file_to_str
, mock_read_file_to_str
);
91 "HiddenServiceDir %s\n" \
92 "HiddenServicePort 22\n" \
93 "HiddenServiceOnionBalanceInstance 1\n"
94 tor_asprintf(&conf
, fmt_conf
, get_fname("hs3"));
97 /* Build the OB frontend onion addresses. */
98 ed25519_keypair_generate(&onion_addr_kp_1
, 0);
99 hs_build_address(&onion_addr_kp_1
.pubkey
, HS_VERSION_THREE
, onion_addr_1
);
100 ed25519_keypair_generate(&onion_addr_kp_2
, 0);
101 hs_build_address(&onion_addr_kp_2
.pubkey
, HS_VERSION_THREE
, onion_addr_2
);
103 ret
= helper_tor_config(conf
);
105 tt_int_op(ret
, OP_EQ
, 0);
107 /* Load the keys for the service. After that, the v3 service should be
108 * registered in the global map and we'll be able to access it. */
109 tt_int_op(get_hs_service_staging_list_size(), OP_EQ
, 1);
110 hs_service_load_all_keys();
111 tt_int_op(get_hs_service_map_size(), OP_EQ
, 1);
112 const hs_service_t
*s
= get_first_service();
114 tt_assert(s
->config
.ob_master_pubkeys
);
115 tt_assert(hs_ob_service_is_instance(s
));
116 tt_assert(smartlist_len(s
->config
.ob_master_pubkeys
) == 2);
118 /* Test the public keys we've added. */
119 pkey
= smartlist_get(s
->config
.ob_master_pubkeys
, 0);
120 tt_mem_op(&onion_addr_kp_1
.pubkey
, OP_EQ
, pkey
, ED25519_PUBKEY_LEN
);
121 pkey
= smartlist_get(s
->config
.ob_master_pubkeys
, 1);
122 tt_mem_op(&onion_addr_kp_2
.pubkey
, OP_EQ
, pkey
, ED25519_PUBKEY_LEN
);
127 UNMOCK(read_file_to_str
);
131 test_parse_config_file_bad(void *arg
)
140 MOCK(read_file_to_str
, mock_read_file_to_str
);
142 /* Indicate mock_read_file_to_str() to use the bad config. */
143 config_is_good
= false;
146 "HiddenServiceDir %s\n" \
147 "HiddenServicePort 22\n" \
148 "HiddenServiceOnionBalanceInstance 1\n"
149 tor_asprintf(&conf
, fmt_conf
, get_fname("hs3"));
152 setup_full_capture_of_logs(LOG_INFO
);
153 ret
= helper_tor_config(conf
);
155 tt_int_op(ret
, OP_EQ
, -1);
156 expect_log_msg_containing("OnionBalance: MasterOnionAddress "
157 "JUNKJUNKJUNK.onion is invalid");
158 expect_log_msg_containing("Found unrecognized option \'UnknownOption\'; "
160 teardown_capture_of_logs();
165 UNMOCK(read_file_to_str
);
169 test_get_subcredentials(void *arg
)
172 hs_service_t
*service
= NULL
;
173 hs_service_config_t config
;
174 hs_subcredential_t
*subcreds
= NULL
;
177 memset(&config
, 0, sizeof(config
));
179 MOCK(networkstatus_get_live_consensus
,
180 mock_networkstatus_get_live_consensus
);
182 /* Setup consensus with proper time so we can compute the time period. */
183 ret
= parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
184 &mock_ns
.valid_after
);
185 tt_int_op(ret
, OP_EQ
, 0);
186 ret
= parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
187 &mock_ns
.fresh_until
);
188 tt_int_op(ret
, OP_EQ
, 0);
190 config
.ob_master_pubkeys
= smartlist_new();
191 tt_assert(config
.ob_master_pubkeys
);
193 /* Set up an instance */
194 service
= tor_malloc_zero(sizeof(hs_service_t
));
195 service
->config
= config
;
196 /* Setup the service descriptors */
197 service
->desc_current
= service_descriptor_new();
198 service
->desc_next
= service_descriptor_new();
200 /* First try to compute subcredentials but with no OB keys. Make sure that
201 * subcreds get NULLed. To do this check we first poison subcreds. */
202 subcreds
= (void*)999;
203 tt_ptr_op(subcreds
, OP_NE
, NULL
);
204 size_t num
= compute_subcredentials(service
, &subcreds
);
205 tt_ptr_op(subcreds
, OP_EQ
, NULL
);
207 /* Generate a keypair to add to the OB keys list. */
208 ed25519_keypair_generate(&onion_addr_kp_1
, 0);
209 smartlist_add(config
.ob_master_pubkeys
, &onion_addr_kp_1
.pubkey
);
211 /* Set up the instance subcredentials */
212 char current_subcred
[SUBCRED_LEN
];
213 char next_subcred
[SUBCRED_LEN
];
214 memset(current_subcred
, 'C', SUBCRED_LEN
);
215 memset(next_subcred
, 'N', SUBCRED_LEN
);
216 memcpy(service
->desc_current
->desc
->subcredential
.subcred
, current_subcred
,
218 memcpy(service
->desc_next
->desc
->subcredential
.subcred
, next_subcred
,
221 /* See that subcreds are computed properly */
222 num
= compute_subcredentials(service
, &subcreds
);
223 /* 5 subcredentials: 3 for the frontend, 2 for the instance */
224 tt_uint_op(num
, OP_EQ
, 5);
225 tt_ptr_op(subcreds
, OP_NE
, NULL
);
227 /* Validate the subcredentials we just got. We'll build them oursevles with
228 * the right time period steps and compare. */
229 const uint64_t tp
= hs_get_time_period_num(0);
230 const int steps
[3] = {0, -1, 1};
233 for (i
= 0; i
< 3; i
++) {
234 hs_subcredential_t subcredential
;
235 ed25519_public_key_t blinded_pubkey
;
236 hs_build_blinded_pubkey(&onion_addr_kp_1
.pubkey
, NULL
, 0, tp
+ steps
[i
],
238 hs_get_subcredential(&onion_addr_kp_1
.pubkey
, &blinded_pubkey
,
240 tt_mem_op(subcreds
[i
].subcred
, OP_EQ
, subcredential
.subcred
,
244 tt_mem_op(subcreds
[i
++].subcred
, OP_EQ
, current_subcred
, SUBCRED_LEN
);
245 tt_mem_op(subcreds
[i
++].subcred
, OP_EQ
, next_subcred
, SUBCRED_LEN
);
250 smartlist_free(config
.ob_master_pubkeys
);
252 memset(&service
->config
, 0, sizeof(hs_service_config_t
));
253 hs_service_free(service
);
256 UNMOCK(networkstatus_get_live_consensus
);
259 struct testcase_t hs_ob_tests
[] = {
260 { "parse_config_file", test_parse_config_file
, TT_FORK
,
262 { "parse_config_file_bad", test_parse_config_file_bad
, TT_FORK
,
265 { "get_subcredentials", test_get_subcredentials
, TT_FORK
,