diff options
Diffstat (limited to 'src/feature/rend/rendcommon.c')
-rw-r--r-- | src/feature/rend/rendcommon.c | 944 |
1 files changed, 7 insertions, 937 deletions
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c index 775d487805..0628422812 100644 --- a/src/feature/rend/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2020, The Tor Project, Inc. */ + * Copyright (c) 2007-2021, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,761 +11,22 @@ #define RENDCOMMON_PRIVATE #include "core/or/or.h" -#include "core/or/circuitbuild.h" + +#include "app/config/config.h" + #include "core/or/circuitlist.h" #include "core/or/circuituse.h" -#include "core/or/extendinfo.h" -#include "app/config/config.h" -#include "feature/control/control_events.h" -#include "lib/crypt_ops/crypto_rand.h" -#include "lib/crypt_ops/crypto_util.h" + #include "feature/hs/hs_client.h" #include "feature/hs/hs_common.h" #include "feature/hs/hs_intropoint.h" -#include "feature/nodelist/networkstatus.h" -#include "feature/rend/rendclient.h" #include "feature/rend/rendcommon.h" #include "feature/rend/rendmid.h" -#include "feature/rend/rendparse.h" -#include "feature/rend/rendservice.h" -#include "feature/stats/rephist.h" -#include "feature/hs_common/replaycache.h" -#include "feature/relay/router.h" -#include "feature/nodelist/routerlist.h" -#include "feature/dirparse/signing.h" +#include "core/or/circuit_st.h" #include "core/or/cpath_build_state_st.h" #include "core/or/crypt_path_st.h" -#include "core/or/extend_info_st.h" -#include "feature/nodelist/networkstatus_st.h" #include "core/or/origin_circuit_st.h" -#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" -#include "feature/rend/rend_intro_point_st.h" -#include "feature/rend/rend_service_descriptor_st.h" -#include "feature/nodelist/routerstatus_st.h" - -/** Return 0 if one and two are the same service ids, else -1 or 1 */ -int -rend_cmp_service_ids(const char *one, const char *two) -{ - return strcasecmp(one,two); -} - -/** Free the storage held by the service descriptor <b>desc</b>. - */ -void -rend_service_descriptor_free_(rend_service_descriptor_t *desc) -{ - if (!desc) - return; - if (desc->pk) - crypto_pk_free(desc->pk); - if (desc->intro_nodes) { - SMARTLIST_FOREACH(desc->intro_nodes, rend_intro_point_t *, intro, - rend_intro_point_free(intro);); - smartlist_free(desc->intro_nodes); - } - if (desc->successful_uploads) { - SMARTLIST_FOREACH(desc->successful_uploads, char *, c, tor_free(c);); - smartlist_free(desc->successful_uploads); - } - tor_free(desc); -} - -/** Length of the descriptor cookie that is used for versioned hidden - * service descriptors. */ -#define REND_DESC_COOKIE_LEN 16 - -/** Length of the replica number that is used to determine the secret ID - * part of versioned hidden service descriptors. */ -#define REND_REPLICA_LEN 1 - -/** Compute the descriptor ID for <b>service_id</b> of length - * <b>REND_SERVICE_ID_LEN</b> and <b>secret_id_part</b> of length - * <b>DIGEST_LEN</b>, and write it to <b>descriptor_id_out</b> of length - * <b>DIGEST_LEN</b>. */ -void -rend_get_descriptor_id_bytes(char *descriptor_id_out, - const char *service_id, - const char *secret_id_part) -{ - crypto_digest_t *digest = crypto_digest_new(); - crypto_digest_add_bytes(digest, service_id, REND_SERVICE_ID_LEN); - crypto_digest_add_bytes(digest, secret_id_part, DIGEST_LEN); - crypto_digest_get_digest(digest, descriptor_id_out, DIGEST_LEN); - crypto_digest_free(digest); -} - -/** Compute the secret ID part for time_period, - * a <b>descriptor_cookie</b> of length - * <b>REND_DESC_COOKIE_LEN</b> which may also be <b>NULL</b> if no - * descriptor_cookie shall be used, and <b>replica</b>, and write it to - * <b>secret_id_part</b> of length DIGEST_LEN. */ -static void -get_secret_id_part_bytes(char *secret_id_part, uint32_t time_period, - const char *descriptor_cookie, uint8_t replica) -{ - crypto_digest_t *digest = crypto_digest_new(); - time_period = htonl(time_period); - crypto_digest_add_bytes(digest, (char*)&time_period, sizeof(uint32_t)); - if (descriptor_cookie) { - crypto_digest_add_bytes(digest, descriptor_cookie, - REND_DESC_COOKIE_LEN); - } - crypto_digest_add_bytes(digest, (const char *)&replica, REND_REPLICA_LEN); - crypto_digest_get_digest(digest, secret_id_part, DIGEST_LEN); - crypto_digest_free(digest); -} - -/** Return the time period for time <b>now</b> plus a potentially - * intended <b>deviation</b> of one or more periods, based on the first byte - * of <b>service_id</b>. */ -static uint32_t -get_time_period(time_t now, uint8_t deviation, const char *service_id) -{ - /* The time period is the number of REND_TIME_PERIOD_V2_DESC_VALIDITY - * intervals that have passed since the epoch, offset slightly so that - * each service's time periods start and end at a fraction of that - * period based on their first byte. */ - return (uint32_t) - (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256) - / REND_TIME_PERIOD_V2_DESC_VALIDITY + deviation; -} - -/** Compute the time in seconds that a descriptor that is generated - * <b>now</b> for <b>service_id</b> will be valid. */ -static uint32_t -get_seconds_valid(time_t now, const char *service_id) -{ - uint32_t result = REND_TIME_PERIOD_V2_DESC_VALIDITY - - ((uint32_t) - (now + ((uint8_t) *service_id) * REND_TIME_PERIOD_V2_DESC_VALIDITY / 256) - % REND_TIME_PERIOD_V2_DESC_VALIDITY); - return result; -} - -/** Compute the binary <b>desc_id_out</b> (DIGEST_LEN bytes long) for a given - * base32-encoded <b>service_id</b> and optional unencoded - * <b>descriptor_cookie</b> of length REND_DESC_COOKIE_LEN, - * at time <b>now</b> for replica number - * <b>replica</b>. <b>desc_id</b> needs to have <b>DIGEST_LEN</b> bytes - * free. Return 0 for success, -1 otherwise. */ -int -rend_compute_v2_desc_id(char *desc_id_out, const char *service_id, - const char *descriptor_cookie, time_t now, - uint8_t replica) -{ - char service_id_binary[REND_SERVICE_ID_LEN]; - char secret_id_part[DIGEST_LEN]; - uint32_t time_period; - if (!service_id || - strlen(service_id) != REND_SERVICE_ID_LEN_BASE32) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal service ID: %s", - safe_str(service_id)); - return -1; - } - if (replica >= REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Replica number out of range: %d", replica); - return -1; - } - /* Convert service ID to binary. */ - if (base32_decode(service_id_binary, REND_SERVICE_ID_LEN, - service_id, REND_SERVICE_ID_LEN_BASE32) != - REND_SERVICE_ID_LEN) { - log_warn(LD_REND, "Could not compute v2 descriptor ID: " - "Illegal characters or wrong length for service ID: %s", - safe_str_client(service_id)); - return -1; - } - /* Calculate current time-period. */ - time_period = get_time_period(now, 0, service_id_binary); - /* Calculate secret-id-part = h(time-period | desc-cookie | replica). */ - get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, - replica); - /* Calculate descriptor ID: H(permanent-id | secret-id-part) */ - rend_get_descriptor_id_bytes(desc_id_out, service_id_binary, secret_id_part); - return 0; -} - -/** Encode the introduction points in <b>desc</b> and write the result to a - * newly allocated string pointed to by <b>encoded</b>. Return 0 for - * success, -1 otherwise. */ -static int -rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc) -{ - size_t unenc_len; - char *unenc = NULL; - size_t unenc_written = 0; - int i; - int r = -1; - /* Assemble unencrypted list of introduction points. */ - unenc_len = smartlist_len(desc->intro_nodes) * 1000; /* too long, but ok. */ - unenc = tor_malloc_zero(unenc_len); - for (i = 0; i < smartlist_len(desc->intro_nodes); i++) { - char id_base32[REND_INTRO_POINT_ID_LEN_BASE32 + 1]; - char *onion_key = NULL; - size_t onion_key_len; - crypto_pk_t *intro_key; - char *service_key = NULL; - char *address = NULL; - size_t service_key_len; - int res; - rend_intro_point_t *intro = smartlist_get(desc->intro_nodes, i); - /* Obtain extend info with introduction point details. */ - extend_info_t *info = intro->extend_info; - /* Encode introduction point ID. */ - base32_encode(id_base32, sizeof(id_base32), - info->identity_digest, DIGEST_LEN); - /* Encode onion key. */ - if (crypto_pk_write_public_key_to_string(info->onion_key, &onion_key, - &onion_key_len) < 0) { - log_warn(LD_REND, "Could not write onion key."); - goto done; - } - /* Encode intro key. */ - intro_key = intro->intro_key; - if (!intro_key || - crypto_pk_write_public_key_to_string(intro_key, &service_key, - &service_key_len) < 0) { - log_warn(LD_REND, "Could not write intro key."); - tor_free(onion_key); - goto done; - } - /* Assemble everything for this introduction point. */ - const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET); - IF_BUG_ONCE(!orport) { - /* There must be an IPv4 address for v2 hs. */ - goto done; - } - address = tor_addr_to_str_dup(&orport->addr); - res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written, - "introduction-point %s\n" - "ip-address %s\n" - "onion-port %d\n" - "onion-key\n%s" - "service-key\n%s", - id_base32, - address, - orport->port, - onion_key, - service_key); - tor_free(address); - tor_free(onion_key); - tor_free(service_key); - if (res < 0) { - log_warn(LD_REND, "Not enough space for writing introduction point " - "string."); - goto done; - } - /* Update total number of written bytes for unencrypted intro points. */ - unenc_written += res; - } - /* Finalize unencrypted introduction points. */ - if (unenc_len < unenc_written + 2) { - log_warn(LD_REND, "Not enough space for finalizing introduction point " - "string."); - goto done; - } - unenc[unenc_written++] = '\n'; - unenc[unenc_written++] = 0; - *encoded = unenc; - r = 0; - done: - if (r<0) - tor_free(unenc); - return r; -} - -/** Encrypt the encoded introduction points in <b>encoded</b> using - * authorization type 'basic' with <b>client_cookies</b> and write the - * result to a newly allocated string pointed to by <b>encrypted_out</b> of - * length <b>encrypted_len_out</b>. Return 0 for success, -1 otherwise. */ -static int -rend_encrypt_v2_intro_points_basic(char **encrypted_out, - size_t *encrypted_len_out, - const char *encoded, - smartlist_t *client_cookies) -{ - int r = -1, i, pos, enclen, client_blocks; - size_t len, client_entries_len; - char *enc = NULL, iv[CIPHER_IV_LEN], *client_part = NULL, - session_key[CIPHER_KEY_LEN]; - smartlist_t *encrypted_session_keys = NULL; - crypto_digest_t *digest; - crypto_cipher_t *cipher; - tor_assert(encoded); - tor_assert(client_cookies && smartlist_len(client_cookies) > 0); - - /* Generate session key. */ - crypto_rand(session_key, CIPHER_KEY_LEN); - - /* Determine length of encrypted introduction points including session - * keys. */ - client_blocks = 1 + ((smartlist_len(client_cookies) - 1) / - REND_BASIC_AUTH_CLIENT_MULTIPLE); - client_entries_len = client_blocks * REND_BASIC_AUTH_CLIENT_MULTIPLE * - REND_BASIC_AUTH_CLIENT_ENTRY_LEN; - len = 2 + client_entries_len + CIPHER_IV_LEN + strlen(encoded); - if (client_blocks >= 256) { - log_warn(LD_REND, "Too many clients in introduction point string."); - goto done; - } - enc = tor_malloc_zero(len); - enc[0] = 0x01; /* type of authorization. */ - enc[1] = (uint8_t)client_blocks; - - /* Encrypt with random session key. */ - enclen = crypto_cipher_encrypt_with_iv(session_key, - enc + 2 + client_entries_len, - CIPHER_IV_LEN + strlen(encoded), encoded, strlen(encoded)); - - if (enclen < 0) { - log_warn(LD_REND, "Could not encrypt introduction point string."); - goto done; - } - memcpy(iv, enc + 2 + client_entries_len, CIPHER_IV_LEN); - - /* Encrypt session key for cookies, determine client IDs, and put both - * in a smartlist. */ - encrypted_session_keys = smartlist_new(); - SMARTLIST_FOREACH_BEGIN(client_cookies, const char *, cookie) { - client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - /* Encrypt session key. */ - cipher = crypto_cipher_new(cookie); - if (crypto_cipher_encrypt(cipher, client_part + - REND_BASIC_AUTH_CLIENT_ID_LEN, - session_key, CIPHER_KEY_LEN) < 0) { - log_warn(LD_REND, "Could not encrypt session key for client."); - crypto_cipher_free(cipher); - tor_free(client_part); - goto done; - } - crypto_cipher_free(cipher); - - /* Determine client ID. */ - digest = crypto_digest_new(); - crypto_digest_add_bytes(digest, cookie, REND_DESC_COOKIE_LEN); - crypto_digest_add_bytes(digest, iv, CIPHER_IV_LEN); - crypto_digest_get_digest(digest, client_part, - REND_BASIC_AUTH_CLIENT_ID_LEN); - crypto_digest_free(digest); - - /* Put both together. */ - smartlist_add(encrypted_session_keys, client_part); - } SMARTLIST_FOREACH_END(cookie); - - /* Add some fake client IDs and encrypted session keys. */ - for (i = (smartlist_len(client_cookies) - 1) % - REND_BASIC_AUTH_CLIENT_MULTIPLE; - i < REND_BASIC_AUTH_CLIENT_MULTIPLE - 1; i++) { - client_part = tor_malloc_zero(REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - smartlist_add(encrypted_session_keys, client_part); - } - /* Sort smartlist and put elements in result in order. */ - smartlist_sort_digests(encrypted_session_keys); - pos = 2; - SMARTLIST_FOREACH(encrypted_session_keys, const char *, entry, { - memcpy(enc + pos, entry, REND_BASIC_AUTH_CLIENT_ENTRY_LEN); - pos += REND_BASIC_AUTH_CLIENT_ENTRY_LEN; - }); - *encrypted_out = enc; - *encrypted_len_out = len; - enc = NULL; /* prevent free. */ - r = 0; - done: - tor_free(enc); - if (encrypted_session_keys) { - SMARTLIST_FOREACH(encrypted_session_keys, char *, d, tor_free(d);); - smartlist_free(encrypted_session_keys); - } - return r; -} - -/** Encrypt the encoded introduction points in <b>encoded</b> using - * authorization type 'stealth' with <b>descriptor_cookie</b> of length - * REND_DESC_COOKIE_LEN and write the result to a newly allocated string - * pointed to by <b>encrypted_out</b> of length <b>encrypted_len_out</b>. - * Return 0 for success, -1 otherwise. */ -static int -rend_encrypt_v2_intro_points_stealth(char **encrypted_out, - size_t *encrypted_len_out, - const char *encoded, - const char *descriptor_cookie) -{ - int r = -1, enclen; - char *enc; - tor_assert(encoded); - tor_assert(descriptor_cookie); - - enc = tor_malloc_zero(1 + CIPHER_IV_LEN + strlen(encoded)); - enc[0] = 0x02; /* Auth type */ - enclen = crypto_cipher_encrypt_with_iv(descriptor_cookie, - enc + 1, - CIPHER_IV_LEN+strlen(encoded), - encoded, strlen(encoded)); - if (enclen < 0) { - log_warn(LD_REND, "Could not encrypt introduction point string."); - goto done; - } - *encrypted_out = enc; - *encrypted_len_out = enclen; - enc = NULL; /* prevent free */ - r = 0; - done: - tor_free(enc); - return r; -} - -/** Attempt to parse the given <b>desc_str</b> and return true if this - * succeeds, false otherwise. */ -STATIC int -rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc) -{ - rend_service_descriptor_t *test_parsed = NULL; - char test_desc_id[DIGEST_LEN]; - char *test_intro_content = NULL; - size_t test_intro_size; - size_t test_encoded_size; - const char *test_next; - int res = rend_parse_v2_service_descriptor(&test_parsed, test_desc_id, - &test_intro_content, - &test_intro_size, - &test_encoded_size, - &test_next, desc->desc_str, 1); - rend_service_descriptor_free(test_parsed); - tor_free(test_intro_content); - return (res >= 0); -} - -/** Free the storage held by an encoded v2 service descriptor. */ -void -rend_encoded_v2_service_descriptor_free_( - rend_encoded_v2_service_descriptor_t *desc) -{ - if (!desc) - return; - tor_free(desc->desc_str); - tor_free(desc); -} - -/** Free the storage held by an introduction point info. */ -void -rend_intro_point_free_(rend_intro_point_t *intro) -{ - if (!intro) - return; - - extend_info_free(intro->extend_info); - crypto_pk_free(intro->intro_key); - - if (intro->accepted_intro_rsa_parts != NULL) { - replaycache_free(intro->accepted_intro_rsa_parts); - } - - tor_free(intro); -} - -/** Encode a set of rend_encoded_v2_service_descriptor_t's for <b>desc</b> - * at time <b>now</b> using <b>service_key</b>, depending on - * <b>auth_type</b> a <b>descriptor_cookie</b> and a list of - * <b>client_cookies</b> (which are both <b>NULL</b> if no client - * authorization is performed), and <b>period</b> (e.g. 0 for the current - * period, 1 for the next period, etc.) and add them to the existing list - * <b>descs_out</b>; return the number of seconds that the descriptors will - * be found by clients, or -1 if the encoding was not successful. */ -int -rend_encode_v2_descriptors(smartlist_t *descs_out, - rend_service_descriptor_t *desc, time_t now, - uint8_t period, rend_auth_type_t auth_type, - crypto_pk_t *client_key, - smartlist_t *client_cookies) -{ - char service_id[DIGEST_LEN]; - char service_id_base32[REND_SERVICE_ID_LEN_BASE32+1]; - uint32_t time_period; - char *ipos_base64 = NULL, *ipos = NULL, *ipos_encrypted = NULL, - *descriptor_cookie = NULL; - size_t ipos_len = 0, ipos_encrypted_len = 0; - int k; - uint32_t seconds_valid; - crypto_pk_t *service_key; - if (!desc) { - log_warn(LD_BUG, "Could not encode v2 descriptor: No desc given."); - return -1; - } - service_key = (auth_type == REND_STEALTH_AUTH) ? client_key : desc->pk; - tor_assert(service_key); - if (auth_type == REND_STEALTH_AUTH) { - descriptor_cookie = smartlist_get(client_cookies, 0); - tor_assert(descriptor_cookie); - } - /* Obtain service_id from public key. */ - if (crypto_pk_get_digest(service_key, service_id) < 0) { - log_warn(LD_BUG, "Couldn't compute service key digest."); - return -1; - } - /* Calculate current time-period. */ - time_period = get_time_period(now, period, service_id); - /* Determine how many seconds the descriptor will be valid. */ - seconds_valid = period * REND_TIME_PERIOD_V2_DESC_VALIDITY + - get_seconds_valid(now, service_id); - /* Assemble, possibly encrypt, and encode introduction points. */ - if (smartlist_len(desc->intro_nodes) > 0) { - if (rend_encode_v2_intro_points(&ipos, desc) < 0) { - log_warn(LD_REND, "Encoding of introduction points did not succeed."); - return -1; - } - switch (auth_type) { - case REND_NO_AUTH: - ipos_len = strlen(ipos); - break; - case REND_BASIC_AUTH: - if (rend_encrypt_v2_intro_points_basic(&ipos_encrypted, - &ipos_encrypted_len, ipos, - client_cookies) < 0) { - log_warn(LD_REND, "Encrypting of introduction points did not " - "succeed."); - tor_free(ipos); - return -1; - } - tor_free(ipos); - ipos = ipos_encrypted; - ipos_len = ipos_encrypted_len; - break; - case REND_STEALTH_AUTH: - if (rend_encrypt_v2_intro_points_stealth(&ipos_encrypted, - &ipos_encrypted_len, ipos, - descriptor_cookie) < 0) { - log_warn(LD_REND, "Encrypting of introduction points did not " - "succeed."); - tor_free(ipos); - return -1; - } - tor_free(ipos); - ipos = ipos_encrypted; - ipos_len = ipos_encrypted_len; - break; - default: - log_warn(LD_REND|LD_BUG, "Unrecognized authorization type %d", - (int)auth_type); - tor_free(ipos); - return -1; - } - /* Base64-encode introduction points. */ - ipos_base64 = tor_calloc(ipos_len, 2); - if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len, - BASE64_ENCODE_MULTILINE)<0) { - log_warn(LD_REND, "Could not encode introduction point string to " - "base64. length=%d", (int)ipos_len); - tor_free(ipos_base64); - tor_free(ipos); - return -1; - } - tor_free(ipos); - } - /* Encode REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS descriptors. */ - for (k = 0; k < REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS; k++) { - char secret_id_part[DIGEST_LEN]; - char secret_id_part_base32[REND_SECRET_ID_PART_LEN_BASE32 + 1]; - char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; - char *permanent_key = NULL; - size_t permanent_key_len; - char published[ISO_TIME_LEN+1]; - int i; - char protocol_versions_string[16]; /* max len: "0,1,2,3,4,5,6,7\0" */ - size_t protocol_versions_written; - size_t desc_len; - char *desc_str = NULL; - int result = 0; - size_t written = 0; - char desc_digest[DIGEST_LEN]; - rend_encoded_v2_service_descriptor_t *enc = - tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t)); - /* Calculate secret-id-part = h(time-period | cookie | replica). */ - get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie, - k); - base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32), - secret_id_part, DIGEST_LEN); - /* Calculate descriptor ID. */ - rend_get_descriptor_id_bytes(enc->desc_id, service_id, secret_id_part); - base32_encode(desc_id_base32, sizeof(desc_id_base32), - enc->desc_id, DIGEST_LEN); - /* PEM-encode the public key */ - if (crypto_pk_write_public_key_to_string(service_key, &permanent_key, - &permanent_key_len) < 0) { - log_warn(LD_BUG, "Could not write public key to string."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - /* Encode timestamp. */ - format_iso_time(published, desc->timestamp); - /* Write protocol-versions bitmask to comma-separated value string. */ - protocol_versions_written = 0; - for (i = 0; i < 8; i++) { - if (desc->protocols & 1 << i) { - tor_snprintf(protocol_versions_string + protocol_versions_written, - 16 - protocol_versions_written, "%d,", i); - protocol_versions_written += 2; - } - } - if (protocol_versions_written) - protocol_versions_string[protocol_versions_written - 1] = '\0'; - else - protocol_versions_string[0]= '\0'; - /* Assemble complete descriptor. */ - desc_len = 2000 + smartlist_len(desc->intro_nodes) * 1000; /* far too long, - but okay.*/ - enc->desc_str = desc_str = tor_malloc_zero(desc_len); - result = tor_snprintf(desc_str, desc_len, - "rendezvous-service-descriptor %s\n" - "version 2\n" - "permanent-key\n%s" - "secret-id-part %s\n" - "publication-time %s\n" - "protocol-versions %s\n", - desc_id_base32, - permanent_key, - secret_id_part_base32, - published, - protocol_versions_string); - tor_free(permanent_key); - if (result < 0) { - log_warn(LD_BUG, "Descriptor ran out of room."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written = result; - /* Add introduction points. */ - if (ipos_base64) { - result = tor_snprintf(desc_str + written, desc_len - written, - "introduction-points\n" - "-----BEGIN MESSAGE-----\n%s" - "-----END MESSAGE-----\n", - ipos_base64); - if (result < 0) { - log_warn(LD_BUG, "could not write introduction points."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written += result; - } - /* Add signature. */ - strlcpy(desc_str + written, "signature\n", desc_len - written); - written += strlen(desc_str + written); - if (crypto_digest(desc_digest, desc_str, written) < 0) { - log_warn(LD_BUG, "could not create digest."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - if (router_append_dirobj_signature(desc_str + written, - desc_len - written, - desc_digest, DIGEST_LEN, - service_key) < 0) { - log_warn(LD_BUG, "Couldn't sign desc."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - written += strlen(desc_str+written); - if (written+2 > desc_len) { - log_warn(LD_BUG, "Could not finish desc."); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - desc_str[written++] = 0; - /* Check if we can parse our own descriptor. */ - if (!rend_desc_v2_is_parsable(enc)) { - log_warn(LD_BUG, "Could not parse my own descriptor: %s", desc_str); - rend_encoded_v2_service_descriptor_free(enc); - goto err; - } - smartlist_add(descs_out, enc); - /* Add the uploaded descriptor to the local service's descriptor cache */ - rend_cache_store_v2_desc_as_service(enc->desc_str); - base32_encode(service_id_base32, sizeof(service_id_base32), - service_id, REND_SERVICE_ID_LEN); - control_event_hs_descriptor_created(service_id_base32, desc_id_base32, k); - } - - log_info(LD_REND, "Successfully encoded a v2 descriptor and " - "confirmed that it is parsable."); - goto done; - - err: - SMARTLIST_FOREACH(descs_out, rend_encoded_v2_service_descriptor_t *, d, - rend_encoded_v2_service_descriptor_free(d);); - smartlist_clear(descs_out); - seconds_valid = -1; - - done: - tor_free(ipos_base64); - return seconds_valid; -} - -/** Sets <b>out</b> to the first 10 bytes of the digest of <b>pk</b>, - * base32 encoded. NUL-terminates out. (We use this string to - * identify services in directory requests and .onion URLs.) - */ -int -rend_get_service_id(crypto_pk_t *pk, char *out) -{ - char buf[DIGEST_LEN]; - tor_assert(pk); - if (crypto_pk_get_digest(pk, buf) < 0) - return -1; - base32_encode(out, REND_SERVICE_ID_LEN_BASE32+1, buf, REND_SERVICE_ID_LEN); - return 0; -} - -/** Return true iff <b>query</b> is a syntactically valid service ID (as - * generated by rend_get_service_id). */ -int -rend_valid_v2_service_id(const char *query) -{ - if (strlen(query) != REND_SERVICE_ID_LEN_BASE32) - return 0; - - if (strspn(query, BASE32_CHARS) != REND_SERVICE_ID_LEN_BASE32) - return 0; - - return 1; -} - -/** Return true iff <b>query</b> is a syntactically valid descriptor ID. - * (as generated by rend_get_descriptor_id_bytes). */ -int -rend_valid_descriptor_id(const char *query) -{ - if (strlen(query) != REND_DESC_ID_V2_LEN_BASE32) { - goto invalid; - } - if (strspn(query, BASE32_CHARS) != REND_DESC_ID_V2_LEN_BASE32) { - goto invalid; - } - - return 1; - - invalid: - return 0; -} - -/** Return true iff <b>client_name</b> is a syntactically valid name - * for rendezvous client authentication. */ -int -rend_valid_client_name(const char *client_name) -{ - size_t len = strlen(client_name); - if (len < 1 || len > REND_CLIENTNAME_MAX_LEN) { - return 0; - } - if (strspn(client_name, REND_LEGAL_CLIENTNAME_CHARACTERS) != len) { - return 0; - } - - return 1; -} /** Called when we get a rendezvous-related relay cell on circuit * <b>circ</b>. Dispatch on rendezvous relay command. */ @@ -840,168 +101,6 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, command); } -/** Determine the routers that are responsible for <b>id</b> (binary) and - * add pointers to those routers' routerstatus_t to <b>responsible_dirs</b>. - * Return -1 if we're returning an empty smartlist, else return 0. - */ -int -hid_serv_get_responsible_directories(smartlist_t *responsible_dirs, - const char *id) -{ - int start, found, n_added = 0, i; - networkstatus_t *c = networkstatus_get_latest_consensus(); - if (!c || !smartlist_len(c->routerstatus_list)) { - log_info(LD_REND, "We don't have a consensus, so we can't perform v2 " - "rendezvous operations."); - return -1; - } - tor_assert(id); - start = networkstatus_vote_find_entry_idx(c, id, &found); - if (start == smartlist_len(c->routerstatus_list)) start = 0; - i = start; - do { - routerstatus_t *r = smartlist_get(c->routerstatus_list, i); - if (r->is_hs_dir) { - smartlist_add(responsible_dirs, r); - if (++n_added == REND_NUMBER_OF_CONSECUTIVE_REPLICAS) - return 0; - } - if (++i == smartlist_len(c->routerstatus_list)) - i = 0; - } while (i != start); - - /* Even though we don't have the desired number of hidden service - * directories, be happy if we got any. */ - return smartlist_len(responsible_dirs) ? 0 : -1; -} - -/* Length of the 'extended' auth cookie used to encode auth type before - * base64 encoding. */ -#define REND_DESC_COOKIE_LEN_EXT (REND_DESC_COOKIE_LEN + 1) -/* Length of the zero-padded auth cookie when base64 encoded. These two - * padding bytes always (A=) are stripped off of the returned cookie. */ -#define REND_DESC_COOKIE_LEN_EXT_BASE64 (REND_DESC_COOKIE_LEN_BASE64 + 2) - -/** Encode a client authorization descriptor cookie. - * The result of this function is suitable for use in the HidServAuth - * option. The trailing padding characters are removed, and the - * auth type is encoded into the cookie. - * - * Returns a new base64-encoded cookie. This function cannot fail. - * The caller is responsible for freeing the returned value. - */ -char * -rend_auth_encode_cookie(const uint8_t *cookie_in, rend_auth_type_t auth_type) -{ - uint8_t extended_cookie[REND_DESC_COOKIE_LEN_EXT]; - char *cookie_out = tor_malloc_zero(REND_DESC_COOKIE_LEN_EXT_BASE64 + 1); - int re; - - tor_assert(cookie_in); - - memcpy(extended_cookie, cookie_in, REND_DESC_COOKIE_LEN); - extended_cookie[REND_DESC_COOKIE_LEN] = ((int)auth_type - 1) << 4; - re = base64_encode(cookie_out, REND_DESC_COOKIE_LEN_EXT_BASE64 + 1, - (const char *) extended_cookie, REND_DESC_COOKIE_LEN_EXT, - 0); - tor_assert(re == REND_DESC_COOKIE_LEN_EXT_BASE64); - - /* Remove the trailing 'A='. Auth type is encoded in the high bits - * of the last byte, so the last base64 character will always be zero - * (A). This is subtly different behavior from base64_encode_nopad. */ - cookie_out[REND_DESC_COOKIE_LEN_BASE64] = '\0'; - memwipe(extended_cookie, 0, sizeof(extended_cookie)); - return cookie_out; -} - -/** Decode a base64-encoded client authorization descriptor cookie. - * The descriptor_cookie can be truncated to REND_DESC_COOKIE_LEN_BASE64 - * characters (as given to clients), or may include the two padding - * characters (as stored by the service). - * - * The result is stored in REND_DESC_COOKIE_LEN bytes of cookie_out. - * The rend_auth_type_t decoded from the cookie is stored in the - * optional auth_type_out parameter. - * - * Return 0 on success, or -1 on error. The caller is responsible for - * freeing the returned err_msg. - */ -int -rend_auth_decode_cookie(const char *cookie_in, uint8_t *cookie_out, - rend_auth_type_t *auth_type_out, char **err_msg_out) -{ - uint8_t descriptor_cookie_decoded[REND_DESC_COOKIE_LEN_EXT + 1] = { 0 }; - char descriptor_cookie_base64ext[REND_DESC_COOKIE_LEN_EXT_BASE64 + 1]; - const char *descriptor_cookie = cookie_in; - char *err_msg = NULL; - int auth_type_val = 0; - int res = -1; - int decoded_len; - - size_t len = strlen(descriptor_cookie); - if (len == REND_DESC_COOKIE_LEN_BASE64) { - /* Add a trailing zero byte to make base64-decoding happy. */ - tor_snprintf(descriptor_cookie_base64ext, - sizeof(descriptor_cookie_base64ext), - "%sA=", descriptor_cookie); - descriptor_cookie = descriptor_cookie_base64ext; - } else if (len != REND_DESC_COOKIE_LEN_EXT_BASE64) { - tor_asprintf(&err_msg, "Authorization cookie has wrong length: %s", - escaped(cookie_in)); - goto err; - } - - decoded_len = base64_decode((char *) descriptor_cookie_decoded, - sizeof(descriptor_cookie_decoded), - descriptor_cookie, - REND_DESC_COOKIE_LEN_EXT_BASE64); - if (decoded_len != REND_DESC_COOKIE_LEN && - decoded_len != REND_DESC_COOKIE_LEN_EXT) { - tor_asprintf(&err_msg, "Authorization cookie has invalid characters: %s", - escaped(cookie_in)); - goto err; - } - - if (auth_type_out) { - auth_type_val = (descriptor_cookie_decoded[REND_DESC_COOKIE_LEN] >> 4) + 1; - if (auth_type_val < 1 || auth_type_val > 2) { - tor_asprintf(&err_msg, "Authorization cookie type is unknown: %s", - escaped(cookie_in)); - goto err; - } - *auth_type_out = auth_type_val == 1 ? REND_BASIC_AUTH : REND_STEALTH_AUTH; - } - - memcpy(cookie_out, descriptor_cookie_decoded, REND_DESC_COOKIE_LEN); - res = 0; - err: - if (err_msg_out) { - *err_msg_out = err_msg; - } else { - tor_free(err_msg); - } - memwipe(descriptor_cookie_decoded, 0, sizeof(descriptor_cookie_decoded)); - memwipe(descriptor_cookie_base64ext, 0, sizeof(descriptor_cookie_base64ext)); - return res; -} - -/* Is this a rend client or server that allows direct (non-anonymous) - * connections? - * Onion services can be configured to start in this mode for single onion. */ -int -rend_allow_non_anonymous_connection(const or_options_t* options) -{ - return rend_service_allow_non_anonymous_connection(options); -} - -/* Is this a rend client or server in non-anonymous mode? - * Onion services can be configured to start in this mode for single onion. */ -int -rend_non_anonymous_mode_enabled(const or_options_t *options) -{ - return rend_service_non_anonymous_mode_enabled(options); -} - /* Make sure that tor only builds one-hop circuits when they would not * compromise user anonymity. * @@ -1020,35 +119,6 @@ assert_circ_anonymity_ok(const origin_circuit_t *circ, tor_assert(circ->build_state); if (circ->build_state->onehop_tunnel) { - tor_assert(rend_allow_non_anonymous_connection(options)); - } -} - -/* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is - * equal to the digest in the origin circuit <b>ocirc</b> of its rend data . - * If the rend data doesn't exist, 0 is returned. This function is agnostic to - * the rend data version. */ -int -rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, - const uint8_t *digest) -{ - size_t rend_pk_digest_len; - const uint8_t *rend_pk_digest; - - tor_assert(ocirc); - tor_assert(digest); - - if (ocirc->rend_data == NULL) { - goto no_match; - } - - rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data, - &rend_pk_digest_len); - if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) { - goto match; + tor_assert(hs_service_allow_non_anonymous_connection(options)); } - no_match: - return 0; - match: - return 1; } |