1 /* Copyright (c) 2020, 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
;
178 MOCK(networkstatus_get_live_consensus
,
179 mock_networkstatus_get_live_consensus
);
181 /* Setup consensus with proper time so we can compute the time period. */
182 ret
= parse_rfc1123_time("Sat, 26 Oct 1985 13:00:00 UTC",
183 &mock_ns
.valid_after
);
184 tt_int_op(ret
, OP_EQ
, 0);
185 ret
= parse_rfc1123_time("Sat, 26 Oct 1985 14:00:00 UTC",
186 &mock_ns
.fresh_until
);
187 tt_int_op(ret
, OP_EQ
, 0);
189 config
.ob_master_pubkeys
= smartlist_new();
190 tt_assert(config
.ob_master_pubkeys
);
192 /* Set up an instance */
193 service
= tor_malloc_zero(sizeof(hs_service_t
));
194 service
->config
= config
;
195 /* Setup the service descriptors */
196 service
->desc_current
= service_descriptor_new();
197 service
->desc_next
= service_descriptor_new();
199 /* First try to compute subcredentials but with no OB keys. Make sure that
200 * subcreds get NULLed. To do this check we first poison subcreds. */
201 subcreds
= (void*)999;
202 tt_ptr_op(subcreds
, OP_NE
, NULL
);
203 size_t num
= compute_subcredentials(service
, &subcreds
);
204 tt_ptr_op(subcreds
, OP_EQ
, NULL
);
206 /* Generate a keypair to add to the OB keys list. */
207 ed25519_keypair_generate(&onion_addr_kp_1
, 0);
208 smartlist_add(config
.ob_master_pubkeys
, &onion_addr_kp_1
.pubkey
);
210 /* Set up the instance subcredentials */
211 char current_subcred
[SUBCRED_LEN
];
212 char next_subcred
[SUBCRED_LEN
];
213 memset(current_subcred
, 'C', SUBCRED_LEN
);
214 memset(next_subcred
, 'N', SUBCRED_LEN
);
215 memcpy(service
->desc_current
->desc
->subcredential
.subcred
, current_subcred
,
217 memcpy(service
->desc_next
->desc
->subcredential
.subcred
, next_subcred
,
220 /* See that subcreds are computed properly */
221 num
= compute_subcredentials(service
, &subcreds
);
222 /* 5 subcredentials: 3 for the frontend, 2 for the instance */
223 tt_uint_op(num
, OP_EQ
, 5);
224 tt_ptr_op(subcreds
, OP_NE
, NULL
);
226 /* Validate the subcredentials we just got. We'll build them oursevles with
227 * the right time period steps and compare. */
228 const uint64_t tp
= hs_get_time_period_num(0);
229 const int steps
[3] = {0, -1, 1};
232 for (i
= 0; i
< 3; i
++) {
233 hs_subcredential_t subcredential
;
234 ed25519_public_key_t blinded_pubkey
;
235 hs_build_blinded_pubkey(&onion_addr_kp_1
.pubkey
, NULL
, 0, tp
+ steps
[i
],
237 hs_get_subcredential(&onion_addr_kp_1
.pubkey
, &blinded_pubkey
,
239 tt_mem_op(subcreds
[i
].subcred
, OP_EQ
, subcredential
.subcred
,
243 tt_mem_op(subcreds
[i
++].subcred
, OP_EQ
, current_subcred
, SUBCRED_LEN
);
244 tt_mem_op(subcreds
[i
++].subcred
, OP_EQ
, next_subcred
, SUBCRED_LEN
);
249 smartlist_free(config
.ob_master_pubkeys
);
251 memset(&service
->config
, 0, sizeof(hs_service_config_t
));
252 hs_service_free(service
);
255 UNMOCK(networkstatus_get_live_consensus
);
258 struct testcase_t hs_ob_tests
[] = {
259 { "parse_config_file", test_parse_config_file
, TT_FORK
,
261 { "parse_config_file_bad", test_parse_config_file_bad
, TT_FORK
,
264 { "get_subcredentials", test_get_subcredentials
, TT_FORK
,