123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515 |
- /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2015, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \file rendcommon.c
- * \brief Rendezvous implementation: shared code between
- * introducers, services, clients, and rendezvous points.
- **/
- #include "or.h"
- #include "circuitbuild.h"
- #include "config.h"
- #include "rendclient.h"
- #include "rendcommon.h"
- #include "rendmid.h"
- #include "rendservice.h"
- #include "rephist.h"
- #include "routerlist.h"
- #include "routerparse.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) < 0) {
- log_warn(LD_REND, "Could not compute v2 descriptor ID: "
- "Illegal characters in 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. */
- address = tor_dup_addr(&info->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,
- info->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. */
- if (crypto_rand(session_key, CIPHER_KEY_LEN) < 0) {
- log_warn(LD_REND, "Unable to generate random session key to encrypt "
- "introduction point string.");
- goto done;
- }
- /* 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);
- if (crypto_rand(client_part, REND_BASIC_AUTH_CLIENT_ENTRY_LEN) < 0) {
- log_warn(LD_REND, "Unable to generate fake client entry.");
- tor_free(client_part);
- goto done;
- }
- 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];
- 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. */
- crypto_pk_get_digest(service_key, service_id);
- /* 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);
- }
- 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;
- }
- /* ==== Rendezvous service descriptor cache. */
- /** How old do we let hidden service descriptors get before discarding
- * them as too old? */
- #define REND_CACHE_MAX_AGE (2*24*60*60)
- /** How wrong do we assume our clock may be when checking whether hidden
- * services are too old or too new? */
- #define REND_CACHE_MAX_SKEW (24*60*60)
- /** Map from service id (as generated by rend_get_service_id) to
- * rend_cache_entry_t. */
- static strmap_t *rend_cache = NULL;
- /** Map from descriptor id to rend_cache_entry_t; only for hidden service
- * directories. */
- static digestmap_t *rend_cache_v2_dir = NULL;
- /** DOCDOC */
- static size_t rend_cache_total_allocation = 0;
- /** Initializes the service descriptor cache.
- */
- void
- rend_cache_init(void)
- {
- rend_cache = strmap_new();
- rend_cache_v2_dir = digestmap_new();
- }
- /** Return the approximate number of bytes needed to hold <b>e</b>. */
- static size_t
- rend_cache_entry_allocation(const rend_cache_entry_t *e)
- {
- if (!e)
- return 0;
- /* This doesn't count intro_nodes or key size */
- return sizeof(*e) + e->len + sizeof(*e->parsed);
- }
- /** DOCDOC */
- size_t
- rend_cache_get_total_allocation(void)
- {
- return rend_cache_total_allocation;
- }
- /** Decrement the total bytes attributed to the rendezvous cache by n. */
- static void
- rend_cache_decrement_allocation(size_t n)
- {
- static int have_underflowed = 0;
- if (rend_cache_total_allocation >= n) {
- rend_cache_total_allocation -= n;
- } else {
- rend_cache_total_allocation = 0;
- if (! have_underflowed) {
- have_underflowed = 1;
- log_warn(LD_BUG, "Underflow in rend_cache_decrement_allocation");
- }
- }
- }
- /** Increase the total bytes attributed to the rendezvous cache by n. */
- static void
- rend_cache_increment_allocation(size_t n)
- {
- static int have_overflowed = 0;
- if (rend_cache_total_allocation <= SIZE_MAX - n) {
- rend_cache_total_allocation += n;
- } else {
- rend_cache_total_allocation = SIZE_MAX;
- if (! have_overflowed) {
- have_overflowed = 1;
- log_warn(LD_BUG, "Overflow in rend_cache_increment_allocation");
- }
- }
- }
- /** Helper: free storage held by a single service descriptor cache entry. */
- static void
- rend_cache_entry_free(rend_cache_entry_t *e)
- {
- if (!e)
- return;
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- tor_free(e);
- }
- /** Helper: deallocate a rend_cache_entry_t. (Used with strmap_free(), which
- * requires a function pointer whose argument is void*). */
- static void
- rend_cache_entry_free_(void *p)
- {
- rend_cache_entry_free(p);
- }
- /** Free all storage held by the service descriptor cache. */
- void
- rend_cache_free_all(void)
- {
- strmap_free(rend_cache, rend_cache_entry_free_);
- digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
- rend_cache = NULL;
- rend_cache_v2_dir = NULL;
- rend_cache_total_allocation = 0;
- }
- /** Removes all old entries from the service descriptor cache.
- */
- void
- rend_cache_clean(time_t now)
- {
- strmap_iter_t *iter;
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
- for (iter = strmap_iter_init(rend_cache); !strmap_iter_done(iter); ) {
- strmap_iter_get(iter, &key, &val);
- ent = (rend_cache_entry_t*)val;
- if (ent->parsed->timestamp < cutoff) {
- iter = strmap_iter_next_rmv(rend_cache, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = strmap_iter_next(rend_cache, iter);
- }
- }
- }
- /** Remove ALL entries from the rendezvous service descriptor cache.
- */
- void
- rend_cache_purge(void)
- {
- if (rend_cache) {
- log_info(LD_REND, "Purging HS descriptor cache");
- strmap_free(rend_cache, rend_cache_entry_free_);
- }
- rend_cache = strmap_new();
- }
- /** Remove all old v2 descriptors and those for which this hidden service
- * directory is not responsible for any more.
- *
- * If at all possible, remove at least <b>force_remove</b> bytes of data.
- */
- void
- rend_cache_clean_v2_descs_as_dir(time_t now, size_t force_remove)
- {
- digestmap_iter_t *iter;
- time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
- const int LAST_SERVED_CUTOFF_STEP = 1800;
- time_t last_served_cutoff = cutoff;
- size_t bytes_removed = 0;
- do {
- for (iter = digestmap_iter_init(rend_cache_v2_dir);
- !digestmap_iter_done(iter); ) {
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- digestmap_iter_get(iter, &key, &val);
- ent = val;
- if (ent->parsed->timestamp < cutoff ||
- ent->last_served < last_served_cutoff ||
- !hid_serv_responsible_for_desc_id(key)) {
- char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
- log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
- safe_str_client(key_base32));
- bytes_removed += rend_cache_entry_allocation(ent);
- iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = digestmap_iter_next(rend_cache_v2_dir, iter);
- }
- }
- /* In case we didn't remove enough bytes, advance the cutoff a little. */
- last_served_cutoff += LAST_SERVED_CUTOFF_STEP;
- if (last_served_cutoff > now)
- break;
- } while (bytes_removed < force_remove);
- }
- /** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
- * <b>c</b> (included) in a circular digest ring; returns 1 if this is the
- * case, and 0 otherwise.
- */
- int
- rend_id_is_in_interval(const char *a, const char *b, const char *c)
- {
- int a_b, b_c, c_a;
- tor_assert(a);
- tor_assert(b);
- tor_assert(c);
- /* There are five cases in which a is outside the interval ]b,c]: */
- a_b = tor_memcmp(a,b,DIGEST_LEN);
- if (a_b == 0)
- return 0; /* 1. a == b (b is excluded) */
- b_c = tor_memcmp(b,c,DIGEST_LEN);
- if (b_c == 0)
- return 0; /* 2. b == c (interval is empty) */
- else if (a_b <= 0 && b_c < 0)
- return 0; /* 3. a b c */
- c_a = tor_memcmp(c,a,DIGEST_LEN);
- if (c_a < 0 && a_b <= 0)
- return 0; /* 4. c a b */
- else if (b_c < 0 && c_a < 0)
- return 0; /* 5. b c a */
- /* In the other cases (a c b; b a c; c b a), a is inside the interval. */
- return 1;
- }
- /** Return true iff <b>query</b> is a syntactically valid service ID (as
- * generated by rend_get_service_id). */
- int
- rend_valid_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;
- }
- /** Lookup in the client cache the given service ID <b>query</b> for
- * <b>version</b>.
- *
- * Return 0 if found and if <b>e</b> is non NULL, set it with the entry
- * found. Else, a negative value is returned and <b>e</b> is untouched.
- * -EINVAL means that <b>query</b> is not a valid service id.
- * -ENOENT means that no entry in the cache was found. */
- int
- rend_cache_lookup_entry(const char *query, int version, rend_cache_entry_t **e)
- {
- int ret = 0;
- char key[REND_SERVICE_ID_LEN_BASE32 + 2]; /* <version><query>\0 */
- rend_cache_entry_t *entry = NULL;
- static const int default_version = 2;
- tor_assert(rend_cache);
- tor_assert(query);
- if (!rend_valid_service_id(query)) {
- ret = -EINVAL;
- goto end;
- }
- switch (version) {
- case 0:
- log_warn(LD_REND, "Cache lookup of a v0 renddesc is deprecated.");
- break;
- case 2:
- /* Default is version 2. */
- default:
- tor_snprintf(key, sizeof(key), "%d%s", default_version, query);
- entry = strmap_get_lc(rend_cache, key);
- break;
- }
- if (!entry) {
- ret = -ENOENT;
- goto end;
- }
- tor_assert(entry->parsed && entry->parsed->intro_nodes);
- if (e) {
- *e = entry;
- }
- end:
- return ret;
- }
- /** Lookup the v2 service descriptor with base32-encoded <b>desc_id</b> and
- * copy the pointer to it to *<b>desc</b>. Return 1 on success, 0 on
- * well-formed-but-not-found, and -1 on failure.
- */
- int
- rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
- {
- rend_cache_entry_t *e;
- char desc_id_digest[DIGEST_LEN];
- tor_assert(rend_cache_v2_dir);
- if (base32_decode(desc_id_digest, DIGEST_LEN,
- desc_id, REND_DESC_ID_V2_LEN_BASE32) < 0) {
- log_fn(LOG_PROTOCOL_WARN, LD_REND,
- "Rejecting v2 rendezvous descriptor request -- descriptor ID "
- "contains illegal characters: %s",
- safe_str(desc_id));
- return -1;
- }
- /* Lookup descriptor and return. */
- e = digestmap_get(rend_cache_v2_dir, desc_id_digest);
- if (e) {
- *desc = e->desc;
- e->last_served = approx_time();
- return 1;
- }
- return 0;
- }
- /* Do not allow more than this many introduction points in a hidden service
- * descriptor */
- #define MAX_INTRO_POINTS 10
- /** Parse the v2 service descriptor(s) in <b>desc</b> and store it/them to the
- * local rend cache. Don't attempt to decrypt the included list of introduction
- * points (as we don't have a descriptor cookie for it).
- *
- * If we have a newer descriptor with the same ID, ignore this one.
- * If we have an older descriptor with the same ID, replace it.
- *
- * Return an appropriate rend_cache_store_status_t.
- */
- rend_cache_store_status_t
- rend_cache_store_v2_desc_as_dir(const char *desc)
- {
- const or_options_t *options = get_options();
- rend_service_descriptor_t *parsed;
- char desc_id[DIGEST_LEN];
- char *intro_content;
- size_t intro_size;
- size_t encoded_size;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- int number_parsed = 0, number_stored = 0;
- const char *current_desc = desc;
- const char *next_desc;
- rend_cache_entry_t *e;
- time_t now = time(NULL);
- tor_assert(rend_cache_v2_dir);
- tor_assert(desc);
- if (!hid_serv_acting_as_directory()) {
- /* Cannot store descs, because we are (currently) not acting as
- * hidden service directory. */
- log_info(LD_REND, "Cannot store descs: Not acting as hs dir");
- return RCS_NOTDIR;
- }
- while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, current_desc, 1) >= 0) {
- number_parsed++;
- /* We don't care about the introduction points. */
- tor_free(intro_content);
- /* For pretty log statements. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32),
- desc_id, DIGEST_LEN);
- /* Is desc ID in the range that we are (directly or indirectly) responsible
- * for? */
- if (!hid_serv_responsible_for_desc_id(desc_id)) {
- log_info(LD_REND, "Service descriptor with desc ID %s is not in "
- "interval that we are responsible for.",
- safe_str_client(desc_id_base32));
- goto skip;
- }
- /* Is descriptor too old? */
- if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
- log_info(LD_REND, "Service descriptor with desc ID %s is too old.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Is descriptor too far in the future? */
- if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
- log_info(LD_REND, "Service descriptor with desc ID %s is too far in the "
- "future.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Do we already have a newer descriptor? */
- e = digestmap_get(rend_cache_v2_dir, desc_id);
- if (e && e->parsed->timestamp > parsed->timestamp) {
- log_info(LD_REND, "We already have a newer service descriptor with the "
- "same desc ID %s and version.",
- safe_str(desc_id_base32));
- goto skip;
- }
- /* Do we already have this descriptor? */
- if (e && !strcmp(desc, e->desc)) {
- log_info(LD_REND, "We already have this service descriptor with desc "
- "ID %s.", safe_str(desc_id_base32));
- goto skip;
- }
- /* Store received descriptor. */
- if (!e) {
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- digestmap_set(rend_cache_v2_dir, desc_id, e);
- /* Treat something just uploaded as having been served a little
- * while ago, so that flooding with new descriptors doesn't help
- * too much.
- */
- e->last_served = approx_time() - 3600;
- } else {
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- }
- e->parsed = parsed;
- e->desc = tor_strndup(current_desc, encoded_size);
- e->len = encoded_size;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- log_info(LD_REND, "Successfully stored service descriptor with desc ID "
- "'%s' and len %d.",
- safe_str(desc_id_base32), (int)encoded_size);
- /* Statistics: Note down this potentially new HS. */
- if (options->HiddenServiceStatistics) {
- rep_hist_stored_maybe_new_hs(e->parsed->pk);
- }
- number_stored++;
- goto advance;
- skip:
- rend_service_descriptor_free(parsed);
- advance:
- /* advance to next descriptor, if available. */
- current_desc = next_desc;
- /* check if there is a next descriptor. */
- if (!current_desc ||
- strcmpstart(current_desc, "rendezvous-service-descriptor "))
- break;
- }
- if (!number_parsed) {
- log_info(LD_REND, "Could not parse any descriptor.");
- return RCS_BADDESC;
- }
- log_info(LD_REND, "Parsed %d and added %d descriptor%s.",
- number_parsed, number_stored, number_stored != 1 ? "s" : "");
- return RCS_OKAY;
- }
- /** Parse the v2 service descriptor in <b>desc</b>, decrypt the included list
- * of introduction points with <b>descriptor_cookie</b> (which may also be
- * <b>NULL</b> if decryption is not necessary), and store the descriptor to
- * the local cache under its version and service id.
- *
- * If we have a newer v2 descriptor with the same ID, ignore this one.
- * If we have an older descriptor with the same ID, replace it.
- * If the descriptor's service ID does not match
- * <b>rend_query</b>-\>onion_address, reject it.
- *
- * If the descriptor's descriptor ID doesn't match <b>desc_id_base32</b>,
- * reject it.
- *
- * Return an appropriate rend_cache_store_status_t. If entry is not NULL,
- * set it with the cache entry pointer of the descriptor.
- */
- rend_cache_store_status_t
- rend_cache_store_v2_desc_as_client(const char *desc,
- const char *desc_id_base32,
- const rend_data_t *rend_query,
- rend_cache_entry_t **entry)
- {
- /*XXXX this seems to have a bit of duplicate code with
- * rend_cache_store_v2_desc_as_dir(). Fix that. */
- /* Though having similar elements, both functions were separated on
- * purpose:
- * - dirs don't care about encoded/encrypted introduction points, clients
- * do.
- * - dirs store descriptors in a separate cache by descriptor ID, whereas
- * clients store them by service ID; both caches are different data
- * structures and have different access methods.
- * - dirs store a descriptor only if they are responsible for its ID,
- * clients do so in every way (because they have requested it before).
- * - dirs can process multiple concatenated descriptors which is required
- * for replication, whereas clients only accept a single descriptor.
- * Thus, combining both methods would result in a lot of if statements
- * which probably would not improve, but worsen code readability. -KL */
- rend_service_descriptor_t *parsed = NULL;
- char desc_id[DIGEST_LEN];
- char *intro_content = NULL;
- size_t intro_size;
- size_t encoded_size;
- const char *next_desc;
- time_t now = time(NULL);
- char key[REND_SERVICE_ID_LEN_BASE32+2];
- char service_id[REND_SERVICE_ID_LEN_BASE32+1];
- char want_desc_id[DIGEST_LEN];
- rend_cache_entry_t *e;
- rend_cache_store_status_t retval = RCS_BADDESC;
- tor_assert(rend_cache);
- tor_assert(desc);
- tor_assert(desc_id_base32);
- memset(want_desc_id, 0, sizeof(want_desc_id));
- if (entry) {
- *entry = NULL;
- }
- if (base32_decode(want_desc_id, sizeof(want_desc_id),
- desc_id_base32, strlen(desc_id_base32)) != 0) {
- log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.",
- escaped_safe_str_client(desc_id_base32));
- goto err;
- }
- /* Parse the descriptor. */
- if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
- &intro_size, &encoded_size,
- &next_desc, desc, 0) < 0) {
- log_warn(LD_REND, "Could not parse descriptor.");
- goto err;
- }
- /* Compute service ID from public key. */
- if (rend_get_service_id(parsed->pk, service_id)<0) {
- log_warn(LD_REND, "Couldn't compute service ID.");
- goto err;
- }
- if (rend_query->onion_address[0] != '\0' &&
- strcmp(rend_query->onion_address, service_id)) {
- log_warn(LD_REND, "Received service descriptor for service ID %s; "
- "expected descriptor for service ID %s.",
- service_id, safe_str(rend_query->onion_address));
- goto err;
- }
- if (tor_memneq(desc_id, want_desc_id, DIGEST_LEN)) {
- log_warn(LD_REND, "Received service descriptor for %s with incorrect "
- "descriptor ID.", service_id);
- goto err;
- }
- /* Decode/decrypt introduction points. */
- if (intro_content && intro_size > 0) {
- int n_intro_points;
- if (rend_query->auth_type != REND_NO_AUTH &&
- !tor_mem_is_zero(rend_query->descriptor_cookie,
- sizeof(rend_query->descriptor_cookie))) {
- char *ipos_decrypted = NULL;
- size_t ipos_decrypted_size;
- if (rend_decrypt_introduction_points(&ipos_decrypted,
- &ipos_decrypted_size,
- rend_query->descriptor_cookie,
- intro_content,
- intro_size) < 0) {
- log_warn(LD_REND, "Failed to decrypt introduction points. We are "
- "probably unable to parse the encoded introduction points.");
- } else {
- /* Replace encrypted with decrypted introduction points. */
- log_info(LD_REND, "Successfully decrypted introduction points.");
- tor_free(intro_content);
- intro_content = ipos_decrypted;
- intro_size = ipos_decrypted_size;
- }
- }
- n_intro_points = rend_parse_introduction_points(parsed, intro_content,
- intro_size);
- if (n_intro_points <= 0) {
- log_warn(LD_REND, "Failed to parse introduction points. Either the "
- "service has published a corrupt descriptor or you have "
- "provided invalid authorization data.");
- goto err;
- } else if (n_intro_points > MAX_INTRO_POINTS) {
- log_warn(LD_REND, "Found too many introduction points on a hidden "
- "service descriptor for %s. This is probably a (misguided) "
- "attempt to improve reliability, but it could also be an "
- "attempt to do a guard enumeration attack. Rejecting.",
- safe_str_client(service_id));
- goto err;
- }
- } else {
- log_info(LD_REND, "Descriptor does not contain any introduction points.");
- parsed->intro_nodes = smartlist_new();
- }
- /* We don't need the encoded/encrypted introduction points any longer. */
- tor_free(intro_content);
- /* Is descriptor too old? */
- if (parsed->timestamp < now - REND_CACHE_MAX_AGE-REND_CACHE_MAX_SKEW) {
- log_warn(LD_REND, "Service descriptor with service ID %s is too old.",
- safe_str_client(service_id));
- goto err;
- }
- /* Is descriptor too far in the future? */
- if (parsed->timestamp > now + REND_CACHE_MAX_SKEW) {
- log_warn(LD_REND, "Service descriptor with service ID %s is too far in "
- "the future.", safe_str_client(service_id));
- goto err;
- }
- /* Do we already have a newer descriptor? */
- tor_snprintf(key, sizeof(key), "2%s", service_id);
- e = (rend_cache_entry_t*) strmap_get_lc(rend_cache, key);
- if (e && e->parsed->timestamp >= parsed->timestamp) {
- log_info(LD_REND, "We already have a new enough service descriptor for "
- "service ID %s with the same desc ID and version.",
- safe_str_client(service_id));
- goto okay;
- }
- if (!e) {
- e = tor_malloc_zero(sizeof(rend_cache_entry_t));
- strmap_set_lc(rend_cache, key, e);
- } else {
- rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
- rend_service_descriptor_free(e->parsed);
- tor_free(e->desc);
- }
- e->parsed = parsed;
- e->desc = tor_malloc_zero(encoded_size + 1);
- strlcpy(e->desc, desc, encoded_size + 1);
- e->len = encoded_size;
- rend_cache_increment_allocation(rend_cache_entry_allocation(e));
- log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
- safe_str_client(service_id), (int)encoded_size);
- if (entry) {
- *entry = e;
- }
- return RCS_OKAY;
- okay:
- if (entry) {
- *entry = e;
- }
- retval = RCS_OKAY;
- err:
- rend_service_descriptor_free(parsed);
- tor_free(intro_content);
- return retval;
- }
- /** Called when we get a rendezvous-related relay cell on circuit
- * <b>circ</b>. Dispatch on rendezvous relay command. */
- void
- rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint,
- int command, size_t length,
- const uint8_t *payload)
- {
- or_circuit_t *or_circ = NULL;
- origin_circuit_t *origin_circ = NULL;
- int r = -2;
- if (CIRCUIT_IS_ORIGIN(circ)) {
- origin_circ = TO_ORIGIN_CIRCUIT(circ);
- if (!layer_hint || layer_hint != origin_circ->cpath->prev) {
- log_fn(LOG_PROTOCOL_WARN, LD_APP,
- "Relay cell (rend purpose %d) from wrong hop on origin circ",
- command);
- origin_circ = NULL;
- }
- } else {
- or_circ = TO_OR_CIRCUIT(circ);
- }
- switch (command) {
- case RELAY_COMMAND_ESTABLISH_INTRO:
- if (or_circ)
- r = rend_mid_establish_intro(or_circ,payload,length);
- break;
- case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
- if (or_circ)
- r = rend_mid_establish_rendezvous(or_circ,payload,length);
- break;
- case RELAY_COMMAND_INTRODUCE1:
- if (or_circ)
- r = rend_mid_introduce(or_circ,payload,length);
- break;
- case RELAY_COMMAND_INTRODUCE2:
- if (origin_circ)
- r = rend_service_introduce(origin_circ,payload,length);
- break;
- case RELAY_COMMAND_INTRODUCE_ACK:
- if (origin_circ)
- r = rend_client_introduction_acked(origin_circ,payload,length);
- break;
- case RELAY_COMMAND_RENDEZVOUS1:
- if (or_circ)
- r = rend_mid_rendezvous(or_circ,payload,length);
- break;
- case RELAY_COMMAND_RENDEZVOUS2:
- if (origin_circ)
- r = rend_client_receive_rendezvous(origin_circ,payload,length);
- break;
- case RELAY_COMMAND_INTRO_ESTABLISHED:
- if (origin_circ)
- r = rend_service_intro_established(origin_circ,payload,length);
- break;
- case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
- if (origin_circ)
- r = rend_client_rendezvous_acked(origin_circ,payload,length);
- break;
- default:
- tor_fragile_assert();
- }
- if (r == -2)
- log_info(LD_PROTOCOL, "Dropping cell (type %d) for wrong circuit type.",
- command);
- }
- /** Allocate and return a new rend_data_t with the same
- * contents as <b>query</b>. */
- rend_data_t *
- rend_data_dup(const rend_data_t *data)
- {
- rend_data_t *data_dup;
- tor_assert(data);
- data_dup = tor_memdup(data, sizeof(rend_data_t));
- data_dup->hsdirs_fp = smartlist_new();
- SMARTLIST_FOREACH(data->hsdirs_fp, char *, fp,
- smartlist_add(data_dup->hsdirs_fp,
- tor_memdup(fp, DIGEST_LEN)));
- return data_dup;
- }
- /** Compute descriptor ID for each replicas and save them. A valid onion
- * address must be present in the <b>rend_data</b>.
- *
- * Return 0 on success else -1. */
- static int
- compute_desc_id(rend_data_t *rend_data)
- {
- int ret;
- unsigned replica;
- time_t now = time(NULL);
- tor_assert(rend_data);
- /* Compute descriptor ID for each replicas. */
- for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
- replica++) {
- ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica],
- rend_data->onion_address,
- rend_data->descriptor_cookie,
- now, replica);
- if (ret < 0) {
- goto end;
- }
- }
- end:
- return ret;
- }
- /** Allocate and initialize a rend_data_t object for a service using the
- * given arguments. Only the <b>onion_address</b> is not optional.
- *
- * Return a valid rend_data_t pointer. */
- rend_data_t *
- rend_data_service_create(const char *onion_address, const char *pk_digest,
- const uint8_t *cookie, rend_auth_type_t auth_type)
- {
- rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
- /* We need at least one else the call is wrong. */
- tor_assert(onion_address != NULL);
- if (pk_digest) {
- memcpy(rend_data->rend_pk_digest, pk_digest,
- sizeof(rend_data->rend_pk_digest));
- }
- if (cookie) {
- memcpy(rend_data->rend_cookie, cookie,
- sizeof(rend_data->rend_cookie));
- }
- strlcpy(rend_data->onion_address, onion_address,
- sizeof(rend_data->onion_address));
- rend_data->auth_type = auth_type;
- /* Won't be used but still need to initialize it for rend_data dup and
- * free. */
- rend_data->hsdirs_fp = smartlist_new();
- return rend_data;
- }
- /** Allocate and initialize a rend_data_t object for a client request using
- * the given arguments. Either an onion address or a descriptor ID is
- * needed. Both can be given but only the onion address will be used to make
- * the descriptor fetch.
- *
- * Return a valid rend_data_t pointer or NULL on error meaning the
- * descriptor IDs couldn't be computed from the given data. */
- rend_data_t *
- rend_data_client_create(const char *onion_address, const char *desc_id,
- const char *cookie, rend_auth_type_t auth_type)
- {
- rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
- /* We need at least one else the call is wrong. */
- tor_assert(onion_address != NULL || desc_id != NULL);
- if (cookie) {
- memcpy(rend_data->descriptor_cookie, cookie,
- sizeof(rend_data->descriptor_cookie));
- }
- if (desc_id) {
- memcpy(rend_data->desc_id_fetch, desc_id,
- sizeof(rend_data->desc_id_fetch));
- }
- if (onion_address) {
- strlcpy(rend_data->onion_address, onion_address,
- sizeof(rend_data->onion_address));
- if (compute_desc_id(rend_data) < 0) {
- goto error;
- }
- }
- rend_data->auth_type = auth_type;
- rend_data->hsdirs_fp = smartlist_new();
- return rend_data;
- error:
- rend_data_free(rend_data);
- return NULL;
- }
|