[tor-commits] [obfsproxy/master] Allow protocols to allocate extra state for their protocol_params_t as well as their protocol_t. Use this to remove the obfs2 shared secret from the generic protocol_params_t.
nickm at torproject.org
nickm at torproject.org
Fri Sep 9 17:08:56 UTC 2011
commit ebd15e8027e89ca3027c2ffc2c629a8a552cb772
Author: Zack Weinberg <zackw at panix.com>
Date: Sun Jul 24 13:49:51 2011 -0700
Allow protocols to allocate extra state for their protocol_params_t as well as their protocol_t. Use this to remove the obfs2 shared secret from the generic protocol_params_t.
---
src/protocol.c | 15 ++++--
src/protocol.h | 62 +++++++++++------------
src/protocols/dummy.c | 7 +++
src/protocols/obfs2.c | 131 ++++++++++++++++++++++++++----------------------
src/protocols/obfs2.h | 6 ++-
5 files changed, 122 insertions(+), 99 deletions(-)
diff --git a/src/protocol.c b/src/protocol.c
index 8cd069e..212ddaa 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -52,14 +52,19 @@ void
proto_params_free(protocol_params_t *params)
{
obfs_assert(params);
+ obfs_assert(params->vtable);
+ obfs_assert(params->vtable->fini);
- if (params->target_addr)
+ if (params->target_addr) {
evutil_freeaddrinfo(params->target_addr);
- if (params->listen_addr)
+ params->target_addr = NULL;
+ }
+ if (params->listen_addr) {
evutil_freeaddrinfo(params->listen_addr);
- if (params->shared_secret)
- free(params->shared_secret);
- free(params);
+ params->listen_addr = NULL;
+ }
+
+ params->vtable->fini(params);
}
/**
diff --git a/src/protocol.h b/src/protocol.h
index 6fa3eb4..c1189ea 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -11,39 +11,28 @@
struct evbuffer;
/**
- This struct defines parameters of a protocol on a per-listener basis.
-
- By 'per-listener basis' I mean that the parameters defined here will
- be inherited by *all* connections opened from the listener_t that
- owns this protocol_params_t.
-*/
+ This struct defines the protocol-specific state for all connections
+ opened from a particular listener. Each protocol may extend this
+ structure with additional private data by embedding it as the first
+ member of a larger structure (standard fake-inheritance-in-C
+ technique).
+ */
typedef struct protocol_params_t {
const struct protocol_vtable *vtable;
struct evutil_addrinfo *target_addr;
struct evutil_addrinfo *listen_addr;
- char *shared_secret;
- size_t shared_secret_len;
int mode;
} protocol_params_t;
/**
- This protocol specific struct defines the state of the protocol
- on a per-connection basis.
-
- By 'protocol specific' I mean that every protocol has its own
- state struct. (for example, obfs2 has obfs2_state_t). A protocol_t
- struct is always the first member of this struct, and vtable->create
- returns that member (standard fake-inheritance-in-C technique).
- All data other than the vtable is hidden from everything but the
- protocol implementation.
-
- By 'per-connection basis' I mean that the every connection has a
- different protocol_t struct, and that's precisely the reason that
- this struct is owned by the conn_t struct.
+ This struct defines the protocol-specific state for a particular
+ connection. Again, each protocol may extend this structure with
+ additional private data by embedding it as the first member of a
+ larger structure.
*/
-struct protocol_t {
+typedef struct protocol_t {
const struct protocol_vtable *vtable;
-};
+} protocol_t;
/**
This struct defines a protocol and its methods; note that not all
@@ -58,23 +47,29 @@ typedef struct protocol_vtable
/** The short name of this protocol. */
const char *name;
- /** Initialization function: Allocate a 'protocol_params_t' object
- and fill it in from the provided 'options' array. */
- struct protocol_params_t *(*init)(int n_options,
- const char *const *options);
+ /** Initialization: Allocate a 'protocol_params_t' object and fill
+ it in from the provided 'options' array. */
+ protocol_params_t *(*init)(int n_options, const char *const *options);
+
+ /** Finalization: Destroy the provided 'protocol_params_t' object.
+ This function is responsible for deallocating any data that the
+ protocol's extended structure points to, and deallocating the
+ object itself. But it is *not* responsible for deallocating the
+ data pointed to by the generic 'protocol_params_t'; that's
+ already been done. */
+ void (*fini)(protocol_params_t *params);
/** Constructor: Allocates per-connection, protocol-specific state. */
- struct protocol_t *(*create)(struct protocol_params_t *params);
+ protocol_t *(*create)(protocol_params_t *params);
/** Destructor: Destroys per-connection, protocol-specific state. */
- void (*destroy)(struct protocol_t *state);
+ void (*destroy)(protocol_t *state);
/** Perform a connection handshake. Not all protocols have a handshake. */
- int (*handshake)(struct protocol_t *state,
- struct evbuffer *buf);
+ int (*handshake)(protocol_t *state, struct evbuffer *buf);
/** Send data coming downstream from 'source' along to 'dest'. */
- int (*send)(struct protocol_t *state,
+ int (*send)(protocol_t *state,
struct evbuffer *source,
struct evbuffer *dest);
@@ -93,7 +88,8 @@ typedef struct protocol_vtable
#define DEFINE_PROTOCOL_VTABLE(name) \
const struct protocol_vtable name##_vtable = { \
#name, \
- name##_init, name##_create, name##_destroy, \
+ name##_init, name##_fini, \
+ name##_create, name##_destroy, \
name##_handshake, name##_send, name##_recv \
}
diff --git a/src/protocols/dummy.c b/src/protocols/dummy.c
index c12fe01..ae45d9c 100644
--- a/src/protocols/dummy.c
+++ b/src/protocols/dummy.c
@@ -29,6 +29,7 @@ dummy_init(int n_options, const char *const *options)
{
struct protocol_params_t *params
= xzalloc(sizeof(struct protocol_params_t));
+ params->vtable = &dummy_vtable;
if (parse_and_set_options(n_options, options, params) < 0) {
proto_params_free(params);
@@ -87,6 +88,12 @@ usage(void)
"\tobfsproxy dummy socks 127.0.0.1:5000");
}
+static void
+dummy_fini(struct protocol_params_t *params)
+{
+ free(params);
+}
+
/*
This is called everytime we get a connection for the dummy
protocol.
diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c
index 42d30c1..f7862fe 100644
--- a/src/protocols/obfs2.c
+++ b/src/protocols/obfs2.c
@@ -16,13 +16,22 @@
static void usage(void);
static int parse_and_set_options(int n_options,
const char *const *options,
- struct protocol_params_t *params);
+ obfs2_params_t *params);
-static inline obfs2_protocol_t *
-downcast(struct protocol_t *proto)
+/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
+static inline int
+seed_nonzero(const uchar *seed)
{
- return (obfs2_protocol_t *)
- ((char *)proto - offsetof(obfs2_protocol_t, super));
+ static const uchar OBFUSCATE_ZERO_SEED[OBFUSCATE_SEED_LENGTH] = {0};
+ return memcmp(seed, OBFUSCATE_ZERO_SEED, OBFUSCATE_SEED_LENGTH) != 0;
+}
+
+/** Return true iff the SHARED_SECRET_LENGTH-byte seed in 'seed' is nonzero */
+static inline int
+shared_seed_nonzero(const uchar *seed)
+{
+ static const uchar SHARED_ZERO_SEED[SHARED_SECRET_LENGTH] = {0};
+ return memcmp(seed, SHARED_ZERO_SEED, SHARED_SECRET_LENGTH) != 0;
}
/*
@@ -31,19 +40,19 @@ downcast(struct protocol_t *proto)
Returns 0 on success, -1 on fail.
*/
-static struct protocol_params_t *
+static protocol_params_t *
obfs2_init(int n_options, const char *const *options)
{
- struct protocol_params_t *params
- = xzalloc(sizeof(struct protocol_params_t));
+ obfs2_params_t *params = xzalloc(sizeof(obfs2_params_t));
+ params->super.vtable = &obfs2_vtable;
if (parse_and_set_options(n_options, options, params) < 0) {
- proto_params_free(params);
+ proto_params_free(¶ms->super);
usage();
return NULL;
}
- return params;
+ return ¶ms->super;
}
/**
@@ -51,7 +60,7 @@ obfs2_init(int n_options, const char *const *options)
*/
int
parse_and_set_options(int n_options, const char *const *options,
- struct protocol_params_t *params)
+ obfs2_params_t *params)
{
int got_dest=0;
int got_ss=0;
@@ -67,17 +76,23 @@ parse_and_set_options(int n_options, const char *const *options,
if (!strncmp(*options,"--dest=",7)) {
if (got_dest)
return -1;
- params->target_addr = resolve_address_port(*options+7, 1, 0, NULL);
- if (!params->target_addr)
+ params->super.target_addr =
+ resolve_address_port(*options+7, 1, 0, NULL);
+ if (!params->super.target_addr)
return -1;
got_dest=1;
} else if (!strncmp(*options,"--shared-secret=",16)) {
+ digest_t *c;
if (got_ss)
return -1;
- /* this is freed in proto_params_free() */
- params->shared_secret_len = strlen(*options+16);
- params->shared_secret = xmemdup(*options+16,
- params->shared_secret_len + 1);
+
+ /* ASN we must say in spec that we hash command line shared
+ secret. */
+ c = digest_new();
+ digest_update(c, (uchar*)*options+16, strlen(*options+16));
+ digest_getdigest(c, params->shared_secret, SHARED_SECRET_LENGTH);
+ digest_free(c);
+
got_ss=1;
} else {
log_warn("obfs2: Unknown argument.");
@@ -88,37 +103,36 @@ parse_and_set_options(int n_options, const char *const *options,
if (!strcmp(*options, "client")) {
defport = "48988"; /* bf5c */
- params->mode = LSN_SIMPLE_CLIENT;
+ params->super.mode = LSN_SIMPLE_CLIENT;
} else if (!strcmp(*options, "socks")) {
defport = "23548"; /* 5bf5 */
- params->mode = LSN_SOCKS_CLIENT;
+ params->super.mode = LSN_SOCKS_CLIENT;
} else if (!strcmp(*options, "server")) {
defport = "11253"; /* 2bf5 */
- params->mode = LSN_SIMPLE_SERVER;
+ params->super.mode = LSN_SIMPLE_SERVER;
} else {
log_warn("obfs2: only client/socks/server modes supported.");
return -1;
}
options++;
- params->listen_addr = resolve_address_port(*options, 1, 1, defport);
- if (!params->listen_addr)
+ params->super.listen_addr = resolve_address_port(*options, 1, 1, defport);
+ if (!params->super.listen_addr)
return -1;
/* Validate option selection. */
- if (got_dest && (params->mode == LSN_SOCKS_CLIENT)) {
+ if (got_dest && (params->super.mode == LSN_SOCKS_CLIENT)) {
log_warn("obfs2: You can't be on socks mode and have --dest.");
return -1;
}
- if (!got_dest && (params->mode != LSN_SOCKS_CLIENT)) {
+ if (!got_dest && (params->super.mode != LSN_SOCKS_CLIENT)) {
log_warn("obfs2: client/server mode needs --dest.");
return -1;
}
log_debug("obfs2: Parsed options nicely!");
- params->vtable = &obfs2_vtable;
return 0;
}
@@ -142,13 +156,6 @@ usage(void)
"\tobfs2 server 127.0.0.1:1026");
}
-/** 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'.
@@ -166,12 +173,12 @@ derive_key(void *s, const char *keytype)
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))
+ if (shared_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));
- if (seed_nonzero(state->secret_seed)) {
+ if (shared_seed_nonzero(state->secret_seed)) {
digest_t *d;
int i;
for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
@@ -206,13 +213,13 @@ derive_padding_key(void *s, const uchar *seed,
digest_update(c, (uchar*)keytype, strlen(keytype));
if (seed_nonzero(seed))
digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
- if (seed_nonzero(state->secret_seed))
+ if (shared_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));
digest_free(c);
- if (seed_nonzero(state->secret_seed)) {
+ if (shared_seed_nonzero(state->secret_seed)) {
digest_t *d;
int i;
for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
@@ -230,22 +237,32 @@ derive_padding_key(void *s, const uchar *seed,
}
/**
+ Frees obfs2 parameters 'p'
+ */
+static void
+obfs2_fini(protocol_params_t *p)
+{
+ obfs2_params_t *params = DOWNCAST(obfs2_params_t, super, p);
+ /* wipe out keys */
+ memset(params, 0x99, sizeof(obfs2_params_t));
+ free(params);
+}
+
+
+/**
This is called everytime we get a connection for the obfs2
protocol.
-
- It sets up the protocol vtable in 'proto_struct' and then attempts
- to create and return a protocol state according to the protocol
- parameters 'params'.
*/
-static struct protocol_t *
-obfs2_create(protocol_params_t *params)
+static protocol_t *
+obfs2_create(protocol_params_t *p)
{
+ obfs2_params_t *params = DOWNCAST(obfs2_params_t, super, p);
obfs2_protocol_t *proto = xzalloc(sizeof(obfs2_protocol_t));
uchar *seed;
const char *send_pad_type;
proto->state = ST_WAIT_FOR_KEY;
- proto->we_are_initiator = (params->mode != LSN_SIMPLE_SERVER);
+ proto->we_are_initiator = (params->super.mode != LSN_SIMPLE_SERVER);
if (proto->we_are_initiator) {
send_pad_type = INITIATOR_PAD_TYPE;
seed = proto->initiator_seed;
@@ -255,19 +272,13 @@ obfs2_create(protocol_params_t *params)
}
/* Generate our seed */
+ memcpy(proto->secret_seed, params->shared_secret, SHARED_SECRET_LENGTH);
+
if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
free(proto);
return NULL;
}
- if (params->shared_secret) {
- /* ASN we must say in spec that we hash command line shared secret. */
- digest_t *c = digest_new();
- digest_update(c, (uchar*)params->shared_secret, params->shared_secret_len);
- digest_getdigest(c, proto->secret_seed, SHARED_SECRET_LENGTH);
- digest_free(c);
- }
-
/* Derive the key for what we're sending */
proto->send_padding_crypto = derive_padding_key(proto, seed, send_pad_type);
proto->super.vtable = &obfs2_vtable;
@@ -278,9 +289,9 @@ obfs2_create(protocol_params_t *params)
Frees obfs2 state 's'
*/
static void
-obfs2_destroy(struct protocol_t *s)
+obfs2_destroy(protocol_t *s)
{
- obfs2_protocol_t *state = downcast(s);
+ obfs2_protocol_t *state = DOWNCAST(obfs2_protocol_t, super, s);
if (state->send_crypto)
crypt_free(state->send_crypto);
if (state->send_padding_crypto)
@@ -301,9 +312,9 @@ obfs2_destroy(struct protocol_t *s)
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
static int
-obfs2_handshake(struct protocol_t *s, struct evbuffer *buf)
+obfs2_handshake(protocol_t *s, struct evbuffer *buf)
{
- obfs2_protocol_t *state = downcast(s);
+ obfs2_protocol_t *state = DOWNCAST(obfs2_protocol_t, super, s);
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
@@ -367,10 +378,10 @@ obfs2_crypt_and_transmit(crypt_t *crypto,
using the state in 'state'. Returns 0 on success, -1 on failure.
*/
static int
-obfs2_send(struct protocol_t *s,
- struct evbuffer *source, struct evbuffer *dest)
+obfs2_send(protocol_t *s,
+ struct evbuffer *source, struct evbuffer *dest)
{
- obfs2_protocol_t *state = downcast(s);
+ obfs2_protocol_t *state = DOWNCAST(obfs2_protocol_t, super, s);
if (state->send_crypto) {
/* First of all, send any data that we've been waiting to send. */
@@ -440,10 +451,10 @@ init_crypto(void *s)
* our callers that they must call obfs2_send() immediately.
*/
static enum recv_ret
-obfs2_recv(struct protocol_t *s, struct evbuffer *source,
+obfs2_recv(protocol_t *s, struct evbuffer *source,
struct evbuffer *dest)
{
- obfs2_protocol_t *state = downcast(s);
+ obfs2_protocol_t *state = DOWNCAST(obfs2_protocol_t, super, s);
enum recv_ret r=0;
if (state->state == ST_WAIT_FOR_KEY) {
diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h
index e93fbcd..eb55a9f 100644
--- a/src/protocols/obfs2.h
+++ b/src/protocols/obfs2.h
@@ -25,7 +25,6 @@ extern const struct protocol_vtable obfs2_vtable;
#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 OBFUSCATE_HASH_ITERATIONS 100000
#define INITIATOR_PAD_TYPE "Initiator obfuscation padding"
@@ -35,6 +34,11 @@ extern const struct protocol_vtable obfs2_vtable;
#define SHARED_SECRET_LENGTH SHA256_LENGTH
+typedef struct obfs2_params_t {
+ protocol_params_t super;
+ uchar shared_secret[SHARED_SECRET_LENGTH];
+} obfs2_params_t;
+
typedef struct obfs2_protocol_t {
struct protocol_t super;
More information about the tor-commits
mailing list