]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - crypto/openssl/demos/tunala/tunala.c
Fix multiple OpenSSL vulnerabilities.
[FreeBSD/releng/9.3.git] / crypto / openssl / demos / tunala / tunala.c
1 #if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL)
2 # error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*"
3 #endif
4
5 /* Include our bits'n'pieces */
6 #include "tunala.h"
7
8 /********************************************/
9 /* Our local types that specify our "world" */
10 /********************************************/
11
12 /*
13  * These represent running "tunnels". Eg. if you wanted to do SSL in a
14  * "message-passing" scanario, the "int" file-descriptors might be replaced
15  * by thread or process IDs, and the "select" code might be replaced by
16  * message handling code. Whatever.
17  */
18 typedef struct _tunala_item_t {
19     /*
20      * The underlying SSL state machine. This is a data-only processing unit
21      * and we communicate with it by talking to its four "buffers".
22      */
23     state_machine_t sm;
24     /*
25      * The file-descriptors for the "dirty" (encrypted) side of the SSL
26      * setup. In actuality, this is typically a socket and both values are
27      * identical.
28      */
29     int dirty_read, dirty_send;
30     /*
31      * The file-descriptors for the "clean" (unencrypted) side of the SSL
32      * setup. These could be stdin/stdout, a socket (both values the same),
33      * or whatever you like.
34      */
35     int clean_read, clean_send;
36 } tunala_item_t;
37
38 /*
39  * This structure is used as the data for running the main loop. Namely, in a
40  * network format such as this, it is stuff for select() - but as pointed out,
41  * when moving the real-world to somewhere else, this might be replaced by
42  * something entirely different. It's basically the stuff that controls when
43  * it's time to do some "work".
44  */
45 typedef struct _select_sets_t {
46     int max;                    /* As required as the first argument to
47                                  * select() */
48     fd_set reads, sends, excepts; /* As passed to select() */
49 } select_sets_t;
50 typedef struct _tunala_selector_t {
51     select_sets_t last_selected; /* Results of the last select() */
52     select_sets_t next_select;  /* What we'll next select on */
53 } tunala_selector_t;
54
55 /*
56  * This structure is *everything*. We do it to avoid the use of globals so
57  * that, for example, it would be easier to shift things around between
58  * async-IO, thread-based, or multi-fork()ed (or combinations thereof).
59  */
60 typedef struct _tunala_world_t {
61     /* The file-descriptor we "listen" on for new connections */
62     int listen_fd;
63     /* The array of tunnels */
64     tunala_item_t *tunnels;
65     /* the number of tunnels in use and allocated, respectively */
66     unsigned int tunnels_used, tunnels_size;
67     /* Our outside "loop" context stuff */
68     tunala_selector_t selector;
69     /*
70      * Our SSL_CTX, which is configured as the SSL client or server and has
71      * the various cert-settings and callbacks configured.
72      */
73     SSL_CTX *ssl_ctx;
74     /*
75      * Simple flag with complex logic :-) Indicates whether we're an SSL
76      * server or an SSL client.
77      */
78     int server_mode;
79 } tunala_world_t;
80
81 /*****************************/
82 /* Internal static functions */
83 /*****************************/
84
85 static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
86                                    const char *CAfile, const char *cert,
87                                    const char *key, const char *dcert,
88                                    const char *dkey, const char *cipher_list,
89                                    const char *dh_file,
90                                    const char *dh_special, int tmp_rsa,
91                                    int ctx_options, int out_state,
92                                    int out_verify, int verify_mode,
93                                    unsigned int verify_depth);
94 static void selector_init(tunala_selector_t * selector);
95 static void selector_add_listener(tunala_selector_t * selector, int fd);
96 static void selector_add_tunala(tunala_selector_t * selector,
97                                 tunala_item_t * t);
98 static int selector_select(tunala_selector_t * selector);
99 /*
100  * This returns -1 for error, 0 for no new connections, or 1 for success, in
101  * which case *newfd is populated.
102  */
103 static int selector_get_listener(tunala_selector_t * selector, int fd,
104                                  int *newfd);
105 static int tunala_world_new_item(tunala_world_t * world, int fd,
106                                  const char *ip, unsigned short port,
107                                  int flipped);
108 static void tunala_world_del_item(tunala_world_t * world, unsigned int idx);
109 static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item);
110
111 /*********************************************/
112 /* MAIN FUNCTION (and its utility functions) */
113 /*********************************************/
114
115 static const char *def_proxyhost = "127.0.0.1:443";
116 static const char *def_listenhost = "127.0.0.1:8080";
117 static int def_max_tunnels = 50;
118 static const char *def_cacert = NULL;
119 static const char *def_cert = NULL;
120 static const char *def_key = NULL;
121 static const char *def_dcert = NULL;
122 static const char *def_dkey = NULL;
123 static const char *def_engine_id = NULL;
124 static int def_server_mode = 0;
125 static int def_flipped = 0;
126 static const char *def_cipher_list = NULL;
127 static const char *def_dh_file = NULL;
128 static const char *def_dh_special = NULL;
129 static int def_tmp_rsa = 1;
130 static int def_ctx_options = 0;
131 static int def_verify_mode = 0;
132 static unsigned int def_verify_depth = 10;
133 static int def_out_state = 0;
134 static unsigned int def_out_verify = 0;
135 static int def_out_totals = 0;
136 static int def_out_conns = 0;
137
138 static const char *helpstring =
139     "\n'Tunala' (A tunneler with a New Zealand accent)\n"
140     "Usage: tunala [options], where options are from;\n"
141     " -listen [host:]<port>  (default = 127.0.0.1:8080)\n"
142     " -proxy <host>:<port>   (default = 127.0.0.1:443)\n"
143     " -maxtunnels <num>      (default = 50)\n"
144     " -cacert <path|NULL>    (default = NULL)\n"
145     " -cert <path|NULL>      (default = NULL)\n"
146     " -key <path|NULL>       (default = whatever '-cert' is)\n"
147     " -dcert <path|NULL>     (usually for DSA, default = NULL)\n"
148     " -dkey <path|NULL>      (usually for DSA, default = whatever '-dcert' is)\n"
149     " -engine <id|NULL>      (default = NULL)\n"
150     " -server <0|1>          (default = 0, ie. an SSL client)\n"
151     " -flipped <0|1>         (makes SSL servers be network clients, and vice versa)\n"
152     " -cipher <list>         (specifies cipher list to use)\n"
153     " -dh_file <path>        (a PEM file containing DH parameters to use)\n"
154     " -dh_special <NULL|generate|standard> (see below: def=NULL)\n"
155     " -no_tmp_rsa            (don't generate temporary RSA keys)\n"
156     " -no_ssl2               (disable SSLv2)\n"
157     " -no_ssl3               (disable SSLv3)\n"
158     " -no_tls1               (disable TLSv1)\n"
159     " -v_peer                (verify the peer certificate)\n"
160     " -v_strict              (do not continue if peer doesn't authenticate)\n"
161     " -v_once                (no verification in renegotiates)\n"
162     " -v_depth <num>         (limit certificate chain depth, default = 10)\n"
163     " -out_conns             (prints client connections and disconnections)\n"
164     " -out_state             (prints SSL handshake states)\n"
165     " -out_verify <0|1|2|3>  (prints certificate verification states: def=1)\n"
166     " -out_totals            (prints out byte-totals when a tunnel closes)\n"
167     " -<h|help|?>            (displays this help screen)\n"
168     "Notes:\n"
169     "(1) It is recommended to specify a cert+key when operating as an SSL server.\n"
170     "    If you only specify '-cert', the same file must contain a matching\n"
171     "    private key.\n"
172     "(2) Either dh_file or dh_special can be used to specify where DH parameters\n"
173     "    will be obtained from (or '-dh_special NULL' for the default choice) but\n"
174     "    you cannot specify both. For dh_special, 'generate' will create new DH\n"
175     "    parameters on startup, and 'standard' will use embedded parameters\n"
176     "    instead.\n"
177     "(3) Normally an ssl client connects to an ssl server - so that an 'ssl client\n"
178     "    tunala' listens for 'clean' client connections and proxies ssl, and an\n"
179     "    'ssl server tunala' listens for ssl connections and proxies 'clean'. With\n"
180     "    '-flipped 1', this behaviour is reversed so that an 'ssl server tunala'\n"
181     "    listens for clean client connections and proxies ssl (but participating\n"
182     "    as an ssl *server* in the SSL/TLS protocol), and an 'ssl client tunala'\n"
183     "    listens for ssl connections (participating as an ssl *client* in the\n"
184     "    SSL/TLS protocol) and proxies 'clean' to the end destination. This can\n"
185     "    be useful for allowing network access to 'servers' where only the server\n"
186     "    needs to authenticate the client (ie. the other way is not required).\n"
187     "    Even with client and server authentication, this 'technique' mitigates\n"
188     "    some DoS (denial-of-service) potential as it will be the network client\n"
189     "    having to perform the first private key operation rather than the other\n"
190     "    way round.\n"
191     "(4) The 'technique' used by setting '-flipped 1' is probably compatible with\n"
192     "    absolutely nothing except another complimentary instance of 'tunala'\n"
193     "    running with '-flipped 1'. :-)\n";
194
195 /*
196  * Default DH parameters for use with "-dh_special standard" ... stolen
197  * striaght from s_server.
198  */
199 static unsigned char dh512_p[] = {
200     0xDA, 0x58, 0x3C, 0x16, 0xD9, 0x85, 0x22, 0x89, 0xD0, 0xE4, 0xAF, 0x75,
201     0x6F, 0x4C, 0xCA, 0x92, 0xDD, 0x4B, 0xE5, 0x33, 0xB8, 0x04, 0xFB, 0x0F,
202     0xED, 0x94, 0xEF, 0x9C, 0x8A, 0x44, 0x03, 0xED, 0x57, 0x46, 0x50, 0xD3,
203     0x69, 0x99, 0xDB, 0x29, 0xD7, 0x76, 0x27, 0x6B, 0xA2, 0xD3, 0xD4, 0x12,
204     0xE2, 0x18, 0xF4, 0xDD, 0x1E, 0x08, 0x4C, 0xF6, 0xD8, 0x00, 0x3E, 0x7C,
205     0x47, 0x74, 0xE8, 0x33,
206 };
207
208 static unsigned char dh512_g[] = {
209     0x02,
210 };
211
212 /*
213  * And the function that parses the above "standard" parameters, again,
214  * straight out of s_server.
215  */
216 static DH *get_dh512(void)
217 {
218     DH *dh = NULL;
219
220     if ((dh = DH_new()) == NULL)
221         return (NULL);
222     dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
223     dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
224     if ((dh->p == NULL) || (dh->g == NULL))
225         return (NULL);
226     return (dh);
227 }
228
229 /* Various help/error messages used by main() */
230 static int usage(const char *errstr, int isunknownarg)
231 {
232     if (isunknownarg)
233         fprintf(stderr, "Error: unknown argument '%s'\n", errstr);
234     else
235         fprintf(stderr, "Error: %s\n", errstr);
236     fprintf(stderr, "%s\n", helpstring);
237     return 1;
238 }
239
240 static int err_str0(const char *str0)
241 {
242     fprintf(stderr, "%s\n", str0);
243     return 1;
244 }
245
246 static int err_str1(const char *fmt, const char *str1)
247 {
248     fprintf(stderr, fmt, str1);
249     fprintf(stderr, "\n");
250     return 1;
251 }
252
253 static int parse_max_tunnels(const char *s, unsigned int *maxtunnels)
254 {
255     unsigned long l;
256     if (!int_strtoul(s, &l) || (l < 1) || (l > 1024)) {
257         fprintf(stderr, "Error, '%s' is an invalid value for "
258                 "maxtunnels\n", s);
259         return 0;
260     }
261     *maxtunnels = (unsigned int)l;
262     return 1;
263 }
264
265 static int parse_server_mode(const char *s, int *servermode)
266 {
267     unsigned long l;
268     if (!int_strtoul(s, &l) || (l > 1)) {
269         fprintf(stderr, "Error, '%s' is an invalid value for the "
270                 "server mode\n", s);
271         return 0;
272     }
273     *servermode = (int)l;
274     return 1;
275 }
276
277 static int parse_dh_special(const char *s, const char **dh_special)
278 {
279     if ((strcmp(s, "NULL") == 0) || (strcmp(s, "generate") == 0) ||
280         (strcmp(s, "standard") == 0)) {
281         *dh_special = s;
282         return 1;
283     }
284     fprintf(stderr, "Error, '%s' is an invalid value for 'dh_special'\n", s);
285     return 0;
286 }
287
288 static int parse_verify_level(const char *s, unsigned int *verify_level)
289 {
290     unsigned long l;
291     if (!int_strtoul(s, &l) || (l > 3)) {
292         fprintf(stderr, "Error, '%s' is an invalid value for "
293                 "out_verify\n", s);
294         return 0;
295     }
296     *verify_level = (unsigned int)l;
297     return 1;
298 }
299
300 static int parse_verify_depth(const char *s, unsigned int *verify_depth)
301 {
302     unsigned long l;
303     if (!int_strtoul(s, &l) || (l < 1) || (l > 50)) {
304         fprintf(stderr, "Error, '%s' is an invalid value for "
305                 "verify_depth\n", s);
306         return 0;
307     }
308     *verify_depth = (unsigned int)l;
309     return 1;
310 }
311
312 /* Some fprintf format strings used when tunnels close */
313 static const char *io_stats_dirty =
314     "    SSL traffic;   %8lu bytes in, %8lu bytes out\n";
315 static const char *io_stats_clean =
316     "    clear traffic; %8lu bytes in, %8lu bytes out\n";
317
318 int main(int argc, char *argv[])
319 {
320     unsigned int loop;
321     int newfd;
322     tunala_world_t world;
323     tunala_item_t *t_item;
324     const char *proxy_ip;
325     unsigned short proxy_port;
326     /* Overridables */
327     const char *proxyhost = def_proxyhost;
328     const char *listenhost = def_listenhost;
329     unsigned int max_tunnels = def_max_tunnels;
330     const char *cacert = def_cacert;
331     const char *cert = def_cert;
332     const char *key = def_key;
333     const char *dcert = def_dcert;
334     const char *dkey = def_dkey;
335     const char *engine_id = def_engine_id;
336     int server_mode = def_server_mode;
337     int flipped = def_flipped;
338     const char *cipher_list = def_cipher_list;
339     const char *dh_file = def_dh_file;
340     const char *dh_special = def_dh_special;
341     int tmp_rsa = def_tmp_rsa;
342     int ctx_options = def_ctx_options;
343     int verify_mode = def_verify_mode;
344     unsigned int verify_depth = def_verify_depth;
345     int out_state = def_out_state;
346     unsigned int out_verify = def_out_verify;
347     int out_totals = def_out_totals;
348     int out_conns = def_out_conns;
349
350 /* Parse command-line arguments */
351  next_arg:
352     argc--;
353     argv++;
354     if (argc > 0) {
355         if (strcmp(*argv, "-listen") == 0) {
356             if (argc < 2)
357                 return usage("-listen requires an argument", 0);
358             argc--;
359             argv++;
360             listenhost = *argv;
361             goto next_arg;
362         } else if (strcmp(*argv, "-proxy") == 0) {
363             if (argc < 2)
364                 return usage("-proxy requires an argument", 0);
365             argc--;
366             argv++;
367             proxyhost = *argv;
368             goto next_arg;
369         } else if (strcmp(*argv, "-maxtunnels") == 0) {
370             if (argc < 2)
371                 return usage("-maxtunnels requires an argument", 0);
372             argc--;
373             argv++;
374             if (!parse_max_tunnels(*argv, &max_tunnels))
375                 return 1;
376             goto next_arg;
377         } else if (strcmp(*argv, "-cacert") == 0) {
378             if (argc < 2)
379                 return usage("-cacert requires an argument", 0);
380             argc--;
381             argv++;
382             if (strcmp(*argv, "NULL") == 0)
383                 cacert = NULL;
384             else
385                 cacert = *argv;
386             goto next_arg;
387         } else if (strcmp(*argv, "-cert") == 0) {
388             if (argc < 2)
389                 return usage("-cert requires an argument", 0);
390             argc--;
391             argv++;
392             if (strcmp(*argv, "NULL") == 0)
393                 cert = NULL;
394             else
395                 cert = *argv;
396             goto next_arg;
397         } else if (strcmp(*argv, "-key") == 0) {
398             if (argc < 2)
399                 return usage("-key requires an argument", 0);
400             argc--;
401             argv++;
402             if (strcmp(*argv, "NULL") == 0)
403                 key = NULL;
404             else
405                 key = *argv;
406             goto next_arg;
407         } else if (strcmp(*argv, "-dcert") == 0) {
408             if (argc < 2)
409                 return usage("-dcert requires an argument", 0);
410             argc--;
411             argv++;
412             if (strcmp(*argv, "NULL") == 0)
413                 dcert = NULL;
414             else
415                 dcert = *argv;
416             goto next_arg;
417         } else if (strcmp(*argv, "-dkey") == 0) {
418             if (argc < 2)
419                 return usage("-dkey requires an argument", 0);
420             argc--;
421             argv++;
422             if (strcmp(*argv, "NULL") == 0)
423                 dkey = NULL;
424             else
425                 dkey = *argv;
426             goto next_arg;
427         } else if (strcmp(*argv, "-engine") == 0) {
428             if (argc < 2)
429                 return usage("-engine requires an argument", 0);
430             argc--;
431             argv++;
432             engine_id = *argv;
433             goto next_arg;
434         } else if (strcmp(*argv, "-server") == 0) {
435             if (argc < 2)
436                 return usage("-server requires an argument", 0);
437             argc--;
438             argv++;
439             if (!parse_server_mode(*argv, &server_mode))
440                 return 1;
441             goto next_arg;
442         } else if (strcmp(*argv, "-flipped") == 0) {
443             if (argc < 2)
444                 return usage("-flipped requires an argument", 0);
445             argc--;
446             argv++;
447             if (!parse_server_mode(*argv, &flipped))
448                 return 1;
449             goto next_arg;
450         } else if (strcmp(*argv, "-cipher") == 0) {
451             if (argc < 2)
452                 return usage("-cipher requires an argument", 0);
453             argc--;
454             argv++;
455             cipher_list = *argv;
456             goto next_arg;
457         } else if (strcmp(*argv, "-dh_file") == 0) {
458             if (argc < 2)
459                 return usage("-dh_file requires an argument", 0);
460             if (dh_special)
461                 return usage("cannot mix -dh_file with " "-dh_special", 0);
462             argc--;
463             argv++;
464             dh_file = *argv;
465             goto next_arg;
466         } else if (strcmp(*argv, "-dh_special") == 0) {
467             if (argc < 2)
468                 return usage("-dh_special requires an argument", 0);
469             if (dh_file)
470                 return usage("cannot mix -dh_file with " "-dh_special", 0);
471             argc--;
472             argv++;
473             if (!parse_dh_special(*argv, &dh_special))
474                 return 1;
475             goto next_arg;
476         } else if (strcmp(*argv, "-no_tmp_rsa") == 0) {
477             tmp_rsa = 0;
478             goto next_arg;
479         } else if (strcmp(*argv, "-no_ssl2") == 0) {
480             ctx_options |= SSL_OP_NO_SSLv2;
481             goto next_arg;
482         } else if (strcmp(*argv, "-no_ssl3") == 0) {
483             ctx_options |= SSL_OP_NO_SSLv3;
484             goto next_arg;
485         } else if (strcmp(*argv, "-no_tls1") == 0) {
486             ctx_options |= SSL_OP_NO_TLSv1;
487             goto next_arg;
488         } else if (strcmp(*argv, "-v_peer") == 0) {
489             verify_mode |= SSL_VERIFY_PEER;
490             goto next_arg;
491         } else if (strcmp(*argv, "-v_strict") == 0) {
492             verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
493             goto next_arg;
494         } else if (strcmp(*argv, "-v_once") == 0) {
495             verify_mode |= SSL_VERIFY_CLIENT_ONCE;
496             goto next_arg;
497         } else if (strcmp(*argv, "-v_depth") == 0) {
498             if (argc < 2)
499                 return usage("-v_depth requires an argument", 0);
500             argc--;
501             argv++;
502             if (!parse_verify_depth(*argv, &verify_depth))
503                 return 1;
504             goto next_arg;
505         } else if (strcmp(*argv, "-out_state") == 0) {
506             out_state = 1;
507             goto next_arg;
508         } else if (strcmp(*argv, "-out_verify") == 0) {
509             if (argc < 2)
510                 return usage("-out_verify requires an argument", 0);
511             argc--;
512             argv++;
513             if (!parse_verify_level(*argv, &out_verify))
514                 return 1;
515             goto next_arg;
516         } else if (strcmp(*argv, "-out_totals") == 0) {
517             out_totals = 1;
518             goto next_arg;
519         } else if (strcmp(*argv, "-out_conns") == 0) {
520             out_conns = 1;
521             goto next_arg;
522         } else if ((strcmp(*argv, "-h") == 0) ||
523                    (strcmp(*argv, "-help") == 0) ||
524                    (strcmp(*argv, "-?") == 0)) {
525             fprintf(stderr, "%s\n", helpstring);
526             return 0;
527         } else
528             return usage(*argv, 1);
529     }
530     /* Run any sanity checks we want here */
531     if (!cert && !dcert && server_mode)
532         fprintf(stderr, "WARNING: you are running an SSL server without "
533                 "a certificate - this may not work!\n");
534
535     /* Initialise network stuff */
536     if (!ip_initialise())
537         return err_str0("ip_initialise failed");
538     /* Create the SSL_CTX */
539     if ((world.ssl_ctx = initialise_ssl_ctx(server_mode, engine_id,
540                                             cacert, cert, key, dcert, dkey,
541                                             cipher_list, dh_file, dh_special,
542                                             tmp_rsa, ctx_options, out_state,
543                                             out_verify, verify_mode,
544                                             verify_depth)) == NULL)
545         return err_str1("initialise_ssl_ctx(engine_id=%s) failed",
546                         (engine_id == NULL) ? "NULL" : engine_id);
547     if (engine_id)
548         fprintf(stderr, "Info, engine '%s' initialised\n", engine_id);
549     /* Create the listener */
550     if ((world.listen_fd = ip_create_listener(listenhost)) == -1)
551         return err_str1("ip_create_listener(%s) failed", listenhost);
552     fprintf(stderr, "Info, listening on '%s'\n", listenhost);
553     if (!ip_parse_address(proxyhost, &proxy_ip, &proxy_port, 0))
554         return err_str1("ip_parse_address(%s) failed", proxyhost);
555     fprintf(stderr, "Info, proxying to '%s' (%d.%d.%d.%d:%d)\n", proxyhost,
556             (int)proxy_ip[0], (int)proxy_ip[1],
557             (int)proxy_ip[2], (int)proxy_ip[3], (int)proxy_port);
558     fprintf(stderr, "Info, set maxtunnels to %d\n", (int)max_tunnels);
559     fprintf(stderr, "Info, set to operate as an SSL %s\n",
560             (server_mode ? "server" : "client"));
561     /* Initialise the rest of the stuff */
562     world.tunnels_used = world.tunnels_size = 0;
563     world.tunnels = NULL;
564     world.server_mode = server_mode;
565     selector_init(&world.selector);
566
567 /* We're ready to loop */
568  main_loop:
569     /* Should we listen for *new* tunnels? */
570     if (world.tunnels_used < max_tunnels)
571         selector_add_listener(&world.selector, world.listen_fd);
572     /* We should add in our existing tunnels */
573     for (loop = 0; loop < world.tunnels_used; loop++)
574         selector_add_tunala(&world.selector, world.tunnels + loop);
575     /* Now do the select */
576     switch (selector_select(&world.selector)) {
577     case -1:
578         if (errno != EINTR) {
579             fprintf(stderr, "selector_select returned a " "badness error.\n");
580             goto shouldnt_happen;
581         }
582         fprintf(stderr, "Warn, selector interrupted by a signal\n");
583         goto main_loop;
584     case 0:
585         fprintf(stderr, "Warn, selector_select returned 0 - signal?" "?\n");
586         goto main_loop;
587     default:
588         break;
589     }
590     /* Accept new connection if we should and can */
591     if ((world.tunnels_used < max_tunnels)
592         && (selector_get_listener(&world.selector, world.listen_fd, &newfd) ==
593             1)) {
594         /* We have a new connection */
595         if (!tunala_world_new_item(&world, newfd, proxy_ip,
596                                    proxy_port, flipped))
597             fprintf(stderr, "tunala_world_new_item failed\n");
598         else if (out_conns)
599             fprintf(stderr, "Info, new tunnel opened, now up to "
600                     "%d\n", world.tunnels_used);
601     }
602     /*
603      * Give each tunnel its moment, note the while loop is because it makes
604      * the logic easier than with "for" to deal with an array that may shift
605      * because of deletes.
606      */
607     loop = 0;
608     t_item = world.tunnels;
609     while (loop < world.tunnels_used) {
610         if (!tunala_item_io(&world.selector, t_item)) {
611             /*
612              * We're closing whether for reasons of an error or a natural
613              * close. Don't increment loop or t_item because the next item is
614              * moving to us!
615              */
616             if (!out_totals)
617                 goto skip_totals;
618             fprintf(stderr, "Tunnel closing, traffic stats follow\n");
619             /* Display the encrypted (over the network) stats */
620             fprintf(stderr, io_stats_dirty,
621                     buffer_total_in(state_machine_get_buffer
622                                     (&t_item->sm, SM_DIRTY_IN)),
623                     buffer_total_out(state_machine_get_buffer
624                                      (&t_item->sm, SM_DIRTY_OUT)));
625             /*
626              * Display the local (tunnelled) stats. NB: Data we *receive* is
627              * data sent *out* of the state_machine on its 'clean' side.
628              * Hence the apparent back-to-front OUT/IN mixup here :-)
629              */
630             fprintf(stderr, io_stats_clean,
631                     buffer_total_out(state_machine_get_buffer
632                                      (&t_item->sm, SM_CLEAN_OUT)),
633                     buffer_total_in(state_machine_get_buffer
634                                     (&t_item->sm, SM_CLEAN_IN)));
635  skip_totals:
636             tunala_world_del_item(&world, loop);
637             if (out_conns)
638                 fprintf(stderr, "Info, tunnel closed, down to %d\n",
639                         world.tunnels_used);
640         } else {
641             /* Move to the next item */
642             loop++;
643             t_item++;
644         }
645     }
646     goto main_loop;
647     /* Should never get here */
648  shouldnt_happen:
649     abort();
650     return 1;
651 }
652
653 /****************/
654 /* OpenSSL bits */
655 /****************/
656
657 static int ctx_set_cert(SSL_CTX *ctx, const char *cert, const char *key)
658 {
659     FILE *fp = NULL;
660     X509 *x509 = NULL;
661     EVP_PKEY *pkey = NULL;
662     int toret = 0;              /* Assume an error */
663
664     /* cert */
665     if (cert) {
666         if ((fp = fopen(cert, "r")) == NULL) {
667             fprintf(stderr, "Error opening cert file '%s'\n", cert);
668             goto err;
669         }
670         if (!PEM_read_X509(fp, &x509, NULL, NULL)) {
671             fprintf(stderr, "Error reading PEM cert from '%s'\n", cert);
672             goto err;
673         }
674         if (!SSL_CTX_use_certificate(ctx, x509)) {
675             fprintf(stderr, "Error, cert in '%s' can not be used\n", cert);
676             goto err;
677         }
678         /* Clear the FILE* for reuse in the "key" code */
679         fclose(fp);
680         fp = NULL;
681         fprintf(stderr, "Info, operating with cert in '%s'\n", cert);
682         /*
683          * If a cert was given without matching key, we assume the same file
684          * contains the required key.
685          */
686         if (!key)
687             key = cert;
688     } else {
689         if (key)
690             fprintf(stderr, "Error, can't specify a key without a "
691                     "corresponding certificate\n");
692         else
693             fprintf(stderr, "Error, ctx_set_cert called with " "NULLs!\n");
694         goto err;
695     }
696     /* key */
697     if (key) {
698         if ((fp = fopen(key, "r")) == NULL) {
699             fprintf(stderr, "Error opening key file '%s'\n", key);
700             goto err;
701         }
702         if (!PEM_read_PrivateKey(fp, &pkey, NULL, NULL)) {
703             fprintf(stderr, "Error reading PEM key from '%s'\n", key);
704             goto err;
705         }
706         if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {
707             fprintf(stderr, "Error, key in '%s' can not be used\n", key);
708             goto err;
709         }
710         fprintf(stderr, "Info, operating with key in '%s'\n", key);
711     } else
712         fprintf(stderr, "Info, operating without a cert or key\n");
713     /* Success */
714     toret = 1;
715  err:
716     if (x509)
717         X509_free(x509);
718     if (pkey)
719         EVP_PKEY_free(pkey);
720     if (fp)
721         fclose(fp);
722     return toret;
723 }
724
725 static int ctx_set_dh(SSL_CTX *ctx, const char *dh_file,
726                       const char *dh_special)
727 {
728     DH *dh = NULL;
729     FILE *fp = NULL;
730
731     if (dh_special) {
732         if (strcmp(dh_special, "NULL") == 0)
733             return 1;
734         if (strcmp(dh_special, "standard") == 0) {
735             if ((dh = get_dh512()) == NULL) {
736                 fprintf(stderr, "Error, can't parse 'standard'"
737                         " DH parameters\n");
738                 return 0;
739             }
740             fprintf(stderr, "Info, using 'standard' DH parameters\n");
741             goto do_it;
742         }
743         if (strcmp(dh_special, "generate") != 0)
744             /*
745              * This shouldn't happen - screening values is handled in main().
746              */
747             abort();
748         fprintf(stderr, "Info, generating DH parameters ... ");
749         fflush(stderr);
750         if ((dh = DH_generate_parameters(512, DH_GENERATOR_5,
751                                          NULL, NULL)) == NULL) {
752             fprintf(stderr, "error!\n");
753             return 0;
754         }
755         fprintf(stderr, "complete\n");
756         goto do_it;
757     }
758     /* So, we're loading dh_file */
759     if ((fp = fopen(dh_file, "r")) == NULL) {
760         fprintf(stderr, "Error, couldn't open '%s' for DH parameters\n",
761                 dh_file);
762         return 0;
763     }
764     dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
765     fclose(fp);
766     if (dh == NULL) {
767         fprintf(stderr, "Error, could not parse DH parameters from '%s'\n",
768                 dh_file);
769         return 0;
770     }
771     fprintf(stderr, "Info, using DH parameters from file '%s'\n", dh_file);
772  do_it:
773     SSL_CTX_set_tmp_dh(ctx, dh);
774     DH_free(dh);
775     return 1;
776 }
777
778 static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id,
779                                    const char *CAfile, const char *cert,
780                                    const char *key, const char *dcert,
781                                    const char *dkey, const char *cipher_list,
782                                    const char *dh_file,
783                                    const char *dh_special, int tmp_rsa,
784                                    int ctx_options, int out_state,
785                                    int out_verify, int verify_mode,
786                                    unsigned int verify_depth)
787 {
788     SSL_CTX *ctx = NULL, *ret = NULL;
789     SSL_METHOD *meth;
790     ENGINE *e = NULL;
791
792     OpenSSL_add_ssl_algorithms();
793     SSL_load_error_strings();
794
795     meth = (server_mode ? SSLv23_server_method() : SSLv23_client_method());
796     if (meth == NULL)
797         goto err;
798     if (engine_id) {
799         ENGINE_load_builtin_engines();
800         if ((e = ENGINE_by_id(engine_id)) == NULL) {
801             fprintf(stderr, "Error obtaining '%s' engine, openssl "
802                     "errors follow\n", engine_id);
803             goto err;
804         }
805         if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
806             fprintf(stderr, "Error assigning '%s' engine, openssl "
807                     "errors follow\n", engine_id);
808             goto err;
809         }
810         ENGINE_free(e);
811     }
812     if ((ctx = SSL_CTX_new(meth)) == NULL)
813         goto err;
814     /* cacert */
815     if (CAfile) {
816         if (!X509_STORE_load_locations(SSL_CTX_get_cert_store(ctx),
817                                        CAfile, NULL)) {
818             fprintf(stderr, "Error loading CA cert(s) in '%s'\n", CAfile);
819             goto err;
820         }
821         fprintf(stderr, "Info, operating with CA cert(s) in '%s'\n", CAfile);
822     } else
823         fprintf(stderr, "Info, operating without a CA cert(-list)\n");
824     if (!SSL_CTX_set_default_verify_paths(ctx)) {
825         fprintf(stderr, "Error setting default verify paths\n");
826         goto err;
827     }
828
829     /* cert and key */
830     if ((cert || key) && !ctx_set_cert(ctx, cert, key))
831         goto err;
832     /* dcert and dkey */
833     if ((dcert || dkey) && !ctx_set_cert(ctx, dcert, dkey))
834         goto err;
835     /* temporary RSA key generation */
836     if (tmp_rsa)
837         SSL_CTX_set_tmp_rsa_callback(ctx, cb_generate_tmp_rsa);
838
839     /* cipher_list */
840     if (cipher_list) {
841         if (!SSL_CTX_set_cipher_list(ctx, cipher_list)) {
842             fprintf(stderr, "Error setting cipher list '%s'\n", cipher_list);
843             goto err;
844         }
845         fprintf(stderr, "Info, set cipher list '%s'\n", cipher_list);
846     } else
847         fprintf(stderr, "Info, operating with default cipher list\n");
848
849     /* dh_file & dh_special */
850     if ((dh_file || dh_special) && !ctx_set_dh(ctx, dh_file, dh_special))
851         goto err;
852
853     /* ctx_options */
854     SSL_CTX_set_options(ctx, ctx_options);
855
856     /* out_state (output of SSL handshake states to screen). */
857     if (out_state)
858         cb_ssl_info_set_output(stderr);
859
860     /* out_verify */
861     if (out_verify > 0) {
862         cb_ssl_verify_set_output(stderr);
863         cb_ssl_verify_set_level(out_verify);
864     }
865
866     /* verify_depth */
867     cb_ssl_verify_set_depth(verify_depth);
868
869     /* Success! (includes setting verify_mode) */
870     SSL_CTX_set_info_callback(ctx, cb_ssl_info);
871     SSL_CTX_set_verify(ctx, verify_mode, cb_ssl_verify);
872     ret = ctx;
873  err:
874     if (!ret) {
875         ERR_print_errors_fp(stderr);
876         if (ctx)
877             SSL_CTX_free(ctx);
878     }
879     return ret;
880 }
881
882 /*****************/
883 /* Selector bits */
884 /*****************/
885
886 static void selector_sets_init(select_sets_t * s)
887 {
888     s->max = 0;
889     FD_ZERO(&s->reads);
890     FD_ZERO(&s->sends);
891     FD_ZERO(&s->excepts);
892 }
893
894 static void selector_init(tunala_selector_t * selector)
895 {
896     selector_sets_init(&selector->last_selected);
897     selector_sets_init(&selector->next_select);
898 }
899
900 #define SEL_EXCEPTS 0x00
901 #define SEL_READS   0x01
902 #define SEL_SENDS   0x02
903 static void selector_add_raw_fd(tunala_selector_t * s, int fd, int flags)
904 {
905     FD_SET(fd, &s->next_select.excepts);
906     if (flags & SEL_READS)
907         FD_SET(fd, &s->next_select.reads);
908     if (flags & SEL_SENDS)
909         FD_SET(fd, &s->next_select.sends);
910     /* Adjust "max" */
911     if (s->next_select.max < (fd + 1))
912         s->next_select.max = fd + 1;
913 }
914
915 static void selector_add_listener(tunala_selector_t * selector, int fd)
916 {
917     selector_add_raw_fd(selector, fd, SEL_READS);
918 }
919
920 static void selector_add_tunala(tunala_selector_t * s, tunala_item_t * t)
921 {
922     /* Set clean read if sm.clean_in is not full */
923     if (t->clean_read != -1) {
924         selector_add_raw_fd(s, t->clean_read,
925                             (buffer_full(state_machine_get_buffer(&t->sm,
926                                                                   SM_CLEAN_IN))
927                              ? SEL_EXCEPTS : SEL_READS));
928     }
929     /* Set clean send if sm.clean_out is not empty */
930     if (t->clean_send != -1) {
931         selector_add_raw_fd(s, t->clean_send,
932                             (buffer_empty(state_machine_get_buffer(&t->sm,
933                                                                    SM_CLEAN_OUT))
934                              ? SEL_EXCEPTS : SEL_SENDS));
935     }
936     /* Set dirty read if sm.dirty_in is not full */
937     if (t->dirty_read != -1) {
938         selector_add_raw_fd(s, t->dirty_read,
939                             (buffer_full(state_machine_get_buffer(&t->sm,
940                                                                   SM_DIRTY_IN))
941                              ? SEL_EXCEPTS : SEL_READS));
942     }
943     /* Set dirty send if sm.dirty_out is not empty */
944     if (t->dirty_send != -1) {
945         selector_add_raw_fd(s, t->dirty_send,
946                             (buffer_empty(state_machine_get_buffer(&t->sm,
947                                                                    SM_DIRTY_OUT))
948                              ? SEL_EXCEPTS : SEL_SENDS));
949     }
950 }
951
952 static int selector_select(tunala_selector_t * selector)
953 {
954     memcpy(&selector->last_selected, &selector->next_select,
955            sizeof(select_sets_t));
956     selector_sets_init(&selector->next_select);
957     return select(selector->last_selected.max,
958                   &selector->last_selected.reads,
959                   &selector->last_selected.sends,
960                   &selector->last_selected.excepts, NULL);
961 }
962
963 /*
964  * This returns -1 for error, 0 for no new connections, or 1 for success, in
965  * which case *newfd is populated.
966  */
967 static int selector_get_listener(tunala_selector_t * selector, int fd,
968                                  int *newfd)
969 {
970     if (FD_ISSET(fd, &selector->last_selected.excepts))
971         return -1;
972     if (!FD_ISSET(fd, &selector->last_selected.reads))
973         return 0;
974     if ((*newfd = ip_accept_connection(fd)) == -1)
975         return -1;
976     return 1;
977 }
978
979 /************************/
980 /* "Tunala" world stuff */
981 /************************/
982
983 static int tunala_world_make_room(tunala_world_t * world)
984 {
985     unsigned int newsize;
986     tunala_item_t *newarray;
987
988     if (world->tunnels_used < world->tunnels_size)
989         return 1;
990     newsize = (world->tunnels_size == 0 ? 16 :
991                ((world->tunnels_size * 3) / 2));
992     if ((newarray = malloc(newsize * sizeof(tunala_item_t))) == NULL)
993         return 0;
994     memset(newarray, 0, newsize * sizeof(tunala_item_t));
995     if (world->tunnels_used > 0)
996         memcpy(newarray, world->tunnels,
997                world->tunnels_used * sizeof(tunala_item_t));
998     if (world->tunnels_size > 0)
999         free(world->tunnels);
1000     /* migrate */
1001     world->tunnels = newarray;
1002     world->tunnels_size = newsize;
1003     return 1;
1004 }
1005
1006 static int tunala_world_new_item(tunala_world_t * world, int fd,
1007                                  const char *ip, unsigned short port,
1008                                  int flipped)
1009 {
1010     tunala_item_t *item;
1011     int newfd;
1012     SSL *new_ssl = NULL;
1013
1014     if (!tunala_world_make_room(world))
1015         return 0;
1016     if ((new_ssl = SSL_new(world->ssl_ctx)) == NULL) {
1017         fprintf(stderr, "Error creating new SSL\n");
1018         ERR_print_errors_fp(stderr);
1019         return 0;
1020     }
1021     item = world->tunnels + (world->tunnels_used++);
1022     state_machine_init(&item->sm);
1023     item->clean_read = item->clean_send =
1024         item->dirty_read = item->dirty_send = -1;
1025     if ((newfd = ip_create_connection_split(ip, port)) == -1)
1026         goto err;
1027     /*
1028      * Which way round? If we're a server, "fd" is the dirty side and the
1029      * connection we open is the clean one. For a client, it's the other way
1030      * around. Unless, of course, we're "flipped" in which case everything
1031      * gets reversed. :-)
1032      */
1033     if ((world->server_mode && !flipped) || (!world->server_mode && flipped)) {
1034         item->dirty_read = item->dirty_send = fd;
1035         item->clean_read = item->clean_send = newfd;
1036     } else {
1037         item->clean_read = item->clean_send = fd;
1038         item->dirty_read = item->dirty_send = newfd;
1039     }
1040     /*
1041      * We use the SSL's "app_data" to indicate a call-back induced "kill"
1042      */
1043     SSL_set_app_data(new_ssl, NULL);
1044     if (!state_machine_set_SSL(&item->sm, new_ssl, world->server_mode))
1045         goto err;
1046     return 1;
1047  err:
1048     tunala_world_del_item(world, world->tunnels_used - 1);
1049     return 0;
1050
1051 }
1052
1053 static void tunala_world_del_item(tunala_world_t * world, unsigned int idx)
1054 {
1055     tunala_item_t *item = world->tunnels + idx;
1056     if (item->clean_read != -1)
1057         close(item->clean_read);
1058     if (item->clean_send != item->clean_read)
1059         close(item->clean_send);
1060     item->clean_read = item->clean_send = -1;
1061     if (item->dirty_read != -1)
1062         close(item->dirty_read);
1063     if (item->dirty_send != item->dirty_read)
1064         close(item->dirty_send);
1065     item->dirty_read = item->dirty_send = -1;
1066     state_machine_close(&item->sm);
1067     /* OK, now we fix the item array */
1068     if (idx + 1 < world->tunnels_used)
1069         /* We need to scroll entries to the left */
1070         memmove(world->tunnels + idx,
1071                 world->tunnels + (idx + 1),
1072                 (world->tunnels_used - (idx + 1)) * sizeof(tunala_item_t));
1073     world->tunnels_used--;
1074 }
1075
1076 static int tunala_item_io(tunala_selector_t * selector, tunala_item_t * item)
1077 {
1078     int c_r, c_s, d_r, d_s;     /* Four boolean flags */
1079
1080     /* Take ourselves out of the gene-pool if there was an except */
1081     if ((item->clean_read != -1) && FD_ISSET(item->clean_read,
1082                                              &selector->
1083                                              last_selected.excepts))
1084         return 0;
1085     if ((item->clean_send != -1) && FD_ISSET(item->clean_send,
1086                                              &selector->
1087                                              last_selected.excepts))
1088         return 0;
1089     if ((item->dirty_read != -1) && FD_ISSET(item->dirty_read,
1090                                              &selector->
1091                                              last_selected.excepts))
1092         return 0;
1093     if ((item->dirty_send != -1) && FD_ISSET(item->dirty_send,
1094                                              &selector->
1095                                              last_selected.excepts))
1096         return 0;
1097     /* Grab our 4 IO flags */
1098     c_r = c_s = d_r = d_s = 0;
1099     if (item->clean_read != -1)
1100         c_r = FD_ISSET(item->clean_read, &selector->last_selected.reads);
1101     if (item->clean_send != -1)
1102         c_s = FD_ISSET(item->clean_send, &selector->last_selected.sends);
1103     if (item->dirty_read != -1)
1104         d_r = FD_ISSET(item->dirty_read, &selector->last_selected.reads);
1105     if (item->dirty_send != -1)
1106         d_s = FD_ISSET(item->dirty_send, &selector->last_selected.sends);
1107     /* If no IO has happened for us, skip needless data looping */
1108     if (!c_r && !c_s && !d_r && !d_s)
1109         return 1;
1110     if (c_r)
1111         c_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1112                                                        SM_CLEAN_IN),
1113                               item->clean_read) <= 0);
1114     if (c_s)
1115         c_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1116                                                      SM_CLEAN_OUT),
1117                             item->clean_send) <= 0);
1118     if (d_r)
1119         d_r = (buffer_from_fd(state_machine_get_buffer(&item->sm,
1120                                                        SM_DIRTY_IN),
1121                               item->dirty_read) <= 0);
1122     if (d_s)
1123         d_s = (buffer_to_fd(state_machine_get_buffer(&item->sm,
1124                                                      SM_DIRTY_OUT),
1125                             item->dirty_send) <= 0);
1126     /* If any of the flags is non-zero, that means they need closing */
1127     if (c_r) {
1128         close(item->clean_read);
1129         if (item->clean_send == item->clean_read)
1130             item->clean_send = -1;
1131         item->clean_read = -1;
1132     }
1133     if (c_s && (item->clean_send != -1)) {
1134         close(item->clean_send);
1135         if (item->clean_send == item->clean_read)
1136             item->clean_read = -1;
1137         item->clean_send = -1;
1138     }
1139     if (d_r) {
1140         close(item->dirty_read);
1141         if (item->dirty_send == item->dirty_read)
1142             item->dirty_send = -1;
1143         item->dirty_read = -1;
1144     }
1145     if (d_s && (item->dirty_send != -1)) {
1146         close(item->dirty_send);
1147         if (item->dirty_send == item->dirty_read)
1148             item->dirty_read = -1;
1149         item->dirty_send = -1;
1150     }
1151     /*
1152      * This function name is attributed to the term donated by David Schwartz
1153      * on openssl-dev, message-ID:
1154      * <NCBBLIEPOCbmasEKBEAKEEDGLIAA.davids@webmaster.com>. :-)
1155      */
1156     if (!state_machine_churn(&item->sm))
1157         /*
1158          * If the SSL closes, it will also zero-out the _in buffers and will
1159          * in future process just outgoing data. As and when the outgoing
1160          * data has gone, it will return zero here to tell us to bail out.
1161          */
1162         return 0;
1163     /* Otherwise, we return zero if both sides are dead. */
1164     if (((item->clean_read == -1) || (item->clean_send == -1)) &&
1165         ((item->dirty_read == -1) || (item->dirty_send == -1)))
1166         return 0;
1167     /*
1168      * If only one side closed, notify the SSL of this so it can take
1169      * appropriate action.
1170      */
1171     if ((item->clean_read == -1) || (item->clean_send == -1)) {
1172         if (!state_machine_close_clean(&item->sm))
1173             return 0;
1174     }
1175     if ((item->dirty_read == -1) || (item->dirty_send == -1)) {
1176         if (!state_machine_close_dirty(&item->sm))
1177             return 0;
1178     }
1179     return 1;
1180 }