static void test_rend_cache_validate_intro_point_failure(void *data) { (void)data; rend_service_descriptor_t *desc = NULL; char *service_id = NULL; rend_intro_point_t *intro = NULL; const char *identity = NULL; rend_cache_failure_t *failure; rend_cache_failure_intro_t *ip; rend_cache_init(); create_descriptor(&desc, &service_id, 3); desc->timestamp = time(NULL) + RECENT_TIME; intro = (rend_intro_point_t *)smartlist_get(desc->intro_nodes, 0); identity = intro->extend_info->identity_digest; failure = rend_cache_failure_entry_new(); ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT); digestmap_set(failure->intro_failures, identity, ip); strmap_set_lc(rend_cache_failure, service_id, failure); // Test when we have an intro point in our cache validate_intro_point_failure(desc, service_id); tt_int_op(smartlist_len(desc->intro_nodes), OP_EQ, 2); done: rend_cache_free_all(); rend_service_descriptor_free(desc); tor_free(service_id); }
static void test_rend_cache_store_v2_desc_as_dir_with_different_content(void *data) { (void)data; rend_cache_store_status_t ret; rend_service_descriptor_t *generated = NULL; smartlist_t *descs = smartlist_new(); time_t t; char *service_id = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_one = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_two = NULL; NS_MOCK(router_get_my_routerinfo); NS_MOCK(hid_serv_responsible_for_desc_id); rend_cache_init(); t = time(NULL); create_descriptor(&generated, &service_id, 3); generated->timestamp = t + RECENT_TIME; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_one = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); descs = smartlist_new(); generated->timestamp = t + RECENT_TIME; generated->protocols = 41; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_two = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); // Test when we have another descriptor stored, with a different descriptor mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); hid_serv_responsible_for_desc_id_response = 1; rend_cache_store_v2_desc_as_dir(desc_holder_one->desc_str); ret = rend_cache_store_v2_desc_as_dir(desc_holder_two->desc_str); tt_int_op(ret, OP_EQ, RCS_OKAY); done: NS_UNMOCK(router_get_my_routerinfo); NS_UNMOCK(hid_serv_responsible_for_desc_id); rend_cache_free_all(); rend_service_descriptor_free(generated); tor_free(service_id); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); rend_encoded_v2_service_descriptor_free(desc_holder_one); rend_encoded_v2_service_descriptor_free(desc_holder_two); }
/** 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)); /* We are about to remove a descriptor from the cache so remove the entry * in the failure cache. */ rend_cache_failure_remove(e->parsed); rend_service_descriptor_free(e->parsed); tor_free(e->desc); tor_free(e); }
int fuzz_main(const uint8_t *data, size_t sz) { rend_service_descriptor_t *desc = NULL; char desc_id[64]; char *ipts = NULL; size_t ipts_size, esize; const char *next; char *str = tor_memdup_nulterm(data, sz); (void) rend_parse_v2_service_descriptor(&desc, desc_id, &ipts, &ipts_size, &esize, &next, str, 1); if (desc) { log_debug(LD_GENERAL, "Parsing okay"); rend_service_descriptor_free(desc); } else { log_debug(LD_GENERAL, "Parsing failed"); } tor_free(ipts); tor_free(str); return 0; }
static void test_rend_cache_failure_remove(void *data) { rend_service_descriptor_t *desc; (void)data; rend_cache_init(); // Test that it deals well with a NULL desc rend_cache_failure_remove(NULL); // Test a descriptor that isn't in the cache desc = tor_malloc_zero(sizeof(rend_service_descriptor_t)); desc->pk = pk_generate(0); rend_cache_failure_remove(desc); // There seems to not exist any way of getting rend_cache_failure_remove() // to fail because of a problem with rend_get_service_id from here rend_cache_free_all(); rend_service_descriptor_free(desc); /* done: */ /* (void)0; */ }
static void test_rend_cache_store_v2_desc_as_dir_with_different_time(void *data) { (void)data; int ret; rend_service_descriptor_t *generated = NULL; smartlist_t *descs = smartlist_new(); time_t t; char *service_id = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_newer; rend_encoded_v2_service_descriptor_t *desc_holder_older; NS_MOCK(router_get_my_routerinfo); rend_cache_init(); t = time(NULL); create_descriptor(&generated, &service_id, 3); generated->timestamp = t + RECENT_TIME; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); descs = smartlist_new(); generated->timestamp = (t + RECENT_TIME) - 20; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); // Test when we have a newer descriptor stored mock_routerinfo = tor_malloc(sizeof(routerinfo_t)); rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); ret = rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); tt_int_op(ret, OP_EQ, 0); // Test when we have an old descriptor stored rend_cache_purge(); rend_cache_store_v2_desc_as_dir(desc_holder_older->desc_str); ret = rend_cache_store_v2_desc_as_dir(desc_holder_newer->desc_str); tt_int_op(ret, OP_EQ, 0); done: NS_UNMOCK(router_get_my_routerinfo); rend_cache_free_all(); rend_service_descriptor_free(generated); tor_free(service_id); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); rend_encoded_v2_service_descriptor_free(desc_holder_newer); rend_encoded_v2_service_descriptor_free(desc_holder_older); tor_free(mock_routerinfo); }
static void test_rend_cache_store_v2_desc_as_client_with_different_time(void *data) { int ret; rend_data_t *mock_rend_query; char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1]; rend_service_descriptor_t *generated = NULL; smartlist_t *descs = smartlist_new(); time_t t; char *service_id = NULL; rend_encoded_v2_service_descriptor_t *desc_holder_newer; rend_encoded_v2_service_descriptor_t *desc_holder_older; t = time(NULL); rend_cache_init(); create_descriptor(&generated, &service_id, 3); generated->timestamp = t + RECENT_TIME; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_newer = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); descs = smartlist_new(); generated->timestamp = (t + RECENT_TIME) - 20; rend_encode_v2_descriptors(descs, generated, t + RECENT_TIME, 0, REND_NO_AUTH, NULL, NULL); desc_holder_older = ((rend_encoded_v2_service_descriptor_t *) smartlist_get(descs, 0)); smartlist_set(descs, 0, NULL); (void)data; // Test when a descriptor is already in the cache and it is newer than the // one we submit mock_rend_query = mock_rend_data(service_id); base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder_newer->desc_id, DIGEST_LEN); rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, desc_id_base32, mock_rend_query, NULL); ret = rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, desc_id_base32, mock_rend_query, NULL); tt_int_op(ret, OP_EQ, 0); rend_cache_free_all(); // Test when an old descriptor is in the cache and we submit a newer one rend_cache_init(); rend_cache_store_v2_desc_as_client(desc_holder_older->desc_str, desc_id_base32, mock_rend_query, NULL); ret = rend_cache_store_v2_desc_as_client(desc_holder_newer->desc_str, desc_id_base32, mock_rend_query, NULL); tt_int_op(ret, OP_EQ, 0); done: rend_encoded_v2_service_descriptor_free(desc_holder_newer); rend_encoded_v2_service_descriptor_free(desc_holder_older); SMARTLIST_FOREACH(descs, rend_encoded_v2_service_descriptor_t *, d, rend_encoded_v2_service_descriptor_free(d)); smartlist_free(descs); rend_service_descriptor_free(generated); tor_free(service_id); rend_cache_free_all(); rend_data_free(mock_rend_query); }
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the * encrypted introduction points to the newly allocated * *<b>intro_points_encrypted_out</b>, their encrypted size to * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor * to *<b>encoded_size_out</b>, and a pointer to the possibly next * descriptor to *<b>next_out</b>; return 0 for success (including validation) * and -1 for failure. * * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should * be strict about time formats. */ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char *desc_id_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, const char **next_out, const char *desc, int as_hsdir) { rend_service_descriptor_t *result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); char desc_hash[DIGEST_LEN]; const char *eos; smartlist_t *tokens = smartlist_new(); directory_token_t *tok; char secret_id_part[DIGEST_LEN]; int i, version, num_ok=1; smartlist_t *versions; char public_key_hash[DIGEST_LEN]; char test_desc_id[DIGEST_LEN]; memarea_t *area = NULL; const int strict_time_fmt = as_hsdir; tor_assert(desc); /* Check if desc starts correctly. */ if (strcmpstart(desc, "rendezvous-service-descriptor ")) { log_info(LD_REND, "Descriptor does not start correctly."); goto err; } /* Compute descriptor hash for later validation. */ if (router_get_hash_impl(desc, strlen(desc), desc_hash, "rendezvous-service-descriptor ", "\nsignature", '\n', DIGEST_SHA1) < 0) { log_warn(LD_REND, "Couldn't compute descriptor hash."); goto err; } /* Determine end of string. */ eos = strstr(desc, "\nrendezvous-service-descriptor "); if (!eos) eos = desc + strlen(desc); else eos = eos + 1; /* Check length. */ if (eos-desc > REND_DESC_MAX_SIZE) { /* XXXX+ If we are parsing this descriptor as a server, this * should be a protocol warning. */ log_warn(LD_REND, "Descriptor length is %d which exceeds " "maximum rendezvous descriptor size of %d bytes.", (int)(eos-desc), REND_DESC_MAX_SIZE); goto err; } /* Tokenize descriptor. */ area = memarea_new(); if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) { log_warn(LD_REND, "Error tokenizing descriptor."); goto err; } /* Set next to next descriptor, if available. */ *next_out = eos; /* Set length of encoded descriptor. */ *encoded_size_out = eos - desc; /* Check min allowed length of token list. */ if (smartlist_len(tokens) < 7) { log_warn(LD_REND, "Impossibly short descriptor."); goto err; } /* Parse base32-encoded descriptor ID. */ tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); if (!rend_valid_descriptor_id(tok->args[0])) { log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", tok->args[0]); goto err; } /* Parse descriptor version. */ tok = find_by_keyword(tokens, R_VERSION); tor_assert(tok->n_args == 1); result->version = (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); if (result->version != 2 || !num_ok) { /* If it's <2, it shouldn't be under this format. If the number * is greater than 2, we bumped it because we broke backward * compatibility. See how version numbers in our other formats * work. */ log_warn(LD_REND, "Unrecognized descriptor version: %s", escaped(tok->args[0])); goto err; } /* Parse public key. */ tok = find_by_keyword(tokens, R_PERMANENT_KEY); result->pk = tok->key; tok->key = NULL; /* Prevent free */ /* Parse secret ID part. */ tok = find_by_keyword(tokens, R_SECRET_ID_PART); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { log_warn(LD_REND, "Secret ID part contains illegal characters: %s", tok->args[0]); goto err; } /* Parse publication time -- up-to-date check is done when storing the * descriptor. */ tok = find_by_keyword(tokens, R_PUBLICATION_TIME); tor_assert(tok->n_args == 1); if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt, 0) < 0) { log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); goto err; } /* Parse protocol versions. */ tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); tor_assert(tok->n_args == 1); versions = smartlist_new(); smartlist_split_string(versions, tok->args[0], ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); for (i = 0; i < smartlist_len(versions); i++) { version = (int) tor_parse_long(smartlist_get(versions, i), 10, 0, INT_MAX, &num_ok, NULL); if (!num_ok) /* It's a string; let's ignore it. */ continue; if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH) /* Avoid undefined left-shift behaviour. */ continue; result->protocols |= 1 << version; } SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); smartlist_free(versions); /* Parse encrypted introduction points. Don't verify. */ tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS); if (tok) { if (strcmp(tok->object_type, "MESSAGE")) { log_warn(LD_DIR, "Bad object type: introduction points should be of " "type MESSAGE"); goto err; } *intro_points_encrypted_out = tor_memdup(tok->object_body, tok->object_size); *intro_points_encrypted_size_out = tok->object_size; } else { *intro_points_encrypted_out = NULL; *intro_points_encrypted_size_out = 0; } /* Parse and verify signature. */ tok = find_by_keyword(tokens, R_SIGNATURE); if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0, "v2 rendezvous service descriptor") < 0) goto err; /* Verify that descriptor ID belongs to public key and secret ID part. */ if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) { log_warn(LD_REND, "Unable to compute rend descriptor public key digest"); goto err; } rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, secret_id_part); if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { log_warn(LD_REND, "Parsed descriptor ID does not match " "computed descriptor ID."); goto err; } goto done; err: rend_service_descriptor_free(result); result = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) memarea_drop_all(area); *parsed_out = result; if (result) return 0; return -1; }