Merge branch 'ntor-resquashed'

Conflicts:
	src/or/cpuworker.c
	src/or/or.h
	src/test/bench.c
This commit is contained in:
Nick Mathewson
2013-01-03 11:52:41 -05:00
59 changed files with 5924 additions and 649 deletions
+142 -1
View File
@@ -15,17 +15,23 @@ const char tor_git_revision[] = "";
#include "orconfig.h"
#define RELAY_PRIVATE
#define CONFIG_PRIVATE
#include "or.h"
#include "onion_tap.h"
#include "relay.h"
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
#ifndef OPENSSL_NO_EC
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/obj_mac.h>
#endif
#include "config.h"
#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#endif
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
@@ -105,6 +111,125 @@ bench_aes(void)
crypto_cipher_free(c);
}
static void
bench_onion_TAP(void)
{
const int iters = 1<<9;
int i;
crypto_pk_t *key, *key2;
uint64_t start, end;
char os[TAP_ONIONSKIN_CHALLENGE_LEN];
char or[TAP_ONIONSKIN_REPLY_LEN];
crypto_dh_t *dh_out;
key = crypto_pk_new();
key2 = crypto_pk_new();
crypto_pk_generate_key_with_bits(key, 1024);
crypto_pk_generate_key_with_bits(key2, 1024);
reset_perftime();
start = perftime();
for (i = 0; i < iters; ++i) {
onion_skin_TAP_create(key, &dh_out, os);
crypto_dh_free(dh_out);
}
end = perftime();
printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
onion_skin_TAP_create(key, &dh_out, os);
start = perftime();
for (i = 0; i < iters; ++i) {
char key_out[CPATH_KEY_MATERIAL_LEN];
onion_skin_TAP_server_handshake(os, key, NULL, or,
key_out, sizeof(key_out));
}
end = perftime();
printf("Server-side, key guessed right: %f usec\n",
NANOCOUNT(start, end, iters)/1e3);
start = perftime();
for (i = 0; i < iters; ++i) {
char key_out[CPATH_KEY_MATERIAL_LEN];
onion_skin_TAP_server_handshake(os, key2, key, or,
key_out, sizeof(key_out));
}
end = perftime();
printf("Server-side, key guessed wrong: %f usec.\n",
NANOCOUNT(start, end, iters)/1e3);
start = perftime();
for (i = 0; i < iters; ++i) {
crypto_dh_t *dh;
char key_out[CPATH_KEY_MATERIAL_LEN];
int s;
dh = crypto_dh_dup(dh_out);
s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out));
tor_assert(s == 0);
}
end = perftime();
printf("Client-side, part 2: %f usec.\n",
NANOCOUNT(start, end, iters)/1e3);
crypto_pk_free(key);
}
#ifdef CURVE25519_ENABLED
static void
bench_onion_ntor(void)
{
const int iters = 1<<10;
int i;
curve25519_keypair_t keypair1, keypair2;
uint64_t start, end;
uint8_t os[NTOR_ONIONSKIN_LEN];
uint8_t or[NTOR_REPLY_LEN];
ntor_handshake_state_t *state = NULL;
uint8_t nodeid[DIGEST_LEN];
di_digest256_map_t *keymap = NULL;
curve25519_secret_key_generate(&keypair1.seckey, 0);
curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey);
curve25519_secret_key_generate(&keypair2.seckey, 0);
curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
reset_perftime();
start = perftime();
for (i = 0; i < iters; ++i) {
onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
ntor_handshake_state_free(state);
}
end = perftime();
printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
start = perftime();
for (i = 0; i < iters; ++i) {
uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or,
key_out, sizeof(key_out));
}
end = perftime();
printf("Server-side: %f usec\n",
NANOCOUNT(start, end, iters)/1e3);
start = perftime();
for (i = 0; i < iters; ++i) {
uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
int s;
s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out));
tor_assert(s == 0);
}
end = perftime();
printf("Client-side, part 2: %f usec.\n",
NANOCOUNT(start, end, iters)/1e3);
ntor_handshake_state_free(state);
dimap_free(keymap, NULL);
}
#endif
static void
bench_cell_aes(void)
{
@@ -355,6 +480,10 @@ typedef struct benchmark_t {
static struct benchmark_t benchmarks[] = {
ENT(dmap),
ENT(aes),
ENT(onion_TAP),
#ifdef CURVE25519_ENABLED
ENT(onion_ntor),
#endif
ENT(cell_aes),
ENT(cell_ops),
ENT(dh),
@@ -385,6 +514,8 @@ main(int argc, const char **argv)
int i;
int list=0, n_enabled=0;
benchmark_t *b;
char *errmsg;
or_options_t *options;
tor_threads_init();
@@ -405,6 +536,16 @@ main(int argc, const char **argv)
reset_perftime();
crypto_seed_rng(1);
options = options_new();
init_logging();
options->command = CMD_RUN_UNITTESTS;
options->DataDirectory = tor_strdup("");
options_init(options);
if (set_options(options, &errmsg) < 0) {
printf("Failed to set initial options: %s\n", errmsg);
tor_free(errmsg);
return 1;
}
for (b = benchmarks; b->name; ++b) {
if (b->enabled || n_enabled == 0) {
+17 -2
View File
@@ -36,14 +36,16 @@ src_test_bench_CPPFLAGS= $(src_test_AM_CPPFLAGS)
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
src_test_test_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
src_test_bench_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypto.a \
src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
@@ -51,3 +53,16 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-crypt
noinst_HEADERS+= \
src/test/test.h
if CURVE25519_ENABLED
noinst_PROGRAMS+= src/test/test-ntor-cl
src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@
src_test_test_ntor_cl_AM_CPPFLAGS = \
-I"$(top_srcdir)/src/or"
endif
+387
View File
@@ -0,0 +1,387 @@
# Copyright 2012 The Tor Project, Inc
# See LICENSE for licensing information
"""
ntor_ref.py
This module is a reference implementation for the "ntor" protocol
s proposed by Goldberg, Stebila, and Ustaoglu and as instantiated in
Tor Proposal 216.
It's meant to be used to validate Tor's ntor implementation. It
requirs the curve25519 python module from the curve25519-donna
package.
*** DO NOT USE THIS IN PRODUCTION. ***
commands:
gen_kdf_vectors: Print out some test vectors for the RFC5869 KDF.
timing: Print a little timing information about this implementation's
handshake.
self-test: Try handshaking with ourself; make sure we can.
test-tor: Handshake with tor's ntor implementation via the program
src/test/test-ntor-cl; make sure we can.
"""
import binascii
import curve25519
import hashlib
import hmac
import subprocess
# **********************************************************************
# Helpers and constants
def HMAC(key,msg):
"Return the HMAC-SHA256 of 'msg' using the key 'key'."
H = hmac.new(key, "", hashlib.sha256)
H.update(msg)
return H.digest()
def H(msg,tweak):
"""Return the hash of 'msg' using tweak 'tweak'. (In this version of ntor,
the tweaked hash is just HMAC with the tweak as the key.)"""
return HMAC(key=tweak,
msg=msg)
def keyid(k):
"""Return the 32-byte key ID of a public key 'k'. (Since we're
using curve25519, we let k be its own keyid.)
"""
return k.serialize()
NODE_ID_LENGTH = 20
KEYID_LENGTH = 32
G_LENGTH = 32
H_LENGTH = 32
PROTOID = b"ntor-curve25519-sha256-1"
M_EXPAND = PROTOID + ":key_expand"
T_MAC = PROTOID + ":mac"
T_KEY = PROTOID + ":key_extract"
T_VERIFY = PROTOID + ":verify"
def H_mac(msg): return H(msg, tweak=T_MAC)
def H_verify(msg): return H(msg, tweak=T_VERIFY)
class PrivateKey(curve25519.keys.Private):
"""As curve25519.keys.Private, but doesn't regenerate its public key
every time you ask for it.
"""
def __init__(self):
curve25519.keys.Private.__init__(self)
self._memo_public = None
def get_public(self):
if self._memo_public is None:
self._memo_public = curve25519.keys.Private.get_public(self)
return self._memo_public
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def kdf_rfc5869(key, salt, info, n):
prk = HMAC(key=salt, msg=key)
out = b""
last = b""
i = 1
while len(out) < n:
m = last + info + chr(i)
last = h = HMAC(key=prk, msg=m)
out += h
i = i + 1
return out[:n]
def kdf_ntor(key, n):
return kdf_rfc5869(key, T_KEY, M_EXPAND, n)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def client_part1(node_id, pubkey_B):
"""Initial handshake, client side.
From the specification:
<<To send a create cell, the client generates a keypair x,X =
KEYGEN(), and sends a CREATE cell with contents:
NODEID: ID -- ID_LENGTH bytes
KEYID: KEYID(B) -- H_LENGTH bytes
CLIENT_PK: X -- G_LENGTH bytes
>>
Takes node_id -- a digest of the server's identity key,
pubkey_B -- a public key for the server.
Returns a tuple of (client secret key x, client->server message)"""
assert len(node_id) == NODE_ID_LENGTH
key_id = keyid(pubkey_B)
seckey_x = PrivateKey()
pubkey_X = seckey_x.get_public().serialize()
message = node_id + key_id + pubkey_X
assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
return seckey_x , message
def hash_nil(x):
"""Identity function: if we don't pass a hash function that does nothing,
the curve25519 python lib will try to sha256 it for us."""
return x
def bad_result(r):
"""Helper: given a result of multiplying a public key by a private key,
return True iff one of the inputs was broken"""
assert len(r) == 32
return r == '\x00'*32
def server(seckey_b, my_node_id, message, keyBytes=72):
"""Handshake step 2, server side.
From the spec:
<<
The server generates a keypair of y,Y = KEYGEN(), and computes
secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
KEY_SEED = H(secret_input, t_key)
verify = H(secret_input, t_verify)
auth_input = verify | ID | B | Y | X | PROTOID | "Server"
The server sends a CREATED cell containing:
SERVER_PK: Y -- G_LENGTH bytes
AUTH: H(auth_input, t_mac) -- H_LENGTH byets
>>
Takes seckey_b -- the server's secret key
my_node_id -- the servers's public key digest,
message -- a message from a client
keybytes -- amount of key material to generate
Returns a tuple of (key material, sever->client reply), or None on
error.
"""
assert len(message) == NODE_ID_LENGTH + H_LENGTH + H_LENGTH
if my_node_id != message[:NODE_ID_LENGTH]:
return None
badness = (keyid(seckey_b.get_public()) !=
message[NODE_ID_LENGTH:NODE_ID_LENGTH+H_LENGTH])
pubkey_X = curve25519.keys.Public(message[NODE_ID_LENGTH+H_LENGTH:])
seckey_y = PrivateKey()
pubkey_Y = seckey_y.get_public()
pubkey_B = seckey_b.get_public()
xy = seckey_y.get_shared_key(pubkey_X, hash_nil)
xb = seckey_b.get_shared_key(pubkey_X, hash_nil)
# secret_input = EXP(X,y) | EXP(X,b) | ID | B | X | Y | PROTOID
secret_input = (xy + xb + my_node_id +
pubkey_B.serialize() +
pubkey_X.serialize() +
pubkey_Y.serialize() +
PROTOID)
verify = H_verify(secret_input)
# auth_input = verify | ID | B | Y | X | PROTOID | "Server"
auth_input = (verify +
my_node_id +
pubkey_B.serialize() +
pubkey_Y.serialize() +
pubkey_X.serialize() +
PROTOID +
"Server")
msg = pubkey_Y.serialize() + H_mac(auth_input)
badness += bad_result(xb)
badness += bad_result(xy)
if badness:
return None
keys = kdf_ntor(secret_input, keyBytes)
return keys, msg
def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
"""Handshake step 3: client side again.
From the spec:
<<
The client then checks Y is in G^* [see NOTE below], and computes
secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
KEY_SEED = H(secret_input, t_key)
verify = H(secret_input, t_verify)
auth_input = verify | ID | B | Y | X | PROTOID | "Server"
The client verifies that AUTH == H(auth_input, t_mac).
>>
Takes seckey_x -- the secret key we generated in step 1.
msg -- the message from the server.
node_id -- the node_id we used in step 1.
server_key -- the same public key we used in step 1.
keyBytes -- the number of bytes we want to generate
Returns key material, or None on error
"""
assert len(msg) == G_LENGTH + H_LENGTH
pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH])
their_auth = msg[G_LENGTH:]
pubkey_X = seckey_x.get_public()
yx = seckey_x.get_shared_key(pubkey_Y, hash_nil)
bx = seckey_x.get_shared_key(pubkey_B, hash_nil)
# secret_input = EXP(Y,x) | EXP(B,x) | ID | B | X | Y | PROTOID
secret_input = (yx + bx + node_id +
pubkey_B.serialize() +
pubkey_X.serialize() +
pubkey_Y.serialize() + PROTOID)
verify = H_verify(secret_input)
# auth_input = verify | ID | B | Y | X | PROTOID | "Server"
auth_input = (verify + node_id +
pubkey_B.serialize() +
pubkey_Y.serialize() +
pubkey_X.serialize() + PROTOID +
"Server")
my_auth = H_mac(auth_input)
badness = my_auth != their_auth
badness = bad_result(yx) + bad_result(bx)
if badness:
return None
return kdf_ntor(secret_input, keyBytes)
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def demo(node_id="iToldYouAboutStairs.", server_key=PrivateKey()):
"""
Try to handshake with ourself.
"""
x, create = client_part1(node_id, server_key.get_public())
skeys, created = server(server_key, node_id, create)
ckeys = client_part2(x, created, node_id, server_key.get_public())
assert len(skeys) == 72
assert len(ckeys) == 72
assert skeys == ckeys
# ======================================================================
def timing():
"""
Use Python's timeit module to see how fast this nonsense is
"""
import timeit
t = timeit.Timer(stmt="ntor_ref.demo(N,SK)",
setup="import ntor_ref,curve25519;N='ABCD'*5;SK=ntor_ref.PrivateKey()")
print t.timeit(number=1000)
# ======================================================================
def kdf_vectors():
"""
Generate some vectors to check our KDF.
"""
import binascii
def kdf_vec(inp):
k = kdf(inp, T_KEY, M_EXPAND, 100)
print repr(inp), "\n\""+ binascii.b2a_hex(k)+ "\""
kdf_vec("")
kdf_vec("Tor")
kdf_vec("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT")
# ======================================================================
def test_tor():
"""
Call the test-ntor-cl command-line program to make sure we can
interoperate with Tor's ntor program
"""
enhex=binascii.b2a_hex
dehex=lambda s: binascii.a2b_hex(s.strip())
PROG = "./src/test/test-ntor-cl"
def tor_client1(node_id, pubkey_B):
" returns (msg, state) "
p = subprocess.Popen([PROG, "client1", enhex(node_id),
enhex(pubkey_B.serialize())],
stdout=subprocess.PIPE)
return map(dehex, p.stdout.readlines())
def tor_server1(seckey_b, node_id, msg, n):
" returns (msg, keys) "
p = subprocess.Popen([PROG, "server1", enhex(seckey_b.serialize()),
enhex(node_id), enhex(msg), str(n)],
stdout=subprocess.PIPE)
return map(dehex, p.stdout.readlines())
def tor_client2(state, msg, n):
" returns (keys,) "
p = subprocess.Popen([PROG, "client2", enhex(state),
enhex(msg), str(n)],
stdout=subprocess.PIPE)
return map(dehex, p.stdout.readlines())
node_id = "thisisatornodeid$#%^"
seckey_b = PrivateKey()
pubkey_B = seckey_b.get_public()
# Do a pure-Tor handshake
c2s_msg, c_state = tor_client1(node_id, pubkey_B)
s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
c_keys, = tor_client2(c_state, s2c_msg, 90)
assert c_keys == s_keys
assert len(c_keys) == 90
# Try a mixed handshake with Tor as the client
c2s_msg, c_state = tor_client1(node_id, pubkey_B)
s_keys, s2c_msg = server(seckey_b, node_id, c2s_msg, 90)
c_keys, = tor_client2(c_state, s2c_msg, 90)
assert c_keys == s_keys
assert len(c_keys) == 90
# Now do a mixed handshake with Tor as the server
c_x, c2s_msg = client_part1(node_id, pubkey_B)
s2c_msg, s_keys = tor_server1(seckey_b, node_id, c2s_msg, 90)
c_keys = client_part2(c_x, s2c_msg, node_id, pubkey_B, 90)
assert c_keys == s_keys
assert len(c_keys) == 90
print "We just interoperated."
# ======================================================================
if __name__ == '__main__':
import sys
if sys.argv[1] == 'gen_kdf_vectors':
kdf_vectors()
elif sys.argv[1] == 'timing':
timing()
elif sys.argv[1] == 'self-test':
demo()
elif sys.argv[1] == 'test-tor':
test_tor()
else:
print __doc__
+69 -8
View File
@@ -53,10 +53,14 @@ double fabs(double x);
#include "torgzip.h"
#include "mempool.h"
#include "memarea.h"
#include "onion.h"
#include "onion_tap.h"
#include "policies.h"
#include "rephist.h"
#include "routerparse.h"
#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#endif
#ifdef USE_DMALLOC
#include <dmalloc.h>
@@ -815,11 +819,11 @@ test_onion_handshake(void)
{
/* client-side */
crypto_dh_t *c_dh = NULL;
char c_buf[ONIONSKIN_CHALLENGE_LEN];
char c_buf[TAP_ONIONSKIN_CHALLENGE_LEN];
char c_keys[40];
/* server-side */
char s_buf[ONIONSKIN_REPLY_LEN];
char s_buf[TAP_ONIONSKIN_REPLY_LEN];
char s_keys[40];
/* shared */
@@ -828,18 +832,18 @@ test_onion_handshake(void)
pk = pk_generate(0);
/* client handshake 1. */
memset(c_buf, 0, ONIONSKIN_CHALLENGE_LEN);
test_assert(! onion_skin_create(pk, &c_dh, c_buf));
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
/* server handshake */
memset(s_buf, 0, ONIONSKIN_REPLY_LEN);
memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
memset(s_keys, 0, 40);
test_assert(! onion_skin_server_handshake(c_buf, pk, NULL,
test_assert(! onion_skin_TAP_server_handshake(c_buf, pk, NULL,
s_buf, s_keys, 40));
/* client handshake 2 */
memset(c_keys, 0, 40);
test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40));
test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
if (memcmp(c_keys, s_keys, 40)) {
puts("Aiiiie");
@@ -856,6 +860,60 @@ test_onion_handshake(void)
crypto_pk_free(pk);
}
#ifdef CURVE25519_ENABLED
static void
test_ntor_handshake(void *arg)
{
/* client-side */
ntor_handshake_state_t *c_state = NULL;
uint8_t c_buf[NTOR_ONIONSKIN_LEN];
uint8_t c_keys[400];
/* server-side */
di_digest256_map_t *s_keymap=NULL;
curve25519_keypair_t s_keypair;
uint8_t s_buf[NTOR_REPLY_LEN];
uint8_t s_keys[400];
/* shared */
const curve25519_public_key_t *server_pubkey;
uint8_t node_id[20] = "abcdefghijklmnopqrst";
(void) arg;
/* Make the server some keys */
curve25519_secret_key_generate(&s_keypair.seckey, 0);
curve25519_public_key_generate(&s_keypair.pubkey, &s_keypair.seckey);
dimap_add_entry(&s_keymap, s_keypair.pubkey.public_key, &s_keypair);
server_pubkey = &s_keypair.pubkey;
/* client handshake 1. */
memset(c_buf, 0, NTOR_ONIONSKIN_LEN);
tt_int_op(0, ==, onion_skin_ntor_create(node_id, server_pubkey,
&c_state, c_buf));
/* server handshake */
memset(s_buf, 0, NTOR_REPLY_LEN);
memset(s_keys, 0, 40);
tt_int_op(0, ==, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL,
node_id,
s_buf, s_keys, 400));
/* client handshake 2 */
memset(c_keys, 0, 40);
tt_int_op(0, ==, onion_skin_ntor_client_handshake(c_state, s_buf,
c_keys, 400));
test_memeq(c_keys, s_keys, 400);
memset(s_buf, 0, 40);
test_memneq(c_keys, s_buf, 40);
done:
ntor_handshake_state_free(c_state);
dimap_free(s_keymap, NULL);
}
#endif
static void
test_circuit_timeout(void)
{
@@ -1947,6 +2005,9 @@ static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
#ifdef CURVE25519_ENABLED
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
#endif
ENT(circuit_timeout),
ENT(policies),
ENT(rend_fns),
+502
View File
@@ -9,6 +9,10 @@
#define RELAY_PRIVATE
#include "or.h"
#include "connection_edge.h"
#include "onion.h"
#include "onion_tap.h"
#include "onion_fast.h"
#include "onion_ntor.h"
#include "relay.h"
#include "test.h"
@@ -374,6 +378,500 @@ test_cfmt_connected_cells(void *arg)
tor_free(mem_op_hex_tmp);
}
static void
test_cfmt_create_cells(void *arg)
{
uint8_t b[MAX_ONIONSKIN_CHALLENGE_LEN];
create_cell_t cc;
cell_t cell;
cell_t cell2;
(void)arg;
/* === Let's try parsing some good cells! */
/* A valid create cell. */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
cell.command = CELL_CREATE;
memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN);
tt_int_op(0, ==, create_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATE, ==, cc.cell_type);
tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
tt_int_op(0, ==, create_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create_fast cell. */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, CREATE_FAST_LEN);
cell.command = CELL_CREATE_FAST;
memcpy(cell.payload, b, CREATE_FAST_LEN);
tt_int_op(0, ==, create_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type);
tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type);
tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len);
test_memeq(cc.onionskin, b, CREATE_FAST_LEN + 10);
tt_int_op(0, ==, create_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create2 cell with a TAP payload */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */
memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN);
tt_int_op(0, ==, create_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATE2, ==, cc.cell_type);
tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
tt_int_op(0, ==, create_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create2 cell with an ntor payload */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */
memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN);
#ifdef CURVE25519_ENABLED
tt_int_op(0, ==, create_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATE2, ==, cc.cell_type);
tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
tt_int_op(0, ==, create_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
#else
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
#endif
/* A valid create cell with an ntor payload, in legacy format. */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
cell.command = CELL_CREATE;
memcpy(cell.payload, "ntorNTORntorNTOR", 16);
memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
#ifdef CURVE25519_ENABLED
tt_int_op(0, ==, create_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATE, ==, cc.cell_type);
tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
tt_int_op(0, ==, create_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
#else
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
#endif
/* == Okay, now let's try to parse some impossible stuff. */
/* It has to be some kind of a create cell! */
cell.command = CELL_CREATED;
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
/* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */
/* Try some CREATE2 cells. First with a bad type. */
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
/* Now a good type with an incorrect length. */
memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
/* Now a good type with a ridiculous length. */
memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/
tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
/* == Time to try formatting bad cells. The important thing is that
we reject big lengths, so just check that for now. */
cc.handshake_len = 512;
tt_int_op(-1, ==, create_cell_format(&cell2, &cc));
/* == Try formatting a create2 cell we don't understand. XXXX */
done:
;
}
static void
test_cfmt_created_cells(void *arg)
{
uint8_t b[512];
created_cell_t cc;
cell_t cell;
cell_t cell2;
(void)arg;
/* A good CREATED cell */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
cell.command = CELL_CREATED;
memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN);
tt_int_op(0, ==, created_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATED, ==, cc.cell_type);
tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len);
test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10);
tt_int_op(0, ==, created_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED_FAST cell */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, CREATED_FAST_LEN);
cell.command = CELL_CREATED_FAST;
memcpy(cell.payload, b, CREATED_FAST_LEN);
tt_int_op(0, ==, created_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type);
tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len);
test_memeq(cc.reply, b, CREATED_FAST_LEN + 10);
tt_int_op(0, ==, created_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED2 cell with short reply */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, 64);
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x00\x40", 2);
memcpy(cell.payload+2, b, 64);
tt_int_op(0, ==, created_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATED2, ==, cc.cell_type);
tt_int_op(64, ==, cc.handshake_len);
test_memeq(cc.reply, b, 80);
tt_int_op(0, ==, created_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED2 cell with maximal reply */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, 496);
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x01\xF0", 2);
memcpy(cell.payload+2, b, 496);
tt_int_op(0, ==, created_cell_parse(&cc, &cell));
tt_int_op(CELL_CREATED2, ==, cc.cell_type);
tt_int_op(496, ==, cc.handshake_len);
test_memeq(cc.reply, b, 496);
tt_int_op(0, ==, created_cell_format(&cell2, &cc));
tt_int_op(cell.command, ==, cell2.command);
test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
/* Bogus CREATED2 cell: too long! */
memset(&cell, 0, sizeof(cell));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, 496);
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x01\xF1", 2);
tt_int_op(-1, ==, created_cell_parse(&cc, &cell));
/* Unformattable CREATED2 cell: too long! */
cc.handshake_len = 497;
tt_int_op(-1, ==, created_cell_format(&cell2, &cc));
done:
;
}
static void
test_cfmt_extend_cells(void *arg)
{
cell_t cell;
uint8_t b[512];
extend_cell_t ec;
create_cell_t *cc = &ec.create_cell;
uint8_t p[RELAY_PAYLOAD_SIZE];
uint8_t p2[RELAY_PAYLOAD_SIZE];
uint8_t p2_cmd;
uint16_t p2_len;
char *mem_op_hex_tmp = NULL;
(void) arg;
/* Let's start with a simple EXTEND cell. */
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN);
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
tt_int_op(258, ==, ec.orport_ipv4.port);
tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
test_memeq(ec.node_id, "electroencephalogram", 20);
tt_int_op(cc->cell_type, ==, CELL_CREATE);
tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP);
tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN);
test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
/* Let's do an ntor stuffed in a legacy EXTEND cell */
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
memcpy(p+6,"ntorNTORntorNTOR", 16);
memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
tt_int_op(258, ==, ec.orport_ipv4.port);
tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
test_memeq(ec.node_id, "electroencephalogram", 20);
tt_int_op(cc->cell_type, ==, CELL_CREATE2);
tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
/* Now let's do a minimal ntor EXTEND2 cell. */
memset(&ec, 0xff, sizeof(ec));
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, NTOR_ONIONSKIN_LEN);
/* 2 items; one 18.244.0.1:61681 */
memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
/* The other is a digest. */
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
/* Prep for the handshake: type and length */
memcpy(p+31, "\x00\x02\x00\x54", 4);
memcpy(p+35, b, NTOR_ONIONSKIN_LEN);
tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, 35+NTOR_ONIONSKIN_LEN));
tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
tt_int_op(61681, ==, ec.orport_ipv4.port);
tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
test_memeq(ec.node_id, "anarchoindividualist", 20);
tt_int_op(cc->cell_type, ==, CELL_CREATE2);
tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN);
test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
/* Now let's do a fanciful EXTEND2 cell. */
memset(&ec, 0xff, sizeof(ec));
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, 99);
/* 4 items; one 18 244 0 1 61681 */
memcpy(p, "\x04\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
/* One is a digest. */
memcpy(p+9, "\x02\x14" "anthropomorphization", 22);
/* One is an ipv6 address */
memcpy(p+31, "\x01\x12\x20\x02\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\xf0\xc5\x1e\x11\x12", 20);
/* One is the Konami code. */
memcpy(p+51, "\xf0\x20upupdowndownleftrightleftrightba", 34);
/* Prep for the handshake: weird type and length */
memcpy(p+85, "\x01\x05\x00\x63", 4);
memcpy(p+89, b, 99);
tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99));
tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
tt_int_op(61681, ==, ec.orport_ipv4.port);
tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr));
tt_int_op(4370, ==, ec.orport_ipv6.port);
test_memeq(ec.node_id, "anthropomorphization", 20);
tt_int_op(cc->cell_type, ==, CELL_CREATE2);
tt_int_op(cc->handshake_type, ==, 0x105);
tt_int_op(cc->handshake_len, ==, 99);
test_memeq(cc->onionskin, b, 99+20);
tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
/* We'll generate it minus the IPv6 address and minus the konami code */
tt_int_op(p2_len, ==, 89+99-34-20);
test_memeq_hex(p2,
/* Two items: one that same darn IP address. */
"02000612F40001F0F1"
/* The next is a digest : anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
/* Now the handshake prologue */
"01050063");
test_memeq(p2+1+8+22+4, b, 99+20);
tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
/* == Now try parsing some junk */
/* Try a too-long handshake */
memset(p, 0, sizeof(p));
memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\xff\xff\x01\xd0", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Try two identities. */
memset(p, 0, sizeof(p));
memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x02\x14" "autodepolymerization", 22);
memcpy(p+53, "\xff\xff\x00\x10", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* No identities. */
memset(p, 0, sizeof(p));
memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+53, "\xff\xff\x00\x10", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Try a bad IPv4 address (too long, too short)*/
memset(p, 0, sizeof(p));
memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10);
memcpy(p+10, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+32, "\xff\xff\x00\x10", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8);
memcpy(p+8, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+30, "\xff\xff\x00\x10", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* IPv6 address (too long, too short, no IPv4)*/
memset(p, 0, sizeof(p));
memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19);
memcpy(p+50, "\xff\xff\x00\x20", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17);
memcpy(p+48, "\xff\xff\x00\x20", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x02", 1);
memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
memcpy(p+41, "\xff\xff\x00\x20", 4);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Running out of space in specifiers */
memset(p,0,sizeof(p));
memcpy(p, "\x05\x0a\xff", 3);
memcpy(p+3+255, "\x0a\xff", 2);
tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Fuzz, because why not. */
memset(&ec, 0xff, sizeof(ec));
{
int i;
memset(p, 0, sizeof(p));
for (i = 0; i < 10000; ++i) {
int n = crypto_rand_int(sizeof(p));
crypto_rand((char *)p, n);
extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, n);
}
}
done:
tor_free(mem_op_hex_tmp);
}
static void
test_cfmt_extended_cells(void *arg)
{
uint8_t b[512];
extended_cell_t ec;
created_cell_t *cc = &ec.created_cell;
uint8_t p[RELAY_PAYLOAD_SIZE];
uint8_t p2[RELAY_PAYLOAD_SIZE];
uint8_t p2_cmd;
uint16_t p2_len;
char *mem_op_hex_tmp = NULL;
(void) arg;
/* Try a regular EXTENDED cell. */
memset(&ec, 0xff, sizeof(ec));
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN);
tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
TAP_ONIONSKIN_REPLY_LEN));
tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type);
tt_int_op(cc->cell_type, ==, CELL_CREATED);
tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN);
test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN);
tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd);
tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len);
test_memeq(p2, p, sizeof(p2));
/* Try an EXTENDED2 cell */
memset(&ec, 0xff, sizeof(ec));
memset(p, 0, sizeof(p));
memset(b, 0, sizeof(b));
crypto_rand((char*)b, 42);
memcpy(p,"\x00\x2a",2);
memcpy(p+2,b,42);
tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42));
tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type);
tt_int_op(cc->cell_type, ==, CELL_CREATED2);
tt_int_op(cc->handshake_len, ==, 42);
test_memeq(cc->reply, b, 42+10);
tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd);
tt_int_op(2+42, ==, p2_len);
test_memeq(p2, p, sizeof(p2));
/* Try an almost-too-long EXTENDED2 cell */
memcpy(p, "\x01\xf0", 2);
tt_int_op(0, ==,
extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
/* Now try a too-long extended2 cell. That's the only misparse I can think
* of. */
memcpy(p, "\x01\xf1", 2);
tt_int_op(-1, ==,
extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
done:
tor_free(mem_op_hex_tmp);
}
#define TEST(name, flags) \
{ #name, test_cfmt_ ## name, flags, 0, NULL }
@@ -381,6 +879,10 @@ struct testcase_t cell_format_tests[] = {
TEST(relay_header, 0),
TEST(begin_cells, 0),
TEST(connected_cells, 0),
TEST(create_cells, 0),
TEST(created_cells, 0),
TEST(extend_cells, 0),
TEST(extended_cells, 0),
END_OF_TESTCASES
};
+45
View File
@@ -782,6 +782,50 @@ test_container_order_functions(void)
;
}
static void
test_di_map(void *arg)
{
di_digest256_map_t *map = NULL;
const uint8_t key1[] = "In view of the fact that it was ";
const uint8_t key2[] = "superficially convincing, being ";
const uint8_t key3[] = "properly enciphered in a one-tim";
const uint8_t key4[] = "e cipher scheduled for use today";
char *v1 = tor_strdup(", it came close to causing a disaster...");
char *v2 = tor_strdup("I regret to have to advise you that the mission");
char *v3 = tor_strdup("was actually initiated...");
/* -- John Brunner, _The Shockwave Rider_ */
(void)arg;
/* Try searching on an empty map. */
tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL));
tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
dimap_free(map, NULL);
map = NULL;
/* Add a single entry. */
dimap_add_entry(&map, key1, v1);
tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
/* Now try it with three entries in the map. */
dimap_add_entry(&map, key2, v2);
dimap_add_entry(&map, key3, v3);
tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
tt_ptr_op(v2, ==, dimap_search(map, key2, NULL));
tt_ptr_op(v3, ==, dimap_search(map, key3, NULL));
tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL));
tt_ptr_op(v1, ==, dimap_search(map, key4, v1));
done:
tor_free(v1);
tor_free(v2);
tor_free(v3);
dimap_free(map, NULL);
}
#define CONTAINER_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
@@ -796,6 +840,7 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(strmap),
CONTAINER_LEGACY(pqueue),
CONTAINER_LEGACY(order_functions),
{ "di_map", test_di_map, 0, NULL, NULL },
END_OF_TESTCASES
};
+181
View File
@@ -5,9 +5,13 @@
#include "orconfig.h"
#define CRYPTO_PRIVATE
#define CRYPTO_CURVE25519_PRIVATE
#include "or.h"
#include "test.h"
#include "aes.h"
#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#endif
/** Run unit tests for Diffie-Hellman functionality. */
static void
@@ -832,6 +836,177 @@ test_crypto_base32_decode(void)
;
}
static void
test_crypto_kdf_TAP(void *arg)
{
uint8_t key_material[100];
int r;
char *mem_op_hex_tmp = NULL;
(void)arg;
#define EXPAND(s) \
r = crypto_expand_key_material_TAP( \
(const uint8_t*)(s), strlen(s), \
key_material, 100)
/* Test vectors generated with a little python script; feel free to write
* your own. */
memset(key_material, 0, sizeof(key_material));
EXPAND("");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"5ba93c9db0cff93f52b521d7420e43f6eda2784fbf8b4530d8"
"d246dd74ac53a13471bba17941dff7c4ea21bb365bbeeaf5f2"
"c654883e56d11e43c44e9842926af7ca0a8cca12604f945414"
"f07b01e13da42c6cf1de3abfdea9b95f34687cbbe92b9a7383");
EXPAND("Tor");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"776c6214fc647aaa5f683c737ee66ec44f03d0372e1cce6922"
"7950f236ddf1e329a7ce7c227903303f525a8c6662426e8034"
"870642a6dabbd41b5d97ec9bf2312ea729992f48f8ea2d0ba8"
"3f45dfda1a80bdc8b80de01b23e3e0ffae099b3e4ccf28dc28");
EXPAND("AN ALARMING ITEM TO FIND ON A MONTHLY AUTO-DEBIT NOTICE");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"a340b5d126086c3ab29c2af4179196dbf95e1c72431419d331"
"4844bf8f6afb6098db952b95581fb6c33625709d6f4400b8e7"
"ace18a70579fad83c0982ef73f89395bcc39493ad53a685854"
"daf2ba9b78733b805d9a6824c907ee1dba5ac27a1e466d4d10");
done:
tor_free(mem_op_hex_tmp);
#undef EXPAND
}
static void
test_crypto_hkdf_sha256(void *arg)
{
uint8_t key_material[100];
const uint8_t salt[] = "ntor-curve25519-sha256-1:key_extract";
const size_t salt_len = strlen((char*)salt);
const uint8_t m_expand[] = "ntor-curve25519-sha256-1:key_expand";
const size_t m_expand_len = strlen((char*)m_expand);
int r;
char *mem_op_hex_tmp = NULL;
(void)arg;
#define EXPAND(s) \
r = crypto_expand_key_material_rfc5869_sha256( \
(const uint8_t*)(s), strlen(s), \
salt, salt_len, \
m_expand, m_expand_len, \
key_material, 100)
/* Test vectors generated with ntor_ref.py */
memset(key_material, 0, sizeof(key_material));
EXPAND("");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75"
"eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd"
"d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7"
"dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8");
EXPAND("Tor");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6"
"c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d"
"66c4a3c4d6225429b3a016e3c3d45911152fc87bc2de9630c3"
"961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac");
EXPAND("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT");
tt_int_op(r, ==, 0);
test_memeq_hex(key_material,
"a2aa9b50da7e481d30463adb8f233ff06e9571a0ca6ab6df0f"
"b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c"
"5f8bd13e0f88b3459600b4dc21d69363e2895321c06184879d"
"94b18f078411be70b767c7fc40679a9440a0c95ea83a23efbf");
done:
tor_free(mem_op_hex_tmp);
#undef EXPAND
}
#ifdef CURVE25519_ENABLED
static void
test_crypto_curve25519_impl(void *arg)
{
/* adapted from curve25519_donna, which adapted it from test-curve25519
version 20050915, by D. J. Bernstein, Public domain. */
unsigned char e1k[32];
unsigned char e2k[32];
unsigned char e1e2k[32];
unsigned char e2e1k[32];
unsigned char e1[32] = {3};
unsigned char e2[32] = {5};
unsigned char k[32] = {9};
int loop, i;
const int loop_max=10000;
char *mem_op_hex_tmp = NULL;
(void)arg;
for (loop = 0; loop < loop_max; ++loop) {
curve25519_impl(e1k,e1,k);
curve25519_impl(e2e1k,e2,e1k);
curve25519_impl(e2k,e2,k);
curve25519_impl(e1e2k,e1,e2k);
test_memeq(e1e2k, e2e1k, 32);
if (loop == loop_max-1) {
break;
}
for (i = 0;i < 32;++i) e1[i] ^= e2k[i];
for (i = 0;i < 32;++i) e2[i] ^= e1k[i];
for (i = 0;i < 32;++i) k[i] ^= e1e2k[i];
}
test_memeq_hex(e1,
"4faf81190869fd742a33691b0e0824d5"
"7e0329f4dd2819f5f32d130f1296b500");
test_memeq_hex(e2k,
"05aec13f92286f3a781ccae98995a3b9"
"e0544770bc7de853b38f9100489e3e79");
test_memeq_hex(e1e2k,
"cd6e8269104eb5aaee886bd2071fba88"
"bd13861475516bc2cd2b6e005e805064");
done:
tor_free(mem_op_hex_tmp);
}
static void
test_crypto_curve25519_wrappers(void *arg)
{
curve25519_public_key_t pubkey1, pubkey2;
curve25519_secret_key_t seckey1, seckey2;
uint8_t output1[CURVE25519_OUTPUT_LEN];
uint8_t output2[CURVE25519_OUTPUT_LEN];
(void)arg;
/* Test a simple handshake, serializing and deserializing some stuff. */
curve25519_secret_key_generate(&seckey1, 0);
curve25519_secret_key_generate(&seckey2, 1);
curve25519_public_key_generate(&pubkey1, &seckey1);
curve25519_public_key_generate(&pubkey2, &seckey2);
test_assert(curve25519_public_key_is_ok(&pubkey1));
test_assert(curve25519_public_key_is_ok(&pubkey2));
curve25519_handshake(output1, &seckey1, &pubkey2);
curve25519_handshake(output2, &seckey2, &pubkey1);
test_memeq(output1, output2, sizeof(output1));
done:
;
}
#endif
static void *
pass_data_setup_fn(const struct testcase_t *testcase)
{
@@ -863,6 +1038,12 @@ struct testcase_t crypto_tests[] = {
{ "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
{ "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
{ "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL },
{ "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL },
#ifdef CURVE25519_ENABLED
{ "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL },
{ "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL },
#endif
END_OF_TESTCASES
};
+166
View File
@@ -0,0 +1,166 @@
/* Copyright (c) 2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include <stdio.h>
#include <stdlib.h>
#define ONION_NTOR_PRIVATE
#include "or.h"
#include "util.h"
#include "compat.h"
#include "crypto.h"
#include "crypto_curve25519.h"
#include "onion_ntor.h"
#ifndef CURVE25519_ENABLED
#error "This isn't going to work without curve25519."
#endif
#define N_ARGS(n) STMT_BEGIN { \
if (argc < (n)) { \
fprintf(stderr, "%s needs %d arguments.\n",argv[1],n); \
return 1; \
} \
} STMT_END
#define BASE16(idx, var, n) STMT_BEGIN { \
const char *s = argv[(idx)]; \
if (base16_decode((char*)var, n, s, strlen(s)) < 0 ) { \
fprintf(stderr, "couldn't decode argument %d (%s)\n",idx,s); \
return 1; \
} \
} STMT_END
#define INT(idx, var) STMT_BEGIN { \
var = atoi(argv[(idx)]); \
if (var <= 0) { \
fprintf(stderr, "bad integer argument %d (%s)\n",idx,argv[(idx)]); \
} \
} STMT_END
static int
client1(int argc, char **argv)
{
/* client1 nodeID B -> msg state */
curve25519_public_key_t B;
uint8_t node_id[DIGEST_LEN];
ntor_handshake_state_t *state;
uint8_t msg[NTOR_ONIONSKIN_LEN];
char buf[1024];
memset(&state, 0, sizeof(state));
N_ARGS(4);
BASE16(2, node_id, DIGEST_LEN);
BASE16(3, B.public_key, CURVE25519_PUBKEY_LEN);
if (onion_skin_ntor_create(node_id, &B, &state, msg)<0) {
fprintf(stderr, "handshake failed");
return 2;
}
base16_encode(buf, sizeof(buf), (const char*)msg, sizeof(msg));
printf("%s\n", buf);
base16_encode(buf, sizeof(buf), (void*)state, sizeof(*state));
printf("%s\n", buf);
ntor_handshake_state_free(state);
return 0;
}
static int
server1(int argc, char **argv)
{
uint8_t msg_in[NTOR_ONIONSKIN_LEN];
curve25519_keypair_t kp;
di_digest256_map_t *keymap=NULL;
uint8_t node_id[DIGEST_LEN];
int keybytes;
uint8_t msg_out[NTOR_REPLY_LEN];
uint8_t *keys;
char *hexkeys;
char buf[256];
/* server1: b nodeID msg N -> msg keys */
N_ARGS(6);
BASE16(2, kp.seckey.secret_key, CURVE25519_SECKEY_LEN);
BASE16(3, node_id, DIGEST_LEN);
BASE16(4, msg_in, NTOR_ONIONSKIN_LEN);
INT(5, keybytes);
curve25519_public_key_generate(&kp.pubkey, &kp.seckey);
dimap_add_entry(&keymap, kp.pubkey.public_key, &kp);
keys = tor_malloc(keybytes);
hexkeys = tor_malloc(keybytes*2+1);
if (onion_skin_ntor_server_handshake(
msg_in, keymap, NULL, node_id, msg_out, keys,
(size_t)keybytes)<0) {
fprintf(stderr, "handshake failed");
return 2;
}
base16_encode(buf, sizeof(buf), (const char*)msg_out, sizeof(msg_out));
printf("%s\n", buf);
base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
printf("%s\n", hexkeys);
tor_free(keys);
tor_free(hexkeys);
return 0;
}
static int
client2(int argc, char **argv)
{
struct ntor_handshake_state_t state;
uint8_t msg[NTOR_REPLY_LEN];
int keybytes;
uint8_t *keys;
char *hexkeys;
N_ARGS(5);
BASE16(2, (&state), sizeof(state));
BASE16(3, msg, sizeof(msg));
INT(4, keybytes);
keys = tor_malloc(keybytes);
hexkeys = tor_malloc(keybytes*2+1);
if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes)<0) {
fprintf(stderr, "handshake failed");
return 2;
}
base16_encode(hexkeys, keybytes*2+1, (const char*)keys, keybytes);
printf("%s\n", hexkeys);
tor_free(keys);
tor_free(hexkeys);
return 0;
}
int
main(int argc, char **argv)
{
/*
client1: nodeID B -> msg state
server1: b nodeID msg N -> msg keys
client2: state msg N -> keys
*/
if (argc < 2) {
fprintf(stderr, "I need arguments. Read source for more info.\n");
return 1;
} else if (!strcmp(argv[1], "client1")) {
return client1(argc, argv);
} else if (!strcmp(argv[1], "server1")) {
return server1(argc, argv);
} else if (!strcmp(argv[1], "client2")) {
return client2(argc, argv);
} else {
fprintf(stderr, "What's a %s?\n", argv[1]);
return 1;
}
}
+10
View File
@@ -2843,6 +2843,16 @@ test_util_di_ops(void)
test_eq(neq1, !eq1);
}
tt_int_op(1, ==, safe_mem_is_zero("", 0));
tt_int_op(1, ==, safe_mem_is_zero("", 1));
tt_int_op(0, ==, safe_mem_is_zero("a", 1));
tt_int_op(0, ==, safe_mem_is_zero("a", 2));
tt_int_op(0, ==, safe_mem_is_zero("\0a", 2));
tt_int_op(1, ==, safe_mem_is_zero("\0\0a", 2));
tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8));
tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8));
tt_int_op(0, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9));
done:
;
}