tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 213394 discussions

[obfsproxy/master] This commit attempts to abstract the whole obfsproxy thing.
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit 6575674cda96198692d610d90512ee939e2fc733
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Thu Feb 24 17:21:19 2011 +0100
This commit attempts to abstract the whole obfsproxy thing.
This is an ugly commit.
What happened?
* Changed function names of crypt_protocol.c to brl_* instead of proto_*.
* Introduced a generic protocol_t struct with some operations that can be
considered generic. It's function pointer design practically works, but shouldn't
be quite right. I suck in C OO design.
* crypt_protocol.c module initializes it's protocol_t structure with new_brl().
* A module.c:set_up_module() was introduced that is called from network.c and
initializes the obfsproxy based on the active module.
* Changed a couple of names in network.c, as well.
* Disabled appropriate unit tests.
Of course everything is just a dirty little PoC and is to be changed, but like I
said I had some innocent fun.
Enjoy.
---
Makefile.am | 4 ++-
src/crypt_protocol.c | 42 ++++++++++++++++++++++------------
src/crypt_protocol.h | 19 +++++++++------
src/main.c | 10 ++------
src/module.c | 31 ++++++++++++++++++++++++++
src/module.h | 29 ++++++++++++++++++++++++
src/network.c | 50 ++++++++++++++++++++++++++++++-----------
src/network.h | 9 +++++--
src/test/unittest.c | 2 +-
src/test/unittest_protocol.c | 2 +
10 files changed, 149 insertions(+), 49 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 7b1bac6..430fd13 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
-CFLAGS = -g -Wall -O2 -Werror @libevent_CFLAGS@ @openssl_CFLAGS@
+CFLAGS = -DDEBUG -g -Wall -O2 -Werror @libevent_CFLAGS@ @openssl_CFLAGS@
bin_PROGRAMS = obfsproxy
@@ -10,6 +10,7 @@ noinst_PROGRAMS = unittests
libobfsproxy_a_SOURCES = \
src/crypt.c \
src/crypt_protocol.c \
+ src/module.c \
src/network.c \
src/socks.c \
src/util.c
@@ -30,6 +31,7 @@ unittests_LDADD = @libevent_LIBS@ @openssl_LIBS@ libobfsproxy.a
noinst_HEADERS = \
src/crypt_protocol.h \
src/crypt.h \
+ src/module.h \
src/network.h \
src/socks.h \
src/util.h \
diff --git a/src/crypt_protocol.c b/src/crypt_protocol.c
index f499fbe..ce81a33 100644
--- a/src/crypt_protocol.c
+++ b/src/crypt_protocol.c
@@ -18,6 +18,18 @@
#include "crypt.h"
#include "crypt_protocol.h"
#include "util.h"
+#include "module.h"
+
+void *
+new_brl(struct protocol_t *proto_struct) {
+ proto_struct->destroy = (void *)brl_state_free;
+ proto_struct->init = (void *)brl_state_new;
+ proto_struct->handshake = (void *)brl_send_initial_message;
+ proto_struct->send = (void *)brl_send;
+ proto_struct->recv = (void *)brl_recv;
+
+ return NULL;
+}
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
static int
@@ -31,7 +43,7 @@ seed_nonzero(const uchar *seed)
'state'. Returns NULL on failure.
*/
static crypt_t *
-derive_key(protocol_state_t *state, const char *keytype)
+derive_key(brl_state_t *state, const char *keytype)
{
crypt_t *cryptstate;
uchar buf[32];
@@ -53,7 +65,7 @@ derive_key(protocol_state_t *state, const char *keytype)
}
static crypt_t *
-derive_padding_key(protocol_state_t *state, const uchar *seed,
+derive_padding_key(brl_state_t *state, const uchar *seed,
const char *keytype)
{
crypt_t *cryptstate;
@@ -78,18 +90,18 @@ derive_padding_key(protocol_state_t *state, const uchar *seed,
we're the handshake initiator. Otherwise, we're the responder. Return
NULL on failure.
*/
-protocol_state_t *
-protocol_state_new(int initiator)
+brl_state_t *
+brl_state_new(int *initiator)
{
- protocol_state_t *state = calloc(1, sizeof(protocol_state_t));
+ brl_state_t *state = calloc(1, sizeof(brl_state_t));
uchar *seed;
const char *send_pad_type;
if (!state)
return NULL;
state->state = ST_WAIT_FOR_KEY;
- state->we_are_initiator = initiator;
- if (initiator) {
+ state->we_are_initiator = *initiator;
+ if (*initiator) {
send_pad_type = INITIATOR_PAD_TYPE;
seed = state->initiator_seed;
} else {
@@ -115,7 +127,7 @@ protocol_state_new(int initiator)
/** Set the shared secret to be used with this protocol state. */
void
-protocol_state_set_shared_secret(protocol_state_t *state,
+brl_state_set_shared_secret(brl_state_t *state,
const char *secret, size_t secretlen)
{
if (secretlen > SHARED_SECRET_LENGTH)
@@ -128,7 +140,7 @@ protocol_state_set_shared_secret(protocol_state_t *state,
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
int
-proto_send_initial_message(protocol_state_t *state, struct evbuffer *buf)
+brl_send_initial_message(brl_state_t *state, struct evbuffer *buf)
{
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
@@ -193,8 +205,8 @@ crypt_and_transmit(crypt_t *crypto,
using the state in 'state'. Returns 0 on success, -1 on failure.
*/
int
-proto_send(protocol_state_t *state,
- struct evbuffer *source, struct evbuffer *dest)
+brl_send(brl_state_t *state,
+ struct evbuffer *source, struct evbuffer *dest)
{
if (state->send_crypto) {
/* Our crypto is set up; just relay the bytes */
@@ -216,7 +228,7 @@ proto_send(protocol_state_t *state,
keys. Returns 0 on success, -1 on failure.
*/
static int
-init_crypto(protocol_state_t *state)
+init_crypto(brl_state_t *state)
{
const char *send_keytype;
const char *recv_keytype;
@@ -253,7 +265,7 @@ init_crypto(protocol_state_t *state)
* Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
* for "fail, close" */
int
-proto_recv(protocol_state_t *state, struct evbuffer *source,
+brl_recv(brl_state_t *state, struct evbuffer *source,
struct evbuffer *dest)
{
if (state->state == ST_WAIT_FOR_KEY) {
@@ -330,7 +342,7 @@ proto_recv(protocol_state_t *state, struct evbuffer *source,
}
void
-protocol_state_free(protocol_state_t *s)
+brl_state_free(brl_state_t *s)
{
if (s->send_crypto)
crypt_free(s->send_crypto);
@@ -342,6 +354,6 @@ protocol_state_free(protocol_state_t *s)
crypt_free(s->recv_padding_crypto);
if (s->pending_data_to_send)
evbuffer_free(s->pending_data_to_send);
- memset(s, 0x0a, sizeof(protocol_state_t));
+ memset(s, 0x0a, sizeof(brl_state_t));
free(s);
}
diff --git a/src/crypt_protocol.h b/src/crypt_protocol.h
index b8694d3..e6e76d2 100644
--- a/src/crypt_protocol.h
+++ b/src/crypt_protocol.h
@@ -10,21 +10,24 @@
#include <sys/types.h>
-typedef struct protocol_state_t protocol_state_t;
+typedef struct brl_state_t brl_state_t;
struct evbuffer;
+struct protocol_t;
#define SHARED_SECRET_LENGTH 16
-protocol_state_t *protocol_state_new(int initiator);
-void protocol_state_set_shared_secret(protocol_state_t *state,
+brl_state_t *brl_state_new(int *initiator);
+void brl_state_set_shared_secret(brl_state_t *state,
const char *secret, size_t secretlen);
-void protocol_state_free(protocol_state_t *state);
-int proto_send_initial_message(protocol_state_t *state, struct evbuffer *buf);
-int proto_send(protocol_state_t *state,
+void brl_state_free(brl_state_t *state);
+int brl_send_initial_message(brl_state_t *state, struct evbuffer *buf);
+int brl_send(brl_state_t *state,
struct evbuffer *source, struct evbuffer *dest);
-int proto_recv(protocol_state_t *state, struct evbuffer *source,
+int brl_recv(brl_state_t *state, struct evbuffer *source,
struct evbuffer *dest);
+void *new_brl(struct protocol_t *proto_struct);
+
#ifdef CRYPT_PROTOCOL_PRIVATE
/* ==========
@@ -46,7 +49,7 @@ int proto_recv(protocol_state_t *state, struct evbuffer *source,
#define INITIATOR_SEND_TYPE "Initiator obfuscated data"
#define RESPONDER_SEND_TYPE "Responder obfuscated data"
-struct protocol_state_t {
+struct brl_state_t {
/** Current protocol state. We start out waiting for key information. Then
we have a key and wait for padding to arrive. Finally, we are sending
and receiving bytes on the connection.
diff --git a/src/main.c b/src/main.c
index 07b5bcc..94e8442 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,6 +14,7 @@
#include "crypt.h"
#include "network.h"
#include "util.h"
+#include "module.h"
#ifndef __GNUC__
#define __attribute__(x)
@@ -92,12 +93,6 @@ main(int argc, const char **argv)
sa_target = (struct sockaddr *)&ss_target;
}
- /* Initialize crypto */
- if (initialize_crypto() < 0) {
- fprintf(stderr, "Can't initialize crypto; failing\n");
- return 2;
- }
-
/* Initialize libevent */
base = event_base_new();
if (base == NULL) {
@@ -115,8 +110,9 @@ main(int argc, const char **argv)
sigevent = evsignal_new(base, SIGINT, handle_signal_cb, (void*) base);
/* start an evconnlistener on the appropriate port(s) */
+ /* ASN We hardcode BRL_PROTOCOL for now. */
listener = listener_new(base,
- mode,
+ mode, BRL_PROTOCOL,
(struct sockaddr *)&ss_listen, sl_listen,
sa_target, sl_target,
NULL, 0);
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 0000000..51f91ac
--- /dev/null
+++ b/src/module.c
@@ -0,0 +1,31 @@
+#include "stdlib.h"
+#include "stdio.h"
+
+#include "module.h"
+#include "crypt_protocol.h"
+#include "crypt.h"
+#include "network.h"
+
+/**
+ This function returns a protocol_t structure based on the mode
+ of obfsproxy
+*/
+struct protocol_t *
+set_up_module(int protocol) {
+ struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
+
+ if (protocol == BRL_PROTOCOL) {
+ proto->new = &new_brl;
+ proto->new(proto);
+ printf("Protocol constructed\n");
+
+ if (initialize_crypto() < 0) {
+ fprintf(stderr, "Can't initialize crypto; failing\n");
+ return NULL;
+ }
+ }
+ /* elif { other protocols } */
+
+ return proto;
+}
+
diff --git a/src/module.h b/src/module.h
new file mode 100644
index 0000000..8302acf
--- /dev/null
+++ b/src/module.h
@@ -0,0 +1,29 @@
+#ifndef MODULE_H
+#define MODULE_H
+
+/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
+#define BRL_PROTOCOL 1
+
+struct protocol_t *set_up_module(int protocol);
+
+/* ASN */
+struct protocol_t {
+ /* Constructor: creates the protocol; sets up functions etc. */
+ void *(*new)(struct protocol_t *self);
+ /* Destructor */
+ void (*destroy)(void *arg);
+
+ /* does nessesary initiation steps; like build a proto state etc. */
+ void *(*init)(void *arg);
+
+ /* does handshake. Supposedly all modules have a handshake. */
+ void *(*handshake)(void *state, void *buf);
+ /* send data function */
+ int (*send)(void *state, void *source,
+ void *dest);
+ /* receive data function */
+ int (*recv)(void *state, void *source,
+ void *dest);
+};
+
+#endif
diff --git a/src/network.c b/src/network.c
index 3ac45cf..882d352 100644
--- a/src/network.c
+++ b/src/network.c
@@ -10,6 +10,7 @@
#include "network.h"
#include "util.h"
#include "socks.h"
+#include "module.h"
#include <assert.h>
#include <stdlib.h>
@@ -27,6 +28,7 @@ struct listener_t {
struct evconnlistener *listener;
struct sockaddr_storage target_address;
int target_address_len;
+ struct protocol_t *proto; /* Protocol that this listener can speak. */
int mode;
char shared_secret[SHARED_SECRET_LENGTH];
unsigned int have_shared_secret : 1;
@@ -40,13 +42,15 @@ static void conn_free(conn_t *conn);
static void close_conn_on_flush(struct bufferevent *bev, void *arg);
static void plaintext_read_cb(struct bufferevent *bev, void *arg);
static void socks_read_cb(struct bufferevent *bev, void *arg);
-static void encrypted_read_cb(struct bufferevent *bev, void *arg);
+/* ASN Changed encrypted_read_cb() to obfuscated_read_cb(), it sounds
+ a bit more obfsproxy generic. I still don't like it though. */
+static void obfsucated_read_cb(struct bufferevent *bev, void *arg);
static void input_event_cb(struct bufferevent *bev, short what, void *arg);
static void output_event_cb(struct bufferevent *bev, short what, void *arg);
listener_t *
listener_new(struct event_base *base,
- int mode,
+ int mode, int protocol,
const struct sockaddr *on_address, int on_address_len,
const struct sockaddr *target_address, int target_address_len,
const char *shared_secret, size_t shared_secret_len)
@@ -55,10 +59,18 @@ listener_new(struct event_base *base,
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE;
listener_t *lsn = calloc(1, sizeof(listener_t));
- lsn->mode = mode;
assert(mode == LSN_SIMPLE_CLIENT || mode == LSN_SIMPLE_SERVER ||
mode == LSN_SOCKS_CLIENT);
+ struct protocol_t *proto = set_up_module(protocol);
+ if (!proto) {
+ printf("This is just terrible. We can't even set up a module!Seppuku time!\n");
+ exit(-1);
+ }
+
+ lsn->proto = proto;
+ lsn->mode = mode;
+
if (target_address) {
assert(target_address_len <= sizeof(struct sockaddr_storage));
memcpy(&lsn->target_address, target_address, target_address_len);
@@ -107,7 +119,13 @@ simple_listener_cb(struct evconnlistener *evcl,
dbg(("Got a connection\n"));
conn->mode = lsn->mode;
- conn->proto_state = protocol_state_new(lsn->mode != LSN_SIMPLE_SERVER);
+ conn->proto = lsn->proto;
+
+ /* ASN Is this actually modular. Will all protocols need to init here?
+ I don't think so. I don't know. */
+ int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
+ conn->proto_state = lsn->proto->init(&is_initiator);
+
if (!conn->proto_state)
goto err;
@@ -129,7 +147,7 @@ simple_listener_cb(struct evconnlistener *evcl,
if (conn->mode == LSN_SIMPLE_SERVER) {
bufferevent_setcb(conn->input,
- encrypted_read_cb, NULL, input_event_cb, conn);
+ obfsucated_read_cb, NULL, input_event_cb, conn);
} else if (conn->mode == LSN_SIMPLE_CLIENT) {
bufferevent_setcb(conn->input,
plaintext_read_cb, NULL, input_event_cb, conn);
@@ -153,13 +171,14 @@ simple_listener_cb(struct evconnlistener *evcl,
plaintext_read_cb, NULL, output_event_cb, conn);
else
bufferevent_setcb(conn->output,
- encrypted_read_cb, NULL, output_event_cb, conn);
+ obfsucated_read_cb, NULL, output_event_cb, conn);
/* Queue output right now. */
struct bufferevent *encrypted =
conn->mode == LSN_SIMPLE_SERVER ? conn->input : conn->output;
- if (proto_send_initial_message(conn->proto_state,
- bufferevent_get_output(encrypted))<0)
+ /* ASN Send handshake */
+ if (lsn->proto->handshake(conn->proto_state,
+ bufferevent_get_output(encrypted))<0)
goto err;
if (conn->mode == LSN_SIMPLE_SERVER || conn->mode == LSN_SIMPLE_CLIENT) {
@@ -184,7 +203,7 @@ static void
conn_free(conn_t *conn)
{
if (conn->proto_state)
- protocol_state_free(conn->proto_state);
+ conn->proto->destroy((void *)conn->proto_state);
if (conn->socks_state)
socks_state_free(conn->socks_state);
if (conn->input)
@@ -259,21 +278,21 @@ plaintext_read_cb(struct bufferevent *bev, void *arg)
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on plaintext side\n"));
- if (proto_send(conn->proto_state,
+ if (conn->proto->send(conn->proto_state,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
}
static void
-encrypted_read_cb(struct bufferevent *bev, void *arg)
+obfsucated_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on encrypted side\n"));
- if (proto_recv(conn->proto_state,
+ if (conn->proto->recv(conn->proto_state,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
@@ -309,6 +328,8 @@ input_event_cb(struct bufferevent *bev, short what, void *arg)
assert(bev == conn->input);
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
+ printf("Got error: %s\n",
+ evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
error_or_eof(conn, bev, conn->output);
}
/* XXX we don't expect any other events */
@@ -321,6 +342,8 @@ output_event_cb(struct bufferevent *bev, short what, void *arg)
assert(bev == conn->output);
if (conn->flushing || (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR))) {
+ printf("Got error: %s\n",
+ evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
error_or_eof(conn, bev, conn->input);
return;
}
@@ -341,7 +364,6 @@ output_event_cb(struct bufferevent *bev, short what, void *arg)
}
socks_send_reply(conn->socks_state, bufferevent_get_output(conn->input),
SOCKS5_REP_SUCCESS);
-
/* we sent a socks reply. We can finally move over to being a regular
input bufferevent. */
socks_state_free(conn->socks_state);
@@ -349,7 +371,7 @@ output_event_cb(struct bufferevent *bev, short what, void *arg)
bufferevent_setcb(conn->input,
plaintext_read_cb, NULL, input_event_cb, conn);
if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
- encrypted_read_cb(bev, conn->input);
+ obfsucated_read_cb(bev, conn->input);
}
}
/* XXX we don't expect any other events */
diff --git a/src/network.h b/src/network.h
index 6987bad..048f80c 100644
--- a/src/network.h
+++ b/src/network.h
@@ -13,7 +13,7 @@ typedef struct listener_t *listener;
struct sockaddr;
struct event_base;
struct socks_state_t;
-struct protocol_state_t;
+
#define LSN_SIMPLE_CLIENT 1
#define LSN_SIMPLE_SERVER 2
@@ -24,7 +24,7 @@ struct addrinfo;
listener_t *listener_new(
struct event_base *base,
- int mode,
+ int mode, int protocol,
const struct sockaddr *on_address, int on_address_len,
const struct sockaddr *target_address, int target_address_len,
const char *shared_secret, size_t shared_secret_len);
@@ -33,7 +33,10 @@ void listener_free(listener_t *listener);
#ifdef NETWORK_PRIVATE
typedef struct conn_t {
struct socks_state_t *socks_state;
- struct protocol_state_t *proto_state;
+ void *proto_state; /* ASN Is this correct?
+ Supposedly, it represents a generic proto state. */
+ struct protocol_t *proto; /* ASN Do we like this here? We probably don't.
+ But it's so convenient!! So convenient! */
int mode;
struct bufferevent *input;
struct bufferevent *output;
diff --git a/src/test/unittest.c b/src/test/unittest.c
index 4e1368c..c9c6e17 100644
--- a/src/test/unittest.c
+++ b/src/test/unittest.c
@@ -15,7 +15,7 @@ extern struct testcase_t socks_tests[];
struct testgroup_t groups[] = {
{ "crypt/", crypt_tests },
- { "proto/", protocol_tests },
+ /* { "proto/", protocol_tests }, */
{ "socks/", socks_tests },
END_OF_GROUPS
};
diff --git a/src/test/unittest_protocol.c b/src/test/unittest_protocol.c
index f9bf988..69dff6f 100644
--- a/src/test/unittest_protocol.c
+++ b/src/test/unittest_protocol.c
@@ -1,3 +1,4 @@
+#if 0
/* Copyright 2011 Nick Mathewson
You may do anything with this work that copyright law would normally
@@ -475,3 +476,4 @@ struct testcase_t protocol_tests[] = {
T(wrong_handshake_plength, 0),
END_OF_TESTCASES
};
+#endif
1
0

[obfsproxy/master] * Renamed the OpenSSH obfuscation variant plugin to "obfs2" and moved
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit bff0015cb6aef8cde564c2b3d51f3a9019b25533
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Thu Mar 17 16:09:19 2011 +0100
* Renamed the OpenSSH obfuscation variant plugin to "obfs2" and moved
it to the right place.
* Renamed module.{c,h} to protocol.{c,h}.
* Moved the protocol state inside protocol_t.
---
Makefile.am | 14 +-
src/crypt_protocol.c | 359 ---------------------------------------------
src/crypt_protocol.h | 88 -----------
src/main.c | 2 +-
src/module.c | 31 ----
src/module.h | 29 ----
src/network.c | 24 ++--
src/network.h | 5 +-
src/plugins/obfs2.c | 359 +++++++++++++++++++++++++++++++++++++++++++++
src/plugins/obfs2.h | 88 +++++++++++
src/protocol.c | 31 ++++
src/protocol.h | 32 ++++
src/test/unittest_socks.c | 2 +-
13 files changed, 533 insertions(+), 531 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 430fd13..9376df3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,12 +9,11 @@ noinst_PROGRAMS = unittests
libobfsproxy_a_SOURCES = \
src/crypt.c \
- src/crypt_protocol.c \
- src/module.c \
src/network.c \
+ src/protocol.c \
src/socks.c \
- src/util.c
-
+ src/util.c \
+ src/plugins/obfs2.c
obfsproxy_SOURCES = \
src/main.c
@@ -29,15 +28,14 @@ unittests_SOURCES = \
unittests_LDADD = @libevent_LIBS@ @openssl_LIBS@ libobfsproxy.a
noinst_HEADERS = \
- src/crypt_protocol.h \
src/crypt.h \
- src/module.h \
src/network.h \
+ src/protocol.h \
src/socks.h \
src/util.h \
src/test/tinytest.h \
- src/test/tinytest_macros.h
-
+ src/test/tinytest_macros.h \
+ src/plugins/obfs2.h
EXTRA_DIST = doc/protocol-spec.txt src/sha256.c
diff --git a/autogen.sh b/autogen.sh
old mode 100644
new mode 100755
diff --git a/src/crypt_protocol.c b/src/crypt_protocol.c
deleted file mode 100644
index ce81a33..0000000
--- a/src/crypt_protocol.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <openssl/rand.h>
-#include <event2/buffer.h>
-
-#define CRYPT_PROTOCOL_PRIVATE
-
-#include "crypt.h"
-#include "crypt_protocol.h"
-#include "util.h"
-#include "module.h"
-
-void *
-new_brl(struct protocol_t *proto_struct) {
- proto_struct->destroy = (void *)brl_state_free;
- proto_struct->init = (void *)brl_state_new;
- proto_struct->handshake = (void *)brl_send_initial_message;
- proto_struct->send = (void *)brl_send;
- proto_struct->recv = (void *)brl_recv;
-
- return NULL;
-}
-
-/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
-static int
-seed_nonzero(const uchar *seed)
-{
- return memcmp(seed, OBFUSCATE_ZERO_SEED, OBFUSCATE_SEED_LENGTH) != 0;
-}
-
-/**
- Derive and return key of type 'keytype' from the seeds currently set in
- 'state'. Returns NULL on failure.
- */
-static crypt_t *
-derive_key(brl_state_t *state, const char *keytype)
-{
- crypt_t *cryptstate;
- uchar buf[32];
- digest_t *c = digest_new();
- digest_update(c, (uchar*)keytype, strlen(keytype));
- if (seed_nonzero(state->initiator_seed))
- digest_update(c, state->initiator_seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->responder_seed))
- digest_update(c, state->responder_seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->secret_seed))
- digest_update(c, state->secret_seed, SHARED_SECRET_LENGTH);
- digest_update(c, (uchar*)keytype, strlen(keytype));
- digest_getdigest(c, buf, sizeof(buf));
- cryptstate = crypt_new(buf, 16);
- crypt_set_iv(cryptstate, buf+16, 16);
- memset(buf, 0, sizeof(buf));
- digest_free(c);
- return cryptstate;
-}
-
-static crypt_t *
-derive_padding_key(brl_state_t *state, const uchar *seed,
- const char *keytype)
-{
- crypt_t *cryptstate;
- uchar buf[32];
- digest_t *c = digest_new();
- digest_update(c, (uchar*)keytype, strlen(keytype));
- if (seed_nonzero(seed))
- digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->secret_seed))
- digest_update(c, state->secret_seed, OBFUSCATE_SEED_LENGTH);
- digest_update(c, (uchar*)keytype, strlen(keytype));
- digest_getdigest(c, buf, sizeof(buf));
- cryptstate = crypt_new(buf, 16);
- crypt_set_iv(cryptstate, buf+16, 16);
- memset(buf, 0, 16);
- digest_free(c);
- return cryptstate;
-}
-
-/**
- Return a new object to handle protocol state. If 'initiator' is true,
- we're the handshake initiator. Otherwise, we're the responder. Return
- NULL on failure.
- */
-brl_state_t *
-brl_state_new(int *initiator)
-{
- brl_state_t *state = calloc(1, sizeof(brl_state_t));
- uchar *seed;
- const char *send_pad_type;
-
- if (!state)
- return NULL;
- state->state = ST_WAIT_FOR_KEY;
- state->we_are_initiator = *initiator;
- if (*initiator) {
- send_pad_type = INITIATOR_PAD_TYPE;
- seed = state->initiator_seed;
- } else {
- send_pad_type = RESPONDER_PAD_TYPE;
- seed = state->responder_seed;
- }
-
- /* Generate our seed */
- if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
- free(state);
- return NULL;
- }
-
- /* Derive the key for what we're sending */
- state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
- if (state->send_padding_crypto == NULL) {
- free(state);
- return NULL;
- }
-
- return state;
-}
-
-/** Set the shared secret to be used with this protocol state. */
-void
-brl_state_set_shared_secret(brl_state_t *state,
- const char *secret, size_t secretlen)
-{
- if (secretlen > SHARED_SECRET_LENGTH)
- secretlen = SHARED_SECRET_LENGTH;
- memcpy(state->secret_seed, secret, secretlen);
-}
-
-/**
- Write the initial protocol setup and padding message for 'state' to
- the evbuffer 'buf'. Return 0 on success, -1 on failure.
- */
-int
-brl_send_initial_message(brl_state_t *state, struct evbuffer *buf)
-{
- uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
- uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
- const uchar *seed;
-
- /* We're going to send:
- SEED | E_PAD_KEY( UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN) )
- */
-
- assert(sizeof(magic) == 4);
-
- /* generate padlen */
- if (random_bytes((uchar*)&plength, 4) < 0)
- return -1;
- plength %= OBFUSCATE_MAX_PADDING;
- send_plength = htonl(plength);
-
- if (state->we_are_initiator)
- seed = state->initiator_seed;
- else
- seed = state->responder_seed;
-
- /* Marshal the message, but with no parts encrypted */
- memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
- memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
- if (random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength) < 0)
- return -1;
-
- /* Encrypt it */
- stream_crypt(state->send_padding_crypto,
- msg+OBFUSCATE_SEED_LENGTH, 8+plength);
-
- /* Put it on the buffer */
- evbuffer_add(buf, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- return 0;
-}
-
-/**
- Helper: encrypt every byte from 'source' using the key in 'crypto',
- and write those bytes onto 'dest'. Return 0 on success, -1 on failure.
- */
-static int
-crypt_and_transmit(crypt_t *crypto,
- struct evbuffer *source, struct evbuffer *dest)
-{
- uchar data[1024];
- while (1) {
- int n = evbuffer_remove(source, data, 1024);
- if (n <= 0)
- return 0;
- stream_crypt(crypto, data, n);
- // printf("Message is: %s", data);
- evbuffer_add(dest, data, n);
- dbg(("Processed %d bytes.", n));
- }
-}
-
-/**
- Called when data arrives from the user side and we want to send the
- obfuscated version. Copies and obfuscates data from 'source' into 'dest'
- using the state in 'state'. Returns 0 on success, -1 on failure.
- */
-int
-brl_send(brl_state_t *state,
- struct evbuffer *source, struct evbuffer *dest)
-{
- if (state->send_crypto) {
- /* Our crypto is set up; just relay the bytes */
- return crypt_and_transmit(state->send_crypto, source, dest);
- } else {
- /* Our crypto isn't set up yet, we'll have to queue the data */
- if (evbuffer_get_length(source)) {
- if (! state->pending_data_to_send) {
- state->pending_data_to_send = evbuffer_new();
- }
- evbuffer_add_buffer(state->pending_data_to_send, source);
- }
- return 0;
- }
-}
-
-/**
- Helper: called after reciving our partner's setup message. Initializes all
- keys. Returns 0 on success, -1 on failure.
- */
-static int
-init_crypto(brl_state_t *state)
-{
- const char *send_keytype;
- const char *recv_keytype;
- const char *recv_pad_keytype;
- const uchar *recv_seed;
-
- if (state->we_are_initiator) {
- send_keytype = INITIATOR_SEND_TYPE;
- recv_keytype = RESPONDER_SEND_TYPE;
- recv_pad_keytype = RESPONDER_PAD_TYPE;
- recv_seed = state->responder_seed;
- } else {
- send_keytype = RESPONDER_SEND_TYPE;
- recv_keytype = INITIATOR_SEND_TYPE;
- recv_pad_keytype = INITIATOR_PAD_TYPE;
- recv_seed = state->initiator_seed;
- }
-
- /* Derive all of the keys that depend on our partner's seed */
- state->send_crypto = derive_key(state, send_keytype);
- state->recv_crypto = derive_key(state, recv_keytype);
- state->recv_padding_crypto =
- derive_padding_key(state, recv_seed, recv_pad_keytype);
-
- if (state->send_crypto && state->recv_crypto && state->recv_padding_crypto)
- return 0;
- else
- return -1;
-}
-
-/* Called when we receive data in an evbuffer 'source': deobfuscates that data
- * and writes it to 'dest'.
- *
- * Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
- * for "fail, close" */
-int
-brl_recv(brl_state_t *state, struct evbuffer *source,
- struct evbuffer *dest)
-{
- if (state->state == ST_WAIT_FOR_KEY) {
- /* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
- * so we can learn the partner's seed and padding length */
- uchar buf[OBFUSCATE_SEED_LENGTH+8], *other_seed;
- uint32_t magic, plength;
- if (evbuffer_get_length(source) < OBFUSCATE_SEED_LENGTH+8) {
- /* data not here yet */
- return OBFUSCATE_SEED_LENGTH+8;
- }
- evbuffer_remove(source, buf, OBFUSCATE_SEED_LENGTH+8);
-
- if (state->we_are_initiator)
- other_seed = state->responder_seed;
- else
- other_seed = state->initiator_seed;
-
- memcpy(other_seed, buf, OBFUSCATE_SEED_LENGTH);
-
- /* Now we can set up all the keys from the seed */
- if (init_crypto(state) < 0)
- return -1;
-
- /* Decrypt the next 8 bytes */
- stream_crypt(state->recv_padding_crypto, buf+OBFUSCATE_SEED_LENGTH, 8);
- /* Check the magic number and extract the padding length */
- memcpy(&magic, buf+OBFUSCATE_SEED_LENGTH, 4);
- memcpy(&plength, buf+OBFUSCATE_SEED_LENGTH+4, 4);
- magic = ntohl(magic);
- plength = ntohl(plength);
- if (magic != OBFUSCATE_MAGIC_VALUE)
- return -1;
- if (plength > OBFUSCATE_MAX_PADDING)
- return -1;
-
- /* Send any data that we've been waiting to send */
- if (state->pending_data_to_send) {
- crypt_and_transmit(state->send_crypto, state->pending_data_to_send, dest);
- evbuffer_free(state->pending_data_to_send);
- state->pending_data_to_send = NULL;
- }
-
- /* Now we're waiting for plength bytes of padding */
- state->padding_left_to_read = plength;
- state->state = ST_WAIT_FOR_PADDING;
-
- /* Fall through here: if there is padding data waiting on the buffer, pull
- it off immediately. */
- dbg(("Received key, expecting %d bytes of padding\n", plength));
- }
-
- /* If we're still looking for padding, start pulling off bytes and
- discarding them. */
- while (state->padding_left_to_read) {
- int n = state->padding_left_to_read;
- size_t sourcelen = evbuffer_get_length(source);
- if (!sourcelen)
- return n;
- if ((size_t) n > evbuffer_get_length(source))
- n = evbuffer_get_length(source);
- evbuffer_drain(source, n);
- state->padding_left_to_read -= n;
- dbg(("Received %d bytes of padding; %d left to read\n", n,
- state->padding_left_to_read));
- }
-
- /* Okay; now we're definitely open. Process whatever data we have. */
- state->state = ST_OPEN;
-
- dbg(("Processing %d bytes data onto destination buffer\n",
- (int) evbuffer_get_length(source)));
- return crypt_and_transmit(state->recv_crypto, source, dest);
-}
-
-void
-brl_state_free(brl_state_t *s)
-{
- if (s->send_crypto)
- crypt_free(s->send_crypto);
- if (s->send_padding_crypto)
- crypt_free(s->send_padding_crypto);
- if (s->recv_crypto)
- crypt_free(s->recv_crypto);
- if (s->recv_padding_crypto)
- crypt_free(s->recv_padding_crypto);
- if (s->pending_data_to_send)
- evbuffer_free(s->pending_data_to_send);
- memset(s, 0x0a, sizeof(brl_state_t));
- free(s);
-}
diff --git a/src/crypt_protocol.h b/src/crypt_protocol.h
deleted file mode 100644
index e6e76d2..0000000
--- a/src/crypt_protocol.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#ifndef CRYPT_PROTOCOL_H
-#define CRYPT_PROTOCOL_H
-
-#include <sys/types.h>
-
-typedef struct brl_state_t brl_state_t;
-struct evbuffer;
-struct protocol_t;
-
-#define SHARED_SECRET_LENGTH 16
-
-brl_state_t *brl_state_new(int *initiator);
-void brl_state_set_shared_secret(brl_state_t *state,
- const char *secret, size_t secretlen);
-void brl_state_free(brl_state_t *state);
-int brl_send_initial_message(brl_state_t *state, struct evbuffer *buf);
-int brl_send(brl_state_t *state,
- struct evbuffer *source, struct evbuffer *dest);
-int brl_recv(brl_state_t *state, struct evbuffer *source,
- struct evbuffer *dest);
-
-void *new_brl(struct protocol_t *proto_struct);
-
-
-#ifdef CRYPT_PROTOCOL_PRIVATE
-/* ==========
- These definitions are not part of the crypt_protocol interface.
- They're exposed here so that the unit tests can use them.
- ==========
-*/
-/* from brl's obfuscated-ssh standard. */
-//#define OBFUSCATE_MAGIC_VALUE 0x0BF5CA7E
-
-/* our own, since we break brl's spec */
-#define OBFUSCATE_MAGIC_VALUE 0x2BF5CA7E
-#define OBFUSCATE_SEED_LENGTH 16
-#define OBFUSCATE_MAX_PADDING 8192
-#define OBFUSCATE_ZERO_SEED "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-
-#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
-#define RESPONDER_PAD_TYPE "Responder obfuscation padding"
-#define INITIATOR_SEND_TYPE "Initiator obfuscated data"
-#define RESPONDER_SEND_TYPE "Responder obfuscated data"
-
-struct brl_state_t {
- /** Current protocol state. We start out waiting for key information. Then
- we have a key and wait for padding to arrive. Finally, we are sending
- and receiving bytes on the connection.
- */
- enum {
- ST_WAIT_FOR_KEY,
- ST_WAIT_FOR_PADDING,
- ST_OPEN,
- } state;
- /** Random seed we generated for this stream */
- uchar initiator_seed[OBFUSCATE_SEED_LENGTH];
- /** Random seed the other side generated for this stream */
- uchar responder_seed[OBFUSCATE_SEED_LENGTH];
- /** Shared secret seed value. */
- uchar secret_seed[SHARED_SECRET_LENGTH];
- /** True iff we opened this connection */
- int we_are_initiator;
-
- /** key used to encrypt outgoing data */
- crypt_t *send_crypto;
- /** key used to encrypt outgoing padding */
- crypt_t *send_padding_crypto;
- /** key used to decrypt incoming data */
- crypt_t *recv_crypto;
- /** key used to decrypt incoming padding */
- crypt_t *recv_padding_crypto;
-
- /** Buffer full of data we'll send once the handshake is done. */
- struct evbuffer *pending_data_to_send;
-
- /** Number of padding bytes to read before we get to real data */
- int padding_left_to_read;
-};
-#endif
-
-#endif
diff --git a/src/main.c b/src/main.c
index 94e8442..de5cd61 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
#include "crypt.h"
#include "network.h"
#include "util.h"
-#include "module.h"
+#include "protocol.h"
#ifndef __GNUC__
#define __attribute__(x)
diff --git a/src/module.c b/src/module.c
deleted file mode 100644
index 51f91ac..0000000
--- a/src/module.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "stdlib.h"
-#include "stdio.h"
-
-#include "module.h"
-#include "crypt_protocol.h"
-#include "crypt.h"
-#include "network.h"
-
-/**
- This function returns a protocol_t structure based on the mode
- of obfsproxy
-*/
-struct protocol_t *
-set_up_module(int protocol) {
- struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
-
- if (protocol == BRL_PROTOCOL) {
- proto->new = &new_brl;
- proto->new(proto);
- printf("Protocol constructed\n");
-
- if (initialize_crypto() < 0) {
- fprintf(stderr, "Can't initialize crypto; failing\n");
- return NULL;
- }
- }
- /* elif { other protocols } */
-
- return proto;
-}
-
diff --git a/src/module.h b/src/module.h
deleted file mode 100644
index 8302acf..0000000
--- a/src/module.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef MODULE_H
-#define MODULE_H
-
-/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
-#define BRL_PROTOCOL 1
-
-struct protocol_t *set_up_module(int protocol);
-
-/* ASN */
-struct protocol_t {
- /* Constructor: creates the protocol; sets up functions etc. */
- void *(*new)(struct protocol_t *self);
- /* Destructor */
- void (*destroy)(void *arg);
-
- /* does nessesary initiation steps; like build a proto state etc. */
- void *(*init)(void *arg);
-
- /* does handshake. Supposedly all modules have a handshake. */
- void *(*handshake)(void *state, void *buf);
- /* send data function */
- int (*send)(void *state, void *source,
- void *dest);
- /* receive data function */
- int (*recv)(void *state, void *source,
- void *dest);
-};
-
-#endif
diff --git a/src/network.c b/src/network.c
index 882d352..b6dadd7 100644
--- a/src/network.c
+++ b/src/network.c
@@ -6,11 +6,10 @@
*/
#define NETWORK_PRIVATE
-#include "crypt_protocol.h"
#include "network.h"
#include "util.h"
#include "socks.h"
-#include "module.h"
+#include "protocol.h"
#include <assert.h>
#include <stdlib.h>
@@ -24,6 +23,8 @@
#include <errno.h>
#include <event2/util.h>
+#include "plugins/obfs2.h"
+
struct listener_t {
struct evconnlistener *listener;
struct sockaddr_storage target_address;
@@ -62,9 +63,9 @@ listener_new(struct event_base *base,
assert(mode == LSN_SIMPLE_CLIENT || mode == LSN_SIMPLE_SERVER ||
mode == LSN_SOCKS_CLIENT);
- struct protocol_t *proto = set_up_module(protocol);
+ struct protocol_t *proto = set_up_protocol(protocol);
if (!proto) {
- printf("This is just terrible. We can't even set up a module!Seppuku time!\n");
+ printf("This is just terrible. We can't even set up a protocol! Seppuku time!\n");
exit(-1);
}
@@ -124,9 +125,9 @@ simple_listener_cb(struct evconnlistener *evcl,
/* ASN Is this actually modular. Will all protocols need to init here?
I don't think so. I don't know. */
int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
- conn->proto_state = lsn->proto->init(&is_initiator);
+ conn->proto->state = lsn->proto->init(&is_initiator);
- if (!conn->proto_state)
+ if (!conn->proto->state)
goto err;
if (conn->mode == LSN_SOCKS_CLIENT) {
@@ -176,8 +177,9 @@ simple_listener_cb(struct evconnlistener *evcl,
/* Queue output right now. */
struct bufferevent *encrypted =
conn->mode == LSN_SIMPLE_SERVER ? conn->input : conn->output;
+
/* ASN Send handshake */
- if (lsn->proto->handshake(conn->proto_state,
+ if (lsn->proto->handshake(conn->proto->state,
bufferevent_get_output(encrypted))<0)
goto err;
@@ -202,8 +204,8 @@ simple_listener_cb(struct evconnlistener *evcl,
static void
conn_free(conn_t *conn)
{
- if (conn->proto_state)
- conn->proto->destroy((void *)conn->proto_state);
+ if (conn->proto->state)
+ conn->proto->destroy((void *)conn->proto->state);
if (conn->socks_state)
socks_state_free(conn->socks_state);
if (conn->input)
@@ -278,7 +280,7 @@ plaintext_read_cb(struct bufferevent *bev, void *arg)
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on plaintext side\n"));
- if (conn->proto->send(conn->proto_state,
+ if (conn->proto->send(conn->proto->state,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
@@ -292,7 +294,7 @@ obfsucated_read_cb(struct bufferevent *bev, void *arg)
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on encrypted side\n"));
- if (conn->proto->recv(conn->proto_state,
+ if (conn->proto->recv(conn->proto->state,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
diff --git a/src/network.h b/src/network.h
index 048f80c..619e45f 100644
--- a/src/network.h
+++ b/src/network.h
@@ -8,13 +8,14 @@
#ifndef NETWORK_H
#define NETWORK_H
+#include <stdlib.h>
+
typedef struct listener_t *listener;
struct sockaddr;
struct event_base;
struct socks_state_t;
-
#define LSN_SIMPLE_CLIENT 1
#define LSN_SIMPLE_SERVER 2
#define LSN_SOCKS_CLIENT 3
@@ -33,8 +34,6 @@ void listener_free(listener_t *listener);
#ifdef NETWORK_PRIVATE
typedef struct conn_t {
struct socks_state_t *socks_state;
- void *proto_state; /* ASN Is this correct?
- Supposedly, it represents a generic proto state. */
struct protocol_t *proto; /* ASN Do we like this here? We probably don't.
But it's so convenient!! So convenient! */
int mode;
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
new file mode 100644
index 0000000..90a8528
--- /dev/null
+++ b/src/plugins/obfs2.c
@@ -0,0 +1,359 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <openssl/rand.h>
+#include <event2/buffer.h>
+
+#define CRYPT_PROTOCOL_PRIVATE
+
+#include "../crypt.h"
+#include "obfs2.h"
+#include "../util.h"
+#include "../protocol.h"
+
+void *
+obfs2_new(struct protocol_t *proto_struct) {
+ proto_struct->destroy = (void *)obfs2_state_free;
+ proto_struct->init = (void *)obfs2_state_new;
+ proto_struct->handshake = (void *)obfs2_send_initial_message;
+ proto_struct->send = (void *)obfs2_send;
+ proto_struct->recv = (void *)obfs2_recv;
+
+ return NULL;
+}
+
+/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
+static int
+seed_nonzero(const uchar *seed)
+{
+ return memcmp(seed, OBFUSCATE_ZERO_SEED, OBFUSCATE_SEED_LENGTH) != 0;
+}
+
+/**
+ Derive and return key of type 'keytype' from the seeds currently set in
+ 'state'. Returns NULL on failure.
+ */
+static crypt_t *
+derive_key(obfs2_state_t *state, const char *keytype)
+{
+ crypt_t *cryptstate;
+ uchar buf[32];
+ digest_t *c = digest_new();
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ if (seed_nonzero(state->initiator_seed))
+ digest_update(c, state->initiator_seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->responder_seed))
+ digest_update(c, state->responder_seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->secret_seed))
+ digest_update(c, state->secret_seed, SHARED_SECRET_LENGTH);
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ digest_getdigest(c, buf, sizeof(buf));
+ cryptstate = crypt_new(buf, 16);
+ crypt_set_iv(cryptstate, buf+16, 16);
+ memset(buf, 0, sizeof(buf));
+ digest_free(c);
+ return cryptstate;
+}
+
+static crypt_t *
+derive_padding_key(obfs2_state_t *state, const uchar *seed,
+ const char *keytype)
+{
+ crypt_t *cryptstate;
+ uchar buf[32];
+ digest_t *c = digest_new();
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ if (seed_nonzero(seed))
+ digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->secret_seed))
+ digest_update(c, state->secret_seed, OBFUSCATE_SEED_LENGTH);
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ digest_getdigest(c, buf, sizeof(buf));
+ cryptstate = crypt_new(buf, 16);
+ crypt_set_iv(cryptstate, buf+16, 16);
+ memset(buf, 0, 16);
+ digest_free(c);
+ return cryptstate;
+}
+
+/**
+ Return a new object to handle protocol state. If 'initiator' is true,
+ we're the handshake initiator. Otherwise, we're the responder. Return
+ NULL on failure.
+ */
+obfs2_state_t *
+obfs2_state_new(int *initiator)
+{
+ obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
+ uchar *seed;
+ const char *send_pad_type;
+
+ if (!state)
+ return NULL;
+ state->state = ST_WAIT_FOR_KEY;
+ state->we_are_initiator = *initiator;
+ if (*initiator) {
+ send_pad_type = INITIATOR_PAD_TYPE;
+ seed = state->initiator_seed;
+ } else {
+ send_pad_type = RESPONDER_PAD_TYPE;
+ seed = state->responder_seed;
+ }
+
+ /* Generate our seed */
+ if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
+ free(state);
+ return NULL;
+ }
+
+ /* Derive the key for what we're sending */
+ state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
+ if (state->send_padding_crypto == NULL) {
+ free(state);
+ return NULL;
+ }
+
+ return state;
+}
+
+/** Set the shared secret to be used with this protocol state. */
+void
+obfs2_state_set_shared_secret(obfs2_state_t *state,
+ const char *secret, size_t secretlen)
+{
+ if (secretlen > SHARED_SECRET_LENGTH)
+ secretlen = SHARED_SECRET_LENGTH;
+ memcpy(state->secret_seed, secret, secretlen);
+}
+
+/**
+ Write the initial protocol setup and padding message for 'state' to
+ the evbuffer 'buf'. Return 0 on success, -1 on failure.
+ */
+int
+obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf)
+{
+ uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
+ uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
+ const uchar *seed;
+
+ /* We're going to send:
+ SEED | E_PAD_KEY( UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN) )
+ */
+
+ assert(sizeof(magic) == 4);
+
+ /* generate padlen */
+ if (random_bytes((uchar*)&plength, 4) < 0)
+ return -1;
+ plength %= OBFUSCATE_MAX_PADDING;
+ send_plength = htonl(plength);
+
+ if (state->we_are_initiator)
+ seed = state->initiator_seed;
+ else
+ seed = state->responder_seed;
+
+ /* Marshal the message, but with no parts encrypted */
+ memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
+ if (random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength) < 0)
+ return -1;
+
+ /* Encrypt it */
+ stream_crypt(state->send_padding_crypto,
+ msg+OBFUSCATE_SEED_LENGTH, 8+plength);
+
+ /* Put it on the buffer */
+ evbuffer_add(buf, msg, OBFUSCATE_SEED_LENGTH+8+plength);
+ return 0;
+}
+
+/**
+ Helper: encrypt every byte from 'source' using the key in 'crypto',
+ and write those bytes onto 'dest'. Return 0 on success, -1 on failure.
+ */
+static int
+crypt_and_transmit(crypt_t *crypto,
+ struct evbuffer *source, struct evbuffer *dest)
+{
+ uchar data[1024];
+ while (1) {
+ int n = evbuffer_remove(source, data, 1024);
+ if (n <= 0)
+ return 0;
+ stream_crypt(crypto, data, n);
+ // printf("Message is: %s", data);
+ evbuffer_add(dest, data, n);
+ dbg(("Processed %d bytes.", n));
+ }
+}
+
+/**
+ Called when data arrives from the user side and we want to send the
+ obfuscated version. Copies and obfuscates data from 'source' into 'dest'
+ using the state in 'state'. Returns 0 on success, -1 on failure.
+ */
+int
+obfs2_send(obfs2_state_t *state,
+ struct evbuffer *source, struct evbuffer *dest)
+{
+ if (state->send_crypto) {
+ /* Our crypto is set up; just relay the bytes */
+ return crypt_and_transmit(state->send_crypto, source, dest);
+ } else {
+ /* Our crypto isn't set up yet, we'll have to queue the data */
+ if (evbuffer_get_length(source)) {
+ if (! state->pending_data_to_send) {
+ state->pending_data_to_send = evbuffer_new();
+ }
+ evbuffer_add_buffer(state->pending_data_to_send, source);
+ }
+ return 0;
+ }
+}
+
+/**
+ Helper: called after reciving our partner's setup message. Initializes all
+ keys. Returns 0 on success, -1 on failure.
+ */
+static int
+init_crypto(obfs2_state_t *state)
+{
+ const char *send_keytype;
+ const char *recv_keytype;
+ const char *recv_pad_keytype;
+ const uchar *recv_seed;
+
+ if (state->we_are_initiator) {
+ send_keytype = INITIATOR_SEND_TYPE;
+ recv_keytype = RESPONDER_SEND_TYPE;
+ recv_pad_keytype = RESPONDER_PAD_TYPE;
+ recv_seed = state->responder_seed;
+ } else {
+ send_keytype = RESPONDER_SEND_TYPE;
+ recv_keytype = INITIATOR_SEND_TYPE;
+ recv_pad_keytype = INITIATOR_PAD_TYPE;
+ recv_seed = state->initiator_seed;
+ }
+
+ /* Derive all of the keys that depend on our partner's seed */
+ state->send_crypto = derive_key(state, send_keytype);
+ state->recv_crypto = derive_key(state, recv_keytype);
+ state->recv_padding_crypto =
+ derive_padding_key(state, recv_seed, recv_pad_keytype);
+
+ if (state->send_crypto && state->recv_crypto && state->recv_padding_crypto)
+ return 0;
+ else
+ return -1;
+}
+
+/* Called when we receive data in an evbuffer 'source': deobfuscates that data
+ * and writes it to 'dest'.
+ *
+ * Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
+ * for "fail, close" */
+int
+obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
+ struct evbuffer *dest)
+{
+ if (state->state == ST_WAIT_FOR_KEY) {
+ /* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
+ * so we can learn the partner's seed and padding length */
+ uchar buf[OBFUSCATE_SEED_LENGTH+8], *other_seed;
+ uint32_t magic, plength;
+ if (evbuffer_get_length(source) < OBFUSCATE_SEED_LENGTH+8) {
+ /* data not here yet */
+ return OBFUSCATE_SEED_LENGTH+8;
+ }
+ evbuffer_remove(source, buf, OBFUSCATE_SEED_LENGTH+8);
+
+ if (state->we_are_initiator)
+ other_seed = state->responder_seed;
+ else
+ other_seed = state->initiator_seed;
+
+ memcpy(other_seed, buf, OBFUSCATE_SEED_LENGTH);
+
+ /* Now we can set up all the keys from the seed */
+ if (init_crypto(state) < 0)
+ return -1;
+
+ /* Decrypt the next 8 bytes */
+ stream_crypt(state->recv_padding_crypto, buf+OBFUSCATE_SEED_LENGTH, 8);
+ /* Check the magic number and extract the padding length */
+ memcpy(&magic, buf+OBFUSCATE_SEED_LENGTH, 4);
+ memcpy(&plength, buf+OBFUSCATE_SEED_LENGTH+4, 4);
+ magic = ntohl(magic);
+ plength = ntohl(plength);
+ if (magic != OBFUSCATE_MAGIC_VALUE)
+ return -1;
+ if (plength > OBFUSCATE_MAX_PADDING)
+ return -1;
+
+ /* Send any data that we've been waiting to send */
+ if (state->pending_data_to_send) {
+ crypt_and_transmit(state->send_crypto, state->pending_data_to_send, dest);
+ evbuffer_free(state->pending_data_to_send);
+ state->pending_data_to_send = NULL;
+ }
+
+ /* Now we're waiting for plength bytes of padding */
+ state->padding_left_to_read = plength;
+ state->state = ST_WAIT_FOR_PADDING;
+
+ /* Fall through here: if there is padding data waiting on the buffer, pull
+ it off immediately. */
+ dbg(("Received key, expecting %d bytes of padding\n", plength));
+ }
+
+ /* If we're still looking for padding, start pulling off bytes and
+ discarding them. */
+ while (state->padding_left_to_read) {
+ int n = state->padding_left_to_read;
+ size_t sourcelen = evbuffer_get_length(source);
+ if (!sourcelen)
+ return n;
+ if ((size_t) n > evbuffer_get_length(source))
+ n = evbuffer_get_length(source);
+ evbuffer_drain(source, n);
+ state->padding_left_to_read -= n;
+ dbg(("Received %d bytes of padding; %d left to read\n", n,
+ state->padding_left_to_read));
+ }
+
+ /* Okay; now we're definitely open. Process whatever data we have. */
+ state->state = ST_OPEN;
+
+ dbg(("Processing %d bytes data onto destination buffer\n",
+ (int) evbuffer_get_length(source)));
+ return crypt_and_transmit(state->recv_crypto, source, dest);
+}
+
+void
+obfs2_state_free(obfs2_state_t *s)
+{
+ if (s->send_crypto)
+ crypt_free(s->send_crypto);
+ if (s->send_padding_crypto)
+ crypt_free(s->send_padding_crypto);
+ if (s->recv_crypto)
+ crypt_free(s->recv_crypto);
+ if (s->recv_padding_crypto)
+ crypt_free(s->recv_padding_crypto);
+ if (s->pending_data_to_send)
+ evbuffer_free(s->pending_data_to_send);
+ memset(s, 0x0a, sizeof(obfs2_state_t));
+ free(s);
+}
diff --git a/src/plugins/obfs2.h b/src/plugins/obfs2.h
new file mode 100644
index 0000000..dd0c842
--- /dev/null
+++ b/src/plugins/obfs2.h
@@ -0,0 +1,88 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#ifndef OBFS2_H
+#define OBFS2_H
+
+#include <sys/types.h>
+
+typedef struct obfs2_state_t obfs2_state_t;
+struct evbuffer;
+struct protocol_t;
+
+#define SHARED_SECRET_LENGTH 16
+
+obfs2_state_t *obfs2_state_new(int *initiator);
+void obfs2_state_set_shared_secret(obfs2_state_t *state,
+ const char *secret, size_t secretlen);
+void obfs2_state_free(obfs2_state_t *state);
+int obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf);
+int obfs2_send(obfs2_state_t *state,
+ struct evbuffer *source, struct evbuffer *dest);
+int obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
+ struct evbuffer *dest);
+
+void *obfs2_new(struct protocol_t *proto_struct);
+
+
+#ifdef CRYPT_PROTOCOL_PRIVATE
+/* ==========
+ These definitions are not part of the crypt_protocol interface.
+ They're exposed here so that the unit tests can use them.
+ ==========
+*/
+/* from brl's obfuscated-ssh standard. */
+//#define OBFUSCATE_MAGIC_VALUE 0x0BF5CA7E
+
+/* our own, since we break brl's spec */
+#define OBFUSCATE_MAGIC_VALUE 0x2BF5CA7E
+#define OBFUSCATE_SEED_LENGTH 16
+#define OBFUSCATE_MAX_PADDING 8192
+#define OBFUSCATE_ZERO_SEED "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+
+#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
+#define RESPONDER_PAD_TYPE "Responder obfuscation padding"
+#define INITIATOR_SEND_TYPE "Initiator obfuscated data"
+#define RESPONDER_SEND_TYPE "Responder obfuscated data"
+
+struct obfs2_state_t {
+ /** Current protocol state. We start out waiting for key information. Then
+ we have a key and wait for padding to arrive. Finally, we are sending
+ and receiving bytes on the connection.
+ */
+ enum {
+ ST_WAIT_FOR_KEY,
+ ST_WAIT_FOR_PADDING,
+ ST_OPEN,
+ } state;
+ /** Random seed we generated for this stream */
+ uchar initiator_seed[OBFUSCATE_SEED_LENGTH];
+ /** Random seed the other side generated for this stream */
+ uchar responder_seed[OBFUSCATE_SEED_LENGTH];
+ /** Shared secret seed value. */
+ uchar secret_seed[SHARED_SECRET_LENGTH];
+ /** True iff we opened this connection */
+ int we_are_initiator;
+
+ /** key used to encrypt outgoing data */
+ crypt_t *send_crypto;
+ /** key used to encrypt outgoing padding */
+ crypt_t *send_padding_crypto;
+ /** key used to decrypt incoming data */
+ crypt_t *recv_crypto;
+ /** key used to decrypt incoming padding */
+ crypt_t *recv_padding_crypto;
+
+ /** Buffer full of data we'll send once the handshake is done. */
+ struct evbuffer *pending_data_to_send;
+
+ /** Number of padding bytes to read before we get to real data */
+ int padding_left_to_read;
+};
+#endif
+
+#endif
diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644
index 0000000..c186857
--- /dev/null
+++ b/src/protocol.c
@@ -0,0 +1,31 @@
+#include "stdlib.h"
+#include "stdio.h"
+
+#include "protocol.h"
+#include "crypt.h"
+#include "network.h"
+
+#include "plugins/obfs2.h"
+
+/**
+ This function returns a protocol_t structure based on the mode
+ of obfsproxy
+*/
+struct protocol_t *
+set_up_protocol(int protocol) {
+ struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
+
+ if (protocol == BRL_PROTOCOL) {
+ proto->new = &obfs2_new;
+ proto->new(proto);
+ printf("Protocol constructed\n");
+
+ if (initialize_crypto() < 0) {
+ fprintf(stderr, "Can't initialize crypto; failing\n");
+ return NULL;
+ }
+ }
+ /* elif { other protocols } */
+
+ return proto;
+}
diff --git a/src/protocol.h b/src/protocol.h
new file mode 100644
index 0000000..159f3e3
--- /dev/null
+++ b/src/protocol.h
@@ -0,0 +1,32 @@
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
+#define BRL_PROTOCOL 1
+
+struct protocol_t *set_up_protocol(int protocol);
+
+/* ASN */
+struct protocol_t {
+ /* Constructor: creates the protocol; sets up functions etc. */
+ void *(*new)(struct protocol_t *self);
+ /* Destructor */
+ void (*destroy)(void *arg);
+
+ /* does nessesary initiation steps; like build a proto state etc. */
+ void *(*init)(void *arg);
+
+ /* does handshake. Supposedly all protocols have a handshake. */
+ void *(*handshake)(void *state, void *buf);
+ /* send data function */
+ int (*send)(void *state, void *source,
+ void *dest);
+ /* receive data function */
+ int (*recv)(void *state, void *source,
+ void *dest);
+
+ /* ASN do we need a proto_get_state()? */
+ void *state;
+};
+
+#endif
diff --git a/src/test/unittest_socks.c b/src/test/unittest_socks.c
index 2b4e38a..ec24e5f 100644
--- a/src/test/unittest_socks.c
+++ b/src/test/unittest_socks.c
@@ -11,7 +11,7 @@
#include "../socks.h"
#include "../crypt.h"
#include "../util.h"
-#include "../crypt_protocol.h"
+#include "../plugins/obfs2.h"
static void
test_socks_send_negotiation(void *data)
1
0

[obfsproxy/master] * Abstracted the protocol interface more by adding proto_<operation>() functions.
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit 71eff4394b01cf19c08b7d504574d425199bcd71
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Thu Mar 17 16:41:47 2011 +0100
* Abstracted the protocol interface more by adding proto_<operation>() functions.
---
src/network.c | 17 ++++++++---------
src/protocol.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
src/protocol.h | 15 ++++++++++++---
3 files changed, 66 insertions(+), 14 deletions(-)
diff --git a/src/network.c b/src/network.c
index b6dadd7..9350a61 100644
--- a/src/network.c
+++ b/src/network.c
@@ -122,10 +122,9 @@ simple_listener_cb(struct evconnlistener *evcl,
conn->mode = lsn->mode;
conn->proto = lsn->proto;
- /* ASN Is this actually modular. Will all protocols need to init here?
- I don't think so. I don't know. */
+ /* Will all protocols need to _init() here? Don't think so! */
int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
- conn->proto->state = lsn->proto->init(&is_initiator);
+ conn->proto->state = proto_init(conn->proto, &is_initiator);
if (!conn->proto->state)
goto err;
@@ -178,9 +177,9 @@ simple_listener_cb(struct evconnlistener *evcl,
struct bufferevent *encrypted =
conn->mode == LSN_SIMPLE_SERVER ? conn->input : conn->output;
- /* ASN Send handshake */
- if (lsn->proto->handshake(conn->proto->state,
- bufferevent_get_output(encrypted))<0)
+ /* ASN Will all protocols need to handshake here? Don't think so. */
+ if (proto_handshake(conn->proto,
+ bufferevent_get_output(encrypted))<0)
goto err;
if (conn->mode == LSN_SIMPLE_SERVER || conn->mode == LSN_SIMPLE_CLIENT) {
@@ -205,7 +204,7 @@ static void
conn_free(conn_t *conn)
{
if (conn->proto->state)
- conn->proto->destroy((void *)conn->proto->state);
+ proto_destroy(conn->proto->state);
if (conn->socks_state)
socks_state_free(conn->socks_state);
if (conn->input)
@@ -280,7 +279,7 @@ plaintext_read_cb(struct bufferevent *bev, void *arg)
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on plaintext side\n"));
- if (conn->proto->send(conn->proto->state,
+ if (proto_send(conn->proto,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
@@ -294,7 +293,7 @@ obfsucated_read_cb(struct bufferevent *bev, void *arg)
other = (bev == conn->input) ? conn->output : conn->input;
dbg(("Got data on encrypted side\n"));
- if (conn->proto->recv(conn->proto->state,
+ if (proto_recv(conn->proto,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
conn_free(conn);
diff --git a/src/protocol.c b/src/protocol.c
index c186857..9fda4b0 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -1,5 +1,6 @@
-#include "stdlib.h"
-#include "stdio.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
#include "protocol.h"
#include "crypt.h"
@@ -29,3 +30,46 @@ set_up_protocol(int protocol) {
return proto;
}
+
+void *
+proto_init(struct protocol_t *proto, void *arg) {
+ assert(proto);
+ if (proto->init)
+ return proto->init(arg);
+ else
+ return NULL;
+}
+
+int
+proto_handshake(struct protocol_t *proto, void *buf) {
+ assert(proto);
+ if (proto->handshake)
+ return proto->handshake(proto->state, buf);
+ else
+ return -1;
+}
+
+int
+proto_send(struct protocol_t *proto, void *source, void *dest) {
+ assert(proto);
+ if (proto->send)
+ return proto->send(proto->state, source, dest);
+ else
+ return -1;
+}
+
+int
+proto_recv(struct protocol_t *proto, void *source, void *dest) {
+ assert(proto);
+ if (proto->recv)
+ return proto->recv(proto->state, source, dest);
+ else
+ return -1;
+}
+
+void proto_destroy(struct protocol_t *proto) {
+ assert(proto);
+
+ if (proto->destroy)
+ proto->destroy(proto->state);
+}
diff --git a/src/protocol.h b/src/protocol.h
index 159f3e3..4de5c70 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -5,22 +5,31 @@
#define BRL_PROTOCOL 1
struct protocol_t *set_up_protocol(int protocol);
+void *proto_init(struct protocol_t *proto, void *arg);
+void proto_destroy(struct protocol_t *proto);
+int proto_handshake(struct protocol_t *proto, void *buf);
+int proto_send(struct protocol_t *proto, void *source, void *dest);
+int proto_recv(struct protocol_t *proto, void *source, void *dest);
-/* ASN */
+
+
+/* ASN Why the hell do half of them return int? FIXME */
struct protocol_t {
/* Constructor: creates the protocol; sets up functions etc. */
void *(*new)(struct protocol_t *self);
/* Destructor */
- void (*destroy)(void *arg);
+ void (*destroy)(void *state);
/* does nessesary initiation steps; like build a proto state etc. */
void *(*init)(void *arg);
/* does handshake. Supposedly all protocols have a handshake. */
- void *(*handshake)(void *state, void *buf);
+ int (*handshake)(void *state, void *buf);
+
/* send data function */
int (*send)(void *state, void *source,
void *dest);
+
/* receive data function */
int (*recv)(void *state, void *source,
void *dest);
1
0
commit 5200697b9074178b48083925a7df4f25cc4757ff
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Thu Mar 17 21:44:43 2011 +0100
reviving unittests
---
src/plugins/obfs2.c | 2 +
src/protocol.c | 3 +-
src/test/unittest.c | 2 +-
src/test/unittest_protocol.c | 262 ++++++++++++++++++++----------------------
4 files changed, 131 insertions(+), 138 deletions(-)
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
index 90a8528..c0cdc1e 100644
--- a/src/plugins/obfs2.c
+++ b/src/plugins/obfs2.c
@@ -158,6 +158,8 @@ obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf)
plength %= OBFUSCATE_MAX_PADDING;
send_plength = htonl(plength);
+ printf("death and dest\n");
+
if (state->we_are_initiator)
seed = state->initiator_seed;
else
diff --git a/src/protocol.c b/src/protocol.c
index 9fda4b0..6530fe0 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -19,12 +19,13 @@ set_up_protocol(int protocol) {
if (protocol == BRL_PROTOCOL) {
proto->new = &obfs2_new;
proto->new(proto);
- printf("Protocol constructed\n");
if (initialize_crypto() < 0) {
fprintf(stderr, "Can't initialize crypto; failing\n");
return NULL;
}
+
+ printf("Protocol constructed\n");
}
/* elif { other protocols } */
diff --git a/src/test/unittest.c b/src/test/unittest.c
index c9c6e17..4e1368c 100644
--- a/src/test/unittest.c
+++ b/src/test/unittest.c
@@ -15,7 +15,7 @@ extern struct testcase_t socks_tests[];
struct testgroup_t groups[] = {
{ "crypt/", crypt_tests },
- /* { "proto/", protocol_tests }, */
+ { "proto/", protocol_tests },
{ "socks/", socks_tests },
END_OF_GROUPS
};
diff --git a/src/test/unittest_protocol.c b/src/test/unittest_protocol.c
index 69dff6f..334591c 100644
--- a/src/test/unittest_protocol.c
+++ b/src/test/unittest_protocol.c
@@ -1,4 +1,3 @@
-#if 0
/* Copyright 2011 Nick Mathewson
You may do anything with this work that copyright law would normally
@@ -20,22 +19,31 @@
#define CRYPT_PRIVATE
#include "../crypt.h"
#include "../util.h"
-#include "../crypt_protocol.h"
+#include "../protocol.h"
+#include "../plugins/obfs2.h"
/* Make sure we can successfully set up a protocol state */
static void
test_proto_setup(void *data)
{
- protocol_state_t *proto1, *proto2;
- proto1 = protocol_state_new(1);
- proto2 = protocol_state_new(0);
- tt_assert(proto1);
- tt_assert(proto2);
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
end:
- if (proto1)
- protocol_state_free(proto1);
- if (proto2)
- protocol_state_free(proto2);
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
}
@@ -47,24 +55,33 @@ test_proto_handshake(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- protocol_state_t *client_state, *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ obfs2_state_t *client_state = client_proto->state;
+ obfs2_state_t *server_state = server_proto->state;
/* We create a client handshake message and pass it to output_buffer */
- tt_int_op(0, <=, proto_send_initial_message(client_state, output_buffer)<0);
+ tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
/* We simulate the server receiving and processing the client's handshake message,
by using proto_recv() on the output_buffer */
- tt_int_op(0, <=, proto_recv(server_state, output_buffer, dummy_buffer) <0);
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
/* Now, we create the server's handshake and pass it to output_buffer */
- tt_int_op(0, <=, proto_send_initial_message(server_state, output_buffer)<0);
+ tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
/* We simulate the client receiving and processing the server's handshake */
- tt_int_op(0, <=, proto_recv(client_state, output_buffer, dummy_buffer) <0);
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
/* The handshake is now complete. We should have:
client's send_crypto == server's recv_crypto
@@ -78,10 +95,10 @@ test_proto_handshake(void *data)
sizeof(crypt_t)));
end:
- if (client_state)
- protocol_state_free(client_state);
- if (server_state)
- protocol_state_free(server_state);
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
if (output_buffer)
evbuffer_free(output_buffer);
@@ -97,20 +114,26 @@ test_proto_transfer(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- protocol_state_t *client_state, *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
int n;
struct evbuffer_iovec v[2];
/* Handshake */
- tt_int_op(0, <=, proto_send_initial_message(client_state, output_buffer)<0);
- tt_int_op(0, <=, proto_recv(server_state, output_buffer, dummy_buffer) <0);
- tt_int_op(0, <=, proto_send_initial_message(server_state, output_buffer)<0);
- tt_int_op(0, <=, proto_recv(client_state, output_buffer, dummy_buffer) <0);
+ tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
+ tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
/* End of Handshake */
/* Now let's pass some data around. */
@@ -119,9 +142,9 @@ test_proto_transfer(void *data)
/* client -> server */
evbuffer_add(dummy_buffer, msg1, 54);
- proto_send(client_state, dummy_buffer, output_buffer);
+ proto_send(client_proto, dummy_buffer, output_buffer);
- tt_int_op(0, <=, proto_recv(server_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
n = evbuffer_peek(dummy_buffer, -1, NULL, &v[0], 2);
@@ -134,18 +157,18 @@ test_proto_transfer(void *data)
/* client <- server */
evbuffer_add(dummy_buffer, msg2, 55);
- tt_int_op(0, <=, proto_send(server_state, dummy_buffer, output_buffer));
+ tt_int_op(0, <=, proto_send(server_proto, dummy_buffer, output_buffer));
- tt_int_op(0, <=, proto_recv(client_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
n = evbuffer_peek(dummy_buffer, -1, NULL, &v[1], 2);
tt_int_op(0, ==, strncmp(msg2, v[1].iov_base, 55));
end:
- if (client_state)
- protocol_state_free(client_state);
- if (server_state)
- protocol_state_free(server_state);
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
if (output_buffer)
evbuffer_free(output_buffer);
@@ -166,17 +189,28 @@ test_proto_transfer(void *data)
static void
test_proto_splitted_handshake(void *data)
{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
+
struct evbuffer *output_buffer = NULL;
struct evbuffer *dummy_buffer = NULL;
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- protocol_state_t *client_state;
- protocol_state_t *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
uint32_t plength1, plength1_msg1, plength1_msg2, send_plength1;
@@ -208,7 +242,7 @@ test_proto_splitted_handshake(void *data)
evbuffer_add(output_buffer, msgclient_1, OBFUSCATE_SEED_LENGTH+8+plength1_msg1);
/* Server receives handshake part 1 */
- tt_int_op(0, <=, proto_recv(server_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_PADDING);
@@ -220,7 +254,7 @@ test_proto_splitted_handshake(void *data)
evbuffer_add(output_buffer, msgclient_2, plength1_msg2);
/* Server receives handshake part 2 */
- tt_int_op(0, <=, proto_recv(server_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
tt_assert(server_state->state == ST_OPEN);
@@ -249,7 +283,7 @@ test_proto_splitted_handshake(void *data)
evbuffer_add(output_buffer, msgserver_1, OBFUSCATE_SEED_LENGTH+8);
/* Client receives handshake part 1 */
- tt_int_op(0, <=, proto_recv(client_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
tt_assert(client_state->state == ST_WAIT_FOR_PADDING);
@@ -261,7 +295,7 @@ test_proto_splitted_handshake(void *data)
evbuffer_add(output_buffer, msgserver_2, plength2);
/* Client receives handshake part 2 */
- tt_int_op(0, <=, proto_recv(client_state, output_buffer, dummy_buffer));
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
tt_assert(client_state->state == ST_OPEN);
@@ -278,9 +312,9 @@ test_proto_splitted_handshake(void *data)
end:
if (client_state)
- protocol_state_free(client_state);
+ proto_destroy(client_proto);
if (server_state)
- protocol_state_free(server_state);
+ proto_destroy(server_proto);
if (output_buffer)
evbuffer_free(output_buffer);
@@ -295,17 +329,28 @@ test_proto_splitted_handshake(void *data)
static void
test_proto_wrong_handshake_magic(void *data)
{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
+
struct evbuffer *output_buffer = NULL;
struct evbuffer *dummy_buffer = NULL;
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- protocol_state_t *client_state;
- protocol_state_t *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
uint32_t wrong_magic = 0xD15EA5E;
@@ -328,84 +373,21 @@ test_proto_wrong_handshake_magic(void *data)
evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- tt_int_op(-1, ==, proto_recv(server_state, output_buffer, dummy_buffer));
-
- tt_assert(server_state->state == ST_WAIT_FOR_KEY);
-
- end:
- if (client_state)
- protocol_state_free(client_state);
- if (server_state)
- protocol_state_free(server_state);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-#if 0
-/*
- Erroneous handshake test:
- Normal plength field but actual padding larger than
- OBFUSCATE_MAX_PADDING.
-
- XXXX This won't actually fail. If we send extra padding, it gets treated as
- part of the message. Decrypting it will give odd results, but this protocol
- doesn't actually get you integrity.
-*/
-static void
-test_proto_wrong_handshake_padding(void *data)
-{
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- protocol_state_t *client_state;
- protocol_state_t *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
-
- uchar bigmsg[OBFUSCATE_MAX_PADDING + 1 + OBFUSCATE_SEED_LENGTH + 8];
- uint32_t actual_plength, fake_plength, send_plength;
-
- const uchar *seed;
- seed = client_state->initiator_seed;
- uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
-
- actual_plength = OBFUSCATE_MAX_PADDING + 1U;
- fake_plength = 666U;
- send_plength = htonl(fake_plength);
-
- memcpy(bigmsg, seed, OBFUSCATE_SEED_LENGTH);
- memcpy(bigmsg+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(bigmsg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
- tt_int_op(0, >=, random_bytes(bigmsg+OBFUSCATE_SEED_LENGTH+8, actual_plength));
-
- stream_crypt(client_state->send_padding_crypto,
- bigmsg+OBFUSCATE_SEED_LENGTH, 8+actual_plength);
-
- evbuffer_add(output_buffer, bigmsg, OBFUSCATE_SEED_LENGTH+8+actual_plength);
-
- tt_int_op(-1, ==, proto_recv(server_state, output_buffer, dummy_buffer));
+ tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_KEY);
end:
if (client_state)
- protocol_state_free(client_state);
+ proto_destroy(client_proto);
if (server_state)
- protocol_state_free(server_state);
+ proto_destroy(server_proto);
if (output_buffer)
evbuffer_free(output_buffer);
if (dummy_buffer)
evbuffer_free(dummy_buffer);
}
-#endif
/* Erroneous handshake test:
plength field larger than OBFUSCATE_MAX_PADDING
@@ -413,17 +395,26 @@ test_proto_wrong_handshake_padding(void *data)
static void
test_proto_wrong_handshake_plength(void *data)
{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
struct evbuffer *output_buffer = NULL;
struct evbuffer *dummy_buffer = NULL;
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
-
- protocol_state_t *client_state;
- protocol_state_t *server_state;
- client_state = protocol_state_new(1);
- server_state = protocol_state_new(0);
- tt_assert(client_state);
- tt_assert(server_state);
+
+ struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ int initiator = 1;
+ int no_initiator = 0;
+ client_proto->state = proto_init(client_proto, &initiator);
+ server_proto->state = proto_init(server_proto, &no_initiator);
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8 + 1];
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
@@ -444,15 +435,15 @@ test_proto_wrong_handshake_plength(void *data)
evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- tt_int_op(-1, ==, proto_recv(server_state, output_buffer, dummy_buffer));
+ tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_KEY);
end:
if (client_state)
- protocol_state_free(client_state);
+ proto_destroy(client_proto);
if (server_state)
- protocol_state_free(server_state);
+ proto_destroy(server_proto);
if (output_buffer)
evbuffer_free(output_buffer);
@@ -476,4 +467,3 @@ struct testcase_t protocol_tests[] = {
T(wrong_handshake_plength, 0),
END_OF_TESTCASES
};
-#endif
1
0

[obfsproxy/master] * Moved crypt.{c, h} to the plugins directory, since it's obfs2 stuff.
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit d2f65a45028ba2c2d808b2002babdb1e83ecf92e
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Thu Mar 17 22:21:42 2011 +0100
* Moved crypt.{c,h} to the plugins directory, since it's obfs2 stuff.
* Stripped off dependencies to obfs2 from the obfsproxy code.
---
Makefile.am | 8 +-
src/crypt.c | 206 ------------------------------------------
src/crypt.h | 62 -------------
src/main.c | 1 -
src/network.c | 9 ++-
src/plugins/obfs2.c | 15 +++-
src/plugins/obfs2.h | 2 +-
src/plugins/obfs2_crypt.c | 206 ++++++++++++++++++++++++++++++++++++++++++
src/plugins/obfs2_crypt.h | 62 +++++++++++++
src/protocol.c | 11 +--
src/protocol.h | 2 +-
src/socks.c | 3 +-
src/test/unittest.c | 2 +-
src/test/unittest_crypt.c | 2 +-
src/test/unittest_protocol.c | 2 +-
src/test/unittest_socks.c | 2 +-
16 files changed, 300 insertions(+), 295 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 9376df3..67cd34d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,12 +8,12 @@ noinst_LIBRARIES = libobfsproxy.a
noinst_PROGRAMS = unittests
libobfsproxy_a_SOURCES = \
- src/crypt.c \
src/network.c \
src/protocol.c \
src/socks.c \
src/util.c \
- src/plugins/obfs2.c
+ src/plugins/obfs2.c \
+ src/plugins/obfs2_crypt.c
obfsproxy_SOURCES = \
src/main.c
@@ -28,14 +28,14 @@ unittests_SOURCES = \
unittests_LDADD = @libevent_LIBS@ @openssl_LIBS@ libobfsproxy.a
noinst_HEADERS = \
- src/crypt.h \
src/network.h \
src/protocol.h \
src/socks.h \
src/util.h \
src/test/tinytest.h \
src/test/tinytest_macros.h \
- src/plugins/obfs2.h
+ src/plugins/obfs2.h \
+ src/plugins/obfs2_crypt.h
EXTRA_DIST = doc/protocol-spec.txt src/sha256.c
diff --git a/src/crypt.c b/src/crypt.c
deleted file mode 100644
index 1192364..0000000
--- a/src/crypt.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
-#include <openssl/opensslv.h>
-#include <openssl/aes.h>
-#include <openssl/rand.h>
-#include <openssl/err.h>
-
-#define CRYPT_PRIVATE
-#include "crypt.h"
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090800f
-#define USE_OPENSSL_RANDPOLL 1
-#define USE_OPENSSL_SHA256 1
-#include <openssl/sha.h>
-#else
-#define STMT_BEGIN do {
-#define STMT_END } while (0)
-static void
-set_uint32(void *ptr, uint32_t val)
-{
- memcpy(ptr, &val, 4);
-}
-static uint32_t
-get_uint32(const void *ptr)
-{
- uint32_t val;
- memcpy(&val, ptr, 4);
- return val;
-}
-#define LTC_ARGCHK(x) assert((x))
-#include "sha256.c"
-#endif
-
-int
-initialize_crypto(void)
-{
- ERR_load_crypto_strings();
-
-#ifdef USE_OPENSSL_RANDPOLL
- return RAND_poll() == 1 ? 0 : -1;
-#else
- /* XXX Or maybe fall back to the arc4random implementation in libevent2? */
- {
- char buf[32];
- int fd, n;
- fd = open("/dev/urandom", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return -1;
- }
- n = read(fd, buf, sizeof(buf));
- if (n != sizeof(buf)) {
- close(fd);
- return -1;
- }
- RAND_seed(buf, sizeof(buf));
- close(fd);
- return 0;
- }
-#endif
-}
-
-void
-cleanup_crypto(void)
-{
- ERR_free_strings();
-}
-
-/* =====
- Digests
- ===== */
-
-#ifdef USE_OPENSSL_SHA256
-struct digest_t {
- SHA256_CTX ctx;
-};
-digest_t *
-digest_new(void)
-{
- digest_t *d = malloc(sizeof(digest_t));
- SHA256_Init(&d->ctx);
- return d;
-}
-void
-digest_update(digest_t *d, const uchar *buf, size_t len)
-{
- SHA256_Update(&d->ctx, buf, len);
-}
-size_t
-digest_getdigest(digest_t *d, uchar *buf, size_t len)
-{
- uchar tmp[32];
- int n = 32;
- SHA256_Final(tmp, &d->ctx);
- if (len < 32)
- n = len;
- memcpy(buf, tmp, n);
- memset(tmp, 0, sizeof(tmp));
- return n;
-}
-#else
-struct digest_t {
- sha256_state ctx;
-};
-digest_t *
-digest_new(void)
-{
- digest_t *d = malloc(sizeof(digest_t));
- sha256_init(&d->ctx);
- return d;
-}
-void
-digest_update(digest_t *d, const uchar *buf, size_t len)
-{
- sha256_process(&d->ctx, buf, len);
-}
-size_t
-digest_getdigest(digest_t *d, uchar *buf, size_t len)
-{
- uchar tmp[32];
- int n = 32;
- sha256_done(&d->ctx, tmp);
- if (len < 32)
- n = len;
- memcpy(buf, tmp, n);
- memset(tmp, 0, sizeof(tmp));
- return n;
-}
-#endif
-
-void
-digest_free(digest_t *d)
-{
- memset(d, 0, sizeof(digest_t));
- free(d);
-}
-
-/* =====
- Stream crypto
- ===== */
-
-crypt_t *
-crypt_new(const uchar *key, size_t keylen)
-{
- crypt_t *k;
- if (keylen < AES_BLOCK_SIZE)
- return NULL;
-
- k = calloc(1, sizeof(crypt_t));
- if (k == NULL)
- return NULL;
-
- AES_set_encrypt_key(key, 128, &k->key);
-
- return k;
-}
-void
-crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen)
-{
- assert(ivlen == sizeof(key->ivec));
- memcpy(key->ivec, iv, ivlen);
-}
-void
-stream_crypt(crypt_t *key, uchar *buf, size_t len)
-{
- AES_ctr128_encrypt(buf, buf, /* XXX make sure this is okay to do. */
- len,
- &key->key, key->ivec, key->ecount_buf,
- &key->pos);
-}
-void
-crypt_free(crypt_t *key)
-{
- memset(key, 0, sizeof(key));
- free(key);
-}
-
-/* =====
- PRNG
- ===== */
-
-int
-random_bytes(uchar *buf, size_t buflen)
-{
- return RAND_bytes(buf, buflen) == 1 ? 0 : -1;
-}
diff --git a/src/crypt.h b/src/crypt.h
deleted file mode 100644
index 59876b1..0000000
--- a/src/crypt.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#ifndef CRYPT_H
-#define CRYPT_H
-
-#include <sys/types.h>
-
-/* Stream cipher state */
-typedef struct crypt_t crypt_t;
-/* Digest state */
-typedef struct digest_t digest_t;
-
-typedef unsigned char uchar;
-
-/** Initialize global crypto state. Returrn 0 on success, -1 on failure */
-int initialize_crypto(void);
-/** Clean up global crypto state */
-void cleanup_crypto(void);
-
-/** Return a newly allocated digest state, or NULL on failure. */
-digest_t *digest_new(void);
-/** Add n bytes from b to the digest state. */
-void digest_update(digest_t *, const uchar *b, size_t n);
-/** Get a digest from the digest state. Put it in up the first n bytes of the
-buffer b. Return the number of bytes actually written.*/
-size_t digest_getdigest(digest_t *, uchar *b, size_t n);
-/** Clear and free a digest state */
-void digest_free(digest_t *);
-
-/** Return a new stream cipher state taking key and IV from the data provided.
- * The data length must be exactly 32 */
-crypt_t *crypt_new(const uchar *, size_t);
-void crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen);
-
-/** Encrypt n bytes of data in the buffer b, in place. */
-void stream_crypt(crypt_t *, uchar *b, size_t n);
-/** Clear and free a stream cipher state. */
-void crypt_free(crypt_t *);
-
-/** Set b to contain n random bytes. */
-int random_bytes(uchar *b, size_t n);
-
-#ifdef CRYPT_PRIVATE
-/* ==========
- These definitions are not part of the crypt interface.
- They're exposed here so that the unit tests can use them.
- ==========
-*/
-struct crypt_t {
- AES_KEY key;
- uchar ivec[AES_BLOCK_SIZE];
- uchar ecount_buf[AES_BLOCK_SIZE];
- unsigned int pos;
-};
-#endif
-
-#endif
diff --git a/src/main.c b/src/main.c
index de5cd61..93d5820 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,7 +11,6 @@
#include <signal.h>
#include <event2/event.h>
-#include "crypt.h"
#include "network.h"
#include "util.h"
#include "protocol.h"
diff --git a/src/network.c b/src/network.c
index 9350a61..833b939 100644
--- a/src/network.c
+++ b/src/network.c
@@ -23,16 +23,16 @@
#include <errno.h>
#include <event2/util.h>
-#include "plugins/obfs2.h"
-
struct listener_t {
struct evconnlistener *listener;
struct sockaddr_storage target_address;
int target_address_len;
struct protocol_t *proto; /* Protocol that this listener can speak. */
int mode;
- char shared_secret[SHARED_SECRET_LENGTH];
+ /* ASN */
+ /* char shared_secret[SHARED_SECRET_LENGTH];
unsigned int have_shared_secret : 1;
+ */
};
static void simple_listener_cb(struct evconnlistener *evcl,
@@ -79,11 +79,14 @@ listener_new(struct event_base *base,
} else {
assert(lsn->mode == LSN_SOCKS_CLIENT);
}
+ /* ASN */
+ /*
assert(shared_secret == NULL || shared_secret_len == SHARED_SECRET_LENGTH);
if (shared_secret) {
memcpy(lsn->shared_secret, shared_secret, SHARED_SECRET_LENGTH);
lsn->have_shared_secret = 1;
}
+ */
lsn->listener = evconnlistener_new_bind(base, simple_listener_cb, lsn,
flags,
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
index c0cdc1e..01c74f3 100644
--- a/src/plugins/obfs2.c
+++ b/src/plugins/obfs2.c
@@ -15,12 +15,16 @@
#define CRYPT_PROTOCOL_PRIVATE
-#include "../crypt.h"
+#include "obfs2_crypt.h"
#include "obfs2.h"
#include "../util.h"
#include "../protocol.h"
-void *
+/* Sets the function table for the obfs2 protocol and
+ calls initialize_crypto().
+ Returns 0 on success, -1 on fail.
+*/
+int
obfs2_new(struct protocol_t *proto_struct) {
proto_struct->destroy = (void *)obfs2_state_free;
proto_struct->init = (void *)obfs2_state_new;
@@ -28,7 +32,12 @@ obfs2_new(struct protocol_t *proto_struct) {
proto_struct->send = (void *)obfs2_send;
proto_struct->recv = (void *)obfs2_recv;
- return NULL;
+ if (initialize_crypto() < 0) {
+ fprintf(stderr, "Can't initialize crypto; failing\n");
+ return -1;
+ }
+
+ return 0;
}
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
diff --git a/src/plugins/obfs2.h b/src/plugins/obfs2.h
index dd0c842..2d1d24e 100644
--- a/src/plugins/obfs2.h
+++ b/src/plugins/obfs2.h
@@ -26,7 +26,7 @@ int obfs2_send(obfs2_state_t *state,
int obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
struct evbuffer *dest);
-void *obfs2_new(struct protocol_t *proto_struct);
+int obfs2_new(struct protocol_t *proto_struct);
#ifdef CRYPT_PROTOCOL_PRIVATE
diff --git a/src/plugins/obfs2_crypt.c b/src/plugins/obfs2_crypt.c
new file mode 100644
index 0000000..0121c93
--- /dev/null
+++ b/src/plugins/obfs2_crypt.c
@@ -0,0 +1,206 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <openssl/opensslv.h>
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
+#define CRYPT_PRIVATE
+#include "obfs2_crypt.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800f
+#define USE_OPENSSL_RANDPOLL 1
+#define USE_OPENSSL_SHA256 1
+#include <openssl/sha.h>
+#else
+#define STMT_BEGIN do {
+#define STMT_END } while (0)
+static void
+set_uint32(void *ptr, uint32_t val)
+{
+ memcpy(ptr, &val, 4);
+}
+static uint32_t
+get_uint32(const void *ptr)
+{
+ uint32_t val;
+ memcpy(&val, ptr, 4);
+ return val;
+}
+#define LTC_ARGCHK(x) assert((x))
+#include "sha256.c"
+#endif
+
+int
+initialize_crypto(void)
+{
+ ERR_load_crypto_strings();
+
+#ifdef USE_OPENSSL_RANDPOLL
+ return RAND_poll() == 1 ? 0 : -1;
+#else
+ /* XXX Or maybe fall back to the arc4random implementation in libevent2? */
+ {
+ char buf[32];
+ int fd, n;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return -1;
+ }
+ n = read(fd, buf, sizeof(buf));
+ if (n != sizeof(buf)) {
+ close(fd);
+ return -1;
+ }
+ RAND_seed(buf, sizeof(buf));
+ close(fd);
+ return 0;
+ }
+#endif
+}
+
+void
+cleanup_crypto(void)
+{
+ ERR_free_strings();
+}
+
+/* =====
+ Digests
+ ===== */
+
+#ifdef USE_OPENSSL_SHA256
+struct digest_t {
+ SHA256_CTX ctx;
+};
+digest_t *
+digest_new(void)
+{
+ digest_t *d = malloc(sizeof(digest_t));
+ SHA256_Init(&d->ctx);
+ return d;
+}
+void
+digest_update(digest_t *d, const uchar *buf, size_t len)
+{
+ SHA256_Update(&d->ctx, buf, len);
+}
+size_t
+digest_getdigest(digest_t *d, uchar *buf, size_t len)
+{
+ uchar tmp[32];
+ int n = 32;
+ SHA256_Final(tmp, &d->ctx);
+ if (len < 32)
+ n = len;
+ memcpy(buf, tmp, n);
+ memset(tmp, 0, sizeof(tmp));
+ return n;
+}
+#else
+struct digest_t {
+ sha256_state ctx;
+};
+digest_t *
+digest_new(void)
+{
+ digest_t *d = malloc(sizeof(digest_t));
+ sha256_init(&d->ctx);
+ return d;
+}
+void
+digest_update(digest_t *d, const uchar *buf, size_t len)
+{
+ sha256_process(&d->ctx, buf, len);
+}
+size_t
+digest_getdigest(digest_t *d, uchar *buf, size_t len)
+{
+ uchar tmp[32];
+ int n = 32;
+ sha256_done(&d->ctx, tmp);
+ if (len < 32)
+ n = len;
+ memcpy(buf, tmp, n);
+ memset(tmp, 0, sizeof(tmp));
+ return n;
+}
+#endif
+
+void
+digest_free(digest_t *d)
+{
+ memset(d, 0, sizeof(digest_t));
+ free(d);
+}
+
+/* =====
+ Stream crypto
+ ===== */
+
+crypt_t *
+crypt_new(const uchar *key, size_t keylen)
+{
+ crypt_t *k;
+ if (keylen < AES_BLOCK_SIZE)
+ return NULL;
+
+ k = calloc(1, sizeof(crypt_t));
+ if (k == NULL)
+ return NULL;
+
+ AES_set_encrypt_key(key, 128, &k->key);
+
+ return k;
+}
+void
+crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen)
+{
+ assert(ivlen == sizeof(key->ivec));
+ memcpy(key->ivec, iv, ivlen);
+}
+void
+stream_crypt(crypt_t *key, uchar *buf, size_t len)
+{
+ AES_ctr128_encrypt(buf, buf, /* XXX make sure this is okay to do. */
+ len,
+ &key->key, key->ivec, key->ecount_buf,
+ &key->pos);
+}
+void
+crypt_free(crypt_t *key)
+{
+ memset(key, 0, sizeof(key));
+ free(key);
+}
+
+/* =====
+ PRNG
+ ===== */
+
+int
+random_bytes(uchar *buf, size_t buflen)
+{
+ return RAND_bytes(buf, buflen) == 1 ? 0 : -1;
+}
diff --git a/src/plugins/obfs2_crypt.h b/src/plugins/obfs2_crypt.h
new file mode 100644
index 0000000..c9841d8
--- /dev/null
+++ b/src/plugins/obfs2_crypt.h
@@ -0,0 +1,62 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#ifndef OBFS2_CRYPT_H
+#define OBFS2_CRYPT_H
+
+#include <sys/types.h>
+
+/* Stream cipher state */
+typedef struct crypt_t crypt_t;
+/* Digest state */
+typedef struct digest_t digest_t;
+
+typedef unsigned char uchar;
+
+/** Initialize global crypto state. Returrn 0 on success, -1 on failure */
+int initialize_crypto(void);
+/** Clean up global crypto state */
+void cleanup_crypto(void);
+
+/** Return a newly allocated digest state, or NULL on failure. */
+digest_t *digest_new(void);
+/** Add n bytes from b to the digest state. */
+void digest_update(digest_t *, const uchar *b, size_t n);
+/** Get a digest from the digest state. Put it in up the first n bytes of the
+buffer b. Return the number of bytes actually written.*/
+size_t digest_getdigest(digest_t *, uchar *b, size_t n);
+/** Clear and free a digest state */
+void digest_free(digest_t *);
+
+/** Return a new stream cipher state taking key and IV from the data provided.
+ * The data length must be exactly 32 */
+crypt_t *crypt_new(const uchar *, size_t);
+void crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen);
+
+/** Encrypt n bytes of data in the buffer b, in place. */
+void stream_crypt(crypt_t *, uchar *b, size_t n);
+/** Clear and free a stream cipher state. */
+void crypt_free(crypt_t *);
+
+/** Set b to contain n random bytes. */
+int random_bytes(uchar *b, size_t n);
+
+#ifdef CRYPT_PRIVATE
+/* ==========
+ These definitions are not part of the crypt interface.
+ They're exposed here so that the unit tests can use them.
+ ==========
+*/
+struct crypt_t {
+ AES_KEY key;
+ uchar ivec[AES_BLOCK_SIZE];
+ uchar ecount_buf[AES_BLOCK_SIZE];
+ unsigned int pos;
+};
+#endif
+
+#endif
diff --git a/src/protocol.c b/src/protocol.c
index 6530fe0..6df93ca 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -3,7 +3,6 @@
#include <assert.h>
#include "protocol.h"
-#include "crypt.h"
#include "network.h"
#include "plugins/obfs2.h"
@@ -18,14 +17,8 @@ set_up_protocol(int protocol) {
if (protocol == BRL_PROTOCOL) {
proto->new = &obfs2_new;
- proto->new(proto);
-
- if (initialize_crypto() < 0) {
- fprintf(stderr, "Can't initialize crypto; failing\n");
- return NULL;
- }
-
- printf("Protocol constructed\n");
+ if (proto->new(proto))
+ printf("Protocol constructed\n");
}
/* elif { other protocols } */
diff --git a/src/protocol.h b/src/protocol.h
index 4de5c70..9e58ea8 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -16,7 +16,7 @@ int proto_recv(struct protocol_t *proto, void *source, void *dest);
/* ASN Why the hell do half of them return int? FIXME */
struct protocol_t {
/* Constructor: creates the protocol; sets up functions etc. */
- void *(*new)(struct protocol_t *self);
+ int (*new)(struct protocol_t *self);
/* Destructor */
void (*destroy)(void *state);
diff --git a/src/socks.c b/src/socks.c
index 13bc391..8f432e1 100644
--- a/src/socks.c
+++ b/src/socks.c
@@ -9,7 +9,6 @@
#define SOCKS_PRIVATE
#include "socks.h"
-#include "crypt.h"
#include "util.h"
#include <event2/buffer.h>
@@ -40,6 +39,8 @@
static int socks5_do_negotiation(struct evbuffer *dest,
unsigned int neg_was_success);
+typedef unsigned char uchar;
+
socks_state_t *
socks_state_new(void)
{
diff --git a/src/test/unittest.c b/src/test/unittest.c
index 4e1368c..494e90b 100644
--- a/src/test/unittest.c
+++ b/src/test/unittest.c
@@ -7,7 +7,7 @@
#include <stdlib.h>
#include "tinytest.h"
-#include "../crypt.h"
+#include "../plugins/obfs2_crypt.h"
extern struct testcase_t crypt_tests[];
extern struct testcase_t protocol_tests[];
diff --git a/src/test/unittest_crypt.c b/src/test/unittest_crypt.c
index f2822fe..b624e15 100644
--- a/src/test/unittest_crypt.c
+++ b/src/test/unittest_crypt.c
@@ -12,7 +12,7 @@
#include <openssl/aes.h>
-#include "../crypt.h"
+#include "../plugins/obfs2_crypt.h"
struct crypt_t {
AES_KEY key;
diff --git a/src/test/unittest_protocol.c b/src/test/unittest_protocol.c
index 334591c..ceb666d 100644
--- a/src/test/unittest_protocol.c
+++ b/src/test/unittest_protocol.c
@@ -17,7 +17,7 @@
#define CRYPT_PROTOCOL_PRIVATE
#define CRYPT_PRIVATE
-#include "../crypt.h"
+#include "../plugins/obfs2_crypt.h"
#include "../util.h"
#include "../protocol.h"
#include "../plugins/obfs2.h"
diff --git a/src/test/unittest_socks.c b/src/test/unittest_socks.c
index ec24e5f..db91188 100644
--- a/src/test/unittest_socks.c
+++ b/src/test/unittest_socks.c
@@ -9,7 +9,7 @@
#define SOCKS_PRIVATE
#include "../socks.h"
-#include "../crypt.h"
+#include "../plugins/obfs2_crypt.h"
#include "../util.h"
#include "../plugins/obfs2.h"
1
0

[obfsproxy/master] Added dummy plugin. A plugin that just leaves data pass by.
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit f3f7d7d00e92835fc0db3e7731147898c46480e2
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Wed Mar 23 19:31:09 2011 +0100
Added dummy plugin. A plugin that just leaves data pass by.
---
Makefile.am | 6 +++-
src/main.c | 24 +++++++++++-----
src/network.c | 15 +++++-----
src/plugins/dummy.c | 61 ++++++++++++++++++++++++++++++++++++++++++
src/plugins/dummy.h | 21 ++++++++++++++
src/plugins/obfs2.c | 4 +--
src/protocol.c | 18 +++++++-----
src/protocol.h | 4 ++-
src/socks.c | 9 ++++--
src/test/unittest_protocol.c | 24 ++++++++--------
10 files changed, 143 insertions(+), 43 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 67cd34d..32d5c05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,8 @@ libobfsproxy_a_SOURCES = \
src/socks.c \
src/util.c \
src/plugins/obfs2.c \
- src/plugins/obfs2_crypt.c
+ src/plugins/obfs2_crypt.c \
+ src/plugins/dummy.c
obfsproxy_SOURCES = \
src/main.c
@@ -35,7 +36,8 @@ noinst_HEADERS = \
src/test/tinytest.h \
src/test/tinytest_macros.h \
src/plugins/obfs2.h \
- src/plugins/obfs2_crypt.h
+ src/plugins/obfs2_crypt.h \
+ src/plugins/dummy.h
EXTRA_DIST = doc/protocol-spec.txt src/sha256.c
diff --git a/src/main.c b/src/main.c
index 93d5820..4f29005 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,7 +25,7 @@ static void
usage(void)
{
fprintf(stderr,
- "Usage: obfsproxy {client/server/socks} listenaddr[:port] targetaddr:port\n"
+ "Usage: obfsproxy {client/server/socks} {obfs2/dummy} listenaddr[:port] targetaddr:port\n"
" (Default listen port is 48988 for client; 23548 for socks; 11253 for server)\n"
);
exit(1);
@@ -43,6 +43,7 @@ handle_signal_cb(evutil_socket_t fd, short what, void *arg)
int
main(int argc, const char **argv)
{
+ int protocol;
int is_client, is_socks = 0, mode;
struct sockaddr_storage ss_listen, ss_target;
struct sockaddr *sa_target=NULL;
@@ -54,7 +55,7 @@ main(int argc, const char **argv)
listener_t *listener;
/* XXXXX the interface is crap. Fix that. XXXXX */
- if (argc < 3)
+ if (argc < 4)
usage();
if (!strcmp(argv[1], "client")) {
is_client = 1;
@@ -73,21 +74,28 @@ main(int argc, const char **argv)
usage();
}
+ if (!strcmp(argv[2], "obfs2"))
+ protocol = OBFS2_PROTOCOL;
+ else if (!strcmp(argv[2], "dummy"))
+ protocol = DUMMY_PROTOCOL;
+ else
+ usage();
+
/* figure out what port(s) to listen on as client/server */
- if (resolve_address_port(argv[2], 1, 1, &ss_listen, &sl_listen, defport) < 0)
+ if (resolve_address_port(argv[3], 1, 1, &ss_listen, &sl_listen, defport) < 0)
usage();
if (is_socks) {
- if (argc != 3)
+ if (argc != 4)
usage();
} else {
- if (argc != 4)
+ if (argc != 5)
usage();
/* figure out what place to connect to as a client/server. */
/* XXXX when we add socks support, clients will not have a fixed "target"
* XXXX address but will instead connect to a client-selected address. */
- if (resolve_address_port(argv[3], 1, 0, &ss_target, &sl_target, NULL) < 0)
+ if (resolve_address_port(argv[4], 1, 0, &ss_target, &sl_target, NULL) < 0)
usage();
sa_target = (struct sockaddr *)&ss_target;
}
@@ -109,9 +117,9 @@ main(int argc, const char **argv)
sigevent = evsignal_new(base, SIGINT, handle_signal_cb, (void*) base);
/* start an evconnlistener on the appropriate port(s) */
- /* ASN We hardcode BRL_PROTOCOL for now. */
+ /* ASN We hardcode OBFS2_PROTOCOL for now. */
listener = listener_new(base,
- mode, BRL_PROTOCOL,
+ mode, protocol,
(struct sockaddr *)&ss_listen, sl_listen,
sa_target, sl_target,
NULL, 0);
diff --git a/src/network.c b/src/network.c
index 833b939..3e23cdc 100644
--- a/src/network.c
+++ b/src/network.c
@@ -45,7 +45,7 @@ static void plaintext_read_cb(struct bufferevent *bev, void *arg);
static void socks_read_cb(struct bufferevent *bev, void *arg);
/* ASN Changed encrypted_read_cb() to obfuscated_read_cb(), it sounds
a bit more obfsproxy generic. I still don't like it though. */
-static void obfsucated_read_cb(struct bufferevent *bev, void *arg);
+static void obfuscated_read_cb(struct bufferevent *bev, void *arg);
static void input_event_cb(struct bufferevent *bev, short what, void *arg);
static void output_event_cb(struct bufferevent *bev, short what, void *arg);
@@ -129,6 +129,7 @@ simple_listener_cb(struct evconnlistener *evcl,
int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
conn->proto->state = proto_init(conn->proto, &is_initiator);
+ /* ASN Which means that all plugins need a state... */
if (!conn->proto->state)
goto err;
@@ -150,7 +151,7 @@ simple_listener_cb(struct evconnlistener *evcl,
if (conn->mode == LSN_SIMPLE_SERVER) {
bufferevent_setcb(conn->input,
- obfsucated_read_cb, NULL, input_event_cb, conn);
+ obfuscated_read_cb, NULL, input_event_cb, conn);
} else if (conn->mode == LSN_SIMPLE_CLIENT) {
bufferevent_setcb(conn->input,
plaintext_read_cb, NULL, input_event_cb, conn);
@@ -174,7 +175,7 @@ simple_listener_cb(struct evconnlistener *evcl,
plaintext_read_cb, NULL, output_event_cb, conn);
else
bufferevent_setcb(conn->output,
- obfsucated_read_cb, NULL, output_event_cb, conn);
+ obfuscated_read_cb, NULL, output_event_cb, conn);
/* Queue output right now. */
struct bufferevent *encrypted =
@@ -206,8 +207,8 @@ simple_listener_cb(struct evconnlistener *evcl,
static void
conn_free(conn_t *conn)
{
- if (conn->proto->state)
- proto_destroy(conn->proto->state);
+ if (conn->proto)
+ proto_destroy(conn->proto);
if (conn->socks_state)
socks_state_free(conn->socks_state);
if (conn->input)
@@ -289,7 +290,7 @@ plaintext_read_cb(struct bufferevent *bev, void *arg)
}
static void
-obfsucated_read_cb(struct bufferevent *bev, void *arg)
+obfuscated_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
@@ -375,7 +376,7 @@ output_event_cb(struct bufferevent *bev, short what, void *arg)
bufferevent_setcb(conn->input,
plaintext_read_cb, NULL, input_event_cb, conn);
if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
- obfsucated_read_cb(bev, conn->input);
+ obfuscated_read_cb(bev, conn->input);
}
}
/* XXX we don't expect any other events */
diff --git a/src/plugins/dummy.c b/src/plugins/dummy.c
new file mode 100644
index 0000000..957c30b
--- /dev/null
+++ b/src/plugins/dummy.c
@@ -0,0 +1,61 @@
+/* Copyright 2011 Princess Peach Toadstool
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <unistd.h>
+
+#include <openssl/rand.h>
+#include <event2/buffer.h>
+
+#include "dummy.h"
+#include "../util.h"
+#include "../protocol.h"
+
+int
+dummy_new(struct protocol_t *proto_struct) {
+ proto_struct->destroy = (void *)NULL;
+ proto_struct->init = (void *)dummy_init;
+ proto_struct->handshake = (void *)NULL;
+ proto_struct->send = (void *)dummy_send;
+ proto_struct->recv = (void *)dummy_recv;
+
+ return 0;
+}
+
+int *
+dummy_init(int *initiator) {
+ /* Dodging state check. */
+ return initiator;
+}
+
+int
+dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest) {
+ (void)nothing;
+
+ /* ASN evbuffer_add_buffer() doesn't work for some reason. */
+ while (1) {
+ int n = evbuffer_remove_buffer(source, dest, 1024);
+ if (n <= 0)
+ return 0;
+ }
+}
+
+int
+dummy_recv(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest) {
+ (void)nothing;
+ while (1) {
+ int n = evbuffer_remove_buffer(source, dest, 1024);
+ if (n <= 0)
+ return 0;
+ }
+}
diff --git a/src/plugins/dummy.h b/src/plugins/dummy.h
new file mode 100644
index 0000000..cf9342a
--- /dev/null
+++ b/src/plugins/dummy.h
@@ -0,0 +1,21 @@
+/* Copyright 2011 Princess Peach Toadstool
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#ifndef DUMMY_H
+#define DUMMY_H
+
+struct protocol_t;
+struct evbuffer;
+
+int *dummy_init(int *initiator);
+int dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest);
+int dummy_recv(void *nothing, struct evbuffer *source,
+ struct evbuffer *dest);
+int dummy_new(struct protocol_t *proto_struct);
+
+#endif
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
index 01c74f3..ef8be8e 100644
--- a/src/plugins/obfs2.c
+++ b/src/plugins/obfs2.c
@@ -37,7 +37,7 @@ obfs2_new(struct protocol_t *proto_struct) {
return -1;
}
- return 0;
+ return 1;
}
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
@@ -167,8 +167,6 @@ obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf)
plength %= OBFUSCATE_MAX_PADDING;
send_plength = htonl(plength);
- printf("death and dest\n");
-
if (state->we_are_initiator)
seed = state->initiator_seed;
else
diff --git a/src/protocol.c b/src/protocol.c
index 6df93ca..339feae 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -6,6 +6,7 @@
#include "network.h"
#include "plugins/obfs2.h"
+#include "plugins/dummy.h"
/**
This function returns a protocol_t structure based on the mode
@@ -15,13 +16,15 @@ struct protocol_t *
set_up_protocol(int protocol) {
struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
- if (protocol == BRL_PROTOCOL) {
+ if (protocol == OBFS2_PROTOCOL)
proto->new = &obfs2_new;
- if (proto->new(proto))
- printf("Protocol constructed\n");
- }
+ else if (protocol == DUMMY_PROTOCOL)
+ proto->new = &dummy_new;
/* elif { other protocols } */
+ if (proto->new(proto)>0)
+ printf("Protocol constructed\n");
+
return proto;
}
@@ -39,8 +42,8 @@ proto_handshake(struct protocol_t *proto, void *buf) {
assert(proto);
if (proto->handshake)
return proto->handshake(proto->state, buf);
- else
- return -1;
+ else /* It's okay with me, protocol didn't have a handshake */
+ return 0;
}
int
@@ -48,7 +51,7 @@ proto_send(struct protocol_t *proto, void *source, void *dest) {
assert(proto);
if (proto->send)
return proto->send(proto->state, source, dest);
- else
+ else
return -1;
}
@@ -63,6 +66,7 @@ proto_recv(struct protocol_t *proto, void *source, void *dest) {
void proto_destroy(struct protocol_t *proto) {
assert(proto);
+ assert(proto->state);
if (proto->destroy)
proto->destroy(proto->state);
diff --git a/src/protocol.h b/src/protocol.h
index 9e58ea8..781bde0 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -2,7 +2,9 @@
#define PROTOCOL_H
/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
-#define BRL_PROTOCOL 1
+#define DUMMY_PROTOCOL 0
+#define OBFS2_PROTOCOL 1
+
struct protocol_t *set_up_protocol(int protocol);
void *proto_init(struct protocol_t *proto, void *arg);
diff --git a/src/socks.c b/src/socks.c
index 8f432e1..a3fb729 100644
--- a/src/socks.c
+++ b/src/socks.c
@@ -17,7 +17,7 @@
/**
- General idea:
+ General SOCKS5 idea:
Client ------------------------> Server
Method Negotiation Packet
@@ -32,8 +32,9 @@
Server reply
"Method Negotiation Packet" is handled by: socks5_handle_negotiation()
- "Method Negotiation Reply" is done by: socks5_reply_negotiation()
- "Client request" is handled by: socks5_validate_request()
+ "Method Negotiation Reply" is done by: socks5_do_negotiation()
+ "Client request" is handled by: socks5_handle_request()
+ "Server reply" is done by: socks5_send_reply
*/
static int socks5_do_negotiation(struct evbuffer *dest,
@@ -191,6 +192,8 @@ socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state,
/* We either failed or succeded.
Either way, we should send something back to the client */
p[0] = SOCKS5_VERSION; /* Version field */
+ if (status == SOCKS5_REP_FAIL)
+ printf("Sending negative shit\n");
p[1] = (unsigned char) status; /* Reply field */
p[2] = 0; /* Reserved */
if (state->parsereq.af == AF_UNSPEC) {
diff --git a/src/test/unittest_protocol.c b/src/test/unittest_protocol.c
index ceb666d..1864a3a 100644
--- a/src/test/unittest_protocol.c
+++ b/src/test/unittest_protocol.c
@@ -26,8 +26,8 @@
static void
test_proto_setup(void *data)
{
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
@@ -55,8 +55,8 @@ test_proto_handshake(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
@@ -114,8 +114,8 @@ test_proto_transfer(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
@@ -197,8 +197,8 @@ test_proto_splitted_handshake(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
@@ -337,8 +337,8 @@ test_proto_wrong_handshake_magic(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
@@ -402,8 +402,8 @@ test_proto_wrong_handshake_plength(void *data)
output_buffer = evbuffer_new();
dummy_buffer = evbuffer_new();
- struct protocol_t *client_proto = set_up_protocol(BRL_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(BRL_PROTOCOL);
+ struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
+ struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
int initiator = 1;
int no_initiator = 0;
client_proto->state = proto_init(client_proto, &initiator);
1
0

[obfsproxy/master] Adding BUG. It contains a bug I found, which I shouldn't forget to seek and destroy.
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit b24115a947c7e64efff9b242dee415ebb882db4d
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Fri Mar 25 02:23:35 2011 +0100
Adding BUG. It contains a bug I found, which I shouldn't forget to seek and destroy.
---
BUG | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/BUG b/BUG
new file mode 100644
index 0000000..248b855
--- /dev/null
+++ b/BUG
@@ -0,0 +1,21 @@
+-
+Program received signal SIGSEGV, Segmentation fault.
+crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
+194 memset(key, 0, sizeof(key));
+(gdb) backtrace
+#0 crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
+#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
+#2 0x0000000000401df2 in conn_free (conn=0x615bc0) at src/network.c:210
+#3 0x00007ffff7bb4ad8 in bufferevent_readcb (fd=<value optimized out>, event=<value optimized out>, arg=0x615f30) at bufferevent_sock.c:191
+#4 0x00007ffff7baa88c in event_process_active_single_queue (base=0x606220, flags=<value optimized out>) at event.c:1287
+#5 event_process_active (base=0x606220, flags=<value optimized out>) at event.c:1354
+#6 event_base_loop (base=0x606220, flags=<value optimized out>) at event.c:1551
+#7 0x0000000000401cc9 in main (argc=<value optimized out>, argv=<value optimized out>) at src/main.c:124
+(gdb) up
+#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
+357 crypt_free(s->send_crypto);
+(gdb) p s
+$1 = (obfs2_state_t *) 0x618230
+(gdb) p s->send_crypto
+$2 = (crypt_t *) 0xa0a0a0a0a0a0a0a
+-
1
0
commit aa399c851ad5e4741edde13d05d2f92c59d20335
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Mon Apr 11 02:34:15 2011 +0200
* Revived obfs2 unit tests.
* Renamed unittest_protocol.c to unittest_obfs2.c
* Renamed src/plugins/ to src/protocols/
---
Makefile.am | 14 +-
src/plugins/dummy.c | 63 ------
src/plugins/dummy.h | 10 -
src/plugins/obfs2.c | 405 -----------------------------------
src/plugins/obfs2.h | 81 -------
src/plugins/obfs2_crypt.c | 206 ------------------
src/plugins/obfs2_crypt.h | 62 ------
src/protocols/dummy.c | 63 ++++++
src/protocols/dummy.h | 10 +
src/protocols/obfs2.c | 405 +++++++++++++++++++++++++++++++++++
src/protocols/obfs2.h | 81 +++++++
src/protocols/obfs2_crypt.c | 206 ++++++++++++++++++
src/protocols/obfs2_crypt.h | 62 ++++++
src/test/unittest_obfs2.c | 476 ++++++++++++++++++++++++++++++++++++++++++
src/test/unittest_protocol.c | 469 -----------------------------------------
15 files changed, 1310 insertions(+), 1303 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 32d5c05..bd3a2b2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,9 +12,9 @@ libobfsproxy_a_SOURCES = \
src/protocol.c \
src/socks.c \
src/util.c \
- src/plugins/obfs2.c \
- src/plugins/obfs2_crypt.c \
- src/plugins/dummy.c
+ src/protocols/obfs2.c \
+ src/protocols/obfs2_crypt.c \
+ src/protocols/dummy.c
obfsproxy_SOURCES = \
src/main.c
@@ -23,7 +23,7 @@ obfsproxy_LDADD = @libevent_LIBS@ @openssl_LIBS@ libobfsproxy.a
unittests_SOURCES = \
src/test/tinytest.c \
src/test/unittest.c \
- src/test/unittest_protocol.c \
+ src/test/unittest_obfs2.c \
src/test/unittest_crypt.c \
src/test/unittest_socks.c
unittests_LDADD = @libevent_LIBS@ @openssl_LIBS@ libobfsproxy.a
@@ -35,9 +35,9 @@ noinst_HEADERS = \
src/util.h \
src/test/tinytest.h \
src/test/tinytest_macros.h \
- src/plugins/obfs2.h \
- src/plugins/obfs2_crypt.h \
- src/plugins/dummy.h
+ src/protocols/obfs2.h \
+ src/protocols/obfs2_crypt.h \
+ src/protocols/dummy.h
EXTRA_DIST = doc/protocol-spec.txt src/sha256.c
diff --git a/src/plugins/dummy.c b/src/plugins/dummy.c
deleted file mode 100644
index 8fe722e..0000000
--- a/src/plugins/dummy.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <unistd.h>
-
-#include <openssl/rand.h>
-#include <event2/buffer.h>
-
-#include "dummy.h"
-#include "../util.h"
-#include "../protocol.h"
-
-
-static int dummy_send(void *nothing,
- struct evbuffer *source, struct evbuffer *dest);
-static int dummy_recv(void *nothing, struct evbuffer *source,
- struct evbuffer *dest);
-
-static protocol_vtable *vtable=NULL;
-
-int
-dummy_init(void) {
- vtable = calloc(1, sizeof(protocol_vtable));
- if (!vtable)
- return -1;
-
- vtable->destroy = NULL;
- vtable->create = dummy_new;
- vtable->handshake = NULL;
- vtable->send = dummy_send;
- vtable->recv = dummy_recv;
-
- return 1;
-}
-
-void *
-dummy_new(struct protocol_t *proto_struct, int whatever) {
- (void)whatever;
-
- proto_struct->vtable = vtable;
-
- /* Dodging state check.
- This is terrible I know.*/
- return (void *)666U;
-}
-
-static int
-dummy_send(void *nothing,
- struct evbuffer *source, struct evbuffer *dest) {
- (void)nothing;
-
- return evbuffer_add_buffer(dest,source);
-}
-
-static int
-dummy_recv(void *nothing,
- struct evbuffer *source, struct evbuffer *dest) {
- (void)nothing;
-
- return evbuffer_add_buffer(dest,source);
-}
diff --git a/src/plugins/dummy.h b/src/plugins/dummy.h
deleted file mode 100644
index 241366d..0000000
--- a/src/plugins/dummy.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef DUMMY_H
-#define DUMMY_H
-
-struct protocol_t;
-struct evbuffer;
-
-int dummy_init(void);
-void *dummy_new(struct protocol_t *proto_struct, int whatever);
-
-#endif
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
deleted file mode 100644
index cac7bb2..0000000
--- a/src/plugins/obfs2.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <openssl/rand.h>
-#include <event2/buffer.h>
-
-#define CRYPT_PROTOCOL_PRIVATE
-
-#include "obfs2_crypt.h"
-#include "obfs2.h"
-#include "../util.h"
-#include "../protocol.h"
-
-static void obfs2_state_free(void *state);
-static int obfs2_send_initial_message(void *state, struct evbuffer *buf);
-static int obfs2_send(void *state,
- struct evbuffer *source, struct evbuffer *dest);
-static int obfs2_recv(void *state, struct evbuffer *source,
- struct evbuffer *dest);
-static void *obfs2_state_new(int initiator);
-
-static protocol_vtable *vtable=NULL;
-
-/* Sets the function table for the obfs2 protocol and
- calls initialize_crypto().
- Returns 0 on success, -1 on fail.
-*/
-int
-obfs2_init(void) {
- vtable = calloc(1, sizeof(protocol_vtable));
- if (!vtable)
- return -1;
-
- vtable->destroy = obfs2_state_free;
- vtable->create = obfs2_new;
- vtable->handshake = obfs2_send_initial_message;
- vtable->send = obfs2_send;
- vtable->recv = obfs2_recv;
-
- if (initialize_crypto() < 0) {
- fprintf(stderr, "Can't initialize crypto; failing\n");
- return -1;
- }
-
- return 1;
-}
-
-/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
-static int
-seed_nonzero(const uchar *seed)
-{
- return memcmp(seed, OBFUSCATE_ZERO_SEED, OBFUSCATE_SEED_LENGTH) != 0;
-}
-
-/**
- Derive and return key of type 'keytype' from the seeds currently set in
- 'state'. Returns NULL on failure.
- */
-static crypt_t *
-derive_key(void *s, const char *keytype)
-{
- obfs2_state_t *state = s;
-
- crypt_t *cryptstate;
- uchar buf[32];
- digest_t *c = digest_new();
- digest_update(c, (uchar*)keytype, strlen(keytype));
- if (seed_nonzero(state->initiator_seed))
- digest_update(c, state->initiator_seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->responder_seed))
- digest_update(c, state->responder_seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->secret_seed))
- digest_update(c, state->secret_seed, SHARED_SECRET_LENGTH);
- digest_update(c, (uchar*)keytype, strlen(keytype));
- digest_getdigest(c, buf, sizeof(buf));
- cryptstate = crypt_new(buf, 16);
- crypt_set_iv(cryptstate, buf+16, 16);
- memset(buf, 0, sizeof(buf));
- digest_free(c);
- return cryptstate;
-}
-
-static crypt_t *
-derive_padding_key(void *s, const uchar *seed,
- const char *keytype)
-{
- obfs2_state_t *state = s;
-
- crypt_t *cryptstate;
- uchar buf[32];
- digest_t *c = digest_new();
- digest_update(c, (uchar*)keytype, strlen(keytype));
- if (seed_nonzero(seed))
- digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->secret_seed))
- digest_update(c, state->secret_seed, OBFUSCATE_SEED_LENGTH);
- digest_update(c, (uchar*)keytype, strlen(keytype));
- digest_getdigest(c, buf, sizeof(buf));
- cryptstate = crypt_new(buf, 16);
- crypt_set_iv(cryptstate, buf+16, 16);
- memset(buf, 0, 16);
- digest_free(c);
- return cryptstate;
-}
-
-void *
-obfs2_new(struct protocol_t *proto_struct, int initiator) {
- assert(vtable);
- proto_struct->vtable = vtable;
-
- return obfs2_state_new(initiator);
-}
-
-/**
- Return a new object to handle protocol state. If 'initiator' is true,
- we're the handshake initiator. Otherwise, we're the responder. Return
- NULL on failure.
- */
-static void *
-obfs2_state_new(int initiator)
-{
- obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
- uchar *seed;
- const char *send_pad_type;
-
- if (!state)
- return NULL;
- state->state = ST_WAIT_FOR_KEY;
- state->we_are_initiator = initiator;
- if (initiator) {
- send_pad_type = INITIATOR_PAD_TYPE;
- seed = state->initiator_seed;
- } else {
- send_pad_type = RESPONDER_PAD_TYPE;
- seed = state->responder_seed;
- }
-
- /* Generate our seed */
- if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
- free(state);
- return NULL;
- }
-
- /* Derive the key for what we're sending */
- state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
- if (state->send_padding_crypto == NULL) {
- free(state);
- return NULL;
- }
-
- return state;
-}
-
-/** Set the shared secret to be used with this protocol state. */
-void
-obfs2_state_set_shared_secret(void *s,
- const char *secret, size_t secretlen)
-{
- obfs2_state_t *state = s;
-
- if (secretlen > SHARED_SECRET_LENGTH)
- secretlen = SHARED_SECRET_LENGTH;
- memcpy(state->secret_seed, secret, secretlen);
-}
-
-/**
- Write the initial protocol setup and padding message for 'state' to
- the evbuffer 'buf'. Return 0 on success, -1 on failure.
- */
-static int
-obfs2_send_initial_message(void *s, struct evbuffer *buf)
-{
- obfs2_state_t *state = s;
-
- uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
- uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
- const uchar *seed;
-
- /* We're going to send:
- SEED | E_PAD_KEY( UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN) )
- */
-
- assert(sizeof(magic) == 4);
-
- /* generate padlen */
- if (random_bytes((uchar*)&plength, 4) < 0)
- return -1;
- plength %= OBFUSCATE_MAX_PADDING;
- send_plength = htonl(plength);
-
- if (state->we_are_initiator)
- seed = state->initiator_seed;
- else
- seed = state->responder_seed;
-
- /* Marshal the message, but with no parts encrypted */
- memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
- memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
- if (random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength) < 0)
- return -1;
-
- /* Encrypt it */
- stream_crypt(state->send_padding_crypto,
- msg+OBFUSCATE_SEED_LENGTH, 8+plength);
-
- /* Put it on the buffer */
- evbuffer_add(buf, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- return 0;
-}
-
-/**
- Helper: encrypt every byte from 'source' using the key in 'crypto',
- and write those bytes onto 'dest'. Return 0 on success, -1 on failure.
- */
-static int
-crypt_and_transmit(crypt_t *crypto,
- struct evbuffer *source, struct evbuffer *dest)
-{
- uchar data[1024];
- while (1) {
- int n = evbuffer_remove(source, data, 1024);
- if (n <= 0)
- return 0;
- stream_crypt(crypto, data, n);
- // printf("Message is: %s", data);
- evbuffer_add(dest, data, n);
- dbg(("Processed %d bytes.", n));
- }
-}
-
-/**
- Called when data arrives from the user side and we want to send the
- obfuscated version. Copies and obfuscates data from 'source' into 'dest'
- using the state in 'state'. Returns 0 on success, -1 on failure.
- */
-static int
-obfs2_send(void *s,
- struct evbuffer *source, struct evbuffer *dest)
-{
- obfs2_state_t *state = s;
-
- if (state->send_crypto) {
- /* Our crypto is set up; just relay the bytes */
- return crypt_and_transmit(state->send_crypto, source, dest);
- } else {
- /* Our crypto isn't set up yet, we'll have to queue the data */
- if (evbuffer_get_length(source)) {
- if (! state->pending_data_to_send) {
- state->pending_data_to_send = evbuffer_new();
- }
- evbuffer_add_buffer(state->pending_data_to_send, source);
- }
- return 0;
- }
-}
-
-/**
- Helper: called after reciving our partner's setup message. Initializes all
- keys. Returns 0 on success, -1 on failure.
- */
-static int
-init_crypto(void *s)
-{
- obfs2_state_t *state = s;
-
- const char *send_keytype;
- const char *recv_keytype;
- const char *recv_pad_keytype;
- const uchar *recv_seed;
-
- if (state->we_are_initiator) {
- send_keytype = INITIATOR_SEND_TYPE;
- recv_keytype = RESPONDER_SEND_TYPE;
- recv_pad_keytype = RESPONDER_PAD_TYPE;
- recv_seed = state->responder_seed;
- } else {
- send_keytype = RESPONDER_SEND_TYPE;
- recv_keytype = INITIATOR_SEND_TYPE;
- recv_pad_keytype = INITIATOR_PAD_TYPE;
- recv_seed = state->initiator_seed;
- }
-
- /* Derive all of the keys that depend on our partner's seed */
- state->send_crypto = derive_key(state, send_keytype);
- state->recv_crypto = derive_key(state, recv_keytype);
- state->recv_padding_crypto =
- derive_padding_key(state, recv_seed, recv_pad_keytype);
-
- if (state->send_crypto && state->recv_crypto && state->recv_padding_crypto)
- return 0;
- else
- return -1;
-}
-
-/* Called when we receive data in an evbuffer 'source': deobfuscates that data
- * and writes it to 'dest'.
- *
- * Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
- * for "fail, close" */
-static int
-obfs2_recv(void *s, struct evbuffer *source,
- struct evbuffer *dest)
-{
- obfs2_state_t *state = s;
-
- if (state->state == ST_WAIT_FOR_KEY) {
- /* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
- * so we can learn the partner's seed and padding length */
- uchar buf[OBFUSCATE_SEED_LENGTH+8], *other_seed;
- uint32_t magic, plength;
- if (evbuffer_get_length(source) < OBFUSCATE_SEED_LENGTH+8) {
- /* data not here yet */
- return OBFUSCATE_SEED_LENGTH+8;
- }
- evbuffer_remove(source, buf, OBFUSCATE_SEED_LENGTH+8);
-
- if (state->we_are_initiator)
- other_seed = state->responder_seed;
- else
- other_seed = state->initiator_seed;
-
- memcpy(other_seed, buf, OBFUSCATE_SEED_LENGTH);
-
- /* Now we can set up all the keys from the seed */
- if (init_crypto(state) < 0)
- return -1;
-
- /* Decrypt the next 8 bytes */
- stream_crypt(state->recv_padding_crypto, buf+OBFUSCATE_SEED_LENGTH, 8);
- /* Check the magic number and extract the padding length */
- memcpy(&magic, buf+OBFUSCATE_SEED_LENGTH, 4);
- memcpy(&plength, buf+OBFUSCATE_SEED_LENGTH+4, 4);
- magic = ntohl(magic);
- plength = ntohl(plength);
- if (magic != OBFUSCATE_MAGIC_VALUE)
- return -1;
- if (plength > OBFUSCATE_MAX_PADDING)
- return -1;
-
- /* Send any data that we've been waiting to send */
- if (state->pending_data_to_send) {
- crypt_and_transmit(state->send_crypto, state->pending_data_to_send, dest);
- evbuffer_free(state->pending_data_to_send);
- state->pending_data_to_send = NULL;
- }
-
- /* Now we're waiting for plength bytes of padding */
- state->padding_left_to_read = plength;
- state->state = ST_WAIT_FOR_PADDING;
-
- /* Fall through here: if there is padding data waiting on the buffer, pull
- it off immediately. */
- dbg(("Received key, expecting %d bytes of padding\n", plength));
- }
-
- /* If we're still looking for padding, start pulling off bytes and
- discarding them. */
- while (state->padding_left_to_read) {
- int n = state->padding_left_to_read;
- size_t sourcelen = evbuffer_get_length(source);
- if (!sourcelen)
- return n;
- if ((size_t) n > evbuffer_get_length(source))
- n = evbuffer_get_length(source);
- evbuffer_drain(source, n);
- state->padding_left_to_read -= n;
- dbg(("Received %d bytes of padding; %d left to read\n", n,
- state->padding_left_to_read));
- }
-
- /* Okay; now we're definitely open. Process whatever data we have. */
- state->state = ST_OPEN;
-
- dbg(("Processing %d bytes data onto destination buffer\n",
- (int) evbuffer_get_length(source)));
- return crypt_and_transmit(state->recv_crypto, source, dest);
-}
-
-static void
-obfs2_state_free(void *s)
-{
- obfs2_state_t *state = s;
- if (state->send_crypto)
- crypt_free(state->send_crypto);
- if (state->send_padding_crypto)
- crypt_free(state->send_padding_crypto);
- if (state->recv_crypto)
- crypt_free(state->recv_crypto);
- if (state->recv_padding_crypto)
- crypt_free(state->recv_padding_crypto);
- if (state->pending_data_to_send)
- evbuffer_free(state->pending_data_to_send);
- memset(state, 0x0a, sizeof(obfs2_state_t));
- free(state);
-}
diff --git a/src/plugins/obfs2.h b/src/plugins/obfs2.h
deleted file mode 100644
index 3124bbc..0000000
--- a/src/plugins/obfs2.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#ifndef OBFS2_H
-#define OBFS2_H
-
-#include <sys/types.h>
-
-typedef struct obfs2_state_t obfs2_state_t;
-struct evbuffer;
-struct protocol_t;
-
-#define SHARED_SECRET_LENGTH 16
-
-void obfs2_state_set_shared_secret(void *state,
- const char *secret, size_t secretlen);
-int obfs2_init(void);
-void *obfs2_new(struct protocol_t *proto_struct, int initiator);
-
-
-#ifdef CRYPT_PROTOCOL_PRIVATE
-/* ==========
- These definitions are not part of the crypt_protocol interface.
- They're exposed here so that the unit tests can use them.
- ==========
-*/
-/* from brl's obfuscated-ssh standard. */
-//#define OBFUSCATE_MAGIC_VALUE 0x0BF5CA7E
-
-/* our own, since we break brl's spec */
-#define OBFUSCATE_MAGIC_VALUE 0x2BF5CA7E
-#define OBFUSCATE_SEED_LENGTH 16
-#define OBFUSCATE_MAX_PADDING 8192
-#define OBFUSCATE_ZERO_SEED "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-
-#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
-#define RESPONDER_PAD_TYPE "Responder obfuscation padding"
-#define INITIATOR_SEND_TYPE "Initiator obfuscated data"
-#define RESPONDER_SEND_TYPE "Responder obfuscated data"
-
-struct obfs2_state_t {
- /** Current protocol state. We start out waiting for key information. Then
- we have a key and wait for padding to arrive. Finally, we are sending
- and receiving bytes on the connection.
- */
- enum {
- ST_WAIT_FOR_KEY,
- ST_WAIT_FOR_PADDING,
- ST_OPEN,
- } state;
- /** Random seed we generated for this stream */
- uchar initiator_seed[OBFUSCATE_SEED_LENGTH];
- /** Random seed the other side generated for this stream */
- uchar responder_seed[OBFUSCATE_SEED_LENGTH];
- /** Shared secret seed value. */
- uchar secret_seed[SHARED_SECRET_LENGTH];
- /** True iff we opened this connection */
- int we_are_initiator;
-
- /** key used to encrypt outgoing data */
- crypt_t *send_crypto;
- /** key used to encrypt outgoing padding */
- crypt_t *send_padding_crypto;
- /** key used to decrypt incoming data */
- crypt_t *recv_crypto;
- /** key used to decrypt incoming padding */
- crypt_t *recv_padding_crypto;
-
- /** Buffer full of data we'll send once the handshake is done. */
- struct evbuffer *pending_data_to_send;
-
- /** Number of padding bytes to read before we get to real data */
- int padding_left_to_read;
-};
-#endif
-
-#endif
diff --git a/src/plugins/obfs2_crypt.c b/src/plugins/obfs2_crypt.c
deleted file mode 100644
index 0121c93..0000000
--- a/src/plugins/obfs2_crypt.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
-#include <openssl/opensslv.h>
-#include <openssl/aes.h>
-#include <openssl/rand.h>
-#include <openssl/err.h>
-
-#define CRYPT_PRIVATE
-#include "obfs2_crypt.h"
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090800f
-#define USE_OPENSSL_RANDPOLL 1
-#define USE_OPENSSL_SHA256 1
-#include <openssl/sha.h>
-#else
-#define STMT_BEGIN do {
-#define STMT_END } while (0)
-static void
-set_uint32(void *ptr, uint32_t val)
-{
- memcpy(ptr, &val, 4);
-}
-static uint32_t
-get_uint32(const void *ptr)
-{
- uint32_t val;
- memcpy(&val, ptr, 4);
- return val;
-}
-#define LTC_ARGCHK(x) assert((x))
-#include "sha256.c"
-#endif
-
-int
-initialize_crypto(void)
-{
- ERR_load_crypto_strings();
-
-#ifdef USE_OPENSSL_RANDPOLL
- return RAND_poll() == 1 ? 0 : -1;
-#else
- /* XXX Or maybe fall back to the arc4random implementation in libevent2? */
- {
- char buf[32];
- int fd, n;
- fd = open("/dev/urandom", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return -1;
- }
- n = read(fd, buf, sizeof(buf));
- if (n != sizeof(buf)) {
- close(fd);
- return -1;
- }
- RAND_seed(buf, sizeof(buf));
- close(fd);
- return 0;
- }
-#endif
-}
-
-void
-cleanup_crypto(void)
-{
- ERR_free_strings();
-}
-
-/* =====
- Digests
- ===== */
-
-#ifdef USE_OPENSSL_SHA256
-struct digest_t {
- SHA256_CTX ctx;
-};
-digest_t *
-digest_new(void)
-{
- digest_t *d = malloc(sizeof(digest_t));
- SHA256_Init(&d->ctx);
- return d;
-}
-void
-digest_update(digest_t *d, const uchar *buf, size_t len)
-{
- SHA256_Update(&d->ctx, buf, len);
-}
-size_t
-digest_getdigest(digest_t *d, uchar *buf, size_t len)
-{
- uchar tmp[32];
- int n = 32;
- SHA256_Final(tmp, &d->ctx);
- if (len < 32)
- n = len;
- memcpy(buf, tmp, n);
- memset(tmp, 0, sizeof(tmp));
- return n;
-}
-#else
-struct digest_t {
- sha256_state ctx;
-};
-digest_t *
-digest_new(void)
-{
- digest_t *d = malloc(sizeof(digest_t));
- sha256_init(&d->ctx);
- return d;
-}
-void
-digest_update(digest_t *d, const uchar *buf, size_t len)
-{
- sha256_process(&d->ctx, buf, len);
-}
-size_t
-digest_getdigest(digest_t *d, uchar *buf, size_t len)
-{
- uchar tmp[32];
- int n = 32;
- sha256_done(&d->ctx, tmp);
- if (len < 32)
- n = len;
- memcpy(buf, tmp, n);
- memset(tmp, 0, sizeof(tmp));
- return n;
-}
-#endif
-
-void
-digest_free(digest_t *d)
-{
- memset(d, 0, sizeof(digest_t));
- free(d);
-}
-
-/* =====
- Stream crypto
- ===== */
-
-crypt_t *
-crypt_new(const uchar *key, size_t keylen)
-{
- crypt_t *k;
- if (keylen < AES_BLOCK_SIZE)
- return NULL;
-
- k = calloc(1, sizeof(crypt_t));
- if (k == NULL)
- return NULL;
-
- AES_set_encrypt_key(key, 128, &k->key);
-
- return k;
-}
-void
-crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen)
-{
- assert(ivlen == sizeof(key->ivec));
- memcpy(key->ivec, iv, ivlen);
-}
-void
-stream_crypt(crypt_t *key, uchar *buf, size_t len)
-{
- AES_ctr128_encrypt(buf, buf, /* XXX make sure this is okay to do. */
- len,
- &key->key, key->ivec, key->ecount_buf,
- &key->pos);
-}
-void
-crypt_free(crypt_t *key)
-{
- memset(key, 0, sizeof(key));
- free(key);
-}
-
-/* =====
- PRNG
- ===== */
-
-int
-random_bytes(uchar *buf, size_t buflen)
-{
- return RAND_bytes(buf, buflen) == 1 ? 0 : -1;
-}
diff --git a/src/plugins/obfs2_crypt.h b/src/plugins/obfs2_crypt.h
deleted file mode 100644
index c9841d8..0000000
--- a/src/plugins/obfs2_crypt.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
-#ifndef OBFS2_CRYPT_H
-#define OBFS2_CRYPT_H
-
-#include <sys/types.h>
-
-/* Stream cipher state */
-typedef struct crypt_t crypt_t;
-/* Digest state */
-typedef struct digest_t digest_t;
-
-typedef unsigned char uchar;
-
-/** Initialize global crypto state. Returrn 0 on success, -1 on failure */
-int initialize_crypto(void);
-/** Clean up global crypto state */
-void cleanup_crypto(void);
-
-/** Return a newly allocated digest state, or NULL on failure. */
-digest_t *digest_new(void);
-/** Add n bytes from b to the digest state. */
-void digest_update(digest_t *, const uchar *b, size_t n);
-/** Get a digest from the digest state. Put it in up the first n bytes of the
-buffer b. Return the number of bytes actually written.*/
-size_t digest_getdigest(digest_t *, uchar *b, size_t n);
-/** Clear and free a digest state */
-void digest_free(digest_t *);
-
-/** Return a new stream cipher state taking key and IV from the data provided.
- * The data length must be exactly 32 */
-crypt_t *crypt_new(const uchar *, size_t);
-void crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen);
-
-/** Encrypt n bytes of data in the buffer b, in place. */
-void stream_crypt(crypt_t *, uchar *b, size_t n);
-/** Clear and free a stream cipher state. */
-void crypt_free(crypt_t *);
-
-/** Set b to contain n random bytes. */
-int random_bytes(uchar *b, size_t n);
-
-#ifdef CRYPT_PRIVATE
-/* ==========
- These definitions are not part of the crypt interface.
- They're exposed here so that the unit tests can use them.
- ==========
-*/
-struct crypt_t {
- AES_KEY key;
- uchar ivec[AES_BLOCK_SIZE];
- uchar ecount_buf[AES_BLOCK_SIZE];
- unsigned int pos;
-};
-#endif
-
-#endif
diff --git a/src/protocols/dummy.c b/src/protocols/dummy.c
new file mode 100644
index 0000000..8fe722e
--- /dev/null
+++ b/src/protocols/dummy.c
@@ -0,0 +1,63 @@
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <unistd.h>
+
+#include <openssl/rand.h>
+#include <event2/buffer.h>
+
+#include "dummy.h"
+#include "../util.h"
+#include "../protocol.h"
+
+
+static int dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest);
+static int dummy_recv(void *nothing, struct evbuffer *source,
+ struct evbuffer *dest);
+
+static protocol_vtable *vtable=NULL;
+
+int
+dummy_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = NULL;
+ vtable->create = dummy_new;
+ vtable->handshake = NULL;
+ vtable->send = dummy_send;
+ vtable->recv = dummy_recv;
+
+ return 1;
+}
+
+void *
+dummy_new(struct protocol_t *proto_struct, int whatever) {
+ (void)whatever;
+
+ proto_struct->vtable = vtable;
+
+ /* Dodging state check.
+ This is terrible I know.*/
+ return (void *)666U;
+}
+
+static int
+dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest) {
+ (void)nothing;
+
+ return evbuffer_add_buffer(dest,source);
+}
+
+static int
+dummy_recv(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest) {
+ (void)nothing;
+
+ return evbuffer_add_buffer(dest,source);
+}
diff --git a/src/protocols/dummy.h b/src/protocols/dummy.h
new file mode 100644
index 0000000..241366d
--- /dev/null
+++ b/src/protocols/dummy.h
@@ -0,0 +1,10 @@
+#ifndef DUMMY_H
+#define DUMMY_H
+
+struct protocol_t;
+struct evbuffer;
+
+int dummy_init(void);
+void *dummy_new(struct protocol_t *proto_struct, int whatever);
+
+#endif
diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c
new file mode 100644
index 0000000..cac7bb2
--- /dev/null
+++ b/src/protocols/obfs2.c
@@ -0,0 +1,405 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <openssl/rand.h>
+#include <event2/buffer.h>
+
+#define CRYPT_PROTOCOL_PRIVATE
+
+#include "obfs2_crypt.h"
+#include "obfs2.h"
+#include "../util.h"
+#include "../protocol.h"
+
+static void obfs2_state_free(void *state);
+static int obfs2_send_initial_message(void *state, struct evbuffer *buf);
+static int obfs2_send(void *state,
+ struct evbuffer *source, struct evbuffer *dest);
+static int obfs2_recv(void *state, struct evbuffer *source,
+ struct evbuffer *dest);
+static void *obfs2_state_new(int initiator);
+
+static protocol_vtable *vtable=NULL;
+
+/* Sets the function table for the obfs2 protocol and
+ calls initialize_crypto().
+ Returns 0 on success, -1 on fail.
+*/
+int
+obfs2_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = obfs2_state_free;
+ vtable->create = obfs2_new;
+ vtable->handshake = obfs2_send_initial_message;
+ vtable->send = obfs2_send;
+ vtable->recv = obfs2_recv;
+
+ if (initialize_crypto() < 0) {
+ fprintf(stderr, "Can't initialize crypto; failing\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
+static int
+seed_nonzero(const uchar *seed)
+{
+ return memcmp(seed, OBFUSCATE_ZERO_SEED, OBFUSCATE_SEED_LENGTH) != 0;
+}
+
+/**
+ Derive and return key of type 'keytype' from the seeds currently set in
+ 'state'. Returns NULL on failure.
+ */
+static crypt_t *
+derive_key(void *s, const char *keytype)
+{
+ obfs2_state_t *state = s;
+
+ crypt_t *cryptstate;
+ uchar buf[32];
+ digest_t *c = digest_new();
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ if (seed_nonzero(state->initiator_seed))
+ digest_update(c, state->initiator_seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->responder_seed))
+ digest_update(c, state->responder_seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->secret_seed))
+ digest_update(c, state->secret_seed, SHARED_SECRET_LENGTH);
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ digest_getdigest(c, buf, sizeof(buf));
+ cryptstate = crypt_new(buf, 16);
+ crypt_set_iv(cryptstate, buf+16, 16);
+ memset(buf, 0, sizeof(buf));
+ digest_free(c);
+ return cryptstate;
+}
+
+static crypt_t *
+derive_padding_key(void *s, const uchar *seed,
+ const char *keytype)
+{
+ obfs2_state_t *state = s;
+
+ crypt_t *cryptstate;
+ uchar buf[32];
+ digest_t *c = digest_new();
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ if (seed_nonzero(seed))
+ digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
+ if (seed_nonzero(state->secret_seed))
+ digest_update(c, state->secret_seed, OBFUSCATE_SEED_LENGTH);
+ digest_update(c, (uchar*)keytype, strlen(keytype));
+ digest_getdigest(c, buf, sizeof(buf));
+ cryptstate = crypt_new(buf, 16);
+ crypt_set_iv(cryptstate, buf+16, 16);
+ memset(buf, 0, 16);
+ digest_free(c);
+ return cryptstate;
+}
+
+void *
+obfs2_new(struct protocol_t *proto_struct, int initiator) {
+ assert(vtable);
+ proto_struct->vtable = vtable;
+
+ return obfs2_state_new(initiator);
+}
+
+/**
+ Return a new object to handle protocol state. If 'initiator' is true,
+ we're the handshake initiator. Otherwise, we're the responder. Return
+ NULL on failure.
+ */
+static void *
+obfs2_state_new(int initiator)
+{
+ obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
+ uchar *seed;
+ const char *send_pad_type;
+
+ if (!state)
+ return NULL;
+ state->state = ST_WAIT_FOR_KEY;
+ state->we_are_initiator = initiator;
+ if (initiator) {
+ send_pad_type = INITIATOR_PAD_TYPE;
+ seed = state->initiator_seed;
+ } else {
+ send_pad_type = RESPONDER_PAD_TYPE;
+ seed = state->responder_seed;
+ }
+
+ /* Generate our seed */
+ if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
+ free(state);
+ return NULL;
+ }
+
+ /* Derive the key for what we're sending */
+ state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
+ if (state->send_padding_crypto == NULL) {
+ free(state);
+ return NULL;
+ }
+
+ return state;
+}
+
+/** Set the shared secret to be used with this protocol state. */
+void
+obfs2_state_set_shared_secret(void *s,
+ const char *secret, size_t secretlen)
+{
+ obfs2_state_t *state = s;
+
+ if (secretlen > SHARED_SECRET_LENGTH)
+ secretlen = SHARED_SECRET_LENGTH;
+ memcpy(state->secret_seed, secret, secretlen);
+}
+
+/**
+ Write the initial protocol setup and padding message for 'state' to
+ the evbuffer 'buf'. Return 0 on success, -1 on failure.
+ */
+static int
+obfs2_send_initial_message(void *s, struct evbuffer *buf)
+{
+ obfs2_state_t *state = s;
+
+ uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
+ uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
+ const uchar *seed;
+
+ /* We're going to send:
+ SEED | E_PAD_KEY( UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN) )
+ */
+
+ assert(sizeof(magic) == 4);
+
+ /* generate padlen */
+ if (random_bytes((uchar*)&plength, 4) < 0)
+ return -1;
+ plength %= OBFUSCATE_MAX_PADDING;
+ send_plength = htonl(plength);
+
+ if (state->we_are_initiator)
+ seed = state->initiator_seed;
+ else
+ seed = state->responder_seed;
+
+ /* Marshal the message, but with no parts encrypted */
+ memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
+ if (random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength) < 0)
+ return -1;
+
+ /* Encrypt it */
+ stream_crypt(state->send_padding_crypto,
+ msg+OBFUSCATE_SEED_LENGTH, 8+plength);
+
+ /* Put it on the buffer */
+ evbuffer_add(buf, msg, OBFUSCATE_SEED_LENGTH+8+plength);
+ return 0;
+}
+
+/**
+ Helper: encrypt every byte from 'source' using the key in 'crypto',
+ and write those bytes onto 'dest'. Return 0 on success, -1 on failure.
+ */
+static int
+crypt_and_transmit(crypt_t *crypto,
+ struct evbuffer *source, struct evbuffer *dest)
+{
+ uchar data[1024];
+ while (1) {
+ int n = evbuffer_remove(source, data, 1024);
+ if (n <= 0)
+ return 0;
+ stream_crypt(crypto, data, n);
+ // printf("Message is: %s", data);
+ evbuffer_add(dest, data, n);
+ dbg(("Processed %d bytes.", n));
+ }
+}
+
+/**
+ Called when data arrives from the user side and we want to send the
+ obfuscated version. Copies and obfuscates data from 'source' into 'dest'
+ using the state in 'state'. Returns 0 on success, -1 on failure.
+ */
+static int
+obfs2_send(void *s,
+ struct evbuffer *source, struct evbuffer *dest)
+{
+ obfs2_state_t *state = s;
+
+ if (state->send_crypto) {
+ /* Our crypto is set up; just relay the bytes */
+ return crypt_and_transmit(state->send_crypto, source, dest);
+ } else {
+ /* Our crypto isn't set up yet, we'll have to queue the data */
+ if (evbuffer_get_length(source)) {
+ if (! state->pending_data_to_send) {
+ state->pending_data_to_send = evbuffer_new();
+ }
+ evbuffer_add_buffer(state->pending_data_to_send, source);
+ }
+ return 0;
+ }
+}
+
+/**
+ Helper: called after reciving our partner's setup message. Initializes all
+ keys. Returns 0 on success, -1 on failure.
+ */
+static int
+init_crypto(void *s)
+{
+ obfs2_state_t *state = s;
+
+ const char *send_keytype;
+ const char *recv_keytype;
+ const char *recv_pad_keytype;
+ const uchar *recv_seed;
+
+ if (state->we_are_initiator) {
+ send_keytype = INITIATOR_SEND_TYPE;
+ recv_keytype = RESPONDER_SEND_TYPE;
+ recv_pad_keytype = RESPONDER_PAD_TYPE;
+ recv_seed = state->responder_seed;
+ } else {
+ send_keytype = RESPONDER_SEND_TYPE;
+ recv_keytype = INITIATOR_SEND_TYPE;
+ recv_pad_keytype = INITIATOR_PAD_TYPE;
+ recv_seed = state->initiator_seed;
+ }
+
+ /* Derive all of the keys that depend on our partner's seed */
+ state->send_crypto = derive_key(state, send_keytype);
+ state->recv_crypto = derive_key(state, recv_keytype);
+ state->recv_padding_crypto =
+ derive_padding_key(state, recv_seed, recv_pad_keytype);
+
+ if (state->send_crypto && state->recv_crypto && state->recv_padding_crypto)
+ return 0;
+ else
+ return -1;
+}
+
+/* Called when we receive data in an evbuffer 'source': deobfuscates that data
+ * and writes it to 'dest'.
+ *
+ * Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
+ * for "fail, close" */
+static int
+obfs2_recv(void *s, struct evbuffer *source,
+ struct evbuffer *dest)
+{
+ obfs2_state_t *state = s;
+
+ if (state->state == ST_WAIT_FOR_KEY) {
+ /* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
+ * so we can learn the partner's seed and padding length */
+ uchar buf[OBFUSCATE_SEED_LENGTH+8], *other_seed;
+ uint32_t magic, plength;
+ if (evbuffer_get_length(source) < OBFUSCATE_SEED_LENGTH+8) {
+ /* data not here yet */
+ return OBFUSCATE_SEED_LENGTH+8;
+ }
+ evbuffer_remove(source, buf, OBFUSCATE_SEED_LENGTH+8);
+
+ if (state->we_are_initiator)
+ other_seed = state->responder_seed;
+ else
+ other_seed = state->initiator_seed;
+
+ memcpy(other_seed, buf, OBFUSCATE_SEED_LENGTH);
+
+ /* Now we can set up all the keys from the seed */
+ if (init_crypto(state) < 0)
+ return -1;
+
+ /* Decrypt the next 8 bytes */
+ stream_crypt(state->recv_padding_crypto, buf+OBFUSCATE_SEED_LENGTH, 8);
+ /* Check the magic number and extract the padding length */
+ memcpy(&magic, buf+OBFUSCATE_SEED_LENGTH, 4);
+ memcpy(&plength, buf+OBFUSCATE_SEED_LENGTH+4, 4);
+ magic = ntohl(magic);
+ plength = ntohl(plength);
+ if (magic != OBFUSCATE_MAGIC_VALUE)
+ return -1;
+ if (plength > OBFUSCATE_MAX_PADDING)
+ return -1;
+
+ /* Send any data that we've been waiting to send */
+ if (state->pending_data_to_send) {
+ crypt_and_transmit(state->send_crypto, state->pending_data_to_send, dest);
+ evbuffer_free(state->pending_data_to_send);
+ state->pending_data_to_send = NULL;
+ }
+
+ /* Now we're waiting for plength bytes of padding */
+ state->padding_left_to_read = plength;
+ state->state = ST_WAIT_FOR_PADDING;
+
+ /* Fall through here: if there is padding data waiting on the buffer, pull
+ it off immediately. */
+ dbg(("Received key, expecting %d bytes of padding\n", plength));
+ }
+
+ /* If we're still looking for padding, start pulling off bytes and
+ discarding them. */
+ while (state->padding_left_to_read) {
+ int n = state->padding_left_to_read;
+ size_t sourcelen = evbuffer_get_length(source);
+ if (!sourcelen)
+ return n;
+ if ((size_t) n > evbuffer_get_length(source))
+ n = evbuffer_get_length(source);
+ evbuffer_drain(source, n);
+ state->padding_left_to_read -= n;
+ dbg(("Received %d bytes of padding; %d left to read\n", n,
+ state->padding_left_to_read));
+ }
+
+ /* Okay; now we're definitely open. Process whatever data we have. */
+ state->state = ST_OPEN;
+
+ dbg(("Processing %d bytes data onto destination buffer\n",
+ (int) evbuffer_get_length(source)));
+ return crypt_and_transmit(state->recv_crypto, source, dest);
+}
+
+static void
+obfs2_state_free(void *s)
+{
+ obfs2_state_t *state = s;
+ if (state->send_crypto)
+ crypt_free(state->send_crypto);
+ if (state->send_padding_crypto)
+ crypt_free(state->send_padding_crypto);
+ if (state->recv_crypto)
+ crypt_free(state->recv_crypto);
+ if (state->recv_padding_crypto)
+ crypt_free(state->recv_padding_crypto);
+ if (state->pending_data_to_send)
+ evbuffer_free(state->pending_data_to_send);
+ memset(state, 0x0a, sizeof(obfs2_state_t));
+ free(state);
+}
diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h
new file mode 100644
index 0000000..3124bbc
--- /dev/null
+++ b/src/protocols/obfs2.h
@@ -0,0 +1,81 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#ifndef OBFS2_H
+#define OBFS2_H
+
+#include <sys/types.h>
+
+typedef struct obfs2_state_t obfs2_state_t;
+struct evbuffer;
+struct protocol_t;
+
+#define SHARED_SECRET_LENGTH 16
+
+void obfs2_state_set_shared_secret(void *state,
+ const char *secret, size_t secretlen);
+int obfs2_init(void);
+void *obfs2_new(struct protocol_t *proto_struct, int initiator);
+
+
+#ifdef CRYPT_PROTOCOL_PRIVATE
+/* ==========
+ These definitions are not part of the crypt_protocol interface.
+ They're exposed here so that the unit tests can use them.
+ ==========
+*/
+/* from brl's obfuscated-ssh standard. */
+//#define OBFUSCATE_MAGIC_VALUE 0x0BF5CA7E
+
+/* our own, since we break brl's spec */
+#define OBFUSCATE_MAGIC_VALUE 0x2BF5CA7E
+#define OBFUSCATE_SEED_LENGTH 16
+#define OBFUSCATE_MAX_PADDING 8192
+#define OBFUSCATE_ZERO_SEED "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+
+#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
+#define RESPONDER_PAD_TYPE "Responder obfuscation padding"
+#define INITIATOR_SEND_TYPE "Initiator obfuscated data"
+#define RESPONDER_SEND_TYPE "Responder obfuscated data"
+
+struct obfs2_state_t {
+ /** Current protocol state. We start out waiting for key information. Then
+ we have a key and wait for padding to arrive. Finally, we are sending
+ and receiving bytes on the connection.
+ */
+ enum {
+ ST_WAIT_FOR_KEY,
+ ST_WAIT_FOR_PADDING,
+ ST_OPEN,
+ } state;
+ /** Random seed we generated for this stream */
+ uchar initiator_seed[OBFUSCATE_SEED_LENGTH];
+ /** Random seed the other side generated for this stream */
+ uchar responder_seed[OBFUSCATE_SEED_LENGTH];
+ /** Shared secret seed value. */
+ uchar secret_seed[SHARED_SECRET_LENGTH];
+ /** True iff we opened this connection */
+ int we_are_initiator;
+
+ /** key used to encrypt outgoing data */
+ crypt_t *send_crypto;
+ /** key used to encrypt outgoing padding */
+ crypt_t *send_padding_crypto;
+ /** key used to decrypt incoming data */
+ crypt_t *recv_crypto;
+ /** key used to decrypt incoming padding */
+ crypt_t *recv_padding_crypto;
+
+ /** Buffer full of data we'll send once the handshake is done. */
+ struct evbuffer *pending_data_to_send;
+
+ /** Number of padding bytes to read before we get to real data */
+ int padding_left_to_read;
+};
+#endif
+
+#endif
diff --git a/src/protocols/obfs2_crypt.c b/src/protocols/obfs2_crypt.c
new file mode 100644
index 0000000..0121c93
--- /dev/null
+++ b/src/protocols/obfs2_crypt.c
@@ -0,0 +1,206 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#include <openssl/opensslv.h>
+#include <openssl/aes.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
+#define CRYPT_PRIVATE
+#include "obfs2_crypt.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800f
+#define USE_OPENSSL_RANDPOLL 1
+#define USE_OPENSSL_SHA256 1
+#include <openssl/sha.h>
+#else
+#define STMT_BEGIN do {
+#define STMT_END } while (0)
+static void
+set_uint32(void *ptr, uint32_t val)
+{
+ memcpy(ptr, &val, 4);
+}
+static uint32_t
+get_uint32(const void *ptr)
+{
+ uint32_t val;
+ memcpy(&val, ptr, 4);
+ return val;
+}
+#define LTC_ARGCHK(x) assert((x))
+#include "sha256.c"
+#endif
+
+int
+initialize_crypto(void)
+{
+ ERR_load_crypto_strings();
+
+#ifdef USE_OPENSSL_RANDPOLL
+ return RAND_poll() == 1 ? 0 : -1;
+#else
+ /* XXX Or maybe fall back to the arc4random implementation in libevent2? */
+ {
+ char buf[32];
+ int fd, n;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return -1;
+ }
+ n = read(fd, buf, sizeof(buf));
+ if (n != sizeof(buf)) {
+ close(fd);
+ return -1;
+ }
+ RAND_seed(buf, sizeof(buf));
+ close(fd);
+ return 0;
+ }
+#endif
+}
+
+void
+cleanup_crypto(void)
+{
+ ERR_free_strings();
+}
+
+/* =====
+ Digests
+ ===== */
+
+#ifdef USE_OPENSSL_SHA256
+struct digest_t {
+ SHA256_CTX ctx;
+};
+digest_t *
+digest_new(void)
+{
+ digest_t *d = malloc(sizeof(digest_t));
+ SHA256_Init(&d->ctx);
+ return d;
+}
+void
+digest_update(digest_t *d, const uchar *buf, size_t len)
+{
+ SHA256_Update(&d->ctx, buf, len);
+}
+size_t
+digest_getdigest(digest_t *d, uchar *buf, size_t len)
+{
+ uchar tmp[32];
+ int n = 32;
+ SHA256_Final(tmp, &d->ctx);
+ if (len < 32)
+ n = len;
+ memcpy(buf, tmp, n);
+ memset(tmp, 0, sizeof(tmp));
+ return n;
+}
+#else
+struct digest_t {
+ sha256_state ctx;
+};
+digest_t *
+digest_new(void)
+{
+ digest_t *d = malloc(sizeof(digest_t));
+ sha256_init(&d->ctx);
+ return d;
+}
+void
+digest_update(digest_t *d, const uchar *buf, size_t len)
+{
+ sha256_process(&d->ctx, buf, len);
+}
+size_t
+digest_getdigest(digest_t *d, uchar *buf, size_t len)
+{
+ uchar tmp[32];
+ int n = 32;
+ sha256_done(&d->ctx, tmp);
+ if (len < 32)
+ n = len;
+ memcpy(buf, tmp, n);
+ memset(tmp, 0, sizeof(tmp));
+ return n;
+}
+#endif
+
+void
+digest_free(digest_t *d)
+{
+ memset(d, 0, sizeof(digest_t));
+ free(d);
+}
+
+/* =====
+ Stream crypto
+ ===== */
+
+crypt_t *
+crypt_new(const uchar *key, size_t keylen)
+{
+ crypt_t *k;
+ if (keylen < AES_BLOCK_SIZE)
+ return NULL;
+
+ k = calloc(1, sizeof(crypt_t));
+ if (k == NULL)
+ return NULL;
+
+ AES_set_encrypt_key(key, 128, &k->key);
+
+ return k;
+}
+void
+crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen)
+{
+ assert(ivlen == sizeof(key->ivec));
+ memcpy(key->ivec, iv, ivlen);
+}
+void
+stream_crypt(crypt_t *key, uchar *buf, size_t len)
+{
+ AES_ctr128_encrypt(buf, buf, /* XXX make sure this is okay to do. */
+ len,
+ &key->key, key->ivec, key->ecount_buf,
+ &key->pos);
+}
+void
+crypt_free(crypt_t *key)
+{
+ memset(key, 0, sizeof(key));
+ free(key);
+}
+
+/* =====
+ PRNG
+ ===== */
+
+int
+random_bytes(uchar *buf, size_t buflen)
+{
+ return RAND_bytes(buf, buflen) == 1 ? 0 : -1;
+}
diff --git a/src/protocols/obfs2_crypt.h b/src/protocols/obfs2_crypt.h
new file mode 100644
index 0000000..c9841d8
--- /dev/null
+++ b/src/protocols/obfs2_crypt.h
@@ -0,0 +1,62 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+
+#ifndef OBFS2_CRYPT_H
+#define OBFS2_CRYPT_H
+
+#include <sys/types.h>
+
+/* Stream cipher state */
+typedef struct crypt_t crypt_t;
+/* Digest state */
+typedef struct digest_t digest_t;
+
+typedef unsigned char uchar;
+
+/** Initialize global crypto state. Returrn 0 on success, -1 on failure */
+int initialize_crypto(void);
+/** Clean up global crypto state */
+void cleanup_crypto(void);
+
+/** Return a newly allocated digest state, or NULL on failure. */
+digest_t *digest_new(void);
+/** Add n bytes from b to the digest state. */
+void digest_update(digest_t *, const uchar *b, size_t n);
+/** Get a digest from the digest state. Put it in up the first n bytes of the
+buffer b. Return the number of bytes actually written.*/
+size_t digest_getdigest(digest_t *, uchar *b, size_t n);
+/** Clear and free a digest state */
+void digest_free(digest_t *);
+
+/** Return a new stream cipher state taking key and IV from the data provided.
+ * The data length must be exactly 32 */
+crypt_t *crypt_new(const uchar *, size_t);
+void crypt_set_iv(crypt_t *key, const uchar *iv, size_t ivlen);
+
+/** Encrypt n bytes of data in the buffer b, in place. */
+void stream_crypt(crypt_t *, uchar *b, size_t n);
+/** Clear and free a stream cipher state. */
+void crypt_free(crypt_t *);
+
+/** Set b to contain n random bytes. */
+int random_bytes(uchar *b, size_t n);
+
+#ifdef CRYPT_PRIVATE
+/* ==========
+ These definitions are not part of the crypt interface.
+ They're exposed here so that the unit tests can use them.
+ ==========
+*/
+struct crypt_t {
+ AES_KEY key;
+ uchar ivec[AES_BLOCK_SIZE];
+ uchar ecount_buf[AES_BLOCK_SIZE];
+ unsigned int pos;
+};
+#endif
+
+#endif
diff --git a/src/test/unittest_obfs2.c b/src/test/unittest_obfs2.c
new file mode 100644
index 0000000..cdac4c9
--- /dev/null
+++ b/src/test/unittest_obfs2.c
@@ -0,0 +1,476 @@
+/* Copyright 2011 Nick Mathewson
+
+ You may do anything with this work that copyright law would normally
+ restrict, so long as you retain the above notice(s) and this license
+ in all redistributed copies and derived works. There is no warranty.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tinytest.h"
+#include "tinytest_macros.h"
+
+#include <event2/buffer.h>
+#include <openssl/aes.h>
+
+
+#define CRYPT_PROTOCOL_PRIVATE
+#define CRYPT_PRIVATE
+#include "../plugins/obfs2_crypt.h"
+#include "../util.h"
+#include "../protocol.h"
+#include "../plugins/obfs2.h"
+
+/* Make sure we can successfully set up a protocol state */
+static void
+test_proto_setup(void *data)
+{
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,1);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ end:
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
+
+}
+
+static void
+test_proto_handshake(void *data)
+{
+ struct evbuffer *output_buffer = NULL;
+ struct evbuffer *dummy_buffer = NULL;
+ output_buffer = evbuffer_new();
+ dummy_buffer = evbuffer_new();
+
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,0);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ obfs2_state_t *client_state = client_proto->state;
+ obfs2_state_t *server_state = server_proto->state;
+
+ /* We create a client handshake message and pass it to output_buffer */
+ tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
+
+ /* We simulate the server receiving and processing the client's handshake message,
+ by using proto_recv() on the output_buffer */
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
+
+ /* Now, we create the server's handshake and pass it to output_buffer */
+ tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
+
+ /* We simulate the client receiving and processing the server's handshake */
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
+
+ /* The handshake is now complete. We should have:
+ client's send_crypto == server's recv_crypto
+ server's send_crypto == client's recv_crypto . */
+ tt_int_op(0, ==, memcmp(client_state->send_crypto,
+ server_state->recv_crypto,
+ sizeof(crypt_t)));
+
+ tt_int_op(0, ==, memcmp(client_state->recv_crypto,
+ server_state->send_crypto,
+ sizeof(crypt_t)));
+
+ end:
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
+
+ if (output_buffer)
+ evbuffer_free(output_buffer);
+ if (dummy_buffer)
+ evbuffer_free(dummy_buffer);
+}
+
+static void
+test_proto_transfer(void *data)
+{
+ struct evbuffer *output_buffer = NULL;
+ struct evbuffer *dummy_buffer = NULL;
+ output_buffer = evbuffer_new();
+ dummy_buffer = evbuffer_new();
+
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,0);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ int n;
+ struct evbuffer_iovec v[2];
+
+ /* Handshake */
+ tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
+ tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
+ /* End of Handshake */
+
+ /* Now let's pass some data around. */
+ char *msg1 = "this is a 54-byte message passed from client to server";
+ char *msg2 = "this is a 55-byte message passed from server to client!";
+
+ /* client -> server */
+ evbuffer_add(dummy_buffer, msg1, 54);
+ proto_send(client_proto, dummy_buffer, output_buffer);
+
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
+
+ n = evbuffer_peek(dummy_buffer, -1, NULL, &v[0], 2);
+
+ /* Let's check if it matches. */
+ tt_int_op(0, ==, strncmp(msg1, v[0].iov_base, 54));
+
+ /* emptying dummy_buffer before next test */
+ size_t buffer_len = evbuffer_get_length(dummy_buffer);
+ tt_int_op(0, ==, evbuffer_drain(dummy_buffer, buffer_len));
+
+ /* client <- server */
+ evbuffer_add(dummy_buffer, msg2, 55);
+ tt_int_op(0, <=, proto_send(server_proto, dummy_buffer, output_buffer));
+
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
+
+ n = evbuffer_peek(dummy_buffer, -1, NULL, &v[1], 2);
+ tt_int_op(0, ==, strncmp(msg2, v[1].iov_base, 55));
+
+ end:
+ if (client_proto->state)
+ proto_destroy(client_proto);
+ if (server_proto->state)
+ proto_destroy(server_proto);
+
+ if (output_buffer)
+ evbuffer_free(output_buffer);
+ if (dummy_buffer)
+ evbuffer_free(dummy_buffer);
+}
+
+/* We are going to split client's handshake into:
+ msgclient_1 = [OBFUSCATE_SEED_LENGTH + 8 + <one fourth of padding>]
+ and msgclient_2 = [<rest of padding>].
+
+ We are then going to split server's handshake into:
+ msgserver_1 = [OBFUSCATE_SEED_LENGTH + 8]
+ and msgserver_2 = [<all padding>].
+
+ Afterwards we will verify that they both got the correct keys.
+ That's right, this unit test is loco . */
+static void
+test_proto_splitted_handshake(void *data)
+{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
+
+ struct evbuffer *output_buffer = NULL;
+ struct evbuffer *dummy_buffer = NULL;
+ output_buffer = evbuffer_new();
+ dummy_buffer = evbuffer_new();
+
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,0);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
+
+ uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
+ uint32_t plength1, plength1_msg1, plength1_msg2, send_plength1;
+ const uchar *seed1;
+
+ /* generate padlen */
+ tt_int_op(0, <=, random_bytes((uchar*)&plength1, 4));
+
+ plength1 %= OBFUSCATE_MAX_PADDING;
+
+ plength1_msg1 = plength1 / 4;
+ plength1_msg2 = plength1 - plength1_msg1;
+
+ send_plength1 = htonl(plength1);
+
+ uchar msgclient_1[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
+ uchar msgclient_2[OBFUSCATE_MAX_PADDING];
+
+ seed1 = client_state->initiator_seed;
+
+ memcpy(msgclient_1, seed1, OBFUSCATE_SEED_LENGTH);
+ memcpy(msgclient_1+OBFUSCATE_SEED_LENGTH, &magic, 4);
+ memcpy(msgclient_1+OBFUSCATE_SEED_LENGTH+4, &send_plength1, 4);
+ tt_int_op(0, <=, random_bytes(msgclient_1+OBFUSCATE_SEED_LENGTH+8, plength1_msg1));
+
+ stream_crypt(client_state->send_padding_crypto, msgclient_1+OBFUSCATE_SEED_LENGTH, 8+plength1_msg1);
+
+ /* Client sends handshake part 1 */
+ evbuffer_add(output_buffer, msgclient_1, OBFUSCATE_SEED_LENGTH+8+plength1_msg1);
+
+ /* Server receives handshake part 1 */
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
+
+ tt_assert(server_state->state == ST_WAIT_FOR_PADDING);
+
+ /* Preparing client's handshake part 2 */
+ tt_int_op(0, <=, random_bytes(msgclient_2, plength1_msg2));
+ stream_crypt(client_state->send_padding_crypto, msgclient_2, plength1_msg2);
+
+ /* Client sends handshake part 2 */
+ evbuffer_add(output_buffer, msgclient_2, plength1_msg2);
+
+ /* Server receives handshake part 2 */
+ tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
+
+ tt_assert(server_state->state == ST_OPEN);
+
+ /* Since everything went right, let's do a server to client handshake now! */
+ uint32_t plength2, send_plength2;
+ const uchar *seed2;
+
+ /* generate padlen */
+ tt_int_op(0, <=, random_bytes((uchar*)&plength2, 4));
+
+ plength2 %= OBFUSCATE_MAX_PADDING;
+ send_plength2 = htonl(plength2);
+
+ uchar msgserver_1[OBFUSCATE_SEED_LENGTH + 8];
+ uchar msgserver_2[OBFUSCATE_MAX_PADDING];
+
+ seed2 = server_state->responder_seed;
+
+ memcpy(msgserver_1, seed2, OBFUSCATE_SEED_LENGTH);
+ memcpy(msgserver_1+OBFUSCATE_SEED_LENGTH, &magic, 4);
+ memcpy(msgserver_1+OBFUSCATE_SEED_LENGTH+4, &send_plength2, 4);
+
+ stream_crypt(server_state->send_padding_crypto, msgserver_1+OBFUSCATE_SEED_LENGTH, 8);
+
+ /* Server sends handshake part 1 */
+ evbuffer_add(output_buffer, msgserver_1, OBFUSCATE_SEED_LENGTH+8);
+
+ /* Client receives handshake part 1 */
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
+
+ tt_assert(client_state->state == ST_WAIT_FOR_PADDING);
+
+ /* Preparing client's handshake part 2 */
+ tt_int_op(0, <=, random_bytes(msgserver_2, plength2));
+ stream_crypt(server_state->send_padding_crypto, msgserver_2, plength2);
+
+ /* Server sends handshake part 2 */
+ evbuffer_add(output_buffer, msgserver_2, plength2);
+
+ /* Client receives handshake part 2 */
+ tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
+
+ tt_assert(client_state->state == ST_OPEN);
+
+ /* The handshake is finally complete. We should have: */
+ /* client's send_crypto == server's recv_crypto */
+ /* server's send_crypto == client's recv_crypto . */
+ tt_int_op(0, ==, memcmp(client_state->send_crypto,
+ server_state->recv_crypto,
+ sizeof(crypt_t)));
+
+ tt_int_op(0, ==, memcmp(client_state->recv_crypto,
+ server_state->send_crypto,
+ sizeof(crypt_t)));
+
+ end:
+ if (client_state)
+ proto_destroy(client_proto);
+ if (server_state)
+ proto_destroy(server_proto);
+
+ if (output_buffer)
+ evbuffer_free(output_buffer);
+ if (dummy_buffer)
+ evbuffer_free(dummy_buffer);
+}
+
+/*
+ Erroneous handshake test:
+ Wrong magic value.
+*/
+static void
+test_proto_wrong_handshake_magic(void *data)
+{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
+
+ struct evbuffer *output_buffer = NULL;
+ struct evbuffer *dummy_buffer = NULL;
+ output_buffer = evbuffer_new();
+ dummy_buffer = evbuffer_new();
+
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,0);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
+
+ uint32_t wrong_magic = 0xD15EA5E;
+
+ uint32_t plength, send_plength;
+ const uchar *seed;
+ uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
+
+ tt_int_op(0, >=, random_bytes((uchar*)&plength, 4));
+ plength %= OBFUSCATE_MAX_PADDING;
+ send_plength = htonl(plength);
+
+ seed = client_state->initiator_seed;
+ memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH, &wrong_magic, 4);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
+ tt_int_op(0, >=, random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength));
+
+ stream_crypt(client_state->send_padding_crypto,
+ msg+OBFUSCATE_SEED_LENGTH, 8+plength);
+
+ evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
+
+ tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
+
+ tt_assert(server_state->state == ST_WAIT_FOR_KEY);
+
+ end:
+ if (client_state)
+ proto_destroy(client_proto);
+ if (server_state)
+ proto_destroy(server_proto);
+
+ if (output_buffer)
+ evbuffer_free(output_buffer);
+ if (dummy_buffer)
+ evbuffer_free(dummy_buffer);
+}
+
+/* Erroneous handshake test:
+ plength field larger than OBFUSCATE_MAX_PADDING
+*/
+static void
+test_proto_wrong_handshake_plength(void *data)
+{
+ obfs2_state_t *client_state = NULL;
+ obfs2_state_t *server_state = NULL;
+
+ struct evbuffer *output_buffer = NULL;
+ struct evbuffer *dummy_buffer = NULL;
+ output_buffer = evbuffer_new();
+ dummy_buffer = evbuffer_new();
+
+ struct protocol_t *client_proto = NULL;
+ struct protocol_t *server_proto = NULL;
+
+ tt_assert(set_up_protocol(OBFS2_PROTOCOL) >= 0);
+
+ client_proto = proto_new(OBFS2_PROTOCOL,1);
+ server_proto = proto_new(OBFS2_PROTOCOL,0);
+
+ tt_assert(client_proto);
+ tt_assert(server_proto);
+ tt_assert(client_proto->state);
+ tt_assert(server_proto->state);
+
+ client_state = client_proto->state;
+ server_state = server_proto->state;
+
+ uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8 + 1];
+ uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
+ uint32_t plength, send_plength;
+ const uchar *seed;
+ seed = client_state->initiator_seed;
+
+ plength = OBFUSCATE_MAX_PADDING + 1U;
+ send_plength = htonl(plength);
+
+ memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
+ memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
+ tt_int_op(0, >=, random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength));
+
+ stream_crypt(client_state->send_padding_crypto,
+ msg+OBFUSCATE_SEED_LENGTH, 8+plength);
+
+ evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
+
+ tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
+
+ tt_assert(server_state->state == ST_WAIT_FOR_KEY);
+
+ end:
+ if (client_state)
+ proto_destroy(client_proto);
+ if (server_state)
+ proto_destroy(server_proto);
+
+ if (output_buffer)
+ evbuffer_free(output_buffer);
+ if (dummy_buffer)
+ evbuffer_free(dummy_buffer);
+}
+
+
+#define T(name, flags) \
+ { #name, test_proto_##name, (flags), NULL, NULL }
+
+struct testcase_t protocol_tests[] = {
+ T(setup, 0),
+ T(handshake, 0),
+ T(transfer, 0),
+ T(splitted_handshake, 0),
+ T(wrong_handshake_magic, 0),
+#if 0
+ T(wrong_handshake_padding, 0),
+#endif
+ T(wrong_handshake_plength, 0),
+ END_OF_TESTCASES
+};
diff --git a/src/test/unittest_protocol.c b/src/test/unittest_protocol.c
deleted file mode 100644
index 1864a3a..0000000
--- a/src/test/unittest_protocol.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/* Copyright 2011 Nick Mathewson
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tinytest.h"
-#include "tinytest_macros.h"
-
-#include <event2/buffer.h>
-#include <openssl/aes.h>
-
-
-#define CRYPT_PROTOCOL_PRIVATE
-#define CRYPT_PRIVATE
-#include "../plugins/obfs2_crypt.h"
-#include "../util.h"
-#include "../protocol.h"
-#include "../plugins/obfs2.h"
-
-/* Make sure we can successfully set up a protocol state */
-static void
-test_proto_setup(void *data)
-{
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
-
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
-
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- end:
- if (client_proto->state)
- proto_destroy(client_proto);
- if (server_proto->state)
- proto_destroy(server_proto);
-
-}
-
-static void
-test_proto_handshake(void *data)
-{
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
-
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- obfs2_state_t *client_state = client_proto->state;
- obfs2_state_t *server_state = server_proto->state;
-
- /* We create a client handshake message and pass it to output_buffer */
- tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
-
- /* We simulate the server receiving and processing the client's handshake message,
- by using proto_recv() on the output_buffer */
- tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
-
- /* Now, we create the server's handshake and pass it to output_buffer */
- tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
-
- /* We simulate the client receiving and processing the server's handshake */
- tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
-
- /* The handshake is now complete. We should have:
- client's send_crypto == server's recv_crypto
- server's send_crypto == client's recv_crypto . */
- tt_int_op(0, ==, memcmp(client_state->send_crypto,
- server_state->recv_crypto,
- sizeof(crypt_t)));
-
- tt_int_op(0, ==, memcmp(client_state->recv_crypto,
- server_state->send_crypto,
- sizeof(crypt_t)));
-
- end:
- if (client_proto->state)
- proto_destroy(client_proto);
- if (server_proto->state)
- proto_destroy(server_proto);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-static void
-test_proto_transfer(void *data)
-{
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
-
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- int n;
- struct evbuffer_iovec v[2];
-
- /* Handshake */
- tt_int_op(0, <=, proto_handshake(client_proto, output_buffer)<0);
- tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer) <0);
- tt_int_op(0, <=, proto_handshake(server_proto, output_buffer)<0);
- tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer) <0);
- /* End of Handshake */
-
- /* Now let's pass some data around. */
- char *msg1 = "this is a 54-byte message passed from client to server";
- char *msg2 = "this is a 55-byte message passed from server to client!";
-
- /* client -> server */
- evbuffer_add(dummy_buffer, msg1, 54);
- proto_send(client_proto, dummy_buffer, output_buffer);
-
- tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
-
- n = evbuffer_peek(dummy_buffer, -1, NULL, &v[0], 2);
-
- /* Let's check if it matches. */
- tt_int_op(0, ==, strncmp(msg1, v[0].iov_base, 54));
-
- /* emptying dummy_buffer before next test */
- size_t buffer_len = evbuffer_get_length(dummy_buffer);
- tt_int_op(0, ==, evbuffer_drain(dummy_buffer, buffer_len));
-
- /* client <- server */
- evbuffer_add(dummy_buffer, msg2, 55);
- tt_int_op(0, <=, proto_send(server_proto, dummy_buffer, output_buffer));
-
- tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
-
- n = evbuffer_peek(dummy_buffer, -1, NULL, &v[1], 2);
- tt_int_op(0, ==, strncmp(msg2, v[1].iov_base, 55));
-
- end:
- if (client_proto->state)
- proto_destroy(client_proto);
- if (server_proto->state)
- proto_destroy(server_proto);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-/* We are going to split client's handshake into:
- msgclient_1 = [OBFUSCATE_SEED_LENGTH + 8 + <one fourth of padding>]
- and msgclient_2 = [<rest of padding>].
-
- We are then going to split server's handshake into:
- msgserver_1 = [OBFUSCATE_SEED_LENGTH + 8]
- and msgserver_2 = [<all padding>].
-
- Afterwards we will verify that they both got the correct keys.
- That's right, this unit test is loco . */
-static void
-test_proto_splitted_handshake(void *data)
-{
- obfs2_state_t *client_state = NULL;
- obfs2_state_t *server_state = NULL;
-
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
-
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- client_state = client_proto->state;
- server_state = server_proto->state;
-
- uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
- uint32_t plength1, plength1_msg1, plength1_msg2, send_plength1;
- const uchar *seed1;
-
- /* generate padlen */
- tt_int_op(0, <=, random_bytes((uchar*)&plength1, 4));
-
- plength1 %= OBFUSCATE_MAX_PADDING;
-
- plength1_msg1 = plength1 / 4;
- plength1_msg2 = plength1 - plength1_msg1;
-
- send_plength1 = htonl(plength1);
-
- uchar msgclient_1[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
- uchar msgclient_2[OBFUSCATE_MAX_PADDING];
-
- seed1 = client_state->initiator_seed;
-
- memcpy(msgclient_1, seed1, OBFUSCATE_SEED_LENGTH);
- memcpy(msgclient_1+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(msgclient_1+OBFUSCATE_SEED_LENGTH+4, &send_plength1, 4);
- tt_int_op(0, <=, random_bytes(msgclient_1+OBFUSCATE_SEED_LENGTH+8, plength1_msg1));
-
- stream_crypt(client_state->send_padding_crypto, msgclient_1+OBFUSCATE_SEED_LENGTH, 8+plength1_msg1);
-
- /* Client sends handshake part 1 */
- evbuffer_add(output_buffer, msgclient_1, OBFUSCATE_SEED_LENGTH+8+plength1_msg1);
-
- /* Server receives handshake part 1 */
- tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
-
- tt_assert(server_state->state == ST_WAIT_FOR_PADDING);
-
- /* Preparing client's handshake part 2 */
- tt_int_op(0, <=, random_bytes(msgclient_2, plength1_msg2));
- stream_crypt(client_state->send_padding_crypto, msgclient_2, plength1_msg2);
-
- /* Client sends handshake part 2 */
- evbuffer_add(output_buffer, msgclient_2, plength1_msg2);
-
- /* Server receives handshake part 2 */
- tt_int_op(0, <=, proto_recv(server_proto, output_buffer, dummy_buffer));
-
- tt_assert(server_state->state == ST_OPEN);
-
- /* Since everything went right, let's do a server to client handshake now! */
- uint32_t plength2, send_plength2;
- const uchar *seed2;
-
- /* generate padlen */
- tt_int_op(0, <=, random_bytes((uchar*)&plength2, 4));
-
- plength2 %= OBFUSCATE_MAX_PADDING;
- send_plength2 = htonl(plength2);
-
- uchar msgserver_1[OBFUSCATE_SEED_LENGTH + 8];
- uchar msgserver_2[OBFUSCATE_MAX_PADDING];
-
- seed2 = server_state->responder_seed;
-
- memcpy(msgserver_1, seed2, OBFUSCATE_SEED_LENGTH);
- memcpy(msgserver_1+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(msgserver_1+OBFUSCATE_SEED_LENGTH+4, &send_plength2, 4);
-
- stream_crypt(server_state->send_padding_crypto, msgserver_1+OBFUSCATE_SEED_LENGTH, 8);
-
- /* Server sends handshake part 1 */
- evbuffer_add(output_buffer, msgserver_1, OBFUSCATE_SEED_LENGTH+8);
-
- /* Client receives handshake part 1 */
- tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
-
- tt_assert(client_state->state == ST_WAIT_FOR_PADDING);
-
- /* Preparing client's handshake part 2 */
- tt_int_op(0, <=, random_bytes(msgserver_2, plength2));
- stream_crypt(server_state->send_padding_crypto, msgserver_2, plength2);
-
- /* Server sends handshake part 2 */
- evbuffer_add(output_buffer, msgserver_2, plength2);
-
- /* Client receives handshake part 2 */
- tt_int_op(0, <=, proto_recv(client_proto, output_buffer, dummy_buffer));
-
- tt_assert(client_state->state == ST_OPEN);
-
- /* The handshake is finally complete. We should have: */
- /* client's send_crypto == server's recv_crypto */
- /* server's send_crypto == client's recv_crypto . */
- tt_int_op(0, ==, memcmp(client_state->send_crypto,
- server_state->recv_crypto,
- sizeof(crypt_t)));
-
- tt_int_op(0, ==, memcmp(client_state->recv_crypto,
- server_state->send_crypto,
- sizeof(crypt_t)));
-
- end:
- if (client_state)
- proto_destroy(client_proto);
- if (server_state)
- proto_destroy(server_proto);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-/*
- Erroneous handshake test:
- Wrong magic value.
-*/
-static void
-test_proto_wrong_handshake_magic(void *data)
-{
- obfs2_state_t *client_state = NULL;
- obfs2_state_t *server_state = NULL;
-
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
-
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- client_state = client_proto->state;
- server_state = server_proto->state;
-
- uint32_t wrong_magic = 0xD15EA5E;
-
- uint32_t plength, send_plength;
- const uchar *seed;
- uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
-
- tt_int_op(0, >=, random_bytes((uchar*)&plength, 4));
- plength %= OBFUSCATE_MAX_PADDING;
- send_plength = htonl(plength);
-
- seed = client_state->initiator_seed;
- memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
- memcpy(msg+OBFUSCATE_SEED_LENGTH, &wrong_magic, 4);
- memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
- tt_int_op(0, >=, random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength));
-
- stream_crypt(client_state->send_padding_crypto,
- msg+OBFUSCATE_SEED_LENGTH, 8+plength);
-
- evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
-
- tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
-
- tt_assert(server_state->state == ST_WAIT_FOR_KEY);
-
- end:
- if (client_state)
- proto_destroy(client_proto);
- if (server_state)
- proto_destroy(server_proto);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-/* Erroneous handshake test:
- plength field larger than OBFUSCATE_MAX_PADDING
-*/
-static void
-test_proto_wrong_handshake_plength(void *data)
-{
- obfs2_state_t *client_state = NULL;
- obfs2_state_t *server_state = NULL;
- struct evbuffer *output_buffer = NULL;
- struct evbuffer *dummy_buffer = NULL;
- output_buffer = evbuffer_new();
- dummy_buffer = evbuffer_new();
-
- struct protocol_t *client_proto = set_up_protocol(OBFS2_PROTOCOL);
- struct protocol_t *server_proto = set_up_protocol(OBFS2_PROTOCOL);
- int initiator = 1;
- int no_initiator = 0;
- client_proto->state = proto_init(client_proto, &initiator);
- server_proto->state = proto_init(server_proto, &no_initiator);
- tt_assert(client_proto);
- tt_assert(server_proto);
- tt_assert(client_proto->state);
- tt_assert(server_proto->state);
-
- client_state = client_proto->state;
- server_state = server_proto->state;
-
- uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8 + 1];
- uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
- uint32_t plength, send_plength;
- const uchar *seed;
- seed = client_state->initiator_seed;
-
- plength = OBFUSCATE_MAX_PADDING + 1U;
- send_plength = htonl(plength);
-
- memcpy(msg, seed, OBFUSCATE_SEED_LENGTH);
- memcpy(msg+OBFUSCATE_SEED_LENGTH, &magic, 4);
- memcpy(msg+OBFUSCATE_SEED_LENGTH+4, &send_plength, 4);
- tt_int_op(0, >=, random_bytes(msg+OBFUSCATE_SEED_LENGTH+8, plength));
-
- stream_crypt(client_state->send_padding_crypto,
- msg+OBFUSCATE_SEED_LENGTH, 8+plength);
-
- evbuffer_add(output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
-
- tt_int_op(-1, ==, proto_recv(server_proto, output_buffer, dummy_buffer));
-
- tt_assert(server_state->state == ST_WAIT_FOR_KEY);
-
- end:
- if (client_state)
- proto_destroy(client_proto);
- if (server_state)
- proto_destroy(server_proto);
-
- if (output_buffer)
- evbuffer_free(output_buffer);
- if (dummy_buffer)
- evbuffer_free(dummy_buffer);
-}
-
-
-#define T(name, flags) \
- { #name, test_proto_##name, (flags), NULL, NULL }
-
-struct testcase_t protocol_tests[] = {
- T(setup, 0),
- T(handshake, 0),
- T(transfer, 0),
- T(splitted_handshake, 0),
- T(wrong_handshake_magic, 0),
-#if 0
- T(wrong_handshake_padding, 0),
-#endif
- T(wrong_handshake_plength, 0),
- END_OF_TESTCASES
-};
1
0
commit b46dde9aa8ebd779fe651c04704f8e253830f3eb
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Mon Apr 11 02:18:39 2011 +0200
This commit:
* Fixes many small bugs all around the code reported by Nick Mathewson.
* Removes the nasty casts to (void *) on the vtable assignment.
* Fixes BUG:
* The BUG was caused by the fact that we initialized a single
protocol_t in listener_new() for all connections. This means that
multiple connections shared the same protocol_t and hence the same
protocol state. So when a connection was freed, the state of other
connections was also freed and overwritten.
This was fixed:
* By introducing a proto_init() function, which initializes the
protocol. It's run only once; in the start of obfsproxy.
* By using a proto_new() function which returns a protocol_t for
every connection.
* We now use a protocol_vtable structure which contains the
function pointer table, and each protocol maintains a static
vtable of it's own.
* TODO:
Right now, both proto_new() and set_up_protocol() are protocol
specific. proto_new() must be proto-agnostic, but I
didn't have time to tinker and I wanted to see if my BUG
solution would work so I left it like this. I'll fix it soonish.
---
BUG | 21 ----------
src/main.c | 1 -
src/network.c | 23 ++++-------
src/plugins/dummy.c | 66 ++++++++++++++++---------------
src/plugins/dummy.h | 15 +------
src/plugins/obfs2.c | 105 ++++++++++++++++++++++++++++++++++----------------
src/plugins/obfs2.h | 13 +-----
src/protocol.c | 66 ++++++++++++++++++++------------
src/protocol.h | 38 ++++++++++++-------
src/socks.c | 2 -
10 files changed, 184 insertions(+), 166 deletions(-)
diff --git a/BUG b/BUG
deleted file mode 100644
index 248b855..0000000
--- a/BUG
+++ /dev/null
@@ -1,21 +0,0 @@
--
-Program received signal SIGSEGV, Segmentation fault.
-crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
-194 memset(key, 0, sizeof(key));
-(gdb) backtrace
-#0 crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
-#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
-#2 0x0000000000401df2 in conn_free (conn=0x615bc0) at src/network.c:210
-#3 0x00007ffff7bb4ad8 in bufferevent_readcb (fd=<value optimized out>, event=<value optimized out>, arg=0x615f30) at bufferevent_sock.c:191
-#4 0x00007ffff7baa88c in event_process_active_single_queue (base=0x606220, flags=<value optimized out>) at event.c:1287
-#5 event_process_active (base=0x606220, flags=<value optimized out>) at event.c:1354
-#6 event_base_loop (base=0x606220, flags=<value optimized out>) at event.c:1551
-#7 0x0000000000401cc9 in main (argc=<value optimized out>, argv=<value optimized out>) at src/main.c:124
-(gdb) up
-#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
-357 crypt_free(s->send_crypto);
-(gdb) p s
-$1 = (obfs2_state_t *) 0x618230
-(gdb) p s->send_crypto
-$2 = (crypt_t *) 0xa0a0a0a0a0a0a0a
--
diff --git a/src/main.c b/src/main.c
index 4f29005..225c698 100644
--- a/src/main.c
+++ b/src/main.c
@@ -117,7 +117,6 @@ main(int argc, const char **argv)
sigevent = evsignal_new(base, SIGINT, handle_signal_cb, (void*) base);
/* start an evconnlistener on the appropriate port(s) */
- /* ASN We hardcode OBFS2_PROTOCOL for now. */
listener = listener_new(base,
mode, protocol,
(struct sockaddr *)&ss_listen, sl_listen,
diff --git a/src/network.c b/src/network.c
index 3e23cdc..1199c96 100644
--- a/src/network.c
+++ b/src/network.c
@@ -27,7 +27,7 @@ struct listener_t {
struct evconnlistener *listener;
struct sockaddr_storage target_address;
int target_address_len;
- struct protocol_t *proto; /* Protocol that this listener can speak. */
+ int proto; /* Protocol that this listener can speak. */
int mode;
/* ASN */
/* char shared_secret[SHARED_SECRET_LENGTH];
@@ -63,13 +63,12 @@ listener_new(struct event_base *base,
assert(mode == LSN_SIMPLE_CLIENT || mode == LSN_SIMPLE_SERVER ||
mode == LSN_SOCKS_CLIENT);
- struct protocol_t *proto = set_up_protocol(protocol);
- if (!proto) {
- printf("This is just terrible. We can't even set up a protocol! Seppuku time!\n");
- exit(-1);
+ if (set_up_protocol(protocol)<0) {
+ printf("This is just terrible. We can't even set up a protocol! Exiting.\n");
+ exit(1);
}
- lsn->proto = proto;
+ lsn->proto = protocol;
lsn->mode = mode;
if (target_address) {
@@ -79,6 +78,7 @@ listener_new(struct event_base *base,
} else {
assert(lsn->mode == LSN_SOCKS_CLIENT);
}
+
/* ASN */
/*
assert(shared_secret == NULL || shared_secret_len == SHARED_SECRET_LENGTH);
@@ -123,16 +123,11 @@ simple_listener_cb(struct evconnlistener *evcl,
dbg(("Got a connection\n"));
conn->mode = lsn->mode;
- conn->proto = lsn->proto;
/* Will all protocols need to _init() here? Don't think so! */
- int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
- conn->proto->state = proto_init(conn->proto, &is_initiator);
-
- /* ASN Which means that all plugins need a state... */
- if (!conn->proto->state)
- goto err;
-
+ conn->proto = proto_new(lsn->proto,
+ conn->mode != LSN_SIMPLE_SERVER);
+
if (conn->mode == LSN_SOCKS_CLIENT) {
/* Construct SOCKS state. */
conn->socks_state = socks_state_new();
diff --git a/src/plugins/dummy.c b/src/plugins/dummy.c
index 957c30b..8fe722e 100644
--- a/src/plugins/dummy.c
+++ b/src/plugins/dummy.c
@@ -1,10 +1,3 @@
-/* Copyright 2011 Princess Peach Toadstool
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -19,43 +12,52 @@
#include "../util.h"
#include "../protocol.h"
+
+static int dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest);
+static int dummy_recv(void *nothing, struct evbuffer *source,
+ struct evbuffer *dest);
+
+static protocol_vtable *vtable=NULL;
+
int
-dummy_new(struct protocol_t *proto_struct) {
- proto_struct->destroy = (void *)NULL;
- proto_struct->init = (void *)dummy_init;
- proto_struct->handshake = (void *)NULL;
- proto_struct->send = (void *)dummy_send;
- proto_struct->recv = (void *)dummy_recv;
-
- return 0;
+dummy_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = NULL;
+ vtable->create = dummy_new;
+ vtable->handshake = NULL;
+ vtable->send = dummy_send;
+ vtable->recv = dummy_recv;
+
+ return 1;
}
-int *
-dummy_init(int *initiator) {
- /* Dodging state check. */
- return initiator;
+void *
+dummy_new(struct protocol_t *proto_struct, int whatever) {
+ (void)whatever;
+
+ proto_struct->vtable = vtable;
+
+ /* Dodging state check.
+ This is terrible I know.*/
+ return (void *)666U;
}
-int
+static int
dummy_send(void *nothing,
struct evbuffer *source, struct evbuffer *dest) {
(void)nothing;
- /* ASN evbuffer_add_buffer() doesn't work for some reason. */
- while (1) {
- int n = evbuffer_remove_buffer(source, dest, 1024);
- if (n <= 0)
- return 0;
- }
+ return evbuffer_add_buffer(dest,source);
}
-int
+static int
dummy_recv(void *nothing,
struct evbuffer *source, struct evbuffer *dest) {
(void)nothing;
- while (1) {
- int n = evbuffer_remove_buffer(source, dest, 1024);
- if (n <= 0)
- return 0;
- }
+
+ return evbuffer_add_buffer(dest,source);
}
diff --git a/src/plugins/dummy.h b/src/plugins/dummy.h
index cf9342a..241366d 100644
--- a/src/plugins/dummy.h
+++ b/src/plugins/dummy.h
@@ -1,21 +1,10 @@
-/* Copyright 2011 Princess Peach Toadstool
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
#ifndef DUMMY_H
#define DUMMY_H
struct protocol_t;
struct evbuffer;
-int *dummy_init(int *initiator);
-int dummy_send(void *nothing,
- struct evbuffer *source, struct evbuffer *dest);
-int dummy_recv(void *nothing, struct evbuffer *source,
- struct evbuffer *dest);
-int dummy_new(struct protocol_t *proto_struct);
+int dummy_init(void);
+void *dummy_new(struct protocol_t *proto_struct, int whatever);
#endif
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
index ef8be8e..cac7bb2 100644
--- a/src/plugins/obfs2.c
+++ b/src/plugins/obfs2.c
@@ -20,17 +20,31 @@
#include "../util.h"
#include "../protocol.h"
+static void obfs2_state_free(void *state);
+static int obfs2_send_initial_message(void *state, struct evbuffer *buf);
+static int obfs2_send(void *state,
+ struct evbuffer *source, struct evbuffer *dest);
+static int obfs2_recv(void *state, struct evbuffer *source,
+ struct evbuffer *dest);
+static void *obfs2_state_new(int initiator);
+
+static protocol_vtable *vtable=NULL;
+
/* Sets the function table for the obfs2 protocol and
calls initialize_crypto().
Returns 0 on success, -1 on fail.
*/
int
-obfs2_new(struct protocol_t *proto_struct) {
- proto_struct->destroy = (void *)obfs2_state_free;
- proto_struct->init = (void *)obfs2_state_new;
- proto_struct->handshake = (void *)obfs2_send_initial_message;
- proto_struct->send = (void *)obfs2_send;
- proto_struct->recv = (void *)obfs2_recv;
+obfs2_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = obfs2_state_free;
+ vtable->create = obfs2_new;
+ vtable->handshake = obfs2_send_initial_message;
+ vtable->send = obfs2_send;
+ vtable->recv = obfs2_recv;
if (initialize_crypto() < 0) {
fprintf(stderr, "Can't initialize crypto; failing\n");
@@ -52,8 +66,10 @@ seed_nonzero(const uchar *seed)
'state'. Returns NULL on failure.
*/
static crypt_t *
-derive_key(obfs2_state_t *state, const char *keytype)
+derive_key(void *s, const char *keytype)
{
+ obfs2_state_t *state = s;
+
crypt_t *cryptstate;
uchar buf[32];
digest_t *c = digest_new();
@@ -74,9 +90,11 @@ derive_key(obfs2_state_t *state, const char *keytype)
}
static crypt_t *
-derive_padding_key(obfs2_state_t *state, const uchar *seed,
+derive_padding_key(void *s, const uchar *seed,
const char *keytype)
{
+ obfs2_state_t *state = s;
+
crypt_t *cryptstate;
uchar buf[32];
digest_t *c = digest_new();
@@ -94,13 +112,21 @@ derive_padding_key(obfs2_state_t *state, const uchar *seed,
return cryptstate;
}
+void *
+obfs2_new(struct protocol_t *proto_struct, int initiator) {
+ assert(vtable);
+ proto_struct->vtable = vtable;
+
+ return obfs2_state_new(initiator);
+}
+
/**
Return a new object to handle protocol state. If 'initiator' is true,
we're the handshake initiator. Otherwise, we're the responder. Return
NULL on failure.
*/
-obfs2_state_t *
-obfs2_state_new(int *initiator)
+static void *
+obfs2_state_new(int initiator)
{
obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
uchar *seed;
@@ -109,8 +135,8 @@ obfs2_state_new(int *initiator)
if (!state)
return NULL;
state->state = ST_WAIT_FOR_KEY;
- state->we_are_initiator = *initiator;
- if (*initiator) {
+ state->we_are_initiator = initiator;
+ if (initiator) {
send_pad_type = INITIATOR_PAD_TYPE;
seed = state->initiator_seed;
} else {
@@ -136,9 +162,11 @@ obfs2_state_new(int *initiator)
/** Set the shared secret to be used with this protocol state. */
void
-obfs2_state_set_shared_secret(obfs2_state_t *state,
+obfs2_state_set_shared_secret(void *s,
const char *secret, size_t secretlen)
{
+ obfs2_state_t *state = s;
+
if (secretlen > SHARED_SECRET_LENGTH)
secretlen = SHARED_SECRET_LENGTH;
memcpy(state->secret_seed, secret, secretlen);
@@ -148,9 +176,11 @@ obfs2_state_set_shared_secret(obfs2_state_t *state,
Write the initial protocol setup and padding message for 'state' to
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
-int
-obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf)
+static int
+obfs2_send_initial_message(void *s, struct evbuffer *buf)
{
+ obfs2_state_t *state = s;
+
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
const uchar *seed;
@@ -213,10 +243,12 @@ crypt_and_transmit(crypt_t *crypto,
obfuscated version. Copies and obfuscates data from 'source' into 'dest'
using the state in 'state'. Returns 0 on success, -1 on failure.
*/
-int
-obfs2_send(obfs2_state_t *state,
+static int
+obfs2_send(void *s,
struct evbuffer *source, struct evbuffer *dest)
{
+ obfs2_state_t *state = s;
+
if (state->send_crypto) {
/* Our crypto is set up; just relay the bytes */
return crypt_and_transmit(state->send_crypto, source, dest);
@@ -237,8 +269,10 @@ obfs2_send(obfs2_state_t *state,
keys. Returns 0 on success, -1 on failure.
*/
static int
-init_crypto(obfs2_state_t *state)
+init_crypto(void *s)
{
+ obfs2_state_t *state = s;
+
const char *send_keytype;
const char *recv_keytype;
const char *recv_pad_keytype;
@@ -273,10 +307,12 @@ init_crypto(obfs2_state_t *state)
*
* Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
* for "fail, close" */
-int
-obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
+static int
+obfs2_recv(void *s, struct evbuffer *source,
struct evbuffer *dest)
{
+ obfs2_state_t *state = s;
+
if (state->state == ST_WAIT_FOR_KEY) {
/* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
* so we can learn the partner's seed and padding length */
@@ -350,19 +386,20 @@ obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
return crypt_and_transmit(state->recv_crypto, source, dest);
}
-void
-obfs2_state_free(obfs2_state_t *s)
+static void
+obfs2_state_free(void *s)
{
- if (s->send_crypto)
- crypt_free(s->send_crypto);
- if (s->send_padding_crypto)
- crypt_free(s->send_padding_crypto);
- if (s->recv_crypto)
- crypt_free(s->recv_crypto);
- if (s->recv_padding_crypto)
- crypt_free(s->recv_padding_crypto);
- if (s->pending_data_to_send)
- evbuffer_free(s->pending_data_to_send);
- memset(s, 0x0a, sizeof(obfs2_state_t));
- free(s);
+ obfs2_state_t *state = s;
+ if (state->send_crypto)
+ crypt_free(state->send_crypto);
+ if (state->send_padding_crypto)
+ crypt_free(state->send_padding_crypto);
+ if (state->recv_crypto)
+ crypt_free(state->recv_crypto);
+ if (state->recv_padding_crypto)
+ crypt_free(state->recv_padding_crypto);
+ if (state->pending_data_to_send)
+ evbuffer_free(state->pending_data_to_send);
+ memset(state, 0x0a, sizeof(obfs2_state_t));
+ free(state);
}
diff --git a/src/plugins/obfs2.h b/src/plugins/obfs2.h
index 2d1d24e..3124bbc 100644
--- a/src/plugins/obfs2.h
+++ b/src/plugins/obfs2.h
@@ -16,17 +16,10 @@ struct protocol_t;
#define SHARED_SECRET_LENGTH 16
-obfs2_state_t *obfs2_state_new(int *initiator);
-void obfs2_state_set_shared_secret(obfs2_state_t *state,
+void obfs2_state_set_shared_secret(void *state,
const char *secret, size_t secretlen);
-void obfs2_state_free(obfs2_state_t *state);
-int obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf);
-int obfs2_send(obfs2_state_t *state,
- struct evbuffer *source, struct evbuffer *dest);
-int obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
- struct evbuffer *dest);
-
-int obfs2_new(struct protocol_t *proto_struct);
+int obfs2_init(void);
+void *obfs2_new(struct protocol_t *proto_struct, int initiator);
#ifdef CRYPT_PROTOCOL_PRIVATE
diff --git a/src/protocol.c b/src/protocol.c
index 339feae..b95ab11 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -9,30 +9,46 @@
#include "plugins/dummy.h"
/**
- This function returns a protocol_t structure based on the mode
- of obfsproxy
+ This function initializes <protocol>.
+ It's called once in the runtime of the program for each proto.
*/
-struct protocol_t *
+int
set_up_protocol(int protocol) {
- struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
-
if (protocol == OBFS2_PROTOCOL)
- proto->new = &obfs2_new;
+ obfs2_init();
else if (protocol == DUMMY_PROTOCOL)
- proto->new = &dummy_new;
- /* elif { other protocols } */
-
- if (proto->new(proto)>0)
- printf("Protocol constructed\n");
+ dummy_init();
+ else
+ return -1;
- return proto;
+ return 1;
}
-void *
-proto_init(struct protocol_t *proto, void *arg) {
- assert(proto);
- if (proto->init)
- return proto->init(arg);
+/**
+ This function initializes a protocol. It creates a new
+ protocol_t structure and fills it's vtable etc.
+ Return the protocol_t if successful, NULL otherwise.
+*/
+struct protocol_t *
+proto_new(int protocol, int is_initiator) {
+ struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
+ if (!proto)
+ return NULL;
+
+ proto->vtable = calloc(1, sizeof(struct protocol_vtable));
+ if (!proto->vtable)
+ return NULL;
+
+ if (protocol == OBFS2_PROTOCOL) {
+ proto->proto = protocol;
+ proto->state = obfs2_new(proto, is_initiator);
+ } else if (protocol == DUMMY_PROTOCOL) {
+ proto->proto = protocol;
+ proto->state = dummy_new(proto, is_initiator);
+ }
+
+ if (proto->state)
+ return proto;
else
return NULL;
}
@@ -40,8 +56,8 @@ proto_init(struct protocol_t *proto, void *arg) {
int
proto_handshake(struct protocol_t *proto, void *buf) {
assert(proto);
- if (proto->handshake)
- return proto->handshake(proto->state, buf);
+ if (proto->vtable->handshake)
+ return proto->vtable->handshake(proto->state, buf);
else /* It's okay with me, protocol didn't have a handshake */
return 0;
}
@@ -49,8 +65,8 @@ proto_handshake(struct protocol_t *proto, void *buf) {
int
proto_send(struct protocol_t *proto, void *source, void *dest) {
assert(proto);
- if (proto->send)
- return proto->send(proto->state, source, dest);
+ if (proto->vtable->send)
+ return proto->vtable->send(proto->state, source, dest);
else
return -1;
}
@@ -58,8 +74,8 @@ proto_send(struct protocol_t *proto, void *source, void *dest) {
int
proto_recv(struct protocol_t *proto, void *source, void *dest) {
assert(proto);
- if (proto->recv)
- return proto->recv(proto->state, source, dest);
+ if (proto->vtable->recv)
+ return proto->vtable->recv(proto->state, source, dest);
else
return -1;
}
@@ -68,6 +84,6 @@ void proto_destroy(struct protocol_t *proto) {
assert(proto);
assert(proto->state);
- if (proto->destroy)
- proto->destroy(proto->state);
+ if (proto->vtable->destroy)
+ proto->vtable->destroy(proto->state);
}
diff --git a/src/protocol.h b/src/protocol.h
index 781bde0..7ec430c 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,40 +1,50 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
-/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
-#define DUMMY_PROTOCOL 0
+#define DUMMY_PROTOCOL 0
#define OBFS2_PROTOCOL 1
+struct evbuffer;
-struct protocol_t *set_up_protocol(int protocol);
-void *proto_init(struct protocol_t *proto, void *arg);
+int set_up_protocol(int protocol);
+struct protocol_t *proto_new(int protocol, int arg);
void proto_destroy(struct protocol_t *proto);
int proto_handshake(struct protocol_t *proto, void *buf);
int proto_send(struct protocol_t *proto, void *source, void *dest);
int proto_recv(struct protocol_t *proto, void *source, void *dest);
-
-/* ASN Why the hell do half of them return int? FIXME */
-struct protocol_t {
+typedef struct protocol_vtable {
/* Constructor: creates the protocol; sets up functions etc. */
- int (*new)(struct protocol_t *self);
+ int (*init)(struct protocol_t *self);
/* Destructor */
void (*destroy)(void *state);
/* does nessesary initiation steps; like build a proto state etc. */
- void *(*init)(void *arg);
+ void *(*create)(struct protocol_t *proto_struct,
+ int is_initiator);
/* does handshake. Supposedly all protocols have a handshake. */
- int (*handshake)(void *state, void *buf);
+ int (*handshake)(void *state,
+ struct evbuffer *buf);
/* send data function */
- int (*send)(void *state, void *source,
- void *dest);
+ int (*send)(void *state,
+ struct evbuffer *source,
+ struct evbuffer *dest);
/* receive data function */
- int (*recv)(void *state, void *source,
- void *dest);
+ int (*recv)(void *state,
+ struct evbuffer *source,
+ struct evbuffer *dest);
+} protocol_vtable;
+
+struct protocol_t {
+ /* protocol */
+ int proto;
+
+ /* protocol vtable */
+ protocol_vtable *vtable;
/* ASN do we need a proto_get_state()? */
void *state;
diff --git a/src/socks.c b/src/socks.c
index a3fb729..a1f794a 100644
--- a/src/socks.c
+++ b/src/socks.c
@@ -192,8 +192,6 @@ socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state,
/* We either failed or succeded.
Either way, we should send something back to the client */
p[0] = SOCKS5_VERSION; /* Version field */
- if (status == SOCKS5_REP_FAIL)
- printf("Sending negative shit\n");
p[1] = (unsigned char) status; /* Reply field */
p[2] = 0; /* Reserved */
if (state->parsereq.af == AF_UNSPEC) {
1
0
commit fc248868cf653e33cec3380a8631d4c682d85fd1
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Wed Apr 13 19:49:15 2011 +0200
Trivial documentation changes.
---
src/protocol.c | 5 +++--
src/protocol.h | 8 ++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/protocol.c b/src/protocol.c
index b95ab11..2195b29 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -25,8 +25,9 @@ set_up_protocol(int protocol) {
}
/**
- This function initializes a protocol. It creates a new
- protocol_t structure and fills it's vtable etc.
+ This function creates a protocol object. It's called once
+ for every connection. It creates a new protocol_t structure
+ and fills it's vtable etc.
Return the protocol_t if successful, NULL otherwise.
*/
struct protocol_t *
diff --git a/src/protocol.h b/src/protocol.h
index 7ec430c..dd34585 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -15,16 +15,16 @@ int proto_recv(struct protocol_t *proto, void *source, void *dest);
typedef struct protocol_vtable {
- /* Constructor: creates the protocol; sets up functions etc. */
+ /* Initialization function: Fills in the protocol vtable. */
int (*init)(struct protocol_t *self);
- /* Destructor */
+ /* Destructor: Destroys the protocol state. */
void (*destroy)(void *state);
- /* does nessesary initiation steps; like build a proto state etc. */
+ /* Constructor: Creates a protocol object. */
void *(*create)(struct protocol_t *proto_struct,
int is_initiator);
- /* does handshake. Supposedly all protocols have a handshake. */
+ /* does handshake. Not all protocols have a handshake. */
int (*handshake)(void *state,
struct evbuffer *buf);
1
0