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