Files
shadowsocks-android/jni/obfsproxy/protocols/obfs2.c
T

680 lines
19 KiB
C

/* Copyright 2011 Nick Mathewson, George Kadianakis
See LICENSE for other credits and copying information
*/
/**
* \file obfs2.c
* \headerfile obfs2.h
* \brief Implements the 'obfs2' pluggable transport.
*
* \details We track the state of the obfs2 protocol in the
* <b>state</b> member of <b>obfs2_state_t</b>.
*
* The first step of the obfs2 protocol, is to send the handshake
* message (obfs2_handshake()) and move to the initial state which is
* <em>ST_WAIT_FOR_KEY</em>.
*
* During <em>ST_WAIT_FOR_KEY</em>, we are waiting for the key of our
* peer. obfs2_recv() is responsible for picking up the key from our
* peer's handshake message, deriving additional keys out of it
* (init_crypto()), and progressing to the <em>ST_WAIT_FOR_PADDING</em> state.
*
* During <em>ST_WAIT_FOR_PADDING</em>, we are waiting for the amount
* of padding that our peer promised in his handshake message. When we
* receive the padding, we move to the final state <em>ST_OPEN</em>
* and start exchanging data messages with our peer using the derived
* keys.
**/
#include "util.h"
#define PROTOCOL_OBFS2_PRIVATE
#include "obfs2.h"
#include <event2/buffer.h>
/* type-safe downcast wrappers */
static inline obfs2_config_t *
downcast_config(config_t *p)
{
return DOWNCAST(obfs2_config_t, super, p);
}
static inline obfs2_conn_t *
downcast_conn(conn_t *p)
{
return DOWNCAST(obfs2_conn_t, super, p);
}
static inline obfs2_circuit_t *
downcast_circuit(circuit_t *p)
{
return DOWNCAST(obfs2_circuit_t, super, p);
}
static int parse_and_set_options(int n_options,
const char *const *options,
obfs2_config_t *params);
static obfs2_state_t *state_create(config_t *p);
static void obfs2_destroy(obfs2_state_t *state);
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
static inline int
seed_nonzero(const uchar *seed)
{
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;
}
static inline obfs2_state_t *
get_state_from_conn(conn_t *conn)
{
return downcast_circuit(conn->circuit)->state;
}
static void
obfs2_config_free(config_t *c)
{
obfs2_config_t *cfg = downcast_config(c);
if (cfg->listen_addr)
evutil_freeaddrinfo(cfg->listen_addr);
if (cfg->target_addr)
evutil_freeaddrinfo(cfg->target_addr);
free(cfg);
}
/*
This function parses 'options' and fills the protocol parameters
structure 'params'.
Returns 0 on success, -1 on fail.
*/
static config_t *
obfs2_config_create(int n_options, const char *const *options)
{
obfs2_config_t *cfg = xzalloc(sizeof(obfs2_config_t));
cfg->super.vtable = &obfs2_vtable;
if (parse_and_set_options(n_options, options, cfg) == 0)
return &cfg->super;
obfs2_config_free(&cfg->super);
log_warn("You failed at creating a correct obfs2 line.\n"
"obfs2 syntax:\n"
"\tobfs2 [obfs2_args] obfs2_opts\n"
"\t'obfs2_opts':\n"
"\t\tmode ~ server|client|socks\n"
"\t\tlisten address ~ host:port\n"
"\t'obfs2_args':\n"
"\t\tDestination Address ~ --dest=host:port\n"
"\t\tShared Secret ~ --shared-secret=<secret>\n"
"\tExample:\n"
"\tobfsproxy obfs2 --dest=127.0.0.1:666 --shared-secret=himitsu "
"server 127.0.0.1:1026");
return NULL;
}
/**
Populate a config_t for a managed proxy listener.
*/
static config_t *
obfs2_config_create_managed(int is_server, const char *protocol,
const char *bindaddr, const char *orport)
{
const char* defport;
obfs2_config_t *cfg = xzalloc(sizeof(obfs2_config_t));
cfg->super.vtable = &obfs2_vtable;
if (is_server) {
defport = "11253"; /* 2bf5 */
cfg->mode = LSN_SIMPLE_SERVER;
} else {
defport = "23548"; /* 5bf5 */
cfg->mode = LSN_SOCKS_CLIENT;
}
cfg->listen_addr = resolve_address_port(bindaddr, 1, 1, defport);
if (!cfg->listen_addr)
goto err;
if (is_server) {
cfg->target_addr = resolve_address_port(orport, 1, 0, NULL);
if (!cfg->target_addr)
goto err;
}
return &cfg->super;
err:
obfs2_config_free(&cfg->super);
return NULL;
}
/**
Helper: Parses 'options' and fills 'cfg'.
*/
int
parse_and_set_options(int n_options, const char *const *options,
obfs2_config_t *cfg)
{
int options_left = n_options;
int got_dest=0;
int got_ss=0;
const char* defport;
if ((n_options < 2) || (n_options > 4)) {
log_warn("obfs2: wrong number of options: %d", n_options);
return -1;
}
/* Now parse the optional arguments */
while (options_left && !strncmp(*options,"--",2)) {
if (!strncmp(*options,"--dest=",7)) {
if (got_dest)
return -1;
cfg->target_addr =
resolve_address_port(*options+7, 1, 0, NULL);
if (!cfg->target_addr)
return -1;
got_dest=1;
} else if (!strncmp(*options,"--shared-secret=",16)) {
digest_t *c;
if (got_ss)
return -1;
c = digest_new();
digest_update(c, (uchar*)*options+16, strlen(*options+16));
digest_getdigest(c, cfg->shared_secret, SHARED_SECRET_LENGTH);
digest_free(c);
got_ss=1;
} else {
log_warn("obfs2: Unknown argument '%s'.", *options);
return -1;
}
options_left--;
options++;
}
/* we still need to parse the mode and the listen address. */
if (options_left != 2) {
log_warn("obfs2 needs two options (mode, listen address), after its "
"optional arguments. You provided %d.", options_left);
return -1;
}
if (!strcmp(*options, "client")) {
defport = "48988"; /* bf5c */
cfg->mode = LSN_SIMPLE_CLIENT;
} else if (!strcmp(*options, "socks")) {
defport = "23548"; /* 5bf5 */
cfg->mode = LSN_SOCKS_CLIENT;
} else if (!strcmp(*options, "server")) {
defport = "11253"; /* 2bf5 */
cfg->mode = LSN_SIMPLE_SERVER;
} else {
log_warn("obfs2: only client/socks/server modes supported.");
return -1;
}
options++;
cfg->listen_addr = resolve_address_port(*options, 1, 1, defport);
if (!cfg->listen_addr)
return -1;
/* Validate option selection. */
if (got_dest && (cfg->mode == LSN_SOCKS_CLIENT)) {
log_warn("obfs2: You can't be on socks mode and have --dest.");
return -1;
}
if (!got_dest && (cfg->mode != LSN_SOCKS_CLIENT)) {
log_warn("obfs2: client/server mode needs --dest.");
return -1;
}
log_debug("obfs2: Parsed options nicely!");
return 0;
}
/** Retrieve the 'n'th set of listen addresses for this configuration. */
static struct evutil_addrinfo *
obfs2_config_get_listen_addrs(config_t *cfg, size_t n)
{
if (n > 0)
return 0;
return downcast_config(cfg)->listen_addr;
}
/* Retrieve the target address for this configuration. */
static struct evutil_addrinfo *
obfs2_config_get_target_addr(config_t *cfg)
{
return downcast_config(cfg)->target_addr;
}
/*
This is called everytime we get a connection for the obfs2
protocol.
*/
static conn_t *
obfs2_conn_create(config_t *cfg)
{
obfs2_conn_t *conn = xzalloc(sizeof(obfs2_conn_t));
conn->super.cfg = cfg;
conn->super.mode = downcast_config(cfg)->mode;
return &conn->super;
}
static void
obfs2_conn_free(conn_t *conn)
{
free(downcast_conn(conn));
}
static circuit_t *
obfs2_circuit_create(config_t *cfg)
{
obfs2_circuit_t *circuit = xzalloc(sizeof(obfs2_circuit_t));
circuit->state = state_create(cfg);
return &circuit->super;
}
static void
obfs2_circuit_free(circuit_t *circuit)
{
obfs2_circuit_t *obfs2_circuit = downcast_circuit(circuit);
obfs2_destroy(obfs2_circuit->state);
free(obfs2_circuit);
}
/**
Derive and return key of type 'keytype' from the seeds currently set in
'state'.
*/
static crypt_t *
derive_key(obfs2_state_t *state, const char *keytype)
{
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
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 (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 (shared_seed_nonzero(state->secret_seed)) {
digest_t *d;
int i;
for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
d = digest_new();
digest_update(d, buf, sizeof(buf));
digest_getdigest(d, buf, sizeof(buf));
digest_free(d);
}
}
cryptstate = crypt_new(buf, 16);
crypt_set_iv(cryptstate, buf+16, 16);
memset(buf, 0, sizeof(buf));
digest_free(c);
return cryptstate;
}
/**
Derive and return padding key of type 'keytype' from the seeds
currently set in state 's'.
*/
static crypt_t *
derive_padding_key(obfs2_state_t *state, const uchar *seed,
const char *keytype)
{
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
digest_t *c = digest_new();
digest_update(c, (uchar*)keytype, strlen(keytype));
if (seed_nonzero(seed))
digest_update(c, seed, OBFUSCATE_SEED_LENGTH);
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 (shared_seed_nonzero(state->secret_seed)) {
digest_t *d;
int i;
for (i=0; i < OBFUSCATE_HASH_ITERATIONS; i++) {
d = digest_new();
digest_update(d, buf, sizeof(buf));
digest_getdigest(d, buf, sizeof(buf));
digest_free(d);
}
}
cryptstate = crypt_new(buf, 16);
crypt_set_iv(cryptstate, buf+16, 16);
memset(buf, 0, 16);
return cryptstate;
}
/**
This is called everytime we get a connection for the obfs2
protocol.
*/
static obfs2_state_t *
state_create(config_t *p)
{
obfs2_config_t *cfg = downcast_config(p);
obfs2_state_t *state = xzalloc(sizeof(obfs2_state_t));
uchar *seed;
const char *send_pad_type;
state->state = ST_WAIT_FOR_KEY;
state->we_are_initiator = (cfg->mode != LSN_SIMPLE_SERVER);
if (state->we_are_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 */
memcpy(state->secret_seed, cfg->shared_secret, SHARED_SECRET_LENGTH);
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);
return state;
}
/**
Frees obfs2 state 's'
*/
static void
obfs2_destroy(obfs2_state_t *state)
{
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);
}
/**
Write the initial protocol setup and padding message for state 's' to
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
static int
obfs2_handshake(conn_t *s, struct evbuffer *buf)
{
obfs2_state_t *state = get_state_from_conn(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) )
*/
obfs_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);
log_debug("obfs2_handshake: %s queued %lu bytes",
state->we_are_initiator ? "initiator" : "responder",
(unsigned long)evbuffer_get_length(buf));
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
obfs2_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);
evbuffer_add(dest, data, n);
log_debug("%s: Processed %d bytes.", __func__, 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(conn_t *s,
struct evbuffer *source, struct evbuffer *dest)
{
obfs2_state_t *state = get_state_from_conn(s);
if (state->send_crypto) {
/* First of all, send any data that we've been waiting to send. */
if (state->pending_data_to_send) {
log_debug("%s: transmitting %lu bytes previously queued.", __func__,
(unsigned long)evbuffer_get_length(state->pending_data_to_send));
obfs2_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;
}
/* Our crypto is set up; just relay the bytes */
if (evbuffer_get_length(source)) {
log_debug("%s: transmitting %lu bytes.", __func__,
(unsigned long)evbuffer_get_length(source));
}
return obfs2_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)) {
log_debug("%s: handshake incomplete, queueing %lu bytes.", __func__,
(unsigned long)evbuffer_get_length(source));
if (! state->pending_data_to_send) {
if ((state->pending_data_to_send = evbuffer_new()) == NULL)
return -1;
}
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 void
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);
}
/* Called when we receive data in an evbuffer 'source': deobfuscates that data
* and writes it to 'dest', by using protocol state 's' to get crypto keys.
*
* It returns:
* RECV_GOOD to say that everything went fine.
* RECV_BAD to say that something went bad.
* RECV_INCOMPLETE to say that we need more data to form an opinion.
* RECV_SEND_PENDING to say that everything went fine and on top of
* that we also have pending data that we have to send. This notifies
* our callers that they must call obfs2_send() immediately.
*/
static enum recv_ret
obfs2_recv(conn_t *s, struct evbuffer *source,
struct evbuffer *dest)
{
obfs2_state_t *state = get_state_from_conn(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) {
log_debug("%s: waiting for key, %lu/%u bytes so far",
__func__, (unsigned long)evbuffer_get_length(source),
OBFUSCATE_SEED_LENGTH+8);
/* data not here yet */
return RECV_INCOMPLETE;
}
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 */
init_crypto(state);
/* 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 RECV_BAD;
if (plength > OBFUSCATE_MAX_PADDING)
return RECV_BAD;
/* 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. */
log_debug("%s: received key, expecting %d bytes of padding",
__func__, 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 RECV_INCOMPLETE;
if ((size_t) n > sourcelen)
n = sourcelen;
evbuffer_drain(source, n);
state->padding_left_to_read -= n;
log_debug("%s: consumed %d bytes padding, %d still to come",
__func__, n, state->padding_left_to_read);
}
/* Okay; now we're definitely open. Process whatever data we have. */
state->state = ST_OPEN;
log_debug("%s: Processing %lu bytes application data",
__func__, (unsigned long)evbuffer_get_length(source));
obfs2_crypt_and_transmit(state->recv_crypto, source, dest);
/* If we have pending data to send, transmit it now. */
if (state->pending_data_to_send)
return RECV_SEND_PENDING;
return RECV_GOOD;
}
DEFINE_PROTOCOL_VTABLE(obfs2);