Skip to content

Commit

Permalink
Add support for a new big-endian handshake format
Browse files Browse the repository at this point in the history
Because of strange dicisions in the past, fastd currently uses little endian
type and length values in its handshake. As the common network byte order is
big endian, changing the handshake format would be preferable.

This commit adds support for a new big-endian handshake. For now, fastd will
continue to send little-endian handshakes so ensure backwarts compatiblity, but
if it receives a big-endian handshake, it will respond with a big-endian one.
  • Loading branch information
neocturne committed Jan 8, 2015
1 parent 05a41fe commit e9baf5d
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 57 deletions.
68 changes: 44 additions & 24 deletions src/handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,11 @@ static inline uint32_t as_uint32(const fastd_handshake_record_t *record) {
}

/** Reads a TLV record as a 16bit integer (little endian) */
static inline uint16_t as_uint16_le(const fastd_handshake_record_t *record) {
return as_uint8(record) | (uint16_t)record->data[1] << 8;
static inline uint16_t as_uint16_endian(const fastd_handshake_record_t *record, bool little_endian) {
if (little_endian)
return as_uint8(record) | (uint16_t)record->data[1] << 8;
else
return as_uint16(record);
}

/** Reads a TLV record as a variable-length integer (little endian) */
Expand Down Expand Up @@ -157,7 +160,7 @@ static fastd_string_stack_t * parse_string_list(const uint8_t *data, size_t len)
}

/** Allocates and initializes a new handshake packet */
static fastd_buffer_t new_handshake(uint8_t type, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) {
static fastd_handshake_buffer_t new_handshake(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) {
size_t version_len = strlen(FASTD_VERSION);
size_t protocol_len = strlen(conf.protocol->name);
size_t method_len = method ? strlen(method->name) : 0;
Expand All @@ -168,22 +171,24 @@ static fastd_buffer_t new_handshake(uint8_t type, const fastd_method_info_t *met
if (with_method_list)
method_list = create_method_list(&method_list_len);

fastd_buffer_t buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 1,
3*5 + /* handshake type, mode, reply code */
6 + /* MTU */
4+version_len + /* version name */
4+protocol_len + /* protocol name */
4+method_len + /* method name */
4+method_list_len + /* supported method name list */
tail_space);
fastd_handshake_packet_t *packet = buffer.data;
fastd_handshake_buffer_t buffer = {
.buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 1,
3*5 + /* handshake type, mode, reply code */
6 + /* MTU */
4+version_len + /* version name */
4+protocol_len + /* protocol name */
4+method_len + /* method name */
4+method_list_len + /* supported method name list */
tail_space),
.little_endian = little_endian};
fastd_handshake_packet_t *packet = buffer.buffer.data;

packet->rsv = 0;
packet->tlv_len = 0;

fastd_handshake_add_uint8(&buffer, RECORD_HANDSHAKE_TYPE, type);
fastd_handshake_add_uint8(&buffer, RECORD_MODE, conf.mode);
fastd_handshake_add_uint16_le(&buffer, RECORD_MTU, conf.mtu);
fastd_handshake_add_uint16_endian(&buffer, RECORD_MTU, conf.mtu);

fastd_handshake_add(&buffer, RECORD_VERSION_NAME, version_len, FASTD_VERSION);
fastd_handshake_add(&buffer, RECORD_PROTOCOL_NAME, protocol_len, conf.protocol->name);
Expand All @@ -200,13 +205,13 @@ static fastd_buffer_t new_handshake(uint8_t type, const fastd_method_info_t *met
}

/** Allocates and initializes a new initial handshake packet */
fastd_buffer_t fastd_handshake_new_init(size_t tail_space) {
return new_handshake(1, NULL, !conf.secure_handshakes, tail_space);
fastd_handshake_buffer_t fastd_handshake_new_init(size_t tail_space) {
return new_handshake(1, true, NULL, !conf.secure_handshakes, tail_space);
}

/** Allocates and initializes a new reply handshake packet */
fastd_buffer_t fastd_handshake_new_reply(uint8_t type, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) {
fastd_buffer_t buffer = new_handshake(type, method, with_method_list, tail_space);
fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) {
fastd_handshake_buffer_t buffer = new_handshake(type, little_endian, method, with_method_list, tail_space);
fastd_handshake_add_uint8(&buffer, RECORD_REPLY_CODE, 0);
return buffer;
}
Expand Down Expand Up @@ -258,8 +263,11 @@ static void print_error(const char *prefix, const fastd_peer_address_t *remote_a
static void send_error(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const fastd_handshake_t *handshake, uint8_t reply_code, uint16_t error_detail) {
print_error("sending", remote_addr, reply_code, error_detail);

fastd_buffer_t buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 0, 3*5 /* enough space for handshake type, reply code and error detail */);
fastd_handshake_packet_t *reply = buffer.data;
fastd_handshake_buffer_t buffer = {
.buffer = fastd_buffer_alloc(sizeof(fastd_handshake_packet_t), 0, 3*5 /* enough space for handshake type, reply code and error detail */),
.little_endian = handshake->little_endian
};
fastd_handshake_packet_t *reply = buffer.buffer.data;

reply->rsv = 0;
reply->tlv_len = 0;
Expand All @@ -268,7 +276,7 @@ static void send_error(fastd_socket_t *sock, const fastd_peer_address_t *local_a
fastd_handshake_add_uint8(&buffer, RECORD_REPLY_CODE, reply_code);
fastd_handshake_add_uint(&buffer, RECORD_ERROR_DETAIL, error_detail);

fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer);
fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer.buffer);
}

/** Parses the TLV records of a handshake */
Expand Down Expand Up @@ -297,8 +305,20 @@ static inline fastd_handshake_t parse_tlvs(const fastd_buffer_t *buffer) {
if (ptr+4 > end)
break;

uint16_t type = ptr[0] + (ptr[1] << 8);
uint16_t len = ptr[2] + (ptr[3] << 8);
uint16_t type, len;

if (!handshake.little_endian) {
type = ptr[1] + (ptr[0] << 8);
len = ptr[3] + (ptr[2] << 8);

if (type > 0xff || (type == 0 && len > 0xff))
handshake.little_endian = true;
}

if (handshake.little_endian) {
type = ptr[0] + (ptr[1] << 8);
len = ptr[2] + (ptr[3] << 8);
}

if (ptr+4+len > end)
break;
Expand Down Expand Up @@ -343,9 +363,9 @@ static inline bool check_records(fastd_socket_t *sock, const fastd_peer_address_

if (!conf.secure_handshakes || handshake->type > 1) {
if (handshake->records[RECORD_MTU].length == 2) {
if (as_uint16_le(&handshake->records[RECORD_MTU]) != conf.mtu) {
if (as_uint16_endian(&handshake->records[RECORD_MTU], handshake->little_endian) != conf.mtu) {
pr_warn("MTU configuration differs with peer %I: local MTU is %u, remote MTU is %u",
remote_addr, conf.mtu, as_uint16_le(&handshake->records[RECORD_MTU]));
remote_addr, conf.mtu, as_uint16_endian(&handshake->records[RECORD_MTU], handshake->little_endian));
}
}
}
Expand Down
65 changes: 43 additions & 22 deletions src/handshake.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,18 @@ struct fastd_handshake {
fastd_handshake_record_t records[RECORD_MAX]; /**< The TLV records of the handshake */
uint16_t tlv_len; /**< The length of the TLV record data */
void *tlv_data; /**< TLV record data */
bool little_endian; /**< true if the old little-endian handshake format is used */
};

/** A buffer a handshake to send is prepared in */
struct fastd_handshake_buffer {
fastd_buffer_t buffer;
bool little_endian;
};


fastd_buffer_t fastd_handshake_new_init(size_t tail_space);
fastd_buffer_t fastd_handshake_new_reply(uint8_t type, const fastd_method_info_t *method, bool with_method_list, size_t tail_space);
fastd_handshake_buffer_t fastd_handshake_new_init(size_t tail_space);
fastd_handshake_buffer_t fastd_handshake_new_reply(uint8_t type, bool little_endian, const fastd_method_info_t *method, bool with_method_list, size_t tail_space);

void fastd_handshake_handle(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, fastd_buffer_t buffer);

Expand All @@ -111,57 +118,65 @@ static inline uint16_t fastd_handshake_tlv_len(const fastd_buffer_t *buffer) {
}

/** Adds an uninitialized TLV record of given type and length to a handshake buffer */
static inline uint8_t * fastd_handshake_extend(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len) {
uint8_t *dst = buffer->data + buffer->len;
static inline uint8_t * fastd_handshake_extend(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len) {
uint8_t *dst = buffer->buffer.data + buffer->buffer.len;

if (buffer->data + buffer->len + 4 + len > buffer->base + buffer->base_len)
if (buffer->buffer.data + buffer->buffer.len + 4 + len > buffer->buffer.base + buffer->buffer.base_len)
exit_bug("not enough buffer allocated for handshake");

buffer->len += 4 + len;
buffer->buffer.len += 4 + len;

fastd_handshake_packet_t *packet = buffer->data;
packet->tlv_len = htons(fastd_handshake_tlv_len(buffer) + 4 + len);
fastd_handshake_packet_t *packet = buffer->buffer.data;
packet->tlv_len = htons(fastd_handshake_tlv_len(&buffer->buffer) + 4 + len);

dst[0] = type;
dst[1] = type >> 8;
dst[2] = len;
dst[3] = len >> 8;
if (buffer->little_endian) {
dst[0] = type;
dst[1] = type >> 8;
dst[2] = len;
dst[3] = len >> 8;
}
else {
dst[0] = type >> 8;
dst[1] = type;
dst[2] = len >> 8;
dst[3] = len;
}

return dst+4;
}

/** Adds an TLV record of given type and length initialized with arbitraty data to a handshake buffer */
static inline void fastd_handshake_add(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len, const void *data) {
static inline void fastd_handshake_add(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len, const void *data) {
uint8_t *dst = fastd_handshake_extend(buffer, type, len);

memcpy(dst, data, len);
}

/** Adds an TLV record of given type and length initialized with zeros to a handshake buffer */
static inline uint8_t * fastd_handshake_add_zero(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len) {
static inline uint8_t * fastd_handshake_add_zero(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, size_t len) {
uint8_t *dst = fastd_handshake_extend(buffer, type, len);

memset(dst, 0, len);
return dst;
}

/** Adds an uint8 TLV record of given type and value to a handshake buffer */
static inline void fastd_handshake_add_uint8(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint8_t value) {
static inline void fastd_handshake_add_uint8(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint8_t value) {
uint8_t *dst = fastd_handshake_extend(buffer, type, 1);

dst[0] = value;
}

/** Adds an uint16 TLV record of given type and value to a handshake buffer */
static inline void fastd_handshake_add_uint16(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint16_t value) {
static inline void fastd_handshake_add_uint16(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint16_t value) {
uint8_t *dst = fastd_handshake_extend(buffer, type, 2);

dst[0] = value >> 8;
dst[1] = value;
}

/** Adds an uint24 TLV record of given type and value to a handshake buffer */
static inline void fastd_handshake_add_uint24(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
static inline void fastd_handshake_add_uint24(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
uint8_t *dst = fastd_handshake_extend(buffer, type, 3);

dst[0] = value >> 16;
Expand All @@ -170,7 +185,7 @@ static inline void fastd_handshake_add_uint24(fastd_buffer_t *buffer, fastd_hand
}

/** Adds an uint32 TLV record of given type and value to a handshake buffer */
static inline void fastd_handshake_add_uint32(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
static inline void fastd_handshake_add_uint32(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
uint8_t *dst = fastd_handshake_extend(buffer, type, 4);

dst[0] = value >> 24;
Expand All @@ -180,15 +195,21 @@ static inline void fastd_handshake_add_uint32(fastd_buffer_t *buffer, fastd_hand
}

/** Adds an uint16 TLV record of given type and value to a handshake buffer encoded as little endian */
static inline void fastd_handshake_add_uint16_le(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint16_t value) {
static inline void fastd_handshake_add_uint16_endian(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint16_t value) {
uint8_t *dst = fastd_handshake_extend(buffer, type, 2);

dst[0] = value;
dst[1] = value >> 8;
if (buffer->little_endian) {
dst[0] = value;
dst[1] = value >> 8;
}
else {
dst[0] = value >> 8;
dst[1] = value;
}
}

/** Adds an TLV record of given type and value to a handshake buffer, automatically using a 1- to 4-byte value */
static inline void fastd_handshake_add_uint(fastd_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
static inline void fastd_handshake_add_uint(fastd_handshake_buffer_t *buffer, fastd_handshake_record_type_t type, uint32_t value) {
if (value > 0xffffff)
fastd_handshake_add_uint32(buffer, type, value);
if (value > 0xffff)
Expand Down
24 changes: 13 additions & 11 deletions src/protocols/ec25519_fhmqvc/handshake.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,15 +329,15 @@ static void clear_shared_handshake_key(const fastd_peer_t *peer) {

/** Sends a reply to an initial handshake (type 1) */
static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer,
const aligned_int256_t *peer_handshake_key, const fastd_method_info_t *method) {
const aligned_int256_t *peer_handshake_key, const fastd_method_info_t *method, bool little_endian) {
pr_debug("responding handshake with %P[%I]...", peer, remote_addr);

const handshake_key_t *handshake_key = &ctx.protocol_state->handshake_key;

if (!update_shared_handshake_key(peer, handshake_key, peer_handshake_key))
return;

fastd_buffer_t buffer = fastd_handshake_new_reply(2, method, true, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES));
fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(2, little_endian, method, true, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES));

fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public);
fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key);
Expand All @@ -352,10 +352,10 @@ static void respond_handshake(const fastd_socket_t *sock, const fastd_peer_addre
}

uint8_t *mac = fastd_handshake_add_zero(&buffer, RECORD_TLV_MAC, HASHBYTES);
fastd_hmacsha256(&hmacbuf, peer->protocol_state->shared_handshake_key.w, fastd_handshake_tlv_data(&buffer), fastd_handshake_tlv_len(&buffer));
fastd_hmacsha256(&hmacbuf, peer->protocol_state->shared_handshake_key.w, fastd_handshake_tlv_data(&buffer.buffer), fastd_handshake_tlv_len(&buffer.buffer));
memcpy(mac, hmacbuf.b, HASHBYTES);

fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer);
fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer.buffer);
}

/** Sends a reply to a handshake response (type 2) */
Expand Down Expand Up @@ -398,7 +398,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l
&peer->key->key, &sigma, compat ? NULL : shared_handshake_key.w, handshake_key->serial))
return;

fastd_buffer_t buffer = fastd_handshake_new_reply(3, method, false, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES));
fastd_handshake_buffer_t buffer = fastd_handshake_new_reply(3, handshake->little_endian, method, false, 4*(4+PUBLICKEYBYTES) + 2*(4+HASHBYTES));

fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public);
fastd_handshake_add(&buffer, RECORD_RECIPIENT_KEY, PUBLICKEYBYTES, &peer->key->key);
Expand All @@ -408,7 +408,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l
if (!compat) {
fastd_sha256_t hmacbuf;
uint8_t *mac = fastd_handshake_add_zero(&buffer, RECORD_TLV_MAC, HASHBYTES);
fastd_hmacsha256(&hmacbuf, shared_handshake_key.w, fastd_handshake_tlv_data(&buffer), fastd_handshake_tlv_len(&buffer));
fastd_hmacsha256(&hmacbuf, shared_handshake_key.w, fastd_handshake_tlv_data(&buffer.buffer), fastd_handshake_tlv_len(&buffer.buffer));
memcpy(mac, hmacbuf.b, HASHBYTES);
}
else {
Expand All @@ -417,7 +417,7 @@ static void finish_handshake(fastd_socket_t *sock, const fastd_peer_address_t *l
fastd_handshake_add(&buffer, RECORD_T, HASHBYTES, hmacbuf.b);
}

fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer);
fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer.buffer);
}

/** Handles a reply to a handshake response (type 3) */
Expand Down Expand Up @@ -521,7 +521,7 @@ static fastd_peer_t * match_sender_key(const fastd_socket_t *sock, const fastd_p
void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer) {
fastd_protocol_ec25519_fhmqvc_maintenance();

fastd_buffer_t buffer = fastd_handshake_new_init(3*(4+PUBLICKEYBYTES) /* sender key, recipient key, handshake key */);
fastd_handshake_buffer_t buffer = fastd_handshake_new_init(3*(4+PUBLICKEYBYTES) /* sender key, recipient key, handshake key */);

fastd_handshake_add(&buffer, RECORD_SENDER_KEY, PUBLICKEYBYTES, &conf.protocol_config->key.public);

Expand All @@ -539,7 +539,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_socket_t *sock, const fa
if (!peer || !fastd_peer_is_established(peer))
fastd_peer_exec_shell_command(&conf.on_connect, peer, (local_addr && local_addr->sa.sa_family) ? local_addr : sock->bound_addr, remote_addr);

fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer);
fastd_send_handshake(sock, local_addr, remote_addr, peer, buffer.buffer);
}


Expand All @@ -557,6 +557,7 @@ static inline void print_unknown_key(const fastd_peer_address_t *addr, const uns
/** Data attached to an asynchronous on-verify run */
typedef struct verify_data {
aligned_int256_t peer_handshake_key; /**< The public key of the peer being verified */
bool little_endian; /**< The handshake endianess */
} verify_data_t;

/** Adds a dynamic peer for an unknown key */
Expand Down Expand Up @@ -614,6 +615,7 @@ static bool handle_dynamic(fastd_socket_t *sock, const fastd_peer_address_t *loc
verify_data_t verify_data;
memset(&verify_data, 0, sizeof(verify_data));
memcpy(&verify_data.peer_handshake_key, handshake->records[RECORD_SENDER_HANDSHAKE_KEY].data, PUBLICKEYBYTES);
verify_data.little_endian = handshake->little_endian;

fastd_tristate_t verified = fastd_verify_peer(peer, sock, local_addr, remote_addr, method, &verify_data, sizeof(verify_data));

Expand All @@ -640,7 +642,7 @@ void fastd_protocol_ec25519_fhmqvc_handle_verify_return(fastd_peer_t *peer, fast

peer->last_handshake_response_timeout = ctx.now + MIN_HANDSHAKE_INTERVAL;
peer->last_handshake_response_address = *remote_addr;
respond_handshake(sock, local_addr, remote_addr, peer, &data->peer_handshake_key, method);
respond_handshake(sock, local_addr, remote_addr, peer, &data->peer_handshake_key, method, data->little_endian);
}

#else
Expand Down Expand Up @@ -726,7 +728,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_socket_t *sock, const

peer->last_handshake_response_timeout = ctx.now + MIN_HANDSHAKE_INTERVAL;
peer->last_handshake_response_address = *remote_addr;
respond_handshake(sock, local_addr, remote_addr, peer, &peer_handshake_key, method);
respond_handshake(sock, local_addr, remote_addr, peer, &peer_handshake_key, method, handshake->little_endian);
return;
}

Expand Down
1 change: 1 addition & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ typedef struct fastd_mac_info fastd_mac_info_t;
typedef struct fastd_mac fastd_mac_t;

typedef struct fastd_handshake fastd_handshake_t;
typedef struct fastd_handshake_buffer fastd_handshake_buffer_t;

typedef struct fastd_lex fastd_lex_t;
typedef struct fastd_parser_state fastd_parser_state_t;
Expand Down

0 comments on commit e9baf5d

Please sign in to comment.