From 6f1f926bb82b7a4bb1fd3cfc981c7596843a9a6e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 30 Mar 2012 04:36:50 +0200 Subject: Make ecfxp protocol work with new handshake --- src/handshake.c | 52 +-- src/handshake.h | 34 +- src/peer.c | 2 + src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c | 412 +++++++++++------------- src/protocol_null.c | 12 +- 5 files changed, 240 insertions(+), 272 deletions(-) diff --git a/src/handshake.c b/src/handshake.c index fcec5af..ce8895d 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -39,6 +39,11 @@ static const char const *RECORD_TYPES[RECORD_MAX] = { "flags", "mode", "protocol name", + "(protocol specific 1)", + "(protocol specific 2)", + "(protocol specific 3)", + "(protocol specific 4)", + "(protocol specific 5)", }; static const char const *REPLY_TYPES[REPLY_MAX] = { @@ -49,31 +54,6 @@ static const char const *REPLY_TYPES[REPLY_MAX] = { #define AS_UINT8(ptr) (*(uint8_t*)(ptr).data) -static inline void handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) { - if ((uint8_t*)buffer->data + buffer->len + 2 + len > (uint8_t*)buffer->base + buffer->base_len) - exit_bug(ctx, "not enough buffer allocated for handshake"); - - uint8_t *dst = (uint8_t*)buffer->data + buffer->len; - - dst[0] = type; - dst[1] = len; - memcpy(dst+2, data, len); - - buffer->len += 2 + len; -} - -static inline void handshake_add_uint8(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, uint8_t value) { - if ((uint8_t*)buffer->data + buffer->len + 3 > (uint8_t*)buffer->base + buffer->base_len) - exit_bug(ctx, "not enough buffer allocated for handshake"); - - uint8_t *dst = (uint8_t*)buffer->data + buffer->len; - - dst[0] = type; - dst[1] = 1; - dst[2] = value; - - buffer->len += 3; -} fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size_t tail_space) { size_t protocol_len = strlen(ctx->conf->protocol->name); @@ -87,10 +67,10 @@ fastd_buffer fastd_handshake_new_init(fastd_context *ctx, fastd_peer *peer, size request->req_id = ++peer->last_req_id; request->rsv = 0; - handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, 1); - handshake_add_uint8(ctx, &buffer, RECORD_MODE, ctx->conf->mode); + fastd_handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, 1); + fastd_handshake_add_uint8(ctx, &buffer, RECORD_MODE, ctx->conf->mode); - handshake_add(ctx, &buffer, RECORD_PROTOCOL_NAME, protocol_len, ctx->conf->protocol->name); + fastd_handshake_add(ctx, &buffer, RECORD_PROTOCOL_NAME, protocol_len, ctx->conf->protocol->name); return buffer; } @@ -105,8 +85,8 @@ fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, con request->req_id = handshake->req_id; request->rsv = 0; - handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE])+1); - handshake_add_uint8(ctx, &buffer, RECORD_REPLY_CODE, 0); + fastd_handshake_add_uint8(ctx, &buffer, RECORD_HANDSHAKE_TYPE, AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE])+1); + fastd_handshake_add_uint8(ctx, &buffer, RECORD_REPLY_CODE, 0); return buffer; } @@ -145,7 +125,9 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b if (handshake.records[RECORD_HANDSHAKE_TYPE].length != 1) goto end_free; - if (AS_UINT8(handshake.records[RECORD_HANDSHAKE_TYPE]) == 1) { + handshake.type = AS_UINT8(handshake.records[RECORD_HANDSHAKE_TYPE]); + + if (handshake.type == 1) { uint8_t reply_code = REPLY_SUCCESS; uint8_t error_detail = 0; @@ -182,16 +164,16 @@ void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer b reply->req_id = packet->req_id; reply->rsv = 0; - handshake_add_uint8(ctx, &reply_buffer, RECORD_HANDSHAKE_TYPE, 2); - handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code); - handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail); + fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_HANDSHAKE_TYPE, 2); + fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_REPLY_CODE, reply_code); + fastd_handshake_add_uint8(ctx, &reply_buffer, RECORD_ERROR_DETAIL, error_detail); } else { ctx->conf->protocol->handshake_handle(ctx, peer, &handshake); } } else { - if ((AS_UINT8(handshake.records[RECORD_HANDSHAKE_TYPE]) & 1) == 0) { + if ((handshake.type & 1) == 0) { if (packet->req_id != peer->last_req_id) { pr_warn(ctx, "received handshake reply with request ID %u from %P while %u was expected", packet->req_id, peer, peer->last_req_id); goto end_free; diff --git a/src/handshake.h b/src/handshake.h index 064e167..c59d141 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -28,7 +28,6 @@ #define _FASTD_HANDSHAKE_H_ #include "fastd.h" -#include "packet.h" typedef enum _fastd_handshake_record_type { @@ -38,6 +37,11 @@ typedef enum _fastd_handshake_record_type { RECORD_FLAGS, RECORD_MODE, RECORD_PROTOCOL_NAME, + RECORD_PROTOCOL1, + RECORD_PROTOCOL2, + RECORD_PROTOCOL3, + RECORD_PROTOCOL4, + RECORD_PROTOCOL5, RECORD_MAX, } fastd_handshake_record_type; @@ -56,6 +60,7 @@ typedef struct _fastd_handshake_record { struct _fastd_handshake { uint8_t req_id; + uint8_t type; fastd_handshake_record records[RECORD_MAX]; }; @@ -66,4 +71,31 @@ fastd_buffer fastd_handshake_new_reply(fastd_context *ctx, fastd_peer *peer, con void fastd_handshake_handle(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer); +static inline void fastd_handshake_add(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, size_t len, const void *data) { + if ((uint8_t*)buffer->data + buffer->len + 2 + len > (uint8_t*)buffer->base + buffer->base_len) + exit_bug(ctx, "not enough buffer allocated for handshake"); + + uint8_t *dst = (uint8_t*)buffer->data + buffer->len; + + dst[0] = type; + dst[1] = len; + memcpy(dst+2, data, len); + + buffer->len += 2 + len; +} + +static inline void fastd_handshake_add_uint8(fastd_context *ctx, fastd_buffer *buffer, fastd_handshake_record_type type, uint8_t value) { + if ((uint8_t*)buffer->data + buffer->len + 3 > (uint8_t*)buffer->base + buffer->base_len) + exit_bug(ctx, "not enough buffer allocated for handshake"); + + uint8_t *dst = (uint8_t*)buffer->data + buffer->len; + + dst[0] = type; + dst[1] = 1; + dst[2] = value; + + buffer->len += 3; +} + + #endif /* _FASTD_HANDSHAKE_H_ */ diff --git a/src/peer.c b/src/peer.c index ea53e95..ff72c8e 100644 --- a/src/peer.c +++ b/src/peer.c @@ -169,6 +169,8 @@ fastd_peer* fastd_peer_set_established_merge(fastd_context *ctx, fastd_peer *per fastd_peer_reset(ctx, temp_peer); + pr_info(ctx, "Connection with %P established.", perm_peer); + return perm_peer; } diff --git a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c index 449a1c6..5b05041 100644 --- a/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c +++ b/src/protocol_ec25519_fhmqvc_xsalsa20_poly1305.c @@ -27,6 +27,7 @@ #define _GNU_SOURCE #include "fastd.h" +#include "handshake.h" #include "peer.h" #include "task.h" @@ -105,39 +106,12 @@ struct _fastd_protocol_peer_state { protocol_handshake *accepting_handshake; }; -typedef enum _handshake_packet_type { - HANDSHAKE_PACKET_INIT = 0, - HANDSHAKE_PACKET_RESPONSE, - HANDSHAKE_PACKET_FINISH -} handshake_packet_type; - -typedef struct __attribute__ ((__packed__)) _protocol_handshake_packet_common { - uint8_t noncepad[NONCEBYTES]; - uint8_t type; - - uint8_t sender_key[PUBLICKEYBYTES]; - uint8_t receipient_key[PUBLICKEYBYTES]; -} protocol_handshake_packet_common; - -typedef struct __attribute__ ((__packed__)) _protocol_handshake_init_packet { - protocol_handshake_packet_common common; - uint8_t handshake_key[PUBLICKEYBYTES]; -} protocol_handshake_init_packet; - -typedef struct __attribute__ ((__packed__)) _protocol_handshake_response_finish_packet { - protocol_handshake_packet_common common; - uint8_t handshake_key[PUBLICKEYBYTES]; - uint8_t handshake_key2[PUBLICKEYBYTES]; - uint8_t t[HMACBYTES]; -} protocol_handshake_response_packet, protocol_handshake_finish_packet; - -typedef union _protocol_handshake_packet { - protocol_handshake_packet_common common; - protocol_handshake_init_packet init; - protocol_handshake_response_packet response; - protocol_handshake_finish_packet finish; -} protocol_handshake_packet; +#define RECORD_SENDER_KEY RECORD_PROTOCOL1 +#define RECORD_RECEIPIENT_KEY RECORD_PROTOCOL2 +#define RECORD_SENDER_HANDSHAKE_KEY RECORD_PROTOCOL3 +#define RECORD_RECEIPIENT_HANDSHAKE_KEY RECORD_PROTOCOL4 +#define RECORD_T RECORD_PROTOCOL5 static inline bool read_key(uint8_t key[32], const char *hexkey) { @@ -235,7 +209,10 @@ static size_t protocol_min_decrypt_head_space(fastd_context *ctx) { return (crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES - NONCEBYTES); } -static void create_peer_state(fastd_context *ctx, fastd_peer *peer) { +static void init_peer_state(fastd_context *ctx, fastd_peer *peer) { + if (peer->protocol_state) + return; + peer->protocol_state = malloc(sizeof(fastd_protocol_peer_state)); peer->protocol_state->old_session.valid = false; @@ -251,7 +228,7 @@ static inline void free_handshake(protocol_handshake *handshake) { } } -static void new_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiate) { +static protocol_handshake* new_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiate) { protocol_handshake **handshake; if (initiate) @@ -273,50 +250,39 @@ static void new_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_peer ecc_25519_work work; ecc_25519_scalarmult_base(&work, &(*handshake)->secret_key); ecc_25519_store(&(*handshake)->public_key, &work); -} -static void protocol_handshake_init(fastd_context *ctx, fastd_peer *peer) { + return *handshake; } -static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { -} - -#if 0 -static void protocol_init_peer(fastd_context *ctx, fastd_peer *peer) { - pr_info(ctx, "Initializing session with %P...", peer); +static void protocol_handshake_init(fastd_context *ctx, fastd_peer *peer) { + init_peer_state(ctx, peer); - if (peer->protocol_state) { - pr_warn(ctx, "trying to reinitialize session with %P", peer); - return; - } + fastd_buffer buffer = fastd_handshake_new_init(ctx, peer, 3*(2+PUBLICKEYBYTES) /* sender key, receipient key, handshake key */); - if (fastd_peer_is_temporary(peer)) { - pr_warn(ctx, "trying to initialize session for temporary peer %P", peer); - return; - } + protocol_handshake *handshake = new_handshake(ctx, peer, peer->config, true); - create_peer_state(ctx, peer); + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p); - new_handshake(ctx, peer, peer->config, true); + if (handshake->peer_config) + fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, handshake->peer_config->protocol_config->public_key.p); + else + pr_debug(ctx, "sending handshake to unknown peer %P", peer); - fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_init_packet), 0, 0); - protocol_handshake_init_packet *packet = buffer.data; + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, handshake->public_key.p); - 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_handshake(ctx, peer, buffer); +} - fastd_task_put_send(ctx, peer, buffer); +static inline bool has_field(const fastd_handshake *handshake, uint8_t type, size_t length) { + return (handshake->records[type].length == length); } -#endif -static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { - pr_info(ctx, "Responding protocol handshake with %P...", peer); +static void respond_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { + pr_info(ctx, "Responding handshake with %P...", peer); uint8_t hashinput[5*PUBLICKEYBYTES]; uint8_t hashbuf[HASHBYTES]; + uint8_t hmacbuf[HMACBYTES]; memcpy(hashinput, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p, PUBLICKEYBYTES); @@ -355,25 +321,36 @@ static void respond_handshake(fastd_context *ctx, fastd_peer *peer) { memcpy(hashinput, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->public_key.p, PUBLICKEYBYTES); - fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_response_packet), 0, 0); - protocol_handshake_response_packet *packet = buffer.data; + crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key); - 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->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); + fastd_buffer buffer = fastd_handshake_new_reply(ctx, peer, handshake, 4*(2+PUBLICKEYBYTES) + 2+HMACBYTES); - crypto_auth_hmacsha256(packet->t, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key); + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->peer_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf); - fastd_task_put_send(ctx, peer, buffer); + fastd_task_put_send_handshake(ctx, peer, buffer); peer->protocol_state->accepting_handshake->state = HANDSHAKE_STATE_RESPONSE; } -static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiator) { +static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_config *peer_config, bool initiator, + const ecc_public_key_256 *A, const ecc_public_key_256 *B, const ecc_public_key_256 *X, + const ecc_public_key_256 *Y, const ecc_public_key_256 *sigma) { int i; + uint8_t hashinput[5*PUBLICKEYBYTES]; + + if (peer->protocol_state->session.valid) + peer->protocol_state->old_session = peer->protocol_state->session; + + memcpy(hashinput, X->p, PUBLICKEYBYTES); + memcpy(hashinput+PUBLICKEYBYTES, Y->p, PUBLICKEYBYTES); + memcpy(hashinput+2*PUBLICKEYBYTES, A->p, PUBLICKEYBYTES); + memcpy(hashinput+3*PUBLICKEYBYTES, B->p, PUBLICKEYBYTES); + memcpy(hashinput+4*PUBLICKEYBYTES, sigma->p, PUBLICKEYBYTES); + crypto_hash_sha256(peer->protocol_state->session.key, hashinput, 5*PUBLICKEYBYTES); peer->protocol_state->session.valid = true; peer->protocol_state->session.since = ctx->now; @@ -385,7 +362,7 @@ static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_con peer->protocol_state->session.receive_nonce[i] = 0; } - pr_info(ctx, "Connection with %P established.", peer); + peer->seen = ctx->now; if (peer_config != peer->config) { fastd_peer *perm_peer; @@ -396,13 +373,17 @@ static void establish(fastd_context *ctx, fastd_peer *peer, const fastd_peer_con } } } + else { + fastd_peer_set_established(ctx, peer); + } } -static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMACBYTES]) { +static void finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { pr_info(ctx, "Finishing protocol handshake with %P...", peer); uint8_t hashinput[5*PUBLICKEYBYTES]; uint8_t hashbuf[HASHBYTES]; + uint8_t hmacbuf[HMACBYTES]; memcpy(hashinput, peer->protocol_state->initiating_handshake->peer_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); @@ -441,68 +422,55 @@ static void finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMA 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) { + if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key) != 0) { pr_warn(ctx, "received invalid protocol handshake response from %P", peer); return; } memcpy(hashinput, ctx->conf->protocol_config->public_key.p, PUBLICKEYBYTES); memcpy(hashinput+PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p, PUBLICKEYBYTES); + crypto_auth_hmacsha256(hmacbuf, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key); - fastd_buffer buffer = fastd_buffer_alloc(sizeof(protocol_handshake_finish_packet), 0, 0); - protocol_handshake_finish_packet *packet = buffer.data; - - 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->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); + fastd_buffer buffer = fastd_handshake_new_reply(ctx, peer, handshake, 4*(2+PUBLICKEYBYTES) + 2+HMACBYTES); - crypto_auth_hmacsha256(packet->t, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->shared_handshake_key); + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, ctx->conf->protocol_config->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->public_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES, peer->protocol_state->initiating_handshake->peer_key.p); + fastd_handshake_add(ctx, &buffer, RECORD_T, HMACBYTES, hmacbuf); - fastd_task_put_send(ctx, peer, buffer); - - if (peer->protocol_state->session.valid) - peer->protocol_state->old_session = peer->protocol_state->session; - - 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->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); + fastd_task_put_send_handshake(ctx, peer, buffer); - establish(ctx, peer, peer->protocol_state->initiating_handshake->peer_config, true); + establish(ctx, peer, peer->protocol_state->initiating_handshake->peer_config, true, + &peer->protocol_state->initiating_handshake->public_key, + &peer->protocol_state->initiating_handshake->peer_key, + &ctx->conf->protocol_config->public_key, + &peer->protocol_state->initiating_handshake->peer_config->protocol_config->public_key, + &peer->protocol_state->initiating_handshake->sigma); } -static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, uint8_t t[HMACBYTES]) { - uint8_t hashinput[5*PUBLICKEYBYTES]; +static void handle_finish_handshake(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { + uint8_t hashinput[2*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) { + if(crypto_auth_hmacsha256_verify(handshake->records[RECORD_T].data, hashinput, 2*PUBLICKEYBYTES, peer->protocol_state->accepting_handshake->shared_handshake_key) != 0) { pr_warn(ctx, "received invalid protocol handshake finish from %P", peer); return; } - if (peer->protocol_state->session.valid) - peer->protocol_state->old_session = peer->protocol_state->session; - - 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->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, peer->protocol_state->accepting_handshake->peer_config, false); + establish(ctx, peer, peer->protocol_state->accepting_handshake->peer_config, false, + &peer->protocol_state->accepting_handshake->peer_key, + &peer->protocol_state->accepting_handshake->public_key, + &peer->protocol_state->accepting_handshake->peer_config->protocol_config->public_key, + &ctx->conf->protocol_config->public_key, + &peer->protocol_state->accepting_handshake->sigma); } -static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer *peer, const protocol_handshake_packet *packet) { +static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, const fastd_peer *peer, const unsigned char key[32]) { if (peer->config) { - if (memcmp(peer->config->protocol_config->public_key.p, packet->common.sender_key, PUBLICKEYBYTES) == 0) + if (memcmp(peer->config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) return peer->config; } @@ -512,7 +480,7 @@ static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, cons if (!fastd_peer_config_is_floating(config)) continue; - if (memcmp(config->protocol_config->public_key.p, packet->common.sender_key, PUBLICKEYBYTES) == 0) + if (memcmp(config->protocol_config->public_key.p, key, PUBLICKEYBYTES) == 0) return config; } } @@ -520,148 +488,136 @@ static inline const fastd_peer_config* match_sender_key(fastd_context *ctx, cons return NULL; } -static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { - if (buffer.len < NONCEBYTES) - goto end; - - /* protocol handshake */ - if (is_nonce_zero(buffer.data)) { - if (buffer.len < sizeof(protocol_handshake_packet_common)) { - pr_debug(ctx, "received short protocol handshake from %P", peer); - goto end; - } +static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { + init_peer_state(ctx, peer); - protocol_handshake_packet *packet = buffer.data; + if (!has_field(handshake, RECORD_SENDER_KEY, PUBLICKEYBYTES)) { + pr_debug(ctx, "received handshake without sender key from %P", peer); + return; + } - if (!peer->protocol_state) - create_peer_state(ctx, peer); + const fastd_peer_config *peer_config = match_sender_key(ctx, peer, handshake->records[RECORD_SENDER_KEY].data); - if (memcmp(ctx->conf->protocol_config->public_key.p, packet->common.receipient_key, PUBLICKEYBYTES) != 0) { + if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) { + pr_debug(ctx, "received handshake reply without receipient key from %P", peer); + return; + } + else if(has_field(handshake, RECORD_RECEIPIENT_KEY, PUBLICKEYBYTES)) { + if (memcmp(ctx->conf->protocol_config->public_key.p, handshake->records[RECORD_RECEIPIENT_KEY].data, PUBLICKEYBYTES) != 0) { pr_debug(ctx, "received protocol handshake with wrong receipient key from %P", peer); - goto end; + return; } + } - const fastd_peer_config *peer_config = match_sender_key(ctx, peer, packet); - - switch (packet->common.type) { - case HANDSHAKE_PACKET_INIT: - if (buffer.len < sizeof(protocol_handshake_init_packet)) { - pr_debug(ctx, "received short protocol handshake init from %P", peer); - 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, peer_config, false); - memcpy(peer->protocol_state->accepting_handshake->peer_key.p, packet->init.handshake_key, PUBLICKEYBYTES); - - fastd_peer_set_established(ctx, peer); - respond_handshake(ctx, peer); - - break; - - case HANDSHAKE_PACKET_RESPONSE: - if (buffer.len < sizeof(protocol_handshake_response_packet)) { - pr_debug(ctx, "received short protocol handshake response from %P", peer); - goto end; - } + if (!has_field(handshake, RECORD_SENDER_HANDSHAKE_KEY, PUBLICKEYBYTES)) { + pr_debug(ctx, "received handshake without sender handshake key from %P", peer); + return; + } - if (!peer->protocol_state->initiating_handshake || peer->protocol_state->initiating_handshake->state != HANDSHAKE_STATE_INIT) { - pr_debug(ctx, "received unexpected protocol handshake response from %P", peer); - goto end; - } + if (handshake->type > 1 && !has_field(handshake, RECORD_RECEIPIENT_HANDSHAKE_KEY, PUBLICKEYBYTES)) { + pr_debug(ctx, "received handshake reply without receipient handshake key from %P", peer); + return; + } - 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 (handshake->type > 1 && !has_field(handshake, RECORD_T, HMACBYTES)) { + pr_debug(ctx, "received handshake reply without HMAC from %P", peer); + return; + } - 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; - } + switch(handshake->type) { + case 1: + new_handshake(ctx, peer, peer_config, false); + memcpy(peer->protocol_state->accepting_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES); + respond_handshake(ctx, peer, handshake); + break; + + case 2: + if (!peer->protocol_state->initiating_handshake || peer->protocol_state->initiating_handshake->state != HANDSHAKE_STATE_INIT) { + pr_debug(ctx, "received unexpected handshake response from %P", peer); + return; + } - pr_debug(ctx, "received protocol handshake response from %P", peer); - memcpy(peer->protocol_state->initiating_handshake->peer_key.p, packet->response.handshake_key2, PUBLICKEYBYTES); + if (peer->protocol_state->initiating_handshake->peer_config != peer_config) { + pr_debug(ctx, "received handshake response with wrong sender key from %P", peer); + return; + } - finish_handshake(ctx, peer, packet->response.t); + if (memcmp(peer->protocol_state->initiating_handshake->public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) { + pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P", peer); + return; + } - break; + pr_debug(ctx, "received handshake response from %P", peer); + memcpy(peer->protocol_state->initiating_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES); - case HANDSHAKE_PACKET_FINISH: - if (buffer.len < sizeof(protocol_handshake_finish_packet)) { - pr_debug(ctx, "received short protocol handshake finish from %P", peer); - goto end; - } + finish_handshake(ctx, peer, handshake); + break; - if (!peer->protocol_state->accepting_handshake || peer->protocol_state->accepting_handshake->state != HANDSHAKE_STATE_RESPONSE) { - pr_debug(ctx, "received unexpected protocol handshake finish from %P", peer); - goto end; - } + case 3: + if (!peer->protocol_state->accepting_handshake || peer->protocol_state->accepting_handshake->state != HANDSHAKE_STATE_RESPONSE) { + pr_debug(ctx, "received unexpected protocol handshake finish from %P", peer); + return; + } - 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 (peer->protocol_state->accepting_handshake->peer_config != peer_config) { + pr_debug(ctx, "received protocol handshake finish with wrong sender key from %P", peer); + return; + } - 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; - } + if (memcmp(peer->protocol_state->accepting_handshake->public_key.p, handshake->records[RECORD_RECEIPIENT_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) { + pr_debug(ctx, "received handshake response with unexpected receipient handshake key from %P", peer); + return; + } - if (memcmp(peer->protocol_state->accepting_handshake->peer_key.p, packet->finish.handshake_key2, PUBLICKEYBYTES) != 0) { - pr_debug(ctx, "received protocol handshake finish with unexpected peer handshake key from %P", peer); - goto end; - } + if (memcmp(peer->protocol_state->accepting_handshake->peer_key.p, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES) != 0) { + pr_debug(ctx, "received handshake response with unexpected sender handshake key from %P", peer); + return; + } + handle_finish_handshake(ctx, peer, handshake); + break; + default: + pr_debug(ctx, "received handshake reply with unknown type %u", handshake->type); + } +} - pr_debug(ctx, "received protocol handshake finish from %P", peer); +static void protocol_handle_recv(fastd_context *ctx, fastd_peer *peer, fastd_buffer buffer) { + if (!fastd_peer_is_established(peer)) + goto end; - handle_finish_handshake(ctx, peer, packet->finish.t); - break; + if (buffer.len < NONCEBYTES) + goto end; - default: - pr_debug(ctx, "received protocol handshake with invalid type from %P", peer); - goto end; - } + if (!peer->protocol_state || !peer->protocol_state->session.valid) { + pr_debug(ctx, "received unexpected packet from %P", peer); + goto end; } - else { - if (!peer->protocol_state || !peer->protocol_state->session.valid) { - pr_debug(ctx, "received unexpected non-handshake packet from %P", peer); - goto end; - } - if (!is_nonce_valid(buffer.data, peer->protocol_state->session.receive_nonce)) { - pr_debug(ctx, "received packet with invalid nonce from %P", peer); - goto end; - } + if (!is_nonce_valid(buffer.data, peer->protocol_state->session.receive_nonce)) { + pr_debug(ctx, "received packet with invalid nonce from %P", peer); + goto end; + } - uint8_t nonce[crypto_secretbox_xsalsa20poly1305_NONCEBYTES]; - memcpy(nonce, buffer.data, NONCEBYTES); - memset(nonce+NONCEBYTES, 0, crypto_secretbox_xsalsa20poly1305_NONCEBYTES-NONCEBYTES); + uint8_t nonce[crypto_secretbox_xsalsa20poly1305_NONCEBYTES]; + memcpy(nonce, buffer.data, NONCEBYTES); + memset(nonce+NONCEBYTES, 0, crypto_secretbox_xsalsa20poly1305_NONCEBYTES-NONCEBYTES); - fastd_buffer_pull_head(&buffer, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES-NONCEBYTES); - memset(buffer.data, 0, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES); + fastd_buffer_pull_head(&buffer, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES-NONCEBYTES); + memset(buffer.data, 0, crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES); - fastd_buffer recv_buffer = fastd_buffer_alloc(buffer.len, 0, 0); + fastd_buffer recv_buffer = fastd_buffer_alloc(buffer.len, 0, 0); - 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; - } + 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; + } - fastd_buffer_push_head(&recv_buffer, crypto_secretbox_xsalsa20poly1305_ZEROBYTES); - fastd_task_put_handle_recv(ctx, peer, recv_buffer); + fastd_buffer_push_head(&recv_buffer, crypto_secretbox_xsalsa20poly1305_ZEROBYTES); + fastd_task_put_handle_recv(ctx, peer, recv_buffer); - memcpy(peer->protocol_state->session.receive_nonce, nonce, NONCEBYTES); - } + memcpy(peer->protocol_state->session.receive_nonce, nonce, NONCEBYTES); end: fastd_buffer_free(buffer); diff --git a/src/protocol_null.c b/src/protocol_null.c index 3a85e6c..d9588b3 100644 --- a/src/protocol_null.c +++ b/src/protocol_null.c @@ -34,9 +34,6 @@ #include -#define AS_UINT8(ptr) (*(uint8_t*)(ptr).data) - - static void protocol_init(fastd_context *ctx, fastd_config *conf) { if (conf->n_floating > 1) exit_error(ctx, "with protocol `null' use can't define more than one floating peer"); @@ -56,6 +53,8 @@ static void protocol_handshake_init(fastd_context *ctx, fastd_peer *peer) { } static void establish(fastd_context *ctx, fastd_peer *peer) { + peer->seen = ctx->now; + if (fastd_peer_is_temporary(peer)) { fastd_peer *perm_peer; for (perm_peer = ctx->peers; perm_peer; perm_peer = perm_peer->next) { @@ -77,27 +76,24 @@ static void establish(fastd_context *ctx, fastd_peer *peer) { static void protocol_handshake_handle(fastd_context *ctx, fastd_peer *peer, const fastd_handshake *handshake) { fastd_buffer buffer; - switch(AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE])) { + switch(handshake->type) { case 1: buffer = fastd_handshake_new_reply(ctx, peer, handshake, 0); fastd_task_put_send_handshake(ctx, peer, buffer); break; case 2: - peer->seen = ctx->now; establish(ctx, peer); buffer = fastd_handshake_new_reply(ctx, peer, handshake, 0); fastd_task_put_send_handshake(ctx, peer, buffer); break; case 3: - peer->seen = ctx->now; establish(ctx, peer); break; default: - pr_debug(ctx, "received handshake reply with unknown type %u", AS_UINT8(handshake->records[RECORD_HANDSHAKE_TYPE])); - break; + pr_debug(ctx, "received handshake reply with unknown type %u", handshake->type); } } -- cgit v1.2.3