diff options
-rw-r--r-- | ChangeLog.adoc | 2 | ||||
-rw-r--r-- | src/plugins/relay/api/relay-api-protocol.c | 57 | ||||
-rw-r--r-- | src/plugins/relay/api/relay-api.c | 2 | ||||
-rw-r--r-- | src/plugins/relay/relay-auth.c | 234 | ||||
-rw-r--r-- | src/plugins/relay/relay-auth.h | 8 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.c | 11 | ||||
-rw-r--r-- | src/plugins/relay/relay-client.h | 1 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.c | 8 | ||||
-rw-r--r-- | src/plugins/relay/relay-config.h | 1 | ||||
-rw-r--r-- | src/plugins/relay/relay-http.c | 172 | ||||
-rw-r--r-- | src/plugins/relay/relay-http.h | 17 | ||||
-rw-r--r-- | src/plugins/relay/weechat/relay-weechat-protocol.c | 11 | ||||
-rw-r--r-- | tests/unit/plugins/relay/test-relay-auth.cpp | 109 | ||||
-rw-r--r-- | tests/unit/plugins/relay/test-relay-http.cpp | 234 |
14 files changed, 638 insertions, 229 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc index 677da6da5..198aa428f 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -19,7 +19,7 @@ New features:: * core: use function util_strftimeval in evaluation of expression `date:xxx` * api: add support of specifier `%!` for timestamp in function util_strftimeval * api: add support of base64url in encode/decode functions - * relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string, rename option relay.weechat.commands to relay.network.commands (issue #2066) + * relay: add "api" protocol (HTTP REST API), add option relay.look.display_clients, change option type relay.look.auto_open_buffer to string, rename option relay.weechat.commands to relay.network.commands, add option relay.network.time_window (issue #2066) * relay: add support of websocket extension "permessage-deflate" (issue #1549) Bug fixes:: diff --git a/src/plugins/relay/api/relay-api-protocol.c b/src/plugins/relay/api/relay-api-protocol.c index f04264125..b850194f7 100644 --- a/src/plugins/relay/api/relay-api-protocol.c +++ b/src/plugins/relay/api/relay-api-protocol.c @@ -39,60 +39,6 @@ /* - * Checks authentication from client. - * - * Returns: - * 1: OK, client authenticated - * 0: client NOT authenticated - */ - -int -relay_api_protocol_check_auth (struct t_relay_client *client, - struct t_relay_http_request *request) -{ - if (client->status == RELAY_STATUS_CONNECTED) - return 1; - - switch (relay_http_check_auth (request)) - { - case 0: /* OK */ - return 1; - case -1: /* missing password */ - relay_api_msg_send_error_json (client, - RELAY_HTTP_401_UNAUTHORIZED, - "WWW-Authenticate: Basic realm=Password", - RELAY_HTTP_ERROR_MISSING_PASSWORD); - break; - case -2: /* invalid password */ - relay_api_msg_send_error_json (client, - RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_INVALID_PASSWORD); - break; - case -3: /* missing TOTP */ - relay_api_msg_send_error_json (client, - RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_MISSING_TOTP); - break; - case -4: /* invalid TOTP */ - relay_api_msg_send_error_json (client, - RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_INVALID_TOTP); - break; - case -5: /* out of memory */ - relay_api_msg_send_error_json (client, - RELAY_HTTP_503_SERVICE_UNAVAILABLE, - NULL, - RELAY_HTTP_ERROR_OUT_OF_MEMORY); - break; - } - - return 0; -} - -/* * Returns value of an URL parameter as boolean (0 or 1), using a default value * if the parameter is not set or if it's not a valid boolean. */ @@ -677,7 +623,8 @@ relay_api_protocol_recv_http (struct t_relay_client *client, if (!request || RELAY_CLIENT_HAS_ENDED(client)) return; - if (!relay_api_protocol_check_auth (client, request)) + if ((client->status != RELAY_STATUS_CONNECTED) + && !relay_http_check_auth (client, request)) { relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); return; diff --git a/src/plugins/relay/api/relay-api.c b/src/plugins/relay/api/relay-api.c index a82c72e0b..158305367 100644 --- a/src/plugins/relay/api/relay-api.c +++ b/src/plugins/relay/api/relay-api.c @@ -134,7 +134,7 @@ relay_api_unhook_signals (struct t_relay_client *client) void relay_api_recv_http (struct t_relay_client *client, - struct t_relay_http_request *request) + struct t_relay_http_request *request) { relay_api_protocol_recv_http (client, request); } diff --git a/src/plugins/relay/relay-auth.c b/src/plugins/relay/relay-auth.c index 76bdf35a7..a03dc0559 100644 --- a/src/plugins/relay/relay-auth.c +++ b/src/plugins/relay/relay-auth.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <time.h> #include <gcrypt.h> #include "../weechat-plugin.h" @@ -103,37 +104,28 @@ relay_auth_generate_nonce (int size) * Checks if password received as plain text is valid. * * Returns: - * 1: password is valid - * 0: password is not valid + * 0: password is valid + * -1: (plain-text password ("plain") is not allowed + * -2: password is not valid */ int -relay_auth_check_password_plain (const char *password, +relay_auth_check_password_plain (struct t_relay_client *client, + const char *password, const char *relay_password) { - if (!password || !relay_password) - return 0; - - return (strcmp (password, relay_password) == 0) ? 1 : 0; -} + if (!client || !password || !relay_password) + return -2; -/* - * Authenticates with password (plain text). - * - * Returns: - * 1: authentication OK - * 0: authentication failed - */ - -int -relay_auth_password (struct t_relay_client *client, - const char *password, const char *relay_password) -{ - if (client->password_hash_algo != RELAY_AUTH_PASSWORD_HASH_PLAIN) - return 0; - - return relay_auth_check_password_plain (password, relay_password); + if (!weechat_string_match_list ( + "plain", + (const char **)relay_config_network_password_hash_algo_list, + 1)) + { + return -1; + } + return (strcmp (password, relay_password) == 0) ? 0 : -2; } /* @@ -145,6 +137,11 @@ relay_auth_password (struct t_relay_client *client, * * salt is the salt in hexadecimal * hash is the hashed password with the parameters above, in hexadecimal + * + * If salt_hexa is not NULL, it is set with salt as hexadecimal, and the parsed + * salt is decoded and put in salt. + * If salt_hexa is NULL, parsed salt is considered not encoded and is put + * directly in salt. */ void @@ -155,7 +152,8 @@ relay_auth_parse_sha (const char *parameters, char **argv; int argc; - *salt_hexa = NULL; + if (salt_hexa) + *salt_hexa = NULL; *salt = NULL; *salt_size = 0; *hash = NULL; @@ -174,18 +172,27 @@ relay_auth_parse_sha (const char *parameters, } /* parameter 1: salt */ - *salt = malloc (strlen (argv[0]) + 1); - if (*salt) + if (salt_hexa) { - *salt_size = weechat_string_base_decode ("16", argv[0], *salt); - if (*salt_size > 0) - *salt_hexa = strdup (argv[0]); - else + *salt = malloc (strlen (argv[0]) + 1); + if (*salt) { - free (*salt); - *salt = NULL; + *salt_size = weechat_string_base_decode ("16", argv[0], *salt); + if (*salt_size > 0) + *salt_hexa = strdup (argv[0]); + else + { + free (*salt); + *salt = NULL; + } } } + else + { + *salt = strdup (argv[0]); + if (*salt) + *salt_size = strlen (*salt); + } /* parameter 2: the SHA256 or SHA512 hash */ *hash = strdup (argv[1]); @@ -203,6 +210,11 @@ relay_auth_parse_sha (const char *parameters, * salt is the salt in hexadecimal * iterations it the number of iterations (≥ 1) * hash is the hashed password with the parameters above, in hexadecimal + * + * If salt_hexa is not NULL, it is set with salt as hexadecimal, and the parsed + * salt is decoded and put in salt. + * If salt_hexa is NULL, parsed salt is considered not encoded and is put + * directly in salt. */ void @@ -213,7 +225,8 @@ relay_auth_parse_pbkdf2 (const char *parameters, char **argv, *error; int argc; - *salt_hexa = NULL; + if (salt_hexa) + *salt_hexa = NULL; *salt = NULL; *salt_size = 0; *iterations = 0; @@ -233,18 +246,27 @@ relay_auth_parse_pbkdf2 (const char *parameters, } /* parameter 1: salt */ - *salt = malloc (strlen (argv[0]) + 1); - if (*salt) + if (salt_hexa) { - *salt_size = weechat_string_base_decode ("16", argv[0], *salt); - if (*salt_size > 0) - *salt_hexa = strdup (argv[0]); - else + *salt = malloc (strlen (argv[0]) + 1); + if (*salt) { - free (*salt); - *salt = NULL; + *salt_size = weechat_string_base_decode ("16", argv[0], *salt); + if (*salt_size > 0) + *salt_hexa = strdup (argv[0]); + else + { + free (*salt); + *salt = NULL; + } } } + else + { + *salt = strdup (argv[0]); + if (*salt) + *salt_size = strlen (*salt); + } /* parameter 2: iterations */ error = NULL; @@ -261,7 +283,12 @@ relay_auth_parse_pbkdf2 (const char *parameters, /* * Checks if the salt received from the client is valid. * - * It is valid if both conditions are true: + * For "api" protocol, it is valid if both conditions are true: + * 1. the salt is a valid integer (unix timestamp) + * 2. the timestamp value is current timestamp (or +/- seconds, according to + * the option relay.network.time_window) + * + * For other protocols, it is valid if both conditions are true: * 1. the salt is longer than the server nonce, so it means it includes a * client nonce * 2. the salt begins with the server nonce (client->nonce) @@ -272,8 +299,31 @@ relay_auth_parse_pbkdf2 (const char *parameters, */ int -relay_auth_check_salt (struct t_relay_client *client, const char *salt_hexa) +relay_auth_check_salt (struct t_relay_client *client, + const char *salt_hexa, const char *salt, int salt_size) { + long number; + int time_window; + char *error; + time_t time_now; + + if (!client) + return 0; + + if (client->protocol == RELAY_PROTOCOL_API) + { + if (!salt || (salt_size < 1)) + return 0; + error = NULL; + number = strtol (salt, &error, 10); + if (!error || error[0]) + return 0; + time_now = time (NULL); + time_window = weechat_config_integer (relay_config_network_time_window); + return ((number >= time_now - time_window) + && (number <= time_now + time_window)) ? 1 : 0; + } + return (salt_hexa && client->nonce && (strlen (salt_hexa) > strlen (client->nonce)) @@ -370,8 +420,11 @@ relay_auth_check_hash_pbkdf2 (const char *hash_pbkdf2_algo, * Authenticates with password hash. * * Returns: - * 1: authentication OK - * 0: authentication failed + * 0: authentication OK + * -1: invalid hash algorithm + * -2: invalid salt + * -3: invalid number of iterations + * -4: invalid password (hash) */ int @@ -387,40 +440,83 @@ relay_auth_password_hash (struct t_relay_client *client, str_hash_algo = NULL; - /* no authentication supported at all? */ - if (client->password_hash_algo < 0) + /* no authentication supported at all with weechat protocol? */ + if ((client->protocol == RELAY_PROTOCOL_WEECHAT) + && (client->password_hash_algo < 0)) + { + rc = -1; goto end; + } if (!hashed_password || !relay_password) + { + rc = -4; goto end; + } pos_hash = strchr (hashed_password, ':'); if (!pos_hash) + { + rc = -4; goto end; + } str_hash_algo = weechat_strndup (hashed_password, pos_hash - hashed_password); if (!str_hash_algo) + { + rc = -1; goto end; + } pos_hash++; hash_algo = relay_auth_password_hash_algo_search (str_hash_algo); + if (hash_algo < 0) + { + rc = -1; + goto end; + } - if (hash_algo != client->password_hash_algo) + /* only algo negotiated in handshake is allowed for protocol "weechat" */ + if ((client->protocol == RELAY_PROTOCOL_WEECHAT) + && (hash_algo != client->password_hash_algo)) + { + rc = -1; + goto end; + } + + /* only algos matching allowed algos are allowed for protocol "api" */ + if ((client->protocol == RELAY_PROTOCOL_API) + && (!weechat_string_match_list ( + relay_auth_password_hash_algo_name[hash_algo], + (const char **)relay_config_network_password_hash_algo_list, + 1))) + { + rc = -1; goto end; + } + + salt_hexa = NULL; switch (hash_algo) { case RELAY_AUTH_PASSWORD_HASH_SHA256: case RELAY_AUTH_PASSWORD_HASH_SHA512: - relay_auth_parse_sha (pos_hash, &salt_hexa, &salt, &salt_size, - &hash_sha); - if (relay_auth_check_salt (client, salt_hexa) - && relay_auth_check_hash_sha (str_hash_algo, salt, salt_size, - hash_sha, relay_password)) + relay_auth_parse_sha ( + pos_hash, + (client->protocol == RELAY_PROTOCOL_API) ? NULL : &salt_hexa, + &salt, + &salt_size, + &hash_sha); + if (!relay_auth_check_salt (client, salt_hexa, salt, salt_size)) { - rc = 1; + rc = -2; + } + else if (!relay_auth_check_hash_sha (str_hash_algo, salt, salt_size, + hash_sha, relay_password)) + { + rc = -4;; } if (salt_hexa) free (salt_hexa); @@ -432,15 +528,26 @@ relay_auth_password_hash (struct t_relay_client *client, case RELAY_AUTH_PASSWORD_HASH_PBKDF2_SHA256: case RELAY_AUTH_PASSWORD_HASH_PBKDF2_SHA512: hash_pbkdf2_algo = strdup (str_hash_algo + 7); - relay_auth_parse_pbkdf2 (pos_hash, &salt_hexa, &salt, &salt_size, - &iterations, &hash_pbkdf2); - if ((iterations == client->password_hash_iterations) - && relay_auth_check_salt (client, salt_hexa) - && relay_auth_check_hash_pbkdf2 (hash_pbkdf2_algo, salt, - salt_size, iterations, - hash_pbkdf2, relay_password)) + relay_auth_parse_pbkdf2 ( + pos_hash, + (client->protocol == RELAY_PROTOCOL_API) ? NULL : &salt_hexa, + &salt, + &salt_size, + &iterations, + &hash_pbkdf2); + if (iterations != weechat_config_integer (relay_config_network_password_hash_iterations)) { - rc = 1; + rc = -3; + } + else if (!relay_auth_check_salt (client, salt_hexa, salt, salt_size)) + { + rc = -2; + } + else if (!relay_auth_check_hash_pbkdf2 (hash_pbkdf2_algo, salt, + salt_size, iterations, + hash_pbkdf2, relay_password)) + { + rc = -4; } if (hash_pbkdf2_algo) free (hash_pbkdf2_algo); @@ -452,6 +559,7 @@ relay_auth_password_hash (struct t_relay_client *client, free (hash_pbkdf2); break; case RELAY_NUM_PASSWORD_HASH_ALGOS: + rc = -4; break; } diff --git a/src/plugins/relay/relay-auth.h b/src/plugins/relay/relay-auth.h index 9d1158c45..dcb7801fc 100644 --- a/src/plugins/relay/relay-auth.h +++ b/src/plugins/relay/relay-auth.h @@ -37,11 +37,9 @@ extern char *relay_auth_password_hash_algo_name[]; extern int relay_auth_password_hash_algo_search (const char *name); extern char *relay_auth_generate_nonce (int size); -extern int relay_auth_check_password_plain (const char *password, +extern int relay_auth_check_password_plain (struct t_relay_client *client, + const char *password, const char *relay_password); -extern int relay_auth_password (struct t_relay_client *client, - const char *password, - const char *relay_password); extern void relay_auth_parse_sha (const char *parameters, char **salt_hexa, char **salt, @@ -53,8 +51,6 @@ extern void relay_auth_parse_pbkdf2 (const char *parameters, int *salt_size, int *iterations, char **hash); -extern int relay_auth_check_salt (struct t_relay_client *client, - const char *salt_hexa); extern int relay_auth_check_hash_sha (const char *hash_algo, const char *salt, int salt_size, diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c index fa62d8f20..b5260700d 100644 --- a/src/plugins/relay/relay-client.c +++ b/src/plugins/relay/relay-client.c @@ -1391,8 +1391,6 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server) (const char **)relay_config_network_password_hash_algo_list, 1); new_client->password_hash_algo = (plain_text_password) ? 0 : -1; - new_client->password_hash_iterations = weechat_config_integer ( - relay_config_network_password_hash_iterations); new_client->listen_start_time = server->start_time; new_client->start_time = time (NULL); new_client->end_time = 0; @@ -1665,12 +1663,6 @@ relay_client_new_with_infolist (struct t_infolist *infolist) new_client->password_hash_algo = weechat_infolist_integer (infolist, "password_hash_algo"); else new_client->password_hash_algo = RELAY_AUTH_PASSWORD_HASH_PLAIN; - /* "password_hash_iterations" is new in WeeChat 2.9 */ - if (weechat_infolist_search_var (infolist, "password_hash_iterations")) - new_client->password_hash_iterations = weechat_infolist_integer (infolist, "password_hash_iterations"); - else - new_client->password_hash_iterations = weechat_config_integer ( - relay_config_network_password_hash_iterations); new_client->listen_start_time = weechat_infolist_time (infolist, "listen_start_time"); new_client->start_time = weechat_infolist_time (infolist, "start_time"); new_client->end_time = weechat_infolist_time (infolist, "end_time"); @@ -2102,8 +2094,6 @@ relay_client_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_algo", client->password_hash_algo)) return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "password_hash_iterations", client->password_hash_iterations)) - return 0; if (!weechat_infolist_new_var_time (ptr_item, "listen_start_time", client->listen_start_time)) return 0; if (!weechat_infolist_new_var_time (ptr_item, "start_time", client->start_time)) @@ -2188,7 +2178,6 @@ relay_client_print_log () ptr_client->password_hash_algo, (ptr_client->password_hash_algo >= 0) ? relay_auth_password_hash_algo_name[ptr_client->password_hash_algo] : ""); - weechat_log_printf (" password_hash_iterations. : %d", ptr_client->password_hash_iterations); weechat_log_printf (" listen_start_time . . . . : %lld", (long long)ptr_client->listen_start_time); weechat_log_printf (" start_time. . . . . . . . : %lld", (long long)ptr_client->start_time); weechat_log_printf (" end_time. . . . . . . . . : %lld", (long long)ptr_client->end_time); diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h index 0afec9387..9d22f629f 100644 --- a/src/plugins/relay/relay-client.h +++ b/src/plugins/relay/relay-client.h @@ -119,7 +119,6 @@ struct t_relay_client /* example: server for irc protocol */ char *nonce; /* nonce used in salt of hashed pwd */ int password_hash_algo; /* password hash algo (negotiated) */ - int password_hash_iterations; /* password hash iterations */ time_t listen_start_time; /* when listening started */ time_t start_time; /* time of client connection */ time_t end_time; /* time of client disconnection */ diff --git a/src/plugins/relay/relay-config.c b/src/plugins/relay/relay-config.c index b9c4422ec..148e693d6 100644 --- a/src/plugins/relay/relay-config.c +++ b/src/plugins/relay/relay-config.c @@ -81,6 +81,7 @@ struct t_config_option *relay_config_network_nonce_size = NULL; struct t_config_option *relay_config_network_password = NULL; struct t_config_option *relay_config_network_password_hash_algo = NULL; struct t_config_option *relay_config_network_password_hash_iterations = NULL; +struct t_config_option *relay_config_network_time_window = NULL; struct t_config_option *relay_config_network_tls_cert_key = NULL; struct t_config_option *relay_config_network_tls_priorities = NULL; struct t_config_option *relay_config_network_totp_secret = NULL; @@ -1370,6 +1371,13 @@ relay_config_init () "if your CPU is slow"), NULL, 1, 1000000, "100000", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + relay_config_network_time_window = weechat_config_new_option ( + relay_config_file, relay_config_section_network, + "time_window", "integer", + N_("number of seconds to allow before and after the current time " + "for salted password in api protocol"), + NULL, 0, 256, "5", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); relay_config_network_tls_cert_key = weechat_config_new_option ( relay_config_file, relay_config_section_network, "tls_cert_key", "string", diff --git a/src/plugins/relay/relay-config.h b/src/plugins/relay/relay-config.h index de5697341..e454ba97e 100644 --- a/src/plugins/relay/relay-config.h +++ b/src/plugins/relay/relay-config.h @@ -53,6 +53,7 @@ extern struct t_config_option *relay_config_network_nonce_size; extern struct t_config_option *relay_config_network_password; extern struct t_config_option *relay_config_network_password_hash_algo; extern struct t_config_option *relay_config_network_password_hash_iterations; +extern struct t_config_option *relay_config_network_time_window; extern struct t_config_option *relay_config_network_tls_cert_key; extern struct t_config_option *relay_config_network_tls_priorities; extern struct t_config_option *relay_config_network_totp_secret; diff --git a/src/plugins/relay/relay-http.c b/src/plugins/relay/relay-http.c index a59552599..51ce00174 100644 --- a/src/plugins/relay/relay-http.c +++ b/src/plugins/relay/relay-http.c @@ -31,6 +31,7 @@ #include "../weechat-plugin.h" #include "relay.h" +#include "relay-auth.h" #include "relay-client.h" #include "relay-config.h" #include "relay-http.h" @@ -514,7 +515,7 @@ relay_http_add_to_body (struct t_relay_http_request *request, } /* - * Checks if authentication is OK. + * Gets authentication status according to headers in the request. * * Returns: * 0: authentication OK (password + TOTP if enabled) @@ -522,11 +523,15 @@ relay_http_add_to_body (struct t_relay_http_request *request, * -2: invalid password * -3: missing TOTP * -4: invalid TOTP - * -5: out of memory + * -5: invalid hash algorithm + * -6: invalid salt + * -7: invalid number of iterations (PBKDF2) + * -8: out of memory */ int -relay_http_check_auth (struct t_relay_http_request *request) +relay_http_get_auth_status (struct t_relay_client *client, + struct t_relay_http_request *request) { const char *auth, *client_totp, *pos; char *relay_password, *totp_secret, *info_totp_args, *info_totp; @@ -538,6 +543,15 @@ relay_http_check_auth (struct t_relay_http_request *request) totp_secret = NULL; user_pass = NULL; + relay_password = weechat_string_eval_expression ( + weechat_config_string (relay_config_network_password), + NULL, NULL, NULL); + if (!relay_password) + { + rc = -8; + goto end; + } + auth = weechat_hashtable_get (request->headers, "authorization"); if (!auth || (weechat_strncasecmp (auth, "basic ", 6) != 0)) { @@ -555,7 +569,7 @@ relay_http_check_auth (struct t_relay_http_request *request) user_pass = malloc (length + 1); if (!user_pass) { - rc = -5; + rc = -8; goto end; } length = weechat_string_base_decode ("64", pos, user_pass); @@ -564,23 +578,43 @@ relay_http_check_auth (struct t_relay_http_request *request) rc = -2; goto end; } - if (strncmp (user_pass, "weechat:", 8) != 0) + if (strncmp (user_pass, "plain:", 6) == 0) { - rc = -2; - goto end; + switch (relay_auth_check_password_plain (client, user_pass + 6, relay_password)) + { + case 0: /* password OK */ + break; + case -1: /* "plain" is not allowed */ + rc = -5; + goto end; + case -2: /* invalid password */ + default: + rc = -2; + goto end; + } } - - relay_password = weechat_string_eval_expression ( - weechat_config_string (relay_config_network_password), - NULL, NULL, NULL); - - if (!relay_password) + else if (strncmp (user_pass, "hash:", 5) == 0) { - rc = -5; - goto end; + switch (relay_auth_password_hash (client, user_pass + 5, relay_password)) + { + case 0: /* password OK */ + break; + case -1: /* invalid hash algorithm */ + rc = -5; + goto end; + case -2: /* invalid salt */ + rc = -6; + goto end; + case -3: /* invalid iterations */ + rc = -7; + goto end; + case -4: /* invalid password */ + default: + rc = -2; + goto end; + } } - - if (strcmp (user_pass + 8, relay_password) != 0) + else { rc = -2; goto end; @@ -632,6 +666,69 @@ end: } /* + * Checks authentication in HTTP request. + * + * Returns: + * 1: authentication OK + * 0: authentication failed + */ + +int +relay_http_check_auth (struct t_relay_client *client, + struct t_relay_http_request *request) +{ + int rc; + + rc = relay_http_get_auth_status (client, request); + switch (rc) + { + case 0: /* authentication OK */ + break; + case -1: /* missing password */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_MISSING_PASSWORD); + break; + case -2: /* invalid password */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_INVALID_PASSWORD); + break; + case -3: /* missing TOTP */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_MISSING_TOTP); + break; + case -4: /* invalid TOTP */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_INVALID_TOTP); + break; + case -5: /* invalid hash algorithm */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_INVALID_HASH_ALGO); + break; + case -6: /* invalid salt */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_INVALID_SALT); + break; + case -7: /* invalid iterations */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_INVALID_ITERATIONS); + break; + case -8: /* out of memory */ + relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, + NULL, + RELAY_HTTP_ERROR_OUT_OF_MEMORY); + break; + } + return (rc == 0) ? 1 : 0; +} + +/* * Processes HTTP websocket request. */ @@ -681,41 +778,14 @@ relay_http_process_websocket (struct t_relay_client *client) /* handshake from client is valid, auth is mandatory for "api" protocol */ if (client->protocol == RELAY_PROTOCOL_API) { - switch (relay_http_check_auth (client->http_req)) + if (relay_http_check_auth (client, client->http_req)) { - case 0: /* authentication OK */ - relay_client_set_status (client, RELAY_STATUS_CONNECTED); - break; - case -1: /* missing password */ - relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_MISSING_PASSWORD); - relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); - return; - case -2: /* invalid password */ - relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_INVALID_PASSWORD); - relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); - return; - case -3: /* missing TOTP */ - relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_MISSING_TOTP); - relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); - return; - case -4: /* invalid TOTP */ - relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_INVALID_TOTP); - relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); - return; - case -5: /* out of memory */ - relay_http_send_error_json (client, RELAY_HTTP_401_UNAUTHORIZED, - NULL, - RELAY_HTTP_ERROR_OUT_OF_MEMORY); - relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); - return; + relay_client_set_status (client, RELAY_STATUS_CONNECTED); + } + else + { + relay_client_set_status (client, RELAY_STATUS_AUTH_FAILED); + return; } } diff --git a/src/plugins/relay/relay-http.h b/src/plugins/relay/relay-http.h index 8ed0bcd88..5716cb98d 100644 --- a/src/plugins/relay/relay-http.h +++ b/src/plugins/relay/relay-http.h @@ -41,11 +41,15 @@ enum t_relay_client_http_status #define RELAY_HTTP_500_INTERNAL_SERVER_ERROR 500, "Internal Server Error" #define RELAY_HTTP_503_SERVICE_UNAVAILABLE 503, "Service Unvavailable" -#define RELAY_HTTP_ERROR_MISSING_PASSWORD "Missing password" -#define RELAY_HTTP_ERROR_INVALID_PASSWORD "Invalid password" -#define RELAY_HTTP_ERROR_MISSING_TOTP "Missing TOTP" -#define RELAY_HTTP_ERROR_INVALID_TOTP "Invalid TOTP" -#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory" +#define RELAY_HTTP_ERROR_MISSING_PASSWORD "Missing password" +#define RELAY_HTTP_ERROR_INVALID_PASSWORD "Invalid password" +#define RELAY_HTTP_ERROR_MISSING_TOTP "Missing TOTP" +#define RELAY_HTTP_ERROR_INVALID_TOTP "Invalid TOTP" +#define RELAY_HTTP_ERROR_INVALID_HASH_ALGO "Invalid hash algorithm " \ + "(not found or not supported)" +#define RELAY_HTTP_ERROR_INVALID_SALT "Invalid salt" +#define RELAY_HTTP_ERROR_INVALID_ITERATIONS "Invalid number of iterations" +#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory" struct t_relay_http_request { @@ -71,7 +75,8 @@ extern void relay_http_request_reinit (struct t_relay_http_request *request); extern struct t_relay_http_request *relay_http_request_alloc (); extern int relay_http_parse_method_path (struct t_relay_http_request *request, const char *method_path); -extern int relay_http_check_auth (struct t_relay_http_request *request); +extern int relay_http_check_auth (struct t_relay_client *client, + struct t_relay_http_request *request); extern void relay_http_recv (struct t_relay_client *client, const char *data); extern int relay_http_send (struct t_relay_client *client, int return_code, const char *message, diff --git a/src/plugins/relay/weechat/relay-weechat-protocol.c b/src/plugins/relay/weechat/relay-weechat-protocol.c index a7d47e3af..948ecd38f 100644 --- a/src/plugins/relay/weechat/relay-weechat-protocol.c +++ b/src/plugins/relay/weechat/relay-weechat-protocol.c @@ -170,7 +170,9 @@ relay_weechat_protocol_handshake_reply (struct t_relay_client *client, "password_hash_algo", (client->password_hash_algo >= 0) ? relay_auth_password_hash_algo_name[client->password_hash_algo] : ""); - snprintf (string, sizeof (string), "%d", client->password_hash_iterations); + snprintf (string, sizeof (string), + "%d", + weechat_config_integer (relay_config_network_password_hash_iterations)); weechat_hashtable_set ( hashtable, "password_hash_iterations", @@ -388,13 +390,16 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(init) if (strcmp (options[i], "password") == 0) { password_received = 1; - if (relay_auth_password (client, pos, relay_password)) + if ((client->password_hash_algo == RELAY_AUTH_PASSWORD_HASH_PLAIN) + && (relay_auth_check_password_plain (client, pos, relay_password) == 0)) + { RELAY_WEECHAT_DATA(client, password_ok) = 1; + } } else if (strcmp (options[i], "password_hash") == 0) { password_received = 1; - if (relay_auth_password_hash (client, pos, relay_password)) + if (relay_auth_password_hash (client, pos, relay_password) == 0) RELAY_WEECHAT_DATA(client, password_ok) = 1; } else if (strcmp (options[i], "totp") == 0) diff --git a/tests/unit/plugins/relay/test-relay-auth.cpp b/tests/unit/plugins/relay/test-relay-auth.cpp index af7738093..32574b6aa 100644 --- a/tests/unit/plugins/relay/test-relay-auth.cpp +++ b/tests/unit/plugins/relay/test-relay-auth.cpp @@ -26,7 +26,16 @@ extern "C" #include <stdio.h> #include <string.h> #include <ctype.h> +#include <time.h> +#include "src/core/wee-config-file.h" +#include "src/plugins/relay/relay.h" #include "src/plugins/relay/relay-auth.h" +#include "src/plugins/relay/relay-client.h" +#include "src/plugins/relay/relay-config.h" + +extern int relay_auth_check_salt (struct t_relay_client *client, + const char *salt_hexa, + const char *salt, int salt_size); } #define WEE_CHECK_PARSE_SHA(__parameters) \ @@ -100,6 +109,38 @@ TEST(RelayAuth, GenerateNonce) /* * Tests functions: + * relay_auth_check_password_plain + */ + +TEST(RelayAuth, CheckPasswordPlain) +{ + struct t_relay_client *client; + + client = (struct t_relay_client *)calloc (1, sizeof (*client)); + CHECK(client); + client->protocol = RELAY_PROTOCOL_API; + + /* invalid arguments */ + LONGS_EQUAL(-2, relay_auth_check_password_plain (client, NULL, NULL)); + LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "abcd", NULL)); + LONGS_EQUAL(-2, relay_auth_check_password_plain (client, NULL, "password")); + + /* wrong password */ + LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "test", "password")); + LONGS_EQUAL(-2, relay_auth_check_password_plain (client, "Password", "password")); + + /* good password */ + LONGS_EQUAL(0, relay_auth_check_password_plain (client, "", "")); + LONGS_EQUAL(0, relay_auth_check_password_plain (client, "password", "password")); + + /* test with "plain" disabled */ + config_file_option_set (relay_config_network_password_hash_algo, "*,!plain", 1); + LONGS_EQUAL(-1, relay_auth_check_password_plain (client, "password", "password")); + config_file_option_reset (relay_config_network_password_hash_algo, 1); +} + +/* + * Tests functions: * relay_auth_parse_sha */ @@ -241,23 +282,53 @@ TEST(RelayAuth, ParsePbkdf2) /* * Tests functions: - * relay_auth_check_password_plain + * relay_auth_check_salt */ -TEST(RelayAuth, CheckPasswordPlain) +TEST(RelayAuth, CheckSalt) { - /* invalid arguments */ - LONGS_EQUAL(0, relay_auth_check_password_plain (NULL, NULL)); - LONGS_EQUAL(0, relay_auth_check_password_plain ("abcd", NULL)); - LONGS_EQUAL(0, relay_auth_check_password_plain (NULL, "password")); - - /* wrong password */ - LONGS_EQUAL(0, relay_auth_check_password_plain ("test", "password")); - LONGS_EQUAL(0, relay_auth_check_password_plain ("Password", "password")); - - /* good password */ - LONGS_EQUAL(1, relay_auth_check_password_plain ("", "")); - LONGS_EQUAL(1, relay_auth_check_password_plain ("password", "password")); + struct t_relay_client *client; + time_t time_now; + char salt[128]; + + client = (struct t_relay_client *)calloc (1, sizeof (*client)); + CHECK(client); + client->nonce = strdup ("01aa03bb"); + + client->protocol = RELAY_PROTOCOL_API; + + LONGS_EQUAL(0, relay_auth_check_salt (NULL, NULL, NULL, 0)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, NULL, 0)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "test", 4)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "1234", 4)); + + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt))); + time_now = time (NULL) - 2; + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt))); + time_now = time (NULL) + 2; + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, relay_auth_check_salt (client, NULL, salt, strlen (salt))); + time_now = time (NULL) - 10; + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, salt, strlen (salt))); + + client->protocol = RELAY_PROTOCOL_WEECHAT; + + LONGS_EQUAL(0, relay_auth_check_salt (NULL, NULL, NULL, 0)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, NULL, 0)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "test", 4)); + LONGS_EQUAL(0, relay_auth_check_salt (client, NULL, "1234", 4)); + + LONGS_EQUAL(0, relay_auth_check_salt (client, "01aa", "\x01\xaa", 2)); + LONGS_EQUAL(0, relay_auth_check_salt (client, "01aa03bb", "\x01\xaa\x03\xbb", 4)); + LONGS_EQUAL(1, relay_auth_check_salt (client, "01aa03bbcc", "\x01\xaa\x03\xbb\xcc", 5)); + LONGS_EQUAL(1, relay_auth_check_salt (client, "01AA03BBCC", "\x01\xaa\x03\xbb\xcc", 5)); + + free (client->nonce); + free (client); } /* @@ -403,3 +474,13 @@ TEST(RelayAuth, CheckHashPbkdf2) "f53326c3729ffd12", "password")); } + +/* + * Tests functions: + * relay_auth_password_hash + */ + +TEST(RelayAuth, PasswordHash) +{ + /* TODO: write tests */ +} diff --git a/tests/unit/plugins/relay/test-relay-http.cpp b/tests/unit/plugins/relay/test-relay-http.cpp index 64bb7b752..075e286d8 100644 --- a/tests/unit/plugins/relay/test-relay-http.cpp +++ b/tests/unit/plugins/relay/test-relay-http.cpp @@ -28,10 +28,15 @@ extern "C" #include <stdio.h> #include <string.h> #include <ctype.h> +#include <time.h> +#include <gcrypt.h> #include "src/core/wee-config-file.h" +#include "src/core/wee-crypto.h" #include "src/core/wee-hashtable.h" #include "src/core/wee-hook.h" #include "src/core/wee-string.h" +#include "src/plugins/relay/relay.h" +#include "src/plugins/relay/relay-client.h" #include "src/plugins/relay/relay-config.h" #include "src/plugins/relay/relay-http.h" #include "src/plugins/relay/relay-websocket.h" @@ -45,6 +50,8 @@ extern int relay_http_parse_header (struct t_relay_http_request *request, const char *header); extern void relay_http_add_to_body (struct t_relay_http_request *request, char **partial_message); +extern int relay_http_get_auth_status (struct t_relay_client *client, + struct t_relay_http_request *request); extern char *relay_http_compress (struct t_relay_http_request *request, const char *data, int data_size, int *compressed_size, @@ -589,51 +596,244 @@ TEST(RelayHttp, AddToBody) /* * Tests functions: - * relay_http_check_auth + * relay_http_get_auth_status */ -TEST(RelayHttp, CheckAuth) +TEST(RelayHttp, GetAuthStatus) { + struct t_relay_client *client; struct t_relay_http_request *request; - char *totp, *totp2; + const char *good_pwd = "secret_password"; + const char *bad_pwd = "test"; + char *totp, *totp2, salt[1024], salt_pass[1024], hash[1024], hash_hexa[2048]; + char auth[4096], auth_base64[4096], auth_header[8192]; + time_t time_now; + int hash_size; + + config_file_option_set (relay_config_network_password, good_pwd, 1); - config_file_option_set (relay_config_network_password, "secret_password", 1); + client = (struct t_relay_client *)calloc (1, sizeof (*client)); + CHECK(client); + client->protocol = RELAY_PROTOCOL_API; request = relay_http_request_alloc (); CHECK(request); - /* test password */ - LONGS_EQUAL(-1, relay_http_check_auth (request)); + LONGS_EQUAL(-1, relay_http_get_auth_status (client, request)); hashtable_set (request->headers, "authorization", "Basic "); - LONGS_EQUAL(-2, relay_http_check_auth (request)); + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); hashtable_set (request->headers, "authorization", "Basic \u26c4"); - LONGS_EQUAL(-2, relay_http_check_auth (request)); - /* set invalid user/password: "weechat:test" */ - hashtable_set (request->headers, "authorization", "Basic d2VlY2hhdDp0ZXN0"); - LONGS_EQUAL(-2, relay_http_check_auth (request)); - /* set valid user/password: "weechat:secret_password" */ + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); + + /* test invalid plain-text password ("test") */ + hashtable_set (request->headers, "authorization", "Basic cGxhaW46dGVzdA=="); + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); + + /* test valid plain-text password ("secret_password") */ hashtable_set (request->headers, - "authorization", "Basic d2VlY2hhdDpzZWNyZXRfcGFzc3dvcmQ"); - LONGS_EQUAL(0, relay_http_check_auth (request)); + "authorization", + "Basic cGxhaW46c2VjcmV0X3Bhc3N3b3Jk"); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); + + /* test invalid hash: "SHA128" */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, bad_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA256, hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha128:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-5, relay_http_get_auth_status (client, request)); + + /* test invalid password hashed with SHA256: "test" */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, bad_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA256, hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha256:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); + + /* test invalid password hashed with SHA512: "test" */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, bad_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA512, hash, &hash_size)); + LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha512:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); + + /* test valid password hashed with SHA256: "secret_password" but too old time (salt) */ + time_now = time (NULL) - 10; + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, good_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA256, hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha256:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-6, relay_http_get_auth_status (client, request)); + + /* test valid password hashed with SHA256: "secret_password" */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, good_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA256, hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha256:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); + + /* test valid password hashed with SHA512: "secret_password" */ + time_now = time (NULL); + snprintf (salt_pass, sizeof (salt_pass), + "%ld%s", time_now, good_pwd); + LONGS_EQUAL(1, weecrypto_hash (salt_pass, strlen (salt_pass), + GCRY_MD_SHA512, hash, &hash_size)); + LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:sha512:%ld:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); + + /* test invalid number of iterations */ + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd), + GCRY_MD_SHA256, + salt, strlen (salt), + 123, + hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:pbkdf2+sha256:%ld:123:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-7, relay_http_get_auth_status (client, request)); + + /* test invalid password hashed with PBKDF2+SHA256: "test" */ + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (bad_pwd, strlen (bad_pwd), + GCRY_MD_SHA256, + salt, strlen (salt), + 100000, + hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:pbkdf2+sha256:%ld:100000:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(-2, relay_http_get_auth_status (client, request)); + + /* test valid password hashed with PBKDF2+SHA256: "secret_password" */ + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd), + GCRY_MD_SHA256, + salt, strlen (salt), + 100000, + hash, &hash_size)); + LONGS_EQUAL(64, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:pbkdf2+sha256:%ld:100000:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); + + /* test valid password hashed with PBKDF2+SHA512: "secret_password" */ + time_now = time (NULL); + snprintf (salt, sizeof (salt), "%ld", time_now); + LONGS_EQUAL(1, weecrypto_hash_pbkdf2 (good_pwd, strlen (good_pwd), + GCRY_MD_SHA512, + salt, strlen (salt), + 100000, + hash, &hash_size)); + LONGS_EQUAL(128, string_base_encode ("16", hash, hash_size, hash_hexa)); + snprintf (auth, sizeof (auth), + "hash:pbkdf2+sha512:%ld:100000:%s", + time_now, + hash_hexa); + string_base_encode ("64", auth, strlen (auth), auth_base64); + snprintf (auth_header, sizeof (auth_header), "Basic %s", auth_base64); + hashtable_set (request->headers, "authorization", auth_header); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); /* test missing/invalid TOTP */ config_file_option_set (relay_config_network_totp_secret, "secretbase32", 1); config_file_option_set (relay_config_network_totp_window, "1", 1); - LONGS_EQUAL(-3, relay_http_check_auth (request)); + LONGS_EQUAL(-3, relay_http_get_auth_status (client, request)); totp = hook_info_get (NULL, "totp_generate", "secretbase32"); CHECK(totp); totp2 = strdup (totp); totp2[0] = (totp2[0] == '1') ? '2' : '1'; hashtable_set (request->headers, "x-weechat-totp", totp2); - LONGS_EQUAL(-4, relay_http_check_auth (request)); + LONGS_EQUAL(-4, relay_http_get_auth_status (client, request)); hashtable_set (request->headers, "x-weechat-totp", totp); - LONGS_EQUAL(0, relay_http_check_auth (request)); + LONGS_EQUAL(0, relay_http_get_auth_status (client, request)); free (totp); free (totp2); config_file_option_reset (relay_config_network_totp_secret, 1); config_file_option_reset (relay_config_network_totp_window, 1); config_file_option_reset (relay_config_network_password, 1); + + relay_http_request_free (request); + free (client); +} + +/* + * Tests functions: + * relay_http_check_auth + */ + +TEST(RelayHttp, CheckAuth) +{ + /* TODO: write tests */ } /* |