Allow building against GnuTLS (for TCP) and GnuTLS (for DTLS) simultaneously
[platform/upstream/openconnect.git] / dtls.c
1 /*
2  * OpenConnect (SSL + DTLS) VPN client
3  *
4  * Copyright © 2008-2012 Intel Corporation.
5  *
6  * Author: David Woodhouse <dwmw2@infradead.org>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * version 2.1, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to:
19  *
20  *   Free Software Foundation, Inc.
21  *   51 Franklin Street, Fifth Floor,
22  *   Boston, MA 02110-1301 USA
23  */
24
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <unistd.h>
30 #include <netinet/in.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36
37 #include "openconnect-internal.h"
38
39 #ifdef HAVE_DTLS1_STOP_TIMER
40 /* OpenSSL doesn't deliberately export this, but we need it to
41    workaround a DTLS bug in versions < 1.0.0e */
42 extern void dtls1_stop_timer (SSL *);
43 #endif
44
45 static unsigned char nybble(unsigned char n)
46 {
47         if      (n >= '0' && n <= '9') return n - '0';
48         else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
49         else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
50         return 0;
51 }
52
53 unsigned char unhex(const char *data)
54 {
55         return (nybble(data[0]) << 4) | nybble(data[1]);
56 }
57
58 #ifdef HAVE_DTLS
59
60 #if 0
61 /*
62  * Useful for catching test cases, where we want everything to be
63  * reproducible.  *NEVER* do this in the wild.
64  */
65 time_t time(time_t *t)
66 {
67         time_t x = 0x3ab2d948;
68         if (t) *t = x;
69         return x;
70 }
71
72 int RAND_pseudo_bytes(char *buf, int len)
73 {
74         memset(buf, 0x5a, len);
75         printf("FAKE PSEUDO RANDOM!\n");
76         return 1;
77
78 }
79 int RAND_bytes(char *buf, int len)
80 {
81         static int foo = 0x5b;
82         printf("FAKE RANDOM!\n");
83         memset(buf, foo, len);
84         return 1;
85 }
86 #endif
87
88 /*
89  * The master-secret is generated randomly by the client. The server
90  * responds with a DTLS Session-ID. These, done over the HTTPS
91  * connection, are enough to 'resume' a DTLS session, bypassing all
92  * the normal setup of a normal DTLS connection.
93  *
94  * Cisco use a version of the protocol which predates RFC4347, but
95  * isn't quite the same as the pre-RFC version of the protocol which
96  * was in OpenSSL 0.9.8e -- it includes backports of some later
97  * OpenSSL patches.
98  *
99  * The openssl/ directory of this source tree should contain both a
100  * small patch against OpenSSL 0.9.8e to make it support Cisco's
101  * snapshot of the protocol, and a larger patch against newer OpenSSL
102  * which gives us an option to use the old protocol again.
103  *
104  * Cisco's server also seems to respond to the official version of the
105  * protocol, with a change in the ChangeCipherSpec packet which implies
106  * that it does know the difference and isn't just repeating the version
107  * number seen in the ClientHello. But although I can make the handshake
108  * complete by hacking tls1_mac() to use the _old_ protocol version
109  * number when calculating the MAC, the server still seems to be ignoring
110  * my subsequent data packets. So we use the old protocol, which is what
111  * their clients use anyway.
112  */
113
114 #if defined (DTLS_OPENSSL)
115 #define DTLS_SEND SSL_write
116 #define DTLS_RECV SSL_read
117 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
118 {
119         STACK_OF(SSL_CIPHER) *ciphers;
120         method_const SSL_METHOD *dtls_method;
121         SSL_CIPHER *dtls_cipher;
122         SSL *dtls_ssl;
123         BIO *dtls_bio;
124
125         if (!vpninfo->dtls_ctx) {
126                 dtls_method = DTLSv1_client_method();
127                 vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
128                 if (!vpninfo->dtls_ctx) {
129                         vpn_progress(vpninfo, PRG_ERR,
130                                      _("Initialise DTLSv1 CTX failed\n"));
131                         openconnect_report_ssl_errors(vpninfo);
132                         vpninfo->dtls_attempt_period = 0;
133                         return -EINVAL;
134                 }
135
136                 /* If we don't readahead, then we do short reads and throw
137                    away the tail of data packets. */
138                 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
139
140                 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
141                         vpn_progress(vpninfo, PRG_ERR,
142                                      _("Set DTLS cipher list failed\n"));
143                         SSL_CTX_free(vpninfo->dtls_ctx);
144                         vpninfo->dtls_ctx = NULL;
145                         vpninfo->dtls_attempt_period = 0;
146                         return -EINVAL;
147                 }
148         }
149
150         if (!vpninfo->dtls_session) {
151                 /* We're going to "resume" a session which never existed. Fake it... */
152                 vpninfo->dtls_session = SSL_SESSION_new();
153                 if (!vpninfo->dtls_session) {
154                         vpn_progress(vpninfo, PRG_ERR,
155                                      _("Initialise DTLSv1 session failed\n"));
156                         vpninfo->dtls_attempt_period = 0;
157                         return -EINVAL;
158                 }
159                 vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */
160         }
161
162         /* Do this every time; it may have changed due to a rekey */
163         vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
164         memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
165                sizeof(vpninfo->dtls_secret));
166
167         vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
168         memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
169                sizeof(vpninfo->dtls_session_id));
170
171         dtls_ssl = SSL_new(vpninfo->dtls_ctx);
172         SSL_set_connect_state(dtls_ssl);
173
174         ciphers = SSL_get_ciphers(dtls_ssl);
175         if (sk_SSL_CIPHER_num(ciphers) != 1) {
176                 vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n"));
177                 SSL_CTX_free(vpninfo->dtls_ctx);
178                 SSL_free(dtls_ssl);
179                 SSL_SESSION_free(vpninfo->dtls_session);
180                 vpninfo->dtls_ctx = NULL;
181                 vpninfo->dtls_session = NULL;
182                 vpninfo->dtls_attempt_period = 0;
183                 return -EINVAL;
184         }
185         dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
186
187         /* Set the appropriate cipher on our session to be resumed */
188         vpninfo->dtls_session->cipher = dtls_cipher;
189         vpninfo->dtls_session->cipher_id = dtls_cipher->id;
190
191         /* Add the generated session to the SSL */
192         if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
193                 vpn_progress(vpninfo, PRG_ERR,
194                              _("SSL_set_session() failed with old protocol version 0x%x\n"
195                                "Are you using a version of OpenSSL older than 0.9.8m?\n"
196                                "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
197                                "Use the --no-dtls command line option to avoid this message\n"),
198                              vpninfo->dtls_session->ssl_version);
199                 vpninfo->dtls_attempt_period = 0;
200                 return -EINVAL;
201         }
202
203         dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
204         /* Set non-blocking */
205         BIO_set_nbio(dtls_bio, 1);
206         SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
207
208         SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
209
210         vpninfo->new_dtls_ssl = dtls_ssl;
211
212         return 0;
213 }
214
215 int dtls_try_handshake(struct openconnect_info *vpninfo)
216 {
217         int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
218
219         if (ret == 1) {
220                 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using OpenSSL)\n"));
221
222                 if (vpninfo->dtls_ssl) {
223                         /* We are replacing an old connection */
224                         SSL_free(vpninfo->dtls_ssl);
225                         close(vpninfo->dtls_fd);
226                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
227                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
228                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
229                 }
230                 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
231                 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
232
233                 vpninfo->new_dtls_ssl = NULL;
234                 vpninfo->new_dtls_fd = -1;
235
236                 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
237
238                 /* From about 8.4.1(11) onwards, the ASA seems to get
239                    very unhappy if we resend ChangeCipherSpec messages
240                    after the initial setup. This was "fixed" in OpenSSL
241                    1.0.0e for RT#2505, but it's not clear if that was
242                    the right fix. What happens if the original packet
243                    *does* get lost? Surely we *wanted* the retransmits,
244                    because without them the server will never be able
245                    to decrypt anything we send?
246                    Oh well, our retransmitted packets upset the server
247                    because we don't get the Cisco-compatibility right
248                    (this is one of the areas in which Cisco's DTLS differs
249                    from the RFC4347 spec), and DPD should help us notice
250                    if *nothing* is getting through. */
251 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
252                 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
253                    However, if we were *built* against 1.0.0e or newer, but at
254                    runtime we find that we are being run against an older 
255                    version, warn about it. */
256                 if (SSLeay() < 0x1000005fL) {
257                         vpn_progress(vpninfo, PRG_ERR,
258                                      _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
259                 }
260 #elif defined (HAVE_DTLS1_STOP_TIMER)
261                 /*
262                  * This works for any normal OpenSSL that supports
263                  * Cisco DTLS compatibility (0.9.8m to 1.0.0d inclusive,
264                  * and even later versions although it isn't needed there.
265                  */
266                 dtls1_stop_timer(vpninfo->dtls_ssl);
267 #elif defined (BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT)
268                 /*
269                  * Debian restricts visibility of dtls1_stop_timer()
270                  * so do it manually. This version also works on all
271                  * sane versions of OpenSSL:
272                  */
273                 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
274                         sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
275                 vpninfo->dtls_ssl->d1->timeout_duration = 1;
276                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
277                          BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
278                          &(vpninfo->dtls_ssl->d1->next_timeout));
279 #elif defined (BIO_CTRL_DGRAM_SET_TIMEOUT)
280                 /*
281                  * OK, here it gets more fun... this shoul handle the case
282                  * of older OpenSSL which has the Cisco DTLS compatibility
283                  * backported, but *not* the fix for RT#1922.
284                  */
285                 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
286                          BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
287 #else
288                 /*
289                  * And if they don't have any of the above, they probably
290                  * don't have RT#1829 fixed either, but that's OK because
291                  * that's the "fix" that *introduces* the timeout we're
292                  * trying to disable. So do nothing...
293                  */
294 #endif
295                 return 0;
296         }
297
298         ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
299         if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
300                 if (time(NULL) < vpninfo->new_dtls_started + 5)
301                         return 0;
302                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
303         }
304
305         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
306         openconnect_report_ssl_errors(vpninfo);
307
308         /* Kill the new (failed) connection... */
309         SSL_free(vpninfo->new_dtls_ssl);
310         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
311         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
312         close(vpninfo->new_dtls_fd);
313         vpninfo->new_dtls_ssl = NULL;
314         vpninfo->new_dtls_fd = -1;
315
316         /* ... and kill the old one too. The only time there'll be a valid
317            existing session is when it was a rekey, and in that case it's
318            time for the old one to die. */
319         if (vpninfo->dtls_ssl) {
320                 SSL_free(vpninfo->dtls_ssl);
321                 close(vpninfo->dtls_fd);
322                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
323                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
324                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
325                 vpninfo->dtls_ssl = NULL;
326                 vpninfo->dtls_fd = -1;
327         }
328
329         time(&vpninfo->new_dtls_started);
330         return -EINVAL;
331 }
332
333 #elif defined (DTLS_GNUTLS)
334 struct {
335         const char *name;
336         gnutls_cipher_algorithm_t cipher;
337         gnutls_mac_algorithm_t mac;
338         const char *prio;
339 } gnutls_dtls_ciphers[] = {
340         { "AES128-SHA", GNUTLS_CIPHER_AES_128_CBC, GNUTLS_MAC_SHA1,
341           "NONE:+VERS-DTLS0.9:+COMP-NULL:+AES-128-CBC:+SHA1:+RSA:%COMPAT:%DISABLE_SAFE_RENEGOTIATION" },
342         { "DES-CBC3-SHA", GNUTLS_CIPHER_3DES_CBC, GNUTLS_MAC_SHA1,
343           "NONE:+VERS-DTLS0.9:+COMP-NULL:+3DES-CBC:+SHA1:+RSA:%COMPAT:%DISABLE_SAFE_RENEGOTIATION" },
344 };
345
346 #define DTLS_SEND gnutls_record_send
347 #define DTLS_RECV gnutls_record_recv
348 static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
349 {
350         gnutls_session_t dtls_ssl;
351         gnutls_datum_t master_secret, session_id;
352         int err;
353         int cipher;
354
355         for (cipher = 0; cipher < sizeof(gnutls_dtls_ciphers)/sizeof(gnutls_dtls_ciphers[0]); cipher++) {
356                 if (!strcmp(vpninfo->dtls_cipher, gnutls_dtls_ciphers[cipher].name))
357                         goto found_cipher;
358         }
359         vpn_progress(vpninfo, PRG_ERR, _("Unknown DTLS parameters for requested CipherSuite '%s'\n"),
360                      vpninfo->dtls_cipher);
361         vpninfo->dtls_attempt_period = 0;
362
363         return -EINVAL;
364
365  found_cipher:
366         gnutls_init(&dtls_ssl, GNUTLS_CLIENT|GNUTLS_DATAGRAM|GNUTLS_NONBLOCK);
367         err = gnutls_priority_set_direct(dtls_ssl,
368                                          gnutls_dtls_ciphers[cipher].prio,
369                                          NULL);
370         if (err) {
371                 vpn_progress(vpninfo, PRG_ERR,
372                              _("Failed to set DTLS priority: %s\n"),
373                              gnutls_strerror(err));
374                 gnutls_deinit(dtls_ssl);
375                 vpninfo->dtls_attempt_period = 0;
376                 return -EINVAL;
377         }
378         gnutls_transport_set_ptr(dtls_ssl,
379                                  (gnutls_transport_ptr_t)(long) dtls_fd);
380         gnutls_record_disable_padding(dtls_ssl);
381         master_secret.data = vpninfo->dtls_secret;
382         master_secret.size = sizeof(vpninfo->dtls_secret);
383         session_id.data = vpninfo->dtls_session_id;
384         session_id.size = sizeof(vpninfo->dtls_session_id);
385         err = gnutls_session_set_premaster(dtls_ssl, GNUTLS_CLIENT, GNUTLS_DTLS0_9,
386                                            GNUTLS_KX_RSA, gnutls_dtls_ciphers[cipher].cipher,
387                                            gnutls_dtls_ciphers[cipher].mac, GNUTLS_COMP_NULL,
388                                            &master_secret, &session_id);
389         if (err) {
390                 vpn_progress(vpninfo, PRG_ERR,
391                              _("Failed to set DTLS session parameters: %s\n"),
392                              gnutls_strerror(err));
393                 gnutls_deinit(dtls_ssl);
394                 vpninfo->dtls_attempt_period = 0;
395                 return -EINVAL;
396         }
397
398         vpninfo->new_dtls_ssl = dtls_ssl;
399         return 0;
400 }
401
402 int dtls_try_handshake(struct openconnect_info *vpninfo)
403 {
404         int err = gnutls_handshake(vpninfo->new_dtls_ssl);
405
406         if (!err) {
407                 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using GnuTLS)\n"));
408
409                 if (vpninfo->dtls_ssl) {
410                         /* We are replacing an old connection */
411                         gnutls_deinit(vpninfo->dtls_ssl);
412                         close(vpninfo->dtls_fd);
413                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
414                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
415                         FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
416                 }
417                 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
418                 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
419
420                 vpninfo->new_dtls_ssl = NULL;
421                 vpninfo->new_dtls_fd = -1;
422
423                 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
424
425                 /* XXX: For OpenSSL we explicitly prevent retransmits here. */
426                 return 0;
427         }
428
429         if (err == GNUTLS_E_AGAIN) {
430                 if (time(NULL) < vpninfo->new_dtls_started + 5)
431                         return 0;
432                 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
433         }
434
435         vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"),
436                      gnutls_strerror(err));
437
438         /* Kill the new (failed) connection... */
439         gnutls_deinit(vpninfo->new_dtls_ssl);
440         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
441         FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
442         close(vpninfo->new_dtls_fd);
443         vpninfo->new_dtls_ssl = NULL;
444         vpninfo->new_dtls_fd = -1;
445
446         /* ... and kill the old one too. The only time there'll be a valid
447            existing session is when it was a rekey, and in that case it's
448            time for the old one to die. */
449         if (vpninfo->dtls_ssl) {
450                 gnutls_deinit(vpninfo->dtls_ssl);
451                 close(vpninfo->dtls_fd);
452                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
453                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
454                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
455                 vpninfo->dtls_ssl = NULL;
456                 vpninfo->dtls_fd = -1;
457         }
458
459         time(&vpninfo->new_dtls_started);
460         return -EINVAL;
461 }
462 #endif
463
464 int connect_dtls_socket(struct openconnect_info *vpninfo)
465 {
466         int dtls_fd, ret;
467
468         if (!vpninfo->dtls_addr) {
469                 vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
470                 vpninfo->dtls_attempt_period = 0;
471                 return -EINVAL;
472         }
473
474         if (!vpninfo->dtls_cipher) {
475                 /* We probably didn't offer it any ciphers it liked */
476                 vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
477                 vpninfo->dtls_attempt_period = 0;
478                 return -EINVAL;
479         }
480
481         if (vpninfo->proxy) {
482                 /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
483                 vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
484                 vpninfo->dtls_attempt_period = 0;
485                 return -EINVAL;
486         }
487
488         dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
489         if (dtls_fd < 0) {
490                 perror(_("Open UDP socket for DTLS:"));
491                 return -EINVAL;
492         }
493
494         if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
495                 perror(_("UDP (DTLS) connect:\n"));
496                 close(dtls_fd);
497                 return -EINVAL;
498         }
499
500         fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
501         fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
502
503         ret = start_dtls_handshake(vpninfo, dtls_fd);
504         if (ret) {
505                 close(dtls_fd);
506                 return ret;
507         }
508
509         vpninfo->new_dtls_fd = dtls_fd;
510         if (vpninfo->select_nfds <= dtls_fd)
511                 vpninfo->select_nfds = dtls_fd + 1;
512
513         FD_SET(dtls_fd, &vpninfo->select_rfds);
514         FD_SET(dtls_fd, &vpninfo->select_efds);
515
516         time(&vpninfo->new_dtls_started);
517
518         return dtls_try_handshake(vpninfo);
519 }
520
521 static int dtls_restart(struct openconnect_info *vpninfo)
522 {
523         if (vpninfo->dtls_ssl) {
524 #if defined (DTLS_OPENSSL)
525                 SSL_free(vpninfo->dtls_ssl);
526 #elif defined (DTLS_GNUTLS)
527                 gnutls_deinit(vpninfo->dtls_ssl);
528 #endif
529                 close(vpninfo->dtls_fd);
530                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
531                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
532                 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
533                 vpninfo->dtls_ssl = NULL;
534                 vpninfo->dtls_fd = -1;
535         }
536
537         return connect_dtls_socket(vpninfo);
538 }
539
540
541 int setup_dtls(struct openconnect_info *vpninfo)
542 {
543         struct vpn_option *dtls_opt = vpninfo->dtls_options;
544         int dtls_port = 0;
545
546 #if defined (OPENCONNECT_GNUTLS) && defined (DTLS_OPENSSL)
547         /* If we're using GnuTLS for authentication but OpenSSL for DTLS,
548            we'll need to initialise OpenSSL now... */
549         SSL_library_init ();
550         ERR_clear_error ();
551         SSL_load_error_strings ();
552         OpenSSL_add_all_algorithms ();
553 #endif
554
555         while (dtls_opt) {
556                 vpn_progress(vpninfo, PRG_TRACE,
557                              _("DTLS option %s : %s\n"),
558                              dtls_opt->option, dtls_opt->value);
559
560                 if (!strcmp(dtls_opt->option + 7, "Port")) {
561                         dtls_port = atol(dtls_opt->value);
562                 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
563                         vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
564                 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
565                         int j = atol(dtls_opt->value);
566                         if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
567                                 vpninfo->dtls_times.dpd = j;
568                 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
569                         vpninfo->dtls_times.rekey = atol(dtls_opt->value);
570                 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
571                         vpninfo->dtls_cipher = strdup(dtls_opt->value);
572                 }
573
574                 dtls_opt = dtls_opt->next;
575         }
576         if (!dtls_port) {
577                 vpninfo->dtls_attempt_period = 0;
578                 return -EINVAL;
579         }
580
581         vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
582         if (!vpninfo->dtls_addr) {
583                 vpninfo->dtls_attempt_period = 0;
584                 return -ENOMEM;
585         }
586         memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
587
588         if (vpninfo->peer_addr->sa_family == AF_INET) {
589                 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
590                 sin->sin_port = htons(dtls_port);
591         } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
592                 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
593                 sin->sin6_port = htons(dtls_port);
594         } else {
595                 vpn_progress(vpninfo, PRG_ERR,
596                              _("Unknown protocol family %d. Cannot do DTLS\n"),
597                              vpninfo->peer_addr->sa_family);
598                 vpninfo->dtls_attempt_period = 0;
599                 return -EINVAL;
600         }
601
602         if (connect_dtls_socket(vpninfo))
603                 return -EINVAL;
604
605         vpn_progress(vpninfo, PRG_TRACE,
606                      _("DTLS connected. DPD %d, Keepalive %d\n"),
607                      vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
608
609         return 0;
610 }
611
612 static struct pkt *dtls_pkt;
613
614 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
615 {
616         int work_done = 0;
617         char magic_pkt;
618
619         while (1) {
620                 int len = vpninfo->mtu;
621                 unsigned char *buf;
622
623                 if (!dtls_pkt) {
624                         dtls_pkt = malloc(sizeof(struct pkt) + len);
625                         if (!dtls_pkt) {
626                                 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
627                                 break;
628                         }
629                 }
630
631                 buf = dtls_pkt->data - 1;
632                 len = DTLS_RECV(vpninfo->dtls_ssl, buf, len + 1);
633                 if (len <= 0)
634                         break;
635
636                 vpn_progress(vpninfo, PRG_TRACE,
637                              _("Received DTLS packet 0x%02x of %d bytes\n"),
638                              buf[0], len);
639
640                 vpninfo->dtls_times.last_rx = time(NULL);
641
642                 switch(buf[0]) {
643                 case AC_PKT_DATA:
644                         dtls_pkt->len = len - 1;
645                         queue_packet(&vpninfo->incoming_queue, dtls_pkt);
646                         dtls_pkt = NULL;
647                         work_done = 1;
648                         break;
649
650                 case AC_PKT_DPD_OUT:
651                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
652
653                         /* FIXME: What if the packet doesn't get through? */
654                         magic_pkt = AC_PKT_DPD_RESP;
655                         if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
656                                 vpn_progress(vpninfo, PRG_ERR,
657                                              _("Failed to send DPD response. Expect disconnect\n"));
658                         continue;
659
660                 case AC_PKT_DPD_RESP:
661                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
662                         break;
663
664                 case AC_PKT_KEEPALIVE:
665                         vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
666                         break;
667
668                 default:
669                         vpn_progress(vpninfo, PRG_ERR,
670                                      _("Unknown DTLS packet type %02x, len %d\n"),
671                                      buf[0], len);
672                         if (1) {
673                                 /* Some versions of OpenSSL have bugs with receiving out-of-order
674                                  * packets. Not only do they wrongly decide to drop packets if
675                                  * two packets get swapped in transit, but they also _fail_ to
676                                  * drop the packet in non-blocking mode; instead they return
677                                  * the appropriate length of garbage. So don't abort... for now. */
678                                 break;
679                         } else {
680                                 vpninfo->quit_reason = "Unknown packet received";
681                                 return 1;
682                         }
683
684                 }
685         }
686
687         switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
688         case KA_REKEY:
689                 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
690
691                 /* There ought to be a method of rekeying DTLS without tearing down
692                    the CSTP session and restarting, but we don't (yet) know it */
693                 if (cstp_reconnect(vpninfo)) {
694                         vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
695                         vpninfo->quit_reason = "CSTP reconnect failed";
696                         return 1;
697                 }
698
699                 if (dtls_restart(vpninfo)) {
700                         vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
701                         return 1;
702                 }
703                 work_done = 1;
704                 break;
705
706
707         case KA_DPD_DEAD:
708                 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
709                 /* Fall back to SSL, and start a new DTLS connection */
710                 dtls_restart(vpninfo);
711                 return 1;
712
713         case KA_DPD:
714                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
715
716                 magic_pkt = AC_PKT_DPD_OUT;
717                 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
718                         vpn_progress(vpninfo, PRG_ERR,
719                                      _("Failed to send DPD request. Expect disconnect\n"));
720
721                 /* last_dpd will just have been set */
722                 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
723                 work_done = 1;
724                 break;
725
726         case KA_KEEPALIVE:
727                 /* No need to send an explicit keepalive
728                    if we have real data to send */
729                 if (vpninfo->outgoing_queue)
730                         break;
731
732                 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
733
734                 magic_pkt = AC_PKT_KEEPALIVE;
735                 if (DTLS_SEND(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
736                         vpn_progress(vpninfo, PRG_ERR,
737                                      _("Failed to send keepalive request. Expect disconnect\n"));
738                 time(&vpninfo->dtls_times.last_tx);
739                 work_done = 1;
740                 break;
741
742         case KA_NONE:
743                 ;
744         }
745
746         /* Service outgoing packet queue */
747         while (vpninfo->outgoing_queue) {
748                 struct pkt *this = vpninfo->outgoing_queue;
749                 int ret;
750
751                 vpninfo->outgoing_queue = this->next;
752                 vpninfo->outgoing_qlen--;
753
754                 /* One byte of header */
755                 this->hdr[7] = AC_PKT_DATA;
756
757 #if defined(DTLS_OPENSSL)
758                 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
759                 if (ret <= 0) {
760                         ret = SSL_get_error(vpninfo->dtls_ssl, ret);
761
762                         /* If it's a real error, kill the DTLS connection and
763                            requeue the packet to be sent over SSL */
764                         if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
765                                 vpn_progress(vpninfo, PRG_ERR,
766                                              _("DTLS got write error %d. Falling back to SSL\n"),
767                                              ret);
768                                 openconnect_report_ssl_errors(vpninfo);
769                                 dtls_restart(vpninfo);
770                                 vpninfo->outgoing_queue = this;
771                                 vpninfo->outgoing_qlen++;
772                         }
773                         return 1;
774                 }
775 #elif defined (DTLS_GNUTLS)
776                 ret = gnutls_record_send(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
777                 if (ret <= 0) {
778                         if (ret != GNUTLS_E_AGAIN) {
779                                 vpn_progress(vpninfo, PRG_ERR,
780                                              _("DTLS got write error: %s. Falling back to SSL\n"),
781                                              gnutls_strerror(ret));
782                                 dtls_restart(vpninfo);
783                                 vpninfo->outgoing_queue = this;
784                                 vpninfo->outgoing_qlen++;
785                         }
786                         return 1;
787                 }
788 #endif
789                 time(&vpninfo->dtls_times.last_tx);
790                 vpn_progress(vpninfo, PRG_TRACE,
791                              _("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
792                              this->len, ret);
793                 free(this);
794         }
795
796         return work_done;
797 }
798 #else /* !HAVE_DTLS */
799 #warning Your SSL library does not seem to support Cisco DTLS compatibility
800  int setup_dtls(struct openconnect_info *vpninfo)
801 {
802         vpn_progress(vpninfo, PRG_ERR,
803                      _("Built against SSL library with no Cisco DTLS support\n"));
804         return -EINVAL;
805 }
806 #endif
807