tor/src/test/test_extorport.c

610 lines
20 KiB
C
Raw Normal View History

2017-03-15 21:13:17 +01:00
/* Copyright (c) 2013-2017, The Tor Project, Inc. */
2013-07-18 21:51:29 +02:00
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
#define EXT_ORPORT_PRIVATE
#define MAIN_PRIVATE
2013-07-18 21:51:29 +02:00
#include "or.h"
#include "buffers.h"
2013-07-18 21:51:29 +02:00
#include "connection.h"
#include "connection_or.h"
#include "config.h"
#include "control.h"
2013-07-18 21:51:29 +02:00
#include "ext_orport.h"
#include "main.h"
2013-07-18 21:51:29 +02:00
#include "test.h"
/* Test connection_or_remove_from_ext_or_id_map and
* connection_or_set_ext_or_identifier */
static void
test_ext_or_id_map(void *arg)
{
or_connection_t *c1 = NULL, *c2 = NULL, *c3 = NULL;
char *idp = NULL, *idp2 = NULL;
(void)arg;
/* pre-initialization */
2014-11-12 19:42:01 +01:00
tt_ptr_op(NULL, OP_EQ,
connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
2013-07-18 21:51:29 +02:00
c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
c3 = or_connection_new(CONN_TYPE_OR, AF_INET);
tt_ptr_op(c1->ext_or_conn_id, OP_NE, NULL);
tt_ptr_op(c2->ext_or_conn_id, OP_NE, NULL);
tt_ptr_op(c3->ext_or_conn_id, OP_EQ, NULL);
2013-07-18 21:51:29 +02:00
tt_ptr_op(c1, OP_EQ, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
2014-11-12 19:42:01 +01:00
tt_ptr_op(NULL, OP_EQ,
connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
2013-07-18 21:51:29 +02:00
idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
/* Give c2 a new ID. */
connection_or_set_ext_or_identifier(c2);
tt_mem_op(idp, OP_NE, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
2013-07-18 21:51:29 +02:00
idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
tt_assert(!tor_digest_is_zero(idp2));
tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(idp2));
2013-07-18 21:51:29 +02:00
/* Now remove it. */
connection_or_remove_from_ext_or_id_map(c2);
tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp2));
2013-07-18 21:51:29 +02:00
done:
if (c1)
connection_free_(TO_CONN(c1));
if (c2)
connection_free_(TO_CONN(c2));
if (c3)
connection_free_(TO_CONN(c3));
tor_free(idp);
tor_free(idp2);
connection_or_clear_ext_or_id_map();
}
/* Simple connection_write_to_buf_impl_ replacement that unconditionally
* writes to outbuf. */
static void
connection_write_to_buf_impl_replacement(const char *string, size_t len,
connection_t *conn, int compressed)
{
(void) compressed;
tor_assert(string);
tor_assert(conn);
buf_add(conn->outbuf, string, len);
}
static char *
buf_get_contents(buf_t *buf, size_t *sz_out)
{
char *out;
*sz_out = buf_datalen(buf);
if (*sz_out >= ULONG_MAX)
return NULL; /* C'mon, really? */
out = tor_malloc(*sz_out + 1);
if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
tor_free(out);
return NULL;
}
out[*sz_out] = '\0'; /* Hopefully gratuitous. */
return out;
}
static void
test_ext_or_write_command(void *arg)
{
or_connection_t *c1;
char *cp = NULL;
char *buf = NULL;
size_t sz;
(void) arg;
MOCK(connection_write_to_buf_impl_,
connection_write_to_buf_impl_replacement);
c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
tt_assert(c1);
/* Length too long */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
OP_LT, 0);
/* Empty command */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
tt_int_op(sz, OP_EQ, 4);
tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4);
tor_free(cp);
/* Medium command. */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
"Wai\0Hello", 9), OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
tt_int_op(sz, OP_EQ, 13);
tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13);
tor_free(cp);
/* Long command */
buf = tor_malloc(65535);
memset(buf, 'x', 65535);
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
buf, 65535), OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
tt_int_op(sz, OP_EQ, 65539);
tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4);
tt_mem_op(cp+4, OP_EQ, buf, 65535);
tor_free(cp);
done:
if (c1)
connection_free_(TO_CONN(c1));
tor_free(cp);
tor_free(buf);
UNMOCK(connection_write_to_buf_impl_);
}
static int
write_bytes_to_file_fail(const char *fname, const char *str, size_t len,
int bin)
{
(void) fname;
(void) str;
(void) len;
(void) bin;
return -1;
}
static void
test_ext_or_init_auth(void *arg)
{
or_options_t *options = get_options_mutable();
const char *fn;
char *cp = NULL;
struct stat st;
char cookie0[32];
(void)arg;
/* Check default filename location */
tor_free(options->DataDirectory);
options->DataDirectory = tor_strdup("foo");
cp = get_ext_or_auth_cookie_file_name();
tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
tor_free(cp);
/* Shouldn't be initialized already, or our tests will be a bit
* meaningless */
ext_or_auth_cookie = tor_malloc_zero(32);
Use coccinelle scripts to clean up our unit tests This should get rid of most of the users of the old test_* functions. Some are in macros and will need manual cleanup, though. This patch is for 13119, and was automatically generated with these scripts. The perl scripts are there because coccinelle hates operators as macro arguments. ------------------------------ s/==,/_X_EQ_,/g; s/!=,/_X_NE_,/g; s/<,/_X_LT_,/g; s/>,/_X_GT_,/g; s/>=,/_X_GEQ_,/g; s/<=,/_X_LEQ_,/g; ------------------------------ @@ expression a; identifier func; @@ func (...) { <... -test_fail_msg +TT_DIE ( +( a +) ) ...> } @@ identifier func; @@ func (...) { <... -test_fail() +TT_DIE(("Assertion failed.")) ...> } @@ expression a; identifier func; @@ func (...) { <... -test_assert +tt_assert (a) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq +tt_int_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_neq +tt_int_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_streq +tt_str_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_strneq +tt_str_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq_ptr +tt_ptr_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func() { <... -test_neq_ptr +tt_ptr_op (a, +_X_NEQ_, b) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memeq +tt_mem_op (a, +_X_EQ_, b, len) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memneq +tt_mem_op (a, +_X_NEQ_, b, len) ...> } ------------------------------ @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } ------------------------------ s/_X_NEQ_/!=/g; s/_X_NE_/!=/g; s/_X_EQ_/==/g; s/_X_GT_/>/g; s/_X_LT_/</g; s/_X_GEQ_/>=/g; s/_X_LEQ_/<=/g; s/test_mem_op\(/tt_mem_op\(/g;
2014-09-16 03:18:21 +02:00
tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Now make sure we use a temporary file */
fn = get_fname("ext_cookie_file");
options->ExtORPortCookieAuthFile = tor_strdup(fn);
cp = get_ext_or_auth_cookie_file_name();
tt_str_op(cp, OP_EQ, fn);
tor_free(cp);
/* Test the initialization function with a broken
write_bytes_to_file(). See if the problem is handled properly. */
MOCK(write_bytes_to_file, write_bytes_to_file_fail);
tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1));
tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0);
UNMOCK(write_bytes_to_file);
/* Now do the actual initialization. */
tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1);
cp = read_file_to_str(fn, RFTS_BIN, &st);
tt_ptr_op(cp, OP_NE, NULL);
tt_u64_op((uint64_t)st.st_size, OP_EQ, 64);
tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
memcpy(cookie0, ext_or_auth_cookie, 32);
Use coccinelle scripts to clean up our unit tests This should get rid of most of the users of the old test_* functions. Some are in macros and will need manual cleanup, though. This patch is for 13119, and was automatically generated with these scripts. The perl scripts are there because coccinelle hates operators as macro arguments. ------------------------------ s/==,/_X_EQ_,/g; s/!=,/_X_NE_,/g; s/<,/_X_LT_,/g; s/>,/_X_GT_,/g; s/>=,/_X_GEQ_,/g; s/<=,/_X_LEQ_,/g; ------------------------------ @@ expression a; identifier func; @@ func (...) { <... -test_fail_msg +TT_DIE ( +( a +) ) ...> } @@ identifier func; @@ func (...) { <... -test_fail() +TT_DIE(("Assertion failed.")) ...> } @@ expression a; identifier func; @@ func (...) { <... -test_assert +tt_assert (a) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq +tt_int_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_neq +tt_int_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_streq +tt_str_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_strneq +tt_str_op (a, +_X_NEQ_, b) ...> } @@ expression a, b; identifier func; @@ func (...) { <... -test_eq_ptr +tt_ptr_op (a, +_X_EQ_, b) ...> } @@ expression a, b; identifier func; @@ func() { <... -test_neq_ptr +tt_ptr_op (a, +_X_NEQ_, b) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memeq +tt_mem_op (a, +_X_EQ_, b, len) ...> } @@ expression a, b, len; identifier func; @@ func (...) { <... -test_memneq +tt_mem_op (a, +_X_NEQ_, b, len) ...> } ------------------------------ @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a == b +a, _X_EQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a != b +a, _X_NEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a >= b +a, _X_GEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a <= b +a, _X_LEQ_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a > b +a, _X_GT_, b ) ...> } @@ char a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_int_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned int a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } @@ unsigned long a, b; identifier func; @@ func (...) { <... -tt_assert +tt_uint_op ( -a < b +a, _X_LT_, b ) ...> } ------------------------------ s/_X_NEQ_/!=/g; s/_X_NE_/!=/g; s/_X_EQ_/==/g; s/_X_GT_/>/g; s/_X_LT_/</g; s/_X_GEQ_/>=/g; s/_X_LEQ_/<=/g; s/test_mem_op\(/tt_mem_op\(/g;
2014-09-16 03:18:21 +02:00
tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Operation should be idempotent. */
tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32);
done:
tor_free(cp);
ext_orport_free_all();
}
static void
test_ext_or_cookie_auth(void *arg)
{
char *reply=NULL, *reply2=NULL, *client_hash=NULL, *client_hash2=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), OP_EQ, 46+32+32);
tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32);
ext_or_auth_cookie = tor_malloc_zero(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, OP_EQ,
handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
&reply_len));
tt_int_op(-1, OP_EQ,
handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
&reply_len));
/* Now let's try this for real! */
tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
&reply_len));
tt_int_op(reply_len, OP_EQ, 64);
tt_ptr_op(reply, OP_NE, NULL);
tt_ptr_op(client_hash, OP_NE, 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, (char*)ext_or_auth_cookie, 32, server_hash_input,
46+32+32);
crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
46+32+32);
tt_mem_op(hmac1,OP_EQ, reply, 32);
tt_mem_op(hmac2,OP_EQ, client_hash, 32);
/* Now do it again and make sure that the results are *different* */
tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
&reply_len));
tt_mem_op(reply2,OP_NE, reply, reply_len);
tt_mem_op(client_hash2,OP_NE, client_hash, 32);
/* But that this one checks out too. */
memcpy(server_hash_input+46+32, reply2+32, 32);
memcpy(client_hash_input+46+32, reply2+32, 32);
/* Check the HMACs are correct... */
crypto_hmac_sha256(hmac1, (char*)ext_or_auth_cookie, 32, server_hash_input,
46+32+32);
crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
46+32+32);
tt_mem_op(hmac1,OP_EQ, reply2, 32);
tt_mem_op(hmac2,OP_EQ, client_hash2, 32);
done:
tor_free(reply);
tor_free(client_hash);
tor_free(reply2);
tor_free(client_hash2);
}
static void
crypto_rand_return_tse_str(char *to, size_t n)
{
if (n != 32) {
TT_FAIL(("Asked for %d bytes, not 32", (int)n));
return;
}
memcpy(to, "te road There is always another ", 32);
}
static void
test_ext_or_cookie_auth_testvec(void *arg)
{
char *reply=NULL, *client_hash=NULL;
size_t reply_len;
char *mem_op_hex_tmp=NULL;
const char client_nonce[] = "But when I look ahead up the whi";
(void)arg;
ext_or_auth_cookie = tor_malloc_zero(32);
memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
ext_or_auth_cookie_is_set = 1;
MOCK(crypto_rand, crypto_rand_return_tse_str);
tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
&reply_len));
tt_ptr_op(reply, OP_NE, NULL );
tt_uint_op(reply_len, OP_EQ, 64);
tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32);
/* HMACSHA256("Gliding wrapt in a brown mantle,"
* "ExtORPort authentication server-to-client hash"
* "But when I look ahead up the write road There is always another ");
*/
test_memeq_hex(reply,
"ec80ed6e546d3b36fdfc22fe1315416b"
"029f1ade7610d910878b62eeb7403821");
/* HMACSHA256("Gliding wrapt in a brown mantle,"
* "ExtORPort authentication client-to-server hash"
* "But when I look ahead up the write road There is always another ");
* (Both values computed using Python CLI.)
*/
test_memeq_hex(client_hash,
"ab391732dd2ed968cd40c087d1b1f25b"
"33b3cd77ff79bd80c2074bbf438119a2");
done:
UNMOCK(crypto_rand);
tor_free(reply);
tor_free(client_hash);
tor_free(mem_op_hex_tmp);
}
static void
ignore_bootstrap_problem(const char *warn, int reason,
or_connection_t *conn)
{
(void)warn;
(void)reason;
(void)conn;
}
static int is_reading = 1;
static int handshake_start_called = 0;
static void
note_read_stopped(connection_t *conn)
{
(void)conn;
is_reading=0;
}
static void
note_read_started(connection_t *conn)
{
(void)conn;
is_reading=1;
}
static int
handshake_start(or_connection_t *conn, int receiving)
{
if (!conn || !receiving)
TT_FAIL(("Bad arguments to handshake_start"));
handshake_start_called = 1;
return 0;
}
#define WRITE(s,n) \
do { \
buf_add(TO_CONN(conn)->inbuf, (s), (n)); \
} while (0)
#define CONTAINS(s,n) \
do { \
tt_int_op((n), OP_LE, sizeof(b)); \
tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n)); \
if ((n)) { \
buf_get_bytes(TO_CONN(conn)->outbuf, b, (n)); \
tt_mem_op(b, OP_EQ, (s), (n)); \
} \
} while (0)
/* Helper: Do a successful Extended ORPort authentication handshake. */
static void
do_ext_or_handshake(or_connection_t *conn)
{
char b[256];
tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
CONTAINS("\x01\x00", 2);
WRITE("\x01", 1);
WRITE("But when I look ahead up the whi", 32);
MOCK(crypto_rand, crypto_rand_return_tse_str);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
UNMOCK(crypto_rand);
2014-11-12 19:42:01 +01:00
tt_int_op(TO_CONN(conn)->state, OP_EQ,
EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
"\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
"te road There is always another ", 64);
/* Send the right response this time. */
WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
"\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
32);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x01", 1);
tt_assert(! TO_CONN(conn)->marked_for_close);
tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
done: ;
}
static void
test_ext_or_handshake(void *arg)
{
or_connection_t *conn=NULL;
char b[256];
(void) arg;
MOCK(connection_write_to_buf_impl_,
connection_write_to_buf_impl_replacement);
/* Use same authenticators as for test_ext_or_cookie_auth_testvec */
ext_or_auth_cookie = tor_malloc_zero(32);
memcpy(ext_or_auth_cookie, "Gliding wrapt in a brown mantle," , 32);
ext_or_auth_cookie_is_set = 1;
init_connection_lists();
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
/* The server starts by telling us about the one supported authtype. */
CONTAINS("\x01\x00", 2);
/* Say the client hasn't responded yet. */
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
/* Let's say the client replies badly. */
WRITE("\x99", 1);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
/* Okay, try again. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
CONTAINS("\x01\x00", 2);
/* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
* sounds delicious. Let's have some of that!" */
WRITE("\x01", 1);
/* Let's say that the client also sends part of a nonce. */
WRITE("But when I look ", 16);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_int_op(TO_CONN(conn)->state, OP_EQ,
EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
/* Pump it again. Nothing should happen. */
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
/* send the rest of the nonce. */
WRITE("ahead up the whi", 16);
MOCK(crypto_rand, crypto_rand_return_tse_str);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
UNMOCK(crypto_rand);
/* We should get the right reply from the server. */
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
"\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
"te road There is always another ", 64);
/* Send the wrong response. */
WRITE("not with a bang but a whimper...", 32);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x00", 1);
tt_assert(TO_CONN(conn)->marked_for_close);
/* XXXX Hold-open-until-flushed. */
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_prob_or);
MOCK(connection_start_reading, note_read_started);
MOCK(connection_stop_reading, note_read_stopped);
MOCK(connection_tls_start_handshake, handshake_start);
/* Okay, this time let's succeed. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* Now let's run through some messages. */
/* First let's send some junk and make sure it's ignored. */
WRITE("\xff\xf0\x00\x03""ABC", 7);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
/* Now let's send a USERADDR command. */
WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678);
tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304);
/* Now let's send a TRANSPORT command. */
WRITE("\x00\x02\x00\x07""rfc1149", 11);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
tt_ptr_op(NULL, OP_NE, conn->ext_or_transport);
tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport);
tt_int_op(is_reading,OP_EQ,1);
tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
/* DONE */
WRITE("\x00\x00\x00\x00", 4);
tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING);
tt_int_op(is_reading,OP_EQ,0);
CONTAINS("\x10\x00\x00\x00", 4);
tt_int_op(handshake_start_called,OP_EQ,0);
tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn));
tt_int_op(is_reading,OP_EQ,1);
tt_int_op(handshake_start_called,OP_EQ,1);
tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
close_closeable_connections();
conn = NULL;
/* Okay, this time let's succeed the handshake but fail the USERADDR
command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* USERADDR command with an extra NUL byte */
WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* TRANSPORT command with an extra NUL byte */
WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_prob_or);
/* Now fail the TRANSPORT command. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
do_ext_or_handshake(conn);
/* TRANSPORT command with transport name with symbols (not a
C-identifier) */
WRITE("\x00\x02\x00\x07""rf*1149", 11);
MOCK(control_event_bootstrap_prob_or, ignore_bootstrap_problem);
tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
conn = NULL;
UNMOCK(control_event_bootstrap_prob_or);
done:
UNMOCK(connection_write_to_buf_impl_);
UNMOCK(crypto_rand);
if (conn)
connection_free_(TO_CONN(conn));
#undef CONTAINS
#undef WRITE
}
2013-07-18 21:51:29 +02:00
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 },
{ "init_auth", test_ext_or_init_auth, TT_FORK, NULL, NULL },
{ "cookie_auth", test_ext_or_cookie_auth, TT_FORK, NULL, NULL },
{ "cookie_auth_testvec", test_ext_or_cookie_auth_testvec, TT_FORK,
NULL, NULL },
{ "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL },
2013-07-18 21:51:29 +02:00
END_OF_TESTCASES
};