1*ebfedea0SLionel SambucThis is intended to be an example of a state-machine driven SSL application. It
2*ebfedea0SLionel Sambucacts as an SSL tunneler (functioning as either the server or client half,
3*ebfedea0SLionel Sambucdepending on command-line arguments). *PLEASE* read the comments in tunala.h
4*ebfedea0SLionel Sambucbefore you treat this stuff as anything more than a curiosity - YOU HAVE BEEN
5*ebfedea0SLionel SambucWARNED!! There, that's the draconian bit out of the way ...
6*ebfedea0SLionel Sambuc
7*ebfedea0SLionel Sambuc
8*ebfedea0SLionel SambucWhy "tunala"??
9*ebfedea0SLionel Sambuc--------------
10*ebfedea0SLionel Sambuc
11*ebfedea0SLionel SambucI thought I asked you to read tunala.h?? :-)
12*ebfedea0SLionel Sambuc
13*ebfedea0SLionel Sambuc
14*ebfedea0SLionel SambucShow me
15*ebfedea0SLionel Sambuc-------
16*ebfedea0SLionel Sambuc
17*ebfedea0SLionel SambucIf you want to simply see it running, skip to the end and see some example
18*ebfedea0SLionel Sambuccommand-line arguments to demonstrate with.
19*ebfedea0SLionel Sambuc
20*ebfedea0SLionel Sambuc
21*ebfedea0SLionel SambucWhere to look and what to do?
22*ebfedea0SLionel Sambuc-----------------------------
23*ebfedea0SLionel Sambuc
24*ebfedea0SLionel SambucThe code is split up roughly coinciding with the detaching of an "abstract" SSL
25*ebfedea0SLionel Sambucstate machine (which is the purpose of all this) and its surrounding application
26*ebfedea0SLionel Sambucspecifics. This is primarily to make it possible for me to know when I could cut
27*ebfedea0SLionel Sambuccorners and when I needed to be rigorous (or at least maintain the pretense as
28*ebfedea0SLionel Sambucsuch :-).
29*ebfedea0SLionel Sambuc
30*ebfedea0SLionel SambucNetwork stuff:
31*ebfedea0SLionel Sambuc
32*ebfedea0SLionel SambucBasically, the network part of all this is what is supposed to be abstracted out
33*ebfedea0SLionel Sambucof the way. The intention is to illustrate one way to stick OpenSSL's mechanisms
34*ebfedea0SLionel Sambucinside a little memory-driven sandbox and operate it like a pure state-machine.
35*ebfedea0SLionel SambucSo, the network code is inside both ip.c (general utility functions and gory
36*ebfedea0SLionel SambucIPv4 details) and tunala.c itself, which takes care of application specifics
37*ebfedea0SLionel Sambuclike the main select() loop. The connectivity between the specifics of this
38*ebfedea0SLionel Sambucapplication (TCP/IP tunneling and the associated network code) and the
39*ebfedea0SLionel Sambucunderlying abstract SSL state machine stuff is through the use of the "buffer_t"
40*ebfedea0SLionel Sambuctype, declared in tunala.h and implemented in buffer.c.
41*ebfedea0SLionel Sambuc
42*ebfedea0SLionel SambucState machine:
43*ebfedea0SLionel Sambuc
44*ebfedea0SLionel SambucWhich leaves us, generally speaking, with the abstract "state machine" code left
45*ebfedea0SLionel Sambucover and this is sitting inside sm.c, with declarations inside tunala.h. As can
46*ebfedea0SLionel Sambucbe seen by the definition of the state_machine_t structure and the associated
47*ebfedea0SLionel Sambucfunctions to manipulate it, there are the 3 OpenSSL "handles" plus 4 buffer_t
48*ebfedea0SLionel Sambucstructures dealing with IO on both the encrypted and unencrypted sides ("dirty"
49*ebfedea0SLionel Sambucand "clean" respectively). The "SSL" handle is what facilitates the reading and
50*ebfedea0SLionel Sambucwriting of the unencrypted (tunneled) data. The two "BIO" handles act as the
51*ebfedea0SLionel Sambucread and write channels for encrypted tunnel traffic - in other applications
52*ebfedea0SLionel Sambucthese are often socket BIOs so that the OpenSSL framework operates with the
53*ebfedea0SLionel Sambucnetwork layer directly. In this example, those two BIOs are memory BIOs
54*ebfedea0SLionel Sambuc(BIO_s_mem()) so that the sending and receiving of the tunnel traffic stays
55*ebfedea0SLionel Sambucwithin the state-machine, and we can handle where this gets send to (or read
56*ebfedea0SLionel Sambucfrom) ourselves.
57*ebfedea0SLionel Sambuc
58*ebfedea0SLionel Sambuc
59*ebfedea0SLionel SambucWhy?
60*ebfedea0SLionel Sambuc----
61*ebfedea0SLionel Sambuc
62*ebfedea0SLionel SambucIf you take a look at the "state_machine_t" section of tunala.h and the code in
63*ebfedea0SLionel Sambucsm.c, you will notice that nothing related to the concept of 'transport' is
64*ebfedea0SLionel Sambucinvolved. The binding to TCP/IP networking occurs in tunala.c, specifically
65*ebfedea0SLionel Sambucwithin the "tunala_item_t" structure that associates a state_machine_t object
66*ebfedea0SLionel Sambucwith 4 file-descriptors. The way to best see where the bridge between the
67*ebfedea0SLionel Sambucoutside world (TCP/IP reads, writes, select()s, file-descriptors, etc) and the
68*ebfedea0SLionel Sambucstate machine is, is to examine the "tunala_item_io()" function in tunala.c.
69*ebfedea0SLionel SambucThis is currently around lines 641-732 but of course could be subject to change.
70*ebfedea0SLionel Sambuc
71*ebfedea0SLionel Sambuc
72*ebfedea0SLionel SambucAnd...?
73*ebfedea0SLionel Sambuc-------
74*ebfedea0SLionel Sambuc
75*ebfedea0SLionel SambucWell, although that function is around 90 lines of code, it could easily have
76*ebfedea0SLionel Sambucbeen a lot less only I was trying to address an easily missed "gotcha" (item (2)
77*ebfedea0SLionel Sambucbelow). The main() code that drives the select/accept/IO loop initialises new
78*ebfedea0SLionel Sambuctunala_item_t structures when connections arrive, and works out which
79*ebfedea0SLionel Sambucfile-descriptors go where depending on whether we're an SSL client or server
80*ebfedea0SLionel Sambuc(client --> accepted connection is clean and proxied is dirty, server -->
81*ebfedea0SLionel Sambucaccepted connection is dirty and proxied is clean). What that tunala_item_io()
82*ebfedea0SLionel Sambucfunction is attempting to do is 2 things;
83*ebfedea0SLionel Sambuc
84*ebfedea0SLionel Sambuc  (1) Perform all reads and writes on the network directly into the
85*ebfedea0SLionel Sambuc      state_machine_t's buffers (based on a previous select() result), and only
86*ebfedea0SLionel Sambuc      then allow the abstact state_machine_t to "churn()" using those buffers.
87*ebfedea0SLionel Sambuc      This will cause the SSL machine to consume as much input data from the two
88*ebfedea0SLionel Sambuc      "IN" buffers as possible, and generate as much output data into the two
89*ebfedea0SLionel Sambuc      "OUT" buffers as possible. Back up in the main() function, the next main
90*ebfedea0SLionel Sambuc      loop loop will examine these output buffers and select() for writability
91*ebfedea0SLionel Sambuc      on the corresponding sockets if the buffers are non-empty.
92*ebfedea0SLionel Sambuc
93*ebfedea0SLionel Sambuc  (2) Handle the complicated tunneling-specific issue of cascading "close"s.
94*ebfedea0SLionel Sambuc      This is the reason for most of the complexity in the logic - if one side
95*ebfedea0SLionel Sambuc      of the tunnel is closed, you can't simply close the other side and throw
96*ebfedea0SLionel Sambuc      away the whole thing - (a) there may still be outgoing data on the other
97*ebfedea0SLionel Sambuc      side of the tunnel that hasn't been sent yet, (b) the close (or things
98*ebfedea0SLionel Sambuc      happening during the close) may cause more data to be generated that needs
99*ebfedea0SLionel Sambuc      sending on the other side. Of course, this logic is complicated yet futher
100*ebfedea0SLionel Sambuc      by the fact that it's different depending on which side closes first :-)
101*ebfedea0SLionel Sambuc      state_machine_close_clean() will indicate to the state machine that the
102*ebfedea0SLionel Sambuc      unencrypted side of the tunnel has closed, so any existing outgoing data
103*ebfedea0SLionel Sambuc      needs to be flushed, and the SSL stream needs to be closed down using the
104*ebfedea0SLionel Sambuc      appropriate shutdown sequence. state_machine_close_dirty() is simpler
105*ebfedea0SLionel Sambuc      because it indicates that the SSL stream has been disconnected, so all
106*ebfedea0SLionel Sambuc      that remains before closing the other side is to flush out anything that
107*ebfedea0SLionel Sambuc      remains and wait for it to all be sent.
108*ebfedea0SLionel Sambuc
109*ebfedea0SLionel SambucAnyway, with those things in mind, the code should be a little easier to follow
110*ebfedea0SLionel Sambucin terms of "what is *this* bit supposed to achieve??!!".
111*ebfedea0SLionel Sambuc
112*ebfedea0SLionel Sambuc
113*ebfedea0SLionel SambucHow might this help?
114*ebfedea0SLionel Sambuc--------------------
115*ebfedea0SLionel Sambuc
116*ebfedea0SLionel SambucWell, the reason I wrote this is that there seemed to be rather a flood of
117*ebfedea0SLionel Sambucquestions of late on the openssl-dev and openssl-users lists about getting this
118*ebfedea0SLionel Sambucwhole IO logic thing sorted out, particularly by those who were trying to either
119*ebfedea0SLionel Sambucuse non-blocking IO, or wanted SSL in an environment where "something else" was
120*ebfedea0SLionel Sambuchandling the network already and they needed to operate in memory only. This
121*ebfedea0SLionel Sambuccode is loosely based on some other stuff I've been working on, although that
122*ebfedea0SLionel Sambucstuff is far more complete, far more dependant on a whole slew of other
123*ebfedea0SLionel Sambucnetwork/framework code I don't want to incorporate here, and far harder to look
124*ebfedea0SLionel Sambucat for 5 minutes and follow where everything is going. I will be trying over
125*ebfedea0SLionel Sambuctime to suck in a few things from that into this demo in the hopes it might be
126*ebfedea0SLionel Sambucmore useful, and maybe to even make this demo usable as a utility of its own.
127*ebfedea0SLionel SambucPossible things include:
128*ebfedea0SLionel Sambuc
129*ebfedea0SLionel Sambuc  * controlling multiple processes/threads - this can be used to combat
130*ebfedea0SLionel Sambuc    latencies and get passed file-descriptor limits on some systems, and it uses
131*ebfedea0SLionel Sambuc    a "controller" process/thread that maintains IPC links with the
132*ebfedea0SLionel Sambuc    processes/threads doing the real work.
133*ebfedea0SLionel Sambuc
134*ebfedea0SLionel Sambuc  * cert verification rules - having some say over which certs get in or out :-)
135*ebfedea0SLionel Sambuc
136*ebfedea0SLionel Sambuc  * control over SSL protocols and cipher suites
137*ebfedea0SLionel Sambuc
138*ebfedea0SLionel Sambuc  * A few other things you can already do in s_client and s_server :-)
139*ebfedea0SLionel Sambuc
140*ebfedea0SLionel Sambuc  * Support (and control over) session resuming, particularly when functioning
141*ebfedea0SLionel Sambuc    as an SSL client.
142*ebfedea0SLionel Sambuc
143*ebfedea0SLionel SambucIf you have a particular environment where this model might work to let you "do
144*ebfedea0SLionel SambucSSL" without having OpenSSL be aware of the transport, then you should find you
145*ebfedea0SLionel Sambuccould use the state_machine_t structure (or your own variant thereof) and hook
146*ebfedea0SLionel Sambucit up to your transport stuff in much the way tunala.c matches it up with those
147*ebfedea0SLionel Sambuc4 file-descriptors. The state_machine_churn(), state_machine_close_clean(), and
148*ebfedea0SLionel Sambucstate_machine_close_dirty() functions are the main things to understand - after
149*ebfedea0SLionel Sambucthat's done, you just have to ensure you're feeding and bleeding the 4
150*ebfedea0SLionel Sambucstate_machine buffers in a logical fashion. This state_machine loop handles not
151*ebfedea0SLionel Sambuconly handshakes and normal streaming, but also renegotiates - there's no special
152*ebfedea0SLionel Sambuchandling required beyond keeping an eye on those 4 buffers and keeping them in
153*ebfedea0SLionel Sambucsync with your outer "loop" logic. Ie. if one of the OUT buffers is not empty,
154*ebfedea0SLionel Sambucyou need to find an opportunity to try and forward its data on. If one of the IN
155*ebfedea0SLionel Sambucbuffers is not full, you should keep an eye out for data arriving that should be
156*ebfedea0SLionel Sambucplaced there.
157*ebfedea0SLionel Sambuc
158*ebfedea0SLionel SambucThis approach could hopefully also allow you to run the SSL protocol in very
159*ebfedea0SLionel Sambucdifferent environments. As an example, you could support encrypted event-driven
160*ebfedea0SLionel SambucIPC where threads/processes pass messages to each other inside an SSL layer;
161*ebfedea0SLionel Sambuceach IPC-message's payload would be in fact the "dirty" content, and the "clean"
162*ebfedea0SLionel Sambucpayload coming out of the tunnel at each end would be the real intended message.
163*ebfedea0SLionel SambucLikewise, this could *easily* be made to work across unix domain sockets, or
164*ebfedea0SLionel Sambuceven entirely different network/comms protocols.
165*ebfedea0SLionel Sambuc
166*ebfedea0SLionel SambucThis is also a quick and easy way to do VPN if you (and the remote network's
167*ebfedea0SLionel Sambucgateway) support virtual network devices that are encapsulted in a single
168*ebfedea0SLionel Sambucnetwork connection, perhaps PPP going through an SSL tunnel?
169*ebfedea0SLionel Sambuc
170*ebfedea0SLionel Sambuc
171*ebfedea0SLionel SambucSuggestions
172*ebfedea0SLionel Sambuc-----------
173*ebfedea0SLionel Sambuc
174*ebfedea0SLionel SambucPlease let me know if you find this useful, or if there's anything wrong or
175*ebfedea0SLionel Sambucsimply too confusing about it. Patches are also welcome, but please attach a
176*ebfedea0SLionel Sambucdescription of what it changes and why, and "diff -urN" format is preferred.
177*ebfedea0SLionel SambucMail to geoff@openssl.org should do the trick.
178*ebfedea0SLionel Sambuc
179*ebfedea0SLionel Sambuc
180*ebfedea0SLionel SambucExample
181*ebfedea0SLionel Sambuc-------
182*ebfedea0SLionel Sambuc
183*ebfedea0SLionel SambucHere is an example of how to use "tunala" ...
184*ebfedea0SLionel Sambuc
185*ebfedea0SLionel SambucFirst, it's assumed that OpenSSL has already built, and that you are building
186*ebfedea0SLionel Sambucinside the ./demos/tunala/ directory. If not - please correct the paths and
187*ebfedea0SLionel Sambucflags inside the Makefile. Likewise, if you want to tweak the building, it's
188*ebfedea0SLionel Sambucbest to try and do so in the makefile (eg. removing the debug flags and adding
189*ebfedea0SLionel Sambucoptimisation flags).
190*ebfedea0SLionel Sambuc
191*ebfedea0SLionel SambucSecondly, this code has mostly only been tested on Linux. However, some
192*ebfedea0SLionel Sambucautoconf/etc support has been added and the code has been compiled on openbsd
193*ebfedea0SLionel Sambucand solaris using that.
194*ebfedea0SLionel Sambuc
195*ebfedea0SLionel SambucThirdly, if you are Win32, you probably need to do some *major* rewriting of
196*ebfedea0SLionel Sambucip.c to stand a hope in hell. Good luck, and please mail me the diff if you do
197*ebfedea0SLionel Sambucthis, otherwise I will take a look at another time. It can certainly be done,
198*ebfedea0SLionel Sambucbut it's very non-POSIXy.
199*ebfedea0SLionel Sambuc
200*ebfedea0SLionel SambucSee the INSTALL document for details on building.
201*ebfedea0SLionel Sambuc
202*ebfedea0SLionel SambucNow, if you don't have an executable "tunala" compiled, go back to "First,...".
203*ebfedea0SLionel SambucRinse and repeat.
204*ebfedea0SLionel Sambuc
205*ebfedea0SLionel SambucInside one console, try typing;
206*ebfedea0SLionel Sambuc
207*ebfedea0SLionel Sambuc(i)  ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \
208*ebfedea0SLionel Sambuc              -cert A-client.pem -out_totals -v_peer -v_strict
209*ebfedea0SLionel Sambuc
210*ebfedea0SLionel SambucIn another console, type;
211*ebfedea0SLionel Sambuc
212*ebfedea0SLionel Sambuc(ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \
213*ebfedea0SLionel Sambuc              -cert A-server.pem -server 1 -out_totals -v_peer -v_strict
214*ebfedea0SLionel Sambuc
215*ebfedea0SLionel SambucNow if you open another console and "telnet localhost 8080", you should be
216*ebfedea0SLionel Sambuctunneled through to the telnet service on your local machine (if it's running -
217*ebfedea0SLionel Sambucyou could change it to port "22" and tunnel ssh instead if you so desired). When
218*ebfedea0SLionel Sambucyou logout of the telnet session, the tunnel should cleanly shutdown and show
219*ebfedea0SLionel Sambucyou some traffic stats in both consoles. Feel free to experiment. :-)
220*ebfedea0SLionel Sambuc
221*ebfedea0SLionel SambucNotes:
222*ebfedea0SLionel Sambuc
223*ebfedea0SLionel Sambuc - the format for the "-listen" argument can skip the host part (eg. "-listen
224*ebfedea0SLionel Sambuc   8080" is fine). If you do, the listening socket will listen on all interfaces
225*ebfedea0SLionel Sambuc   so you can connect from other machines for example. Using the "localhost"
226*ebfedea0SLionel Sambuc   form listens only on 127.0.0.1 so you can only connect locally (unless, of
227*ebfedea0SLionel Sambuc   course, you've set up weird stuff with your networking in which case probably
228*ebfedea0SLionel Sambuc   none of the above applies).
229*ebfedea0SLionel Sambuc
230*ebfedea0SLionel Sambuc - ./tunala -? gives you a list of other command-line options, but tunala.c is
231*ebfedea0SLionel Sambuc   also a good place to look :-)
232*ebfedea0SLionel Sambuc
233*ebfedea0SLionel Sambuc
234