From: David Woodhouse Date: Sun, 21 Sep 2008 19:59:05 +0000 (-0700) Subject: Try using OpenSSL directly X-Git-Tag: v0.90~126 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5d2e4c48906af017174c2dc053671660c24563c1;p=platform%2Fupstream%2Fopenconnect.git Try using OpenSSL directly --- diff --git a/cisco.c b/cisco.c index cf0d5a1..8b4f00f 100644 --- a/cisco.c +++ b/cisco.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,6 +9,14 @@ #include #include #include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE +#include #if 0 /* If the cookie expires, you can get another one by connecting with @@ -23,31 +32,28 @@ X-Transcend-Version: 1 #endif -char request[] = "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n" - "Host: vpnserver\r\n" - "User-Agent: Cisco AnyConnect VPN Agent for Windows 2.2.0\r\n" - "Cookie: webvpn=835267836@921600@1221512527@6BC73D90EB2F59E242F75B424D42F223D0912984\r\n" - "X-CSTP-Version: 1\r\n" - "X-CSTP-Hostname: macbook.infradead.org\r\n" - "X-CSTP-Accept-Encoding: xxdeflate;q=1.0\r\n" - "X-CSTP-MTU: 1406\r\n" - "X-CSTP-Address-Type: IPv6,IPv4\r\n" - "X-DTLS-Master-Secret: 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A\r\n" - "X-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n"; - /* The master-secret is generated randomly by the client. The server responds with a DTLS Session-ID. These are enough to 'resume' the DTLS session, bypassing all the initial setup of a normal DTLS connection. Or you can just send traffic over the HTTPS connection... */ -int main(int argc, char **argv) +struct cstp_option { + const char *option; + const char *value; + struct cstp_option *next; +}; + +char *cookie; +char *hostname; +unsigned char dtls_secret[48]; +int mtu = 1406; +int deflate; +const char *useragent = "Cisco AnyConnect VPN Agent for Windows 2.2.0"; +int verbose; + +/* Set up a tuntap device. */ +int setup_tun(struct cstp_option *options) { - int in_pipes[2]; - int out_pipes[2]; - pid_t ssl_pid; - unsigned char buf[65536 + 8]; - int buflen; - int state = 0; struct ifreq ifr; int tun_fd; @@ -63,38 +69,210 @@ int main(int argc, char **argv) perror("TUNSETIFF"); exit(1); } + /* FIXME: Configure it... */ + /* Better still, use lwip and just provide a SOCKS server rather than + telling the kernel at all */ + return tun_fd; +} + +SSL *open_https(const char *host) +{ + SSL_METHOD *ssl3_method; + SSL_CTX *https_ctx; + SSL *https_ssl; + BIO *https_bio; + int ssl_sock; + int err; + struct addrinfo hints, *result, *rp; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_STREAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + err = getaddrinfo(host, "https", &hints, &result); + if (err) { + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); + return NULL; + } - pipe(in_pipes); - pipe(out_pipes); + for (rp = result; rp ; rp = rp->ai_next) { + ssl_sock = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (ssl_sock < 0) + continue; - ssl_pid = fork(); - if (!ssl_pid) { - dup2(out_pipes[0], 0); - dup2(in_pipes[1], 1); + if (connect(ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) + break; - close(in_pipes[0]); - close(in_pipes[1]); - close(out_pipes[0]); - close(out_pipes[1]); - execlp("openssl", "openssl", "s_client", "-quiet", "-connect", "vpnserver:443", NULL); - perror("exec"); - exit(1); + close(ssl_sock); + } + freeaddrinfo(result); + + if (!rp) { + fprintf(stderr, "Failed to connect to host %s\n", host); + return NULL; + } + + ssl3_method = SSLv23_client_method(); + https_ctx = SSL_CTX_new(ssl3_method); + https_ssl = SSL_new(https_ctx); + + https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE); + SSL_set_bio(https_ssl, https_bio, https_bio); + + if (SSL_connect(https_ssl) <= 0) { + BIO *err_bio = BIO_new_fp(stderr, BIO_NOCLOSE); + fprintf(stderr, "SSL connection failure\n"); + SSL_free(https_ssl); + SSL_CTX_free(https_ctx); + return NULL; + } + + return https_ssl; +} + +struct cstp_option *start_ssl_connection(SSL *ssl) +{ + char buf[65536]; + int i, state = 0; + struct cstp_option *options = NULL, **next_opt = &options; + struct utsname utsbuf; + BIO *bio = BIO_new(BIO_f_ssl()); + + BIO_set_ssl(bio, ssl, BIO_NOCLOSE); + + if (uname(&utsbuf)) + sprintf(utsbuf.nodename, "localhost"); + + if (verbose) + printf("Connected to HTTPS on %s\n", hostname); + + BIO_printf(bio, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n"); + BIO_printf(bio, "Host: %s\r\n", hostname); + BIO_printf(bio, "User-Agent: %S\r\n", useragent); + BIO_printf(bio, "Cookie: webvpn=%s\r\n", cookie); + BIO_printf(bio, "X-CSTP-Version: 1\r\n"); + BIO_printf(bio, "X-CSTP-Hostname: %s\r\n", utsbuf.nodename); + if (deflate) + BIO_printf(bio, "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n"); + BIO_printf(bio, "X-CSTP-MTU: %d\r\n", mtu); + BIO_printf(bio, "X-CSTP-Address-Type: IPv6,IPv4\r\n"); + BIO_printf(bio, "X-DTLS-Master-Secret: "); + for (i = 0; i < sizeof(dtls_secret); i++) + BIO_printf(bio, "%02X", dtls_secret[i]); + BIO_printf(bio, "X-DTLS-CipherSuite: AES256-SHA:AES128-SHA:DES-CBC3-SHA:DES-CBC-SHA\r\n\r\n"); + + state = 0; +#if 0 + state = BIO_gets(bio, buf, sizeof(buf)-1); + + if (state <= 0) { + fprintf(stderr, "Error getting HTTP CONNECT response: %d\n", state); + BIO_free(bio); + return NULL; } + if (!strncmp(buf, "HTTP/1.1 200 ", 13)) { + fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n", + buf); + BIO_free(bio); + return NULL; + } + + while (BIO_gets(bio, buf, sizeof(buf)-1)) { + char *colon = strchr(buf, ':'); + + if (buf[strlen(buf)] == '\r') { + printf("ends \\r\n"); + buf[strlen(buf)] = 0; + } - write(out_pipes[1], request, sizeof(request)); - while (state < 4) { - read(in_pipes[0], buf, 1); - if ((state == 0 || state == 2) && - buf[0] == '\r') - state++; - else if ((state == 1 || state == 3) && - buf[0] == '\n') - state++; - else state = 0; - write(1, buf, 1); + if (!strlen(buf)) + break; + + fprintf(stderr, "Got: %s\n", buf); } +#else + while (state < 4) { + SSL_read(ssl, buf, 1); + if ((state == 0 || state == 2) && + buf[0] == '\r') + state++; + else if ((state == 1 || state == 3) && + buf[0] == '\n') + state++; + else state = 0; + write(1, buf, 1); + } +#endif + return NULL; +} + +static struct option long_options[] = { + {"cookie", 1, 0, 'c'}, + {"host", 1, 0, 'h'}, + {"mtu", 1, 0, 'm'}, +}; + +int main(int argc, char **argv) +{ + SSL *https_ssl; + struct cstp_option *opts; + int tun_fd; + int optind; + int opt; + char buf[65536 + 8]; + + SSL_library_init (); + ERR_clear_error (); + SSL_load_error_strings (); + OpenSSL_add_all_algorithms (); + + while (opt = getopt_long(argc, argv, "c:h:", long_options, &optind)) { + if (opt < 0) + break; + + switch (opt) { + case 'c': + cookie = optarg; + break; + + case 'h': + hostname = optarg; + break; + + case 'm': + mtu = atol(optarg); + if (mtu < 576) { + fprintf(stderr, "MTU %d too small\n", mtu); + exit(1); + } + break; + } + } + if (!hostname || !cookie) { + fprintf(stderr, "Need -h hostname, -c cookie\n"); + exit(1); + } + + https_ssl = open_https(hostname); + if (!https_ssl) + exit(1); + int i; + for (i=0; i<48; i++) + dtls_secret[i] = i; + + opts = start_ssl_connection(https_ssl); + + exit(1); printf("Connected\n"); + tun_fd = setup_tun(NULL); + if (fork()) { while (1) { size_t len; @@ -113,15 +291,15 @@ int main(int argc, char **argv) buf[4] = len >> 8; buf[5] = len & 0xff; } - write(out_pipes[1], buf, len + 8); + SSL_write(https_ssl, buf, len + 8); } } else { while (1) { int len; - read(in_pipes[0], buf, 8); + SSL_read(https_ssl, buf, 8); len = (buf[4] << 8) + buf [5]; - read(in_pipes[0], buf + 8, len); + SSL_read(https_ssl, buf + 8, len); if (buf[0] != 'S' || buf[1] != 'T' || buf[2] != 'F' ||