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
- 213395 discussions

r24679: {projects} initial cleanups while reading also, it's 5 pages again (projects/articles/browser-privacy)
by Roger Dingledine 27 Apr '11
by Roger Dingledine 27 Apr '11
27 Apr '11
Author: arma
Date: 2011-04-27 01:08:34 +0000 (Wed, 27 Apr 2011)
New Revision: 24679
Modified:
projects/articles/browser-privacy/W3CIdentity.tex
Log:
initial cleanups while reading
also, it's 5 pages again
Modified: projects/articles/browser-privacy/W3CIdentity.tex
===================================================================
--- projects/articles/browser-privacy/W3CIdentity.tex 2011-04-26 15:06:46 UTC (rev 24678)
+++ projects/articles/browser-privacy/W3CIdentity.tex 2011-04-27 01:08:34 UTC (rev 24679)
@@ -31,12 +31,14 @@
There is a huge disconnect between how users perceive their online presence
and the reality of their relationship with the websites they visit. This
position paper explores this disconnect and provides some recommendations for
-making the technical reality of the web match user perception, through both
-technical improvements as well as user interface cues. We frame the core
-technical problem as one of ``linkability'' -- the level of correlation
+making the technical reality of the web match user perception. %, through both
+%technical improvements as well as user interface cues.
+We frame the core
+technical problem as one of ``linkability''---the level of correlation
between various online activities that the user naturally expects to be
independent. We look to address the issue of unexpected linkability through
-both improvements to the web's origin model, as well as through user interface
+both technical improvements to the web's origin model, as well as through
+user interface
cues about the set of accumulated identifiers that can be said to comprise
a user's online identity.
@@ -50,11 +52,12 @@
advertisement is relevant to the current activity, and if possible, relevant
to the current user.
-The cost of this is that user privacy on the web is a nightmare. There is
+The cost of this incentive structure is that user privacy on the web is a
+nightmare. There is
ubiquitous tracking, unseen partnership agreements and data exchange, and
surreptitious attempts to uncover users' identities against their will and
without their knowledge. This is not just happening in the dark, unseemly
-corners of the web. It is happening everywhere\cite{facebook-like}.
+corners of the web. It is happening everywhere~\cite{facebook-like}.
The problem is that the revenue model of the web has incentivized companies to
find ways to continue to track users against their will, even if those users
@@ -62,9 +65,9 @@
Starting with the infamous ``Flash cookies'', we have progressed through a
seemingly endless arms race of secondary identifiers and tracking information:
visited history, cache, font and system data, desktop resolution, keystroke
-timing, and so on and so forth\cite{wsj-fingerprinting}.
+timing, and so on and so forth~\cite{wsj-fingerprinting}.
-These efforts have lead to an even wider disconnect between a user's
+These efforts have led to an even wider disconnect between users'
perception of their privacy and the reality of their privacy. Users simply
can't keep up with the ways they are being tracked.
@@ -87,23 +90,25 @@
To this end, the rest of this document is structured as follows: First, we
-examine how the user perceives their privacy on the web, comparing the average
+examine how users perceive their privacy on the web, comparing the average
user's perspective to what actually is happening technically behind the
-scenes, and noting the major disconnects. We then examine solutions attempting
-to bridge this disconnect from two different directions, corresponding to the
+scenes, and noting the major disconnects. We then examine solutions that
+bridge this disconnect from two different directions, corresponding to the
two major sources of disconnect\footnotemark. The first direction is improving
the linkability issues inherent with the multi-origin model of the web itself.
The second direction is improving user cues and browser interface to suggest a
-coherent concept of identity to the user, which more accurately reflects the
+coherent concept of identity to the user by accurately reflecting the
set of unique identifiers they have accumulated. Both of these directions can
be pursued independently.
+% "the user" is not the thing that "accurately reflects". 'which' is a
+% klunky term here. -RD
\footnotetext{We only consider implementations that involve privacy-by-design.
Privacy-by-policy approaches such as Do Not Track will not be discussed.}
\section{User Privacy on the Web}
-To properly examine the privacy problem, we must probe both the average user's
+To properly examine the privacy problem, we must probe both the average users'
perception of what their ``web identity'' is, as well as the technical
realities of web authentication and tracking.
@@ -111,12 +116,13 @@
Instinctively, users define their privacy in terms of their identity: in terms
of how they have interacted with a site in order to inform it of who they are.
-Typically, the user's perception of their identity on the web is usually a direct
+Typically, the users' perception of their identity on the web is usually a direct
function of the identifiers used for strong authentication for particular sites.
For example, users expect that logging in to Facebook creates a relationship
in their browsers when facebook.com is present in the URL bar, but they are
-typically not aware that this also extends to their activity on other, arbitrary
+typically not aware that this relationship also extends to their activity
+on other, arbitrary
sites that happen to include ``Like this on Facebook'' buttons or
Facebook-sourced advertising content.
@@ -141,15 +147,16 @@
Auth tokens, and client TLS certificates. However, this identifier-based
approach breaks down quickly on the modern web. High-security websites are
already using fingerprinting as an auxiliary second factor of
-authentication\cite{security-fingerprinting}, and online data aggregators
+authentication~\cite{security-fingerprinting}, and online data aggregators
utilize everything they can to build complete portraits of users'
-identities\cite{tracking-identity}.
+identities~\cite{tracking-identity}.
Despite what the user may believe, their actual web identity then is a
superset of all the stored identifiers and authentication tokens used by the
browser. It is the ability to link a user's activity in one instance to their
activity in another instance, be it across time, or even on the very same page
due to multiple content origins.
+% 'It'? Their web identity is the ability to link...? -RD
Therefore, instead of viewing the user's identity as the sum of their
identifiers, or as their relationship to individual websites, it is best to
@@ -159,12 +166,12 @@
\subsection{User Privacy as Linkability}
In terms of what the user actually expects, user privacy is more accurately
-modeled as the level of linkability between subsequent actions on the web, as
-opposed to the mere sum of their unique identifiers and authentication tokens.
+modeled as the level of linkability between subsequent actions on the web---not
+just the sum of her unique identifiers and authentication tokens.
When privacy is expanded to cover all items that enable or substantially
contribute to linkability, a lot more components of the browser are now in
-scope. We will briefly enumerate these components.
+scope. We will briefly enumerate these four categories of components.
First, the obvious properties are found in the state of the browser: cookies,
DOM storage, cache, cryptographic tokens and cryptographic state, and
@@ -192,7 +199,7 @@
various browser properties that extend beyond any stored origin-related state.
The Panopticlick project by the EFF provides us with exactly this
-metric\cite{panopticlick}. The researchers conducted a survey of volunteers
+metric~\cite{panopticlick}. The researchers conducted a survey of volunteers
who were asked to visit an experiment page that harvested many of the above
components. They then computed the Shannon entropy of the resulting
distribution of each of several key attributes to determine how many bits of
@@ -201,7 +208,7 @@
While not perfect\footnotemark, this metric allows us to prioritize our efforts
on the
components that have the most potential for linkability.
-
+%
\footnotetext{In particular, the test does not take in all aspects of
resolution information. It did not calculate the size of widgets, window
decoration, or toolbar size. We believe these resolution-related properties
@@ -209,19 +216,20 @@
measure clock offset and other time-based fingerprints. Furthermore, as new
browser features are added, the experiment should be repeated to include
them.}
-
-This metric also indicates that it is beneficial to standardize on
+%
+It also shows the benefits of standardizing on
implementations of fingerprinting resistance where possible. More
implementations using the same defenses means more users with similar
fingerprints, which means less entropy in the metric. Similarly, uniform
-feature deployment leads to less entropy in the metric.
+feature deployment leads to less entropy.
\section{Matching User Perception with Reality}
For users to have privacy, and for private browsing modes to function, the
relationship between a user and a site must be understood by that user.
-
-It is apparent that the user experiences disconnect with the technical
+%
+%It is apparent that
+Users experience disconnects with the technical
realities of the web on two major fronts: the average user does not grasp the
privacy implications of the multi-origin model, nor are they given a clear
concept of browser identity to grasp the privacy implications of the union
@@ -236,7 +244,7 @@
The current identifier origin model used by the web is fundamentally flawed
when viewed from the perspective of meeting the expectations of the user.
Unique, globally linkable identifiers can be transmitted for arbitrary content
-elements on any page, which can be sourced from anywhere without user
+elements on any page, and they can be sourced from anywhere without user
interaction or awareness.
However, the behavior of identifiers and linkable attributes can be improved
@@ -246,26 +254,26 @@
content origin. Where linkability attributes exist, they should be obfuscated
on a per-origin basis.
-An early relevant example of this idea is SafeCache\cite{safecache}.
+An early relevant example of this idea is SafeCache~\cite{safecache}.
SafeCache seeks to reduce the ability for third-party content elements to use
the cache to store identifiers. It does this by limiting the scope of the
-cache to the top-level origin in the URL bar. This has the effect that
-commonly sourced content elements are fetched and cached repeatedly, but this
+cache to the top-level origin in the URL bar. Commonly sourced content
+elements are then fetched and cached repeatedly, but this
is necessary to prevent linkability: each of these content elements can be
crafted to include an identifier unique to each user, thus tracking users who
attempt to avoid tracking by clearing normal cookies.
The Mozilla development wiki describes an origin model improvement for
cookie transmission
-written by Dan Witte\cite{thirdparty}. Dan describes a new
+written by Dan Witte~\cite{thirdparty}. He describes a new
dual-keyed origin for cookies, so that cookies would only be transmitted if
-they matched both the top-level origin and the third-party origin involved in
+they match both the top-level origin and the third-party origin involved in
their creation. This approach would go a long way towards preventing implicit
tracking across multiple websites, and has some interesting properties that
make user interaction with content elements more explicitly tied to the
current site.
% XXXX I can't tell what this paragraph is supposed to mean. --RR
-
+%
Similarly, one could imagine this two-level dual-keyed origin isolation being
deployed to improve similar issues with DOM Storage and cryptographic tokens.
@@ -292,7 +300,7 @@
amenable to improvement under this model. In particular, one can imagine
per-origin plugin loading permissions, per-origin limits on the number of
fonts that can be used, and randomized window-specific time offsets.
-
+%
So, while these approaches are in fact useful for bringing the technical
realities of the web closer to what the user assumes is happening, they must
be deployed uniformly, with a consistent top-level origin restriction model.
@@ -305,9 +313,9 @@
Even if the origin model of identifier transmission and other linkable
attributes is altered uniformly to be more in line with what users expect, it
is likely that the average user will still experience privacy benefits if the
-browser conveys the sum of all linkable information as a single, storable,
+browser conveys the sum of all linkable information as a single storable,
mutable, and clearable user identity.
-
+%
Providing this concept of identity to the user is also simpler than origin
improvements, as it does not require extensive compatibility testing or
standards coordination.
@@ -321,34 +329,34 @@
The better UI appears to lead to less mode error (in which the user forgets
whether
private browsing is enabled) than other browsers' private browsing
-modes\cite{private-browsing}.
-% XXXX ‘mode error’?
+modes~\cite{private-browsing}.
-The Mozilla Weave project appears to be proposing an identity-oriented method
+The Mozilla Weave project~\cite{weave-manager} appears to be proposing
+an identity-oriented method
of managing, syncing, and storing authentication tokens, and also has use
-cases described for multiple users of a single browser\cite{weave-manager}. It
+cases described for multiple users of a single browser. It
is the closest idea on paper to what we envision as the way to bridge user
assumptions with reality.
We believe that the user interface of the browser should convey a sense of
persistent identity prominently to the user in the form of a visual cue. This
cue can either be an abstract image, graphic or theme (such as the user's
-choice of Firefox Persona\cite{firefox-personas}), or it can be a text area
+choice of Firefox Persona~\cite{firefox-personas}), or it can be a text area
with the user's current favored pseudonym. This idea of identity should then
be integrated with the browsing experience. Users should be able to click a
button to get a clean slate for a new identity, and should be able to log into
and out of password-protected stored identities, which would
-contain the entire state of the browser. This is the direction the Tor Project
-intends to head in with the Tor Browser Bundle\cite{not-to-toggle}.
-
+contain the entire state of the browser. The Tor Project is heading in
+this direction with the Tor Browser Bundle~\cite{not-to-toggle}.
+%
To this user, the Private Browsing Mode would be no more than a special case
-of this identity UI - a special identity that they can trust not to store
+of this identity UI---a special identity that they can trust not to store
browsing history information to disk. Such a UI also more explicitly captures
what is going on with respect to the user's relationship to the web.
However, all current private browsing modes fall short of protecting against a
network-level adversary and fail to deal with linkability against such an
-adversary\cite{private-browsing}, claiming that it is outside their threat
+adversary~\cite{private-browsing}, claiming that it is outside their threat
model\footnotemark. If the user is given a new identity that is still linkable
to the previous one due to shortcomings of the browser, this approach has
failed as a privacy measure.
@@ -358,10 +366,11 @@
network-level
adversary is IP-address linkability. However, we believe this to be a red
herring. Users are quite capable of using alternate Internet connections, and
-it is common practice for ISPs in many parts of the world to rotate user IP
+it is common practice for ISPs (especially cellular IP networks)
+%in many parts of the world
+to rotate user IP
addresses daily, to discourage users from operating servers and to impede the
-spread of malware.
-This is especially true of cellular IP networks.}
+spread of malware.}
Linkability solutions within the identity framework would be similar to the
origin model solutions, except they would be properties of the entire browser
@@ -369,18 +378,19 @@
\section{Conclusions}
-The appeal of the prevailing revenue model of the web and the difficulties
+The appeal of the web's prevailing revenue model and the difficulties
associated with altering browser behavior have lulled us into accepting user
deception as the norm for web use. The average user completely lacks the
understanding needed to grasp how web tracking is carried out. This disconnect
-in understanding is extreme to the point where moral issues arise about the
+%in understanding
+is extreme to the point where moral issues arise about the
level of consent actually involved in web use and associated tracking.
In fact, standardization efforts seemed to realize this problem early on but
failed to create a feasible recommendations for improving the situation. RFC
2965 governing HTTP State Management mandated in section 3.3.6 that
third-party origins must not cause the browser to transmit cookies unless the
-interaction is ``verifiable'' and readily apparent to the user\cite{rfc2965}.
+interaction is ``verifiable'' and readily apparent to the user~\cite{rfc2965}.
In section 6, it also strongly suggested that informed consent and user
control should govern the interaction of users to tracking identifiers.
@@ -396,7 +406,8 @@
\bibliographystyle{plain} \bibliography{W3CIdentity}
-\clearpage
-\appendix
+%\clearpage
+%\appendix
\end{document}
+
1
0

[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