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, "Initialise DTLSv1 CTX failed\n");
160 vpninfo->dtls_attempt_period = 0;
164 /* If we don't readahead, then we do short reads and throw
165 away the tail of data packets. */
166 SSL_CTX_set_read_ahead(vpninfo->dtls_ctx, 1);
168 if (!SSL_CTX_set_cipher_list(vpninfo->dtls_ctx, vpninfo->dtls_cipher)) {
169 vpn_progress(vpninfo, PRG_ERR, "Set DTLS cipher list failed\n");
170 SSL_CTX_free(vpninfo->dtls_ctx);
171 vpninfo->dtls_ctx = NULL;
172 vpninfo->dtls_attempt_period = 0;
177 if (!vpninfo->dtls_session) {
178 /* We're going to "resume" a session which never existed. Fake it... */
179 vpninfo->dtls_session = SSL_SESSION_new();
180 if (!vpninfo->dtls_session) {
181 vpn_progress(vpninfo, PRG_ERR, "Initialise DTLSv1 session failed\n");
182 vpninfo->dtls_attempt_period = 0;
185 vpninfo->dtls_session->ssl_version = 0x0100; // DTLS1_BAD_VER
188 /* Do this every time; it may have changed due to a rekey */
189 vpninfo->dtls_session->master_key_length = sizeof(vpninfo->dtls_secret);
190 memcpy(vpninfo->dtls_session->master_key, vpninfo->dtls_secret,
191 sizeof(vpninfo->dtls_secret));
193 vpninfo->dtls_session->session_id_length = sizeof(vpninfo->dtls_session_id);
194 memcpy(vpninfo->dtls_session->session_id, vpninfo->dtls_session_id,
195 sizeof(vpninfo->dtls_session_id));
197 dtls_ssl = SSL_new(vpninfo->dtls_ctx);
198 SSL_set_connect_state(dtls_ssl);
200 ciphers = SSL_get_ciphers(dtls_ssl);
201 if (sk_SSL_CIPHER_num(ciphers) != 1) {
202 vpn_progress(vpninfo, PRG_ERR, "Not precisely one DTLS cipher\n");
203 SSL_CTX_free(vpninfo->dtls_ctx);
205 SSL_SESSION_free(vpninfo->dtls_session);
206 vpninfo->dtls_ctx = NULL;
207 vpninfo->dtls_session = NULL;
208 vpninfo->dtls_attempt_period = 0;
211 dtls_cipher = sk_SSL_CIPHER_value(ciphers, 0);
213 /* Set the appropriate cipher on our session to be resumed */
214 vpninfo->dtls_session->cipher = dtls_cipher;
215 vpninfo->dtls_session->cipher_id = dtls_cipher->id;
217 /* Add the generated session to the SSL */
218 if (!SSL_set_session(dtls_ssl, vpninfo->dtls_session)) {
219 vpn_progress(vpninfo, PRG_ERR,
220 "SSL_set_session() failed with old protocol version 0x%x\n"
221 "Are you using a version of OpenSSL older than 0.9.8m?\n"
222 "See http://rt.openssl.org/Ticket/Display.html?id=1751\n"
223 "Use the --no-dtls command line option to avoid this message\n",
224 vpninfo->dtls_session->ssl_version);
225 vpninfo->dtls_attempt_period = 0;
230 dtls_bio = BIO_new_socket(dtls_fd, BIO_NOCLOSE);
231 SSL_set_bio(dtls_ssl, dtls_bio, dtls_bio);
233 SSL_set_options(dtls_ssl, SSL_OP_CISCO_ANYCONNECT);
235 /* Set non-blocking */
236 BIO_set_nbio(SSL_get_rbio(dtls_ssl), 1);
237 BIO_set_nbio(SSL_get_wbio(dtls_ssl), 1);
239 fcntl(dtls_fd, F_SETFL, fcntl(dtls_fd, F_GETFL) | O_NONBLOCK);
241 vpninfo->new_dtls_fd = dtls_fd;
242 vpninfo->new_dtls_ssl = dtls_ssl;
244 if (vpninfo->select_nfds <= dtls_fd)
245 vpninfo->select_nfds = dtls_fd + 1;
247 FD_SET(dtls_fd, &vpninfo->select_rfds);
248 FD_SET(dtls_fd, &vpninfo->select_efds);
250 time(&vpninfo->new_dtls_started);
251 return dtls_try_handshake(vpninfo);
254 int dtls_try_handshake(struct openconnect_info *vpninfo)
256 int ret = SSL_do_handshake(vpninfo->new_dtls_ssl);
259 vpn_progress(vpninfo, PRG_INFO, "Established DTLS connection\n");
261 if (vpninfo->dtls_ssl) {
262 /* We are replacing an old connection */
263 SSL_free(vpninfo->dtls_ssl);
264 close(vpninfo->dtls_fd);
265 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
266 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
267 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
269 vpninfo->dtls_ssl = vpninfo->new_dtls_ssl;
270 vpninfo->dtls_fd = vpninfo->new_dtls_fd;
272 vpninfo->new_dtls_ssl = NULL;
273 vpninfo->new_dtls_fd = -1;
275 vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL);
277 /* From about 8.4.1(11) onwards, the ASA seems to get
278 very unhappy if we resend ChangeCipherSpec messages
279 after the initial setup. This was "fixed" in OpenSSL
280 1.0.0e for RT#2505, but it's not clear if that was
281 the right fix. What happens if the original packet
282 *does* get lost? Surely we *wanted* the retransmits,
283 because without them the server will never be able
284 to decrypt anything we send?
285 Oh well, our retransmitted packets upset the server
286 because we don't get the Cisco-compatibility right
287 (this is one of the areas in which Cisco's DTLS differs
288 from the RFC4347 spec), and DPD should help us notice
289 if *nothing* is getting through. */
290 #if OPENSSL_VERSION_NUMBER >= 0x1000005fL
291 /* OpenSSL 1.0.0e or above doesn't resend anyway; do nothing.
292 However, if we were *built* against 1.0.0e or newer, but at
293 runtime we find that we are being run against an older
294 version, warn about it. */
295 if (SSLeay() < 0x1000005fL) {
296 vpn_progress(vpninfo, PRG_WARNING,
297 "Your OpenSSL is older than the one you built against, so DTLS may fail!");
299 #elif defined (HAVE_DTLS1_STOP_TIMER)
300 dtls1_stop_timer(vpninfo->dtls_ssl);
302 /* Debian restricts visibility of dtls1_stop_timer()
303 so do it manually. Thankfully this *should* work,
304 from 0.9.8m to 1.0.0d inclusive, and we don't have
305 to worry about future changes because we don't do
306 this for 1.0.0e and above anyway */
307 memset (&(vpninfo->dtls_ssl->d1->next_timeout), 0,
308 sizeof((vpninfo->dtls_ssl->d1->next_timeout)));
309 vpninfo->dtls_ssl->d1->timeout_duration = 1;
310 BIO_ctrl(SSL_get_rbio(vpninfo->dtls_ssl),
311 BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
312 &(vpninfo->dtls_ssl->d1->next_timeout));
317 ret = SSL_get_error(vpninfo->new_dtls_ssl, ret);
318 if (ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ) {
319 if (time(NULL) < vpninfo->new_dtls_started + 5)
321 vpn_progress(vpninfo, PRG_TRACE, "DTLS handshake timed out\n");
324 vpn_progress(vpninfo, PRG_ERR, "DTLS handshake failed: %d\n", ret);
325 report_ssl_errors(vpninfo);
327 /* Kill the new (failed) connection... */
328 SSL_free(vpninfo->new_dtls_ssl);
329 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
330 FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_efds);
331 close(vpninfo->new_dtls_fd);
332 vpninfo->new_dtls_ssl = NULL;
333 vpninfo->new_dtls_fd = -1;
335 /* ... and kill the old one too. The only time there'll be a valid
336 existing session is when it was a rekey, and in that case it's
337 time for the old one to die. */
338 if (vpninfo->dtls_ssl) {
339 SSL_free(vpninfo->dtls_ssl);
340 close(vpninfo->dtls_fd);
341 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
342 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
343 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
344 vpninfo->dtls_ssl = NULL;
345 vpninfo->dtls_fd = -1;
348 time(&vpninfo->new_dtls_started);
352 static int dtls_restart(struct openconnect_info *vpninfo)
354 if (vpninfo->dtls_ssl) {
355 SSL_free(vpninfo->dtls_ssl);
356 close(vpninfo->dtls_fd);
357 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_rfds);
358 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_wfds);
359 FD_CLR(vpninfo->dtls_fd, &vpninfo->select_efds);
360 vpninfo->dtls_ssl = NULL;
361 vpninfo->dtls_fd = -1;
364 return connect_dtls_socket(vpninfo);
368 int setup_dtls(struct openconnect_info *vpninfo)
370 struct vpn_option *dtls_opt = vpninfo->dtls_options;
374 vpn_progress(vpninfo, PRG_TRACE,
375 "DTLS option %s : %s\n",
376 dtls_opt->option, dtls_opt->value);
378 if (!strcmp(dtls_opt->option + 7, "Port")) {
379 dtls_port = atol(dtls_opt->value);
380 } else if (!strcmp(dtls_opt->option + 7, "Keepalive")) {
381 vpninfo->dtls_times.keepalive = atol(dtls_opt->value);
382 } else if (!strcmp(dtls_opt->option + 7, "DPD")) {
383 int j = atol(dtls_opt->value);
384 if (j && (!vpninfo->dtls_times.dpd || j < vpninfo->dtls_times.dpd))
385 vpninfo->dtls_times.dpd = j;
386 } else if (!strcmp(dtls_opt->option + 7, "Rekey-Time")) {
387 vpninfo->dtls_times.rekey = atol(dtls_opt->value);
388 } else if (!strcmp(dtls_opt->option + 7, "CipherSuite")) {
389 vpninfo->dtls_cipher = strdup(dtls_opt->value);
392 dtls_opt = dtls_opt->next;
395 vpninfo->dtls_attempt_period = 0;
399 vpninfo->dtls_addr = malloc(vpninfo->peer_addrlen);
400 if (!vpninfo->dtls_addr) {
401 vpninfo->dtls_attempt_period = 0;
404 memcpy(vpninfo->dtls_addr, vpninfo->peer_addr, vpninfo->peer_addrlen);
406 if (vpninfo->peer_addr->sa_family == AF_INET) {
407 struct sockaddr_in *sin = (void *)vpninfo->dtls_addr;
408 sin->sin_port = htons(dtls_port);
409 } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
410 struct sockaddr_in6 *sin = (void *)vpninfo->dtls_addr;
411 sin->sin6_port = htons(dtls_port);
413 vpn_progress(vpninfo, PRG_ERR, "Unknown protocol family %d. Cannot do DTLS\n",
414 vpninfo->peer_addr->sa_family);
415 vpninfo->dtls_attempt_period = 0;
419 if (connect_dtls_socket(vpninfo))
422 vpn_progress(vpninfo, PRG_TRACE,
423 "DTLS connected. DPD %d, Keepalive %d\n",
424 vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
429 int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
431 unsigned char buf[2000];
436 while ( (len = SSL_read(vpninfo->dtls_ssl, buf, sizeof(buf))) > 0 ) {
438 vpn_progress(vpninfo, PRG_TRACE,
439 "Received DTLS packet 0x%02x of %d bytes\n",
442 vpninfo->dtls_times.last_rx = time(NULL);
446 queue_new_packet(&vpninfo->incoming_queue, buf+1, len-1);
451 vpn_progress(vpninfo, PRG_TRACE, "Got DTLS DPD request\n");
453 /* FIXME: What if the packet doesn't get through? */
454 magic_pkt = AC_PKT_DPD_RESP;
455 if (SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1) != 1)
456 vpn_progress(vpninfo, PRG_ERR, "Failed to send DPD response. Expect disconnect\n");
459 case AC_PKT_DPD_RESP:
460 vpn_progress(vpninfo, PRG_TRACE, "Got DTLS DPD response\n");
463 case AC_PKT_KEEPALIVE:
464 vpn_progress(vpninfo, PRG_TRACE, "Got DTLS Keepalive\n");
468 vpn_progress(vpninfo, PRG_ERR,
469 "Unknown DTLS packet type %02x, len %d\n", buf[0], len);
471 /* Some versions of OpenSSL have bugs with receiving out-of-order
472 * packets. Not only do they wrongly decide to drop packets if
473 * two packets get swapped in transit, but they also _fail_ to
474 * drop the packet in non-blocking mode; instead they return
475 * the appropriate length of garbage. So don't abort... for now. */
478 vpninfo->quit_reason = "Unknown packet received";
485 switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
487 vpn_progress(vpninfo, PRG_INFO, "DTLS rekey due\n");
489 /* There ought to be a method of rekeying DTLS without tearing down
490 the CSTP session and restarting, but we don't (yet) know it */
491 if (cstp_reconnect(vpninfo)) {
492 vpn_progress(vpninfo, PRG_ERR, "Reconnect failed\n");
493 vpninfo->quit_reason = "CSTP reconnect failed";
497 if (dtls_restart(vpninfo)) {
498 vpn_progress(vpninfo, PRG_ERR, "DTLS rekey failed\n");
506 vpn_progress(vpninfo, PRG_ERR, "DTLS Dead Peer Detection detected dead peer!\n");
507 /* Fall back to SSL, and start a new DTLS connection */
508 dtls_restart(vpninfo);
512 vpn_progress(vpninfo, PRG_TRACE, "Send DTLS DPD\n");
514 magic_pkt = AC_PKT_DPD_OUT;
515 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
516 /* last_dpd will just have been set */
517 vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
522 /* No need to send an explicit keepalive
523 if we have real data to send */
524 if (vpninfo->outgoing_queue)
527 vpn_progress(vpninfo, PRG_TRACE, "Send DTLS Keepalive\n");
529 magic_pkt = AC_PKT_KEEPALIVE;
530 SSL_write(vpninfo->dtls_ssl, &magic_pkt, 1);
531 time(&vpninfo->dtls_times.last_tx);
539 /* Service outgoing packet queue */
540 while (vpninfo->outgoing_queue) {
541 struct pkt *this = vpninfo->outgoing_queue;
544 vpninfo->outgoing_queue = this->next;
545 vpninfo->outgoing_qlen--;
547 /* One byte of header */
548 this->hdr[7] = AC_PKT_DATA;
550 ret = SSL_write(vpninfo->dtls_ssl, &this->hdr[7], this->len + 1);
552 ret = SSL_get_error(vpninfo->dtls_ssl, ret);
554 /* If it's a real error, kill the DTLS connection and
555 requeue the packet to be sent over SSL */
556 if (ret != SSL_ERROR_WANT_READ && ret != SSL_ERROR_WANT_WRITE) {
557 vpn_progress(vpninfo, PRG_ERR,
558 "DTLS got write error %d. Falling back to SSL\n", ret);
559 report_ssl_errors(vpninfo);
560 dtls_restart(vpninfo);
561 vpninfo->outgoing_queue = this;
562 vpninfo->outgoing_qlen++;
566 time(&vpninfo->dtls_times.last_tx);
567 vpn_progress(vpninfo, PRG_TRACE,
568 "Sent DTLS packet of %d bytes; SSL_write() returned %d\n",
575 #else /* No DTLS support in OpenSSL */
576 #warning Your version of OpenSSL does not seem to support Cisco DTLS compatibility
577 int setup_dtls(struct openconnect_info *vpninfo)
579 vpn_progress(vpninfo, PRG_ERR, "Built against OpenSSL with no Cisco DTLS support\n");