mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 08:46:58 +08:00
instead of using the TLS session ID as session identifier prior to authentication use the webvpncontext cookie.
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user