diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c index f4df1b7484..ec7c6c5a8b 100644 --- a/src/or/ext_orport.c +++ b/src/or/ext_orport.c @@ -105,11 +105,11 @@ connection_ext_or_transition(or_connection_t *conn) /** If true, we've set ext_or_auth_cookie to a secret code and stored * it to disk. */ -static int ext_or_auth_cookie_is_set = 0; +STATIC int ext_or_auth_cookie_is_set = 0; /** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk * and which we're using to authenticate controllers. (If the controller can * read it off disk, it has permission to connect.) */ -static char ext_or_auth_cookie[EXT_OR_PORT_AUTH_COOKIE_LEN] = {0}; +STATIC char ext_or_auth_cookie[EXT_OR_PORT_AUTH_COOKIE_LEN] = {0}; /** Helper: Return a newly allocated string containing a path to the * file where we store our authentication cookie. */ @@ -198,10 +198,10 @@ connection_ext_or_auth_neg_auth_type(connection_t *conn) } /** DOCDOC */ -static int +STATIC int handle_client_auth_nonce(const char *client_nonce, size_t client_nonce_len, char **client_hash_out, - char**reply_out, size_t *reply_len_out) + char **reply_out, size_t *reply_len_out) { char server_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0}; char server_nonce[EXT_OR_PORT_AUTH_NONCE_LEN] = {0}; diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h index 35b92ad63f..2d15c18aad 100644 --- a/src/or/ext_orport.h +++ b/src/or/ext_orport.h @@ -27,6 +27,14 @@ STATIC int connection_write_ext_or_command(connection_t *conn, uint16_t command, const char *body, size_t bodylen); +STATIC int handle_client_auth_nonce(const char *client_nonce, + size_t client_nonce_len, + char **client_hash_out, + char **reply_out, size_t *reply_len_out); +#ifdef TOR_UNIT_TESTS +extern char ext_or_auth_cookie[]; +extern int ext_or_auth_cookie_is_set; +#endif #endif #endif diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index 525ac4f191..2caf2acfb5 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -144,9 +144,80 @@ test_ext_or_write_command(void *arg) UNMOCK(connection_write_to_buf_impl_); } +static void +test_ext_or_cookie_auth(void *arg) +{ + char *reply=NULL, *client_hash=NULL; + size_t reply_len=0; + char hmac1[32], hmac2[32]; + + const char client_nonce[32] = + "Who is the third who walks alway"; + char server_hash_input[] = + "ExtORPort authentication server-to-client hash" + "Who is the third who walks alway" + "................................"; + char client_hash_input[] = + "ExtORPort authentication client-to-server hash" + "Who is the third who walks alway" + "................................"; + + (void)arg; + + tt_int_op(strlen(client_hash_input), ==, 46+32+32); + tt_int_op(strlen(server_hash_input), ==, 46+32+32); + + memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32); + ext_or_auth_cookie_is_set = 1; + + /* For this authentication, the client sends 32 random bytes (ClientNonce) + * The server replies with 32 byte ServerHash and 32 byte ServerNonce, + * where ServerHash is: + * HMAC-SHA256(CookieString, + * "ExtORPort authentication server-to-client hash" | ClientNonce | + * ServerNonce)" + * The client must reply with 32-byte ClientHash, which we compute as: + * ClientHash is computed as: + * HMAC-SHA256(CookieString, + * "ExtORPort authentication client-to-server hash" | ClientNonce | + * ServerNonce) + */ + + /* Wrong length */ + tt_int_op(-1, ==, + handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply, + &reply_len)); + tt_int_op(-1, ==, + handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply, + &reply_len)); + + /* Now let's try this for real! */ + tt_int_op(0, ==, + handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply, + &reply_len)); + tt_int_op(reply_len, ==, 64); + tt_ptr_op(reply, !=, NULL); + tt_ptr_op(client_hash, !=, NULL); + /* Fill in the server nonce into the hash inputs... */ + memcpy(server_hash_input+46+32, reply+32, 32); + memcpy(client_hash_input+46+32, reply+32, 32); + /* Check the HMACs are correct... */ + crypto_hmac_sha256(hmac1, ext_or_auth_cookie, 32, server_hash_input, + 46+32+32); + crypto_hmac_sha256(hmac2, ext_or_auth_cookie, 32, client_hash_input, + 46+32+32); + test_memeq(hmac1, reply, 32); + test_memeq(hmac2, client_hash, 32); + + done: + tor_free(reply); + tor_free(client_hash); +} + struct testcase_t extorport_tests[] = { { "id_map", test_ext_or_id_map, TT_FORK, NULL, NULL }, { "write_command", test_ext_or_write_command, TT_FORK, NULL, NULL }, + { "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL }, END_OF_TESTCASES };