From 22a6b5706593d222bfc602859dbccd7beb5231ed Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 28 Mar 2012 00:55:39 +0200 Subject: Make crypto handshake with floating peers work --- src/handshake.c | 2 +- src/peer.c | 5 + src/peer.h | 3 +- src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c | 125 ++++++++++++++++-------- src/protocol_null.c | 2 +- 5 files changed, 94 insertions(+), 43 deletions(-) diff --git a/src/handshake.c b/src/handshake.c index 29ed692..735a80c 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -211,7 +211,7 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b switch (reply_code) { case REPLY_SUCCESS: pr_info(ctx, "Handshake with %P successful.", peer); - fastd_peer_set_established(ctx, peer); + fastd_peer_set_established(peer); ctx->conf->protocol->init_peer(ctx, peer); break; diff --git a/src/peer.c b/src/peer.c index f2f79dd..9eeb9f4 100644 --- a/src/peer.c +++ b/src/peer.c @@ -134,9 +134,14 @@ fastd_peer* fastd_peer_add_temp(fastd_context *ctx, const fastd_peer_address *ad fastd_peer* fastd_peer_merge(fastd_context *ctx, fastd_peer *perm_peer, fastd_peer *temp_peer) { pr_debug(ctx, "merging peer %P into %P", temp_peer, perm_peer); + ctx->conf->protocol->free_peer_state(ctx, perm_peer); + perm_peer->address = temp_peer->address; perm_peer->state = fastd_peer_is_established(temp_peer) ? STATE_ESTABLISHED : STATE_WAIT; perm_peer->seen = temp_peer->seen; + perm_peer->protocol_state = temp_peer->protocol_state; + + temp_peer->protocol_state = NULL; int i; for (i = 0; i < ctx->n_eth_addr; i++) { diff --git a/src/peer.h b/src/peer.h index 02aa6de..d68d830 100644 --- a/src/peer.h +++ b/src/peer.h @@ -98,7 +98,7 @@ static inline bool fastd_peer_is_established(const fastd_peer *peer) { return (peer->state == STATE_ESTABLISHED || peer->state == STATE_TEMP_ESTABLISHED); } -static inline void fastd_peer_set_established(fastd_context *ctx, fastd_peer *peer) { +static inline void fastd_peer_set_established(fastd_peer *peer) { switch(peer->state) { case STATE_WAIT: peer->state = STATE_ESTABLISHED; @@ -109,7 +109,6 @@ static inline void fastd_peer_set_established(fastd_context *ctx, fastd_peer *pe break; default: - pr_warn(ctx, "tried to set an already established connection to established"); return; } } diff --git a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c index 8ef0efb..9610d7b 100644 --- a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c +++ b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c @@ -79,6 +79,8 @@ struct _fastd_protocol_peer_config { }; typedef struct _protocol_handshake { + const fastd_peer_config *peer_config; + handshake_state state; ecc_secret_key_256 secret_key; ecc_public_key_256 public_key; @@ -250,7 +252,7 @@ static inline void free_handshake(protocol_handshake *handshake) { } } -static void new_handshake(fastd_context *ctx, fastd_peer *peer, bool initiate) { +static void new_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiate) { protocol_handshake **handshake; if (initiate) @@ -262,6 +264,8 @@ static void new_handshake(fastd_context *ctx, fastd_peer *peer, bool initiate) { *handshake = malloc(sizeof(protocol_handshake)); + (*handshake)->peer_config = peer_config; + (*handshake)->state = HANDSHAKE_STATE_INIT; fastd_random_bytes(ctx, (*handshake)->secret_key.s, 32, false); @@ -280,22 +284,25 @@ static void protocol_init_peer(fastd_context *ctx, fastd_peer *peer) { return; } + if (fastd_peer_is_temporary(peer)) { + pr_warn(ctx, "trying to initialize session for temporary peer %P", peer); + return; + } + create_peer_state(ctx, peer); - if (!fastd_peer_is_temporary(peer)) { - new_handshake(ctx, peer, true); + new_handshake(ctx, peer, peer->config, true); - fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_init_packet), 0, 0); - protocol_handshake_init_packet *packet = buffer.data; + fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_init_packet), 0, 0); + protocol_handshake_init_packet *packet = buffer.data; - memset(packet->common.noncepad, 0, NONCEBYTES); - packet->common.type = HANDSHAKE_PACKET_INIT; - memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->common.receipient_key, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->handshake_key, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); + memset(packet->common.noncepad, 0, NONCEBYTES); + packet->common.type = HANDSHAKE_PACKET_INIT; + memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->common.receipient_key, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->handshake_key, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); - fastd_task_put_send(ctx, peer, buffer); - } + fastd_task_put_send(ctx, peer, buffer); } static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { @@ -307,7 +314,7 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { memcpy(hashinput, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(hashinput+2*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(hashinput+3*PUBLICKEYBYTES, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput+3*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); crypto_hash_sha256(hashbuf, hashinput, 4*PUBLICKEYBYTES); @@ -323,7 +330,7 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { ecc_25519_secret_add(&s, &eb, &peer->protocol_state->accepting_handshake->secret_key); ecc_25519_work work, workX; - ecc_25519_load(&work, &peer->config->protocol_config->public_key); + ecc_25519_load(&work, &peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key); ecc_25519_load(&workX, &peer->protocol_state->accepting_handshake->peer_key); ecc_25519_scalarmult(&work, &d, &work); @@ -344,7 +351,7 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { memset(packet->common.noncepad, 0, NONCEBYTES); packet->common.type = HANDSHAKE_PACKET_RESPONSE; memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->common.receipient_key, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->common.receipient_key, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(packet->handshake_key, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(packet->handshake_key2, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES); @@ -355,7 +362,7 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { peer->protocol_state->accepting_handshake->state = HANDSHAKE_STATE_RESPONSE; } -static void establish(fastd_context *ctx, fastd_peer *peer, bool initiator) { +static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiator) { int i; peer->protocol_state->session.valid = true; @@ -369,6 +376,16 @@ static void establish(fastd_context *ctx, fastd_peer *peer, bool initiator) { } pr_info(ctx, "Connection with %P established.", peer); + + if (fastd_peer_is_temporary(peer)) { + fastd_peer *perm_peer; + for (perm_peer = ctx->peers; perm_peer; perm_peer = perm_peer->next) { + if (perm_peer->config == peer_config) { + fastd_peer_merge(ctx, perm_peer, peer); + break; + } + } + } } static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMACBYTES]) { @@ -379,7 +396,7 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA memcpy(hashinput, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); - memcpy(hashinput+2*PUBLICKEYBYTES, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput+2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+3*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); crypto_hash_sha256(hashbuf, hashinput, 4*PUBLICKEYBYTES); @@ -396,7 +413,7 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA ecc_25519_secret_add(&s, &da, &peer->protocol_state->initiating_handshake->secret_key); ecc_25519_work work, workY; - ecc_25519_load(&work, &peer->config->protocol_config->public_key); + ecc_25519_load(&work, &peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key); ecc_25519_load(&workY, &peer->protocol_state->initiating_handshake->peer_key); ecc_25519_scalarmult(&work, &e, &work); @@ -408,7 +425,7 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA memcpy(hashinput+4*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->sigma.p, PUBLICKEYBYTES); crypto_hash_sha256(peer->protocol_state->initiating_handshake->shared_handshake_key, hashinput, 5*PUBLICKEYBYTES); - memcpy(hashinput, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES); if(crypto_auth_hmacsha256_verify(t, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key) != 0) { @@ -425,7 +442,7 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA memset(packet->common.noncepad, 0, NONCEBYTES); packet->common.type = HANDSHAKE_PACKET_FINISH; memcpy(packet->common.sender_key, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(packet->common.receipient_key, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(packet->common.receipient_key, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(packet->handshake_key, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(packet->handshake_key2, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); @@ -439,17 +456,17 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA memcpy(hashinput, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(hashinput+2*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); - memcpy(hashinput+3*PUBLICKEYBYTES, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput+3*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+4*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->sigma.p, PUBLICKEYBYTES); crypto_hash_sha256(peer->protocol_state->session.key, hashinput, 5*PUBLICKEYBYTES); - establish(ctx, peer, true); + establish(ctx, peer, peer->protocol_state->initiating_handshake->peer_config, true); } static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMACBYTES]) { uint8_t hashinput[5*PUBLICKEYBYTES]; - memcpy(hashinput, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES); if(crypto_auth_hmacsha256_verify(t, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key) != 0) { @@ -462,12 +479,32 @@ static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_ memcpy(hashinput, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES); - memcpy(hashinput+2*PUBLICKEYBYTES, peer->config->protocol_config->public_key.p, PUBLICKEYBYTES); + memcpy(hashinput+2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+3*PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+4*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->sigma.p, PUBLICKEYBYTES); crypto_hash_sha256(peer->protocol_state->session.key, hashinput, 5*PUBLICKEYBYTES); - establish(ctx, peer, false); + establish(ctx, peer, peer->protocol_state->accepting_handshake->peer_config, false); +} + +static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer *peer, const protocol_handshake_packet *packet) { + if (peer->config) { + if (memcmp(peer->config->protocol_config->public_key.p, packet->common.sender_key, PUBLICKEYBYTES) == 0) + return peer->config; + } + + if (fastd_peer_is_temporary(peer) || fastd_peer_is_floating(peer)) { + fastd_peer_config *config; + for (config = ctx->conf->peers; config; config = config->next) { + if (!fastd_peer_config_is_floating(config)) + continue; + + if (memcmp(config->protocol_config->public_key.p, packet->common.sender_key, PUBLICKEYBYTES) == 0) + return config; + } + } + + return NULL; } static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { @@ -483,11 +520,6 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf protocol_handshake_packet *packet = buffer.data; - if (!peer->config) { - pr_debug(ctx, "received protocol handshake from temporary peer %P", peer); - goto end; - } - if (!peer->protocol_state) create_peer_state(ctx, peer); @@ -496,10 +528,7 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf goto end; } - if (memcmp(peer->config->protocol_config->public_key.p, packet->common.sender_key, PUBLICKEYBYTES) != 0) { - pr_debug(ctx, "received protocol handshake with wrong sender key from %P", peer); - goto end; - } + const fastd_peer_config *peer_config = match_sender_key(ctx, peer, packet); switch (packet->common.type) { case HANDSHAKE_PACKET_INIT: @@ -508,12 +537,17 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf goto end; } + if (!peer_config) { + pr_debug(ctx, "received protocol handshake init with wrong sender key from %P", peer); + goto end; + } + pr_debug(ctx, "received protocol handshake init from %P", peer); - new_handshake(ctx, peer, false); + new_handshake(ctx, peer, peer_config, false); memcpy(peer->protocol_state->accepting_handshake->peer_key.p, packet->init.handshake_key, PUBLICKEYBYTES); - fastd_peer_set_established(ctx, peer); + fastd_peer_set_established(peer); respond_handshake(ctx, peer); break; @@ -529,6 +563,11 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf goto end; } + if (peer->protocol_state->initiating_handshake->peer_config != peer_config) { + pr_debug(ctx, "received protocol handshake response with wrong sender key from %P", peer); + goto end; + } + if (memcmp(peer->protocol_state->initiating_handshake->public_key.p, packet->response.handshake_key, PUBLICKEYBYTES) != 0) { pr_debug(ctx, "received protocol handshake response with unexpected handshake key from %P", peer); goto end; @@ -552,6 +591,11 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf goto end; } + if (peer->protocol_state->accepting_handshake->peer_config != peer_config) { + pr_debug(ctx, "received protocol handshake finish with wrong sender key from %P", peer); + goto end; + } + if (memcmp(peer->protocol_state->accepting_handshake->public_key.p, packet->finish.handshake_key, PUBLICKEYBYTES) != 0) { pr_debug(ctx, "received protocol handshake finish with unexpected handshake key from %P", peer); goto end; @@ -596,6 +640,7 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf if (crypto_secretbox_xsalsa20poly1305_open(recv_buffer.data, buffer.data, buffer.len, nonce, peer->protocol_state->session.key) != 0) { pr_debug(ctx, "verification failed for packet received from %P", peer); + fastd_buffer_free(recv_buffer); goto end; } @@ -637,10 +682,12 @@ static void protocol_send(fastd_context *ctx, fastd_peer *peer, fastd_buffer buf } static void protocol_free_peer_state(fastd_context *ctx, fastd_peer *peer) { - free_handshake(peer->protocol_state->initiating_handshake); - free_handshake(peer->protocol_state->accepting_handshake); + if (peer->protocol_state) { + free_handshake(peer->protocol_state->initiating_handshake); + free_handshake(peer->protocol_state->accepting_handshake); - free(peer->protocol_state); + free(peer->protocol_state); + } } diff --git a/src/protocol_null.c b/src/protocol_null.c index 24cb58b..cdf6694 100644 --- a/src/protocol_null.c +++ b/src/protocol_null.c @@ -58,7 +58,7 @@ static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buf if (!fastd_peer_is_established(peer)) { pr_info(ctx, "Connection with %P established.", peer); - fastd_peer_set_established(ctx, peer); + fastd_peer_set_established(peer); } if (fastd_peer_is_temporary(peer)) { -- cgit v1.2.3