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
April 2011
- 18 participants
- 883 discussions

r24680: {projects} finish light mucking. still 5 pages. i suggest a complete re (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:30:49 +0000 (Wed, 27 Apr 2011)
New Revision: 24680
Modified:
projects/articles/browser-privacy/W3CIdentity.tex
Log:
finish light mucking. still 5 pages.
i suggest a complete rewrite, first by picking several key points
you want to communicate, and then putting those points in the abstract,
and then expanding on them.
(topics you plan to talk about in the paper do not count as points.)
Modified: projects/articles/browser-privacy/W3CIdentity.tex
===================================================================
--- projects/articles/browser-privacy/W3CIdentity.tex 2011-04-27 01:08:34 UTC (rev 24679)
+++ projects/articles/browser-privacy/W3CIdentity.tex 2011-04-27 01:30:49 UTC (rev 24680)
@@ -97,11 +97,9 @@
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 by accurately reflecting the
+coherent concept of identity to users 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.}
@@ -142,7 +140,7 @@
pages. The default experience is such that all of this data exchange is
concealed from the user.
-So then what comprises the user's web identity for tracking purposes? In terms
+So then what comprises a user's web identity for tracking purposes? In terms
of authentication, it would at first appear to be limited to cookies, HTTP
Auth tokens, and client TLS certificates. However, this identifier-based
approach breaks down quickly on the modern web. High-security websites are
@@ -151,15 +149,14 @@
utilize everything they can to build complete portraits of users'
identities~\cite{tracking-identity}.
-Despite what the user may believe, their actual web identity then is a
+Despite what the user may believe, her 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
+browser. This identity can link a user's activity in one instance to her
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
+Therefore, instead of viewing the user's identity as the sum of her
+identifiers, or as her relationship to individual websites, it is best to
view it as the ability to link activity from one website to activity in
another website. We will call this property ``user linkability''.
@@ -231,12 +228,12 @@
%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
+privacy implications of the multi-origin model, nor is she given a clear
concept of browser identity to grasp the privacy implications of the union
-of the linkable components of their browsers.
+of the linkable components of her browser.
We will now examine examples of attempts at reducing this disconnect on each
-of these two fronts. Note that these to fronts are orthogonal. Approaches from
+of these two fronts. Note that these two fronts are orthogonal. Approaches from
them may be combined, or used independently.
\subsection{Improving the Origin Model}
@@ -260,7 +257,8 @@
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
+crafted to include an identifier unique to each user, thus tracking even
+users who
attempt to avoid tracking by clearing normal cookies.
The Mozilla development wiki describes an origin model improvement for
@@ -285,7 +283,7 @@
of that top level origin to represent all of the browser state accumulated by
that origin. The user could delete the entire set of browser state (cookies,
cache, storage, cryptographic tokens) associated with a site simply by
-removing its favicon from their privacy info panel.
+removing its favicon from her privacy info panel.
The problem with origin model improvement approaches is that individually,
they do not fully address the linkability problem unless the same
@@ -304,15 +302,16 @@
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.
-This may take significant coordination and standardization efforts. Without
-this, it is necessary to fill the remaining linkability gaps by presenting
-the user with a visual representation of their overall web identity.
+Uniform deployment will take significant coordination and standardization
+efforts. Until then,
+it is necessary to fill the remaining linkability gaps by presenting
+the user with a visual representation of her overall web identity.
\subsection{Conveying Identity to the User}
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
+attributes is altered uniformly to be more in line with what users expect,
+the average user can still experience privacy benefits if the
browser conveys the sum of all linkable information as a single storable,
mutable, and clearable user identity.
%
@@ -346,21 +345,24 @@
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. The Tor Project is heading in
-this direction with the Tor Browser Bundle~\cite{not-to-toggle}.
+contain the entire state of the browser.
%
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
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.
+The Tor Project is heading in this direction with the Tor Browser
+Bundle~\cite{not-to-toggle}.
-However, all current private browsing modes fall short of protecting against a
+Unfortunately, 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
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.
% XXXX Define network-level adversary.
+% I agree. You could do that here or in the footnote. -RD
\footnotetext{The primary reason given to abstain from addressing a
network-level
@@ -382,16 +384,15 @@
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
+is so extreme that it raises moral issues 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
+failed to create 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}.
-In section 6, it also strongly suggested that informed consent and user
+In Section~6, it also strongly suggested that informed consent and user
control should govern the interaction of users to tracking identifiers.
Without changes to browser behavior, browser interface, or both, such informed
@@ -400,6 +401,7 @@
the linkability issues with the web's origin model with minimal breakage.
Additionally, the first steps towards providing the user with an explicit
representation of their web identity have been taken.
+% Taken by who? Change to active tense. -RD
The pieces are in place to build robust private browsing modes based on these
two approaches, and metrics exist to measure their success.
1
0

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] * 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

[obfsproxy/master] Programs that run are more fun: Trivial #include edits
by nickm@torproject.org 27 Apr '11
by nickm@torproject.org 27 Apr '11
27 Apr '11
commit 52513eb4f7dac382655ea86dab8ec5207492c42e
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Wed Apr 27 02:12:02 2011 +0200
Programs that run are more fun: Trivial #include edits
---
src/protocol.c | 4 ++--
src/test/unittest.c | 2 +-
src/test/unittest_crypt.c | 2 +-
src/test/unittest_obfs2.c | 4 ++--
src/test/unittest_socks.c | 4 ++--
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/protocol.c b/src/protocol.c
index 2195b29..1fbd3f7 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -5,8 +5,8 @@
#include "protocol.h"
#include "network.h"
-#include "plugins/obfs2.h"
-#include "plugins/dummy.h"
+#include "protocols/obfs2.h"
+#include "protocols/dummy.h"
/**
This function initializes <protocol>.
diff --git a/src/test/unittest.c b/src/test/unittest.c
index 494e90b..41159ca 100644
--- a/src/test/unittest.c
+++ b/src/test/unittest.c
@@ -7,7 +7,7 @@
#include <stdlib.h>
#include "tinytest.h"
-#include "../plugins/obfs2_crypt.h"
+#include "../protocols/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 b624e15..5980636 100644
--- a/src/test/unittest_crypt.c
+++ b/src/test/unittest_crypt.c
@@ -12,7 +12,7 @@
#include <openssl/aes.h>
-#include "../plugins/obfs2_crypt.h"
+#include "../protocols/obfs2_crypt.h"
struct crypt_t {
AES_KEY key;
diff --git a/src/test/unittest_obfs2.c b/src/test/unittest_obfs2.c
index cdac4c9..f006b2f 100644
--- a/src/test/unittest_obfs2.c
+++ b/src/test/unittest_obfs2.c
@@ -17,10 +17,10 @@
#define CRYPT_PROTOCOL_PRIVATE
#define CRYPT_PRIVATE
-#include "../plugins/obfs2_crypt.h"
+#include "../protocols/obfs2_crypt.h"
#include "../util.h"
#include "../protocol.h"
-#include "../plugins/obfs2.h"
+#include "../protocols/obfs2.h"
/* Make sure we can successfully set up a protocol state */
static void
diff --git a/src/test/unittest_socks.c b/src/test/unittest_socks.c
index db91188..017e624 100644
--- a/src/test/unittest_socks.c
+++ b/src/test/unittest_socks.c
@@ -9,9 +9,9 @@
#define SOCKS_PRIVATE
#include "../socks.h"
-#include "../plugins/obfs2_crypt.h"
+#include "../protocols/obfs2_crypt.h"
#include "../util.h"
-#include "../plugins/obfs2.h"
+#include "../protocols/obfs2.h"
static void
test_socks_send_negotiation(void *data)
1
0
commit fc248868cf653e33cec3380a8631d4c682d85fd1
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Wed Apr 13 19:49:15 2011 +0200
Trivial documentation changes.
---
src/protocol.c | 5 +++--
src/protocol.h | 8 ++++----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/src/protocol.c b/src/protocol.c
index b95ab11..2195b29 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -25,8 +25,9 @@ set_up_protocol(int protocol) {
}
/**
- This function initializes a protocol. It creates a new
- protocol_t structure and fills it's vtable etc.
+ This function creates a protocol object. It's called once
+ for every connection. It creates a new protocol_t structure
+ and fills it's vtable etc.
Return the protocol_t if successful, NULL otherwise.
*/
struct protocol_t *
diff --git a/src/protocol.h b/src/protocol.h
index 7ec430c..dd34585 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -15,16 +15,16 @@ int proto_recv(struct protocol_t *proto, void *source, void *dest);
typedef struct protocol_vtable {
- /* Constructor: creates the protocol; sets up functions etc. */
+ /* Initialization function: Fills in the protocol vtable. */
int (*init)(struct protocol_t *self);
- /* Destructor */
+ /* Destructor: Destroys the protocol state. */
void (*destroy)(void *state);
- /* does nessesary initiation steps; like build a proto state etc. */
+ /* Constructor: Creates a protocol object. */
void *(*create)(struct protocol_t *proto_struct,
int is_initiator);
- /* does handshake. Supposedly all protocols have a handshake. */
+ /* does handshake. Not all protocols have a handshake. */
int (*handshake)(void *state,
struct evbuffer *buf);
1
0
commit b46dde9aa8ebd779fe651c04704f8e253830f3eb
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Mon Apr 11 02:18:39 2011 +0200
This commit:
* Fixes many small bugs all around the code reported by Nick Mathewson.
* Removes the nasty casts to (void *) on the vtable assignment.
* Fixes BUG:
* The BUG was caused by the fact that we initialized a single
protocol_t in listener_new() for all connections. This means that
multiple connections shared the same protocol_t and hence the same
protocol state. So when a connection was freed, the state of other
connections was also freed and overwritten.
This was fixed:
* By introducing a proto_init() function, which initializes the
protocol. It's run only once; in the start of obfsproxy.
* By using a proto_new() function which returns a protocol_t for
every connection.
* We now use a protocol_vtable structure which contains the
function pointer table, and each protocol maintains a static
vtable of it's own.
* TODO:
Right now, both proto_new() and set_up_protocol() are protocol
specific. proto_new() must be proto-agnostic, but I
didn't have time to tinker and I wanted to see if my BUG
solution would work so I left it like this. I'll fix it soonish.
---
BUG | 21 ----------
src/main.c | 1 -
src/network.c | 23 ++++-------
src/plugins/dummy.c | 66 ++++++++++++++++---------------
src/plugins/dummy.h | 15 +------
src/plugins/obfs2.c | 105 ++++++++++++++++++++++++++++++++++----------------
src/plugins/obfs2.h | 13 +-----
src/protocol.c | 66 ++++++++++++++++++++------------
src/protocol.h | 38 ++++++++++++-------
src/socks.c | 2 -
10 files changed, 184 insertions(+), 166 deletions(-)
diff --git a/BUG b/BUG
deleted file mode 100644
index 248b855..0000000
--- a/BUG
+++ /dev/null
@@ -1,21 +0,0 @@
--
-Program received signal SIGSEGV, Segmentation fault.
-crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
-194 memset(key, 0, sizeof(key));
-(gdb) backtrace
-#0 crypt_free (key=0xa0a0a0a0a0a0a0a) at src/plugins/obfs2_crypt.c:194
-#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
-#2 0x0000000000401df2 in conn_free (conn=0x615bc0) at src/network.c:210
-#3 0x00007ffff7bb4ad8 in bufferevent_readcb (fd=<value optimized out>, event=<value optimized out>, arg=0x615f30) at bufferevent_sock.c:191
-#4 0x00007ffff7baa88c in event_process_active_single_queue (base=0x606220, flags=<value optimized out>) at event.c:1287
-#5 event_process_active (base=0x606220, flags=<value optimized out>) at event.c:1354
-#6 event_base_loop (base=0x606220, flags=<value optimized out>) at event.c:1551
-#7 0x0000000000401cc9 in main (argc=<value optimized out>, argv=<value optimized out>) at src/main.c:124
-(gdb) up
-#1 0x0000000000403852 in obfs2_state_free (s=0x618230) at src/plugins/obfs2.c:357
-357 crypt_free(s->send_crypto);
-(gdb) p s
-$1 = (obfs2_state_t *) 0x618230
-(gdb) p s->send_crypto
-$2 = (crypt_t *) 0xa0a0a0a0a0a0a0a
--
diff --git a/src/main.c b/src/main.c
index 4f29005..225c698 100644
--- a/src/main.c
+++ b/src/main.c
@@ -117,7 +117,6 @@ main(int argc, const char **argv)
sigevent = evsignal_new(base, SIGINT, handle_signal_cb, (void*) base);
/* start an evconnlistener on the appropriate port(s) */
- /* ASN We hardcode OBFS2_PROTOCOL for now. */
listener = listener_new(base,
mode, protocol,
(struct sockaddr *)&ss_listen, sl_listen,
diff --git a/src/network.c b/src/network.c
index 3e23cdc..1199c96 100644
--- a/src/network.c
+++ b/src/network.c
@@ -27,7 +27,7 @@ struct listener_t {
struct evconnlistener *listener;
struct sockaddr_storage target_address;
int target_address_len;
- struct protocol_t *proto; /* Protocol that this listener can speak. */
+ int proto; /* Protocol that this listener can speak. */
int mode;
/* ASN */
/* char shared_secret[SHARED_SECRET_LENGTH];
@@ -63,13 +63,12 @@ listener_new(struct event_base *base,
assert(mode == LSN_SIMPLE_CLIENT || mode == LSN_SIMPLE_SERVER ||
mode == LSN_SOCKS_CLIENT);
- struct protocol_t *proto = set_up_protocol(protocol);
- if (!proto) {
- printf("This is just terrible. We can't even set up a protocol! Seppuku time!\n");
- exit(-1);
+ if (set_up_protocol(protocol)<0) {
+ printf("This is just terrible. We can't even set up a protocol! Exiting.\n");
+ exit(1);
}
- lsn->proto = proto;
+ lsn->proto = protocol;
lsn->mode = mode;
if (target_address) {
@@ -79,6 +78,7 @@ listener_new(struct event_base *base,
} else {
assert(lsn->mode == LSN_SOCKS_CLIENT);
}
+
/* ASN */
/*
assert(shared_secret == NULL || shared_secret_len == SHARED_SECRET_LENGTH);
@@ -123,16 +123,11 @@ simple_listener_cb(struct evconnlistener *evcl,
dbg(("Got a connection\n"));
conn->mode = lsn->mode;
- conn->proto = lsn->proto;
/* Will all protocols need to _init() here? Don't think so! */
- int is_initiator = (conn->mode != LSN_SIMPLE_SERVER) ? 1 : 0;
- conn->proto->state = proto_init(conn->proto, &is_initiator);
-
- /* ASN Which means that all plugins need a state... */
- if (!conn->proto->state)
- goto err;
-
+ conn->proto = proto_new(lsn->proto,
+ conn->mode != LSN_SIMPLE_SERVER);
+
if (conn->mode == LSN_SOCKS_CLIENT) {
/* Construct SOCKS state. */
conn->socks_state = socks_state_new();
diff --git a/src/plugins/dummy.c b/src/plugins/dummy.c
index 957c30b..8fe722e 100644
--- a/src/plugins/dummy.c
+++ b/src/plugins/dummy.c
@@ -1,10 +1,3 @@
-/* Copyright 2011 Princess Peach Toadstool
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -19,43 +12,52 @@
#include "../util.h"
#include "../protocol.h"
+
+static int dummy_send(void *nothing,
+ struct evbuffer *source, struct evbuffer *dest);
+static int dummy_recv(void *nothing, struct evbuffer *source,
+ struct evbuffer *dest);
+
+static protocol_vtable *vtable=NULL;
+
int
-dummy_new(struct protocol_t *proto_struct) {
- proto_struct->destroy = (void *)NULL;
- proto_struct->init = (void *)dummy_init;
- proto_struct->handshake = (void *)NULL;
- proto_struct->send = (void *)dummy_send;
- proto_struct->recv = (void *)dummy_recv;
-
- return 0;
+dummy_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = NULL;
+ vtable->create = dummy_new;
+ vtable->handshake = NULL;
+ vtable->send = dummy_send;
+ vtable->recv = dummy_recv;
+
+ return 1;
}
-int *
-dummy_init(int *initiator) {
- /* Dodging state check. */
- return initiator;
+void *
+dummy_new(struct protocol_t *proto_struct, int whatever) {
+ (void)whatever;
+
+ proto_struct->vtable = vtable;
+
+ /* Dodging state check.
+ This is terrible I know.*/
+ return (void *)666U;
}
-int
+static int
dummy_send(void *nothing,
struct evbuffer *source, struct evbuffer *dest) {
(void)nothing;
- /* ASN evbuffer_add_buffer() doesn't work for some reason. */
- while (1) {
- int n = evbuffer_remove_buffer(source, dest, 1024);
- if (n <= 0)
- return 0;
- }
+ return evbuffer_add_buffer(dest,source);
}
-int
+static int
dummy_recv(void *nothing,
struct evbuffer *source, struct evbuffer *dest) {
(void)nothing;
- while (1) {
- int n = evbuffer_remove_buffer(source, dest, 1024);
- if (n <= 0)
- return 0;
- }
+
+ return evbuffer_add_buffer(dest,source);
}
diff --git a/src/plugins/dummy.h b/src/plugins/dummy.h
index cf9342a..241366d 100644
--- a/src/plugins/dummy.h
+++ b/src/plugins/dummy.h
@@ -1,21 +1,10 @@
-/* Copyright 2011 Princess Peach Toadstool
-
- You may do anything with this work that copyright law would normally
- restrict, so long as you retain the above notice(s) and this license
- in all redistributed copies and derived works. There is no warranty.
-*/
-
#ifndef DUMMY_H
#define DUMMY_H
struct protocol_t;
struct evbuffer;
-int *dummy_init(int *initiator);
-int dummy_send(void *nothing,
- struct evbuffer *source, struct evbuffer *dest);
-int dummy_recv(void *nothing, struct evbuffer *source,
- struct evbuffer *dest);
-int dummy_new(struct protocol_t *proto_struct);
+int dummy_init(void);
+void *dummy_new(struct protocol_t *proto_struct, int whatever);
#endif
diff --git a/src/plugins/obfs2.c b/src/plugins/obfs2.c
index ef8be8e..cac7bb2 100644
--- a/src/plugins/obfs2.c
+++ b/src/plugins/obfs2.c
@@ -20,17 +20,31 @@
#include "../util.h"
#include "../protocol.h"
+static void obfs2_state_free(void *state);
+static int obfs2_send_initial_message(void *state, struct evbuffer *buf);
+static int obfs2_send(void *state,
+ struct evbuffer *source, struct evbuffer *dest);
+static int obfs2_recv(void *state, struct evbuffer *source,
+ struct evbuffer *dest);
+static void *obfs2_state_new(int initiator);
+
+static protocol_vtable *vtable=NULL;
+
/* Sets the function table for the obfs2 protocol and
calls initialize_crypto().
Returns 0 on success, -1 on fail.
*/
int
-obfs2_new(struct protocol_t *proto_struct) {
- proto_struct->destroy = (void *)obfs2_state_free;
- proto_struct->init = (void *)obfs2_state_new;
- proto_struct->handshake = (void *)obfs2_send_initial_message;
- proto_struct->send = (void *)obfs2_send;
- proto_struct->recv = (void *)obfs2_recv;
+obfs2_init(void) {
+ vtable = calloc(1, sizeof(protocol_vtable));
+ if (!vtable)
+ return -1;
+
+ vtable->destroy = obfs2_state_free;
+ vtable->create = obfs2_new;
+ vtable->handshake = obfs2_send_initial_message;
+ vtable->send = obfs2_send;
+ vtable->recv = obfs2_recv;
if (initialize_crypto() < 0) {
fprintf(stderr, "Can't initialize crypto; failing\n");
@@ -52,8 +66,10 @@ seed_nonzero(const uchar *seed)
'state'. Returns NULL on failure.
*/
static crypt_t *
-derive_key(obfs2_state_t *state, const char *keytype)
+derive_key(void *s, const char *keytype)
{
+ obfs2_state_t *state = s;
+
crypt_t *cryptstate;
uchar buf[32];
digest_t *c = digest_new();
@@ -74,9 +90,11 @@ derive_key(obfs2_state_t *state, const char *keytype)
}
static crypt_t *
-derive_padding_key(obfs2_state_t *state, const uchar *seed,
+derive_padding_key(void *s, const uchar *seed,
const char *keytype)
{
+ obfs2_state_t *state = s;
+
crypt_t *cryptstate;
uchar buf[32];
digest_t *c = digest_new();
@@ -94,13 +112,21 @@ derive_padding_key(obfs2_state_t *state, const uchar *seed,
return cryptstate;
}
+void *
+obfs2_new(struct protocol_t *proto_struct, int initiator) {
+ assert(vtable);
+ proto_struct->vtable = vtable;
+
+ return obfs2_state_new(initiator);
+}
+
/**
Return a new object to handle protocol state. If 'initiator' is true,
we're the handshake initiator. Otherwise, we're the responder. Return
NULL on failure.
*/
-obfs2_state_t *
-obfs2_state_new(int *initiator)
+static void *
+obfs2_state_new(int initiator)
{
obfs2_state_t *state = calloc(1, sizeof(obfs2_state_t));
uchar *seed;
@@ -109,8 +135,8 @@ obfs2_state_new(int *initiator)
if (!state)
return NULL;
state->state = ST_WAIT_FOR_KEY;
- state->we_are_initiator = *initiator;
- if (*initiator) {
+ state->we_are_initiator = initiator;
+ if (initiator) {
send_pad_type = INITIATOR_PAD_TYPE;
seed = state->initiator_seed;
} else {
@@ -136,9 +162,11 @@ obfs2_state_new(int *initiator)
/** Set the shared secret to be used with this protocol state. */
void
-obfs2_state_set_shared_secret(obfs2_state_t *state,
+obfs2_state_set_shared_secret(void *s,
const char *secret, size_t secretlen)
{
+ obfs2_state_t *state = s;
+
if (secretlen > SHARED_SECRET_LENGTH)
secretlen = SHARED_SECRET_LENGTH;
memcpy(state->secret_seed, secret, secretlen);
@@ -148,9 +176,11 @@ obfs2_state_set_shared_secret(obfs2_state_t *state,
Write the initial protocol setup and padding message for 'state' to
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
-int
-obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf)
+static int
+obfs2_send_initial_message(void *s, struct evbuffer *buf)
{
+ obfs2_state_t *state = s;
+
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
const uchar *seed;
@@ -213,10 +243,12 @@ crypt_and_transmit(crypt_t *crypto,
obfuscated version. Copies and obfuscates data from 'source' into 'dest'
using the state in 'state'. Returns 0 on success, -1 on failure.
*/
-int
-obfs2_send(obfs2_state_t *state,
+static int
+obfs2_send(void *s,
struct evbuffer *source, struct evbuffer *dest)
{
+ obfs2_state_t *state = s;
+
if (state->send_crypto) {
/* Our crypto is set up; just relay the bytes */
return crypt_and_transmit(state->send_crypto, source, dest);
@@ -237,8 +269,10 @@ obfs2_send(obfs2_state_t *state,
keys. Returns 0 on success, -1 on failure.
*/
static int
-init_crypto(obfs2_state_t *state)
+init_crypto(void *s)
{
+ obfs2_state_t *state = s;
+
const char *send_keytype;
const char *recv_keytype;
const char *recv_pad_keytype;
@@ -273,10 +307,12 @@ init_crypto(obfs2_state_t *state)
*
* Returns x for "don't call again till you have x bytes". 0 for "all ok". -1
* for "fail, close" */
-int
-obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
+static int
+obfs2_recv(void *s, struct evbuffer *source,
struct evbuffer *dest)
{
+ obfs2_state_t *state = s;
+
if (state->state == ST_WAIT_FOR_KEY) {
/* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
* so we can learn the partner's seed and padding length */
@@ -350,19 +386,20 @@ obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
return crypt_and_transmit(state->recv_crypto, source, dest);
}
-void
-obfs2_state_free(obfs2_state_t *s)
+static void
+obfs2_state_free(void *s)
{
- if (s->send_crypto)
- crypt_free(s->send_crypto);
- if (s->send_padding_crypto)
- crypt_free(s->send_padding_crypto);
- if (s->recv_crypto)
- crypt_free(s->recv_crypto);
- if (s->recv_padding_crypto)
- crypt_free(s->recv_padding_crypto);
- if (s->pending_data_to_send)
- evbuffer_free(s->pending_data_to_send);
- memset(s, 0x0a, sizeof(obfs2_state_t));
- free(s);
+ obfs2_state_t *state = s;
+ if (state->send_crypto)
+ crypt_free(state->send_crypto);
+ if (state->send_padding_crypto)
+ crypt_free(state->send_padding_crypto);
+ if (state->recv_crypto)
+ crypt_free(state->recv_crypto);
+ if (state->recv_padding_crypto)
+ crypt_free(state->recv_padding_crypto);
+ if (state->pending_data_to_send)
+ evbuffer_free(state->pending_data_to_send);
+ memset(state, 0x0a, sizeof(obfs2_state_t));
+ free(state);
}
diff --git a/src/plugins/obfs2.h b/src/plugins/obfs2.h
index 2d1d24e..3124bbc 100644
--- a/src/plugins/obfs2.h
+++ b/src/plugins/obfs2.h
@@ -16,17 +16,10 @@ struct protocol_t;
#define SHARED_SECRET_LENGTH 16
-obfs2_state_t *obfs2_state_new(int *initiator);
-void obfs2_state_set_shared_secret(obfs2_state_t *state,
+void obfs2_state_set_shared_secret(void *state,
const char *secret, size_t secretlen);
-void obfs2_state_free(obfs2_state_t *state);
-int obfs2_send_initial_message(obfs2_state_t *state, struct evbuffer *buf);
-int obfs2_send(obfs2_state_t *state,
- struct evbuffer *source, struct evbuffer *dest);
-int obfs2_recv(obfs2_state_t *state, struct evbuffer *source,
- struct evbuffer *dest);
-
-int obfs2_new(struct protocol_t *proto_struct);
+int obfs2_init(void);
+void *obfs2_new(struct protocol_t *proto_struct, int initiator);
#ifdef CRYPT_PROTOCOL_PRIVATE
diff --git a/src/protocol.c b/src/protocol.c
index 339feae..b95ab11 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -9,30 +9,46 @@
#include "plugins/dummy.h"
/**
- This function returns a protocol_t structure based on the mode
- of obfsproxy
+ This function initializes <protocol>.
+ It's called once in the runtime of the program for each proto.
*/
-struct protocol_t *
+int
set_up_protocol(int protocol) {
- struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
-
if (protocol == OBFS2_PROTOCOL)
- proto->new = &obfs2_new;
+ obfs2_init();
else if (protocol == DUMMY_PROTOCOL)
- proto->new = &dummy_new;
- /* elif { other protocols } */
-
- if (proto->new(proto)>0)
- printf("Protocol constructed\n");
+ dummy_init();
+ else
+ return -1;
- return proto;
+ return 1;
}
-void *
-proto_init(struct protocol_t *proto, void *arg) {
- assert(proto);
- if (proto->init)
- return proto->init(arg);
+/**
+ This function initializes a protocol. It creates a new
+ protocol_t structure and fills it's vtable etc.
+ Return the protocol_t if successful, NULL otherwise.
+*/
+struct protocol_t *
+proto_new(int protocol, int is_initiator) {
+ struct protocol_t *proto = calloc(1, sizeof(struct protocol_t));
+ if (!proto)
+ return NULL;
+
+ proto->vtable = calloc(1, sizeof(struct protocol_vtable));
+ if (!proto->vtable)
+ return NULL;
+
+ if (protocol == OBFS2_PROTOCOL) {
+ proto->proto = protocol;
+ proto->state = obfs2_new(proto, is_initiator);
+ } else if (protocol == DUMMY_PROTOCOL) {
+ proto->proto = protocol;
+ proto->state = dummy_new(proto, is_initiator);
+ }
+
+ if (proto->state)
+ return proto;
else
return NULL;
}
@@ -40,8 +56,8 @@ proto_init(struct protocol_t *proto, void *arg) {
int
proto_handshake(struct protocol_t *proto, void *buf) {
assert(proto);
- if (proto->handshake)
- return proto->handshake(proto->state, buf);
+ if (proto->vtable->handshake)
+ return proto->vtable->handshake(proto->state, buf);
else /* It's okay with me, protocol didn't have a handshake */
return 0;
}
@@ -49,8 +65,8 @@ proto_handshake(struct protocol_t *proto, void *buf) {
int
proto_send(struct protocol_t *proto, void *source, void *dest) {
assert(proto);
- if (proto->send)
- return proto->send(proto->state, source, dest);
+ if (proto->vtable->send)
+ return proto->vtable->send(proto->state, source, dest);
else
return -1;
}
@@ -58,8 +74,8 @@ proto_send(struct protocol_t *proto, void *source, void *dest) {
int
proto_recv(struct protocol_t *proto, void *source, void *dest) {
assert(proto);
- if (proto->recv)
- return proto->recv(proto->state, source, dest);
+ if (proto->vtable->recv)
+ return proto->vtable->recv(proto->state, source, dest);
else
return -1;
}
@@ -68,6 +84,6 @@ void proto_destroy(struct protocol_t *proto) {
assert(proto);
assert(proto->state);
- if (proto->destroy)
- proto->destroy(proto->state);
+ if (proto->vtable->destroy)
+ proto->vtable->destroy(proto->state);
}
diff --git a/src/protocol.h b/src/protocol.h
index 781bde0..7ec430c 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,40 +1,50 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
-/* ASN I'm gonna be calling crypt_protocol.c BRL_RPOTOCOL for now. Yes. */
-#define DUMMY_PROTOCOL 0
+#define DUMMY_PROTOCOL 0
#define OBFS2_PROTOCOL 1
+struct evbuffer;
-struct protocol_t *set_up_protocol(int protocol);
-void *proto_init(struct protocol_t *proto, void *arg);
+int set_up_protocol(int protocol);
+struct protocol_t *proto_new(int protocol, int arg);
void proto_destroy(struct protocol_t *proto);
int proto_handshake(struct protocol_t *proto, void *buf);
int proto_send(struct protocol_t *proto, void *source, void *dest);
int proto_recv(struct protocol_t *proto, void *source, void *dest);
-
-/* ASN Why the hell do half of them return int? FIXME */
-struct protocol_t {
+typedef struct protocol_vtable {
/* Constructor: creates the protocol; sets up functions etc. */
- int (*new)(struct protocol_t *self);
+ int (*init)(struct protocol_t *self);
/* Destructor */
void (*destroy)(void *state);
/* does nessesary initiation steps; like build a proto state etc. */
- void *(*init)(void *arg);
+ void *(*create)(struct protocol_t *proto_struct,
+ int is_initiator);
/* does handshake. Supposedly all protocols have a handshake. */
- int (*handshake)(void *state, void *buf);
+ int (*handshake)(void *state,
+ struct evbuffer *buf);
/* send data function */
- int (*send)(void *state, void *source,
- void *dest);
+ int (*send)(void *state,
+ struct evbuffer *source,
+ struct evbuffer *dest);
/* receive data function */
- int (*recv)(void *state, void *source,
- void *dest);
+ int (*recv)(void *state,
+ struct evbuffer *source,
+ struct evbuffer *dest);
+} protocol_vtable;
+
+struct protocol_t {
+ /* protocol */
+ int proto;
+
+ /* protocol vtable */
+ protocol_vtable *vtable;
/* ASN do we need a proto_get_state()? */
void *state;
diff --git a/src/socks.c b/src/socks.c
index a3fb729..a1f794a 100644
--- a/src/socks.c
+++ b/src/socks.c
@@ -192,8 +192,6 @@ socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state,
/* We either failed or succeded.
Either way, we should send something back to the client */
p[0] = SOCKS5_VERSION; /* Version field */
- if (status == SOCKS5_REP_FAIL)
- printf("Sending negative shit\n");
p[1] = (unsigned char) status; /* Reply field */
p[2] = 0; /* Reserved */
if (state->parsereq.af == AF_UNSPEC) {
1
0
commit 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

[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

[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] * 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