Skip to content

Commit

Permalink
Add cookie fetching code, given a certificate. This bit sucks
Browse files Browse the repository at this point in the history
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Sep 25, 2008
1 parent 5f6631e commit fb9f39f
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 16 deletions.
8 changes: 8 additions & 0 deletions anyconnect.h
Expand Up @@ -114,6 +114,7 @@ int make_ssl_connection(struct anyconnect_info *vpninfo);
void vpn_init_openssl(void);
int ssl_mainloop(struct anyconnect_info *vpninfo, int *timeout);
int ssl_bye(struct anyconnect_info *vpninfo, char *reason);
int obtain_cookie_cert(struct anyconnect_info *vpninfo);

/* main.c */
extern int verbose;
Expand All @@ -123,3 +124,10 @@ int vpn_add_pollfd(struct anyconnect_info *vpninfo, int fd, short events);
int vpn_mainloop(struct anyconnect_info *vpninfo);
int queue_new_packet(struct pkt **q, int type, void *buf, int len);
void queue_packet(struct pkt **q, struct pkt *new);

/* curl.c */
static inline int obtain_cookie_login(struct anyconnect_info *vpninfo)
{
fprintf(stderr, "No login code yet. Hassle Marcel.\n");
return -1;
}
25 changes: 16 additions & 9 deletions main.c
Expand Up @@ -38,7 +38,8 @@
int verbose = 0;

static struct option long_options[] = {
{"cookie", 1, 0, 'c'},
{"certificate", 1, 0, 'c'},
{"cookie", 1, 0, 'C'},
{"host", 1, 0, 'h'},
{"mtu", 1, 0, 'm'},
{"verbose", 1, 0, 'v'},
Expand Down Expand Up @@ -75,19 +76,19 @@ int main(int argc, char **argv)
else
vpninfo->localname = "localhost";

/* While we get it working, make it slightly easier... and don't forget */
fprintf(stderr, "HACKING DTLS SECRET TO 0x5A5A5A...\n");
memset(vpninfo->dtls_secret, 0x5a, sizeof(vpninfo->dtls_secret));

while ((opt = getopt_long(argc, argv, "c:h:vdu:", long_options, &optind))) {
while ((opt = getopt_long(argc, argv, "C:c:h:vdu:", long_options, &optind))) {
if (opt < 0)
break;

switch (opt) {
case 'c':
case 'C':
vpninfo->cookie = optarg;
break;

case 'c':
vpninfo->cert = optarg;
break;

case 'h':
vpninfo->hostname = optarg;
break;
Expand All @@ -113,8 +114,8 @@ int main(int argc, char **argv)
break;
}
}
if (!vpninfo->hostname || !vpninfo->cookie) {
fprintf(stderr, "Need -h hostname, -c cookie\n");
if (!vpninfo->hostname) {
fprintf(stderr, "Need hostname\n");
exit(1);
}

Expand All @@ -129,6 +130,12 @@ int main(int argc, char **argv)
vpninfo->deflate_adler32 = 1;
vpninfo->inflate_adler32 = 1;

if (!vpninfo->cookie && obtain_cookie_cert(vpninfo) &&
obtain_cookie_login(vpninfo)) {
fprintf(stderr, "Failed to obtain WebVPN cookie\n");
exit(1);
}

if (make_ssl_connection(vpninfo)) {
fprintf(stderr, "Creating SSL connection failed\n");
exit(1);
Expand Down
116 changes: 109 additions & 7 deletions ssl.c
Expand Up @@ -133,6 +133,19 @@ static int open_https(struct anyconnect_info *vpninfo)

ssl3_method = SSLv23_client_method();
https_ctx = SSL_CTX_new(ssl3_method);
if (vpninfo->cert) {
printf("Using Certificate file %s\n", vpninfo->cert);
if (!SSL_CTX_use_certificate_file(https_ctx, vpninfo->cert,
SSL_FILETYPE_PEM))
fprintf(stderr, "Certificate failed\n");

if (!SSL_CTX_use_RSAPrivateKey_file(https_ctx, vpninfo->cert,
SSL_FILETYPE_PEM))
fprintf(stderr, "Private key failed\n");


}

https_ssl = SSL_new(https_ctx);

https_bio = BIO_new_socket(ssl_sock, BIO_NOCLOSE);
Expand All @@ -148,9 +161,101 @@ static int open_https(struct anyconnect_info *vpninfo)

vpninfo->ssl_fd = ssl_sock;
vpninfo->https_ssl = https_ssl;

if (verbose)
printf("Connected to HTTPS on %s\n", vpninfo->hostname);

return 0;
}

int obtain_cookie_cert(struct anyconnect_info *vpninfo)
{
char buf[65536];
int i;

if (!vpninfo->cert)
return -ENOENT;

if (open_https(vpninfo)) {
fprintf(stderr, "Failed to open HTTPS connection to %s\n",
vpninfo->hostname);
exit(1);
}

/*
* It would be nice to use cURL for this, but we really need to guarantee
* that we'll be using OpenSSL (for the TPM stuff), and it doesn't seem
* to have any way to let us provide our own socket read/write functions.
* We can only provide a socket _open_ function. Which would require having
* a socketpair() and servicing the "other" end of it.
*
* So we process the HTTP for ourselves...
*/

my_SSL_printf(vpninfo->https_ssl, "GET /+webvpn+/index.html HTTP/1.1\r\n");
my_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
my_SSL_printf(vpninfo->https_ssl, "X-Transcend-Version: 1\r\n\r\n");

if (my_SSL_gets(vpninfo->https_ssl, buf, 65536) < 0) {
fprintf(stderr, "Error fetching HTTPS response\n");
exit(1);
}

if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
fprintf(stderr, "Got inappropriate HTTP response: %s\n", buf);
exit(1);
}

if (verbose)
printf("Got HTTP response: %s\n", buf);

while ((i=my_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
if (i < 0) {
fprintf(stderr, "Error processing HTTP response\n");
exit(1);
}
if (verbose)
printf("Header: %s\n", buf);
if (!strncmp(buf, "Set-Cookie: webvpn=", 19)) {
char *cookie = buf + 19, *semicolon = strchr(cookie, ';');

if (semicolon && semicolon != cookie) {
*semicolon = 0;
vpninfo->cookie = strdup(cookie);
if (verbose)
printf("Got cookie: %s\n", cookie);
} else {
if (verbose)
printf("No cookie; certificate failed\n");
}
}
}
/* That was the headers. Now we have to eat the (chunked) response body.
This is the part where we _really_ wish we could just use cURL */

while ((i=my_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
int chunklen, rdlen = 0;
if (i < 0) {
fprintf(stderr, "Error fetching chunk header\n");
exit(1);
}
chunklen = strtol(buf, NULL, 16);
while (chunklen &&
(rdlen = SSL_read(vpninfo->https_ssl, buf, chunklen)) > 0) {
chunklen -= rdlen;
}
buf[0] = 0;
if ((i=my_SSL_gets(vpninfo->https_ssl, buf, sizeof(buf)))) {
fprintf(stderr, "error, got %d and %s\n", i, buf);
}
if (!rdlen)
break;
}
if (!vpninfo->cookie)
return -EINVAL;
else
return 0;
}

static int start_ssl_connection(struct anyconnect_info *vpninfo)
{
Expand All @@ -159,9 +264,6 @@ static int start_ssl_connection(struct anyconnect_info *vpninfo)
struct vpn_option **next_dtls_option = &vpninfo->dtls_options;
struct vpn_option **next_cstp_option = &vpninfo->cstp_options;

if (verbose)
printf("Connected to HTTPS on %s\n", vpninfo->hostname);

my_SSL_printf(vpninfo->https_ssl, "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n");
my_SSL_printf(vpninfo->https_ssl, "Host: %s\r\n", vpninfo->hostname);
my_SSL_printf(vpninfo->https_ssl, "User-Agent: %s\r\n", vpninfo->useragent);
Expand All @@ -182,15 +284,15 @@ static int start_ssl_connection(struct anyconnect_info *vpninfo)
return -EINVAL;
}

if (verbose)
printf("Got CONNECT response: %s\n", buf);

if (strncmp(buf, "HTTP/1.1 200 ", 13)) {
fprintf(stderr, "Got inappropriate HTTP CONNECT response: %s\n",
buf);
return -EINVAL;
}

if (verbose)
printf("Got CONNECT response: %s\n", buf);

/* We may have advertised it, but we only do it if the server agrees */
vpninfo->deflate = 0;

Expand Down Expand Up @@ -264,7 +366,7 @@ static int start_ssl_connection(struct anyconnect_info *vpninfo)

int make_ssl_connection(struct anyconnect_info *vpninfo)
{
if (open_https(vpninfo))
if (!vpninfo->https_ssl && open_https(vpninfo))
exit(1);

if (start_ssl_connection(vpninfo))
Expand Down

0 comments on commit fb9f39f

Please sign in to comment.