diff options
Diffstat (limited to 'src/or/rendservice.c')
-rw-r--r-- | src/or/rendservice.c | 166 |
1 files changed, 95 insertions, 71 deletions
diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 545fba1449..ce205313f6 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -556,6 +556,7 @@ rend_config_services(const or_options_t *options, int validate_only) smartlist_t *old_service_list = NULL; smartlist_t *temp_service_list = NULL; int ok = 0; + int rv = -1; /* Use a temporary service list, so that we can check the new services' * consistency with each other */ @@ -568,7 +569,8 @@ rend_config_services(const or_options_t *options, int validate_only) * which is registered below the loop */ if (rend_service_check_dir_and_add(temp_service_list, options, service, validate_only) < 0) { - return -1; + service = NULL; + goto free_and_return; } service = tor_malloc_zero(sizeof(rend_service_t)); service->directory = tor_strdup(line->value); @@ -580,8 +582,7 @@ rend_config_services(const or_options_t *options, int validate_only) if (!service) { log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive", line->key); - rend_service_free(service); - return -1; + goto free_and_return; } if (!strcasecmp(line->key, "HiddenServicePort")) { char *err_msg = NULL; @@ -590,8 +591,7 @@ rend_config_services(const or_options_t *options, int validate_only) if (err_msg) log_warn(LD_CONFIG, "%s", err_msg); tor_free(err_msg); - rend_service_free(service); - return -1; + goto free_and_return; } tor_assert(!err_msg); smartlist_add(service->ports, portcfg); @@ -602,8 +602,8 @@ rend_config_services(const or_options_t *options, int validate_only) log_warn(LD_CONFIG, "HiddenServiceAllowUnknownPorts should be 0 or 1, not %s", line->value); - rend_service_free(service); - return -1; + smartlist_free(temp_service_list); + goto free_and_return; } log_info(LD_CONFIG, "HiddenServiceAllowUnknownPorts=%d for %s", @@ -617,8 +617,7 @@ rend_config_services(const or_options_t *options, int validate_only) log_warn(LD_CONFIG, "HiddenServiceDirGroupReadable should be 0 or 1, not %s", line->value); - rend_service_free(service); - return -1; + goto free_and_return; } log_info(LD_CONFIG, "HiddenServiceDirGroupReadable=%d for %s", @@ -631,8 +630,7 @@ rend_config_services(const or_options_t *options, int validate_only) log_warn(LD_CONFIG, "HiddenServiceMaxStreams should be between 0 and %d, not %s", 65535, line->value); - rend_service_free(service); - return -1; + goto free_and_return; } log_info(LD_CONFIG, "HiddenServiceMaxStreams=%d for %s", @@ -646,8 +644,7 @@ rend_config_services(const or_options_t *options, int validate_only) "HiddenServiceMaxStreamsCloseCircuit should be 0 or 1, " "not %s", line->value); - rend_service_free(service); - return -1; + goto free_and_return; } log_info(LD_CONFIG, "HiddenServiceMaxStreamsCloseCircuit=%d for %s", @@ -664,8 +661,7 @@ rend_config_services(const or_options_t *options, int validate_only) "should be between %d and %d, not %s", NUM_INTRO_POINTS_DEFAULT, NUM_INTRO_POINTS_MAX, line->value); - rend_service_free(service); - return -1; + goto free_and_return; } log_info(LD_CONFIG, "HiddenServiceNumIntroductionPoints=%d for %s", service->n_intro_points_wanted, @@ -680,8 +676,7 @@ rend_config_services(const or_options_t *options, int validate_only) if (service->auth_type != REND_NO_AUTH) { log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient " "lines for a single service."); - rend_service_free(service); - return -1; + goto free_and_return; } type_names_split = smartlist_new(); smartlist_split_string(type_names_split, line->value, " ", 0, 2); @@ -689,9 +684,7 @@ rend_config_services(const or_options_t *options, int validate_only) log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This " "should have been prevented when parsing the " "configuration."); - smartlist_free(type_names_split); - rend_service_free(service); - return -1; + goto free_and_return; } authname = smartlist_get(type_names_split, 0); if (!strcasecmp(authname, "basic")) { @@ -705,8 +698,7 @@ rend_config_services(const or_options_t *options, int validate_only) (char *) smartlist_get(type_names_split, 0)); SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp)); smartlist_free(type_names_split); - rend_service_free(service); - return -1; + goto free_and_return; } service->clients = smartlist_new(); if (smartlist_len(type_names_split) < 2) { @@ -743,8 +735,7 @@ rend_config_services(const or_options_t *options, int validate_only) client_name, REND_CLIENTNAME_MAX_LEN); SMARTLIST_FOREACH(clients, char *, cp, tor_free(cp)); smartlist_free(clients); - rend_service_free(service); - return -1; + goto free_and_return; } client = tor_malloc_zero(sizeof(rend_authorized_client_t)); client->client_name = tor_strdup(client_name); @@ -766,16 +757,14 @@ rend_config_services(const or_options_t *options, int validate_only) smartlist_len(service->clients), service->auth_type == REND_BASIC_AUTH ? 512 : 16, service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth"); - rend_service_free(service); - return -1; + goto free_and_return; } } else { tor_assert(!strcasecmp(line->key, "HiddenServiceVersion")); if (strcmp(line->value, "2")) { log_warn(LD_CONFIG, "The only supported HiddenServiceVersion is 2."); - rend_service_free(service); - return -1; + goto free_and_return; } } } @@ -784,16 +773,15 @@ rend_config_services(const or_options_t *options, int validate_only) * within the loop. It is ok for this service to be NULL, it is ignored. */ if (rend_service_check_dir_and_add(temp_service_list, options, service, validate_only) < 0) { - return -1; + service = NULL; + goto free_and_return; } + service = NULL; /* Free the newly added services if validating */ if (validate_only) { - SMARTLIST_FOREACH(temp_service_list, rend_service_t *, ptr, - rend_service_free(ptr)); - smartlist_free(temp_service_list); - temp_service_list = NULL; - return 0; + rv = 0; + goto free_and_return; } /* Otherwise, use the newly added services as the new service list @@ -889,6 +877,12 @@ rend_config_services(const or_options_t *options, int validate_only) } return 0; + free_and_return: + rend_service_free(service); + SMARTLIST_FOREACH(temp_service_list, rend_service_t *, ptr, + rend_service_free(ptr)); + smartlist_free(temp_service_list); + return rv; } /** Add the ephemeral service <b>pk</b>/<b>ports</b> if possible, using @@ -3160,6 +3154,57 @@ count_intro_point_circuits(const rend_service_t *service) return num_ipos; } +/* Given a buffer of at least RELAY_PAYLOAD_SIZE bytes in <b>cell_body_out</b>, + write the body of a legacy ESTABLISH_INTRO cell in it. Use <b>intro_key</b> + as the intro point auth key, and <b>rend_circ_nonce</b> as the circuit + crypto material. On success, fill <b>cell_body_out</b> and return the number + of bytes written. On fail, return -1. + */ +STATIC ssize_t +encode_establish_intro_cell_legacy(char *cell_body_out, crypto_pk_t *intro_key, + char *rend_circ_nonce) +{ + int retval = -1; + int r; + int len = 0; + char auth[DIGEST_LEN + 9]; + + tor_assert(intro_key); + tor_assert(rend_circ_nonce); + + /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */ + r = crypto_pk_asn1_encode(intro_key, cell_body_out+2, + RELAY_PAYLOAD_SIZE-2); + if (r < 0) { + log_warn(LD_BUG, "Internal error; failed to establish intro point."); + goto err; + } + len = r; + set_uint16(cell_body_out, htons((uint16_t)len)); + len += 2; + memcpy(auth, rend_circ_nonce, DIGEST_LEN); + memcpy(auth+DIGEST_LEN, "INTRODUCE", 9); + if (crypto_digest(cell_body_out+len, auth, DIGEST_LEN+9)) + goto err; + len += 20; + note_crypto_pk_op(REND_SERVER); + r = crypto_pk_private_sign_digest(intro_key, cell_body_out+len, + sizeof(cell_body_out)-len, + cell_body_out, len); + if (r<0) { + log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); + goto err; + } + len += r; + + retval = len; + + err: + memwipe(auth, 0, sizeof(auth)); + + return retval; +} + /** Called when we're done building a circuit to an introduction point: * sends a RELAY_ESTABLISH_INTRO cell. */ @@ -3167,10 +3212,7 @@ void rend_service_intro_has_opened(origin_circuit_t *circuit) { rend_service_t *service; - size_t len; - int r; char buf[RELAY_PAYLOAD_SIZE]; - char auth[DIGEST_LEN + 9]; char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; int reason = END_CIRC_REASON_TORPROTOCOL; const char *rend_pk_digest; @@ -3245,41 +3287,24 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) (unsigned)circuit->base_.n_circ_id, serviceid); circuit_log_path(LOG_INFO, LD_REND, circuit); - /* Use the intro key instead of the service key in ESTABLISH_INTRO. */ - crypto_pk_t *intro_key = circuit->intro_key; - /* Build the payload for a RELAY_ESTABLISH_INTRO cell. */ - r = crypto_pk_asn1_encode(intro_key, buf+2, - RELAY_PAYLOAD_SIZE-2); - if (r < 0) { - log_warn(LD_BUG, "Internal error; failed to establish intro point."); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - len = r; - set_uint16(buf, htons((uint16_t)len)); - len += 2; - memcpy(auth, circuit->cpath->prev->rend_circ_nonce, DIGEST_LEN); - memcpy(auth+DIGEST_LEN, "INTRODUCE", 9); - if (crypto_digest(buf+len, auth, DIGEST_LEN+9) < 0) - goto err; - len += 20; - note_crypto_pk_op(REND_SERVER); - r = crypto_pk_private_sign_digest(intro_key, buf+len, sizeof(buf)-len, - buf, len); - if (r<0) { - log_warn(LD_BUG, "Internal error: couldn't sign introduction request."); - reason = END_CIRC_REASON_INTERNAL; - goto err; - } - len += r; + /* Send the ESTABLISH_INTRO cell */ + { + ssize_t len; + len = encode_establish_intro_cell_legacy(buf, circuit->intro_key, + circuit->cpath->prev->rend_circ_nonce); + if (len < 0) { + reason = END_CIRC_REASON_INTERNAL; + goto err; + } - if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), - RELAY_COMMAND_ESTABLISH_INTRO, - buf, len, circuit->cpath->prev)<0) { - log_info(LD_GENERAL, + if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), + RELAY_COMMAND_ESTABLISH_INTRO, + buf, len, circuit->cpath->prev)<0) { + log_info(LD_GENERAL, "Couldn't send introduction request for service %s on circuit %u", serviceid, (unsigned)circuit->base_.n_circ_id); - goto done; + goto done; + } } /* We've attempted to use this circuit */ @@ -3291,7 +3316,6 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) circuit_mark_for_close(TO_CIRCUIT(circuit), reason); done: memwipe(buf, 0, sizeof(buf)); - memwipe(auth, 0, sizeof(auth)); memwipe(serviceid, 0, sizeof(serviceid)); return; @@ -3628,7 +3652,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, DIRIND_ANONYMOUS, NULL, desc->desc_str, strlen(desc->desc_str), - 0, rend_data); + 0, rend_data, NULL); rend_data_free(rend_data); base32_encode(desc_id_base32, sizeof(desc_id_base32), desc->desc_id, DIGEST_LEN); |