2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2008-2010 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
27 #include <sys/types.h>
28 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <openssl/err.h>
33 #include <openssl/ssl.h>
37 #include "openconnect-internal.h"
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 *);
45 static unsigned char nybble(unsigned char n)
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);
53 unsigned char unhex(const char *data)
55 return (nybble(data[0]) << 4) | nybble(data[1]);
58 #ifdef SSL_OP_CISCO_ANYCONNECT
61 * Useful for catching test cases, where we want everything to be
62 * reproducible. *NEVER* do this in the wild.
64 time_t time(time_t *t)
66 time_t x = 0x3ab2d948;
71 int RAND_pseudo_bytes(char *buf, int len)
73 memset(buf, 0x5a, len);
74 printf("FAKE PSEUDO RANDOM!\n");
78 int RAND_bytes(char *buf, int len)
80 static int foo = 0x5b;
81 printf("FAKE RANDOM!\n");
82 memset(buf, foo, len);
88 * The master-secret is generated randomly by the client. The server
89 * responds with a DTLS Session-ID. These, done over the HTTPS
90 * connection, are enough to 'resume' a DTLS session, bypassing all
91 * the normal setup of a normal DTLS connection.
93 * Cisco use a version of the protocol which predates RFC4347, but
94 * isn't quite the same as the pre-RFC version of the protocol which
95 * was in OpenSSL 0.9.8e -- it includes backports of some later
98 * The openssl/ directory of this source tree should contain both a
99 * small patch against OpenSSL 0.9.8e to make it support Cisco's
100 * snapshot of the protocol, and a larger patch against newer OpenSSL
101 * which gives us an option to use the old protocol again.
103 * Cisco's server also seems to respond to the official version of the
104 * protocol, with a change in the ChangeCipherSpec packet which implies
105 * that it does know the difference and isn't just repeating the version
106 * number seen in the ClientHello. But although I can make the handshake
107 * complete by hacking tls1_mac() to use the _old_ protocol version
108 * number when calculating the MAC, the server still seems to be ignoring
109 * my subsequent data packets. So we use the old protocol, which is what
110 * their clients use anyway.
113 int connect_dtls_socket(struct openconnect_info *vpninfo)
115 STACK_OF(SSL_CIPHER) *ciphers;
116 method_const SSL_METHOD *dtls_method;
117 SSL_CIPHER *dtls_cipher;
122 if (!vpninfo->dtls_addr) {
123 vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
124 vpninfo->dtls_attempt_period = 0;
128 if (!vpninfo->dtls_cipher) {
129 /* We probably didn't offer it any ciphers it liked */
130 vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
131 vpninfo->dtls_attempt_period = 0;
135 if (vpninfo->proxy) {
136 /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
137 vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
138 vpninfo->dtls_attempt_period = 0;
142 dtls_fd = socket(vpninfo->peer_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
144 perror(_("Open UDP socket for DTLS:"));
148 if (connect(dtls_fd, vpninfo->dtls_addr, vpninfo->peer_addrlen)) {
149 perror(_("UDP (DTLS) connect:\n"));
154 fcntl(dtls_fd, F_SETFD, FD_CLOEXEC);
156 if (!vpninfo->dtls_ctx) {
157 dtls_method = DTLSv1_client_method();
158 vpninfo->dtls_ctx = SSL_CTX_new(dtls_method);
159 if (!vpninfo->dtls_ctx) {
160 vpn_progress(vpninfo, PRG_ERR,
161 _("Initialise DTLSv1 CTX failed\n"));
162 vpninfo->dtls_attempt_period = 0;
166 /* If we don't readahead, then we do short reads and throw
167 away the tail of data packets. */
168 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
170 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
171 vpn_progress(vpninfo, PRG_ERR,
172 _("Set DTLS cipher list failed\n"));
173 SSL_CTX_free(vpninfo->dtls_ctx);
174 vpninfo->dtls_ctx = NULL;
175 vpninfo->dtls_attempt_period = 0;
180 if (!vpninfo->dtls_session) {
181 /* We're going to "resume" a session which never existed. Fake it... */
182 vpninfo->dtls_session = SSL_SESSION_new();
183 if (!vpninfo->dtls_session) {
184 vpn_progress(vpninfo, PRG_ERR,
185 _("Initialise DTLSv1 session failed\n"));
186 vpninfo->dtls_attempt_period = 0;
189 vpninfo->dtls_session->ssl_version = 0x0100; /* DTLS1_BAD_VER */
192 /* Do this every time; it may have changed due to a rekey */
193 vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
194 memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
195 sizeof(vpninfo->dtls_secret));
197 vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
198 memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
199 sizeof(vpninfo->dtls_session_id));
201 dtls_ssl = SSL_new(vpninfo->dtls_ctx);
202 SSL_set_connect_state(dtls_ssl);
204 ciphers = SSL_get_ciphers(dtls_ssl);
205 if (sk_SSL_CIPHER_num(ciphers) != 1) {
206 vpn_progress(vpninfo, PRG_ERR, _("Not precisely one DTLS cipher\n"));
207 SSL_CTX_free(vpninfo->dtls_ctx);
209 SSL_SESSION_free(vpninfo->dtls_session);
210 vpninfo->dtls_ctx = NULL;
211 vpninfo->dtls_session = NULL;
212 vpninfo->dtls_attempt_period = 0;
215 dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
217 /* Set the appropriate cipher on our session to be resumed */
218 vpninfo->dtls_session->cipher = dtls_cipher;
219 vpninfo->dtls_session->cipher_id = dtls_cipher->id;
221 /* Add the generated session to the SSL */
222 if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
223 vpn_progress(vpninfo, PRG_ERR,
224 _("SSL_set_session() failed with old protocol version 0x%x\n"
225 "Are you using a version of OpenSSL older than 0.9.8m?\n"
226 "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
227 "Use the --no-dtls command line option to avoid this message\n"),
228 vpninfo->dtls_session->ssl_version);
229 vpninfo->dtls_attempt_period = 0;
234 dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
235 SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
237 SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
239 /* Set non-blocking */
240 BIO_set_nbio(SSL_get_rbio(dtls_ssl), 1);
241 BIO_set_nbio(SSL_get_wbio(dtls_ssl), 1);
243 fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
245 vpninfo->new_dtls_fd = dtls_fd;
246 vpninfo->new_dtls_ssl = dtls_ssl;
248 if (vpninfo->select_nfds <= dtls_fd)
249 vpninfo->select_nfds = dtls_fd + 1;
251 FD_SET(dtls_fd, &vpninfo->select_rfds);
252 FD_SET(dtls_fd, &vpninfo->select_efds);
254 time(&vpninfo->new_dtls_started);
255 return dtls_try_handshake(vpninfo);
258 int dtls_try_handshake(struct openconnect_info *vpninfo)
260 int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
263 vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection\n"));
265 if (vpninfo->dtls_ssl) {
266 /* We are replacing an old connection */
267 SSL_free(vpninfo->dtls_ssl);
268 close(vpninfo->dtls_fd);
269 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
270 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
271 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
273 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
274 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
276 vpninfo->new_dtls_ssl = NULL;
277 vpninfo->new_dtls_fd = -1;
279 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
281 /* From about 8.4.1(11) onwards, the ASA seems to get
282 very unhappy if we resend ChangeCipherSpec messages
283 after the initial setup. This was "fixed" in OpenSSL
284 1.0.0e for RT#2505, but it's not clear if that was
285 the right fix. What happens if the original packet
286 *does* get lost? Surely we *wanted* the retransmits,
287 because without them the server will never be able
288 to decrypt anything we send?
289 Oh well, our retransmitted packets upset the server
290 because we don't get the Cisco-compatibility right
291 (this is one of the areas in which Cisco's DTLS differs
292 from the RFC4347 spec), and DPD should help us notice
293 if *nothing* is getting through. */
294 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
295 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
296 However, if we were *built* against 1.0.0e or newer, but at
297 runtime we find that we are being run against an older
298 version, warn about it. */
299 if (SSLeay() < 0x1000005fL) {
300 vpn_progress(vpninfo, PRG_ERR,
301 _("Your OpenSSL is older than the one you built against, so DTLS may fail!"));
303 #elif defined (HAVE_DTLS1_STOP_TIMER)
304 dtls1_stop_timer(vpninfo->dtls_ssl);
306 /* Debian restricts visibility of dtls1_stop_timer()
307 so do it manually. Thankfully this *should* work,
308 from 0.9.8m to 1.0.0d inclusive, and we don't have
309 to worry about future changes because we don't do
310 this for 1.0.0e and above anyway */
311 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
312 sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
313 vpninfo->dtls_ssl->d1->timeout_duration = 1;
314 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
315 BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
316 &(vpninfo->dtls_ssl->d1->next_timeout));
321 ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
322 if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
323 if (time(NULL) < vpninfo->new_dtls_started + 5)
325 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
328 vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
329 report_ssl_errors(vpninfo);
331 /* Kill the new (failed) connection... */
332 SSL_free(vpninfo->new_dtls_ssl);
333 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
334 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
335 close(vpninfo->new_dtls_fd);
336 vpninfo->new_dtls_ssl = NULL;
337 vpninfo->new_dtls_fd = -1;
339 /* ... and kill the old one too. The only time there'll be a valid
340 existing session is when it was a rekey, and in that case it's
341 time for the old one to die. */
342 if (vpninfo->dtls_ssl) {
343 SSL_free(vpninfo->dtls_ssl);
344 close(vpninfo->dtls_fd);
345 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
346 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
347 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
348 vpninfo->dtls_ssl = NULL;
349 vpninfo->dtls_fd = -1;
352 time(&vpninfo->new_dtls_started);
356 static int dtls_restart(struct openconnect_info *vpninfo)
358 if (vpninfo->dtls_ssl) {
359 SSL_free(vpninfo->dtls_ssl);
360 close(vpninfo->dtls_fd);
361 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
362 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
363 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
364 vpninfo->dtls_ssl = NULL;
365 vpninfo->dtls_fd = -1;
368 return connect_dtls_socket(vpninfo);
372 int setup_dtls(struct openconnect_info *vpninfo)
374 struct vpn_option *dtls_opt = vpninfo->dtls_options;
378 vpn_progress(vpninfo, PRG_TRACE,
379 _("DTLS option %s : %s\n"),
380 dtls_opt->option, dtls_opt->value);
382 if (!strcmp(dtls_opt->option + 7, "Port")) {
383 dtls_port = atol(dtls_opt->value);
384 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
385 vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
386 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
387 int j = atol(dtls_opt->value);
388 if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
389 vpninfo->dtls_times.dpd = j;
390 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
391 vpninfo->dtls_times.rekey = atol(dtls_opt->value);
392 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
393 vpninfo->dtls_cipher = strdup(dtls_opt->value);
396 dtls_opt = dtls_opt->next;
399 vpninfo->dtls_attempt_period = 0;
403 vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
404 if (!vpninfo->dtls_addr) {
405 vpninfo->dtls_attempt_period = 0;
408 memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
410 if (vpninfo->peer_addr->sa_family == AF_INET) {
411 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
412 sin->sin_port = htons(dtls_port);
413 } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
414 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
415 sin->sin6_port = htons(dtls_port);
417 vpn_progress(vpninfo, PRG_ERR,
418 _("Unknown protocol family %d. Cannot do DTLS\n"),
419 vpninfo->peer_addr->sa_family);
420 vpninfo->dtls_attempt_period = 0;
424 if (connect_dtls_socket(vpninfo))
427 vpn_progress(vpninfo, PRG_TRACE,
428 _("DTLS connected. DPD %d, Keepalive %d\n"),
429 vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
434 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
436 unsigned char buf[2000];
441 while ( (len = SSL_read(vpninfo->dtls_ssl, buf, sizeof(buf))) > 0 ) {
443 vpn_progress(vpninfo, PRG_TRACE,
444 _("Received DTLS packet 0x%02x of %d bytes\n"),
447 vpninfo->dtls_times.last_rx = time(NULL);
451 queue_new_packet(&vpninfo->incoming_queue, buf+1, len-1);
456 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
458 /* FIXME: What if the packet doesn't get through? */
459 magic_pkt = AC_PKT_DPD_RESP;
460 if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
461 vpn_progress(vpninfo, PRG_ERR,
462 _("Failed to send DPD response. Expect disconnect\n"));
465 case AC_PKT_DPD_RESP:
466 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
469 case AC_PKT_KEEPALIVE:
470 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
474 vpn_progress(vpninfo, PRG_ERR,
475 _("Unknown DTLS packet type %02x, len %d\n"),
478 /* Some versions of OpenSSL have bugs with receiving out-of-order
479 * packets. Not only do they wrongly decide to drop packets if
480 * two packets get swapped in transit, but they also _fail_ to
481 * drop the packet in non-blocking mode; instead they return
482 * the appropriate length of garbage. So don't abort... for now. */
485 vpninfo->quit_reason = "Unknown packet received";
492 switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
494 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
496 /* There ought to be a method of rekeying DTLS without tearing down
497 the CSTP session and restarting, but we don't (yet) know it */
498 if (cstp_reconnect(vpninfo)) {
499 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
500 vpninfo->quit_reason = "CSTP reconnect failed";
504 if (dtls_restart(vpninfo)) {
505 vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
513 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
514 /* Fall back to SSL, and start a new DTLS connection */
515 dtls_restart(vpninfo);
519 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
521 magic_pkt = AC_PKT_DPD_OUT;
522 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
523 /* last_dpd will just have been set */
524 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
529 /* No need to send an explicit keepalive
530 if we have real data to send */
531 if (vpninfo->outgoing_queue)
534 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
536 magic_pkt = AC_PKT_KEEPALIVE;
537 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
538 time(&vpninfo->dtls_times.last_tx);
546 /* Service outgoing packet queue */
547 while (vpninfo->outgoing_queue) {
548 struct pkt *this = vpninfo->outgoing_queue;
551 vpninfo->outgoing_queue = this->next;
552 vpninfo->outgoing_qlen--;
554 /* One byte of header */
555 this->hdr[7] = AC_PKT_DATA;
557 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
559 ret = SSL_get_error(vpninfo->dtls_ssl, ret);
561 /* If it's a real error, kill the DTLS connection and
562 requeue the packet to be sent over SSL */
563 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
564 vpn_progress(vpninfo, PRG_ERR,
565 _("DTLS got write error %d. Falling back to SSL\n"),
567 report_ssl_errors(vpninfo);
568 dtls_restart(vpninfo);
569 vpninfo->outgoing_queue = this;
570 vpninfo->outgoing_qlen++;
574 time(&vpninfo->dtls_times.last_tx);
575 vpn_progress(vpninfo, PRG_TRACE,
576 _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
583 #else /* No DTLS support in OpenSSL */
584 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
585 int setup_dtls(struct openconnect_info *vpninfo)
587 vpn_progress(vpninfo, PRG_ERR,
588 _("Built against OpenSSL with no Cisco DTLS support\n"));