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
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)
303 dtls1_stop_timer(vpninfo->dtls_ssl);
305 /* Debian restricts visibility of dtls1_stop_timer()
306 so do it manually. Thankfully this *should* work,
307 from 0.9.8m to 1.0.0d inclusive, and we don't have
308 to worry about future changes because we don't do
309 this for 1.0.0e and above anyway */
310 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
311 sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
312 vpninfo->dtls_ssl->d1->timeout_duration = 1;
313 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
314 BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
315 &(vpninfo->dtls_ssl->d1->next_timeout));
320 ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
321 if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
322 if (time(NULL) < vpninfo->new_dtls_started + 5)
324 vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n"));
327 vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %d\n"), ret);
328 report_ssl_errors(vpninfo);
330 /* Kill the new (failed) connection... */
331 SSL_free(vpninfo->new_dtls_ssl);
332 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
333 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
334 close(vpninfo->new_dtls_fd);
335 vpninfo->new_dtls_ssl = NULL;
336 vpninfo->new_dtls_fd = -1;
338 /* ... and kill the old one too. The only time there'll be a valid
339 existing session is when it was a rekey, and in that case it's
340 time for the old one to die. */
341 if (vpninfo->dtls_ssl) {
342 SSL_free(vpninfo->dtls_ssl);
343 close(vpninfo->dtls_fd);
344 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
345 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
346 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
347 vpninfo->dtls_ssl = NULL;
348 vpninfo->dtls_fd = -1;
351 time(&vpninfo->new_dtls_started);
355 static int dtls_restart(struct openconnect_info *vpninfo)
357 if (vpninfo->dtls_ssl) {
358 SSL_free(vpninfo->dtls_ssl);
359 close(vpninfo->dtls_fd);
360 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
361 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
362 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
363 vpninfo->dtls_ssl = NULL;
364 vpninfo->dtls_fd = -1;
367 return connect_dtls_socket(vpninfo);
371 int setup_dtls(struct openconnect_info *vpninfo)
373 struct vpn_option *dtls_opt = vpninfo->dtls_options;
377 vpn_progress(vpninfo, PRG_TRACE,
378 _("DTLS option %s : %s\n"),
379 dtls_opt->option, dtls_opt->value);
381 if (!strcmp(dtls_opt->option + 7, "Port")) {
382 dtls_port = atol(dtls_opt->value);
383 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
384 vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
385 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
386 int j = atol(dtls_opt->value);
387 if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
388 vpninfo->dtls_times.dpd = j;
389 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
390 vpninfo->dtls_times.rekey = atol(dtls_opt->value);
391 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
392 vpninfo->dtls_cipher = strdup(dtls_opt->value);
395 dtls_opt = dtls_opt->next;
398 vpninfo->dtls_attempt_period = 0;
402 vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
403 if (!vpninfo->dtls_addr) {
404 vpninfo->dtls_attempt_period = 0;
407 memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
409 if (vpninfo->peer_addr->sa_family == AF_INET) {
410 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
411 sin->sin_port = htons(dtls_port);
412 } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
413 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
414 sin->sin6_port = htons(dtls_port);
416 vpn_progress(vpninfo, PRG_ERR,
417 _("Unknown protocol family %d. Cannot do DTLS\n"),
418 vpninfo->peer_addr->sa_family);
419 vpninfo->dtls_attempt_period = 0;
423 if (connect_dtls_socket(vpninfo))
426 vpn_progress(vpninfo, PRG_TRACE,
427 _("DTLS connected. DPD %d, Keepalive %d\n"),
428 vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
433 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
435 unsigned char buf[2000];
440 while ( (len = SSL_read(vpninfo->dtls_ssl, buf, sizeof(buf))) > 0 ) {
442 vpn_progress(vpninfo, PRG_TRACE,
443 _("Received DTLS packet 0x%02x of %d bytes\n"),
446 vpninfo->dtls_times.last_rx = time(NULL);
450 queue_new_packet(&vpninfo->incoming_queue, buf+1, len-1);
455 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD request\n"));
457 /* FIXME: What if the packet doesn't get through? */
458 magic_pkt = AC_PKT_DPD_RESP;
459 if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
460 vpn_progress(vpninfo, PRG_ERR,
461 _("Failed to send DPD response. Expect disconnect\n"));
464 case AC_PKT_DPD_RESP:
465 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS DPD response\n"));
468 case AC_PKT_KEEPALIVE:
469 vpn_progress(vpninfo, PRG_TRACE, _("Got DTLS Keepalive\n"));
473 vpn_progress(vpninfo, PRG_ERR,
474 _("Unknown DTLS packet type %02x, len %d\n"),
477 /* Some versions of OpenSSL have bugs with receiving out-of-order
478 * packets. Not only do they wrongly decide to drop packets if
479 * two packets get swapped in transit, but they also _fail_ to
480 * drop the packet in non-blocking mode; instead they return
481 * the appropriate length of garbage. So don't abort... for now. */
484 vpninfo->quit_reason = "Unknown packet received";
491 switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
493 vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
495 /* There ought to be a method of rekeying DTLS without tearing down
496 the CSTP session and restarting, but we don't (yet) know it */
497 if (cstp_reconnect(vpninfo)) {
498 vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n"));
499 vpninfo->quit_reason = "CSTP reconnect failed";
503 if (dtls_restart(vpninfo)) {
504 vpn_progress(vpninfo, PRG_ERR, _("DTLS rekey failed\n"));
512 vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
513 /* Fall back to SSL, and start a new DTLS connection */
514 dtls_restart(vpninfo);
518 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS DPD\n"));
520 magic_pkt = AC_PKT_DPD_OUT;
521 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
522 /* last_dpd will just have been set */
523 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
528 /* No need to send an explicit keepalive
529 if we have real data to send */
530 if (vpninfo->outgoing_queue)
533 vpn_progress(vpninfo, PRG_TRACE, _("Send DTLS Keepalive\n"));
535 magic_pkt = AC_PKT_KEEPALIVE;
536 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
537 time(&vpninfo->dtls_times.last_tx);
545 /* Service outgoing packet queue */
546 while (vpninfo->outgoing_queue) {
547 struct pkt *this = vpninfo->outgoing_queue;
550 vpninfo->outgoing_queue = this->next;
551 vpninfo->outgoing_qlen--;
553 /* One byte of header */
554 this->hdr[7] = AC_PKT_DATA;
556 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
558 ret = SSL_get_error(vpninfo->dtls_ssl, ret);
560 /* If it's a real error, kill the DTLS connection and
561 requeue the packet to be sent over SSL */
562 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
563 vpn_progress(vpninfo, PRG_ERR,
564 _("DTLS got write error %d. Falling back to SSL\n"),
566 report_ssl_errors(vpninfo);
567 dtls_restart(vpninfo);
568 vpninfo->outgoing_queue = this;
569 vpninfo->outgoing_qlen++;
573 time(&vpninfo->dtls_times.last_tx);
574 vpn_progress(vpninfo, PRG_TRACE,
575 _("Sent DTLS packet of %d bytes; SSL_write() returned %d\n"),
582 #else /* No DTLS support in OpenSSL */
583 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
584 int setup_dtls(struct openconnect_info *vpninfo)
586 vpn_progress(vpninfo, PRG_ERR,
587 _("Built against OpenSSL with no Cisco DTLS support\n"));