From 8088a82a2a91d29967cef920ba780eecdf72518e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 30 Nov 2013 03:19:38 +0100 Subject: Perform string-based lookup of method-related information only once --- src/config.c | 54 ++++++--- src/config.h | 2 +- src/config.y | 5 +- src/crypto.h | 4 +- src/crypto/cipher/ciphers.c.in | 8 +- src/crypto/mac/macs.c.in | 8 +- src/fastd.h | 29 +---- src/handshake.c | 53 +++++---- src/handshake.h | 2 +- src/method.h | 77 ++++++++++++ src/methods/cipher_test/cipher_test.c | 80 ++++++------- src/methods/composed_gmac/composed_gmac.c | 138 ++++++++++------------ src/methods/generic_gcm/generic_gcm.c | 102 ++++++++-------- src/methods/generic_gmac/generic_gmac.c | 99 +++++++--------- src/methods/generic_poly1305/generic_poly1305.c | 77 ++++++------ src/methods/methods.c.in | 12 +- src/methods/null/null.c | 21 ++-- src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c | 20 ++-- src/options.c | 3 +- src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c | 16 +-- src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h | 7 +- src/protocols/ec25519_fhmqvc/handshake.c | 41 ++++--- src/protocols/ec25519_fhmqvc/state.c | 2 +- src/types.h | 2 + 24 files changed, 445 insertions(+), 417 deletions(-) create mode 100644 src/method.h (limited to 'src') diff --git a/src/config.c b/src/config.c index ed4a8d7..726d04c 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,7 @@ #include "fastd.h" #include "config.h" #include "lex.h" +#include "method.h" #include "peer.h" #include @@ -87,22 +88,17 @@ bool fastd_config_protocol(fastd_context_t *ctx UNUSED, fastd_config_t *conf, co return true; } -bool fastd_config_method(fastd_context_t *ctx, fastd_config_t *conf, const char *name) { - if (!fastd_method_get_by_name(name)) - return false; - +void fastd_config_method(fastd_context_t *ctx, fastd_config_t *conf, const char *name) { fastd_string_stack_t **method; - for (method = &conf->methods; *method; method = &(*method)->next) { + for (method = &conf->method_list; *method; method = &(*method)->next) { if (!strcmp((*method)->str, name)) { pr_debug(ctx, "duplicate method name `%s', ignoring", name); - return true; + return; } } *method = fastd_string_stack_dup(name); - - return true; } bool fastd_config_bind_address(fastd_context_t *ctx UNUSED, fastd_config_t *conf, const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6) { @@ -482,9 +478,9 @@ static void configure_method_parameters(fastd_config_t *conf) { conf->min_encrypt_tail_space = 0; conf->min_decrypt_tail_space = 0; - fastd_string_stack_t *method_name; - for (method_name = conf->methods; method_name; method_name = method_name->next) { - const fastd_method_t *method = fastd_method_get_by_name(method_name->str); + size_t i; + for (i = 0; conf->methods[i].name; i++) { + const fastd_method_t *method = conf->methods[i].method; conf->max_overhead = max_size_t(conf->max_overhead, method->max_overhead); conf->min_encrypt_head_space = max_size_t(conf->min_encrypt_head_space, method->min_encrypt_head_space); @@ -499,6 +495,32 @@ static void configure_method_parameters(fastd_config_t *conf) { conf->min_decrypt_head_space = alignto(conf->min_decrypt_head_space, 16) + 8; } +static void configure_methods(fastd_context_t *ctx, fastd_config_t *conf) { + size_t n_methods = 0, i; + fastd_string_stack_t *method_name; + for (method_name = conf->method_list; method_name; method_name = method_name->next) + n_methods++; + + conf->methods = calloc(n_methods+1, sizeof(fastd_method_info_t)); + + for (i = 0, method_name = conf->method_list; method_name; i++, method_name = method_name->next) { + conf->methods[i].name = method_name->str; + if (!fastd_method_create_by_name(method_name->str, &conf->methods[i].method, &conf->methods[i].ctx)) + exit_error(ctx, "method `%s' not supported", method_name->str); + } + + configure_method_parameters(conf); +} + +static void destroy_methods(fastd_config_t *conf) { + size_t i; + for (i = 0; conf->methods[i].name; i++) { + conf->methods[i].method->destroy(conf->methods[i].ctx); + } + + free(conf->methods); +} + void fastd_configure(fastd_context_t *ctx, fastd_config_t *conf, int argc, char *const argv[]) { default_config(conf); @@ -534,17 +556,16 @@ void fastd_configure(fastd_context_t *ctx, fastd_config_t *conf, int argc, char exit_error(ctx, "config error: setting pmtu is not supported on this system"); #endif - if (!conf->methods) { + if (!conf->method_list) { pr_warn(ctx, "no encryption method configured, falling back to method `null' (unencrypted)"); - if (!fastd_config_method(ctx, conf, "null")) - exit_error(ctx, "method `null' not supported"); + fastd_config_method(ctx, conf, "null"); } if (!conf->secure_handshakes_set) pr_warn(ctx, "`secure handshakes' not set, please read the documentation about this option; defaulting to no"); configure_user(ctx, conf); - configure_method_parameters(conf); + configure_methods(ctx, conf); } static void peer_dirs_read_peer_group(fastd_context_t *ctx, fastd_config_t *new_conf) { @@ -645,7 +666,8 @@ void fastd_config_release(fastd_context_t *ctx, fastd_config_t *conf) { free_peer_group(conf->peer_group); - fastd_string_stack_free(conf->methods); + destroy_methods(conf); + fastd_string_stack_free(conf->method_list); fastd_mac_config_free(conf->macs); fastd_cipher_config_free(conf->ciphers); diff --git a/src/config.h b/src/config.h index a4777c7..ad3d6b1 100644 --- a/src/config.h +++ b/src/config.h @@ -31,7 +31,7 @@ bool fastd_config_protocol(fastd_context_t *ctx, fastd_config_t *conf, const char *name); -bool fastd_config_method(fastd_context_t *ctx, fastd_config_t *conf, const char *name); +void fastd_config_method(fastd_context_t *ctx, fastd_config_t *conf, const char *name); bool fastd_config_add_log_file(fastd_context_t *ctx, fastd_config_t *conf, const char *name, fastd_loglevel_t level); bool fastd_config_bind_address(fastd_context_t *ctx, fastd_config_t *conf, const fastd_peer_address_t *address, const char *bindtodev, bool default_v4, bool default_v6); void fastd_config_peer_group_push(fastd_context_t *ctx, fastd_config_t *conf, const char *name); diff --git a/src/config.y b/src/config.y index a79e8e9..68d41a4 100644 --- a/src/config.y +++ b/src/config.y @@ -350,10 +350,7 @@ protocol: TOK_STRING { ; method: TOK_STRING { - if (!fastd_config_method(ctx, conf, $1->str)) { - fastd_config_error(&@$, ctx, conf, filename, depth, "unsupported method"); - YYERROR; - } + fastd_config_method(ctx, conf, $1->str); } ; diff --git a/src/crypto.h b/src/crypto.h index 7ee73cd..1f26058 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -58,9 +58,9 @@ struct fastd_mac { const fastd_cipher_info_t* fastd_cipher_info_get_by_name(const char *name); -const fastd_cipher_t* fastd_cipher_get_by_name(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **info); +const fastd_cipher_t* fastd_cipher_get(fastd_context_t *ctx, const fastd_cipher_info_t *info); const fastd_mac_info_t* fastd_mac_info_get_by_name(const char *name); -const fastd_mac_t* fastd_mac_get_by_name(fastd_context_t *ctx, const char *name, const fastd_mac_info_t **info); +const fastd_mac_t* fastd_mac_get(fastd_context_t *ctx, const fastd_mac_info_t *info); #endif /* _FASTD_CRYPTO_H_ */ diff --git a/src/crypto/cipher/ciphers.c.in b/src/crypto/cipher/ciphers.c.in index 72ea3d2..cdc9911 100644 --- a/src/crypto/cipher/ciphers.c.in +++ b/src/crypto/cipher/ciphers.c.in @@ -106,15 +106,11 @@ const fastd_cipher_info_t* fastd_cipher_info_get_by_name(const char *name) { return NULL; } -const fastd_cipher_t* fastd_cipher_get_by_name(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **info) { +const fastd_cipher_t* fastd_cipher_get(fastd_context_t *ctx, const fastd_cipher_info_t *info) { size_t i; for (i = 0; i < array_size(ciphers); i++) { - if (!strcmp(ciphers[i].name, name)) { - if (info) - *info = ciphers[i].info; - + if (ciphers[i].info == info) return ctx->conf->ciphers[i]; - } } return NULL; diff --git a/src/crypto/mac/macs.c.in b/src/crypto/mac/macs.c.in index c70473b..ee64362 100644 --- a/src/crypto/mac/macs.c.in +++ b/src/crypto/mac/macs.c.in @@ -106,15 +106,11 @@ const fastd_mac_info_t* fastd_mac_info_get_by_name(const char *name) { return NULL; } -const fastd_mac_t* fastd_mac_get_by_name(fastd_context_t *ctx, const char *name, const fastd_mac_info_t **info) { +const fastd_mac_t* fastd_mac_get(fastd_context_t *ctx, const fastd_mac_info_t *info) { size_t i; for (i = 0; i < array_size(macs); i++) { - if (!strcmp(macs[i].name, name)) { - if (info) - *info = macs[i].info; - + if (macs[i].info == info) return ctx->conf->macs[i]; - } } return NULL; diff --git a/src/fastd.h b/src/fastd.h index 4290421..ebbcf86 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -63,7 +63,7 @@ struct fastd_protocol { bool (*peer_check_temporary)(fastd_context_t *ctx, fastd_peer_t *peer); void (*handshake_init)(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer); - void (*handshake_handle)(fastd_context_t *ctx, 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, const char *method); + void (*handshake_handle)(fastd_context_t *ctx, 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, const fastd_method_info_t *method); void (*handle_recv)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer); void (*send)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_t buffer); @@ -78,28 +78,6 @@ struct fastd_protocol { bool (*describe_peer)(const fastd_context_t *ctx, const fastd_peer_t *peer, char *buf, size_t len); }; -struct fastd_method { - bool (*provides)(const char *name); - - size_t max_overhead; - size_t min_encrypt_head_space; - size_t min_decrypt_head_space; - size_t min_encrypt_tail_space; - size_t min_decrypt_tail_space; - - size_t (*key_length)(fastd_context_t *ctx, const char *name); - fastd_method_session_state_t* (*session_init)(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator); - fastd_method_session_state_t* (*session_init_compat)(fastd_context_t *ctx, const char *name, const uint8_t *secret, size_t length, bool initiator); - bool (*session_is_valid)(fastd_context_t *ctx, fastd_method_session_state_t *session); - bool (*session_is_initiator)(fastd_context_t *ctx, fastd_method_session_state_t *session); - bool (*session_want_refresh)(fastd_context_t *ctx, fastd_method_session_state_t *session); - void (*session_superseded)(fastd_context_t *ctx, fastd_method_session_state_t *session); - void (*session_free)(fastd_context_t *ctx, fastd_method_session_state_t *session); - - bool (*encrypt)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in); - bool (*decrypt)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in); -}; - union fastd_peer_address { struct sockaddr sa; struct sockaddr_in in; @@ -210,7 +188,8 @@ struct fastd_config { gid_t *groups; const fastd_protocol_t *protocol; - fastd_string_stack_t *methods; + fastd_string_stack_t *method_list; + fastd_method_info_t *methods; size_t max_overhead; size_t min_encrypt_head_space; @@ -335,8 +314,6 @@ void fastd_resolve_peer(fastd_context_t *ctx, fastd_peer_t *peer, fastd_remote_t int fastd_vsnprintf(const fastd_context_t *ctx, char *buffer, size_t size, const char *format, va_list ap); void fastd_logf(const fastd_context_t *ctx, fastd_loglevel_t level, const char *format, ...); -const fastd_method_t* fastd_method_get_by_name(const char *name); - void fastd_tuntap_open(fastd_context_t *ctx); fastd_buffer_t fastd_tuntap_read(fastd_context_t *ctx); void fastd_tuntap_write(fastd_context_t *ctx, fastd_buffer_t buffer); diff --git a/src/handshake.c b/src/handshake.c index 09a197a..4e53802 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -25,6 +25,7 @@ #include "handshake.h" +#include "method.h" #include "peer.h" #include @@ -59,17 +60,19 @@ static const char *const REPLY_TYPES[REPLY_MAX] = { static uint8_t* create_method_list(fastd_context_t *ctx, size_t *len) { - *len = strlen(ctx->conf->methods->str); + *len = 0; - fastd_string_stack_t *method; - for (method = ctx->conf->methods->next; method; method = method->next) - *len += strlen(method->str) + 1; + size_t i; + for (i = 0; ctx->conf->methods[i].name; i++) + *len += strlen(ctx->conf->methods[i].name) + 1; + + uint8_t *ret = malloc(*len); + (*len)--; - uint8_t *ret = malloc(*len+1); char *ptr = (char*)ret; - for (method = ctx->conf->methods; method; method = method->next) - ptr = stpcpy(ptr, method->str) + 1; + for (i = 0; ctx->conf->methods[i].name; i++) + ptr = stpcpy(ptr, ctx->conf->methods[i].name) + 1; return ret; } @@ -85,16 +88,6 @@ static inline bool record_equal(const char *str, const fastd_handshake_record_t return string_equal(str, (const char*)record->data, record->length); } -static const char* method_from_name(fastd_context_t *ctx, const char *name, size_t n) { - fastd_string_stack_t *method; - for (method = ctx->conf->methods; method; method = method->next) { - if (string_equal(method->str, name, n)) - return method->str; - } - - return NULL; -} - static fastd_string_stack_t* parse_string_list(const uint8_t *data, size_t len) { const uint8_t *end = data+len; fastd_string_stack_t *ret = NULL; @@ -109,10 +102,10 @@ static fastd_string_stack_t* parse_string_list(const uint8_t *data, size_t len) return ret; } -static fastd_buffer_t new_handshake(fastd_context_t *ctx, uint8_t type, const char *method, bool with_method_list, size_t tail_space) { +static fastd_buffer_t new_handshake(fastd_context_t *ctx, uint8_t type, 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(ctx->conf->protocol->name); - size_t method_len = method ? strlen(method) : 0; + size_t method_len = method ? strlen(method->name) : 0; size_t method_list_len = 0; uint8_t *method_list = NULL; @@ -141,7 +134,7 @@ static fastd_buffer_t new_handshake(fastd_context_t *ctx, uint8_t type, const ch fastd_handshake_add(ctx, &buffer, RECORD_PROTOCOL_NAME, protocol_len, ctx->conf->protocol->name); if (method && (!with_method_list || !ctx->conf->secure_handshakes)) - fastd_handshake_add(ctx, &buffer, RECORD_METHOD_NAME, method_len, method); + fastd_handshake_add(ctx, &buffer, RECORD_METHOD_NAME, method_len, method->name); if (with_method_list) { fastd_handshake_add(ctx, &buffer, RECORD_METHOD_LIST, method_list_len, method_list); @@ -155,7 +148,7 @@ fastd_buffer_t fastd_handshake_new_init(fastd_context_t *ctx, size_t tail_space) return new_handshake(ctx, 1, NULL, !ctx->conf->secure_handshakes, tail_space); } -fastd_buffer_t fastd_handshake_new_reply(fastd_context_t *ctx, const fastd_handshake_t *handshake, const char *method, bool with_method_list, size_t tail_space) { +fastd_buffer_t fastd_handshake_new_reply(fastd_context_t *ctx, const fastd_handshake_t *handshake, const fastd_method_info_t *method, bool with_method_list, size_t tail_space) { fastd_buffer_t buffer = new_handshake(ctx, handshake->type+1, method, with_method_list, tail_space); fastd_handshake_add_uint8(ctx, &buffer, RECORD_REPLY_CODE, 0); return buffer; @@ -293,15 +286,23 @@ static inline bool check_records(fastd_context_t *ctx, fastd_socket_t *sock, con return true; } -static inline const char* get_method(fastd_context_t *ctx, const fastd_handshake_t *handshake) { +static inline const fastd_method_info_t* get_method_by_name(fastd_context_t *ctx, const char *name, size_t n) { + char name0[n+1]; + memcpy(name0, name, n); + name0[n] = 0; + + return fastd_method_get_by_name(ctx, name0); +} + +static inline const fastd_method_info_t* get_method(fastd_context_t *ctx, const fastd_handshake_t *handshake) { if (handshake->records[RECORD_METHOD_LIST].data && handshake->records[RECORD_METHOD_LIST].length) { fastd_string_stack_t *method_list = parse_string_list(handshake->records[RECORD_METHOD_LIST].data, handshake->records[RECORD_METHOD_LIST].length); - const char *method = NULL; + const fastd_method_info_t *method = NULL; fastd_string_stack_t *method_name; for (method_name = method_list; method_name; method_name = method_name->next) { - const char *cur_method = method_from_name(ctx, method_name->str, SIZE_MAX); + const fastd_method_info_t *cur_method = fastd_method_get_by_name(ctx, method_name->str); if (cur_method) method = cur_method; @@ -315,12 +316,12 @@ static inline const char* get_method(fastd_context_t *ctx, const fastd_handshake if (!handshake->records[RECORD_METHOD_NAME].data) return NULL; - return method_from_name(ctx, (const char*)handshake->records[RECORD_METHOD_NAME].data, handshake->records[RECORD_METHOD_NAME].length); + return get_method_by_name(ctx, (const char*)handshake->records[RECORD_METHOD_NAME].data, handshake->records[RECORD_METHOD_NAME].length); } void fastd_handshake_handle(fastd_context_t *ctx, 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) { char *peer_version = NULL; - const char *method = NULL; + const fastd_method_info_t *method = NULL; fastd_handshake_t handshake = parse_tlvs(&buffer); diff --git a/src/handshake.h b/src/handshake.h index 4aff83c..196cc67 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -79,7 +79,7 @@ struct fastd_handshake { fastd_buffer_t fastd_handshake_new_init(fastd_context_t *ctx, size_t tail_space); -fastd_buffer_t fastd_handshake_new_reply(fastd_context_t *ctx, const fastd_handshake_t *handshake, const char *method, bool with_method_list, size_t tail_space); +fastd_buffer_t fastd_handshake_new_reply(fastd_context_t *ctx, const fastd_handshake_t *handshake, const fastd_method_info_t *method, bool with_method_list, size_t tail_space); void fastd_handshake_handle(fastd_context_t *ctx, 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); diff --git a/src/method.h b/src/method.h new file mode 100644 index 0000000..b56db14 --- /dev/null +++ b/src/method.h @@ -0,0 +1,77 @@ +/* + Copyright (c) 2012-2013, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef _FASTD_METHOD_H_ +#define _FASTD_METHOD_H_ + +#include "fastd.h" + + +struct fastd_method_info { + const char *name; + const fastd_method_t *method; + fastd_method_context_t *ctx; +}; + +struct fastd_method { + size_t max_overhead; + size_t min_encrypt_head_space; + size_t min_decrypt_head_space; + size_t min_encrypt_tail_space; + size_t min_decrypt_tail_space; + + bool (*create_by_name)(const char *name, fastd_method_context_t **method_ctx); + void (*destroy)(fastd_method_context_t *method_ctx); + + size_t (*key_length)(fastd_context_t *ctx, const fastd_method_context_t *method_ctx); + + fastd_method_session_state_t* (*session_init)(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator); + fastd_method_session_state_t* (*session_init_compat)(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, size_t length, bool initiator); + bool (*session_is_valid)(fastd_context_t *ctx, fastd_method_session_state_t *session); + bool (*session_is_initiator)(fastd_context_t *ctx, fastd_method_session_state_t *session); + bool (*session_want_refresh)(fastd_context_t *ctx, fastd_method_session_state_t *session); + void (*session_superseded)(fastd_context_t *ctx, fastd_method_session_state_t *session); + void (*session_free)(fastd_context_t *ctx, fastd_method_session_state_t *session); + + bool (*encrypt)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in); + bool (*decrypt)(fastd_context_t *ctx, fastd_peer_t *peer, fastd_method_session_state_t *session, fastd_buffer_t *out, fastd_buffer_t in); +}; + + +bool fastd_method_create_by_name(const char *name, const fastd_method_t **method, fastd_method_context_t **method_ctx); + + +static inline const fastd_method_info_t* fastd_method_get_by_name(fastd_context_t *ctx, const char *name) { + size_t i; + for (i = 0; ctx->conf->methods[i].name; i++) { + if (!strcmp(ctx->conf->methods[i].name, name)) + return &ctx->conf->methods[i]; + } + + return NULL; +} + +#endif /* _FASTD_METHOD_H_ */ diff --git a/src/methods/cipher_test/cipher_test.c b/src/methods/cipher_test/cipher_test.c index 067835e..fcf58e6 100644 --- a/src/methods/cipher_test/cipher_test.c +++ b/src/methods/cipher_test/cipher_test.c @@ -25,21 +25,27 @@ #include "../../crypto.h" +#include "../../method.h" #include "../common.h" +struct fastd_method_context { + const fastd_cipher_info_t *cipher_info; +}; + struct fastd_method_session_state { fastd_method_common_t common; - const fastd_cipher_info_t *cipher_info; + const fastd_method_context_t *ctx; const fastd_cipher_t *cipher; fastd_cipher_state_t *cipher_state; }; -static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **info, const fastd_cipher_t **cipher) { - size_t len = strlen(name); +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx) { + fastd_method_context_t ctx; + size_t len = strlen(name); if (len < 12) return false; @@ -50,46 +56,30 @@ static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_ciphe memcpy(cipher_name, name, len-12); cipher_name[len-12] = 0; - const fastd_cipher_info_t *cipher_info = NULL; - - if (ctx) { - *cipher = fastd_cipher_get_by_name(ctx, cipher_name, &cipher_info); - if (!*cipher) - return false; - } - else { - cipher_info = fastd_cipher_info_get_by_name(cipher_name); - if (!cipher_info) - return false; - } + ctx.cipher_info = fastd_cipher_info_get_by_name(cipher_name); + if (!ctx.cipher_info) + return false; - if (info) - *info = cipher_info; + *method_ctx = malloc(sizeof(fastd_method_context_t)); + **method_ctx = ctx; return true; } - -static bool method_provides(const char *name) { - return cipher_get(NULL, name, NULL, NULL); +static void method_destroy(fastd_method_context_t *method_ctx) { + free(method_ctx); } -static size_t method_key_length(fastd_context_t *ctx, const char *name) { - const fastd_cipher_info_t *info; - if (!cipher_get(NULL, name, &info, NULL)) - exit_bug(ctx, "cipher-test: can't get cipher key length"); - - return info->key_length; +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx) { + return method_ctx->cipher_info->key_length; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); - - if (!cipher_get(ctx, name, &session->cipher_info, &session->cipher)) - exit_bug(ctx, "cipher-test: can't instanciate cipher"); - + session->ctx = method_ctx; + session->cipher = fastd_cipher_get(ctx, session->ctx->cipher_info); session->cipher_state = session->cipher->init(ctx, secret); pr_warn(ctx, "using cipher-test method; this method must be used for testing and benchmarks only"); @@ -127,11 +117,12 @@ static bool method_encrypt(fastd_context_t *ctx, fastd_peer_t *peer UNUSED, fast if (tail_len) memset(in.data+in.len, 0, tail_len); - uint8_t nonce[session->cipher_info->iv_length]; - if (session->cipher_info->iv_length) { - memset(nonce, 0, session->cipher_info->iv_length); - memcpy(nonce, session->common.send_nonce, min_size_t(COMMON_NONCEBYTES, session->cipher_info->iv_length)); - nonce[session->cipher_info->iv_length-1] = 1; + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + if (iv_length) { + memset(nonce, 0, iv_length); + memcpy(nonce, session->common.send_nonce, min_size_t(COMMON_NONCEBYTES, iv_length)); + nonce[iv_length-1] = 1; } int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); @@ -170,11 +161,12 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho if (common_nonce[COMMON_NONCEBYTES]) /* flags */ return false; - uint8_t nonce[session->cipher_info->iv_length]; - if (session->cipher_info->iv_length) { - memset(nonce, 0, session->cipher_info->iv_length); - memcpy(nonce, common_nonce, min_size_t(COMMON_NONCEBYTES, session->cipher_info->iv_length)); - nonce[session->cipher_info->iv_length-1] = 1; + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + if (iv_length) { + memset(nonce, 0, iv_length); + memcpy(nonce, common_nonce, min_size_t(COMMON_NONCEBYTES, iv_length)); + nonce[iv_length-1] = 1; } int64_t age; @@ -209,15 +201,17 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_cipher_test = { - .provides = method_provides, - .max_overhead = COMMON_HEADBYTES, .min_encrypt_head_space = 0, .min_decrypt_head_space = 0, .min_encrypt_tail_space = sizeof(fastd_block128_t)-1, .min_decrypt_tail_space = sizeof(fastd_block128_t)-1, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_is_valid = method_session_is_valid, .session_is_initiator = method_session_is_initiator, diff --git a/src/methods/composed_gmac/composed_gmac.c b/src/methods/composed_gmac/composed_gmac.c index 0705b7d..d1627ee 100644 --- a/src/methods/composed_gmac/composed_gmac.c +++ b/src/methods/composed_gmac/composed_gmac.c @@ -25,36 +25,43 @@ #include "../../crypto.h" +#include "../../method.h" #include "../common.h" static const fastd_block128_t ZERO_BLOCK = {}; + +struct fastd_method_context { + const fastd_cipher_info_t *cipher_info; + const fastd_cipher_info_t *gmac_cipher_info; + const fastd_mac_info_t *ghash_info; +}; + struct fastd_method_session_state { fastd_method_common_t common; - const fastd_cipher_info_t *cipher_info; + const fastd_method_context_t *ctx; + const fastd_cipher_t *cipher; fastd_cipher_state_t *cipher_state; - const fastd_cipher_info_t *gmac_cipher_info; const fastd_cipher_t *gmac_cipher; fastd_cipher_state_t *gmac_cipher_state; - const fastd_mac_info_t *ghash_info; const fastd_mac_t *ghash; fastd_mac_state_t *ghash_state; }; -static bool cipher_get(fastd_context_t *ctx, const char *name, - const fastd_cipher_info_t **cipher_info, const fastd_cipher_t **cipher, - const fastd_cipher_info_t **gmac_cipher_info, const fastd_cipher_t **gmac_cipher) { - if (!fastd_mac_info_get_by_name("ghash")) +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx) { + fastd_method_context_t ctx; + + ctx.ghash_info = fastd_mac_info_get_by_name("ghash"); + if (!ctx.ghash_info) return false; size_t len = strlen(name); - if (len < 5) return false; @@ -73,76 +80,52 @@ static bool cipher_get(fastd_context_t *ctx, const char *name, *gmac_cipher_name = 0; gmac_cipher_name++; - const fastd_cipher_info_t *info = NULL; - const fastd_cipher_info_t *gmac_info = NULL; - - if (ctx) { - *cipher = fastd_cipher_get_by_name(ctx, cipher_name, &info); - *gmac_cipher = fastd_cipher_get_by_name(ctx, gmac_cipher_name, &gmac_info); - if (!(*cipher && *gmac_cipher)) - return false; - } - else { - info = fastd_cipher_info_get_by_name(cipher_name); - gmac_info = fastd_cipher_info_get_by_name(gmac_cipher_name); - if (!(info && gmac_info)) - return false; - } - - if (cipher_info) - *cipher_info = info; - - if (gmac_cipher_info) - *gmac_cipher_info = gmac_info; - - return true; -} - + ctx.cipher_info = fastd_cipher_info_get_by_name(cipher_name); + if (!ctx.cipher_info) + return false; -static bool method_provides(const char *name) { - const fastd_cipher_info_t *gmac_cipher_info; + if (ctx.cipher_info->iv_length && ctx.cipher_info->iv_length <= COMMON_NONCEBYTES) + return false; - if (!cipher_get(NULL, name, NULL, NULL, &gmac_cipher_info, NULL)) + ctx.gmac_cipher_info = fastd_cipher_info_get_by_name(gmac_cipher_name); + if (!ctx.gmac_cipher_info) return false; - if (gmac_cipher_info->iv_length <= COMMON_NONCEBYTES) + if (ctx.gmac_cipher_info->iv_length <= COMMON_NONCEBYTES) return false; + *method_ctx = malloc(sizeof(fastd_method_context_t)); + **method_ctx = ctx; + return true; } -static size_t method_key_length(fastd_context_t *ctx, const char *name) { - const fastd_cipher_info_t *cipher_info; - const fastd_cipher_info_t *gmac_cipher_info; +static void method_destroy(fastd_method_context_t *method_ctx) { + free(method_ctx); +} - if (!cipher_get(NULL, name, &cipher_info, NULL, &gmac_cipher_info, NULL)) - exit_bug(ctx, "composed-gmac: can't get cipher key length"); - return cipher_info->key_length + gmac_cipher_info->key_length; +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx) { + return method_ctx->cipher_info->key_length + method_ctx->gmac_cipher_info->key_length; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); + session->ctx = method_ctx; - if (!cipher_get(ctx, name, - &session->cipher_info, &session->cipher, - &session->gmac_cipher_info, &session->gmac_cipher)) - exit_bug(ctx, "composed-gmac: can't instanciate cipher"); - + session->cipher = fastd_cipher_get(ctx, session->ctx->cipher_info); session->cipher_state = session->cipher->init(ctx, secret); - if (session->cipher_info->iv_length && session->cipher_info->iv_length <= COMMON_NONCEBYTES) - exit_bug(ctx, "composed-gmac: iv_length to small"); - session->gmac_cipher_state = session->gmac_cipher->init(ctx, secret + session->cipher_info->key_length); - if (session->gmac_cipher_info->iv_length <= COMMON_NONCEBYTES) - exit_bug(ctx, "composed-gmac: GMAC cipher iv_length to small"); + session->gmac_cipher = fastd_cipher_get(ctx, session->ctx->gmac_cipher_info); + session->gmac_cipher_state = session->gmac_cipher->init(ctx, secret + session->ctx->cipher_info->key_length); fastd_block128_t H; - uint8_t zeroiv[session->gmac_cipher_info->iv_length]; - memset(zeroiv, 0, session->gmac_cipher_info->iv_length); + size_t gmac_iv_length = session->ctx->gmac_cipher_info->iv_length; + uint8_t zeroiv[gmac_iv_length]; + memset(zeroiv, 0, gmac_iv_length); if (!session->gmac_cipher->crypt(ctx, session->gmac_cipher_state, &H, &ZERO_BLOCK, sizeof(fastd_block128_t), zeroiv)) { session->cipher->free(ctx, session->cipher_state); @@ -152,10 +135,7 @@ static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, c return NULL; } - session->ghash = fastd_mac_get_by_name(ctx, "ghash", &session->ghash_info); - if (!session->ghash) - exit_bug(ctx, "composed-gmac: can't instanciate ghash mac"); - + session->ghash = fastd_mac_get(ctx, session->ctx->ghash_info); session->ghash_state = session->ghash->init(ctx, H.b); return session; @@ -209,19 +189,21 @@ static bool method_encrypt(fastd_context_t *ctx, fastd_peer_t *peer UNUSED, fast fastd_block128_t *outblocks = out->data; fastd_block128_t sig; - uint8_t gmac_nonce[session->gmac_cipher_info->iv_length]; - memset(gmac_nonce, 0, session->gmac_cipher_info->iv_length); + size_t gmac_iv_length = session->ctx->gmac_cipher_info->iv_length; + uint8_t gmac_nonce[gmac_iv_length]; + memset(gmac_nonce, 0, gmac_iv_length); memcpy(gmac_nonce, session->common.send_nonce, COMMON_NONCEBYTES); - gmac_nonce[session->gmac_cipher_info->iv_length-1] = 1; + gmac_nonce[gmac_iv_length-1] = 1; bool ok = session->gmac_cipher->crypt(ctx, session->gmac_cipher_state, outblocks, &ZERO_BLOCK, sizeof(fastd_block128_t), gmac_nonce); if (ok) { - uint8_t nonce[session->cipher_info->iv_length]; - if (session->cipher_info->iv_length) { - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + if (iv_length) { + memset(nonce, 0, iv_length); memcpy(nonce, session->common.send_nonce, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; } ok = session->cipher->crypt(ctx, session->cipher_state, outblocks+1, inblocks, n_blocks*sizeof(fastd_block128_t), nonce); @@ -271,16 +253,18 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho if (!fastd_method_is_nonce_valid(ctx, &session->common, common_nonce, &age)) return false; - uint8_t gmac_nonce[session->gmac_cipher_info->iv_length]; - memset(gmac_nonce, 0, session->gmac_cipher_info->iv_length); + size_t gmac_iv_length = session->ctx->gmac_cipher_info->iv_length; + uint8_t gmac_nonce[gmac_iv_length]; + memset(gmac_nonce, 0, gmac_iv_length); memcpy(gmac_nonce, common_nonce, COMMON_NONCEBYTES); - gmac_nonce[session->gmac_cipher_info->iv_length-1] = 1; + gmac_nonce[gmac_iv_length-1] = 1; - uint8_t nonce[session->cipher_info->iv_length]; - if (session->cipher_info->iv_length) { - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + if (iv_length) { + memset(nonce, 0, iv_length); memcpy(nonce, common_nonce, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; } fastd_buffer_push_head(ctx, &in, COMMON_HEADBYTES); @@ -326,15 +310,17 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_composed_gmac = { - .provides = method_provides, - .max_overhead = COMMON_HEADBYTES + sizeof(fastd_block128_t), .min_encrypt_head_space = 0, .min_decrypt_head_space = 0, .min_encrypt_tail_space = sizeof(fastd_block128_t)-1, .min_decrypt_tail_space = 2*sizeof(fastd_block128_t)-1, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_is_valid = method_session_is_valid, .session_is_initiator = method_session_is_initiator, diff --git a/src/methods/generic_gcm/generic_gcm.c b/src/methods/generic_gcm/generic_gcm.c index 52065eb..3490f8b 100644 --- a/src/methods/generic_gcm/generic_gcm.c +++ b/src/methods/generic_gcm/generic_gcm.c @@ -25,91 +25,82 @@ #include "../../crypto.h" +#include "../../method.h" #include "../common.h" +struct fastd_method_context { + const fastd_cipher_info_t *cipher_info; + const fastd_mac_info_t *ghash_info; +}; + struct fastd_method_session_state { fastd_method_common_t common; - const fastd_cipher_info_t *cipher_info; + const fastd_method_context_t *ctx; + const fastd_cipher_t *cipher; fastd_cipher_state_t *cipher_state; - const fastd_mac_info_t *ghash_info; const fastd_mac_t *ghash; fastd_mac_state_t *ghash_state; }; -static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **cipher_info, const fastd_cipher_t **cipher) { - if (!fastd_mac_info_get_by_name("ghash")) +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx) { + fastd_method_context_t ctx; + + ctx.ghash_info = fastd_mac_info_get_by_name("ghash"); + if (!ctx.ghash_info) return false; size_t len = strlen(name); - if (len < 4) return false; if (strcmp(name+len-4, "-gcm")) return false; - char name_ctr[len+1]; - memcpy(name_ctr, name, len-3); - strncpy(name_ctr+len-3, "ctr", 4); + char cipher_name[len+1]; + memcpy(cipher_name, name, len-3); + strncpy(cipher_name+len-3, "ctr", 4); - const fastd_cipher_info_t *info = NULL; - - if (ctx) { - *cipher = fastd_cipher_get_by_name(ctx, name_ctr, &info); - if (!*cipher) - return false; - } - else { - info = fastd_cipher_info_get_by_name(name_ctr); - if (!info) - return false; - } + ctx.cipher_info = fastd_cipher_info_get_by_name(cipher_name); + if (!ctx.cipher_info) + return false; - if (info->iv_length <= COMMON_NONCEBYTES) + if (ctx.cipher_info->iv_length <= COMMON_NONCEBYTES) return false; - if (cipher_info) - *cipher_info = info; + *method_ctx = malloc(sizeof(fastd_method_context_t)); + **method_ctx = ctx; return true; } - -static bool method_provides(const char *name) { - return cipher_get(NULL, name, NULL, NULL); +static void method_destroy(fastd_method_context_t *method_ctx) { + free(method_ctx); } -static size_t method_key_length(fastd_context_t *ctx, const char *name) { - const fastd_cipher_info_t *cipher_info; - if (!cipher_get(NULL, name, &cipher_info, NULL)) - exit_bug(ctx, "generic-gcm: can't get cipher key length"); - - return cipher_info->key_length; +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx) { + return method_ctx->cipher_info->key_length; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); + session->ctx = method_ctx; - if (!cipher_get(ctx, name, &session->cipher_info, &session->cipher)) - exit_bug(ctx, "generic-gcm: can't instanciate cipher"); - + session->cipher = fastd_cipher_get(ctx, session->ctx->cipher_info); session->cipher_state = session->cipher->init(ctx, secret); static const fastd_block128_t zeroblock = {}; fastd_block128_t H; - if (session->cipher_info->iv_length <= COMMON_NONCEBYTES) - exit_bug(ctx, "generic-gcm: iv_length to small"); - - uint8_t zeroiv[session->cipher_info->iv_length]; - memset(zeroiv, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t zeroiv[iv_length]; + memset(zeroiv, 0, iv_length); if (!session->cipher->crypt(ctx, session->cipher_state, &H, &zeroblock, sizeof(fastd_block128_t), zeroiv)) { session->cipher->free(ctx, session->cipher_state); @@ -117,20 +108,17 @@ static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, c return NULL; } - session->ghash = fastd_mac_get_by_name(ctx, "ghash", &session->ghash_info); - if (!session->ghash) - exit_bug(ctx, "generic-gcm: can't instanciate ghash mac"); - + session->ghash = fastd_mac_get(ctx, session->ctx->ghash_info); session->ghash_state = session->ghash->init(ctx, H.b); return session; } -static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const char *name, const uint8_t *secret, size_t length, bool initiator) { +static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, size_t length, bool initiator) { if (length < sizeof(fastd_block128_t)) exit_bug(ctx, "generic-gcm: tried to init with short secret"); - return method_session_init(ctx, name, secret, initiator); + return method_session_init(ctx, method_ctx, secret, initiator); } static bool method_session_is_valid(fastd_context_t *ctx, fastd_method_session_state_t *session) { @@ -177,10 +165,11 @@ static bool method_encrypt(fastd_context_t *ctx, fastd_peer_t *peer UNUSED, fast if (tail_len) memset(in.data+in.len, 0, tail_len); - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, session->common.send_nonce, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); @@ -230,10 +219,11 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho if (((const uint8_t*)in.data)[COMMON_NONCEBYTES]) /* flags */ return false; - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, in.data, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int64_t age; if (!fastd_method_is_nonce_valid(ctx, &session->common, nonce, &age)) @@ -279,15 +269,17 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_generic_gcm = { - .provides = method_provides, - .max_overhead = COMMON_HEADBYTES + sizeof(fastd_block128_t), .min_encrypt_head_space = sizeof(fastd_block128_t), .min_decrypt_head_space = 0, .min_encrypt_tail_space = sizeof(fastd_block128_t)-1, .min_decrypt_tail_space = 2*sizeof(fastd_block128_t)-1, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_init_compat = method_session_init_compat, .session_is_valid = method_session_is_valid, diff --git a/src/methods/generic_gmac/generic_gmac.c b/src/methods/generic_gmac/generic_gmac.c index 4de7ad8..91b96cb 100644 --- a/src/methods/generic_gmac/generic_gmac.c +++ b/src/methods/generic_gmac/generic_gmac.c @@ -25,28 +25,37 @@ #include "../../crypto.h" +#include "../../method.h" #include "../common.h" +struct fastd_method_context { + const fastd_cipher_info_t *cipher_info; + const fastd_mac_info_t *ghash_info; +}; + + struct fastd_method_session_state { fastd_method_common_t common; - const fastd_cipher_info_t *cipher_info; + const fastd_method_context_t *ctx; + const fastd_cipher_t *cipher; fastd_cipher_state_t *cipher_state; - const fastd_mac_info_t *ghash_info; const fastd_mac_t *ghash; fastd_mac_state_t *ghash_state; }; -static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **cipher_info, const fastd_cipher_t **cipher) { - if (!fastd_mac_info_get_by_name("ghash")) +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx) { + fastd_method_context_t ctx; + + ctx.ghash_info = fastd_mac_info_get_by_name("ghash"); + if (!ctx.ghash_info) return false; size_t len = strlen(name); - if (len < 5) return false; @@ -60,70 +69,42 @@ static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_ciphe memcpy(cipher_name, name, len-5); cipher_name[len-5] = 0; - const fastd_cipher_info_t *info = NULL; - - if (ctx) { - *cipher = fastd_cipher_get_by_name(ctx, cipher_name, &info); - if (!*cipher) - return false; - } - else { - info = fastd_cipher_info_get_by_name(cipher_name); - if (!info) - return false; - } + ctx.cipher_info = fastd_cipher_info_get_by_name(cipher_name); + if (!ctx.cipher_info) + return false; - if (info->iv_length <= COMMON_NONCEBYTES) + if (ctx.cipher_info->iv_length <= COMMON_NONCEBYTES) return false; - if (cipher_info) - *cipher_info = info; + *method_ctx = malloc(sizeof(fastd_method_context_t)); + **method_ctx = ctx; return true; } - -static bool method_provides(const char *name) { - return cipher_get(NULL, name, NULL, NULL); +static void method_destroy(fastd_method_context_t *method_ctx) { + free(method_ctx); } -static size_t method_key_length(fastd_context_t *ctx, const char *name) { - const fastd_cipher_info_t *cipher_info; - if (!cipher_get(NULL, name, &cipher_info, NULL)) - exit_bug(ctx, "generic-gmac: can't get cipher key length"); - - return cipher_info->key_length + sizeof(fastd_block128_t); +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx) { + return method_ctx->cipher_info->key_length + method_ctx->ghash_info->key_length; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); + session->ctx = method_ctx; - if (!cipher_get(ctx, name, &session->cipher_info, &session->cipher)) - exit_bug(ctx, "generic-gmac: can't instanciate cipher"); - + session->cipher = fastd_cipher_get(ctx, session->ctx->cipher_info); session->cipher_state = session->cipher->init(ctx, secret); - if (session->cipher_info->iv_length <= COMMON_NONCEBYTES) - exit_bug(ctx, "generic-gmac: iv_length to small"); - - session->ghash = fastd_mac_get_by_name(ctx, "ghash", &session->ghash_info); - if (!session->ghash) - exit_bug(ctx, "generic-gmac: can't instanciate ghash mac"); - - session->ghash_state = session->ghash->init(ctx, secret + session->cipher_info->key_length); + session->ghash = fastd_mac_get(ctx, session->ctx->ghash_info); + session->ghash_state = session->ghash->init(ctx, secret + session->ctx->cipher_info->key_length); return session; } -static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const char *name, const uint8_t *secret, size_t length, bool initiator) { - if (length < sizeof(fastd_block128_t)) - exit_bug(ctx, "generic-gmac: tried to init with short secret"); - - return method_session_init(ctx, name, secret, initiator); -} - static bool method_session_is_valid(fastd_context_t *ctx, fastd_method_session_state_t *session) { return (session && fastd_method_session_common_is_valid(ctx, &session->common)); } @@ -168,10 +149,11 @@ static bool method_encrypt(fastd_context_t *ctx, fastd_peer_t *peer UNUSED, fast if (tail_len) memset(in.data+in.len, 0, tail_len); - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, session->common.send_nonce, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); @@ -221,10 +203,12 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho if (((const uint8_t*)in.data)[COMMON_NONCEBYTES]) /* flags */ return false; - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, in.data, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int64_t age; if (!fastd_method_is_nonce_valid(ctx, &session->common, nonce, &age)) @@ -270,17 +254,18 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_generic_gmac = { - .provides = method_provides, - .max_overhead = COMMON_HEADBYTES + sizeof(fastd_block128_t), .min_encrypt_head_space = sizeof(fastd_block128_t), .min_decrypt_head_space = 0, .min_encrypt_tail_space = sizeof(fastd_block128_t)-1, .min_decrypt_tail_space = 2*sizeof(fastd_block128_t)-1, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, - .session_init_compat = method_session_init_compat, .session_is_valid = method_session_is_valid, .session_is_initiator = method_session_is_initiator, .session_want_refresh = method_session_want_refresh, diff --git a/src/methods/generic_poly1305/generic_poly1305.c b/src/methods/generic_poly1305/generic_poly1305.c index c40e70f..f84046e 100644 --- a/src/methods/generic_poly1305/generic_poly1305.c +++ b/src/methods/generic_poly1305/generic_poly1305.c @@ -25,6 +25,7 @@ #include "../../crypto.h" +#include "../../method.h" #include "../common.h" #include @@ -33,18 +34,23 @@ #define AUTHBLOCKS 2 +struct fastd_method_context { + const fastd_cipher_info_t *cipher_info; +}; + struct fastd_method_session_state { fastd_method_common_t common; - const fastd_cipher_info_t *cipher_info; + const fastd_method_context_t *ctx; const fastd_cipher_t *cipher; fastd_cipher_state_t *cipher_state; }; -static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_cipher_info_t **cipher_info, const fastd_cipher_t **cipher) { - size_t len = strlen(name); +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx) { + fastd_method_context_t ctx; + size_t len = strlen(name); if (len < 9) return false; @@ -55,54 +61,35 @@ static bool cipher_get(fastd_context_t *ctx, const char *name, const fastd_ciphe memcpy(cipher_name, name, len-9); cipher_name[len-9] = 0; - const fastd_cipher_info_t *info = NULL; - - if (ctx) { - *cipher = fastd_cipher_get_by_name(ctx, cipher_name, &info); - if (!*cipher) - return false; - } - else { - info = fastd_cipher_info_get_by_name(cipher_name); - if (!info) - return false; - } + ctx.cipher_info = fastd_cipher_info_get_by_name(cipher_name); + if (!ctx.cipher_info) + return false; - if (info->iv_length <= COMMON_NONCEBYTES) + if (ctx.cipher_info->iv_length <= COMMON_NONCEBYTES) return false; - if (cipher_info) - *cipher_info = info; + *method_ctx = malloc(sizeof(fastd_method_context_t)); + **method_ctx = ctx; return true; } - -static bool method_provides(const char *name) { - return cipher_get(NULL, name, NULL, NULL); +static void method_destroy(fastd_method_context_t *method_ctx) { + free(method_ctx); } -static size_t method_key_length(fastd_context_t *ctx, const char *name) { - const fastd_cipher_info_t *cipher_info; - if (!cipher_get(NULL, name, &cipher_info, NULL)) - exit_bug(ctx, "generic-poly1305: can't get cipher key length"); - - return cipher_info->key_length; +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx) { + return method_ctx->cipher_info->key_length; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); - - if (!cipher_get(ctx, name, &session->cipher_info, &session->cipher)) - exit_bug(ctx, "generic-poly1305: can't instanciate cipher"); - + session->ctx = method_ctx; + session->cipher = fastd_cipher_get(ctx, session->ctx->cipher_info); session->cipher_state = session->cipher->init(ctx, secret); - if (session->cipher_info->iv_length <= COMMON_NONCEBYTES) - exit_bug(ctx, "generic-poly1305: iv_length to small"); - return session; } @@ -139,10 +126,11 @@ static bool method_encrypt(fastd_context_t *ctx, fastd_peer_t *peer UNUSED, fast if (tail_len) memset(in.data+in.len, 0, tail_len); - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, session->common.send_nonce, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int n_blocks = block_count(in.len, sizeof(fastd_block128_t)); @@ -186,10 +174,11 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho if (((const uint8_t*)in.data)[COMMON_NONCEBYTES]) /* flags */ return false; - uint8_t nonce[session->cipher_info->iv_length]; - memset(nonce, 0, session->cipher_info->iv_length); + size_t iv_length = session->ctx->cipher_info->iv_length; + uint8_t nonce[iv_length]; + memset(nonce, 0, iv_length); memcpy(nonce, in.data, COMMON_NONCEBYTES); - nonce[session->cipher_info->iv_length-1] = 1; + nonce[iv_length-1] = 1; int64_t age; if (!fastd_method_is_nonce_valid(ctx, &session->common, nonce, &age)) @@ -245,15 +234,17 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_generic_poly1305 = { - .provides = method_provides, - .max_overhead = COMMON_HEADBYTES + crypto_onetimeauth_poly1305_BYTES, .min_encrypt_head_space = AUTHBLOCKS*sizeof(fastd_block128_t), .min_decrypt_head_space = AUTHBLOCKS*sizeof(fastd_block128_t) - crypto_onetimeauth_poly1305_BYTES, .min_encrypt_tail_space = sizeof(fastd_block128_t)-1, .min_decrypt_tail_space = sizeof(fastd_block128_t)-1, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_is_valid = method_session_is_valid, .session_is_initiator = method_session_is_initiator, diff --git a/src/methods/methods.c.in b/src/methods/methods.c.in index 2a8d9fb..a2c7963 100644 --- a/src/methods/methods.c.in +++ b/src/methods/methods.c.in @@ -24,7 +24,7 @@ */ -#include +#include @METHOD_DEFINITIONS@ @@ -33,12 +33,14 @@ static const fastd_method_t *const methods[] = { @METHOD_LIST@ }; -const fastd_method_t* fastd_method_get_by_name(const char *name) { +bool fastd_method_create_by_name(const char *name, const fastd_method_t **method, fastd_method_context_t **method_ctx) { size_t i; for (i = 0; i < array_size(methods); i++) { - if (methods[i]->provides(name)) - return methods[i]; + if (methods[i]->create_by_name(name, method_ctx)) { + *method = methods[i]; + return true; + } } - return NULL; + return false; } diff --git a/src/methods/null/null.c b/src/methods/null/null.c index 3f23866..f4784c8 100644 --- a/src/methods/null/null.c +++ b/src/methods/null/null.c @@ -24,7 +24,7 @@ */ -#include "../../fastd.h" +#include "../../method.h" struct fastd_method_session_state { @@ -33,15 +33,18 @@ struct fastd_method_session_state { }; -static bool method_provides(const char *name) { +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx UNUSED) { return !strcmp(name, "null"); } -static size_t method_key_length(fastd_context_t *ctx UNUSED, const char *name UNUSED) { +static void method_destroy(fastd_method_context_t *method_ctx UNUSED) { +} + +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx UNUSED) { return 0; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx UNUSED, const char *name UNUSED, const uint8_t *secret UNUSED, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx UNUSED, const uint8_t *secret UNUSED, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); session->valid = true; @@ -50,8 +53,8 @@ static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx UN return session; } -static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const char *name, const uint8_t *secret, size_t length UNUSED, bool initiator) { - return method_session_init(ctx, name, secret, initiator); +static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, size_t length UNUSED, bool initiator) { + return method_session_init(ctx, method_ctx, secret, initiator); } static bool method_session_is_valid(fastd_context_t *ctx UNUSED, fastd_method_session_state_t *session) { @@ -80,15 +83,17 @@ static bool method_passthrough(fastd_context_t *ctx UNUSED, fastd_peer_t *peer U } const fastd_method_t fastd_method_null = { - .provides = method_provides, - .max_overhead = 0, .min_encrypt_head_space = 0, .min_decrypt_head_space = 0, .min_encrypt_tail_space = 0, .min_decrypt_tail_space = 0, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_init_compat = method_session_init_compat, .session_is_valid = method_session_is_valid, diff --git a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c index c6e22fb..88a0525 100644 --- a/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c +++ b/src/methods/xsalsa20_poly1305/xsalsa20_poly1305.c @@ -24,7 +24,7 @@ */ -#include "../../fastd.h" +#include "../../method.h" #include "../common.h" #include @@ -37,15 +37,18 @@ struct fastd_method_session_state { }; -static bool method_provides(const char *name) { +static bool method_create_by_name(const char *name, fastd_method_context_t **method_ctx UNUSED) { return !strcmp(name, "xsalsa20-poly1305"); } -static size_t method_key_length(fastd_context_t *ctx UNUSED, const char *name UNUSED) { +static void method_destroy(fastd_method_context_t *method_ctx UNUSED) { +} + +static size_t method_key_length(fastd_context_t *ctx UNUSED, const fastd_method_context_t *method_ctx UNUSED) { return crypto_secretbox_xsalsa20poly1305_KEYBYTES; } -static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const char *name UNUSED, const uint8_t *secret, bool initiator) { +static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, const fastd_method_context_t *method_ctx UNUSED, const uint8_t *secret, bool initiator) { fastd_method_session_state_t *session = malloc(sizeof(fastd_method_session_state_t)); fastd_method_common_init(ctx, &session->common, initiator); @@ -55,11 +58,11 @@ static fastd_method_session_state_t* method_session_init(fastd_context_t *ctx, c return session; } -static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const char *name, const uint8_t *secret, size_t length, bool initiator) { +static fastd_method_session_state_t* method_session_init_compat(fastd_context_t *ctx, const fastd_method_context_t *method_ctx, const uint8_t *secret, size_t length, bool initiator) { if (length < crypto_secretbox_xsalsa20poly1305_KEYBYTES) exit_bug(ctx, "xsalsa20-poly1305: tried to init with short secret"); - return method_session_init(ctx, name, secret, initiator); + return method_session_init(ctx, method_ctx, secret, initiator); } static bool method_session_is_valid(fastd_context_t *ctx, fastd_method_session_state_t *session) { @@ -153,7 +156,6 @@ static bool method_decrypt(fastd_context_t *ctx, fastd_peer_t *peer, fastd_metho } const fastd_method_t fastd_method_xsalsa20_poly1305 = { - .provides = method_provides, .max_overhead = COMMON_HEADBYTES + crypto_secretbox_xsalsa20poly1305_ZEROBYTES - crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES, .min_encrypt_head_space = crypto_secretbox_xsalsa20poly1305_ZEROBYTES, @@ -161,7 +163,11 @@ const fastd_method_t fastd_method_xsalsa20_poly1305 = { .min_encrypt_tail_space = 0, .min_decrypt_tail_space = 0, + .create_by_name = method_create_by_name, + .destroy = method_destroy, + .key_length = method_key_length, + .session_init = method_session_init, .session_init_compat = method_session_init_compat, .session_is_valid = method_session_is_valid, diff --git a/src/options.c b/src/options.c index f7dd88f..c86717b 100644 --- a/src/options.c +++ b/src/options.c @@ -251,8 +251,7 @@ static void option_protocol(fastd_context_t *ctx, fastd_config_t *conf, const ch } static void option_method(fastd_context_t *ctx, fastd_config_t *conf, const char *arg) { - if (!fastd_config_method(ctx, conf, arg)) - exit_error(ctx, "unsupported method `%s'", arg); + fastd_config_method(ctx, conf, arg); } static void option_forward(fastd_context_t *ctx UNUSED, fastd_config_t *conf) { diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c index 743b0d1..a8de436 100644 --- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c +++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.c @@ -41,7 +41,7 @@ static inline bool read_key(uint8_t key[32], const char *hexkey) { static inline void check_session_refresh(fastd_context_t *ctx, fastd_peer_t *peer) { protocol_session_t *session = &peer->protocol_state->session; - if (!session->refreshing && session->method->session_want_refresh(ctx, session->method_state)) { + if (!session->refreshing && session->method->method->session_want_refresh(ctx, session->method_state)) { pr_verbose(ctx, "refreshing session with %P", peer); session->handshakes_cleaned = true; session->refreshing = true; @@ -104,17 +104,17 @@ static void protocol_handle_recv(fastd_context_t *ctx, fastd_peer_t *peer, fastd bool ok = false; if (is_session_valid(ctx, &peer->protocol_state->old_session)) { - if (peer->protocol_state->old_session.method->decrypt(ctx, peer, peer->protocol_state->old_session.method_state, &recv_buffer, buffer)) + if (peer->protocol_state->old_session.method->method->decrypt(ctx, peer, peer->protocol_state->old_session.method_state, &recv_buffer, buffer)) ok = true; } if (!ok) { - if (peer->protocol_state->session.method->decrypt(ctx, peer, peer->protocol_state->session.method_state, &recv_buffer, buffer)) { + if (peer->protocol_state->session.method->method->decrypt(ctx, peer, peer->protocol_state->session.method_state, &recv_buffer, buffer)) { ok = true; if (peer->protocol_state->old_session.method) { pr_debug(ctx, "invalidating old session with %P", peer); - peer->protocol_state->old_session.method->session_free(ctx, peer->protocol_state->old_session.method_state); + peer->protocol_state->old_session.method->method->session_free(ctx, peer->protocol_state->old_session.method_state); peer->protocol_state->old_session = (protocol_session_t){}; } @@ -123,7 +123,7 @@ static void protocol_handle_recv(fastd_context_t *ctx, fastd_peer_t *peer, fastd fastd_peer_unschedule_handshake(ctx, peer); peer->protocol_state->session.handshakes_cleaned = true; - if (peer->protocol_state->session.method->session_is_initiator(ctx, peer->protocol_state->session.method_state)) + if (peer->protocol_state->session.method->method->session_is_initiator(ctx, peer->protocol_state->session.method_state)) fastd_protocol_ec25519_fhmqvc_send_empty(ctx, peer, &peer->protocol_state->session); } @@ -153,7 +153,7 @@ static void session_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer_ size_t stat_size = buffer.len; fastd_buffer_t send_buffer; - if (!session->method->encrypt(ctx, peer, session->method_state, &send_buffer, buffer)) { + if (!session->method->method->encrypt(ctx, peer, session->method_state, &send_buffer, buffer)) { fastd_buffer_free(buffer); pr_error(ctx, "failed to encrypt packet for %P", peer); return; @@ -171,7 +171,7 @@ static void protocol_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer check_session_refresh(ctx, peer); - if (peer->protocol_state->session.method->session_is_initiator(ctx, peer->protocol_state->session.method_state) && is_session_valid(ctx, &peer->protocol_state->old_session)) { + if (peer->protocol_state->session.method->method->session_is_initiator(ctx, peer->protocol_state->session.method_state) && is_session_valid(ctx, &peer->protocol_state->old_session)) { pr_debug2(ctx, "sending packet for old session to %P", peer); session_send(ctx, peer, buffer, &peer->protocol_state->old_session); } @@ -181,7 +181,7 @@ static void protocol_send(fastd_context_t *ctx, fastd_peer_t *peer, fastd_buffer } void fastd_protocol_ec25519_fhmqvc_send_empty(fastd_context_t *ctx, fastd_peer_t *peer, protocol_session_t *session) { - session_send(ctx, peer, fastd_buffer_alloc(ctx, 0, alignto(session->method->min_encrypt_head_space, 8), session->method->min_encrypt_tail_space), session); + session_send(ctx, peer, fastd_buffer_alloc(ctx, 0, alignto(session->method->method->min_encrypt_head_space, 8), session->method->method->min_encrypt_tail_space), session); } const fastd_protocol_t fastd_protocol_ec25519_fhmqvc = { diff --git a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h index 608276f..638117d 100644 --- a/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h +++ b/src/protocols/ec25519_fhmqvc/ec25519_fhmqvc.h @@ -28,6 +28,7 @@ #define _FASTD_PROTOCOL_EC25519_FHMQVC_H_ #include "../../fastd.h" +#include "../../method.h" #include "../../peer.h" #include "../../sha256.h" @@ -59,7 +60,7 @@ typedef struct protocol_session { bool handshakes_cleaned; bool refreshing; - const fastd_method_t *method; + const fastd_method_info_t *method; fastd_method_session_state_t *method_state; } protocol_session_t; @@ -87,7 +88,7 @@ void fastd_protocol_ec25519_fhmqvc_reset_peer_state(fastd_context_t *ctx, fastd_ void fastd_protocol_ec25519_fhmqvc_free_peer_state(fastd_context_t *ctx, fastd_peer_t *peer); void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer); -void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_context_t *ctx, 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, const char *method); +void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_context_t *ctx, 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, const fastd_method_info_t *method); void fastd_protocol_ec25519_fhmqvc_send_empty(fastd_context_t *ctx, fastd_peer_t *peer, protocol_session_t *session); @@ -105,7 +106,7 @@ static inline void hexdump(char out[65], const unsigned char d[32]) { static inline bool is_session_valid(fastd_context_t *ctx, const protocol_session_t *session) { - return (session->method && session->method->session_is_valid(ctx, session->method_state)); + return (session->method && session->method->method->session_is_valid(ctx, session->method_state)); } #endif /* _FASTD_PROTOCOL_EC25519_FHMQVC_H_ */ diff --git a/src/protocols/ec25519_fhmqvc/handshake.c b/src/protocols/ec25519_fhmqvc/handshake.c index c359fb1..0225513 100644 --- a/src/protocols/ec25519_fhmqvc/handshake.c +++ b/src/protocols/ec25519_fhmqvc/handshake.c @@ -68,46 +68,46 @@ static void derive_key(fastd_sha256_t *out, size_t blocks, const uint32_t *salt, fastd_hkdf_sha256_expand(out, blocks, &prk, info, sizeof(info)); } -static inline void supersede_session(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_t *method) { +static inline void supersede_session(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_info_t *method) { if (is_session_valid(ctx, &peer->protocol_state->session) && !is_session_valid(ctx, &peer->protocol_state->old_session)) { if (peer->protocol_state->old_session.method) - peer->protocol_state->old_session.method->session_free(ctx, peer->protocol_state->old_session.method_state); + peer->protocol_state->old_session.method->method->session_free(ctx, peer->protocol_state->old_session.method_state); peer->protocol_state->old_session = peer->protocol_state->session; } else { if (peer->protocol_state->session.method) - peer->protocol_state->session.method->session_free(ctx, peer->protocol_state->session.method_state); + peer->protocol_state->session.method->method->session_free(ctx, peer->protocol_state->session.method_state); } if (peer->protocol_state->old_session.method) { if (peer->protocol_state->old_session.method != method) { pr_debug(ctx, "method of %P has changed, terminating old session", peer); - peer->protocol_state->old_session.method->session_free(ctx, peer->protocol_state->old_session.method_state); + peer->protocol_state->old_session.method->method->session_free(ctx, peer->protocol_state->old_session.method_state); peer->protocol_state->old_session = (protocol_session_t){}; } else { - peer->protocol_state->old_session.method->session_superseded(ctx, peer->protocol_state->old_session.method_state); + peer->protocol_state->old_session.method->method->session_superseded(ctx, peer->protocol_state->old_session.method_state); } } } -static inline bool new_session(fastd_context_t *ctx, fastd_peer_t *peer, const char *method_name, const fastd_method_t *method, bool initiator, +static inline bool new_session(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_info_t *method, bool initiator, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, const aligned_int256_t *sigma, const uint32_t *salt, uint64_t serial) { supersede_session(ctx, peer, method); if (salt) { - size_t blocks = block_count(method->key_length(ctx, method_name), sizeof(fastd_sha256_t)); + size_t blocks = block_count(method->method->key_length(ctx, method->ctx), sizeof(fastd_sha256_t)); fastd_sha256_t secret[blocks]; - derive_key(secret, blocks, salt, method_name, A, B, X, Y, sigma); + derive_key(secret, blocks, salt, method->name, A, B, X, Y, sigma); - peer->protocol_state->session.method_state = method->session_init(ctx, method_name, (const uint8_t*)secret, initiator); + peer->protocol_state->session.method_state = method->method->session_init(ctx, method->ctx, (const uint8_t*)secret, initiator); } else { fastd_sha256_t hash; fastd_sha256_blocks(&hash, X->u32, Y->u32, A->u32, B->u32, sigma->u32, NULL); - peer->protocol_state->session.method_state = method->session_init_compat(ctx, method_name, hash.b, HASHBYTES, initiator); + peer->protocol_state->session.method_state = method->method->session_init_compat(ctx, method->ctx, hash.b, HASHBYTES, initiator); } if (!peer->protocol_state->session.method_state) @@ -122,7 +122,7 @@ static inline bool new_session(fastd_context_t *ctx, fastd_peer_t *peer, const c return true; } -static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const char *method_name, fastd_socket_t *sock, +static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const fastd_method_info_t *method, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, bool initiator, const aligned_int256_t *A, const aligned_int256_t *B, const aligned_int256_t *X, const aligned_int256_t *Y, const aligned_int256_t *sigma, const uint32_t *salt, uint64_t serial) { @@ -131,9 +131,8 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const char *meth return false; } - const fastd_method_t *method = fastd_method_get_by_name(method_name); - if (!salt && !method->session_init_compat) { - pr_warn(ctx, "can't establish session with %P[%I] (method without compat support)", peer, remote_addr); + if (!salt && !method->method->session_init_compat) { + pr_warn(ctx, "can't establish compat session with %P[%I] (method without compat support)", peer, remote_addr); return false; } @@ -145,8 +144,8 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const char *meth return false; } - if (!new_session(ctx, peer, method_name, method, initiator, A, B, X, Y, sigma, salt, serial)) { - pr_error(ctx, "failed to initialize method session for %P (method `%s'%s)", peer, method_name, salt ? "" : " (compat mode)"); + if (!new_session(ctx, peer, method, initiator, A, B, X, Y, sigma, salt, serial)) { + pr_error(ctx, "failed to initialize method session for %P (method `%s'%s)", peer, method->name, salt ? "" : " (compat mode)"); fastd_peer_reset(ctx, peer); return false; } @@ -154,7 +153,7 @@ static bool establish(fastd_context_t *ctx, fastd_peer_t *peer, const char *meth fastd_peer_seen(ctx, peer); fastd_peer_set_established(ctx, peer); - pr_verbose(ctx, "new session with %P established using method `%s'%s.", peer, method_name, salt ? "" : " (compat mode)"); + pr_verbose(ctx, "new session with %P established using method `%s'%s.", peer, method->name, salt ? "" : " (compat mode)"); if (initiator) fastd_peer_schedule_handshake_default(ctx, peer); @@ -271,7 +270,7 @@ static void clear_shared_handshake_key(fastd_context_t *ctx UNUSED, const fastd_ } static void respond_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, - const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, const fastd_handshake_t *handshake, const char *method) { + const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, const fastd_handshake_t *handshake, const fastd_method_info_t *method) { pr_debug(ctx, "responding handshake with %P[%I]...", peer, remote_addr); if (!update_shared_handshake_key(ctx, peer, handshake_key, peer_handshake_key)) @@ -299,7 +298,7 @@ static void respond_handshake(fastd_context_t *ctx, const fastd_socket_t *sock, } static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, - const fastd_handshake_t *handshake, const char *method) { + const fastd_handshake_t *handshake, const fastd_method_info_t *method) { pr_debug(ctx, "finishing handshake with %P[%I]...", peer, remote_addr); bool compat = !secure_handshake(handshake); @@ -361,7 +360,7 @@ static void finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const f static void handle_finish_handshake(fastd_context_t *ctx, fastd_socket_t *sock, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *remote_addr, fastd_peer_t *peer, const handshake_key_t *handshake_key, const aligned_int256_t *peer_handshake_key, - const fastd_handshake_t *handshake, const char *method) { + const fastd_handshake_t *handshake, const fastd_method_info_t *method) { pr_debug(ctx, "handling handshake finish with %P[%I]...", peer, remote_addr); bool compat = !secure_handshake(handshake); @@ -538,7 +537,7 @@ void fastd_protocol_ec25519_fhmqvc_handshake_init(fastd_context_t *ctx, const fa fastd_send_handshake(ctx, sock, local_addr, remote_addr, peer, buffer); } -void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_context_t *ctx, 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, const char *method) { +void fastd_protocol_ec25519_fhmqvc_handshake_handle(fastd_context_t *ctx, 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, const fastd_method_info_t *method) { bool temporary_added = false; fastd_protocol_ec25519_fhmqvc_maintenance(ctx); diff --git a/src/protocols/ec25519_fhmqvc/state.c b/src/protocols/ec25519_fhmqvc/state.c index 727763a..f27fcc6 100644 --- a/src/protocols/ec25519_fhmqvc/state.c +++ b/src/protocols/ec25519_fhmqvc/state.c @@ -77,7 +77,7 @@ void fastd_protocol_ec25519_fhmqvc_init_peer_state(fastd_context_t *ctx, fastd_p static void reset_session(fastd_context_t *ctx, protocol_session_t *session) { if (session->method) - session->method->session_free(ctx, session->method_state); + session->method->method->session_free(ctx, session->method_state); secure_memzero(session, sizeof(protocol_session_t)); } diff --git a/src/types.h b/src/types.h index fc26f3a..664518d 100644 --- a/src/types.h +++ b/src/types.h @@ -113,6 +113,7 @@ typedef struct fastd_config fastd_config_t; typedef struct fastd_context fastd_context_t; typedef struct fastd_protocol fastd_protocol_t; +typedef struct fastd_method_info fastd_method_info_t; typedef struct fastd_method fastd_method_t; typedef struct fastd_cipher_info fastd_cipher_info_t; @@ -141,6 +142,7 @@ typedef struct fastd_protocol_state fastd_protocol_state_t; typedef struct fastd_protocol_peer_config fastd_protocol_peer_config_t; typedef struct fastd_protocol_peer_state fastd_protocol_peer_state_t; +typedef struct fastd_method_context fastd_method_context_t; typedef struct fastd_method_session_state fastd_method_session_state_t; typedef struct fastd_cipher_state fastd_cipher_state_t; -- cgit v1.2.3