diff options
author | George Hazan <ghazan@miranda.im> | 2020-03-26 20:45:32 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2020-03-26 20:45:32 +0300 |
commit | 57bf1c3a69d5b52f0f61172ddff50f24dbe8351e (patch) | |
tree | 9702e1a3e848bffb1ff4d71bbf9096b00d9c3596 /protocols/Tox/libtox/src/toxcore/net_crypto.c | |
parent | c89b7af83f86699b0f7b2564d8c301c9f60aaf4e (diff) |
fixes #2286 (Update libtox to 0.2.11)
Diffstat (limited to 'protocols/Tox/libtox/src/toxcore/net_crypto.c')
-rw-r--r-- | protocols/Tox/libtox/src/toxcore/net_crypto.c | 252 |
1 files changed, 134 insertions, 118 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/net_crypto.c b/protocols/Tox/libtox/src/toxcore/net_crypto.c index b53146137c..fb69b7685f 100644 --- a/protocols/Tox/libtox/src/toxcore/net_crypto.c +++ b/protocols/Tox/libtox/src/toxcore/net_crypto.c @@ -1,27 +1,12 @@ -/* - * Functions for the core network crypto. - * - * NOTE: This code has to be perfect. We don't mess around with encryption. +/* SPDX-License-Identifier: GPL-3.0-or-later + * Copyright © 2016-2018 The TokTok team. + * Copyright © 2013 Tox project. */ /* - * Copyright © 2016-2018 The TokTok team. - * Copyright © 2013 Tox project. - * - * This file is part of Tox, the free peer to peer instant messenger. - * - * Tox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tox is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Functions for the core network crypto. * - * You should have received a copy of the GNU General Public License - * along with Tox. If not, see <http://www.gnu.org/licenses/>. + * NOTE: This code has to be perfect. We don't mess around with encryption. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -45,9 +30,21 @@ typedef struct Packet_Data { typedef struct Packets_Array { Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE]; uint32_t buffer_start; - uint32_t buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */ + uint32_t buffer_end; /* packet numbers in array: `{buffer_start, buffer_end)` */ } Packets_Array; +typedef enum Crypto_Conn_State { + CRYPTO_CONN_FREE = 0, /* the connection slot is free. This value is 0 so it is valid after + * `crypto_memzero(...)` of the parent struct + */ + CRYPTO_CONN_NO_CONNECTION, /* the connection is allocated, but not yet used */ + CRYPTO_CONN_COOKIE_REQUESTING, /* we are sending cookie request packets */ + CRYPTO_CONN_HANDSHAKE_SENT, /* we are sending handshake packets */ + CRYPTO_CONN_NOT_CONFIRMED, /* we are sending handshake packets. + * we have received one from the other, but no data */ + CRYPTO_CONN_ESTABLISHED, /* the connection is established */ +} Crypto_Conn_State; + typedef struct Crypto_Connection { uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The real public key of the peer. */ uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ @@ -56,14 +53,7 @@ typedef struct Crypto_Connection { uint8_t sessionsecret_key[CRYPTO_SECRET_KEY_SIZE]; /* Our private key for this session. */ uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */ uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; /* The precomputed shared key from encrypt_precompute. */ - /** - * 0 if no connection, - * 1 we are sending cookie request packets, - * 2 if we are sending handshake packets, - * 3 if connection is not confirmed yet (we have received a handshake but no data packets yet), - * 4 if the connection is established. - */ - Crypto_Conn_State status; + Crypto_Conn_State status; /* See Crypto_Conn_State documentation */ uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */ @@ -125,7 +115,8 @@ typedef struct Crypto_Connection { uint8_t maximum_speed_reached; - pthread_mutex_t mutex; + /* Must be a pointer, because the struct is moved in memory */ + pthread_mutex_t *mutex; dht_pk_cb *dht_pk_callback; void *dht_pk_callback_object; @@ -193,7 +184,9 @@ static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_conn return 1; } - if (c->crypto_connections[crypt_connection_id].status == CRYPTO_CONN_NO_CONNECTION) { + const Crypto_Conn_State status = c->crypto_connections[crypt_connection_id].status; + + if (status == CRYPTO_CONN_NO_CONNECTION || status == CRYPTO_CONN_FREE) { return 1; } @@ -680,28 +673,30 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t int direct_send_attempt = 0; - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id); // TODO(irungentoo): on bad networks, direct connections might not last indefinitely. if (!net_family_is_unspec(ip_port.ip.family)) { bool direct_connected = 0; + + // FIXME(sudden6): handle return value crypto_connection_status(c, crypt_connection_id, &direct_connected, nullptr); if (direct_connected) { if ((uint32_t)sendpacket(dht_get_net(c->dht), ip_port, data, length) == length) { - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); return 0; } - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); return -1; } // TODO(irungentoo): a better way of sending packets directly to confirm the others ip. const uint64_t current_time = mono_time_get(c->mono_time); - if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) > current_time && length < 96) + if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) < current_time && length < 96) || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { if ((uint32_t)sendpacket(dht_get_net(c->dht), ip_port, data, length) == length) { direct_send_attempt = 1; @@ -710,18 +705,18 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t } } - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); pthread_mutex_lock(&c->tcp_mutex); int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); pthread_mutex_unlock(&c->tcp_mutex); - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); if (ret == 0) { conn->last_tcp_sent = current_time_monotonic(c->mono_time); } - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); if (ret == 0 || direct_send_attempt) { return 0; @@ -730,7 +725,7 @@ static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t return -1; } -/** START: Array Related functions **/ +/** START: Array Related functions */ /* Return number of packets in array @@ -994,7 +989,7 @@ static int handle_request_packet(Mono_Time *mono_time, const Logger *log, Packet uint32_t requested = 0; const uint64_t temp_time = current_time_monotonic(mono_time); - uint64_t l_sent_time = ~0; + uint64_t l_sent_time = -1; for (uint32_t i = send_array->buffer_start; i != send_array->buffer_end; ++i) { if (length == 0) { @@ -1050,7 +1045,7 @@ static int handle_request_packet(Mono_Time *mono_time, const Logger *log, Packet return requested; } -/** END: Array Related functions **/ +/** END: Array Related functions */ #define MAX_DATA_DATA_PACKET_SIZE (MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE)) @@ -1073,19 +1068,19 @@ static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_ return -1; } - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); packet[0] = NET_PACKET_CRYPTO_DATA; memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); const int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); if (len + 1 + sizeof(uint16_t) != SIZEOF_VLA(packet)) { - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); return -1; } increment_nonce(conn->sent_nonce); - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); return send_packet_to(c, crypt_connection_id, packet, SIZEOF_VLA(packet)); } @@ -1172,9 +1167,9 @@ static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, cons dt.sent_time = 0; dt.length = length; memcpy(dt.data, data, length); - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); int64_t packet_num = add_data_end_of_buffer(c->log, &conn->send_array, &dt); - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); if (packet_num == -1) { return -1; @@ -1476,7 +1471,18 @@ static void connection_kill(Net_Crypto *c, int crypt_connection_id, void *userda userdata); } + while (1) { /* TODO(irungentoo): is this really the best way to do this? */ + pthread_mutex_lock(&c->connections_mutex); + + if (!c->connection_use_counter) { + break; + } + + pthread_mutex_unlock(&c->connections_mutex); + } + crypto_kill(c, crypt_connection_id); + pthread_mutex_unlock(&c->connections_mutex); } /* Handle a received data packet. @@ -1578,9 +1584,9 @@ static int handle_data_packet_core(Net_Crypto *c, int crypt_connection_id, const } while (1) { - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); int ret = read_data_beg_buffer(c->log, &conn->recv_array, &dt); - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); if (ret == -1) { break; @@ -1748,12 +1754,6 @@ static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) */ static int create_crypto_connection(Net_Crypto *c) { - for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { - return i; - } - } - while (1) { /* TODO(irungentoo): is this really the best way to do this? */ pthread_mutex_lock(&c->connections_mutex); @@ -1766,21 +1766,42 @@ static int create_crypto_connection(Net_Crypto *c) int id = -1; - if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { - id = c->crypto_connections_length; - ++c->crypto_connections_length; - memset(&c->crypto_connections[id], 0, sizeof(Crypto_Connection)); + for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status == CRYPTO_CONN_FREE) { + id = i; + break; + } + } + + if (id == -1) { + if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { + id = c->crypto_connections_length; + ++c->crypto_connections_length; + memset(&c->crypto_connections[id], 0, sizeof(Crypto_Connection)); + } + } + + if (id != -1) { // Memsetting float/double to 0 is non-portable, so we explicitly set them to 0 c->crypto_connections[id].packet_recv_rate = 0; c->crypto_connections[id].packet_send_rate = 0; c->crypto_connections[id].last_packets_left_rem = 0; c->crypto_connections[id].packet_send_rate_requested = 0; c->crypto_connections[id].last_packets_left_requested_rem = 0; + c->crypto_connections[id].mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t)); - if (pthread_mutex_init(&c->crypto_connections[id].mutex, nullptr) != 0) { + if (c->crypto_connections[id].mutex == nullptr) { pthread_mutex_unlock(&c->connections_mutex); return -1; } + + if (pthread_mutex_init(c->crypto_connections[id].mutex, nullptr) != 0) { + free(c->crypto_connections[id].mutex); + pthread_mutex_unlock(&c->connections_mutex); + return -1; + } + + c->crypto_connections[id].status = CRYPTO_CONN_NO_CONNECTION; } pthread_mutex_unlock(&c->connections_mutex); @@ -1794,21 +1815,29 @@ static int create_crypto_connection(Net_Crypto *c) */ static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) { - if (crypt_connection_id_not_valid(c, crypt_connection_id)) { + if ((uint32_t)crypt_connection_id >= c->crypto_connections_length) { + return -1; + } + + if (c->crypto_connections == nullptr) { + return -1; + } + + const Crypto_Conn_State status = c->crypto_connections[crypt_connection_id].status; + + if (status == CRYPTO_CONN_FREE) { return -1; } uint32_t i; - /* Keep mutex, only destroy it when connection is realloced out. */ - pthread_mutex_t mutex = c->crypto_connections[crypt_connection_id].mutex; + pthread_mutex_destroy(c->crypto_connections[crypt_connection_id].mutex); + free(c->crypto_connections[crypt_connection_id].mutex); crypto_memzero(&c->crypto_connections[crypt_connection_id], sizeof(Crypto_Connection)); - c->crypto_connections[crypt_connection_id].mutex = mutex; + /* check if we can resize the connections array */ for (i = c->crypto_connections_length; i != 0; --i) { - if (c->crypto_connections[i - 1].status == CRYPTO_CONN_NO_CONNECTION) { - pthread_mutex_destroy(&c->crypto_connections[i - 1].mutex); - } else { + if (c->crypto_connections[i - 1].status != CRYPTO_CONN_FREE) { break; } } @@ -1829,10 +1858,12 @@ static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) static int getcryptconnection_id(const Net_Crypto *c, const uint8_t *public_key) { for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { - if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION) { - if (public_key_cmp(public_key, c->crypto_connections[i].public_key) == 0) { - return i; - } + if (crypt_connection_id_not_valid(c, i)) { + continue; + } + + if (public_key_cmp(public_key, c->crypto_connections[i].public_key) == 0) { + return i; } } @@ -1975,6 +2006,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; if (n_c->cookie_length != COOKIE_LENGTH) { + wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -1983,6 +2015,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) pthread_mutex_unlock(&c->tcp_mutex); if (connection_number_tcp == -1) { + wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -1999,7 +2032,7 @@ int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) pthread_mutex_lock(&c->tcp_mutex); kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); pthread_mutex_unlock(&c->tcp_mutex); - conn->status = CRYPTO_CONN_NO_CONNECTION; + wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -2039,6 +2072,7 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const u pthread_mutex_unlock(&c->tcp_mutex); if (connection_number_tcp == -1) { + wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -2062,7 +2096,7 @@ int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const u pthread_mutex_lock(&c->tcp_mutex); kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); pthread_mutex_unlock(&c->tcp_mutex); - conn->status = CRYPTO_CONN_NO_CONNECTION; + wipe_crypto_connection(c, crypt_connection_id); return -1; } @@ -2259,19 +2293,24 @@ static void do_tcp(Net_Crypto *c, void *userdata) continue; } - if (conn->status == CRYPTO_CONN_ESTABLISHED) { - bool direct_connected = 0; - crypto_connection_status(c, i, &direct_connected, nullptr); + if (conn->status != CRYPTO_CONN_ESTABLISHED) { + continue; + } - if (direct_connected) { - pthread_mutex_lock(&c->tcp_mutex); - set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0); - pthread_mutex_unlock(&c->tcp_mutex); - } else { - pthread_mutex_lock(&c->tcp_mutex); - set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1); - pthread_mutex_unlock(&c->tcp_mutex); - } + bool direct_connected = 0; + + if (!crypto_connection_status(c, i, &direct_connected, nullptr)) { + continue; + } + + if (direct_connected) { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0); + pthread_mutex_unlock(&c->tcp_mutex); + } else { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1); + pthread_mutex_unlock(&c->tcp_mutex); } } } @@ -2425,7 +2464,7 @@ static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet return -1; } - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); if (net_family_is_ipv4(source.ip.family)) { conn->direct_lastrecv_timev4 = mono_time_get(c->mono_time); @@ -2433,7 +2472,7 @@ static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet conn->direct_lastrecv_timev6 = mono_time_get(c->mono_time); } - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); return 0; } @@ -2459,7 +2498,7 @@ static void send_crypto_packets(Net_Crypto *c) { const uint64_t temp_time = current_time_monotonic(c->mono_time); double total_send_rate = 0; - uint32_t peak_request_packet_interval = ~0; + uint32_t peak_request_packet_interval = -1; for (uint32_t i = 0; i < c->crypto_connections_length; ++i) { Crypto_Connection *conn = get_crypto_connection(c, i); @@ -2542,6 +2581,7 @@ static void send_crypto_packets(Net_Crypto *c) (CONGESTION_QUEUE_ARRAY_SIZE * CONGESTION_LAST_SENT_ARRAY_SIZE); bool direct_connected = 0; + /* return value can be ignored since the `if` above ensures the connection is established */ crypto_connection_status(c, i, &direct_connected, nullptr); /* When switching from TCP to UDP, don't change the packet send rate for CONGESTION_EVENT_TIMEOUT ms. */ @@ -2667,7 +2707,7 @@ static void send_crypto_packets(Net_Crypto *c) } } - c->current_sleep_time = ~0; + c->current_sleep_time = -1; uint32_t sleep_time = peak_request_packet_interval; if (c->current_sleep_time > sleep_time) { @@ -2824,10 +2864,10 @@ int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t int ret = -1; if (conn) { - pthread_mutex_lock(&conn->mutex); + pthread_mutex_lock(conn->mutex); uint32_t buffer_start = conn->recv_array.buffer_start; uint32_t buffer_end = conn->send_array.buffer_end; - pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(conn->mutex); ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length); } @@ -2845,16 +2885,6 @@ int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t */ int crypto_kill(Net_Crypto *c, int crypt_connection_id) { - while (1) { /* TODO(irungentoo): is this really the best way to do this? */ - pthread_mutex_lock(&c->connections_mutex); - - if (!c->connection_use_counter) { - break; - } - - pthread_mutex_unlock(&c->connections_mutex); - } - Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); int ret = -1; @@ -2876,23 +2906,16 @@ int crypto_kill(Net_Crypto *c, int crypt_connection_id) ret = wipe_crypto_connection(c, crypt_connection_id); } - pthread_mutex_unlock(&c->connections_mutex); - return ret; } -/* return one of CRYPTO_CONN_* values indicating the state of the connection. - * - * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. - * sets online_tcp_relays to the number of connected tcp relays this connection has. - */ -Crypto_Conn_State crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, - unsigned int *online_tcp_relays) +bool crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, + unsigned int *online_tcp_relays) { Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); if (conn == nullptr) { - return CRYPTO_CONN_NO_CONNECTION; + return false; } if (direct_connected) { @@ -2913,7 +2936,7 @@ Crypto_Conn_State crypto_connection_status(const Net_Crypto *c, int crypt_connec *online_tcp_relays = tcp_connection_to_online_tcp_relays(c->tcp_c, conn->connection_number_tcp); } - return conn->status; + return true; } void new_keys(Net_Crypto *c) @@ -3002,10 +3025,6 @@ static void kill_timedout(Net_Crypto *c, void *userdata) continue; } - if (conn->status == CRYPTO_CONN_NO_CONNECTION) { - continue; - } - if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES) { @@ -3036,9 +3055,6 @@ uint32_t crypto_run_interval(const Net_Crypto *c) /* Main loop. */ void do_net_crypto(Net_Crypto *c, void *userdata) { - if (c == nullptr) // !!!!!!!!!!!!!!!!! - return; - kill_timedout(c, userdata); do_tcp(c, userdata); send_crypto_packets(c); |