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
29 #include <openssl/ssl.h>
30 #include <openssl/err.h>
32 #include "openconnect.h"
35 * Data packets are encapsulated in the SSL stream as follows:
37 * 0000: Magic "STF\x1"
38 * 0004: Big-endian 16-bit length (not including 8-byte header)
39 * 0006: Byte packet type (see openconnect.h)
43 static char data_hdr[8] = {
46 AC_PKT_DATA, /* Type */
50 static struct pkt keepalive_pkt = {
51 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_KEEPALIVE, 0 },
54 static struct pkt dpd_pkt = {
55 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_OUT, 0 },
58 static struct pkt dpd_resp_pkt = {
59 .hdr = { 'S', 'T', 'F', 1, 0, 0, AC_PKT_DPD_RESP, 0 },
63 static int start_cstp_connection(struct openconnect_info *vpninfo)
68 struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
69 struct vpn_option **next_cstp_option = &vpninfo->cstp_options;
70 struct vpn_option *old_cstp_opts = vpninfo->cstp_options;
71 struct vpn_option *old_dtls_opts = vpninfo->dtls_options;
72 const char *old_addr = vpninfo->vpn_addr;
73 const char *old_netmask = vpninfo->vpn_netmask;
75 /* Clear old options which will be overwritten */
76 vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL;
77 vpninfo->cstp_options = vpninfo->dtls_options = NULL;
79 vpninfo->vpn_dns[i] = vpninfo->vpn_nbns[i] = NULL;
82 openconnect_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
83 openconnect_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
84 openconnect_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
85 openconnect_SSL_printf(vpninfo->https_ssl, "Cookie: webvpn=%s\r\n", vpninfo->cookie);
86 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Version: 1\r\n");
87 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Hostname: %s\r\n", vpninfo->localname);
89 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n");
90 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-MTU: %d\r\n", vpninfo->mtu);
91 /* To enable IPv6, send 'IPv6,IPv4'.
92 We don't know how most of that works yet though. */
93 openconnect_SSL_printf(vpninfo->https_ssl, "X-CSTP-Address-Type: IPv4\r\n");
94 openconnect_SSL_printf(vpninfo->https_ssl, "X-DTLS-Master-Secret: ");
95 for (i = 0; i < sizeof(vpninfo->dtls_secret); i++)
96 openconnect_SSL_printf(vpninfo->https_ssl, "%02X", vpninfo->dtls_secret[i]);
97 openconnect_SSL_printf(vpninfo->https_ssl, "\r\nX-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n");
99 if (openconnect_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
100 vpninfo->progress(vpninfo, PRG_ERR, "Error fetching HTTPS response\n");
103 openconnect_close_https(vpninfo);
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 if (vpninfo->select_nfds <= vpninfo->ssl_fd)
256 vpninfo->select_nfds = vpninfo->ssl_fd + 1;
258 FD_SET(vpninfo->ssl_fd, &vpninfo->select_rfds);
259 FD_SET(vpninfo->ssl_fd, &vpninfo->select_efds);
261 vpninfo->ssl_times.last_rx = vpninfo->ssl_times.last_tx = time(NULL);
266 int make_cstp_connection(struct openconnect_info *vpninfo)
268 if (!vpninfo->https_ssl && openconnect_open_https(vpninfo))
271 if (vpninfo->deflate) {
272 vpninfo->deflate_adler32 = 1;
273 vpninfo->inflate_adler32 = 1;
275 if (inflateInit2(&vpninfo->inflate_strm, -12) ||
276 deflateInit2(&vpninfo->deflate_strm, Z_DEFAULT_COMPRESSION,
277 Z_DEFLATED, -12, 9, Z_DEFAULT_STRATEGY)) {
278 vpninfo->progress(vpninfo, PRG_ERR, "Compression setup failed\n");
279 vpninfo->deflate = 0;
282 if (!vpninfo->deflate_pkt) {
283 vpninfo->deflate_pkt = malloc(sizeof(struct pkt) + 2048);
284 if (!vpninfo->deflate_pkt) {
285 vpninfo->progress(vpninfo, PRG_ERR, "Allocation of deflate buffer failed\n");
286 vpninfo->deflate = 0;
288 memset(vpninfo->deflate_pkt, 0, sizeof(struct pkt));
289 memcpy(vpninfo->deflate_pkt->hdr, data_hdr, 8);
290 vpninfo->deflate_pkt->hdr[6] = AC_PKT_COMPRESSED;
294 if (start_cstp_connection(vpninfo))
301 static int inflate_and_queue_packet(struct openconnect_info *vpninfo, int type, void *buf, int len)
303 struct pkt *new = malloc(sizeof(struct pkt) + vpninfo->mtu);
311 vpninfo->inflate_strm.next_in = buf;
312 vpninfo->inflate_strm.avail_in = len - 4;
314 vpninfo->inflate_strm.next_out = new->data;
315 vpninfo->inflate_strm.avail_out = vpninfo->mtu;
316 vpninfo->inflate_strm.total_out = 0;
318 if (inflate(&vpninfo->inflate_strm, Z_SYNC_FLUSH)) {
319 vpninfo->progress(vpninfo, PRG_ERR, "inflate failed\n");
324 new->len = vpninfo->inflate_strm.total_out;
326 vpninfo->inflate_adler32 = adler32(vpninfo->inflate_adler32,
327 new->data, new->len);
329 if (vpninfo->inflate_adler32 != ntohl( *(uint32_t *)(buf + len - 4))) {
330 vpninfo->quit_reason = "Compression (inflate) adler32 failure";
333 vpninfo->progress(vpninfo, PRG_TRACE,
334 "Received compressed data packet of %ld bytes\n",
335 vpninfo->inflate_strm.total_out);
337 queue_packet(&vpninfo->incoming_queue, new);
341 int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout)
343 unsigned char buf[16384];
347 /* FIXME: The poll() handling here is fairly simplistic. Actually,
348 if the SSL connection stalls it could return a WANT_WRITE error
349 on _either_ of the SSL_read() or SSL_write() calls. In that case,
350 we should probably remove POLLIN from the events we're looking for,
351 and add POLLOUT. As it is, though, it'll just chew CPU time in that
352 fairly unlikely situation, until the write backlog clears. */
353 while ( (len = SSL_read(vpninfo->https_ssl, buf, sizeof(buf))) > 0) {
356 if (buf[0] != 'S' || buf[1] != 'T' ||
357 buf[2] != 'F' || buf[3] != 1 || buf[7])
360 payload_len = (buf[4] << 8) + buf[5];
361 if (len != 8 + payload_len) {
362 vpninfo->progress(vpninfo, PRG_ERR,
363 "Unexpected packet length. SSL_read returned %d but packet is\n",
365 vpninfo->progress(vpninfo, PRG_ERR,
366 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
367 buf[0], buf[1], buf[2], buf[3],
368 buf[4], buf[5], buf[6], buf[7]);
371 vpninfo->ssl_times.last_rx = time(NULL);
374 vpninfo->progress(vpninfo, PRG_TRACE,
375 "Got CSTP DPD request\n");
376 vpninfo->owe_ssl_dpd_response = 1;
379 case AC_PKT_DPD_RESP:
380 vpninfo->progress(vpninfo, PRG_TRACE,
381 "Got CSTP DPD response\n");
384 case AC_PKT_KEEPALIVE:
385 vpninfo->progress(vpninfo, PRG_TRACE,
386 "Got CSTP Keepalive\n");
390 vpninfo->progress(vpninfo, PRG_TRACE,
391 "Received uncompressed data packet of %d bytes\n",
393 queue_new_packet(&vpninfo->incoming_queue, AF_INET, buf + 8,
398 case AC_PKT_DISCONN: {
400 for (i = 0; i < payload_len; i++) {
401 if (!isprint(buf[payload_len + 8 + i]))
402 buf[payload_len + 8 + i] = '.';
404 buf[payload_len + 8] = 0;
405 vpninfo->progress(vpninfo, PRG_ERR,
406 "Received server disconnect: '%s'\n", buf + 8);
407 vpninfo->quit_reason = "Server request";
410 case AC_PKT_COMPRESSED:
411 if (!vpninfo->deflate) {
412 vpninfo->progress(vpninfo, PRG_ERR, "Compressed packet received in !deflate mode\n");
415 inflate_and_queue_packet(vpninfo, AF_INET, buf + 8, payload_len);
419 case AC_PKT_TERM_SERVER:
420 vpninfo->progress(vpninfo, PRG_ERR, "received server terminate packet\n");
421 vpninfo->quit_reason = "Server request";
426 vpninfo->progress(vpninfo, PRG_ERR,
427 "Unknown packet %02x %02x %02x %02x %02x %02x %02x %02x\n",
428 buf[0], buf[1], buf[2], buf[3],
429 buf[4], buf[5], buf[6], buf[7]);
430 vpninfo->quit_reason = "Unknown packet received";
435 /* If SSL_write() fails we are expected to try again. With exactly
436 the same data, at exactly the same location. So we keep the
437 packet we had before.... */
438 if (vpninfo->current_ssl_pkt) {
440 vpninfo->ssl_times.last_tx = time(NULL);
441 FD_CLR(vpninfo->ssl_fd, &vpninfo->select_wfds);
442 ret = SSL_write(vpninfo->https_ssl,
443 vpninfo->current_ssl_pkt->hdr,
444 vpninfo->current_ssl_pkt->len + 8);
446 ret = SSL_get_error(vpninfo->https_ssl, ret);
448 case SSL_ERROR_WANT_WRITE:
449 /* Waiting for the socket to become writable -- it's
450 probably stalled, and/or the buffers are full */
451 FD_SET(vpninfo->ssl_fd, &vpninfo->select_wfds);
453 case SSL_ERROR_WANT_READ:
454 if (ka_stalled_dpd_time(&vpninfo->ssl_times, timeout))
458 vpninfo->progress(vpninfo, PRG_ERR, "SSL_write failed: %d", ret);
459 ERR_print_errors_fp(stderr);
460 vpninfo->quit_reason = "SSL write error";
464 if (ret != vpninfo->current_ssl_pkt->len + 8) {
465 vpninfo->progress(vpninfo, PRG_ERR, "SSL wrote too few bytes! Asked for %d, sent %d\n",
466 vpninfo->current_ssl_pkt->len + 8, ret);
467 vpninfo->quit_reason = "Internal error";
470 /* Don't free the 'special' packets */
471 if (vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
472 vpninfo->current_ssl_pkt != &dpd_pkt &&
473 vpninfo->current_ssl_pkt != &dpd_resp_pkt &&
474 vpninfo->current_ssl_pkt != &keepalive_pkt)
475 free(vpninfo->current_ssl_pkt);
477 vpninfo->current_ssl_pkt = NULL;
480 if (vpninfo->owe_ssl_dpd_response) {
481 vpninfo->owe_ssl_dpd_response = 0;
482 vpninfo->current_ssl_pkt = &dpd_resp_pkt;
483 goto handle_outgoing;
486 switch (keepalive_action(&vpninfo->ssl_times, timeout)) {
488 /* Not that this will ever happen; we don't even process
489 the setting when we're asked for it. */
490 vpninfo->progress(vpninfo, PRG_ERR, "CSTP rekey due but we don't know how\n");
491 time(&vpninfo->ssl_times.last_rekey);
497 vpninfo->progress(vpninfo, PRG_ERR, "CSTP Dead Peer Detection detected dead peer!\n");
498 openconnect_close_https(vpninfo);
500 /* It's already deflated in the old stream. Extremely
501 non-trivial to reconstitute it; just throw it away */
502 if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt)
503 vpninfo->current_ssl_pkt = NULL;
505 if (make_cstp_connection(vpninfo)) {
506 vpninfo->progress(vpninfo, PRG_ERR, "Reconnect failed\n");
507 vpninfo->quit_reason = "SSL DPD detected dead peer; reconnect failed";
510 /* I think we can leave DTLS to its own devices; when we reconnect
511 with the same master secret, we do seem to get the same sessid */
515 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP DPD\n");
517 vpninfo->current_ssl_pkt = &dpd_pkt;
518 goto handle_outgoing;
521 /* No need to send an explicit keepalive
522 if we have real data to send */
523 if (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue)
526 vpninfo->progress(vpninfo, PRG_TRACE, "Send CSTP Keepalive\n");
528 vpninfo->current_ssl_pkt = &keepalive_pkt;
529 goto handle_outgoing;
535 /* Service outgoing packet queue, if no DTLS */
536 while (vpninfo->dtls_fd == -1 && vpninfo->outgoing_queue) {
537 struct pkt *this = vpninfo->outgoing_queue;
538 vpninfo->outgoing_queue = this->next;
540 if (vpninfo->deflate) {
541 unsigned char *adler;
544 vpninfo->deflate_strm.next_in = this->data;
545 vpninfo->deflate_strm.avail_in = this->len;
546 vpninfo->deflate_strm.next_out = (void *)vpninfo->deflate_pkt->data;
547 vpninfo->deflate_strm.avail_out = 2040;
548 vpninfo->deflate_strm.total_out = 0;
550 ret = deflate(&vpninfo->deflate_strm, Z_SYNC_FLUSH);
552 vpninfo->progress(vpninfo, PRG_ERR, "deflate failed %d\n", ret);
556 vpninfo->deflate_pkt->hdr[4] = (vpninfo->deflate_strm.total_out + 4) >> 8;
557 vpninfo->deflate_pkt->hdr[5] = (vpninfo->deflate_strm.total_out + 4) & 0xff;
559 /* Add ongoing adler32 to tail of compressed packet */
560 vpninfo->deflate_adler32 = adler32(vpninfo->deflate_adler32,
561 this->data, this->len);
563 adler = &vpninfo->deflate_pkt->data[vpninfo->deflate_strm.total_out];
564 *(adler++) = vpninfo->deflate_adler32 >> 24;
565 *(adler++) = (vpninfo->deflate_adler32 >> 16) & 0xff;
566 *(adler++) = (vpninfo->deflate_adler32 >> 8) & 0xff;
567 *(adler) = vpninfo->deflate_adler32 & 0xff;
569 vpninfo->deflate_pkt->len = vpninfo->deflate_strm.total_out + 4;
571 vpninfo->progress(vpninfo, PRG_TRACE,
572 "Sending compressed data packet of %d bytes\n",
575 vpninfo->current_ssl_pkt = vpninfo->deflate_pkt;
578 memcpy(this->hdr, data_hdr, 8);
579 this->hdr[4] = this->len >> 8;
580 this->hdr[5] = this->len & 0xff;
582 vpninfo->progress(vpninfo, PRG_TRACE,
583 "Sending uncompressed data packet of %d bytes\n",
586 vpninfo->current_ssl_pkt = this;
588 goto handle_outgoing;
591 /* Work is not done if we just got rid of packets off the queue */
595 int cstp_bye(struct openconnect_info *vpninfo, char *reason)
597 unsigned char *bye_pkt;
598 int reason_len = strlen(reason);
599 bye_pkt = malloc(reason_len + 8);
603 memcpy(bye_pkt, data_hdr, 8);
604 memcpy(bye_pkt + 8, reason, strlen(reason));
606 bye_pkt[4] = reason_len >> 8;
607 bye_pkt[5] = reason_len & 0xff;
608 bye_pkt[6] = AC_PKT_DISCONN;
610 SSL_write(vpninfo->https_ssl, bye_pkt, reason_len + 8);
613 vpninfo->progress(vpninfo, PRG_TRACE,
614 "Send BYE packet: %s\n", reason);