Merge remote-tracking branch 'asn/ticket23420_032_01'

This commit is contained in:
Nick Mathewson 2017-09-25 09:24:36 -04:00
commit 777e828ef3
8 changed files with 168 additions and 5 deletions

4
changes/ticket23420 Normal file
View File

@ -0,0 +1,4 @@
o Minor bugfixes (hidden service v3):
- Pad RENDEZVOUS cell up to the size of the legacy cell which is much
bigger so the rendezvous point can't distinguish which hidden service
protocol is being used. Fixes ticket 23420.; bugfix on 0.3.2.1-alpha.

View File

@ -5,6 +5,8 @@
* \file hs_circuit.c * \file hs_circuit.c
**/ **/
#define HS_CIRCUIT_PRIVATE
#include "or.h" #include "or.h"
#include "circpathbias.h" #include "circpathbias.h"
#include "circuitbuild.h" #include "circuitbuild.h"
@ -18,10 +20,10 @@
#include "router.h" #include "router.h"
#include "hs_cell.h" #include "hs_cell.h"
#include "hs_circuit.h"
#include "hs_ident.h" #include "hs_ident.h"
#include "hs_ntor.h" #include "hs_ntor.h"
#include "hs_service.h" #include "hs_service.h"
#include "hs_circuit.h"
/* Trunnel. */ /* Trunnel. */
#include "ed25519_cert.h" #include "ed25519_cert.h"
@ -235,7 +237,7 @@ count_opened_desc_intro_point_circuits(const hs_service_t *service,
/* From a given service, rendezvous cookie and handshake info, create a /* From a given service, rendezvous cookie and handshake info, create a
* rendezvous point circuit identifier. This can't fail. */ * rendezvous point circuit identifier. This can't fail. */
static hs_ident_circuit_t * STATIC hs_ident_circuit_t *
create_rp_circuit_identifier(const hs_service_t *service, create_rp_circuit_identifier(const hs_service_t *service,
const uint8_t *rendezvous_cookie, const uint8_t *rendezvous_cookie,
const curve25519_public_key_t *server_pk, const curve25519_public_key_t *server_pk,
@ -820,6 +822,15 @@ hs_circ_service_rp_has_opened(const hs_service_t *service,
sizeof(circ->hs_ident->rendezvous_handshake_info), sizeof(circ->hs_ident->rendezvous_handshake_info),
payload); payload);
/* Pad the payload with random bytes so it matches the size of a legacy cell
* which is normally always bigger. Also, the size of a legacy cell is
* always smaller than the RELAY_PAYLOAD_SIZE so this is safe. */
if (payload_len < HS_LEGACY_RENDEZVOUS_CELL_SIZE) {
crypto_rand((char *) payload + payload_len,
HS_LEGACY_RENDEZVOUS_CELL_SIZE - payload_len);
payload_len = HS_LEGACY_RENDEZVOUS_CELL_SIZE;
}
if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ), if (relay_send_command_from_edge(CONTROL_CELL_ID, TO_CIRCUIT(circ),
RELAY_COMMAND_RENDEZVOUS1, RELAY_COMMAND_RENDEZVOUS1,
(const char *) payload, payload_len, (const char *) payload, payload_len,

View File

@ -59,5 +59,15 @@ int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ, int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
const uint8_t *rend_cell_body); const uint8_t *rend_cell_body);
#ifdef HS_CIRCUIT_PRIVATE
STATIC hs_ident_circuit_t *
create_rp_circuit_identifier(const hs_service_t *service,
const uint8_t *rendezvous_cookie,
const curve25519_public_key_t *server_pk,
const hs_ntor_rend_cell_keys_t *keys);
#endif
#endif /* !defined(TOR_HS_CIRCUIT_H) */ #endif /* !defined(TOR_HS_CIRCUIT_H) */

View File

@ -845,7 +845,7 @@ handle_introduce_ack(origin_circuit_t *circ, const uint8_t *payload,
/* Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The /* Called when we get a RENDEZVOUS2 cell on the rendezvous circuit circ. The
* encoded cell is in payload of length payload_len. Return 0 on success or a * encoded cell is in payload of length payload_len. Return 0 on success or a
* negative value on error. On error, the circuit is marked for close. */ * negative value on error. On error, the circuit is marked for close. */
static int STATIC int
handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload, handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload,
size_t payload_len) size_t payload_len)
{ {

View File

@ -77,6 +77,9 @@ client_get_random_intro(const ed25519_public_key_t *service_pk);
STATIC extend_info_t * STATIC extend_info_t *
desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip); desc_intro_point_to_extend_info(const hs_desc_intro_point_t *ip);
STATIC int handle_rendezvous2(origin_circuit_t *circ, const uint8_t *payload,
size_t payload_len);
#endif /* defined(HS_CLIENT_PRIVATE) */ #endif /* defined(HS_CLIENT_PRIVATE) */
#endif /* !defined(TOR_HS_CLIENT_H) */ #endif /* !defined(TOR_HS_CLIENT_H) */

View File

@ -118,6 +118,12 @@
/* Default value of hsdir spread fetch (hsdir_spread_fetch). */ /* Default value of hsdir spread fetch (hsdir_spread_fetch). */
#define HS_DEFAULT_HSDIR_SPREAD_FETCH 3 #define HS_DEFAULT_HSDIR_SPREAD_FETCH 3
/* The size of a legacy RENDEZVOUS1 cell which adds up to 168 bytes. It is
* bigger than the 84 bytes needed for version 3 so we need to pad up to that
* length so it is indistinguishable between versions. */
#define HS_LEGACY_RENDEZVOUS_CELL_SIZE \
(REND_COOKIE_LEN + DH_KEY_LEN + DIGEST_LEN)
/* Type of authentication key used by an introduction point. */ /* Type of authentication key used by an introduction point. */
typedef enum { typedef enum {
HS_AUTH_KEY_TYPE_LEGACY = 1, HS_AUTH_KEY_TYPE_LEGACY = 1,

View File

@ -3398,7 +3398,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
/* Send the cell */ /* Send the cell */
if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit),
RELAY_COMMAND_RENDEZVOUS1, RELAY_COMMAND_RENDEZVOUS1,
buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN, buf, HS_LEGACY_RENDEZVOUS_CELL_SIZE,
circuit->cpath->prev)<0) { circuit->cpath->prev)<0) {
log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell."); log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
goto done; goto done;

View File

@ -14,10 +14,12 @@
#define HS_COMMON_PRIVATE #define HS_COMMON_PRIVATE
#define HS_SERVICE_PRIVATE #define HS_SERVICE_PRIVATE
#define HS_INTROPOINT_PRIVATE #define HS_INTROPOINT_PRIVATE
#define HS_CIRCUIT_PRIVATE
#define MAIN_PRIVATE #define MAIN_PRIVATE
#define NETWORKSTATUS_PRIVATE #define NETWORKSTATUS_PRIVATE
#define STATEFILE_PRIVATE #define STATEFILE_PRIVATE
#define TOR_CHANNEL_INTERNAL_ #define TOR_CHANNEL_INTERNAL_
#define HS_CLIENT_PRIVATE
#include "test.h" #include "test.h"
#include "test_helpers.h" #include "test_helpers.h"
@ -37,11 +39,12 @@
#include "hs_common.h" #include "hs_common.h"
#include "hs_config.h" #include "hs_config.h"
#include "hs_circuit.h"
#include "hs_ident.h" #include "hs_ident.h"
#include "hs_intropoint.h" #include "hs_intropoint.h"
#include "hs_ntor.h" #include "hs_ntor.h"
#include "hs_circuit.h"
#include "hs_service.h" #include "hs_service.h"
#include "hs_client.h"
#include "main.h" #include "main.h"
#include "rendservice.h" #include "rendservice.h"
#include "statefile.h" #include "statefile.h"
@ -1366,6 +1369,130 @@ test_revision_counter_state(void *arg)
service_descriptor_free(desc_two); service_descriptor_free(desc_two);
} }
/** Global vars used by test_rendezvous1_parsing() */
char rend1_payload[RELAY_PAYLOAD_SIZE];
size_t rend1_payload_len = 0;
/** Mock for relay_send_command_from_edge() to send a RENDEZVOUS1 cell. Instead
* of sending it to the network, instead save it to the global `rend1_payload`
* variable so that we can inspect it in the test_rendezvous1_parsing()
* test. */
static int
mock_relay_send_rendezvous1(streamid_t stream_id, circuit_t *circ,
uint8_t relay_command, const char *payload,
size_t payload_len,
crypt_path_t *cpath_layer,
const char *filename, int lineno)
{
(void) stream_id;
(void) circ;
(void) relay_command;
(void) cpath_layer;
(void) filename;
(void) lineno;
memcpy(rend1_payload, payload, payload_len);
rend1_payload_len = payload_len;
return 0;
}
/** Send a RENDEZVOUS1 as a service, and parse it as a client. */
static void
test_rendezvous1_parsing(void *arg)
{
int retval;
static const char *test_addr =
"4acth47i6kxnvkewtm6q7ib2s3ufpo5sqbsnzjpbi7utijcltosqemad.onion";
hs_service_t *service = NULL;
origin_circuit_t *service_circ = NULL;
origin_circuit_t *client_circ = NULL;
ed25519_keypair_t ip_auth_kp;
curve25519_keypair_t ephemeral_kp;
curve25519_keypair_t client_kp;
curve25519_keypair_t ip_enc_kp;
int flags = CIRCLAUNCH_NEED_UPTIME | CIRCLAUNCH_IS_INTERNAL;
(void) arg;
MOCK(relay_send_command_from_edge_, mock_relay_send_rendezvous1);
{
/* Let's start by setting up the service that will start the rend */
service = tor_malloc_zero(sizeof(hs_service_t));
ed25519_secret_key_generate(&service->keys.identity_sk, 0);
ed25519_public_key_generate(&service->keys.identity_pk,
&service->keys.identity_sk);
memcpy(service->onion_address, test_addr, sizeof(service->onion_address));
tt_assert(service);
}
{
/* Now let's set up the service rendezvous circuit and its keys. */
service_circ = helper_create_origin_circuit(CIRCUIT_PURPOSE_S_CONNECT_REND,
flags);
tor_free(service_circ->hs_ident);
hs_ntor_rend_cell_keys_t hs_ntor_rend_cell_keys;
uint8_t rendezvous_cookie[HS_REND_COOKIE_LEN];
curve25519_keypair_generate(&ip_enc_kp, 0);
curve25519_keypair_generate(&ephemeral_kp, 0);
curve25519_keypair_generate(&client_kp, 0);
ed25519_keypair_generate(&ip_auth_kp, 0);
retval = hs_ntor_service_get_rendezvous1_keys(&ip_auth_kp.pubkey,
&ip_enc_kp,
&ephemeral_kp,
&client_kp.pubkey,
&hs_ntor_rend_cell_keys);
tt_int_op(retval, OP_EQ, 0);
memset(rendezvous_cookie, 2, sizeof(rendezvous_cookie));
service_circ->hs_ident =
create_rp_circuit_identifier(service, rendezvous_cookie,
&ephemeral_kp.pubkey,
&hs_ntor_rend_cell_keys);
}
/* Send out the RENDEZVOUS1 and make sure that our mock func worked */
tt_assert(tor_mem_is_zero(rend1_payload, 32));
hs_circ_service_rp_has_opened(service, service_circ);
tt_assert(!tor_mem_is_zero(rend1_payload, 32));
tt_int_op(rend1_payload_len, OP_EQ, HS_LEGACY_RENDEZVOUS_CELL_SIZE);
/******************************/
/** Now let's create the client rendezvous circuit */
client_circ =
helper_create_origin_circuit(CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED,
flags);
/* fix up its circ ident */
ed25519_pubkey_copy(&client_circ->hs_ident->intro_auth_pk,
&ip_auth_kp.pubkey);
memcpy(&client_circ->hs_ident->rendezvous_client_kp,
&client_kp, sizeof(client_circ->hs_ident->rendezvous_client_kp));
memcpy(&client_circ->hs_ident->intro_enc_pk.public_key,
&ip_enc_kp.pubkey.public_key,
sizeof(client_circ->hs_ident->intro_enc_pk.public_key));
/* Now parse the rendezvous2 circuit and make sure it was fine. We are
* skipping 20 bytes off its payload, since that's the rendezvous cookie
* which is only present in REND1. */
retval = handle_rendezvous2(client_circ,
(uint8_t*)rend1_payload+20,
rend1_payload_len-20);
tt_int_op(retval, OP_EQ, 0);
/* TODO: We are only simulating client/service here. We could also simulate
* the rendezvous point by plugging in rend_mid_establish_rendezvous(). We
* would need an extra circuit and some more stuff but it's doable. */
done:
circuit_free(TO_CIRCUIT(service_circ));
circuit_free(TO_CIRCUIT(client_circ));
hs_service_free(service);
hs_free_all();
UNMOCK(relay_send_command_from_edge_);
}
struct testcase_t hs_service_tests[] = { struct testcase_t hs_service_tests[] = {
{ "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK, { "e2e_rend_circuit_setup", test_e2e_rend_circuit_setup, TT_FORK,
NULL, NULL }, NULL, NULL },
@ -1395,6 +1522,8 @@ struct testcase_t hs_service_tests[] = {
NULL, NULL }, NULL, NULL },
{ "revision_counter_state", test_revision_counter_state, TT_FORK, { "revision_counter_state", test_revision_counter_state, TT_FORK,
NULL, NULL }, NULL, NULL },
{ "rendezvous1_parsing", test_rendezvous1_parsing, TT_FORK,
NULL, NULL },
END_OF_TESTCASES END_OF_TESTCASES
}; };