22 #include "trunnel/congestion_control.h"
23 #include "trunnel/ed25519_cert.h"
24 #include "trunnel/extension.h"
25 #include "trunnel/hs/cell_establish_intro.h"
26 #include "trunnel/hs/cell_introduce1.h"
27 #include "trunnel/hs/cell_rendezvous.h"
38 const uint8_t *encrypted,
size_t encrypted_len,
39 const uint8_t *mac_key,
size_t mac_key_len,
40 uint8_t *mac_out,
size_t mac_out_len)
54 mac_msg_len = encoded_cell_len + (encrypted_len -
DIGEST256_LEN);
58 memcpy(mac_msg, encoded_cell, encoded_cell_len);
59 offset += encoded_cell_len;
62 memcpy(mac_msg + offset, encrypted, (encrypted_len -
DIGEST256_LEN));
68 mac_msg, mac_msg_len);
69 memwipe(mac_msg, 0,
sizeof(mac_msg));
81 size_t n_subcredentials,
83 const uint8_t *encrypted_section,
102 subcredentials, keys) < 0) {
117 size_t encrypted_section_len)
119 uint8_t *decrypted = NULL;
120 crypto_cipher_t *cipher = NULL;
132 decrypted = tor_malloc_zero(encrypted_section_len);
134 (
const char *) encrypted_section,
135 encrypted_section_len) < 0) {
142 crypto_cipher_free(cipher);
150 static trn_cell_introduce_encrypted_t *
155 trn_cell_introduce_encrypted_t *enc_cell = NULL;
161 if (trn_cell_introduce_encrypted_parse(&enc_cell, decrypted_data,
162 decrypted_len) < 0) {
163 log_info(
LD_REND,
"Unable to parse the decrypted ENCRYPTED section of "
164 "the INTRODUCE2 cell on circuit %u for service %s",
170 if (trn_cell_introduce_encrypted_get_onion_key_type(enc_cell) !=
171 TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR) {
172 log_info(
LD_REND,
"INTRODUCE2 onion key type is invalid. Got %u but "
173 "expected %u on circuit %u for service %s",
174 trn_cell_introduce_encrypted_get_onion_key_type(enc_cell),
175 TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR,
181 if (trn_cell_introduce_encrypted_getlen_onion_key(enc_cell) !=
183 log_info(
LD_REND,
"INTRODUCE2 onion key length is invalid. Got %u but "
184 "expected %d on circuit %u for service %s",
185 (
unsigned)trn_cell_introduce_encrypted_getlen_onion_key(enc_cell),
194 trn_cell_introduce_encrypted_free(enc_cell);
207 trn_cell_introduce1_t **cell_ptr_out)
209 trn_cell_introduce1_t *cell = NULL;
217 if (trn_cell_introduce1_parse(&cell, payload, payload_len) < 0) {
218 log_info(
LD_PROTOCOL,
"Unable to parse INTRODUCE2 cell on circuit %u "
226 *cell_ptr_out = cell;
236 const uint8_t *onion_pk)
241 trn_cell_introduce_encrypted_set_onion_key_type(cell,
242 TRUNNEL_HS_INTRO_ONION_KEY_TYPE_NTOR);
245 memcpy(trn_cell_introduce_encrypted_getarray_onion_key(cell), onion_pk,
246 trn_cell_introduce_encrypted_getlen_onion_key(cell));
258 tor_assert(smartlist_len(lspecs) <= UINT8_MAX);
260 uint8_t lspecs_num = (uint8_t) smartlist_len(lspecs);
261 trn_cell_introduce_encrypted_set_nspec(cell, lspecs_num);
266 trn_cell_introduce_encrypted_add_nspecs(cell, ls));
273 trn_cell_introduce_encrypted_t *enc_cell)
278 ssize_t full_len = trn_cell_introduce1_encoded_len(cell) +
279 trn_cell_introduce_encrypted_encoded_len(enc_cell);
283 trn_cell_introduce_encrypted_setlen_pad(enc_cell, padding);
284 memset(trn_cell_introduce_encrypted_getarray_pad(enc_cell), 0,
285 trn_cell_introduce_encrypted_getlen_pad(enc_cell));
296 const trn_cell_introduce_encrypted_t *enc_cell,
300 ssize_t encrypted_len;
301 ssize_t encoded_cell_len, encoded_enc_cell_len;
304 uint8_t *encrypted = NULL;
306 crypto_cipher_t *cipher = NULL;
315 encoded_cell_len = trn_cell_introduce1_encode(encoded_cell,
316 sizeof(encoded_cell), cell);
320 encoded_enc_cell_len =
321 trn_cell_introduce_encrypted_encode(encoded_enc_cell,
322 sizeof(encoded_enc_cell), enc_cell);
327 if (hs_ntor_client_get_introduce1_keys(data->
auth_pk, data->
enc_pk,
330 tor_assert_unreached();
335 sizeof(keys.enc_key) * 8);
340 encrypted_len =
sizeof(data->
client_kp->pubkey) + encoded_enc_cell_len +
343 encrypted = tor_malloc_zero(encrypted_len);
346 memcpy(encrypted, data->
client_kp->pubkey.public_key,
347 sizeof(data->
client_kp->pubkey.public_key));
348 offset +=
sizeof(data->
client_kp->pubkey.public_key);
351 (
const char *) encoded_enc_cell, encoded_enc_cell_len);
352 crypto_cipher_free(cipher);
353 offset += encoded_enc_cell_len;
357 encrypted, encrypted_len,
358 keys.mac_key,
sizeof(keys.mac_key),
360 memcpy(encrypted + offset, mac,
sizeof(mac));
361 offset +=
sizeof(mac);
365 trn_cell_introduce1_setlen_encrypted(cell, encrypted_len);
366 memcpy(trn_cell_introduce1_getarray_encrypted(cell),
367 encrypted, encrypted_len);
370 memwipe(&keys, 0,
sizeof(keys));
372 memwipe(encrypted, 0,
sizeof(encrypted_len));
373 memwipe(encoded_enc_cell, 0,
sizeof(encoded_enc_cell));
382 trn_extension_field_t *field = NULL;
385 field = trn_extension_field_new();
386 trn_extension_field_set_field_type(field,
387 TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST);
390 trn_extension_field_set_field_len(field, 0);
393 trn_extension_add_fields(extensions, field);
394 trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1);
403 trn_cell_introduce_encrypted_t *enc_cell;
404 trn_extension_t *ext;
409 enc_cell = trn_cell_introduce_encrypted_new();
413 ext = trn_extension_new();
419 trn_cell_introduce_encrypted_set_extensions(enc_cell, ext);
422 memcpy(trn_cell_introduce_encrypted_getarray_rend_cookie(enc_cell),
438 trn_cell_introduce_encrypted_free(enc_cell);
449 trn_cell_introduce1_set_auth_key_type(cell,
450 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
453 memcpy(trn_cell_introduce1_getarray_auth_key(cell),
454 data->
auth_pk->pubkey, trn_cell_introduce1_getlen_auth_key(cell));
461 uint8_t param_type, uint64_t param_value)
463 trn_cell_extension_dos_param_t *dos_param =
464 trn_cell_extension_dos_param_new();
467 tor_assert(param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC ||
468 param_type == TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC);
470 trn_cell_extension_dos_param_set_type(dos_param, param_type);
471 trn_cell_extension_dos_param_set_value(dos_param, param_value);
472 trn_cell_extension_dos_add_params(dos_ext, dos_param);
482 trn_extension_t *extensions)
485 size_t dos_ext_encoded_len;
486 uint8_t *field_array;
487 trn_extension_field_t *field = NULL;
488 trn_cell_extension_dos_t *dos_ext = NULL;
494 field = trn_extension_field_new();
495 trn_extension_field_set_field_type(field,
496 TRUNNEL_CELL_EXTENSION_TYPE_DOS);
499 dos_ext = trn_cell_extension_dos_new();
500 trn_cell_extension_dos_set_n_params(dos_ext, 2);
504 TRUNNEL_DOS_PARAM_TYPE_INTRO2_RATE_PER_SEC,
505 service_config->intro_dos_rate_per_sec);
508 TRUNNEL_DOS_PARAM_TYPE_INTRO2_BURST_PER_SEC,
509 service_config->intro_dos_burst_per_sec);
512 ret = trn_cell_extension_dos_encoded_len(dos_ext);
516 dos_ext_encoded_len = ret;
518 trn_extension_field_set_field_len(field, dos_ext_encoded_len);
519 trn_extension_field_setlen_field(field, dos_ext_encoded_len);
521 field_array = trn_extension_field_getarray_field(field);
522 ret = trn_cell_extension_dos_encode(field_array,
523 trn_extension_field_getlen_field(field), dos_ext);
527 tor_assert(ret == (ssize_t) dos_ext_encoded_len);
530 trn_extension_add_fields(extensions, field);
534 trn_extension_set_num(extensions, trn_extension_get_num(extensions) + 1);
537 trn_cell_extension_dos_free(dos_ext);
542 trn_extension_field_free(field);
543 trn_cell_extension_dos_free(dos_ext);
558 trn_extension_t *extensions;
563 extensions = trn_extension_new();
564 trn_extension_set_num(extensions, 0);
592 ssize_t cell_len = -1;
594 trn_cell_establish_intro_t *cell = NULL;
595 trn_extension_t *extensions;
605 cell = trn_cell_establish_intro_new();
606 trn_cell_establish_intro_set_extensions(cell, extensions);
609 trn_cell_establish_intro_set_sig_len(cell, sig_len);
610 trn_cell_establish_intro_setlen_sig(cell, sig_len);
613 trn_cell_establish_intro_set_auth_key_type(cell,
614 TRUNNEL_HS_INTRO_AUTH_KEY_TYPE_ED25519);
620 trn_cell_establish_intro_set_auth_key_len(cell, auth_key_len);
621 trn_cell_establish_intro_setlen_auth_key(cell, auth_key_len);
624 uint8_t *auth_key_ptr = trn_cell_establish_intro_getarray_auth_key(cell);
625 memcpy(auth_key_ptr, ip->
auth_key_kp.pubkey.pubkey, auth_key_len);
630 ssize_t tmp_cell_enc_len = 0;
631 ssize_t tmp_cell_mac_offset =
632 sig_len +
sizeof(cell->sig_len) +
633 trn_cell_establish_intro_getlen_handshake_mac(cell);
635 uint8_t mac[TRUNNEL_SHA3_256_LEN], *handshake_ptr;
639 tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
640 sizeof(tmp_cell_enc),
642 if (BUG(tmp_cell_enc_len < 0)) {
646 tor_assert(tmp_cell_enc_len > tmp_cell_mac_offset);
651 tmp_cell_enc, tmp_cell_enc_len - tmp_cell_mac_offset);
652 handshake_ptr = trn_cell_establish_intro_getarray_handshake_mac(cell);
653 memcpy(handshake_ptr, mac,
sizeof(mac));
656 memwipe(tmp_cell_enc, 0,
sizeof(tmp_cell_enc));
661 ssize_t tmp_cell_enc_len = 0;
662 ssize_t tmp_cell_sig_offset = (sig_len +
sizeof(cell->sig_len));
668 tmp_cell_enc_len = trn_cell_establish_intro_encode(tmp_cell_enc,
669 sizeof(tmp_cell_enc),
671 if (BUG(tmp_cell_enc_len < 0)) {
676 tmp_cell_enc_len - tmp_cell_sig_offset,
678 log_warn(
LD_BUG,
"Unable to make signature for ESTABLISH_INTRO cell.");
682 sig_ptr = trn_cell_establish_intro_getarray_sig(cell);
683 memcpy(sig_ptr, sig.sig, sig_len);
685 memwipe(tmp_cell_enc, 0,
sizeof(tmp_cell_enc));
693 trn_cell_establish_intro_free(cell);
704 trn_cell_intro_established_t *cell = NULL;
710 ret = trn_cell_intro_established_parse(&cell, payload, payload_len);
714 trn_cell_intro_established_free(cell);
727 const uint8_t *encrypted_section,
728 size_t encrypted_section_len)
739 if (intro_keys == NULL) {
740 log_info(
LD_REND,
"Invalid INTRODUCE2 encrypted data. Unable to "
741 "compute key material");
752 intro_keys_result = tor_malloc_zero(
sizeof(*intro_keys_result));
757 size_t mac_offset = encrypted_section_len -
sizeof(mac);
762 encrypted_section, encrypted_section_len,
763 intro_keys[i].mac_key,
764 sizeof(intro_keys[i].mac_key),
769 bool equal =
tor_memeq(mac, encrypted_section + mac_offset,
sizeof(mac));
771 sizeof(*intro_keys_result));
780 log_info(
LD_REND,
"Invalid MAC validation for INTRODUCE2 cell");
784 return intro_keys_result;
791 const trn_extension_field_t *field)
793 trn_extension_field_cc_t *cc_field = NULL;
798 switch (trn_extension_field_get_field_type(field)) {
799 case TRUNNEL_EXT_TYPE_CC_FIELD_REQUEST:
809 trn_extension_field_cc_free(cc_field);
823 uint8_t *decrypted = NULL;
824 size_t encrypted_section_len;
825 const uint8_t *encrypted_section;
826 trn_cell_introduce1_t *cell = NULL;
827 trn_cell_introduce_encrypted_t *enc_cell = NULL;
840 log_info(
LD_REND,
"Received a decodable INTRODUCE2 cell on circuit %u "
841 "for service %s. Decoding encrypted section...",
845 encrypted_section = trn_cell_introduce1_getconstarray_encrypted(cell);
846 encrypted_section_len = trn_cell_introduce1_getlen_encrypted(cell);
851 log_info(
LD_REND,
"Invalid INTRODUCE2 encrypted section length "
852 "for service %s. Dropping cell.",
859 encrypted_section_len, &elapsed)) {
860 log_warn(
LD_REND,
"Possible replay detected! An INTRODUCE2 cell with the "
861 "same ENCRYPTED section was seen %ld seconds ago. "
862 "Dropping cell.", (
long int) elapsed);
870 memcpy(&data->
client_pk.public_key, encrypted_section,
875 encrypted_section_len);
877 log_warn(
LD_REND,
"Could not get valid INTRO2 keys on circuit %u "
878 "for service %s",
TO_CIRCUIT(circ)->n_circ_id,
885 const uint8_t *encrypted_data =
886 encrypted_section +
sizeof(data->
client_pk);
890 size_t encrypted_data_len =
895 encrypted_data, encrypted_data_len);
896 if (decrypted == NULL) {
897 log_info(
LD_REND,
"Unable to decrypt the ENCRYPTED section of an "
898 "INTRODUCE2 cell on circuit %u for service %s",
908 memwipe(decrypted, 0, encrypted_data_len);
909 if (enc_cell == NULL) {
919 trn_cell_introduce_encrypted_getconstarray_onion_key(enc_cell),
922 trn_cell_introduce_encrypted_getconstarray_rend_cookie(enc_cell),
927 idx < trn_cell_introduce_encrypted_get_nspec(enc_cell); idx++) {
928 link_specifier_t *lspec =
929 trn_cell_introduce_encrypted_get_nspecs(enc_cell, idx);
934 if (BUG(!lspec_dup)) {
941 const trn_extension_t *extensions =
942 trn_cell_introduce_encrypted_get_extensions(enc_cell);
943 if (extensions != NULL) {
944 for (
size_t idx = 0; idx < trn_extension_get_num(extensions); idx++) {
945 const trn_extension_field_t *field =
946 trn_extension_getconst_fields(extensions, idx);
947 if (BUG(field == NULL)) {
963 log_info(
LD_REND,
"Valid INTRODUCE2 cell. Launching rendezvous circuit.");
971 trn_cell_introduce_encrypted_free(enc_cell);
972 trn_cell_introduce1_free(cell);
981 size_t rendezvous_cookie_len,
982 const uint8_t *rendezvous_handshake_info,
983 size_t rendezvous_handshake_info_len,
987 trn_cell_rendezvous1_t *cell;
993 cell = trn_cell_rendezvous1_new();
995 memcpy(trn_cell_rendezvous1_getarray_rendezvous_cookie(cell),
996 rendezvous_cookie, rendezvous_cookie_len);
998 trn_cell_rendezvous1_setlen_handshake_info(cell,
999 rendezvous_handshake_info_len);
1000 memcpy(trn_cell_rendezvous1_getarray_handshake_info(cell),
1001 rendezvous_handshake_info, rendezvous_handshake_info_len);
1006 trn_cell_rendezvous1_free(cell);
1019 trn_cell_introduce1_t *cell;
1020 trn_extension_t *ext;
1025 cell = trn_cell_introduce1_new();
1029 ext = trn_extension_new();
1031 trn_extension_set_num(ext, 0);
1032 trn_cell_introduce1_set_extensions(cell, ext);
1044 trn_cell_introduce1_free(cell);
1072 trn_cell_introduce_ack_t *cell = NULL;
1076 if (trn_cell_introduce_ack_parse(&cell, payload, payload_len) < 0) {
1077 log_info(
LD_REND,
"Invalid INTRODUCE_ACK cell. Unable to parse it.");
1081 ret = trn_cell_introduce_ack_get_status(cell);
1084 trn_cell_introduce_ack_free(cell);
1093 uint8_t *handshake_info,
size_t handshake_info_len)
1096 trn_cell_rendezvous2_t *cell = NULL;
1101 if (trn_cell_rendezvous2_parse(&cell, payload, payload_len) < 0) {
1102 log_info(
LD_REND,
"Invalid RENDEZVOUS2 cell. Unable to parse it.");
1108 tor_assert(trn_cell_rendezvous2_getlen_handshake_info(cell) ==
1109 handshake_info_len);
1110 memcpy(handshake_info,
1111 trn_cell_rendezvous2_getconstarray_handshake_info(cell),
1112 handshake_info_len);
1116 trn_cell_rendezvous2_free(cell);
Header file for config.c.
bool congestion_control_enabled(void)
Public APIs for congestion control.
crypto_cipher_t * crypto_cipher_new_with_bits(const char *key, int bits)
int crypto_cipher_decrypt(crypto_cipher_t *env, char *to, const char *from, size_t fromlen)
int crypto_cipher_encrypt(crypto_cipher_t *env, char *to, const char *from, size_t fromlen)
void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, const uint8_t *key, size_t key_len, const uint8_t *msg, size_t msg_len)
int ed25519_sign_prefixed(ed25519_signature_t *signature_out, const uint8_t *msg, size_t msg_len, const char *prefix_str, const ed25519_keypair_t *keypair)
void memwipe(void *mem, uint8_t byte, size_t sz)
Common functions for cryptographic routines.
void memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n)
int tor_memeq(const void *a, const void *b, size_t sz)
int safe_mem_is_zero(const void *mem, size_t sz)
static void build_introduce_cc_extension(trn_extension_t *extensions)
ssize_t hs_cell_build_establish_rendezvous(const uint8_t *rendezvous_cookie, uint8_t *cell_out)
static void introduce1_set_encrypted(trn_cell_introduce1_t *cell, const hs_cell_introduce1_data_t *data)
static void parse_introduce_cell_extension(hs_cell_introduce2_data_t *data, const trn_extension_field_t *field)
static void build_establish_intro_dos_param(trn_cell_extension_dos_t *dos_ext, uint8_t param_type, uint64_t param_value)
static int build_establish_intro_dos_extension(const hs_service_config_t *service_config, trn_extension_t *extensions)
static void compute_introduce_mac(const uint8_t *encoded_cell, size_t encoded_cell_len, const uint8_t *encrypted, size_t encrypted_len, const uint8_t *mac_key, size_t mac_key_len, uint8_t *mac_out, size_t mac_out_len)
static void introduce1_set_encrypted_link_spec(trn_cell_introduce_encrypted_t *cell, const smartlist_t *lspecs)
static int parse_introduce2_cell(const hs_service_t *service, const origin_circuit_t *circ, const uint8_t *payload, size_t payload_len, trn_cell_introduce1_t **cell_ptr_out)
ssize_t hs_cell_parse_intro_established(const uint8_t *payload, size_t payload_len)
ssize_t hs_cell_build_establish_intro(const char *circ_nonce, const hs_service_config_t *service_config, const hs_service_intro_point_t *ip, uint8_t *cell_out)
int hs_cell_parse_introduce_ack(const uint8_t *payload, size_t payload_len)
void hs_cell_introduce1_data_clear(hs_cell_introduce1_data_t *data)
static hs_ntor_intro_cell_keys_t * get_introduce2_key_material(const ed25519_public_key_t *auth_key, const curve25519_keypair_t *enc_key, size_t n_subcredentials, const hs_subcredential_t *subcredentials, const uint8_t *encrypted_section, curve25519_public_key_t *client_pk)
static hs_ntor_intro_cell_keys_t * get_introduce2_keys_and_verify_mac(hs_cell_introduce2_data_t *data, const uint8_t *encrypted_section, size_t encrypted_section_len)
static void introduce1_encrypt_and_encode(trn_cell_introduce1_t *cell, const trn_cell_introduce_encrypted_t *enc_cell, const hs_cell_introduce1_data_t *data)
ssize_t hs_cell_build_rendezvous1(const uint8_t *rendezvous_cookie, size_t rendezvous_cookie_len, const uint8_t *rendezvous_handshake_info, size_t rendezvous_handshake_info_len, uint8_t *cell_out)
ssize_t hs_cell_build_introduce1(const hs_cell_introduce1_data_t *data, uint8_t *cell_out)
STATIC trn_extension_t * build_establish_intro_extensions(const hs_service_config_t *service_config, const hs_service_intro_point_t *ip)
static trn_cell_introduce_encrypted_t * parse_introduce2_encrypted(const uint8_t *decrypted_data, size_t decrypted_len, const origin_circuit_t *circ, const hs_service_t *service)
int hs_cell_parse_rendezvous2(const uint8_t *payload, size_t payload_len, uint8_t *handshake_info, size_t handshake_info_len)
static void introduce1_set_auth_key(trn_cell_introduce1_t *cell, const hs_cell_introduce1_data_t *data)
static void introduce1_set_encrypted_padding(const trn_cell_introduce1_t *cell, trn_cell_introduce_encrypted_t *enc_cell)
static void introduce1_set_encrypted_onion_key(trn_cell_introduce_encrypted_t *cell, const uint8_t *onion_pk)
ssize_t hs_cell_parse_introduce2(hs_cell_introduce2_data_t *data, const origin_circuit_t *circ, const hs_service_t *service)
static uint8_t * decrypt_introduce2(const uint8_t *enc_key, const uint8_t *encrypted_section, size_t encrypted_section_len)
Header file containing cell data for the whole HS subsystem.
#define HS_CELL_INTRODUCE1_MIN_SIZE
link_specifier_t * link_specifier_dup(const link_specifier_t *src)
#define ESTABLISH_INTRO_SIG_PREFIX
#define HS_REND_COOKIE_LEN
int hs_ntor_service_get_introduce1_keys_multi(const struct ed25519_public_key_t *intro_auth_pubkey, const struct curve25519_keypair_t *intro_enc_keypair, const struct curve25519_public_key_t *client_ephemeral_enc_pubkey, size_t n_subcredentials, const hs_subcredential_t *subcredentials, hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
Header file for the specific code for onion balance.
Master header file for Tor-specific functionality.
#define RELAY_PAYLOAD_SIZE
Origin circuit structure.
int replaycache_add_test_and_elapsed(replaycache_t *r, const void *data, size_t len, time_t *elapsed)
Header file for replaycache.c.
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
const ed25519_public_key_t * auth_pk
const struct hs_subcredential_t * subcredential
const curve25519_keypair_t * client_kp
const curve25519_public_key_t * enc_pk
const uint8_t * rendezvous_cookie
const curve25519_public_key_t * onion_pk
smartlist_t * link_specifiers
curve25519_public_key_t onion_pk
protover_summary_flags_t pv
const ed25519_public_key_t * auth_pk
const curve25519_keypair_t * enc_kp
uint8_t rendezvous_cookie[REND_COOKIE_LEN]
replaycache_t * replay_cache
const struct hs_subcredential_t * subcredentials
curve25519_public_key_t client_pk
smartlist_t * link_specifiers
unsigned int has_dos_defense_enabled
unsigned int support_intro2_dos_defense
ed25519_keypair_t auth_key_kp
char onion_address[HS_SERVICE_ADDR_LEN_BASE32+1]
unsigned int supports_congestion_control
unsigned int protocols_known
#define ED25519_PUBKEY_LEN
#define CURVE25519_PUBKEY_LEN