2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2012 Intel Corporation.
6 * Author: David Woodhouse <dwmw2@infradead.org>
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
26 #include <sys/types.h>
27 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <openssl/err.h>
32 #include <openssl/ssl.h>
36 #include "openconnect-internal.h"
38 #ifdef HAVE_DTLS1_STOP_TIMER
39 /* OpenSSL doesn't deliberately export this, but we need it to
40 workaround a DTLS bug in versions < 1.0.0e */
41 extern void dtls1_stop_timer (SSL *);
44 static unsigned char nybble(unsigned char n)
46 if (n >= '0' && n <= '9') return n - '0';
47 else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
48 else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
52 unsigned char unhex(const char *data)
54 return (nybble(data[0]) << 4) | nybble(data[1]);
57 #ifdef SSL_OP_CISCO_ANYCONNECT
60 * Useful for catching test cases, where we want everything to be
61 * reproducible. *NEVER* do this in the wild.
63 time_t time(time_t *t)
65 time_t x = 0x3ab2d948;
70 int RAND_pseudo_bytes(char *buf, int len)
72 memset(buf, 0x5a, len);
73 printf("FAKE PSEUDO RANDOM!\n");
77 int RAND_bytes(char *buf, int len)
79 static int foo = 0x5b;
80 printf("FAKE RANDOM!\n");
81 memset(buf, foo, len);
87 * The master-secret is generated randomly by the client. The server
88 * responds with a DTLS Session-ID. These, done over the HTTPS
89 * connection, are enough to 'resume' a DTLS session, bypassing all
90 * the normal setup of a normal DTLS connection.
92 * Cisco use a version of the protocol which predates RFC4347, but
93 * isn't quite the same as the pre-RFC version of the protocol which
94 * was in OpenSSL 0.9.8e -- it includes backports of some later
97 * The openssl/ directory of this source tree should contain both a
98 * small patch against OpenSSL 0.9.8e to make it support Cisco's
99 * snapshot of the protocol, and a larger patch against newer OpenSSL
100 * which gives us an option to use the old protocol again.
102 * Cisco's server also seems to respond to the official version of the
103 * protocol, with a change in the ChangeCipherSpec packet which implies
104 * that it does know the difference and isn't just repeating the version
105 * number seen in the ClientHello. But although I can make the handshake
106 * complete by hacking tls1_mac() to use the _old_ protocol version
107 * number when calculating the MAC, the server still seems to be ignoring
108 * my subsequent data packets. So we use the old protocol, which is what
109 * their clients use anyway.
112 int connect_dtls_socket(struct openconnect_info *vpninfo)
114 STACK_OF(SSL_CIPHER) *ciphers;
115 method_const SSL_METHOD *dtls_method;
116 SSL_CIPHER *dtls_cipher;
121 if (!vpninfo->dtls_addr) {
122 vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
123 vpninfo->dtls_attempt_period = 0;
127 if (!vpninfo->dtls_cipher) {
128 /* We probably didn't offer it any ciphers it liked */
129 vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
130 vpninfo->dtls_attempt_period = 0;
134 if (vpninfo->proxy) {
135 /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
136 vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
137 vpninfo->dtls_attempt_period = 0;
141 dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
143 perror(_("Open UDP socket for DTLS:"));
147 if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
148 perror(_("UDP (DTLS) connect:\n"));
153 fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
155 if (!vpninfo->dtls_ctx) {
156 dtls_method = DTLSv1_client_method();
157 vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
158 if (!vpninfo->dtls_ctx) {
159 vpn_progress(vpninfo, PRG_ERR,
160 _("Initialise DTLSv1 CTX failed\n"));
161 vpninfo->dtls_attempt_period = 0;
165 /* If we don't readahead, then we do short reads and throw
166 away the tail of data packets. */
167 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
169 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
170 vpn_progress(vpninfo, PRG_ERR,
171 _("Set DTLS cipher list failed\n"));
172 SSL_CTX_free(vpninfo->dtls_ctx);
173 vpninfo->dtls_ctx = NULL;
174 vpninfo->dtls_attempt_period = 0;
179 if (!vpninfo->dtls_session) {
180 /* We're going to "resume" a session which never existed. Fake it... */
181 vpninfo->dtls_session = SSL_SESSION_new();
182 if (!vpninfo->dtls_session) {
183 vpn_progress(vpninfo, PRG_ERR,
184 _("Initialise DTLSv1 session failed\n"));
185 vpninfo->dtls_attempt_period = 0;
188 vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */
191 /* Do this every time; it may have changed due to a rekey */
192 vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
193 memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
194 sizeof(vpninfo->dtls_secret));
196 vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
197 memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
198 sizeof(vpninfo->dtls_session_id));
200 dtls_ssl = SSL_new(vpninfo->dtls_ctx);
201 SSL_set_connect_state(dtls_ssl);
203 ciphers = SSL_get_ciphers(dtls_ssl);
204 if (sk_SSL_CIPHER_num(ciphers) != 1) {
205 vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n"));
206 SSL_CTX_free(vpninfo->dtls_ctx);
208 SSL_SESSION_free(vpninfo->dtls_session);
209 vpninfo->dtls_ctx = NULL;
210 vpninfo->dtls_session = NULL;
211 vpninfo->dtls_attempt_period = 0;
214 dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
216 /* Set the appropriate cipher on our session to be resumed */
217 vpninfo->dtls_session->cipher = dtls_cipher;
218 vpninfo->dtls_session->cipher_id = dtls_cipher->id;
220 /* Add the generated session to the SSL */
221 if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
222 vpn_progress(vpninfo, PRG_ERR,
223 _("SSL_set_session() failed with old protocol version 0x%x\n"
224 "Are you using a version of OpenSSL older than 0.9.8m?\n"
225 "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
226 "Use the --no-dtls command line option to avoid this message\n"),
227 vpninfo->dtls_session->ssl_version);
228 vpninfo->dtls_attempt_period = 0;
233 dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
234 SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
236 SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
238 /* Set non-blocking */
239 BIO_set_nbio(SSL_get_rbio(dtls_ssl), 1);
240 BIO_set_nbio(SSL_get_wbio(dtls_ssl), 1);
242 fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
244 vpninfo->new_dtls_fd = dtls_fd;
245 vpninfo->new_dtls_ssl = dtls_ssl;
247 if (vpninfo->select_nfds <= dtls_fd)
248 vpninfo->select_nfds = dtls_fd + 1;
250 FD_SET(dtls_fd, &vpninfo->select_rfds);
251 FD_SET(dtls_fd, &vpninfo->select_efds);
253 time(&vpninfo->new_dtls_started);
254 return dtls_try_handshake(vpninfo);
257 int dtls_try_handshake(struct openconnect_info *vpninfo)
259 int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
262 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
264 if (vpninfo->dtls_ssl) {
265 /* We are replacing an old connection */
266 SSL_free(vpninfo->dtls_ssl);
267 close(vpninfo->dtls_fd);
268 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
269 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
270 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
272 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
273 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
275 vpninfo->new_dtls_ssl = NULL;
276 vpninfo->new_dtls_fd = -1;
278 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
280 /* From about 8.4.1(11) onwards, the ASA seems to get
281 very unhappy if we resend ChangeCipherSpec messages
282 after the initial setup. This was "fixed" in OpenSSL
283 1.0.0e for RT#2505, but it's not clear if that was
284 the right fix. What happens if the original packet
285 *does* get lost? Surely we *wanted* the retransmits,
286 because without them the server will never be able
287 to decrypt anything we send?
288 Oh well, our retransmitted packets upset the server
289 because we don't get the Cisco-compatibility right
290 (this is one of the areas in which Cisco's DTLS differs
291 from the RFC4347 spec), and DPD should help us notice
292 if *nothing* is getting through. */
293 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
294 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
295 However, if we were *built* against 1.0.0e or newer, but at
296 runtime we find that we are being run against an older
297 version, warn about it. */
298 if (SSLeay() < 0x1000005fL) {
299 vpn_progress(vpninfo, PRG_ERR,
300 _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
302 #elif defined (HAVE_DTLS1_STOP_TIMER)
304 * This works for any normal OpenSSL that supports
305 * Cisco DTLS compatibility (0.9.8m to 1.0.0d inclusive,
306 * and even later versions although it isn't needed there.
308 dtls1_stop_timer(vpninfo->dtls_ssl);
309 #elif defined (BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT)
311 * Debian restricts visibility of dtls1_stop_timer()
312 * so do it manually. This version also works on all
313 * sane versions of OpenSSL:
315 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
316 sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
317 vpninfo->dtls_ssl->d1->timeout_duration = 1;
318 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
319 BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
320 &(vpninfo->dtls_ssl->d1->next_timeout));
321 #elif defined (BIO_CTRL_DGRAM_SET_TIMEOUT)
323 * OK, here it gets more fun... this shoul handle the case
324 * of older OpenSSL which has the Cisco DTLS compatibility
325 * backported, but *not* the fix for RT#1922.
327 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
328 BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
331 * And if they don't have any of the above, they probably
332 * don't have RT#1829 fixed either, but that's OK because
333 * that's the "fix" that *introduces* the timeout we're
334 * trying to disable. So do nothing...
340 ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
341 if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
342 if (time(NULL) < vpninfo->new_dtls_started + 5)
344 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
347 vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
348 openconnect_report_ssl_errors(vpninfo);
350 /* Kill the new (failed) connection... */
351 SSL_free(vpninfo->new_dtls_ssl);
352 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
353 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
354 close(vpninfo->new_dtls_fd);
355 vpninfo->new_dtls_ssl = NULL;
356 vpninfo->new_dtls_fd = -1;
358 /* ... and kill the old one too. The only time there'll be a valid
359 existing session is when it was a rekey, and in that case it's
360 time for the old one to die. */
361 if (vpninfo->dtls_ssl) {
362 SSL_free(vpninfo->dtls_ssl);
363 close(vpninfo->dtls_fd);
364 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
365 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
366 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
367 vpninfo->dtls_ssl = NULL;
368 vpninfo->dtls_fd = -1;
371 time(&vpninfo->new_dtls_started);
375 static int dtls_restart(struct openconnect_info *vpninfo)
377 if (vpninfo->dtls_ssl) {
378 SSL_free(vpninfo->dtls_ssl);
379 close(vpninfo->dtls_fd);
380 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
381 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
382 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
383 vpninfo->dtls_ssl = NULL;
384 vpninfo->dtls_fd = -1;
387 return connect_dtls_socket(vpninfo);
391 int setup_dtls(struct openconnect_info *vpninfo)
393 struct vpn_option *dtls_opt = vpninfo->dtls_options;
397 vpn_progress(vpninfo, PRG_TRACE,
398 _("DTLS option %s : %s\n"),
399 dtls_opt->option, dtls_opt->value);
401 if (!strcmp(dtls_opt->option + 7, "Port")) {
402 dtls_port = atol(dtls_opt->value);
403 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
404 vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
405 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
406 int j = atol(dtls_opt->value);
407 if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
408 vpninfo->dtls_times.dpd = j;
409 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
410 vpninfo->dtls_times.rekey = atol(dtls_opt->value);
411 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
412 vpninfo->dtls_cipher = strdup(dtls_opt->value);
415 dtls_opt = dtls_opt->next;
418 vpninfo->dtls_attempt_period = 0;
422 vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
423 if (!vpninfo->dtls_addr) {
424 vpninfo->dtls_attempt_period = 0;
427 memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
429 if (vpninfo->peer_addr->sa_family == AF_INET) {
430 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
431 sin->sin_port = htons(dtls_port);
432 } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
433 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
434 sin->sin6_port = htons(dtls_port);
436 vpn_progress(vpninfo, PRG_ERR,
437 _("Unknown protocol family %d. Cannot do DTLS\n"),
438 vpninfo->peer_addr->sa_family);
439 vpninfo->dtls_attempt_period = 0;
443 if (connect_dtls_socket(vpninfo))
446 vpn_progress(vpninfo, PRG_TRACE,
447 _("DTLS connected. DPD %d, Keepalive %d\n"),
448 vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
453 static struct pkt *dtls_pkt;
455 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
461 int len = vpninfo->mtu;
465 dtls_pkt = malloc(sizeof(struct pkt) + len);
467 vpn_progress(vpninfo, PRG_ERR, "Allocation failed\n");
472 buf = dtls_pkt->data - 1;
473 len = SSL_read(vpninfo->dtls_ssl, buf, len + 1);
477 vpn_progress(vpninfo, PRG_TRACE,
478 _("Received DTLS packet 0x%02x of %d bytes\n"),
481 vpninfo->dtls_times.last_rx = time(NULL);
485 dtls_pkt->len = len - 1;
486 queue_packet(&vpninfo->incoming_queue, dtls_pkt);
492 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
494 /* FIXME: What if the packet doesn't get through? */
495 magic_pkt = AC_PKT_DPD_RESP;
496 if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
497 vpn_progress(vpninfo, PRG_ERR,
498 _("Failed to send DPD response. Expect disconnect\n"));
501 case AC_PKT_DPD_RESP:
502 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
505 case AC_PKT_KEEPALIVE:
506 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
510 vpn_progress(vpninfo, PRG_ERR,
511 _("Unknown DTLS packet type %02x, len %d\n"),
514 /* Some versions of OpenSSL have bugs with receiving out-of-order
515 * packets. Not only do they wrongly decide to drop packets if
516 * two packets get swapped in transit, but they also _fail_ to
517 * drop the packet in non-blocking mode; instead they return
518 * the appropriate length of garbage. So don't abort... for now. */
521 vpninfo->quit_reason = "Unknown packet received";
528 switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
530 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
532 /* There ought to be a method of rekeying DTLS without tearing down
533 the CSTP session and restarting, but we don't (yet) know it */
534 if (cstp_reconnect(vpninfo)) {
535 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
536 vpninfo->quit_reason = "CSTP reconnect failed";
540 if (dtls_restart(vpninfo)) {
541 vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
549 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
550 /* Fall back to SSL, and start a new DTLS connection */
551 dtls_restart(vpninfo);
555 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
557 magic_pkt = AC_PKT_DPD_OUT;
558 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
559 /* last_dpd will just have been set */
560 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
565 /* No need to send an explicit keepalive
566 if we have real data to send */
567 if (vpninfo->outgoing_queue)
570 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
572 magic_pkt = AC_PKT_KEEPALIVE;
573 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
574 time(&vpninfo->dtls_times.last_tx);
582 /* Service outgoing packet queue */
583 while (vpninfo->outgoing_queue) {
584 struct pkt *this = vpninfo->outgoing_queue;
587 vpninfo->outgoing_queue = this->next;
588 vpninfo->outgoing_qlen--;
590 /* One byte of header */
591 this->hdr[7] = AC_PKT_DATA;
593 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
595 ret = SSL_get_error(vpninfo->dtls_ssl, ret);
597 /* If it's a real error, kill the DTLS connection and
598 requeue the packet to be sent over SSL */
599 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
600 vpn_progress(vpninfo, PRG_ERR,
601 _("DTLS got write error %d. Falling back to SSL\n"),
603 openconnect_report_ssl_errors(vpninfo);
604 dtls_restart(vpninfo);
605 vpninfo->outgoing_queue = this;
606 vpninfo->outgoing_qlen++;
610 time(&vpninfo->dtls_times.last_tx);
611 vpn_progress(vpninfo, PRG_TRACE,
612 _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
619 #else /* No DTLS support in OpenSSL */
620 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
621 int setup_dtls(struct openconnect_info *vpninfo)
623 vpn_progress(vpninfo, PRG_ERR,
624 _("Built against OpenSSL with no Cisco DTLS support\n"));