/* Add all possible link specifiers in node to lspecs. * legacy ID is mandatory thus MUST be present in node. If the primary address * is not IPv4, log a BUG() warning, and return an empty smartlist. * Includes ed25519 id and IPv6 link specifiers if present in the node. */ static void get_lspecs_from_node(const node_t *node, smartlist_t *lspecs) { link_specifier_t *ls; tor_addr_port_t ap; tor_assert(node); tor_assert(lspecs); /* Get the relay's IPv4 address. */ node_get_prim_orport(node, &ap); /* We expect the node's primary address to be a valid IPv4 address. * This conforms to the protocol, which requires either an IPv4 or IPv6 * address (or both). */ if (BUG(!tor_addr_is_v4(&ap.addr)) || BUG(!tor_addr_port_is_valid_ap(&ap, 0))) { return; } ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_IPV4); link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr)); link_specifier_set_un_ipv4_port(ls, ap.port); /* Four bytes IPv4 and two bytes port. */ link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) + sizeof(ap.port)); smartlist_add(lspecs, ls); /* Legacy ID is mandatory and will always be present in node. */ ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_LEGACY_ID); memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity, link_specifier_getlen_un_legacy_id(ls)); link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls)); smartlist_add(lspecs, ls); /* ed25519 ID is only included if the node has it. */ if (!ed25519_public_key_is_zero(&node->ed25519_id)) { ls = link_specifier_new(); link_specifier_set_ls_type(ls, LS_ED25519_ID); memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id, link_specifier_getlen_un_ed25519_id(ls)); link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls)); smartlist_add(lspecs, ls); } /* Check for IPv6. If so, include it as well. */ if (node_has_ipv6_orport(node)) { ls = link_specifier_new(); node_get_pref_ipv6_orport(node, &ap); link_specifier_set_ls_type(ls, LS_IPV6); size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls); const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr); uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls); memcpy(ipv6_array, in6_addr, addr_len); link_specifier_set_un_ipv6_port(ls, ap.port); /* Sixteen bytes IPv6 and two bytes port. */ link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port)); smartlist_add(lspecs, ls); } }
hs_desc_intro_point_t * hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, const char *addr, int legacy) { int ret; ed25519_keypair_t auth_kp; hs_desc_intro_point_t *intro_point = NULL; hs_desc_intro_point_t *ip = hs_desc_intro_point_new(); /* For a usable intro point we need at least two link specifiers: One legacy * keyid and one ipv4 */ { tor_addr_t a; tor_addr_make_unspec(&a); link_specifier_t *ls_legacy = link_specifier_new(); link_specifier_t *ls_ip = link_specifier_new(); link_specifier_set_ls_type(ls_legacy, LS_LEGACY_ID); memset(link_specifier_getarray_un_legacy_id(ls_legacy), 'C', link_specifier_getlen_un_legacy_id(ls_legacy)); int family = tor_addr_parse(&a, addr); switch (family) { case AF_INET: link_specifier_set_ls_type(ls_ip, LS_IPV4); link_specifier_set_un_ipv4_addr(ls_ip, tor_addr_to_ipv4h(&a)); link_specifier_set_un_ipv4_port(ls_ip, 9001); break; case AF_INET6: link_specifier_set_ls_type(ls_ip, LS_IPV6); memcpy(link_specifier_getarray_un_ipv6_addr(ls_ip), tor_addr_to_in6_addr8(&a), link_specifier_getlen_un_ipv6_addr(ls_ip)); link_specifier_set_un_ipv6_port(ls_ip, 9001); break; default: /* Stop the test, not supposed to have an error. * Compare with -1 to show the actual family. */ tt_int_op(family, OP_EQ, -1); } smartlist_add(ip->link_specifiers, ls_legacy); smartlist_add(ip->link_specifiers, ls_ip); } ret = ed25519_keypair_generate(&auth_kp, 0); tt_int_op(ret, ==, 0); ip->auth_key_cert = tor_cert_create(signing_kp, CERT_TYPE_AUTH_HS_IP_KEY, &auth_kp.pubkey, now, HS_DESC_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(ip->auth_key_cert); if (legacy) { ip->legacy.key = crypto_pk_new(); tt_assert(ip->legacy.key); ret = crypto_pk_generate_key(ip->legacy.key); tt_int_op(ret, ==, 0); ssize_t cert_len = tor_make_rsa_ed25519_crosscert( &signing_kp->pubkey, ip->legacy.key, now + HS_DESC_CERT_LIFETIME, &ip->legacy.cert.encoded); tt_assert(ip->legacy.cert.encoded); tt_u64_op(cert_len, OP_GT, 0); ip->legacy.cert.len = cert_len; } /* Encryption key. */ { int signbit; curve25519_keypair_t curve25519_kp; ed25519_keypair_t ed25519_kp; tor_cert_t *cross_cert; ret = curve25519_keypair_generate(&curve25519_kp, 0); tt_int_op(ret, ==, 0); ed25519_keypair_from_curve25519_keypair(&ed25519_kp, &signbit, &curve25519_kp); cross_cert = tor_cert_create(signing_kp, CERT_TYPE_CROSS_HS_IP_KEYS, &ed25519_kp.pubkey, time(NULL), HS_DESC_CERT_LIFETIME, CERT_FLAG_INCLUDE_SIGNING_KEY); tt_assert(cross_cert); ip->enc_key_cert = cross_cert; } intro_point = ip; done: if (intro_point == NULL) tor_free(ip); return intro_point; }