2 * Open AnyConnect (SSL + DTLS) client
4 * © 2008 David Woodhouse <dwmw2@infradead.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to:
19 * Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA
28 #include <openssl/ssl.h>
29 #include <openssl/err.h>
31 #include "openconnect.h"
34 * Data packets are encapsulated in the SSL stream as follows:
36 * 0000: Magic "STF\x1"
37 * 0004: Big-endian 16-bit length (not including 8-byte header)
38 * 0006: Byte packet type (see openconnect.h)
42 static char data_hdr[8] = {
45 AC_PKT_DATA, /* Type */
49 static struct pkt keepalive_pkt = {
50 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
53 static struct pkt dpd_pkt = {
54 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
57 static struct pkt dpd_resp_pkt = {
58 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
62 static int start_cstp_connection(struct openconnect_info *vpninfo)
67 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
68 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
69 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
70 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
71 const char *old_addr = vpninfo->vpn_addr;
72 const char *old_netmask = vpninfo->vpn_netmask;
74 /* Clear old options which will be overwritten */
75 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
76 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
78 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
81 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
82 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
83 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
84 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
85 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
86 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
88 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
89 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
90 /* To enable IPv6, send 'IPv6,IPv4'.
91 We don't know how most of that works yet though. */
92 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
93 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
94 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
95 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
96 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
98 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
99 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
102 SSL_free(vpninfo->https_ssl);
103 close(vpninfo->ssl_fd);
105 if (openconnect_open_https(vpninfo)) {
106 vpninfo->progress(vpninfo, PRG_ERR,
107 "Failed to open HTTPS connection to %s\n",
116 if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
117 vpninfo->progress(vpninfo, PRG_ERR,
118 "Got inappropriate HTTP CONNECT response: %s\n",
120 if (!strncmp(buf, "HTTP/1.1 401 ", 13))
122 openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536);
126 vpninfo->progress(vpninfo, PRG_INFO,
127 "Got CONNECT response: %s\n", buf);
129 /* We may have advertised it, but we only do it if the server agrees */
130 vpninfo->deflate = 0;
132 while ((i=openconnect_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
133 struct vpn_option *new_option;
134 char *colon = strchr(buf, ':');
143 if (strncmp(buf, "X-DTLS-", 7) &&
144 strncmp(buf, "X-CSTP-", 7))
147 new_option = malloc(sizeof(*new_option));
149 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
152 new_option->option = strdup(buf);
153 new_option->value = strdup(colon);
154 new_option->next = NULL;
156 if (!new_option->option || !new_option->value) {
157 vpninfo->progress(vpninfo, PRG_ERR, "No memory for options\n");
161 vpninfo->progress(vpninfo, PRG_TRACE, "%s: %s\n", buf, colon);
163 if (!strncmp(buf, "X-DTLS-", 7)) {
164 *next_dtls_option = new_option;
165 next_dtls_option = &new_option->next;
168 /* CSTP options... */
169 *next_cstp_option = new_option;
170 next_cstp_option = &new_option->next;
173 if (!strcmp(buf + 7, "Keepalive")) {
174 vpninfo->ssl_times.keepalive = atol(colon);
175 } else if (!strcmp(buf + 7, "DPD")) {
176 vpninfo->ssl_times.dpd = atol(colon);
177 } else if (!strcmp(buf + 7, "Content-Encoding")) {
178 if (!strcmp(colon, "deflate"))
179 vpninfo->deflate = 1;
181 vpninfo->progress(vpninfo, PRG_ERR,
182 "Unknown CSTP-Content-Encoding %s\n",
186 } else if (!strcmp(buf + 7, "MTU")) {
187 vpninfo->mtu = atol(colon);
188 } else if (!strcmp(buf + 7, "Address")) {
189 vpninfo->vpn_addr = new_option->value;
190 } else if (!strcmp(buf + 7, "Netmask")) {
191 vpninfo->vpn_netmask = new_option->value;
192 } else if (!strcmp(buf + 7, "DNS")) {
194 for (j = 0; j < 3; j++) {
195 if (!vpninfo->vpn_dns[j]) {
196 vpninfo->vpn_dns[j] = new_option->value;
200 } else if (!strcmp(buf + 7, "NBNS")) {
202 for (j = 0; j < 3; j++) {
203 if (!vpninfo->vpn_nbns[j]) {
204 vpninfo->vpn_nbns[j] = new_option->value;
208 } else if (!strcmp(buf + 7, "Default-Domain")) {
209 vpninfo->vpn_domain = new_option->value;
213 if (!vpninfo->vpn_addr) {
214 vpninfo->progress(vpninfo, PRG_ERR, "No IP address received. Aborting\n");
217 if (!vpninfo->vpn_netmask)
218 vpninfo->vpn_netmask = "255.255.255.255";
220 if (strcmp(old_addr, vpninfo->vpn_addr)) {
221 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different IP address (%s != %s)\n",
222 vpninfo->vpn_addr, old_addr);
227 if (strcmp(old_netmask, vpninfo->vpn_netmask)) {
228 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect gave different netmask (%s != %s)\n",
229 vpninfo->vpn_netmask, old_netmask);
234 while (old_dtls_opts) {
235 struct vpn_option *tmp = old_dtls_opts;
236 old_dtls_opts = old_dtls_opts->next;
241 while (old_cstp_opts) {
242 struct vpn_option *tmp = old_cstp_opts;
243 old_cstp_opts = old_cstp_opts->next;
248 vpninfo->progress(vpninfo, PRG_INFO, "CSTP connected. DPD %d, Keepalive %d\n",
249 vpninfo->ssl_times.dpd, vpninfo->ssl_times.keepalive);
251 BIO_set_nbio(SSL_get_rbio(vpninfo->https_ssl),1);
252 BIO_set_nbio(SSL_get_wbio(vpninfo->https_ssl),1);
254 fcntl(vpninfo->ssl_fd, F_SETFL, fcntl(vpninfo->ssl_fd, F_GETFL) | O_NONBLOCK);
255 vpninfo->ssl_pfd = vpn_add_pollfd(vpninfo, vpninfo->ssl_fd, POLLIN|POLLHUP|POLLERR);
257 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
262 int make_cstp_connection(struct openconnect_info *vpninfo)
264 if (!vpninfo->https_ssl && openconnect_open_https(vpninfo))
267 if (vpninfo->deflate) {
268 vpninfo->deflate_adler32 = 1;
269 vpninfo->inflate_adler32 = 1;
271 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
272 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
273 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
274 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
275 vpninfo->deflate = 0;
278 if (!vpninfo->deflate_pkt) {
279 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
280 if (!vpninfo->deflate_pkt) {
281 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
282 vpninfo->deflate = 0;
284 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
285 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
286 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
290 if (start_cstp_connection(vpninfo))
297 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
299 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
307 vpninfo->inflate_strm.next_in = buf;
308 vpninfo->inflate_strm.avail_in = len - 4;
310 vpninfo->inflate_strm.next_out = new->data;
311 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
312 vpninfo->inflate_strm.total_out = 0;
314 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
315 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
320 new->len = vpninfo->inflate_strm.total_out;
322 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
323 new->data, new->len);
325 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
326 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
329 vpninfo->progress(vpninfo, PRG_TRACE,
330 "Received compressed data packet of %ld bytes\n",
331 vpninfo->inflate_strm.total_out);
333 queue_packet(&vpninfo->incoming_queue, new);
337 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
339 unsigned char buf[16384];
343 /* FIXME: The poll() handling here is fairly simplistic. Actually,
344 if the SSL connection stalls it could return a WANT_WRITE error
345 on _either_ of the SSL_read() or SSL_write() calls. In that case,
346 we should probably remove POLLIN from the events we're looking for,
347 and add POLLOUT. As it is, though, it'll just chew CPU time in that
348 fairly unlikely situation, until the write backlog clears. */
349 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
352 if (buf[0] != 'S' || buf[1] != 'T' ||
353 buf[2] != 'F' || buf[3] != 1 || buf[7])
356 payload_len = (buf[4] << 8) + buf[5];
357 if (len != 8 + payload_len) {
358 vpninfo->progress(vpninfo, PRG_ERR,
359 "Unexpected packet length. SSL_read returned %d but packet is\n",
361 vpninfo->progress(vpninfo, PRG_ERR,
362 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
363 buf[0], buf[1], buf[2], buf[3],
364 buf[4], buf[5], buf[6], buf[7]);
367 vpninfo->ssl_times.last_rx = time(NULL);
370 vpninfo->progress(vpninfo, PRG_TRACE,
371 "Got CSTP DPD request\n");
372 vpninfo->owe_ssl_dpd_response = 1;
375 case AC_PKT_DPD_RESP:
376 vpninfo->progress(vpninfo, PRG_TRACE,
377 "Got CSTP DPD response\n");
380 case AC_PKT_KEEPALIVE:
381 vpninfo->progress(vpninfo, PRG_TRACE,
382 "Got CSTP Keepalive\n");
386 vpninfo->progress(vpninfo, PRG_TRACE,
387 "Received uncompressed data packet of %d bytes\n",
389 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
394 case AC_PKT_DISCONN: {
396 for (i = 0; i < payload_len; i++) {
397 if (!isprint(buf[payload_len + 8 + i]))
398 buf[payload_len + 8 + i] = '.';
400 buf[payload_len + 8] = 0;
401 vpninfo->progress(vpninfo, PRG_ERR,
402 "Received server disconnect: '%s'\n", buf + 8);
403 vpninfo->quit_reason = "Server request";
406 case AC_PKT_COMPRESSED:
407 if (!vpninfo->deflate) {
408 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
411 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
415 case AC_PKT_TERM_SERVER:
416 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
417 vpninfo->quit_reason = "Server request";
422 vpninfo->progress(vpninfo, PRG_ERR,
423 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
424 buf[0], buf[1], buf[2], buf[3],
425 buf[4], buf[5], buf[6], buf[7]);
426 vpninfo->quit_reason = "Unknown packet received";
431 /* If SSL_write() fails we are expected to try again. With exactly
432 the same data, at exactly the same location. So we keep the
433 packet we had before.... */
434 if (vpninfo->current_ssl_pkt) {
436 vpninfo->ssl_times.last_tx = time(NULL);
437 vpninfo->pfds[vpninfo->ssl_pfd].events &= ~POLLOUT;
438 ret = SSL_write(vpninfo->https_ssl,
439 vpninfo->current_ssl_pkt->hdr,
440 vpninfo->current_ssl_pkt->len + 8);
442 ret = SSL_get_error(vpninfo->https_ssl, ret);
444 case SSL_ERROR_WANT_WRITE:
445 /* Waiting for the socket to become writable -- it's
446 probably stalled, and/or the buffers are full */
447 vpninfo->pfds[vpninfo->ssl_pfd].events |= POLLOUT;
448 case SSL_ERROR_WANT_READ:
449 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
453 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
454 ERR_print_errors_fp(stderr);
455 vpninfo->quit_reason = "SSL write error";
459 if (ret != vpninfo->current_ssl_pkt->len + 8) {
460 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
461 vpninfo->current_ssl_pkt->len + 8, ret);
462 vpninfo->quit_reason = "Internal error";
465 /* Don't free the 'special' packets */
466 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
467 vpninfo->current_ssl_pkt != &dpd_pkt &&
468 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
469 vpninfo->current_ssl_pkt != &keepalive_pkt)
470 free(vpninfo->current_ssl_pkt);
472 vpninfo->current_ssl_pkt = NULL;
475 if (vpninfo->owe_ssl_dpd_response) {
476 vpninfo->owe_ssl_dpd_response = 0;
477 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
478 goto handle_outgoing;
481 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
483 /* Not that this will ever happen; we don't even process
484 the setting when we're asked for it. */
485 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
486 time(&vpninfo->ssl_times.last_rekey);
492 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
493 SSL_free(vpninfo->https_ssl);
494 vpninfo->https_ssl = NULL;
495 close(vpninfo->ssl_fd);
497 /* It's already deflated in the old stream. Extremely
498 non-trivial to reconstitute it; just throw it away */
499 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
500 vpninfo->current_ssl_pkt = NULL;
502 if (make_cstp_connection(vpninfo)) {
503 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
504 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
507 /* I think we can leave DTLS to its own devices; when we reconnect
508 with the same master secret, we do seem to get the same sessid */
512 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
514 vpninfo->current_ssl_pkt = &dpd_pkt;
515 goto handle_outgoing;
518 /* No need to send an explicit keepalive
519 if we have real data to send */
520 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
523 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
525 vpninfo->current_ssl_pkt = &keepalive_pkt;
526 goto handle_outgoing;
532 /* Service outgoing packet queue, if no DTLS */
533 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
534 struct pkt *this = vpninfo->outgoing_queue;
535 vpninfo->outgoing_queue = this->next;
537 if (vpninfo->deflate) {
538 unsigned char *adler;
541 vpninfo->deflate_strm.next_in = this->data;
542 vpninfo->deflate_strm.avail_in = this->len;
543 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
544 vpninfo->deflate_strm.avail_out = 2040;
545 vpninfo->deflate_strm.total_out = 0;
547 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
549 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
553 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
554 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
556 /* Add ongoing adler32 to tail of compressed packet */
557 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
558 this->data, this->len);
560 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
561 *(adler++) = vpninfo->deflate_adler32 >> 24;
562 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
563 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
564 *(adler) = vpninfo->deflate_adler32 & 0xff;
566 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
568 vpninfo->progress(vpninfo, PRG_TRACE,
569 "Sending compressed data packet of %d bytes\n",
572 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
575 memcpy(this->hdr, data_hdr, 8);
576 this->hdr[4] = this->len >> 8;
577 this->hdr[5] = this->len & 0xff;
579 vpninfo->progress(vpninfo, PRG_TRACE,
580 "Sending uncompressed data packet of %d bytes\n",
583 vpninfo->current_ssl_pkt = this;
585 goto handle_outgoing;
588 /* Work is not done if we just got rid of packets off the queue */
592 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
594 unsigned char *bye_pkt;
595 int reason_len = strlen(reason);
596 bye_pkt = malloc(reason_len + 8);
600 memcpy(bye_pkt, data_hdr, 8);
601 memcpy(bye_pkt + 8, reason, strlen(reason));
603 bye_pkt[4] = reason_len >> 8;
604 bye_pkt[5] = reason_len & 0xff;
605 bye_pkt[6] = AC_PKT_DISCONN;
607 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
610 vpninfo->progress(vpninfo, PRG_TRACE,
611 "Send BYE packet: %s\n", reason);