From b9010c8bf5f1231c51cd3c7b134ec8576a8f9de5 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 17:21:44 +0200 Subject: [PATCH 01/12] prop224 prepwork: Introduce HMAC-SHA3 function. --- src/common/crypto.c | 22 +++++++++++++++++++++ src/common/crypto.h | 3 +++ src/test/test_crypto.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/common/crypto.c b/src/common/crypto.c index fff516cc8e..e4ef52d510 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -2109,6 +2109,28 @@ crypto_hmac_sha256(char *hmac_out, tor_assert(rv); } +/** Compute an SHA3 MAC of msg using key as the key. The format + * used for our MAC is SHA3(k | m). Write the DIGEST256_LEN-byte result into + * mac_out of size mac_out_len. */ +void +crypto_mac_sha3_256(char *mac_out, size_t mac_out_len, + const char *key, size_t key_len, + const char *msg, size_t msg_len) +{ + crypto_digest_t *digest; + + tor_assert(mac_out); + tor_assert(key); + tor_assert(msg); + + digest = crypto_digest256_new(DIGEST_SHA3_256); + + crypto_digest_add_bytes(digest, key, key_len); + crypto_digest_add_bytes(digest, msg, msg_len); + crypto_digest_get_digest(digest, mac_out, mac_out_len); + crypto_digest_free(digest); +} + /** Internal state for a eXtendable-Output Function (XOF). */ struct crypto_xof_t { keccak_state s; diff --git a/src/common/crypto.h b/src/common/crypto.h index 116e0a62fd..32b6531456 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -255,6 +255,9 @@ void crypto_digest_assign(crypto_digest_t *into, void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len); +void crypto_mac_sha3_256(char *mac_out, size_t mac_out_len, + const char *key, size_t key_len, + const char *msg, size_t msg_len); crypto_xof_t *crypto_xof_new(void); void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len); void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len); diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 64a46f7914..91c55d8c3d 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1135,6 +1135,48 @@ test_crypto_sha3_xof(void *arg) tor_free(mem_op_hex_tmp); } +/* Test our MAC-SHA3 function. There are not actually any MAC-SHA3 test + * vectors out there for our H(len(k) || k || m) construction. Hence what we + * are gonna do is test our crypto_mac_sha3_256() function against manually + * doing H(len(k) || k||m). If in the future the Keccak group decides to + * standarize an MAC construction and make test vectors, we should + * incorporate them here. */ +static void +test_crypto_mac_sha3(void *arg) +{ + const char msg[] = "i am in a library somewhere using my computer"; + const char key[] = "i'm from the past talking to the future."; + + char hmac_test[DIGEST256_LEN]; + char hmac_manual[DIGEST256_LEN]; + + (void) arg; + + /* First let's use our nice HMAC-SHA3 function */ + crypto_mac_sha3_256(hmac_test, sizeof(hmac_test), + key, strlen(key), + msg, strlen(msg)); + + /* Now let's try a manual H(k || m) construction */ + { + char *key_msg_concat = NULL; + int result; + + tor_asprintf(&key_msg_concat, "%s%s", key, msg); + + result = crypto_digest256(hmac_manual, + key_msg_concat, strlen(key_msg_concat), + DIGEST_SHA3_256); + tt_int_op(result, ==, 0); + tor_free(key_msg_concat); + } + + /* Now compare the two results */ + tt_mem_op(hmac_test, OP_EQ, hmac_manual, DIGEST256_LEN); + + done: ; +} + /** Run unit tests for our public key crypto functions */ static void test_crypto_pk(void *arg) @@ -2918,6 +2960,7 @@ struct testcase_t crypto_tests[] = { { "digest_names", test_crypto_digest_names, 0, NULL, NULL }, { "sha3", test_crypto_sha3, TT_FORK, NULL, NULL}, { "sha3_xof", test_crypto_sha3_xof, TT_FORK, NULL, NULL}, + { "mac_sha3", test_crypto_mac_sha3, TT_FORK, NULL, NULL}, CRYPTO_LEGACY(dh), { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup, (void*)"aes" }, From b5b34e62f7fd86c242591dbbf852617a92bfc330 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Fri, 2 Sep 2016 10:42:34 +0200 Subject: [PATCH 02/12] prpo224 prepwork: Decouple legacy ESTABLISH_INTRO creation logic. This commit only moves code. --- src/or/rendservice.c | 64 +++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 0819d8a713..ecb1e276c3 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -2986,6 +2986,40 @@ count_intro_point_circuits(const rend_service_t *service) return num_ipos; } +static size_t +encode_establish_intro_cell_legacy(char *cell_body_out, crypto_pk_t *intro_key, + char *rend_circ_nonce) +{ +/* 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)) + + 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; +} + /** Called when we're done building a circuit to an introduction point: * sends a RELAY_ESTABLISH_INTRO cell. */ @@ -2993,9 +3027,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; @@ -3071,34 +3103,6 @@ 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)) - 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; - if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), RELAY_COMMAND_ESTABLISH_INTRO, buf, len, circuit->cpath->prev)<0) { From e17cc3f0a6283bf9aa04e845f23ccfb8b2db24c3 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 17:36:12 +0200 Subject: [PATCH 03/12] prop224 prepwork: Finish decoupling old ESTABLISH_INTRO creation logic. --- src/or/rendservice.c | 67 ++++++++++++++++++++++++++++++-------------- src/or/rendservice.h | 4 ++- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index ecb1e276c3..e483a498e4 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -2986,38 +2986,55 @@ count_intro_point_circuits(const rend_service_t *service) return num_ipos; } -static size_t +/* Given a buffer of at least RELAY_PAYLOAD_SIZE bytes in cell_body_out, + write the body of a legacy ESTABLISH_INTRO cell in it. Use intro_key + as the intro point auth key, and rend_circ_nonce as the circuit + crypto material. On success, fill cell_body_out 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) { -/* Use the intro key instead of the service key in ESTABLISH_INTRO. */ - crypto_pk_t *intro_key = circuit->intro_key; + 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, buf+2, + 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."); - reason = END_CIRC_REASON_INTERNAL; goto err; } len = r; - set_uint16(buf, htons((uint16_t)len)); + set_uint16(cell_body_out, htons((uint16_t)len)); len += 2; - memcpy(auth, circuit->cpath->prev->rend_circ_nonce, DIGEST_LEN); + memcpy(auth, rend_circ_nonce, DIGEST_LEN); memcpy(auth+DIGEST_LEN, "INTRODUCE", 9); - if (crypto_digest(buf+len, auth, DIGEST_LEN+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, buf+len, sizeof(buf)-len, - buf, len); + 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."); - reason = END_CIRC_REASON_INTERNAL; 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: @@ -3027,8 +3044,7 @@ void rend_service_intro_has_opened(origin_circuit_t *circuit) { rend_service_t *service; - int r; - char auth[DIGEST_LEN + 9]; + char buf[RELAY_PAYLOAD_SIZE]; char serviceid[REND_SERVICE_ID_LEN_BASE32+1]; int reason = END_CIRC_REASON_TORPROTOCOL; const char *rend_pk_digest; @@ -3103,13 +3119,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); - if (relay_send_command_from_edge(0, TO_CIRCUIT(circuit), - RELAY_COMMAND_ESTABLISH_INTRO, - buf, len, circuit->cpath->prev)<0) { - log_info(LD_GENERAL, + /* 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, "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 */ @@ -3121,7 +3148,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; @@ -4284,4 +4310,3 @@ rend_service_non_anonymous_mode_enabled(const or_options_t *options) tor_assert(rend_service_non_anonymous_mode_consistent(options)); return options->HiddenServiceNonAnonymousMode ? 1 : 0; } - diff --git a/src/or/rendservice.h b/src/or/rendservice.h index 630191e8b7..8fb3e8f97a 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -119,7 +119,9 @@ typedef struct rend_service_t { STATIC void rend_service_free(rend_service_t *service); STATIC char *rend_service_sos_poison_path(const rend_service_t *service); - +STATIC ssize_t encode_establish_intro_cell_legacy(char *cell_body_out, + crypto_pk_t *intro_key, + char *rend_circ_nonce); #endif int num_rend_services(void); From 2b9abbef2e5d0e58e5a15b7cf8cd03965aa70117 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 18:48:15 +0300 Subject: [PATCH 04/12] prop224 prepwork: Introduce HS circuitmap subsystem. The HS circuitmap is a hash table that maps introduction and rendezvous tokens to specific circuits such that given a token it's easy to find the corresponding circuit. It supports rend circuits and v2/v3 intro circuits. It will be used by the prop224 ESTABLISH_INTRO code to register and lookup v3 introduction circuits. The next commit after this removes the old code and fixes the unittests. Please consult both commits while reviewing functionality differences between the old and new code. Let me know if you want this rebased differently :) WRT architectural differences, this commit removes the rendinfo pointer from or_circuit_t. It then adds an hs_token_t pointer and a hashtable node for the HS circuitmap. IIUC, this adds another pointer to the weight of or_circuit_t. Let me know if you don't like this, or if you have suggestions on improving it. --- src/or/hs_circuitmap.c | 328 +++++++++++++++++++++++++++++++++++++++++ src/or/hs_circuitmap.h | 69 +++++++++ src/or/or.h | 8 +- 3 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/or/hs_circuitmap.c create mode 100644 src/or/hs_circuitmap.h diff --git a/src/or/hs_circuitmap.c b/src/or/hs_circuitmap.c new file mode 100644 index 0000000000..790c4d3b84 --- /dev/null +++ b/src/or/hs_circuitmap.c @@ -0,0 +1,328 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_circuitmap.c + * + * \brief Manage the hidden service circuitmap: A hash table that maps binary + * tokens to introduction and rendezvous circuits. + **/ + +#define HS_CIRCUITMAP_PRIVATE + +#include "or.h" +#include "config.h" +#include "circuitlist.h" +#include "hs_circuitmap.h" + +/************************** HS circuitmap code *******************************/ + +/* This is the hidden service circuitmap. It's a hash table that maps + introduction and rendezvous tokens to specific circuits such that given a + token it's easy to find the corresponding circuit. */ +static struct hs_circuitmap_ht *the_hs_circuitmap = NULL; + +/* This is a helper function used by the hash table code (HT_). It returns 1 if + * two circuits have the same HS token. */ +static int +hs_circuits_have_same_token(const or_circuit_t *first_circuit, + const or_circuit_t *second_circuit) +{ + const hs_token_t *first_token; + const hs_token_t *second_token; + + tor_assert(first_circuit); + tor_assert(second_circuit); + + first_token = first_circuit->hs_token; + second_token = second_circuit->hs_token; + + /* Both circs must have a token */ + if (BUG(!first_token) || BUG(!second_token)) { + return 0; + } + + if (first_token->type != second_token->type) { + return 0; + } + + if (first_token->token_len != second_token->token_len) + return 0; + + return tor_memeq(first_token->token, + second_token->token, + first_token->token_len); +} + +/* This is a helper function for the hash table code (HT_). It hashes a circuit + * HS token into an unsigned int for use as a key by the hash table routines.*/ +static inline unsigned int +hs_circuit_hash_token(const or_circuit_t *circuit) +{ + tor_assert(circuit->hs_token); + + return (unsigned) siphash24g(circuit->hs_token->token, + circuit->hs_token->token_len); +} + +/* Register the circuitmap hash table */ +HT_PROTOTYPE(hs_circuitmap_ht, // The name of the hashtable struct + or_circuit_t, // The name of the element struct, + hs_circuitmap_node, // The name of HT_ENTRY member + hs_circuit_hash_token, hs_circuits_have_same_token); + +HT_GENERATE2(hs_circuitmap_ht, or_circuit_t, hs_circuitmap_node, + hs_circuit_hash_token, hs_circuits_have_same_token, + 0.6, tor_reallocarray, tor_free_); + +#ifdef TOR_UNIT_TESTS + +/* Return the global HS circuitmap. Used by unittests. */ +hs_circuitmap_ht * +get_hs_circuitmap(void) +{ + return the_hs_circuitmap; +} + +#endif + +/****************** HS circuitmap utility functions **************************/ + +/** Return a new HS token of type type containing token. */ +static hs_token_t * +hs_token_new(hs_token_type_t type, size_t token_len, + const uint8_t *token) +{ + tor_assert(token); + + hs_token_t *hs_token = tor_malloc_zero(sizeof(hs_token_t)); + hs_token->type = type; + hs_token->token_len = token_len; + hs_token->token = tor_memdup(token, token_len); + + return hs_token; +} + +/** Free memory allocated by this hs_token. */ +static void +hs_token_free(hs_token_t *hs_token) +{ + if (!hs_token) { + return; + } + + tor_free(hs_token->token); + tor_free(hs_token); +} + +/** Return the circuit from the circuitmap with token search_token. */ +static or_circuit_t * +get_circuit_with_token(hs_token_t *search_token) +{ + tor_assert(the_hs_circuitmap); + + /* We use a dummy circuit object for the hash table search routine. */ + or_circuit_t search_circ; + search_circ.hs_token = search_token; + return HT_FIND(hs_circuitmap_ht, the_hs_circuitmap, &search_circ); +} + +/* Helper function that registers circ with token on the HS + circuitmap. This function steals reference of token. */ +static void +hs_circuitmap_register_impl(or_circuit_t *circ, hs_token_t *token) +{ + tor_assert(circ); + tor_assert(token); + tor_assert(the_hs_circuitmap); + + /* If this circuit already has a token, clear it. */ + if (circ->hs_token) { + hs_circuitmap_remove_circuit(circ); + } + + /* Kill old circuits with the same token. We want new intro/rend circuits to + take precedence over old ones, so that HSes and clients and reestablish + killed circuits without changing the HS token. */ + { + or_circuit_t *found_circ; + found_circ = get_circuit_with_token(token); + if (found_circ) { + hs_circuitmap_remove_circuit(found_circ); + if (!found_circ->base_.marked_for_close) { + circuit_mark_for_close(TO_CIRCUIT(found_circ), + END_CIRC_REASON_FINISHED); + } + } + } + + /* Register circuit and token to circuitmap. */ + circ->hs_token = token; + HT_INSERT(hs_circuitmap_ht, the_hs_circuitmap, circ); +} + +/** Helper function: Register circ of type on the HS + * circuitmap. Use the HS token as the key to the hash table. If + * token is not set, clear the circuit of any HS tokens. */ +static void +hs_circuitmap_register_circuit(or_circuit_t *circ, + hs_token_type_t type, size_t token_len, + const uint8_t *token) +{ + hs_token_t *hs_token = NULL; + + /* Create a new token and register it to the circuitmap */ + tor_assert(token); + hs_token = hs_token_new(type, token_len, token); + tor_assert(hs_token); + hs_circuitmap_register_impl(circ, hs_token); +} + +/* Query circuitmap for circuit with token of size token_len. + * Only returns a circuit with purpose equal to the wanted_circ_purpose + * parameter and if it is NOT marked for close. Return NULL if no such circuit + * is found. */ +static or_circuit_t * +hs_circuitmap_get_circuit(hs_token_type_t type, + size_t token_len, + const uint8_t *token, + uint8_t wanted_circ_purpose) +{ + or_circuit_t *found_circ = NULL; + + tor_assert(the_hs_circuitmap); + + /* Check the circuitmap if we have a circuit with this token */ + { + hs_token_t *search_hs_token = hs_token_new(type, token_len, token); + tor_assert(search_hs_token); + found_circ = get_circuit_with_token(search_hs_token); + hs_token_free(search_hs_token); + } + + /* Check that the circuit is useful to us */ + if (!found_circ || + found_circ->base_.purpose != wanted_circ_purpose || + found_circ->base_.marked_for_close) { + return NULL; + } + + return found_circ; +} + +/************** Public circuitmap API ****************************************/ + +/* Public function: Return v3 introduction circuit with auth_key. Return + * NULL if no such circuit is found in the circuitmap. */ +or_circuit_t * +hs_circuitmap_get_intro_circ_v3(const ed25519_public_key_t *auth_key) +{ + tor_assert(auth_key); + + return hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V3, + ED25519_PUBKEY_LEN, auth_key->pubkey, + CIRCUIT_PURPOSE_INTRO_POINT); +} + +/* Public function: Return v2 introduction circuit with digest. Return + * NULL if no such circuit is found in the circuitmap. */ +or_circuit_t * +hs_circuitmap_get_intro_circ_v2(const uint8_t *digest) +{ + tor_assert(digest); + + return hs_circuitmap_get_circuit(HS_TOKEN_INTRO_V2, + REND_TOKEN_LEN, digest, + CIRCUIT_PURPOSE_INTRO_POINT); +} + +/* Public function: Return rendezvous circuit with rendezvous + * cookie. Return NULL if no such circuit is found in the circuitmap. */ +or_circuit_t * +hs_circuitmap_get_rend_circ(const uint8_t *cookie) +{ + tor_assert(cookie); + + return hs_circuitmap_get_circuit(HS_TOKEN_REND, + REND_TOKEN_LEN, cookie, + CIRCUIT_PURPOSE_REND_POINT_WAITING); +} + +/* Public function: Register rendezvous circuit with key cookie to the + * circuitmap. */ +void +hs_circuitmap_register_rend_circ(or_circuit_t *circ, const uint8_t *cookie) +{ + hs_circuitmap_register_circuit(circ, + HS_TOKEN_REND, + REND_TOKEN_LEN, cookie); +} + +/* Public function: Register v2 intro circuit with key digest to the + * circuitmap. */ +void +hs_circuitmap_register_intro_circ_v2(or_circuit_t *circ, const uint8_t *digest) +{ + hs_circuitmap_register_circuit(circ, + HS_TOKEN_INTRO_V2, + REND_TOKEN_LEN, digest); +} + +/* Public function: Register v3 intro circuit with key auth_key to the + * circuitmap. */ +void +hs_circuitmap_register_intro_circ_v3(or_circuit_t *circ, + const ed25519_public_key_t *auth_key) +{ + hs_circuitmap_register_circuit(circ, + HS_TOKEN_INTRO_V3, + ED25519_PUBKEY_LEN, auth_key->pubkey); +} + +/** Remove this circuit from the HS circuitmap. Clear its HS token, and remove + * it from the hashtable. */ +void +hs_circuitmap_remove_circuit(or_circuit_t *circ) +{ + tor_assert(the_hs_circuitmap); + + if (!circ || !circ->hs_token) { + return; + } + + /* Remove circ from circuitmap */ + or_circuit_t *tmp; + tmp = HT_REMOVE(hs_circuitmap_ht, the_hs_circuitmap, circ); + /* ... and ensure the removal was successful. */ + if (tmp) { + tor_assert(tmp == circ); + } else { + log_warn(LD_BUG, "Could not find circuit (%u) in circuitmap.", + circ->p_circ_id); + } + + /* Clear token from circ */ + hs_token_free(circ->hs_token); + circ->hs_token = NULL; +} + +/* Initialize the global HS circuitmap. */ +void +hs_circuitmap_init(void) +{ + tor_assert(!the_hs_circuitmap); + + the_hs_circuitmap = tor_malloc_zero(sizeof(struct hs_circuitmap_ht)); + HT_INIT(hs_circuitmap_ht, the_hs_circuitmap); +} + +/* Free all memory allocated by the global HS circuitmap. */ +void +hs_circuitmap_free_all(void) +{ + tor_assert(the_hs_circuitmap); + + HT_CLEAR(hs_circuitmap_ht, the_hs_circuitmap); + tor_free(the_hs_circuitmap); +} + diff --git a/src/or/hs_circuitmap.h b/src/or/hs_circuitmap.h new file mode 100644 index 0000000000..a2be97c029 --- /dev/null +++ b/src/or/hs_circuitmap.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_circuitmap.h + * \brief Header file for hs_circuitmap.c. + **/ + +#ifndef TOR_HS_CIRCUITMAP_H +#define TOR_HS_CIRCUITMAP_H + +typedef HT_HEAD(hs_circuitmap_ht, or_circuit_t) hs_circuitmap_ht; + +typedef struct hs_token_s hs_token_t; +typedef struct or_circuit_t or_circuit_t; + +/** Public HS circuitmap API: */ + +or_circuit_t *hs_circuitmap_get_rend_circ(const uint8_t *cookie); +or_circuit_t * +hs_circuitmap_get_intro_circ_v3(const ed25519_public_key_t *auth_key); +or_circuit_t *hs_circuitmap_get_intro_circ_v2(const uint8_t *digest); + +void hs_circuitmap_register_rend_circ(or_circuit_t *circ, + const uint8_t *cookie); +void hs_circuitmap_register_intro_circ_v2(or_circuit_t *circ, + const uint8_t *digest); +void hs_circuitmap_register_intro_circ_v3(or_circuit_t *circ, + const ed25519_public_key_t *auth_key); + +void hs_circuitmap_remove_circuit(or_circuit_t *circ); + +void hs_circuitmap_init(void); +void hs_circuitmap_free_all(void); + +#ifdef HS_CIRCUITMAP_PRIVATE + +/** Represents the type of HS token. */ +typedef enum { + /** A rendezvous cookie (128bit)*/ + HS_TOKEN_REND, + /** A v2 introduction point pubkey (160bit) */ + HS_TOKEN_INTRO_V2, + /** A v3 introduction point pubkey (256bit) */ + HS_TOKEN_INTRO_V3, +} hs_token_type_t; + +/** Represents a token used in the HS protocol. Each such token maps to a + * specific introduction or rendezvous circuit. */ +struct hs_token_s { + /* Type of HS token. */ + hs_token_type_t type; + + /* The size of the token (depends on the type). */ + size_t token_len; + + /* The token itself. Memory allocated at runtime. */ + uint8_t *token; +}; + +#endif /* HS_CIRCUITMAP_PRIVATE */ + +#ifdef TOR_UNIT_TESTS + +hs_circuitmap_ht *get_hs_circuitmap(void); + +#endif /* TOR_UNIT_TESTS */ + +#endif /* TOR_HS_CIRCUITMAP_H */ diff --git a/src/or/or.h b/src/or/or.h index eb94f63d5e..9581c6da7a 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -80,6 +80,7 @@ #include "crypto_ed25519.h" #include "tor_queue.h" #include "util_format.h" +#include "hs_circuitmap.h" /* These signals are defined to help handle_control_signal work. */ @@ -3352,7 +3353,12 @@ typedef struct or_circuit_t { * is not marked for close. */ struct or_circuit_t *rend_splice; - struct or_circuit_rendinfo_s *rendinfo; + /** If set, points to an HS token that this circuit might be carrying. + * Used by the HS circuitmap. */ + hs_token_t *hs_token; + /** Hashtable node: used to look up the circuit by its HS token using the HS + circuitmap. */ + HT_ENTRY(or_circuit_t) hs_circuitmap_node; /** Stores KH for the handshake. */ char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ From 9192e5928c0b974ba7c1b908b6f2538cd6f56c79 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 18:54:59 +0300 Subject: [PATCH 05/12] prop224 prepwork: Use of HS circuitmap in existing HS code. The new HS circuitmap API replaces old public functions as follows: circuit_clear_rend_token -> hs_circuitmap_remove_circuit circuit_get_rendezvous -> hs_circuitmap_get_rend_circ circuit_get_intro_point -> hs_circuitmap_get_intro_circ_v2 circuit_set_rendezvous_cookie -> hs_circuitmap_register_rend_circ circuit_set_intro_point_digest -> hs_circuitmap_register_intro_circ_v2 This commit also removes the old rendinfo code that is now unused. It also fixes the broken rendinfo unittests. --- src/or/circuitlist.c | 179 +----------------------------------- src/or/circuitlist.h | 4 - src/or/main.c | 5 + src/or/or.h | 14 --- src/or/rendmid.c | 14 +-- src/test/test_circuitlist.c | 63 +++++++------ 6 files changed, 50 insertions(+), 229 deletions(-) diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index dee103e36a..b7ae3f5f48 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -63,6 +63,7 @@ #include "connection_edge.h" #include "connection_or.h" #include "control.h" +#include "hs_circuitmap.h" #include "main.h" #include "hs_common.h" #include "networkstatus.h" @@ -93,9 +94,6 @@ static smartlist_t *circuits_pending_close = NULL; static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); -//static void circuit_set_rend_token(or_circuit_t *circ, int is_rend_circ, -// const uint8_t *token); -static void circuit_clear_rend_token(or_circuit_t *circ); static void circuit_about_to_free_atexit(circuit_t *circ); static void circuit_about_to_free(circuit_t *circ); @@ -866,7 +864,9 @@ circuit_free(circuit_t *circ) crypto_cipher_free(ocirc->n_crypto); crypto_digest_free(ocirc->n_digest); - circuit_clear_rend_token(ocirc); + if (ocirc->hs_token) { + hs_circuitmap_remove_circuit(ocirc); + } if (ocirc->rend_splice) { or_circuit_t *other = ocirc->rend_splice; @@ -1409,177 +1409,6 @@ circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, return NULL; } -/** Map from rendezvous cookie to or_circuit_t */ -static digestmap_t *rend_cookie_map = NULL; - -/** Map from introduction point digest to or_circuit_t */ -static digestmap_t *intro_digest_map = NULL; - -/** Return the OR circuit whose purpose is purpose, and whose - * rend_token is the REND_TOKEN_LEN-byte token. If is_rend_circ, - * look for rendezvous point circuits; otherwise look for introduction point - * circuits. */ -static or_circuit_t * -circuit_get_by_rend_token_and_purpose(uint8_t purpose, int is_rend_circ, - const char *token) -{ - or_circuit_t *circ; - digestmap_t *map = is_rend_circ ? rend_cookie_map : intro_digest_map; - - if (!map) - return NULL; - - circ = digestmap_get(map, token); - if (!circ || - circ->base_.purpose != purpose || - circ->base_.marked_for_close) - return NULL; - - if (!circ->rendinfo) { - char *t = tor_strdup(hex_str(token, REND_TOKEN_LEN)); - log_warn(LD_BUG, "Wanted a circuit with %s:%d, but lookup returned a " - "circuit with no rendinfo set.", - safe_str(t), is_rend_circ); - tor_free(t); - return NULL; - } - - if (! bool_eq(circ->rendinfo->is_rend_circ, is_rend_circ) || - tor_memneq(circ->rendinfo->rend_token, token, REND_TOKEN_LEN)) { - char *t = tor_strdup(hex_str(token, REND_TOKEN_LEN)); - log_warn(LD_BUG, "Wanted a circuit with %s:%d, but lookup returned %s:%d", - safe_str(t), is_rend_circ, - safe_str(hex_str(circ->rendinfo->rend_token, REND_TOKEN_LEN)), - (int)circ->rendinfo->is_rend_circ); - tor_free(t); - return NULL; - } - - return circ; -} - -/** Clear the rendezvous cookie or introduction point key digest that's - * configured on circ, if any, and remove it from any such maps. */ -static void -circuit_clear_rend_token(or_circuit_t *circ) -{ - or_circuit_t *found_circ; - digestmap_t *map; - - if (!circ || !circ->rendinfo) - return; - - map = circ->rendinfo->is_rend_circ ? rend_cookie_map : intro_digest_map; - - if (!map) { - log_warn(LD_BUG, "Tried to clear rend token on circuit, but found no map"); - return; - } - - found_circ = digestmap_get(map, circ->rendinfo->rend_token); - if (found_circ == circ) { - /* Great, this is the right one. */ - digestmap_remove(map, circ->rendinfo->rend_token); - } else if (found_circ) { - log_warn(LD_BUG, "Tried to clear rend token on circuit, but " - "it was already replaced in the map."); - } else { - log_warn(LD_BUG, "Tried to clear rend token on circuit, but " - "it not in the map at all."); - } - - tor_free(circ->rendinfo); /* Sets it to NULL too */ -} - -/** Set the rendezvous cookie (if is_rend_circ), or the introduction point - * digest (if ! is_rend_circ) of circ to the REND_TOKEN_LEN-byte value - * in token, and add it to the appropriate map. If it previously had a - * token, clear it. If another circuit previously had the same - * cookie/intro-digest, mark that circuit and remove it from the map. */ -static void -circuit_set_rend_token(or_circuit_t *circ, int is_rend_circ, - const uint8_t *token) -{ - digestmap_t **map_p, *map; - or_circuit_t *found_circ; - - /* Find the right map, creating it as needed */ - map_p = is_rend_circ ? &rend_cookie_map : &intro_digest_map; - - if (!*map_p) - *map_p = digestmap_new(); - - map = *map_p; - - /* If this circuit already has a token, we need to remove that. */ - if (circ->rendinfo) - circuit_clear_rend_token(circ); - - if (token == NULL) { - /* We were only trying to remove this token, not set a new one. */ - return; - } - - found_circ = digestmap_get(map, (const char *)token); - if (found_circ) { - tor_assert(found_circ != circ); - circuit_clear_rend_token(found_circ); - if (! found_circ->base_.marked_for_close) { - circuit_mark_for_close(TO_CIRCUIT(found_circ), END_CIRC_REASON_FINISHED); - if (is_rend_circ) { - log_fn(LOG_PROTOCOL_WARN, LD_REND, - "Duplicate rendezvous cookie (%s...) used on two circuits", - hex_str((const char*)token, 4)); /* only log first 4 chars */ - } - } - } - - /* Now set up the rendinfo */ - circ->rendinfo = tor_malloc(sizeof(*circ->rendinfo)); - memcpy(circ->rendinfo->rend_token, token, REND_TOKEN_LEN); - circ->rendinfo->is_rend_circ = is_rend_circ ? 1 : 0; - - digestmap_set(map, (const char *)token, circ); -} - -/** Return the circuit waiting for a rendezvous with the provided cookie. - * Return NULL if no such circuit is found. - */ -or_circuit_t * -circuit_get_rendezvous(const uint8_t *cookie) -{ - return circuit_get_by_rend_token_and_purpose( - CIRCUIT_PURPOSE_REND_POINT_WAITING, - 1, (const char*)cookie); -} - -/** Return the circuit waiting for intro cells of the given digest. - * Return NULL if no such circuit is found. - */ -or_circuit_t * -circuit_get_intro_point(const uint8_t *digest) -{ - return circuit_get_by_rend_token_and_purpose( - CIRCUIT_PURPOSE_INTRO_POINT, 0, - (const char *)digest); -} - -/** Set the rendezvous cookie of circ to cookie. If another - * circuit previously had that cookie, mark it. */ -void -circuit_set_rendezvous_cookie(or_circuit_t *circ, const uint8_t *cookie) -{ - circuit_set_rend_token(circ, 1, cookie); -} - -/** Set the intro point key digest of circ to cookie. If another - * circuit previously had that intro point digest, mark it. */ -void -circuit_set_intro_point_digest(or_circuit_t *circ, const uint8_t *digest) -{ - circuit_set_rend_token(circ, 0, digest); -} - /** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, * has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* * flags in flags, and if info is defined, does not already use info diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h index 989c02afd5..b38b6d1afa 100644 --- a/src/or/circuitlist.h +++ b/src/or/circuitlist.h @@ -46,10 +46,6 @@ origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( const rend_data_t *rend_data); origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, const uint8_t *digest, uint8_t purpose); -or_circuit_t *circuit_get_rendezvous(const uint8_t *cookie); -or_circuit_t *circuit_get_intro_point(const uint8_t *digest); -void circuit_set_rendezvous_cookie(or_circuit_t *circ, const uint8_t *cookie); -void circuit_set_intro_point_digest(or_circuit_t *circ, const uint8_t *digest); origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); diff --git a/src/or/main.c b/src/or/main.c index c10f62724a..ff477dba5b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -74,6 +74,7 @@ #include "geoip.h" #include "hibernate.h" #include "hs_cache.h" +#include "hs_circuitmap.h" #include "keypin.h" #include "main.h" #include "microdesc.h" @@ -2400,6 +2401,9 @@ do_main_loop(void) } } + /* Initialize relay-side HS circuitmap */ + hs_circuitmap_init(); + /* set up once-a-second callback. */ if (! second_timer) { struct timeval one_second; @@ -3108,6 +3112,7 @@ tor_free_all(int postfork) connection_edge_free_all(); scheduler_free_all(); nodelist_free_all(); + hs_circuitmap_free_all(); microdesc_free_all(); routerparse_free_all(); ext_orport_free_all(); diff --git a/src/or/or.h b/src/or/or.h index 9581c6da7a..10cfc76856 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3393,25 +3393,11 @@ typedef struct or_circuit_t { uint32_t max_middle_cells; } or_circuit_t; -typedef struct or_circuit_rendinfo_s { - #if REND_COOKIE_LEN != DIGEST_LEN #error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN" #endif #define REND_TOKEN_LEN DIGEST_LEN - /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a - * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes - * otherwise. - */ - char rend_token[REND_TOKEN_LEN]; - - /** True if this is a rendezvous point circuit; false if this is an - * introduction point. */ - unsigned is_rend_circ; - -} or_circuit_rendinfo_t; - /** Convert a circuit subtype to a circuit_t. */ #define TO_CIRCUIT(x) (&((x)->base_)) diff --git a/src/or/rendmid.c b/src/or/rendmid.c index f39c92afae..6b44aa14ea 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -94,7 +94,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, /* Close any other intro circuits with the same pk. */ c = NULL; - while ((c = circuit_get_intro_point((const uint8_t *)pk_digest))) { + while ((c = hs_circuitmap_get_intro_circ_v2((const uint8_t *)pk_digest))) { log_info(LD_REND, "Replacing old circuit for service %s", safe_str(serviceid)); circuit_mark_for_close(TO_CIRCUIT(c), END_CIRC_REASON_FINISHED); @@ -111,7 +111,7 @@ rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, /* Now, set up this circuit. */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); - circuit_set_intro_point_digest(circ, (uint8_t *)pk_digest); + hs_circuitmap_register_intro_circ_v2(circ, (uint8_t *)pk_digest); log_info(LD_REND, "Established introduction point on circuit %u for service %s", @@ -181,7 +181,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, /* The first 20 bytes are all we look at: they have a hash of the service's * PK. */ - intro_circ = circuit_get_intro_point((const uint8_t*)request); + intro_circ = hs_circuitmap_get_intro_circ_v2((const uint8_t*)request); if (!intro_circ) { log_info(LD_REND, "No intro circ found for INTRODUCE1 cell (%s) from circuit %u; " @@ -258,7 +258,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, goto err; } - if (circuit_get_rendezvous(request)) { + if (hs_circuitmap_get_rend_circ(request)) { log_warn(LD_PROTOCOL, "Duplicate rendezvous cookie in ESTABLISH_RENDEZVOUS."); goto err; @@ -274,7 +274,7 @@ rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, } circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_POINT_WAITING); - circuit_set_rendezvous_cookie(circ, request); + hs_circuitmap_register_rend_circ(circ, request); base16_encode(hexid,9,(char*)request,4); @@ -323,7 +323,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, "Got request for rendezvous from circuit %u to cookie %s.", (unsigned)circ->p_circ_id, hexid); - rend_circ = circuit_get_rendezvous(request); + rend_circ = hs_circuitmap_get_rend_circ(request); if (!rend_circ) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Rejecting RENDEZVOUS1 cell with unrecognized rendezvous cookie %s.", @@ -358,7 +358,7 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); circuit_change_purpose(TO_CIRCUIT(rend_circ), CIRCUIT_PURPOSE_REND_ESTABLISHED); - circuit_set_rendezvous_cookie(circ, NULL); + hs_circuitmap_remove_circuit(circ); rend_circ->rend_splice = circ; circ->rend_splice = rend_circ; diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index e996c42115..7eed5fe225 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -4,10 +4,12 @@ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITBUILD_PRIVATE #define CIRCUITLIST_PRIVATE +#define HS_CIRCUITMAP_PRIVATE #include "or.h" #include "channel.h" #include "circuitbuild.h" #include "circuitlist.h" +#include "hs_circuitmap.h" #include "test.h" #include "log_test_helpers.h" @@ -185,6 +187,9 @@ test_rend_token_maps(void *arg) (void)arg; (void)tok1; //xxxx + + hs_circuitmap_init(); + c1 = or_circuit_new(0, NULL); c2 = or_circuit_new(0, NULL); c3 = or_circuit_new(0, NULL); @@ -196,68 +201,68 @@ test_rend_token_maps(void *arg) tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.'); /* No maps; nothing there. */ - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); - circuit_set_rendezvous_cookie(c1, tok1); - circuit_set_intro_point_digest(c2, tok2); + hs_circuitmap_register_rend_circ(c1, tok1); + hs_circuitmap_register_intro_circ_v2(c2, tok2); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok3)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3)); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok1)); /* Without purpose set, we don't get the circuits */ - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; /* Okay, make sure they show up now. */ - tt_ptr_op(c1, OP_EQ, circuit_get_rendezvous(tok1)); - tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); /* Two items at the same place with the same token. */ c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING; - circuit_set_rendezvous_cookie(c3, tok2); - tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2)); - tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2)); + hs_circuitmap_register_rend_circ(c3, tok2); + tt_ptr_op(c2, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); /* Marking a circuit makes it not get returned any more */ circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok1)); circuit_free(TO_CIRCUIT(c1)); c1 = NULL; /* Freeing a circuit makes it not get returned any more. */ circuit_free(TO_CIRCUIT(c2)); c2 = NULL; - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok2)); /* c3 -- are you still there? */ - tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); /* Change its cookie. This never happens in Tor per se, but hey. */ c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - circuit_set_intro_point_digest(c3, tok3); + hs_circuitmap_register_intro_circ_v2(c3, tok3); - tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2)); - tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(tok3)); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ(tok2)); + tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); /* Now replace c3 with c4. */ c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT; - circuit_set_intro_point_digest(c4, tok3); + hs_circuitmap_register_intro_circ_v2(c4, tok3); - tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3)); + tt_ptr_op(c4, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); - tt_ptr_op(c3->rendinfo, OP_EQ, NULL); - tt_ptr_op(c4->rendinfo, OP_NE, NULL); - tt_mem_op(c4->rendinfo, OP_EQ, tok3, REND_TOKEN_LEN); + tt_ptr_op(c3->hs_token, OP_EQ, NULL); + tt_ptr_op(c4->hs_token, OP_NE, NULL); + tt_mem_op(c4->hs_token->token, OP_EQ, tok3, REND_TOKEN_LEN); /* Now clear c4's cookie. */ - circuit_set_intro_point_digest(c4, NULL); - tt_ptr_op(c4->rendinfo, OP_EQ, NULL); - tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3)); + hs_circuitmap_remove_circuit(c4); + tt_ptr_op(c4->hs_token, OP_EQ, NULL); + tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_intro_circ_v2(tok3)); done: if (c1) From c4c90d56b543887ee9bee6553725151b09891d8e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 18:58:19 +0300 Subject: [PATCH 06/12] prop224: Add code that generates ESTABLISH_INTRO cells. Currently unused. It will only be used for creating ESTABLISH_INTRO cells in unittests :) --- src/or/hs_common.h | 7 +- src/or/hs_service.c | 175 ++++++++++++++++++++++++++++++++++++++++++++ src/or/hs_service.h | 31 ++++++++ 3 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src/or/hs_service.c create mode 100644 src/or/hs_service.h diff --git a/src/or/hs_common.h b/src/or/hs_common.h index 2502f35ad4..55710b7f79 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -17,6 +17,12 @@ /* Version 3 of the protocol (prop224). */ #define HS_VERSION_THREE 3 +/* Denotes ed25519 authentication key on ESTABLISH_INTRO cell. */ +#define AUTH_KEY_ED25519 0x02 + +/* String prefix for the signature of ESTABLISH_INTRO */ +#define ESTABLISH_INTRO_SIG_PREFIX "Tor establish-intro cell v1" + void rend_data_free(rend_data_t *data); rend_data_t *rend_data_dup(const rend_data_t *data); rend_data_t *rend_data_client_create(const char *onion_address, @@ -36,4 +42,3 @@ const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data, int hs_v3_protocol_is_enabled(void); #endif /* TOR_HS_COMMON_H */ - diff --git a/src/or/hs_service.c b/src/or/hs_service.c new file mode 100644 index 0000000000..69f83cfaa1 --- /dev/null +++ b/src/or/hs_service.c @@ -0,0 +1,175 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_service.c + * \brief Implement next generation hidden service functionality + **/ + +#define HS_SERVICE_PRIVATE + +#include "or.h" +#include "relay.h" +#include "rendservice.h" +#include "circuitlist.h" +#include "circpathbias.h" + +#include "hs_service.h" +#include "hs_common.h" + +#include "hs/cell_establish_intro.h" +#include "hs/cell_common.h" + +/* XXX We don't currently use these functions, apart from generating unittest + data. When we start implementing the service-side support for prop224 we + should revisit these functions and use them. For now we mark them as + unittest-only code: */ +#ifdef TOR_UNIT_TESTS + +/** Given an ESTABLISH_INTRO cell, encode it and place its payload in + * buf_out which has size buf_out_len. Return the number of + * bytes written, or a negative integer if there was an error. */ +STATIC ssize_t +get_establish_intro_payload(uint8_t *buf_out, size_t buf_out_len, + const hs_cell_establish_intro_t *cell) +{ + ssize_t bytes_used = 0; + + if (buf_out_len < RELAY_PAYLOAD_SIZE) { + return -1; + } + + bytes_used = hs_cell_establish_intro_encode(buf_out, buf_out_len, + cell); + return bytes_used; +} + +/* Set the cell extensions of cell. */ +static void +set_cell_extensions(hs_cell_establish_intro_t *cell) +{ + cell_extension_t *cell_extensions = cell_extension_new(); + + /* For now, we don't use extensions at all. */ + cell_extensions->num = 0; /* It's already zeroed, but be explicit. */ + hs_cell_establish_intro_set_extensions(cell, cell_extensions); +} + +/** Given the circuit handshake info in circuit_key_material, create and + * return an ESTABLISH_INTRO cell. Return NULL if something went wrong. The + * returned cell is allocated on the heap and it's the responsibility of the + * caller to free it. */ +STATIC hs_cell_establish_intro_t * +generate_establish_intro_cell(const char *circuit_key_material, + size_t circuit_key_material_len) +{ + hs_cell_establish_intro_t *cell = NULL; + ssize_t encoded_len; + + log_warn(LD_GENERAL, + "Generating ESTABLISH_INTRO cell (key_material_len: %u)", + (unsigned) circuit_key_material_len); + + /* Generate short-term keypair for use in ESTABLISH_INTRO */ + ed25519_keypair_t key_struct; + if (ed25519_keypair_generate(&key_struct, 0) < 0) { + goto err; + } + + cell = hs_cell_establish_intro_new(); + + /* Set AUTH_KEY_TYPE: 2 means ed25519 */ + hs_cell_establish_intro_set_auth_key_type(cell, AUTH_KEY_ED25519); + + /* Set AUTH_KEY_LEN field */ + /* Must also set byte-length of AUTH_KEY to match */ + int auth_key_len = ED25519_PUBKEY_LEN; + hs_cell_establish_intro_set_auth_key_len(cell, auth_key_len); + hs_cell_establish_intro_setlen_auth_key(cell, auth_key_len); + + /* Set AUTH_KEY field */ + uint8_t *auth_key_ptr = hs_cell_establish_intro_getarray_auth_key(cell); + memcpy(auth_key_ptr, key_struct.pubkey.pubkey, auth_key_len); + + /* No cell extensions needed */ + set_cell_extensions(cell); + + /* Set signature size. + We need to do this up here, because _encode() needs it and we need to call + _encode() to calculate the MAC and signature. + */ + int sig_len = ED25519_SIG_LEN; + hs_cell_establish_intro_set_sig_len(cell, sig_len); + hs_cell_establish_intro_setlen_sig(cell, sig_len); + + /* XXX How to make this process easier and nicer? */ + + /* Calculate the cell MAC (aka HANDSHAKE_AUTH). */ + { + /* To calculate HANDSHAKE_AUTH, we dump the cell in bytes, and then derive + the MAC from it. */ + uint8_t cell_bytes_tmp[RELAY_PAYLOAD_SIZE] = {0}; + char mac[TRUNNEL_SHA3_256_LEN]; + + encoded_len = hs_cell_establish_intro_encode(cell_bytes_tmp, + sizeof(cell_bytes_tmp), + cell); + if (encoded_len < 0) { + log_warn(LD_OR, "Unable to pre-encode ESTABLISH_INTRO cell."); + goto err; + } + + /* sanity check */ + tor_assert(encoded_len > ED25519_SIG_LEN + 2 + TRUNNEL_SHA3_256_LEN); + + /* Calculate MAC of all fields before HANDSHAKE_AUTH */ + crypto_mac_sha3_256(mac, sizeof(mac), + circuit_key_material, circuit_key_material_len, + (const char*)cell_bytes_tmp, + encoded_len - (ED25519_SIG_LEN + 2 + TRUNNEL_SHA3_256_LEN)); + /* Write the MAC to the cell */ + uint8_t *handshake_ptr = + hs_cell_establish_intro_getarray_handshake_mac(cell); + memcpy(handshake_ptr, mac, sizeof(mac)); + } + + /* Calculate the cell signature */ + { + /* To calculate the sig we follow the same procedure as above. We first + dump the cell up to the sig, and then calculate the sig */ + uint8_t cell_bytes_tmp[RELAY_PAYLOAD_SIZE] = {0}; + ed25519_signature_t sig; + + encoded_len = hs_cell_establish_intro_encode(cell_bytes_tmp, + sizeof(cell_bytes_tmp), + cell); + if (encoded_len < 0) { + log_warn(LD_OR, "Unable to pre-encode ESTABLISH_INTRO cell (2)."); + goto err; + } + + tor_assert(encoded_len > ED25519_SIG_LEN); + + if (ed25519_sign_prefixed(&sig, + (uint8_t*) cell_bytes_tmp, + encoded_len - ED25519_SIG_LEN, + ESTABLISH_INTRO_SIG_PREFIX, + &key_struct)) { + log_warn(LD_BUG, "Unable to gen signature for ESTABLISH_INTRO cell."); + goto err; + } + + /* And write the signature to the cell */ + uint8_t *sig_ptr = hs_cell_establish_intro_getarray_sig(cell); + memcpy(sig_ptr, sig.sig, sig_len); + } + + /* We are done! Return the cell! */ + return cell; + + err: + hs_cell_establish_intro_free(cell); + return NULL; +} + +#endif /* TOR_UNIT_TESTS */ diff --git a/src/or/hs_service.h b/src/or/hs_service.h new file mode 100644 index 0000000000..4a7600767e --- /dev/null +++ b/src/or/hs_service.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_service.h + * \brief Header file for hs_service.c. + **/ + +#ifndef TOR_HS_SERVICE_H +#define TOR_HS_SERVICE_H + +#include "or.h" +#include "hs/cell_establish_intro.h" + +#ifdef HS_SERVICE_PRIVATE + +#ifdef TOR_UNIT_TESTS + +STATIC hs_cell_establish_intro_t * +generate_establish_intro_cell(const char *circuit_key_material, + size_t circuit_key_material_len); + +STATIC ssize_t +get_establish_intro_payload(uint8_t *buf, size_t buf_len, + const hs_cell_establish_intro_t *cell); + +#endif /* TOR_UNIT_TESTS */ + +#endif /* HS_SERVICE_PRIVATE */ + +#endif /* TOR_HS_SERVICE_H */ From d7be1fd5197ad984d45c1d9a0a033a2b95a9fd9e Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 2 Nov 2016 11:37:50 -0400 Subject: [PATCH 07/12] prop224: Introduce the new introduction point code. (pun not intended) Now our code supports both legacy and prop224 ESTABLISH_INTRO cells :) hs_intro_received_establish_intro() is the new entry point. --- src/or/hs_intropoint.c | 279 +++++++++++++++++++++++++++++++++++++++++ src/or/hs_intropoint.h | 40 ++++++ src/or/include.am | 6 + src/or/rendcommon.c | 3 +- src/or/rendmid.c | 7 +- src/or/rendmid.h | 4 +- 6 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 src/or/hs_intropoint.c create mode 100644 src/or/hs_intropoint.h diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c new file mode 100644 index 0000000000..fb8637b14e --- /dev/null +++ b/src/or/hs_intropoint.c @@ -0,0 +1,279 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_intropoint.c + * \brief Implement next generation introductions point functionality + **/ + +#define HS_INTROPOINT_PRIVATE + +#include "or.h" +#include "circuitlist.h" +#include "circuituse.h" +#include "relay.h" +#include "rendmid.h" +#include "rephist.h" + +#include "hs/cell_establish_intro.h" +#include "hs/cell_common.h" +#include "hs_circuitmap.h" +#include "hs_intropoint.h" +#include "hs_common.h" + +/** Extract the authentication key from an ESTABLISH_INTRO cell and + * place it in auth_key_out. */ +STATIC void +get_auth_key_from_establish_intro_cell(ed25519_public_key_t *auth_key_out, + const hs_cell_establish_intro_t *cell) +{ + tor_assert(auth_key_out); + + const uint8_t *key_array = + hs_cell_establish_intro_getconstarray_auth_key(cell); + tor_assert(key_array); + tor_assert(hs_cell_establish_intro_getlen_auth_key(cell) == + sizeof(auth_key_out->pubkey)); + + memcpy(auth_key_out->pubkey, key_array, cell->auth_key_len); +} + +/** We received an ESTABLISH_INTRO cell. Verify its signature and MAC, + * given circuit_key_material. Return 0 on success else -1 on error. */ +STATIC int +verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, + const char *circuit_key_material, + size_t circuit_key_material_len) +{ + /* We only reach this function if the first byte of the cell is 0x02 which + * means that auth_key_type is AUTH_KEY_ED25519, hence this check should + * always pass. See hs_intro_received_establish_intro(). */ + if (BUG(cell->auth_key_type != AUTH_KEY_ED25519)) { + return -1; + } + + /* Make sure the auth key length is of the right size for this type. For + * EXTRA safety, we check both the size of the array and the length which + * must be the same. Safety first!*/ + if (hs_cell_establish_intro_getlen_auth_key(cell) != ED25519_PUBKEY_LEN || + hs_cell_establish_intro_get_auth_key_len(cell) != ED25519_PUBKEY_LEN) { + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "ESTABLISH_INTRO auth key length is invalid"); + return -1; + } + + const char *msg = (char*) cell->start_cell; + + /* Verify the sig */ + { + ed25519_signature_t sig_struct; + const uint8_t *sig_array = hs_cell_establish_intro_getconstarray_sig(cell); + + if (hs_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig)) { + log_warn(LD_PROTOCOL, "ESTABLISH_INTRO sig len is invalid"); + return -1; + } + /* We are now sure that sig_len is of the right size. */ + memcpy(sig_struct.sig, sig_array, cell->sig_len); + + ed25519_public_key_t auth_key; + get_auth_key_from_establish_intro_cell(&auth_key, cell); + + const size_t sig_msg_len = (char*) (cell->end_sig_fields) - msg; + int sig_mismatch = ed25519_checksig_prefixed(&sig_struct, + (uint8_t*) msg, sig_msg_len, + ESTABLISH_INTRO_SIG_PREFIX, + &auth_key); + if (sig_mismatch) { + log_warn(LD_PROTOCOL, "ESTABLISH_INTRO signature not as expected"); + return -1; + } + } + + /* Verify the MAC */ + { + const size_t auth_msg_len = (char*) (cell->end_mac_fields) - msg; + char mac[DIGEST256_LEN]; + crypto_mac_sha3_256(mac, sizeof(mac), + circuit_key_material, circuit_key_material_len, + msg, auth_msg_len); + if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) { + log_warn(LD_PROTOCOL, "ESTABLISH_INTRO handshake_auth not as expected"); + return -1; + } + } + + return 0; +} + +/* Send an INTRO_ESTABLISHED cell to circ. */ +MOCK_IMPL(int, +hs_intro_send_intro_established_cell,(or_circuit_t *circ)) +{ + int ret; + uint8_t *encoded_cell = NULL; + ssize_t encoded_len, result_len; + hs_cell_intro_established_t *cell; + cell_extension_t *ext; + + tor_assert(circ); + + /* Build the cell payload. */ + cell = hs_cell_intro_established_new(); + ext = cell_extension_new(); + cell_extension_set_num(ext, 0); + hs_cell_intro_established_set_extensions(cell, ext); + /* Encode the cell to binary format. */ + encoded_len = hs_cell_intro_established_encoded_len(cell); + tor_assert(encoded_len > 0); + encoded_cell = tor_malloc_zero(encoded_len); + result_len = hs_cell_intro_established_encode(encoded_cell, encoded_len, + cell); + tor_assert(encoded_len == result_len); + + ret = relay_send_command_from_edge(0, TO_CIRCUIT(circ), + RELAY_COMMAND_INTRO_ESTABLISHED, + (char *) encoded_cell, encoded_len, + NULL); + /* On failure, the above function will close the circuit. */ + hs_cell_intro_established_free(cell); + tor_free(encoded_cell); + return ret; +} + +/** We received an ESTABLISH_INTRO parsed_cell on circ. It's + * well-formed and passed our verifications. Perform appropriate actions to + * establish an intro point. */ +static int +handle_verified_establish_intro_cell(or_circuit_t *circ, + const hs_cell_establish_intro_t *parsed_cell) +{ + /* Get the auth key of this intro point */ + ed25519_public_key_t auth_key; + get_auth_key_from_establish_intro_cell(&auth_key, parsed_cell); + + /* Then notify the hidden service that the intro point is established by + sending an INTRO_ESTABLISHED cell */ + if (hs_intro_send_intro_established_cell(circ)) { + log_warn(LD_BUG, "Couldn't send INTRO_ESTABLISHED cell."); + return -1; + } + + /* Associate intro point auth key with this circuit. */ + hs_circuitmap_register_intro_circ_v3(circ, &auth_key); + /* Repurpose this circuit into an intro circuit. */ + circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_INTRO_POINT); + + return 0; +} + +/** We just received an ESTABLISH_INTRO cell in circ with payload in + * request. Handle it by making circ an intro circuit. Return 0 + * if everything went well, or -1 if there were errors. */ +static int +handle_establish_intro(or_circuit_t *circ, const uint8_t *request, + size_t request_len) +{ + int cell_ok, retval = -1; + hs_cell_establish_intro_t *parsed_cell = NULL; + + tor_assert(circ); + tor_assert(request); + + log_info(LD_REND, "Received an ESTABLISH_INTRO request on circuit %" PRIu32, + circ->p_circ_id); + + /* Check that the circuit is in shape to become an intro point */ + if (!hs_intro_circuit_is_suitable(circ)) { + goto err; + } + + /* Parse the cell */ + ssize_t parsing_result = hs_cell_establish_intro_parse(&parsed_cell, + request, request_len); + if (parsing_result < 0) { + log_warn(LD_PROTOCOL, "Rejecting %s ESTABLISH_INTRO cell.", + parsing_result == -1 ? "invalid" : "truncated"); + goto err; + } + + cell_ok = verify_establish_intro_cell(parsed_cell, + circ->rend_circ_nonce, + sizeof(circ->rend_circ_nonce)); + if (cell_ok < 0) { + log_warn(LD_PROTOCOL, "Failed to verify ESTABLISH_INTRO cell."); + goto err; + } + + /* This cell is legit. Take the appropriate actions. */ + cell_ok = handle_verified_establish_intro_cell(circ, parsed_cell); + if (cell_ok < 0) { + goto err; + } + + log_warn(LD_GENERAL, "Established prop224 intro point on circuit %" PRIu32, + circ->p_circ_id); + + /* We are done! */ + retval = 0; + goto done; + + err: + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); + + done: + hs_cell_establish_intro_free(parsed_cell); + return retval; +} + + +/* Return True if circuit is suitable for becoming an intro circuit. */ +int +hs_intro_circuit_is_suitable(const or_circuit_t *circ) +{ + /* Basic circuit state sanity checks. */ + if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) { + log_warn(LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-OR circuit."); + return 0; + } + + if (circ->base_.n_chan) { + log_warn(LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-edge circuit."); + return 0; + } + + return 1; +} + +/* We just received an ESTABLISH_INTRO cell in circ. Figure out of it's + * a legacy or a next gen cell, and pass it to the appropriate handler. */ +int +hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, + size_t request_len) +{ + tor_assert(circ); + tor_assert(request); + + if (request_len == 0) { + log_warn(LD_PROTOCOL, "Empty ESTABLISH_INTRO cell."); + goto err; + } + + /* Using the first byte of the cell, figure out the version of + * ESTABLISH_INTRO and pass it to the appropriate cell handler */ + const uint8_t first_byte = request[0]; + switch (first_byte) { + case HS_INTRO_AUTH_KEY_TYPE_LEGACY0: + case HS_INTRO_AUTH_KEY_TYPE_LEGACY1: + return rend_mid_establish_intro_legacy(circ, request, request_len); + case HS_INTRO_AUTH_KEY_TYPE_ED25519: + return handle_establish_intro(circ, request, request_len); + default: + log_warn(LD_PROTOCOL, "Unrecognized AUTH_KEY_TYPE %u.", first_byte); + goto err; + } + + err: + circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL); + return -1; +} diff --git a/src/or/hs_intropoint.h b/src/or/hs_intropoint.h new file mode 100644 index 0000000000..651e2dcc0f --- /dev/null +++ b/src/or/hs_intropoint.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_intropoint.h + * \brief Header file for hs_intropoint.c. + **/ + +#ifndef TOR_HS_INTRO_H +#define TOR_HS_INTRO_H + +/* Authentication key type in an ESTABLISH_INTRO cell. */ +enum hs_intro_auth_key_type { + HS_INTRO_AUTH_KEY_TYPE_LEGACY0 = 0x00, + HS_INTRO_AUTH_KEY_TYPE_LEGACY1 = 0x01, + HS_INTRO_AUTH_KEY_TYPE_ED25519 = 0x02, +}; + +int hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, + size_t request_len); + +MOCK_DECL(int, hs_intro_send_intro_established_cell,(or_circuit_t *circ)); + +/* also used by rendservice.c */ +int hs_intro_circuit_is_suitable(const or_circuit_t *circ); + +#ifdef HS_INTROPOINT_PRIVATE + +STATIC int +verify_establish_intro_cell(const hs_cell_establish_intro_t *out, + const char *circuit_key_material, + size_t circuit_key_material_len); + +STATIC void +get_auth_key_from_establish_intro_cell(ed25519_public_key_t *auth_key_out, + const hs_cell_establish_intro_t *cell); + +#endif /* HS_INTROPOINT_PRIVATE */ + +#endif /* TOR_HS_INTRO_H */ diff --git a/src/or/include.am b/src/or/include.am index 10f8b85bdf..38777ccc6d 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -45,6 +45,9 @@ LIBTOR_A_SOURCES = \ src/or/dnsserv.c \ src/or/fp_pair.c \ src/or/geoip.c \ + src/or/hs_intropoint.c \ + src/or/hs_circuitmap.c \ + src/or/hs_service.c \ src/or/entrynodes.c \ src/or/ext_orport.c \ src/or/hibernate.c \ @@ -164,6 +167,9 @@ ORHEADERS = \ src/or/hs_cache.h \ src/or/hs_common.h \ src/or/hs_descriptor.h \ + src/or/hs_intropoint.h \ + src/or/hs_circuitmap.h \ + src/or/hs_service.h \ src/or/keypin.h \ src/or/main.h \ src/or/microdesc.h \ diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c index f2060e528c..def51b7986 100644 --- a/src/or/rendcommon.c +++ b/src/or/rendcommon.c @@ -16,6 +16,7 @@ #include "rendclient.h" #include "rendcommon.h" #include "rendmid.h" +#include "hs_intropoint.h" #include "rendservice.h" #include "rephist.h" #include "router.h" @@ -762,7 +763,7 @@ rend_process_relay_cell(circuit_t *circ, const crypt_path_t *layer_hint, switch (command) { case RELAY_COMMAND_ESTABLISH_INTRO: if (or_circ) - r = rend_mid_establish_intro(or_circ,payload,length); + r = hs_intro_received_establish_intro(or_circ,payload,length); break; case RELAY_COMMAND_ESTABLISH_RENDEZVOUS: if (or_circ) diff --git a/src/or/rendmid.c b/src/or/rendmid.c index 6b44aa14ea..f3841abf64 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -11,16 +11,19 @@ #include "circuitlist.h" #include "circuituse.h" #include "config.h" +#include "crypto.h" #include "relay.h" #include "rendmid.h" #include "rephist.h" +#include "hs_circuitmap.h" +#include "hs_intropoint.h" /** Respond to an ESTABLISH_INTRO cell by checking the signed data and * setting the circuit's purpose and service pk digest. */ int -rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, - size_t request_len) +rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, + size_t request_len) { crypto_pk_t *pk = NULL; char buf[DIGEST_LEN+9]; diff --git a/src/or/rendmid.h b/src/or/rendmid.h index 10d1287085..374f2b7d66 100644 --- a/src/or/rendmid.h +++ b/src/or/rendmid.h @@ -12,8 +12,8 @@ #ifndef TOR_RENDMID_H #define TOR_RENDMID_H -int rend_mid_establish_intro(or_circuit_t *circ, const uint8_t *request, - size_t request_len); +int rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, + size_t request_len); int rend_mid_introduce(or_circuit_t *circ, const uint8_t *request, size_t request_len); int rend_mid_establish_rendezvous(or_circuit_t *circ, const uint8_t *request, From 12dfe56b1cf9ec9852f27b8d10f2dcfad354f416 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Wed, 2 Nov 2016 11:38:45 -0400 Subject: [PATCH 08/12] prop224: Use new HS functions in old HS code. This is needed to make old code unittestable. --- src/or/rendmid.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/or/rendmid.c b/src/or/rendmid.c index f3841abf64..3319a639b9 100644 --- a/src/or/rendmid.c +++ b/src/or/rendmid.c @@ -35,15 +35,14 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, int reason = END_CIRC_REASON_INTERNAL; log_info(LD_REND, - "Received an ESTABLISH_INTRO request on circuit %u", + "Received a legacy ESTABLISH_INTRO request on circuit %u", (unsigned) circ->p_circ_id); - if (circ->base_.purpose != CIRCUIT_PURPOSE_OR || circ->base_.n_chan) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit."); + if (!hs_intro_circuit_is_suitable(circ)) { reason = END_CIRC_REASON_TORPROTOCOL; goto err; } + if (request_len < 2+DIGEST_LEN) goto truncated; /* First 2 bytes: length of asn1-encoded key. */ @@ -105,9 +104,7 @@ rend_mid_establish_intro_legacy(or_circuit_t *circ, const uint8_t *request, } /* Acknowledge the request. */ - if (relay_send_command_from_edge(0, TO_CIRCUIT(circ), - RELAY_COMMAND_INTRO_ESTABLISHED, - "", 0, NULL)<0) { + if (hs_intro_send_intro_established_cell(circ) < 0) { log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell."); goto err_no_close; } From 297213825b288c954e13c3bccb3b3210063d244a Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 19:03:30 +0300 Subject: [PATCH 09/12] prop224: Add unittests handling v3 ESTABLISH_INTRO cells. Test for both v2 and v3 ESTABLISH_INTRO handling. --- src/common/crypto_ed25519.c | 10 +- src/common/crypto_ed25519.h | 11 +- src/test/include.am | 2 + src/test/test.c | 4 +- src/test/test.h | 2 + src/test/test_hs_intropoint.c | 360 ++++++++++++++++++++++++++++++++++ src/test/test_hs_service.c | 112 +++++++++++ 7 files changed, 490 insertions(+), 11 deletions(-) create mode 100644 src/test/test_hs_intropoint.c create mode 100644 src/test/test_hs_service.c diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 30ed772274..1be225d1a7 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -267,11 +267,11 @@ ed25519_sign(ed25519_signature_t *signature_out, * Like ed25519_sign(), but also prefix msg with prefix_str * before signing. prefix_str must be a NUL-terminated string. */ -int -ed25519_sign_prefixed(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t msg_len, - const char *prefix_str, - const ed25519_keypair_t *keypair) +MOCK_IMPL(int, +ed25519_sign_prefixed,(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_keypair_t *keypair)) { int retval; size_t prefixed_msg_len; diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h index 31afc49ccc..08ba9be2fc 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -55,11 +55,12 @@ int ed25519_checksig(const ed25519_signature_t *signature, const uint8_t *msg, size_t len, const ed25519_public_key_t *pubkey); -int -ed25519_sign_prefixed(ed25519_signature_t *signature_out, - const uint8_t *msg, size_t len, - const char *prefix_str, - const ed25519_keypair_t *keypair); +MOCK_DECL(int, +ed25519_sign_prefixed,(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t len, + const char *prefix_str, + const ed25519_keypair_t *keypair)); + int ed25519_checksig_prefixed(const ed25519_signature_t *signature, const uint8_t *msg, size_t len, diff --git a/src/test/include.am b/src/test/include.am index f6e43148f0..6177e5f920 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -96,6 +96,8 @@ src_test_test_SOURCES = \ src/test/test_guardfraction.c \ src/test/test_extorport.c \ src/test/test_hs.c \ + src/test/test_hs_service.c \ + src/test/test_hs_intropoint.c \ src/test/test_handles.c \ src/test/test_hs_cache.c \ src/test/test_hs_descriptor.c \ diff --git a/src/test/test.c b/src/test/test.c index b02ecb922d..b49180cbfd 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1204,9 +1204,11 @@ struct testgroup_t testgroups[] = { { "entrynodes/", entrynodes_tests }, { "guardfraction/", guardfraction_tests }, { "extorport/", extorport_tests }, - { "hs/", hs_tests }, + { "legacy_hs/", hs_tests }, { "hs_cache/", hs_cache }, { "hs_descriptor/", hs_descriptor }, + { "hs_service/", hs_service_tests }, + { "hs_intropoint/", hs_intropoint_tests }, { "introduce/", introduce_tests }, { "keypin/", keypin_tests }, { "link-handshake/", link_handshake_tests }, diff --git a/src/test/test.h b/src/test/test.h index 49b4499594..cf4735146f 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -201,6 +201,8 @@ extern struct testcase_t extorport_tests[]; extern struct testcase_t hs_tests[]; extern struct testcase_t hs_cache[]; extern struct testcase_t hs_descriptor[]; +extern struct testcase_t hs_service_tests[]; +extern struct testcase_t hs_intropoint_tests[]; extern struct testcase_t introduce_tests[]; extern struct testcase_t keypin_tests[]; extern struct testcase_t link_handshake_tests[]; diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c new file mode 100644 index 0000000000..76f9dbaea0 --- /dev/null +++ b/src/test/test_hs_intropoint.c @@ -0,0 +1,360 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_service.c + * \brief Test hidden service functionality. + */ + +#define HS_SERVICE_PRIVATE +#define HS_INTROPOINT_PRIVATE +#define RENDSERVICE_PRIVATE +#define CIRCUITLIST_PRIVATE + +#include "test.h" +#include "crypto.h" + +#include "or.h" +#include "ht.h" + +#include "hs/cell_establish_intro.h" +#include "hs_service.h" +#include "hs_circuitmap.h" +#include "hs_intropoint.h" + +#include "circuitlist.h" +#include "circuituse.h" +#include "rendservice.h" + +/* Mock function to avoid networking in unittests */ +static int +mock_send_intro_established_cell(or_circuit_t *circ) +{ + (void) circ; + return 0; +} + +/* Try sending an ESTABLISH_INTRO cell on a circuit that is already an intro + * point. Should fail. */ +static void +test_establish_intro_wrong_purpose(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN); + + /* Set a bad circuit purpose!! :) */ + circuit_change_purpose(TO_CIRCUIT(intro_circ), CIRCUIT_PURPOSE_INTRO_POINT); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Receive the cell */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Prepare a circuit for accepting an ESTABLISH_INTRO cell */ +static void +helper_prepare_circ_for_intro(or_circuit_t *circ, char *circuit_key_material) +{ + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); + memcpy(circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN); +} + +/* Send an empty ESTABLISH_INTRO cell. Should fail. */ +static void +test_establish_intro_wrong_keytype(void *arg) +{ + int retval; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, (uint8_t*)"", 0); + tt_int_op(retval, ==, -1); + + done: + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Send an ESTABLISH_INTRO cell with an unknown auth key type. Should fail. */ +static void +test_establish_intro_wrong_keytype2(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Mutate the auth key type! :) */ + cell_body[0] = 42; + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Send a legit ESTABLISH_INTRO cell but slightly change the signature. Should + * fail. */ +static void +test_establish_intro_wrong_sig(void *arg) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + or_circuit_t *intro_circ = or_circuit_new(0,NULL);; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + char circuit_key_material[DIGEST_LEN] = {0}; + + (void)arg; + + /* Get the auth key of the intro point */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Mutate the last byte (signature)! :) */ + cell_body[cell_len-1]++; + + /* Receive the cell. Should fail. */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, -1); + + done: + hs_cell_establish_intro_free(establish_intro_cell); + circuit_free(TO_CIRCUIT(intro_circ)); +} + +/* Helper function: Send a well-formed v3 ESTABLISH_INTRO cell to + * intro_circ. Return the cell. */ +static hs_cell_establish_intro_t * +helper_establish_intro_v3(or_circuit_t *intro_circ) +{ + int retval; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + char circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + establish_intro_cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(establish_intro_cell); + cell_len = get_establish_intro_payload(cell_body, sizeof(cell_body), + establish_intro_cell); + tt_int_op(cell_len, >, 0); + + /* Receive the cell */ + retval = hs_intro_received_establish_intro(intro_circ, cell_body, cell_len); + tt_int_op(retval, ==, 0); + + done: + return establish_intro_cell; +} + +/* Helper function: Send a well-formed v2 ESTABLISH_INTRO cell to + * intro_circ. Return the public key advertised in the cell. */ +static crypto_pk_t * +helper_establish_intro_v2(or_circuit_t *intro_circ) +{ + crypto_pk_t *key1 = NULL; + int retval; + uint8_t cell_body[RELAY_PAYLOAD_SIZE]; + ssize_t cell_len = 0; + char circuit_key_material[DIGEST_LEN] = {0}; + + tt_assert(intro_circ); + + /* Prepare the circuit for the incoming ESTABLISH_INTRO */ + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + helper_prepare_circ_for_intro(intro_circ, circuit_key_material); + + /* Send legacy establish_intro */ + key1 = pk_generate(0); + + /* Use old circuit_key_material why not */ + cell_len = encode_establish_intro_cell_legacy((char*)cell_body, + key1, + circuit_key_material); + tt_int_op(cell_len, >, 0); + + /* Receive legacy establish_intro */ + retval = hs_intro_received_establish_intro(intro_circ, + cell_body, cell_len); + tt_int_op(retval, ==, 0); + + done: + return key1; +} + +/** Successfuly register a v2 intro point and a v3 intro point. Ensure that HS + * circuitmap is maintained properly. */ +static void +test_intro_point_registration(void *arg) +{ + int retval; + hs_circuitmap_ht *the_hs_circuitmap = NULL; + + or_circuit_t *intro_circ = NULL; + hs_cell_establish_intro_t *establish_intro_cell = NULL; + ed25519_public_key_t auth_key; + + crypto_pk_t *legacy_auth_key = NULL; + or_circuit_t *legacy_intro_circ = NULL; + + or_circuit_t *returned_intro_circ = NULL; + + (void) arg; + + MOCK(hs_intro_send_intro_established_cell, mock_send_intro_established_cell); + + hs_circuitmap_init(); + + /* Check that the circuitmap is currently empty */ + { + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(0, ==, HT_SIZE(the_hs_circuitmap)); + /* Do a circuitmap query in any case */ + returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + tt_ptr_op(returned_intro_circ, ==, NULL); + } + + /* Create a v3 intro point */ + { + intro_circ = or_circuit_new(0, NULL); + tt_assert(intro_circ); + establish_intro_cell = helper_establish_intro_v3(intro_circ); + + /* Check that the intro point was registered on the HS circuitmap */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(1, ==, HT_SIZE(the_hs_circuitmap)); + get_auth_key_from_establish_intro_cell(&auth_key, establish_intro_cell); + returned_intro_circ = hs_circuitmap_get_intro_circ_v3(&auth_key); + tt_ptr_op(intro_circ, ==, returned_intro_circ); + } + + /* Create a v2 intro point */ + { + char key_digest[DIGEST_LEN]; + + legacy_intro_circ = or_circuit_new(1, NULL); + tt_assert(legacy_intro_circ); + legacy_auth_key = helper_establish_intro_v2(legacy_intro_circ); + tt_assert(legacy_auth_key); + + /* Check that the circuitmap now has two elements */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + tt_int_op(2, ==, HT_SIZE(the_hs_circuitmap)); + + /* Check that the new element is our legacy intro circuit. */ + retval = crypto_pk_get_digest(legacy_auth_key, key_digest); + tt_int_op(retval, ==, 0); + returned_intro_circ= hs_circuitmap_get_intro_circ_v2((uint8_t*)key_digest); + tt_ptr_op(legacy_intro_circ, ==, returned_intro_circ); + } + + /* XXX Continue test and try to register a second v3 intro point with the + * same auth key. Make sure that old intro circuit gets closed. */ + + done: + crypto_pk_free(legacy_auth_key); + circuit_free(TO_CIRCUIT(intro_circ)); + circuit_free(TO_CIRCUIT(legacy_intro_circ)); + hs_cell_establish_intro_free(establish_intro_cell); + + { /* Test circuitmap free_all function. */ + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(the_hs_circuitmap); + hs_circuitmap_free_all(); + the_hs_circuitmap = get_hs_circuitmap(); + tt_assert(!the_hs_circuitmap); + } + + UNMOCK(hs_intro_send_intro_established_cell); +} + +struct testcase_t hs_intropoint_tests[] = { + { "intro_point_registration", + test_intro_point_registration, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_keytype", + test_establish_intro_wrong_keytype, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_keytype2", + test_establish_intro_wrong_keytype2, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_purpose", + test_establish_intro_wrong_purpose, TT_FORK, NULL, NULL }, + + { "receive_establish_intro_wrong_sig", + test_establish_intro_wrong_sig, TT_FORK, NULL, NULL }, + + END_OF_TESTCASES +}; + diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c new file mode 100644 index 0000000000..88c7ef2b35 --- /dev/null +++ b/src/test/test_hs_service.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2016, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file test_hs_service.c + * \brief Test hidden service functionality. + */ + +#define HS_SERVICE_PRIVATE +#define HS_INTROPOINT_PRIVATE + +#include "test.h" +#include "log_test_helpers.h" +#include "crypto.h" + +#include "hs/cell_establish_intro.h" +#include "hs_service.h" +#include "hs_intropoint.h" + +/** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we + * parse it from the receiver side. */ +static void +test_gen_establish_intro_cell(void *arg) +{ + (void) arg; + int retval; + char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t buf[RELAY_PAYLOAD_SIZE]; + hs_cell_establish_intro_t *cell_out = NULL; + hs_cell_establish_intro_t *cell_in = NULL; + + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + + /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we + attempt to parse it. */ + { + cell_out = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + tt_assert(cell_out); + + retval = get_establish_intro_payload(buf, sizeof(buf), cell_out); + tt_int_op(retval, >=, 0); + } + + /* Parse it as the receiver */ + { + ssize_t parse_result = hs_cell_establish_intro_parse(&cell_in, + buf, sizeof(buf)); + tt_int_op(parse_result, >=, 0); + + retval = verify_establish_intro_cell(cell_in, + circuit_key_material, + sizeof(circuit_key_material)); + tt_int_op(retval, >=, 0); + } + + done: + hs_cell_establish_intro_free(cell_out); + hs_cell_establish_intro_free(cell_in); +} + +/* Mocked ed25519_sign_prefixed() function that always fails :) */ +static int +mock_ed25519_sign_prefixed(ed25519_signature_t *signature_out, + const uint8_t *msg, size_t msg_len, + const char *prefix_str, + const ed25519_keypair_t *keypair) { + (void) signature_out; + (void) msg; + (void) msg_len; + (void) prefix_str; + (void) keypair; + return -1; +} + +/** We simulate a failure to create an ESTABLISH_INTRO cell */ +static void +test_gen_establish_intro_cell_bad(void *arg) +{ + (void) arg; + hs_cell_establish_intro_t *cell = NULL; + char circuit_key_material[DIGEST_LEN] = {0}; + + MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); + + crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + + setup_full_capture_of_logs(LOG_WARN); + /* Easiest way to make that function fail is to mock the + ed25519_sign_prefixed() function and make it fail. */ + cell = generate_establish_intro_cell(circuit_key_material, + sizeof(circuit_key_material)); + expect_log_msg_containing("Unable to gen signature for " + "ESTABLISH_INTRO cell."); + teardown_capture_of_logs(); + tt_assert(!cell); + + done: + hs_cell_establish_intro_free(cell); + UNMOCK(ed25519_sign_prefixed); +} + +struct testcase_t hs_service_tests[] = { + { "gen_establish_intro_cell", test_gen_establish_intro_cell, TT_FORK, + NULL, NULL }, + { "gen_establish_intro_cell_bad", test_gen_establish_intro_cell_bad, TT_FORK, + NULL, NULL }, + + + END_OF_TESTCASES +}; + From 7a204ae8f9c54c15e9bc05b9c2bd62c7e46d6ebb Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Mon, 5 Sep 2016 19:54:06 +0300 Subject: [PATCH 10/12] prop224: Add a changes file for v3 ESTABLISH_INTRO. --- changes/bug19043 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/bug19043 diff --git a/changes/bug19043 b/changes/bug19043 new file mode 100644 index 0000000000..70c35dfa7b --- /dev/null +++ b/changes/bug19043 @@ -0,0 +1,5 @@ + o Major features (hidden services): + - Relays can now handle v3 ESTABLISH_INTRO cells as specified by prop224 + aka "Next Generation Hidden Services". Service and clients don't yet use + this code functionnality. It marks another step towards prop224 + deployment. Resolves ticket 19043. Initial code by Alec Heifetz. From 118691cd47e53521319cdcbf994f29ecca3db4d1 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Mon, 12 Dec 2016 16:45:28 -0500 Subject: [PATCH 11/12] crypto: Change crypto_mac_sha3_256 to use the key length in the construction Signed-off-by: David Goulet --- src/common/crypto.c | 25 ++++++++++++++++--------- src/common/crypto.h | 7 ++++--- src/or/hs_intropoint.c | 18 +++++++++--------- src/or/hs_intropoint.h | 2 +- src/or/hs_service.c | 6 +++--- src/or/hs_service.h | 2 +- src/test/test_crypto.c | 24 +++++++++++++++--------- src/test/test_hs_intropoint.c | 29 +++++++++++++++-------------- src/test/test_hs_service.c | 8 ++++---- 9 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/common/crypto.c b/src/common/crypto.c index e4ef52d510..1b1f1f9aef 100644 --- a/src/common/crypto.c +++ b/src/common/crypto.c @@ -2109,25 +2109,32 @@ crypto_hmac_sha256(char *hmac_out, tor_assert(rv); } -/** Compute an SHA3 MAC of msg using key as the key. The format - * used for our MAC is SHA3(k | m). Write the DIGEST256_LEN-byte result into - * mac_out of size mac_out_len. */ +/** Compute a MAC using SHA3-256 of msg_len bytes in msg using a + * key of length key_len and a salt of length + * salt_len. Store the result of len_out bytes in in + * mac_out. This function can't fail. */ void -crypto_mac_sha3_256(char *mac_out, size_t mac_out_len, - const char *key, size_t key_len, - const char *msg, size_t msg_len) +crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, + const uint8_t *key, size_t key_len, + const uint8_t *msg, size_t msg_len) { crypto_digest_t *digest; + const uint64_t key_len_netorder = tor_htonll(key_len); + tor_assert(mac_out); tor_assert(key); tor_assert(msg); digest = crypto_digest256_new(DIGEST_SHA3_256); - crypto_digest_add_bytes(digest, key, key_len); - crypto_digest_add_bytes(digest, msg, msg_len); - crypto_digest_get_digest(digest, mac_out, mac_out_len); + /* Order matters here that is any subsystem using this function should + * expect this very precise ordering in the MAC construction. */ + crypto_digest_add_bytes(digest, (const char *) &key_len_netorder, + sizeof(key_len_netorder)); + crypto_digest_add_bytes(digest, (const char *) key, key_len); + crypto_digest_add_bytes(digest, (const char *) msg, msg_len); + crypto_digest_get_digest(digest, (char *) mac_out, len_out); crypto_digest_free(digest); } diff --git a/src/common/crypto.h b/src/common/crypto.h index 32b6531456..bf2fa06aaa 100644 --- a/src/common/crypto.h +++ b/src/common/crypto.h @@ -255,9 +255,10 @@ void crypto_digest_assign(crypto_digest_t *into, void crypto_hmac_sha256(char *hmac_out, const char *key, size_t key_len, const char *msg, size_t msg_len); -void crypto_mac_sha3_256(char *mac_out, size_t mac_out_len, - const char *key, size_t key_len, - const char *msg, size_t msg_len); +void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, + const uint8_t *key, size_t key_len, + const uint8_t *msg, size_t msg_len); + crypto_xof_t *crypto_xof_new(void); void crypto_xof_add_bytes(crypto_xof_t *xof, const uint8_t *data, size_t len); void crypto_xof_squeeze_bytes(crypto_xof_t *xof, uint8_t *out, size_t len); diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c index fb8637b14e..b5f62aa21b 100644 --- a/src/or/hs_intropoint.c +++ b/src/or/hs_intropoint.c @@ -42,7 +42,7 @@ get_auth_key_from_establish_intro_cell(ed25519_public_key_t *auth_key_out, * given circuit_key_material. Return 0 on success else -1 on error. */ STATIC int verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, - const char *circuit_key_material, + const uint8_t *circuit_key_material, size_t circuit_key_material_len) { /* We only reach this function if the first byte of the cell is 0x02 which @@ -62,7 +62,7 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, return -1; } - const char *msg = (char*) cell->start_cell; + const uint8_t *msg = cell->start_cell; /* Verify the sig */ { @@ -79,7 +79,7 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, ed25519_public_key_t auth_key; get_auth_key_from_establish_intro_cell(&auth_key, cell); - const size_t sig_msg_len = (char*) (cell->end_sig_fields) - msg; + const size_t sig_msg_len = cell->end_sig_fields - msg; int sig_mismatch = ed25519_checksig_prefixed(&sig_struct, (uint8_t*) msg, sig_msg_len, ESTABLISH_INTRO_SIG_PREFIX, @@ -92,11 +92,11 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, /* Verify the MAC */ { - const size_t auth_msg_len = (char*) (cell->end_mac_fields) - msg; - char mac[DIGEST256_LEN]; + const size_t auth_msg_len = cell->end_mac_fields - msg; + uint8_t mac[DIGEST256_LEN]; crypto_mac_sha3_256(mac, sizeof(mac), - circuit_key_material, circuit_key_material_len, - msg, auth_msg_len); + circuit_key_material, circuit_key_material_len, + msg, auth_msg_len); if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) { log_warn(LD_PROTOCOL, "ESTABLISH_INTRO handshake_auth not as expected"); return -1; @@ -198,8 +198,8 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, } cell_ok = verify_establish_intro_cell(parsed_cell, - circ->rend_circ_nonce, - sizeof(circ->rend_circ_nonce)); + (uint8_t *) circ->rend_circ_nonce, + sizeof(circ->rend_circ_nonce)); if (cell_ok < 0) { log_warn(LD_PROTOCOL, "Failed to verify ESTABLISH_INTRO cell."); goto err; diff --git a/src/or/hs_intropoint.h b/src/or/hs_intropoint.h index 651e2dcc0f..b7846a4d8f 100644 --- a/src/or/hs_intropoint.h +++ b/src/or/hs_intropoint.h @@ -28,7 +28,7 @@ int hs_intro_circuit_is_suitable(const or_circuit_t *circ); STATIC int verify_establish_intro_cell(const hs_cell_establish_intro_t *out, - const char *circuit_key_material, + const uint8_t *circuit_key_material, size_t circuit_key_material_len); STATIC void diff --git a/src/or/hs_service.c b/src/or/hs_service.c index 69f83cfaa1..6f0836ca2e 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -60,7 +60,7 @@ set_cell_extensions(hs_cell_establish_intro_t *cell) * returned cell is allocated on the heap and it's the responsibility of the * caller to free it. */ STATIC hs_cell_establish_intro_t * -generate_establish_intro_cell(const char *circuit_key_material, +generate_establish_intro_cell(const uint8_t *circuit_key_material, size_t circuit_key_material_len) { hs_cell_establish_intro_t *cell = NULL; @@ -109,7 +109,7 @@ generate_establish_intro_cell(const char *circuit_key_material, /* To calculate HANDSHAKE_AUTH, we dump the cell in bytes, and then derive the MAC from it. */ uint8_t cell_bytes_tmp[RELAY_PAYLOAD_SIZE] = {0}; - char mac[TRUNNEL_SHA3_256_LEN]; + uint8_t mac[TRUNNEL_SHA3_256_LEN]; encoded_len = hs_cell_establish_intro_encode(cell_bytes_tmp, sizeof(cell_bytes_tmp), @@ -125,7 +125,7 @@ generate_establish_intro_cell(const char *circuit_key_material, /* Calculate MAC of all fields before HANDSHAKE_AUTH */ crypto_mac_sha3_256(mac, sizeof(mac), circuit_key_material, circuit_key_material_len, - (const char*)cell_bytes_tmp, + cell_bytes_tmp, encoded_len - (ED25519_SIG_LEN + 2 + TRUNNEL_SHA3_256_LEN)); /* Write the MAC to the cell */ uint8_t *handshake_ptr = diff --git a/src/or/hs_service.h b/src/or/hs_service.h index 4a7600767e..a54a960b8c 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -17,7 +17,7 @@ #ifdef TOR_UNIT_TESTS STATIC hs_cell_establish_intro_t * -generate_establish_intro_cell(const char *circuit_key_material, +generate_establish_intro_cell(const uint8_t *circuit_key_material, size_t circuit_key_material_len); STATIC ssize_t diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 91c55d8c3d..d66ddccd4f 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1147,28 +1147,34 @@ test_crypto_mac_sha3(void *arg) const char msg[] = "i am in a library somewhere using my computer"; const char key[] = "i'm from the past talking to the future."; - char hmac_test[DIGEST256_LEN]; + uint8_t hmac_test[DIGEST256_LEN]; char hmac_manual[DIGEST256_LEN]; (void) arg; /* First let's use our nice HMAC-SHA3 function */ crypto_mac_sha3_256(hmac_test, sizeof(hmac_test), - key, strlen(key), - msg, strlen(msg)); + (uint8_t *) key, strlen(key), + (uint8_t *) msg, strlen(msg)); - /* Now let's try a manual H(k || m) construction */ + /* Now let's try a manual H(len(k) || k || m) construction */ { - char *key_msg_concat = NULL; + char *key_msg_concat = NULL, *all = NULL; int result; + const uint64_t key_len_netorder = tor_htonll(strlen(key)); + size_t all_len; tor_asprintf(&key_msg_concat, "%s%s", key, msg); + all_len = sizeof(key_len_netorder) + strlen(key_msg_concat); + all = tor_malloc_zero(all_len); + memcpy(all, &key_len_netorder, sizeof(key_len_netorder)); + memcpy(all + sizeof(key_len_netorder), key_msg_concat, + strlen(key_msg_concat)); - result = crypto_digest256(hmac_manual, - key_msg_concat, strlen(key_msg_concat), - DIGEST_SHA3_256); - tt_int_op(result, ==, 0); + result = crypto_digest256(hmac_manual, all, all_len, DIGEST_SHA3_256); tor_free(key_msg_concat); + tor_free(all); + tt_int_op(result, ==, 0); } /* Now compare the two results */ diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 76f9dbaea0..608988ba9a 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -44,12 +44,12 @@ test_establish_intro_wrong_purpose(void *arg) or_circuit_t *intro_circ = or_circuit_new(0,NULL);; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; (void)arg; /* Get the auth key of the intro point */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); memcpy(intro_circ->rend_circ_nonce, circuit_key_material, DIGEST_LEN); /* Set a bad circuit purpose!! :) */ @@ -75,7 +75,8 @@ test_establish_intro_wrong_purpose(void *arg) /* Prepare a circuit for accepting an ESTABLISH_INTRO cell */ static void -helper_prepare_circ_for_intro(or_circuit_t *circ, char *circuit_key_material) +helper_prepare_circ_for_intro(or_circuit_t *circ, + uint8_t *circuit_key_material) { /* Prepare the circuit for the incoming ESTABLISH_INTRO */ circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); @@ -88,12 +89,12 @@ test_establish_intro_wrong_keytype(void *arg) { int retval; or_circuit_t *intro_circ = or_circuit_new(0,NULL);; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; (void)arg; /* Get the auth key of the intro point */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); helper_prepare_circ_for_intro(intro_circ, circuit_key_material); /* Receive the cell. Should fail. */ @@ -113,12 +114,12 @@ test_establish_intro_wrong_keytype2(void *arg) or_circuit_t *intro_circ = or_circuit_new(0,NULL);; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; (void)arg; /* Get the auth key of the intro point */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); helper_prepare_circ_for_intro(intro_circ, circuit_key_material); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we @@ -152,12 +153,12 @@ test_establish_intro_wrong_sig(void *arg) or_circuit_t *intro_circ = or_circuit_new(0,NULL);; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; (void)arg; /* Get the auth key of the intro point */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); helper_prepare_circ_for_intro(intro_circ, circuit_key_material); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we @@ -190,12 +191,12 @@ helper_establish_intro_v3(or_circuit_t *intro_circ) hs_cell_establish_intro_t *establish_intro_cell = NULL; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; tt_assert(intro_circ); /* Prepare the circuit for the incoming ESTABLISH_INTRO */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); helper_prepare_circ_for_intro(intro_circ, circuit_key_material); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we @@ -224,12 +225,12 @@ helper_establish_intro_v2(or_circuit_t *intro_circ) int retval; uint8_t cell_body[RELAY_PAYLOAD_SIZE]; ssize_t cell_len = 0; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; tt_assert(intro_circ); /* Prepare the circuit for the incoming ESTABLISH_INTRO */ - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); helper_prepare_circ_for_intro(intro_circ, circuit_key_material); /* Send legacy establish_intro */ @@ -238,7 +239,7 @@ helper_establish_intro_v2(or_circuit_t *intro_circ) /* Use old circuit_key_material why not */ cell_len = encode_establish_intro_cell_legacy((char*)cell_body, key1, - circuit_key_material); + (char *) circuit_key_material); tt_int_op(cell_len, >, 0); /* Receive legacy establish_intro */ diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 88c7ef2b35..195e5069cb 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -24,12 +24,12 @@ test_gen_establish_intro_cell(void *arg) { (void) arg; int retval; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; uint8_t buf[RELAY_PAYLOAD_SIZE]; hs_cell_establish_intro_t *cell_out = NULL; hs_cell_establish_intro_t *cell_in = NULL; - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); /* Create outgoing ESTABLISH_INTRO cell and extract its payload so that we attempt to parse it. */ @@ -79,11 +79,11 @@ test_gen_establish_intro_cell_bad(void *arg) { (void) arg; hs_cell_establish_intro_t *cell = NULL; - char circuit_key_material[DIGEST_LEN] = {0}; + uint8_t circuit_key_material[DIGEST_LEN] = {0}; MOCK(ed25519_sign_prefixed, mock_ed25519_sign_prefixed); - crypto_rand(circuit_key_material, sizeof(circuit_key_material)); + crypto_rand((char *) circuit_key_material, sizeof(circuit_key_material)); setup_full_capture_of_logs(LOG_WARN); /* Easiest way to make that function fail is to mock the From a4eb17ed89d4761146280490e838cf850bc81296 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 14 Dec 2016 10:39:33 -0500 Subject: [PATCH 12/12] prop224: Use LOG_PROTOCOL_WARN instead of log_warn(LD_PROTOCOL, ...) in hs_intropoint.c Signed-off-by: David Goulet --- src/or/hs_intropoint.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/or/hs_intropoint.c b/src/or/hs_intropoint.c index b5f62aa21b..67355bc44b 100644 --- a/src/or/hs_intropoint.c +++ b/src/or/hs_intropoint.c @@ -11,6 +11,7 @@ #include "or.h" #include "circuitlist.h" #include "circuituse.h" +#include "config.h" #include "relay.h" #include "rendmid.h" #include "rephist.h" @@ -70,7 +71,8 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, const uint8_t *sig_array = hs_cell_establish_intro_getconstarray_sig(cell); if (hs_cell_establish_intro_getlen_sig(cell) != sizeof(sig_struct.sig)) { - log_warn(LD_PROTOCOL, "ESTABLISH_INTRO sig len is invalid"); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "ESTABLISH_INTRO sig len is invalid"); return -1; } /* We are now sure that sig_len is of the right size. */ @@ -85,7 +87,8 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, ESTABLISH_INTRO_SIG_PREFIX, &auth_key); if (sig_mismatch) { - log_warn(LD_PROTOCOL, "ESTABLISH_INTRO signature not as expected"); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "ESTABLISH_INTRO signature not as expected"); return -1; } } @@ -98,7 +101,8 @@ verify_establish_intro_cell(const hs_cell_establish_intro_t *cell, circuit_key_material, circuit_key_material_len, msg, auth_msg_len); if (tor_memneq(mac, cell->handshake_mac, sizeof(mac))) { - log_warn(LD_PROTOCOL, "ESTABLISH_INTRO handshake_auth not as expected"); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "ESTABLISH_INTRO handshake_auth not as expected"); return -1; } } @@ -192,8 +196,9 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, ssize_t parsing_result = hs_cell_establish_intro_parse(&parsed_cell, request, request_len); if (parsing_result < 0) { - log_warn(LD_PROTOCOL, "Rejecting %s ESTABLISH_INTRO cell.", - parsing_result == -1 ? "invalid" : "truncated"); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Rejecting %s ESTABLISH_INTRO cell.", + parsing_result == -1 ? "invalid" : "truncated"); goto err; } @@ -201,7 +206,8 @@ handle_establish_intro(or_circuit_t *circ, const uint8_t *request, (uint8_t *) circ->rend_circ_nonce, sizeof(circ->rend_circ_nonce)); if (cell_ok < 0) { - log_warn(LD_PROTOCOL, "Failed to verify ESTABLISH_INTRO cell."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Failed to verify ESTABLISH_INTRO cell."); goto err; } @@ -233,12 +239,14 @@ hs_intro_circuit_is_suitable(const or_circuit_t *circ) { /* Basic circuit state sanity checks. */ if (circ->base_.purpose != CIRCUIT_PURPOSE_OR) { - log_warn(LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-OR circuit."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Rejecting ESTABLISH_INTRO on non-OR circuit."); return 0; } if (circ->base_.n_chan) { - log_warn(LD_PROTOCOL, "Rejecting ESTABLISH_INTRO on non-edge circuit."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Rejecting ESTABLISH_INTRO on non-edge circuit."); return 0; } @@ -255,7 +263,7 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, tor_assert(request); if (request_len == 0) { - log_warn(LD_PROTOCOL, "Empty ESTABLISH_INTRO cell."); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Empty ESTABLISH_INTRO cell."); goto err; } @@ -269,7 +277,8 @@ hs_intro_received_establish_intro(or_circuit_t *circ, const uint8_t *request, case HS_INTRO_AUTH_KEY_TYPE_ED25519: return handle_establish_intro(circ, request, request_len); default: - log_warn(LD_PROTOCOL, "Unrecognized AUTH_KEY_TYPE %u.", first_byte); + log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, + "Unrecognized AUTH_KEY_TYPE %u.", first_byte); goto err; }