diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 86b0aa097a..d11e128787 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -67,6 +67,7 @@ #include "main.h" #include "hs_circuitmap.h" #include "hs_common.h" +#include "hs_ident.h" #include "networkstatus.h" #include "nodelist.h" #include "onion.h" @@ -957,6 +958,7 @@ circuit_free(circuit_t *circ) crypto_pk_free(ocirc->intro_key); rend_data_free(ocirc->rend_data); + hs_ident_circuit_free(ocirc->hs_ident); tor_free(ocirc->dest_address); if (ocirc->socks_username) { diff --git a/src/or/connection.c b/src/or/connection.c index 4e890497e9..5c65e886c0 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -84,6 +84,7 @@ #include "geoip.h" #include "main.h" #include "hs_common.h" +#include "hs_ident.h" #include "nodelist.h" #include "policies.h" #include "reasons.h" @@ -605,6 +606,7 @@ connection_free_(connection_t *conn) } if (CONN_IS_EDGE(conn)) { rend_data_free(TO_EDGE_CONN(conn)->rend_data); + hs_ident_edge_conn_free(TO_EDGE_CONN(conn)->hs_ident); } if (conn->type == CONN_TYPE_CONTROL) { control_connection_t *control_conn = TO_CONTROL_CONN(conn); @@ -636,6 +638,7 @@ connection_free_(connection_t *conn) } rend_data_free(dir_conn->rend_data); + hs_ident_dir_conn_free(dir_conn->hs_ident); if (dir_conn->guard_state) { /* Cancel before freeing, if it's still there. */ entry_guard_cancel(&dir_conn->guard_state); diff --git a/src/or/hs_common.h b/src/or/hs_common.h index a8fded652a..872fed763a 100644 --- a/src/or/hs_common.h +++ b/src/or/hs_common.h @@ -49,6 +49,12 @@ /* The time period rotation offset as seen in prop224 section [TIME-PERIODS] */ #define HS_TIME_PERIOD_ROTATION_OFFSET (12 * 60) /* minutes */ +/* Type of authentication key used by an introduction point. */ +typedef enum { + HS_AUTH_KEY_TYPE_LEGACY = 1, + HS_AUTH_KEY_TYPE_ED25519 = 2, +} hs_auth_key_type_t; + int hs_check_service_private_dir(const char *username, const char *path, unsigned int dir_group_readable, unsigned int create); diff --git a/src/or/hs_ident.c b/src/or/hs_ident.c new file mode 100644 index 0000000000..5b5dc9aaff --- /dev/null +++ b/src/or/hs_ident.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_ident.c + * \brief Contains circuit and connection identifier code for the whole HS + * subsytem. + **/ + +#include "hs_ident.h" + +/* Return a newly allocated circuit identifier. The given public key is copied + * identity_pk into the identifier. */ +hs_ident_circuit_t * +hs_ident_circuit_new(const ed25519_public_key_t *identity_pk, + hs_ident_circuit_type_t circuit_type) +{ + tor_assert(circuit_type == HS_IDENT_CIRCUIT_INTRO || + circuit_type == HS_IDENT_CIRCUIT_RENDEZVOUS); + hs_ident_circuit_t *ident = tor_malloc_zero(sizeof(*ident)); + ed25519_pubkey_copy(&ident->identity_pk, identity_pk); + ident->circuit_type = circuit_type; + return ident; +} + +/* Free the given circuit identifier. */ +void +hs_ident_circuit_free(hs_ident_circuit_t *ident) +{ + if (ident == NULL) { + return; + } + if (ident->auth_key_type == HS_AUTH_KEY_TYPE_LEGACY) { + crypto_pk_free(ident->auth_rsa_pk); + } + memwipe(ident, 0, sizeof(hs_ident_circuit_t)); + tor_free(ident); +} + +/* For a given directory connection identifier src, return a newly allocated + * copy of it. This can't fail. */ +hs_ident_dir_conn_t * +hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src) +{ + hs_ident_dir_conn_t *ident = tor_malloc_zero(sizeof(*ident)); + memcpy(ident, src, sizeof(*ident)); + return ident; +} + +/* Free the given directory connection identifier. */ +void +hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident) +{ + if (ident == NULL) { + return; + } + memwipe(ident, 0, sizeof(hs_ident_dir_conn_t)); + tor_free(ident); +} + +/* Return a newly allocated edge connection identifier. The given public key + * identity_pk is copied into the identifier. */ +hs_ident_edge_conn_t * +hs_ident_edge_conn_new(const ed25519_public_key_t *identity_pk) +{ + hs_ident_edge_conn_t *ident = tor_malloc_zero(sizeof(*ident)); + ed25519_pubkey_copy(&ident->identity_pk, identity_pk); + return ident; +} + +/* Free the given edge connection identifier. */ +void +hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident) +{ + if (ident == NULL) { + return; + } + memwipe(ident, 0, sizeof(hs_ident_edge_conn_t)); + tor_free(ident); +} + diff --git a/src/or/hs_ident.h b/src/or/hs_ident.h new file mode 100644 index 0000000000..8a7c3598cf --- /dev/null +++ b/src/or/hs_ident.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file hs_ident.h + * \brief Header file containing circuit and connection identifier data for + * the whole HS subsytem. + * + * \details + * This interface is used to uniquely identify a hidden service on a circuit + * or connection using the service identity public key. Once the circuit or + * connection subsystem calls in the hidden service one, we use those + * identifiers to lookup the corresponding objects like service, intro point + * and descriptor. + * + * Furthermore, the circuit identifier holds cryptographic material needed for + * the e2e encryption on the rendezvous circuit which is set once the + * rendezvous circuit has opened and ready to be used. + **/ + +#ifndef TOR_HS_IDENT_H +#define TOR_HS_IDENT_H + +#include "crypto.h" +#include "crypto_ed25519.h" + +#include "hs_common.h" + +/* Length of the rendezvous cookie that is used to connect circuits at the + * rendezvous point. */ +#define HS_REND_COOKIE_LEN DIGEST_LEN + +/* Type of circuit an hs_ident_t object is associated with. */ +typedef enum { + HS_IDENT_CIRCUIT_INTRO = 1, + HS_IDENT_CIRCUIT_RENDEZVOUS = 2, +} hs_ident_circuit_type_t; + +/* Client and service side circuit identifier that is used for hidden service + * circuit establishment. Not all fields contain data, it depends on the + * circuit purpose. This is attached to an origin_circuit_t. All fields are + * used by both client and service. */ +typedef struct hs_ident_circuit_t { + /* (All circuit) The public key used to uniquely identify the service. It is + * the one found in the onion address. */ + ed25519_public_key_t identity_pk; + + /* (All circuit) The type of circuit this identifier is attached to. + * Accessors of the fields in this object assert non fatal on this circuit + * type. In other words, if a rendezvous field is being accessed, the + * circuit type MUST BE of type HS_IDENT_CIRCUIT_RENDEZVOUS. This value is + * set when an object is initialized in its constructor. */ + hs_ident_circuit_type_t circuit_type; + + /* (Only intro point circuit) Which type of authentication key this + * circuit identifier is using. */ + hs_auth_key_type_t auth_key_type; + + /* (Only intro point circuit) Introduction point authentication key. In + * legacy mode, we use an RSA key else an ed25519 public key. */ + crypto_pk_t *auth_rsa_pk; + ed25519_public_key_t auth_ed25519_pk; + + /* (Only rendezvous circuit) Rendezvous cookie sent from the client to the + * service with an INTRODUCE1 cell and used by the service in an + * RENDEZVOUS1 cell. */ + uint8_t rendezvous_cookie[HS_REND_COOKIE_LEN]; + + /* (Only rendezvous circuit) The HANDSHAKE_INFO needed in the RENDEZVOUS1 + * cell of the service. The construction is as follows: + * SERVER_PK [32 bytes] + * AUTH_MAC [32 bytes] + */ + uint8_t rendezvous_handshake_info[CURVE25519_PUBKEY_LEN + DIGEST256_LEN]; + + /* (Only rendezvous circuit) The NTOR_KEY_SEED needed for key derivation for + * the e2e encryption with the client on the circuit. */ + uint8_t rendezvous_ntor_key_seed[DIGEST256_LEN]; + + /* (Only rendezvous circuit) Number of streams associated with this + * rendezvous circuit. We track this because there is a check on a maximum + * value. */ + uint64_t num_rdv_streams; +} hs_ident_circuit_t; + +/* Client and service side directory connection identifier used for a + * directory connection to identify which service is being queried. This is + * attached to a dir_connection_t. */ +typedef struct hs_ident_dir_conn_t { + /* The public key used to uniquely identify the service. It is the one found + * in the onion address. */ + ed25519_public_key_t identity_pk; + + /* XXX: Client authorization. */ +} hs_ident_dir_conn_t; + +/* Client and service side edge connection identifier used for an edge + * connection to identify which service is being queried. This is attached to + * a edge_connection_t. */ +typedef struct hs_ident_edge_conn_t { + /* The public key used to uniquely identify the service. It is the one found + * in the onion address. */ + ed25519_public_key_t identity_pk; + + /* XXX: Client authorization. */ +} hs_ident_edge_conn_t; + +/* Circuit identifier API. */ +hs_ident_circuit_t *hs_ident_circuit_new( + const ed25519_public_key_t *identity_pk, + hs_ident_circuit_type_t circuit_type); +void hs_ident_circuit_free(hs_ident_circuit_t *ident); + +/* Directory connection identifier API. */ +hs_ident_dir_conn_t *hs_ident_dir_conn_dup(const hs_ident_dir_conn_t *src); +void hs_ident_dir_conn_free(hs_ident_dir_conn_t *ident); + +/* Edge connection identifier API. */ +hs_ident_edge_conn_t *hs_ident_edge_conn_new( + const ed25519_public_key_t *identity_pk); +void hs_ident_edge_conn_free(hs_ident_edge_conn_t *ident); + +#endif /* TOR_HS_IDENT_H */ + diff --git a/src/or/include.am b/src/or/include.am index 1ef5afa013..e800db5604 100644 --- a/src/or/include.am +++ b/src/or/include.am @@ -50,16 +50,17 @@ 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_ntor.c \ - src/or/hs_service.c \ + src/or/hs_cache.c \ + src/or/hs_circuitmap.c \ + src/or/hs_common.c \ + src/or/hs_descriptor.c \ + src/or/hs_ident.c \ + src/or/hs_intropoint.c \ + src/or/hs_ntor.c \ + src/or/hs_service.c \ src/or/entrynodes.c \ src/or/ext_orport.c \ src/or/hibernate.c \ - src/or/hs_cache.c \ - src/or/hs_common.c \ - src/or/hs_descriptor.c \ src/or/keypin.c \ src/or/main.c \ src/or/microdesc.c \ @@ -182,6 +183,7 @@ ORHEADERS = \ src/or/hs_cache.h \ src/or/hs_common.h \ src/or/hs_descriptor.h \ + src/or/hs_ident.h \ src/or/hs_intropoint.h \ src/or/hs_circuitmap.h \ src/or/hs_ntor.h \ diff --git a/src/or/or.h b/src/or/or.h index 1f55b55062..db77d0837f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -846,6 +846,11 @@ rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d) return DOWNCAST(rend_data_v2_t, d); } +/* Stub because we can't include hs_ident.h. */ +typedef struct hs_ident_edge_conn_t hs_ident_edge_conn_t; +typedef struct hs_ident_dir_conn_t hs_ident_dir_conn_t; +typedef struct hs_ident_circuit_t hs_ident_circuit_t; + /** Time interval for tracking replays of DH public keys received in * INTRODUCE2 cells. Used only to avoid launching multiple * simultaneous attempts to connect to the same rendezvous point. */ @@ -1633,6 +1638,10 @@ typedef struct edge_connection_t { * an exit)? */ rend_data_t *rend_data; + /* Hidden service connection identifier that is which service is being + * queried? */ + hs_ident_edge_conn_t *hs_ident; + uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit * connection. Exit connections only. */ uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell @@ -1783,6 +1792,10 @@ typedef struct dir_connection_t { /** What rendezvous service are we querying for? */ rend_data_t *rend_data; + /* Hidden service connection identifier that is which service is being + * queried? */ + hs_ident_dir_conn_t *hs_ident; + /** If this is a one-hop connection, tracks the state of the directory guard * for this connection (if any). */ struct circuit_guard_state_t *guard_state; @@ -3186,6 +3199,10 @@ typedef struct origin_circuit_t { /** Holds all rendezvous data on either client or service side. */ rend_data_t *rend_data; + /** Holds hidden service identifier on either client or service side. This + * is for both introduction and rendezvous circuit. */ + hs_ident_circuit_t *hs_ident; + /** Holds the data that the entry guard system uses to track the * status of the guard this circuit is using, and thereby to determine * whether this circuit can be used. */