From b9fe6b6263b2df8d3973f6212501854a93635d20 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 19 Jan 2014 02:59:04 +0100 Subject: [PATCH] instead of using the TLS session ID as session identifier prior to authentication use the webvpncontext cookie. --- src/ipc.proto | 6 +++--- src/main-auth.c | 51 +++++++++++++++++++++++++++++--------------- src/main.c | 8 ++++--- src/main.h | 8 +++---- src/vpn.h | 3 +++ src/worker-auth.c | 45 ++++++++++++++++++++++++--------------- src/worker-vpn.c | 54 +++++++++++++++++++++++++++++++++-------------- src/worker.h | 6 ++++++ 8 files changed, 121 insertions(+), 60 deletions(-) diff --git a/src/ipc.proto b/src/ipc.proto index 3a474086..cd52f37e 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -26,7 +26,7 @@ * * (worker terminates as client disconnects) * - * <------ AUTH_REINIT (password) + * <------ AUTH_REINIT (password, sid) * AUTH_REP(ΟΚ) ------> * */ @@ -40,7 +40,7 @@ message auth_init_msg optional string cert_user_name = 4; optional string cert_group_name = 5; optional string hostname = 6; - required bytes session_id = 7; /* TLS */ + optional bytes sid = 7; } /* AUTH_REINIT - used in cisco compatible clients, to @@ -49,7 +49,7 @@ message auth_reinit_msg { required bool tls_auth_ok = 1 [default = false]; required string password = 2; - required bytes session_id = 3; + required bytes sid = 3; } /* AUTH_COOKIE_REQ */ diff --git a/src/main-auth.c b/src/main-auth.c index 0cf4f1d9..4239872c 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -249,14 +249,34 @@ const char* ip; return -1; } - if (req->session_id.len == 0 || req->session_id.len > sizeof(proc->tls_session_id)) { - mslog(s, proc, LOG_DEBUG, "auth init from '%s' with no session ID present", ip); - return -1; - } + if (req->hostname != NULL) { + snprintf(proc->hostname, sizeof(proc->hostname), "%s", req->hostname); + } - if (req->hostname == NULL) { - memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE); - proc->hostname[sizeof(proc->hostname)-1] = 0; + if (req->has_sid != 0 && req->sid.len == sizeof(proc->sid)) { + unsigned unique = 1; + struct proc_st *ctmp = NULL; + + /* the client has requested changing its SID. We must first make sure it is + * unique. + */ + list_for_each(&s->proc_list.head, ctmp, list) { + if (ctmp->sid_size > 0 && ctmp->sid_size == req->sid.len) { + if (memcmp(req->sid.data, ctmp->sid, ctmp->sid_size) == 0) { + /* it is not */ + unique = 0; + break; + } + } + } + + if (unique != 0) { + memcpy(proc->sid, req->sid.data, sizeof(proc->sid)); + proc->sid_size = sizeof(proc->sid); + mslog_hex(s, proc, LOG_DEBUG, "auth init updated SID to", req->sid.data, req->sid.len); + } else { + mslog_hex(s, proc, LOG_DEBUG, "auth init asks to update SID but it is not unique", req->sid.data, req->sid.len); + } } if (req->user_name != NULL && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) { @@ -276,9 +296,6 @@ const char* ip; } } - memcpy(proc->tls_session_id, req->session_id.data, req->session_id.len); - proc->tls_session_id_size = req->session_id.len; - ret = check_user_group_status(s, proc, req->tls_auth_ok, req->cert_user_name, req->cert_group_name); if (ret < 0) return ret; @@ -304,8 +321,8 @@ unsigned found = 0; ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, ipbuf, sizeof(ipbuf)); - if (req->session_id.len == 0) { - mslog(s, proc, LOG_DEBUG, "auth reinit from '%s' with no session ID present", ip); + if (req->sid.len == 0) { + mslog(s, proc, LOG_DEBUG, "auth reinit from '%s' with no SID present", ip); return -1; } @@ -314,11 +331,10 @@ unsigned found = 0; return -1; } - /* search all procs for a matching session ID */ - + /* search all procs for a matching SID */ list_for_each(&s->proc_list.head, ctmp, list) { - if (ctmp->status == PS_AUTH_ZOMBIE && ctmp->tls_session_id_size == req->session_id.len) { - if (memcmp(req->session_id.data, ctmp->tls_session_id, ctmp->tls_session_id_size) == 0) { + if (ctmp->status == PS_AUTH_ZOMBIE && ctmp->sid_size > 0 && ctmp->sid_size == req->sid.len) { + if (memcmp(req->sid.data, ctmp->sid, ctmp->sid_size) == 0) { /* replace sessions */ ctmp->pid = proc->pid; ctmp->fd = proc->fd; @@ -326,6 +342,7 @@ unsigned found = 0; proc->pid = -1; proc->fd = -1; + proc->sid_size = 0; *_proc = proc = ctmp; found = 1; break; @@ -334,7 +351,7 @@ unsigned found = 0; } if (found == 0) { - mslog(s, proc, LOG_DEBUG, "auth reinit received from '%s', but does not match any session", ip); + mslog_hex(s, proc, LOG_DEBUG, "auth reinit received but does not match any session with SID", req->sid.data, req->sid.len); return -1; } diff --git a/src/main.c b/src/main.c index 667bef06..b75db575 100644 --- a/src/main.c +++ b/src/main.c @@ -858,8 +858,6 @@ int main(int argc, char** argv) deny_severity = LOG_DAEMON|LOG_WARNING; #endif - memset(&ws, 0, sizeof(ws)); - if (config.foreground == 0) { if (daemon(0, 0) == -1) { e = errno; @@ -943,6 +941,8 @@ int main(int argc, char** argv) set = FD_ISSET(ltmp->fd, &rd_set); if (set && ltmp->socktype == SOCK_STREAM) { /* connection on TCP port */ + memset(&ws, 0, sizeof(ws)); + ws.remote_addr_len = sizeof(ws.remote_addr); fd = accept(ltmp->fd, (void*)&ws.remote_addr, &ws.remote_addr_len); if (fd < 0) { @@ -981,6 +981,9 @@ int main(int argc, char** argv) break; } + gnutls_rnd(GNUTLS_RND_NONCE, ws.sid, sizeof(ws.sid)); + ws.sid_size = sizeof(ws.sid); + pid = fork(); if (pid == 0) { /* child */ /* close any open descriptors, and erase @@ -992,7 +995,6 @@ int main(int argc, char** argv) setproctitle(PACKAGE_NAME"-worker"); kill_on_parent_kill(SIGTERM); - ws.config = &config; ws.cmd_fd = cmd_fd[1]; ws.tun_fd = -1; diff --git a/src/main.h b/src/main.h index dddb644c..446270f2 100644 --- a/src/main.h +++ b/src/main.h @@ -64,7 +64,6 @@ struct script_wait_st { struct proc_st* proc; }; -#define MAX_ZOMBIE_SECS 240 enum { PS_AUTH_INACTIVE, /* no comm with worker */ PS_AUTH_INIT, /* worker has sent an auth init msg */ @@ -90,10 +89,11 @@ struct proc_st { struct sockaddr_storage remote_addr; /* peer address */ socklen_t remote_addr_len; - /* The TLS session ID. + /* A unique session identifier used to distinguish + * sessions prior to authentication. */ - uint8_t tls_session_id[GNUTLS_MAX_SESSION_ID]; - unsigned tls_session_id_size; /* would act as a flag if session_id is set */ + uint8_t sid[MAX_SID_SIZE]; + unsigned sid_size; /* would act as a flag if sid is set */ /* The DTLS session ID associated with the TLS session * it is either generated or restored from a cookie. diff --git a/src/vpn.h b/src/vpn.h index 88ffc9b7..4aea60e8 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -79,6 +79,9 @@ extern int syslog_open; #define MAX_CIPHERSUITE_NAME 64 #define MAX_DTLS_CIPHERSUITE_NAME 24 #define MAX_MSG_SIZE 256 +#define MAX_SID_SIZE 12 + +#define MAX_ZOMBIE_SECS 240 typedef enum { AUTH_INIT = 1, diff --git a/src/worker-auth.c b/src/worker-auth.c index a68bd772..857a2963 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -79,6 +79,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) { int ret; char login_msg[MAX_MSG_SIZE + sizeof(login_msg_user)]; + struct http_req_st *req = &ws->req; unsigned int lsize; tls_cork(ws->session); @@ -90,6 +91,21 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) if (ret < 0) return -1; + if (req->sid_cookie_set == 0) { + char context[MAX_SID_SIZE*2+1]; + size_t csize = sizeof(context); + gnutls_datum_t sid = {ws->sid, ws->sid_size}; + + ret = gnutls_hex_encode(&sid, context, &csize); + ret = + tls_printf(ws->session, "Set-Cookie: webvpncontext=%s; Max-Age=%u; Secure\r\n", + context, (unsigned)MAX_ZOMBIE_SECS); + if (ret < 0) + return -1; + + oclog(ws, LOG_ERR, "sent sid: %s", context); + } + ret = tls_puts(ws->session, "Content-Type: text/xml\r\n"); if (ret < 0) return -1; @@ -454,7 +470,7 @@ int post_common_handler(worker_st * ws, unsigned http_ver) return -1; ret = - tls_printf(ws->session, "Set-Cookie: webvpn=%s;Max-Age=%u\r\n", + tls_printf(ws->session, "Set-Cookie: webvpn=%s; Max-Age=%u; Secure\r\n", str_cookie, (unsigned)ws->config->cookie_validity); if (ret < 0) return -1; @@ -462,21 +478,21 @@ int post_common_handler(worker_st * ws, unsigned http_ver) #ifdef ANYCONNECT_CLIENT_COMPAT ret = tls_puts(ws->session, - "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; secure\r\n"); + "Set-Cookie: webvpnc=; expires=Thu, 01 Jan 1970 22:00:00 GMT; path=/; Secure\r\n"); if (ret < 0) return -1; if (ws->config->xml_config_file) { ret = tls_printf(ws->session, - "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s&lu:/+CSCOT+/translation-table?textdomain%%3DAnyConnect%%26type%%3Dmanifest&fu:profiles%%2F%s&fh:%s; path=/; secure\r\n", + "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s&lu:/+CSCOT+/translation-table?textdomain%%3DAnyConnect%%26type%%3Dmanifest&fu:profiles%%2F%s&fh:%s; path=/; Secure\r\n", ws->config->cert_hash, ws->config->xml_config_file, ws->config->xml_config_hash); } else { ret = tls_printf(ws->session, - "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; secure\r\n", + "Set-Cookie: webvpnc=bu:/&p:t&iu:1/&sh:%s; path=/; Secure\r\n", ws->config->cert_hash); } @@ -656,8 +672,6 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) char *password = NULL; char tmp_user[MAX_USERNAME_SIZE]; char tmp_group[MAX_USERNAME_SIZE]; - uint8_t tls_session_id[GNUTLS_MAX_SESSION_ID]; - size_t tls_session_id_size; char msg[MAX_MSG_SIZE]; oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length, @@ -666,13 +680,6 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) if (ws->auth_state == S_AUTH_INACTIVE) { AuthInitMsg ireq = AUTH_INIT_MSG__INIT; - tls_session_id_size = sizeof(tls_session_id); - ret = gnutls_session_get_id(ws->session, tls_session_id, &tls_session_id_size); - if (ret < 0) { - oclog(ws, LOG_INFO, "failed obtainng session ID"); - goto auth_fail; - } - if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) { ret = read_user_pass(ws, req->body, req->body_length, @@ -695,8 +702,8 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) rreq.tls_auth_ok = ws->cert_auth_ok; rreq.password = password; - rreq.session_id.data = tls_session_id; - rreq.session_id.len = tls_session_id_size; + rreq.sid.data = ws->sid; + rreq.sid.len = ws->sid_size; ret = send_msg_to_main(ws, AUTH_REINIT, &rreq, (pack_size_func)auth_reinit_msg__get_packed_size, @@ -742,9 +749,13 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) ireq.cert_group_name = tmp_group; } - ireq.session_id.data = tls_session_id; - ireq.session_id.len = tls_session_id_size; ireq.hostname = req->hostname; + if (req->sid_cookie_set != 0) { + oclog(ws, LOG_INFO, "updating SID (%u)", ws->sid_size); + ireq.sid.data = ws->sid; + ireq.sid.len = ws->sid_size; + ireq.has_sid = 1; + } ret = send_msg_to_main(ws, AUTH_INIT, &ireq, diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 24f484bf..59451e60 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -308,26 +308,48 @@ static void value_check(struct worker_st *ws, struct http_req_st *req) length = req->value.length; p = memmem(req->value.data, length, "webvpn=", 7); - if (p == NULL || length <= 7) { - req->cookie_set = 0; - break; - } - p += 7; - length -= 7; + if (p != NULL && length > 7) { + p += 7; + length -= 7; - if (length < COOKIE_SIZE * 2) { - req->cookie_set = 0; - break; - } - length = COOKIE_SIZE * 2; - nlen = sizeof(req->cookie); - gnutls_hex2bin((void *)p, length, req->cookie, &nlen); + if (length < COOKIE_SIZE * 2) { + req->cookie_set = 0; + break; + } + length = COOKIE_SIZE * 2; + nlen = sizeof(req->cookie); + gnutls_hex2bin((void *)p, length, req->cookie, &nlen); - if (nlen < COOKIE_SIZE) { - req->cookie_set = 0; + if (nlen < COOKIE_SIZE) { + req->cookie_set = 0; + break; + } + req->cookie_set = 1; break; + } else { + p = memmem(req->value.data, length, "webvpncontext=", 14); + if (p != NULL && length > 14) { + p += 14; + length -= 14; + + if (length < sizeof(ws->sid) * 2) { + req->sid_cookie_set = 0; + break; + } + length = sizeof(ws->sid) * 2; + nlen = sizeof(ws->sid); + gnutls_hex2bin((void *)p, length, ws->sid, &nlen); + + if (nlen < sizeof(ws->sid)) { + req->sid_cookie_set = 0; + break; + } + req->sid_cookie_set = 1; + ws->sid_size = nlen; + oclog(ws, LOG_ERR, "received sid: %.*s", length, p); + break; + } } - req->cookie_set = 1; break; } } diff --git a/src/worker.h b/src/worker.h index f22ac230..5118827e 100644 --- a/src/worker.h +++ b/src/worker.h @@ -79,6 +79,7 @@ struct http_req_st { unsigned int next_header; unsigned char cookie[COOKIE_SIZE]; unsigned int cookie_set; + unsigned int sid_cookie_set; unsigned char master_secret[TLS_MASTER_SIZE]; unsigned int master_secret_set; @@ -105,6 +106,11 @@ typedef struct worker_st { struct tls_st *creds; gnutls_session_t session; gnutls_session_t dtls_session; + + /* inique session identifier */ + uint8_t sid[MAX_SID_SIZE]; + unsigned sid_size; + int cmd_fd; int conn_fd;