instead of using the TLS session ID as session identifier prior to authentication use the webvpncontext cookie.

This commit is contained in:
Nikos Mavrogiannopoulos
2014-01-19 02:59:04 +01:00
parent 90a9286b88
commit b9fe6b6263
8 changed files with 121 additions and 60 deletions

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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,

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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;