Simplified cookie handling

This change set eliminates the need for cryptographically authenticated
cookies and relies on sec-module providing accurate information on
the SID provided by the client.
This commit is contained in:
Nikos Mavrogiannopoulos
2016-02-21 12:13:12 +01:00
committed by Nikos Mavrogiannopoulos
parent 88101dc9fd
commit 010257c6a2
28 changed files with 161 additions and 527 deletions

View File

@@ -63,12 +63,13 @@ leaked during a fork(). It handles:
data to the radius accounting server. See the SM_CMD_CLI_STATS message
handling.
* Gatekeeper for new user sessions. When the main process receives a valid cookie
from a worker process, it will notify the security module which keeps the
authentication state. The security module will return any additional user
configuration settings (received via radius or per-user config file) -
See SM_CMD_AUTH_SESSION_OPEN and SM_CMD_AUTH_SESSION_CLOSE message
handling.
* Gatekeeper for new user sessions. The security module assigns a session
ID (SID) to all connecting users. When the main process receives a request
to resume a session with a SID from a worker process, it will notify the
security module which keeps the authentication state. The security module
will return any additional user configuration settings (received via radius
or per-user config file) - See SM_CMD_AUTH_SESSION_OPEN and SM_CMD_AUTH_SESSION_CLOSE
message handling.
Currently it seems we require quite an amount of communication between the
main process and the security module. That may affect scaling. If that
@@ -142,3 +143,40 @@ device and the client. The tasks handled are:
```
## IPC Communication for SID assignment
This is the same diagram as above but shows how the session ID (SID)
is assigned and used throughout the server.
```
main sec-mod worker
| | |
| | <--SEC_AUTH_INIT--- |
| | -SEC_AUTH_REP (NEW SID)-> |
| | <--SEC_AUTH_CONT (SID)--- |
| | . |
| | . |
| | . |
| | ----SEC_AUTH_REP -------> |
(note that by that time the client/worker may be disconnected,
and reconnect later and use the cookie -SID- to resume the
already authenticated session).
| | |
| <----------AUTH_COOKIE_REQ (SID)----------------- |
| | |
| -SESSION_OPEN (SID)-> | |
| <--SESSION_REPLY---- | | #contains additional config for client
| | |
| -----------------AUTH_REP-----------------------> | #forwards the additional config for client
| | |
| <------------SESSION_INFO------------------------ |
| | |
| | <-- CLI_STATS (SID)------- |
| | (disconnect)
| -SESSION_CLOSE(SID)-> |
| <-- CLI_STATS (SID)-- |
```

View File

@@ -308,12 +308,6 @@ ban-reset-time = 300
# between different networks.
cookie-timeout = 300
# Cookie rekey time (in seconds)
# The time after which the key used to encrypt cookies will be
# refreshed. After this time the previous key will also be valid
# for verification until the next rotation cycle.
cookie-rekey-time = 259200
# If this is enabled (not recommended) the cookies will stay
# valid even after a user manually disconnects, and until they
# expire. This may improve roaming with some broken clients.

View File

@@ -48,8 +48,8 @@ AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h auth/radius.c auth/
ACCT_SOURCES=acct/radius.c acct/radius.h acct/pam.c acct/pam.h
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c main-worker-cmd.c ip-lease.c ip-lease.h main-proc.c \
vpn.h cookies.h tlslib.h log.c tun.c tun.h config-kkdcp.c \
main-worker-cmd.c ip-lease.c ip-lease.h main-proc.c \
vpn.h tlslib.h log.c tun.c tun.h config-kkdcp.c \
config.c worker-resume.c worker.h sec-mod-resume.c main.h \
worker-http-handlers.c html.c html.h worker-http.c \
main-user.c worker-misc.c route-add.c route-add.h worker-privs.c \

View File

@@ -87,8 +87,6 @@ const char *cmd_request_to_str(unsigned _cmd)
return "sm: ban IP";
case SM_CMD_AUTH_BAN_IP_REPLY:
return "sm: ban IP reply";
case SM_CMD_REFRESH_COOKIE_KEY:
return "sm: refresh cookie key";
default:
snprintf(tmp, sizeof(tmp), "unknown (%u)", _cmd);
return tmp;

View File

@@ -49,7 +49,6 @@
#include <netdb.h>
#include <vpn.h>
#include <cookies.h>
#include <main.h>
#include <tlslib.h>
#include <occtl/ctl.h>
@@ -910,10 +909,6 @@ size_t urlfw_size = 0;
config->cookie_timeout = DEFAULT_COOKIE_RECON_TIMEOUT;
READ_TF("persistent-cookies", config->persistent_cookies, 0);
READ_NUMERIC("cookie-rekey-time", config->cookie_rekey_time);
if (config->cookie_rekey_time == 0)
config->cookie_rekey_time = DEFAULT_COOKIE_REKEY_TIME;
READ_NUMERIC("session-timeout", config->session_timeout);
READ_NUMERIC("auth-timeout", config->auth_timeout);

View File

@@ -1,178 +0,0 @@
/*
* Copyright (C) 2013, 2014 Nikos Mavrogiannopoulos
* Copyright (C) 2014 Red Hat
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <ccan/htable/htable.h>
#include <ccan/hash/hash.h>
#include <ip-lease.h>
#include <main.h>
#include <cookies.h>
int decrypt_cookie(ProtobufCAllocator *pa, gnutls_datum_t *key,
uint8_t* cookie, unsigned cookie_size,
Cookie **msg)
{
gnutls_datum_t iv = { (void*)cookie, COOKIE_IV_SIZE };
int ret;
uint8_t tag[COOKIE_MAC_SIZE];
gnutls_cipher_hd_t h;
uint8_t *p, *decrypted = NULL;
unsigned p_size;
if (cookie_size <= COOKIE_IV_SIZE+COOKIE_MAC_SIZE)
return -1;
ret = gnutls_cipher_init(&h, GNUTLS_CIPHER_AES_128_GCM, key, &iv);
if (ret < 0)
return -1;
decrypted = talloc_size(pa->allocator_data, cookie_size);
if (decrypted == NULL) {
ret = -1;
goto cleanup;
}
cookie += COOKIE_IV_SIZE;
cookie_size -= (COOKIE_IV_SIZE + COOKIE_MAC_SIZE);
ret = gnutls_cipher_decrypt2(h, cookie, cookie_size, decrypted, cookie_size);
if (ret < 0) {
ret = -1;
goto cleanup;
}
p = decrypted;
p_size = cookie_size;
ret = gnutls_cipher_tag(h, tag, sizeof(tag));
if (ret < 0) {
ret = -1;
goto cleanup;
}
if (memcmp(tag, cookie+cookie_size, COOKIE_MAC_SIZE) != 0) {
ret = -1;
goto cleanup;
}
/* unpack */
*msg = cookie__unpack(pa, p_size, p);
if (*msg == NULL) {
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
gnutls_cipher_deinit(h);
talloc_free(decrypted);
return ret;
}
int encrypt_cookie(void *pool, gnutls_datum_t *key, const Cookie *msg,
uint8_t** ecookie, unsigned *ecookie_size)
{
uint8_t _iv[COOKIE_IV_SIZE];
gnutls_cipher_hd_t h = NULL;
gnutls_datum_t iv = { _iv, sizeof(_iv) };
int ret;
unsigned packed_size, e_size;
uint8_t *packed = NULL, *e;
/* pack the cookie */
packed_size = cookie__get_packed_size(msg);
if (packed_size == 0)
return -1;
packed = talloc_size(pool, packed_size);
if (packed == NULL)
return -1;
ret = cookie__pack(msg, packed);
if (ret == 0) {
ret = -1;
goto cleanup;
}
ret = gnutls_rnd(GNUTLS_RND_NONCE, _iv, sizeof(_iv));
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = gnutls_cipher_init(&h, GNUTLS_CIPHER_AES_128_GCM, key, &iv);
if (ret < 0) {
ret = -1;
goto cleanup;
}
e_size = packed_size+COOKIE_IV_SIZE+COOKIE_MAC_SIZE;
e = talloc_size(pool, e_size);
if (e == NULL) {
ret = -1;
goto cleanup;
}
*ecookie = e;
*ecookie_size = e_size;
memcpy(e, _iv, COOKIE_IV_SIZE);
e += COOKIE_IV_SIZE;
e_size -= COOKIE_IV_SIZE;
ret = gnutls_cipher_encrypt2(h, packed, packed_size, e, e_size);
if (ret < 0) {
ret = -1;
goto cleanup;
}
e += packed_size;
ret = gnutls_cipher_tag(h, e, COOKIE_MAC_SIZE);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
talloc_free(packed);
if (h != NULL)
gnutls_cipher_deinit(h);
return ret;
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef COOKIES_H
#define COOKIES_H
#include <vpn.h>
#include <main.h>
#include <ipc.pb-c.h>
#define COOKIE_IV_SIZE 12 /* AES-GCM */
#define COOKIE_MAC_SIZE 12 /* 96-bits of AES-GCM */
/* The time after a disconnection the cookie is valid */
#define DEFAULT_COOKIE_RECON_TIMEOUT 120
/* The time after a cookie key is rotated */
#define DEFAULT_COOKIE_REKEY_TIME 259200
int encrypt_cookie(void *pool, gnutls_datum_t *key, const Cookie *msg,
uint8_t** ecookie, unsigned *ecookie_size);
int decrypt_cookie(ProtobufCAllocator *pa, gnutls_datum_t *key,
uint8_t *cookie, unsigned cookie_size,
Cookie **msg);
#endif

View File

@@ -220,11 +220,10 @@ message sec_auth_cont_msg
message sec_auth_reply_msg
{
required AUTH_REP reply = 1;
optional bytes cookie = 2;
optional string user_name = 3;
optional string msg = 4; /* message to display to user */
optional bytes dtls_session_id = 5;
optional bytes sid = 6;
optional bytes sid = 6; /* cookie */
optional uint32 passwd_counter = 8; /* if that's a password prompt indicates the number of password asked */
}
@@ -235,19 +234,6 @@ message sec_op_msg
required bytes data = 2;
}
/* Not a real message, but the cookie */
message cookie
{
required string username = 1;
required string groupname = 2;
required string hostname = 3;
required string ip = 4;
required uint32 expiration = 6;
required uint32 ipv4_seed = 7;
required bytes sid = 8;
required bool tls_auth_ok = 9;
}
/*
* == Session Termination ==
*
@@ -259,9 +245,8 @@ message cookie
/* SEC_SESSION_CLOSE */
message sec_auth_session_msg
{
required bytes sid = 1;
/* on open */
optional bytes cookie = 2;
/* on open/close */
required bytes sid = 1; /* cookie */
/* on close */
optional uint32 uptime = 3;
optional uint64 bytes_in = 4;
@@ -270,16 +255,19 @@ message sec_auth_session_msg
optional string ipv6 = 7;
}
message sec_auth_session_reply_msg
{
required AUTH_REP reply = 1;
required group_cfg_st config = 2;
}
message sec_refresh_cookie_key
{
required bytes key = 1;
required group_cfg_st config = 2;
required string username = 3;
required string groupname = 4;
required string hostname = 5;
required string ip = 6;
required uint32 ipv4_seed = 8;
required bytes sid = 9;
required bool tls_auth_ok = 10;
}
/* SEC_BAN_IP: sent from sec-mod to main */

View File

@@ -40,7 +40,6 @@
#include "str.h"
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <ccan/list/list.h>
@@ -167,37 +166,9 @@ int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
const AuthCookieRequestMsg * req)
{
int ret;
Cookie *cmsg;
gnutls_datum_t key = {s->cookie_key, sizeof(s->cookie_key)};
char str_ip[MAX_IP_STR+1];
PROTOBUF_ALLOCATOR(pa, proc);
struct proc_st *old_proc;
if (req->cookie.len == 0) {
mslog(s, proc, LOG_INFO, "error in cookie size");
return -1;
}
ret = decrypt_cookie(&pa, &key, req->cookie.data, req->cookie.len, &cmsg);
if (ret < 0 && s->prev_cookie_key_active) {
/* try the old key */
key.data = s->prev_cookie_key;
key.size = sizeof(s->prev_cookie_key);
ret = decrypt_cookie(&pa, &key, req->cookie.data, req->cookie.len, &cmsg);
if (ret == 0)
mslog(s, proc, LOG_INFO, "decrypted cookie with previous key");
}
if (ret < 0) {
mslog(s, proc, LOG_INFO, "error decrypting cookie");
return -1;
}
if (cmsg->username == NULL)
return -1;
strlcpy(proc->username, cmsg->username, sizeof(proc->username));
if (cmsg->sid.len != sizeof(proc->sid))
if (req->cookie.data == NULL || req->cookie.len != sizeof(proc->sid))
return -1;
/* generate a new DTLS session ID for each connection, to allow
@@ -207,46 +178,20 @@ struct proc_st *old_proc;
return -1;
proc->dtls_session_id_size = sizeof(proc->dtls_session_id);
memcpy(proc->sid, cmsg->sid.data, cmsg->sid.len);
/* override the group name in order to load the correct configuration in
* case his group is specified in the certificate */
if (cmsg->groupname)
strlcpy(proc->groupname, cmsg->groupname, sizeof(proc->groupname));
/* loads sup config */
/* loads sup config and basic proc info (e.g., username) */
ret = session_open(s, proc, req->cookie.data, req->cookie.len);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "could not open session");
return -1;
}
/* this hints to call session_close() */
proc->active_sid = 1;
/* Put into right cgroup */
if (proc->config->cgroup != NULL) {
put_into_cgroup(s, proc->config->cgroup, proc->pid);
}
/* check whether the cookie IP matches */
if (proc->config->deny_roaming != 0) {
if (cmsg->ip == NULL) {
return -1;
}
if (human_addr2((struct sockaddr *)&proc->remote_addr, proc->remote_addr_len,
str_ip, sizeof(str_ip), 0) == NULL)
return -1;
if (strcmp(str_ip, cmsg->ip) != 0) {
mslog(s, proc, LOG_INFO, "user '%s' is re-using cookie from different IP (prev: %s, current: %s); rejecting",
cmsg->username, cmsg->ip, str_ip);
return -1;
}
}
/* check for a user with the same sid as in the cookie */
old_proc = proc_search_sid(s, cmsg->sid.data);
old_proc = proc_search_sid(s, req->cookie.data);
if (old_proc != NULL) {
mslog(s, old_proc, LOG_DEBUG, "disconnecting previous user session (%u) due to session re-use",
(unsigned)old_proc->pid);
@@ -267,10 +212,10 @@ struct proc_st *old_proc;
mslog(s, proc, LOG_INFO, "new user session");
}
if (cmsg->hostname)
strlcpy(proc->hostname, cmsg->hostname, sizeof(proc->hostname));
memcpy(proc->ipv4_seed, &cmsg->ipv4_seed, sizeof(proc->ipv4_seed));
/* update the SID */
memcpy(proc->sid, req->cookie.data, req->cookie.len);
/* this also hints to call session_close() */
proc->active_sid = 1;
/* add the links to proc hash */
if (proc_table_add(s, proc) < 0) {

View File

@@ -55,7 +55,6 @@
#endif
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <main-ban.h>

View File

@@ -65,7 +65,6 @@ int handle_sec_mod_commands(main_server_st * s)
void *pool = talloc_new(s);
PROTOBUF_ALLOCATOR(pa, pool);
BanIpMsg *tmsg = NULL;
SecRefreshCookieKey *rmsg = NULL;
if (pool == NULL)
return -1;
@@ -122,29 +121,6 @@ int handle_sec_mod_commands(main_server_st * s)
}
switch (cmd) {
case SM_CMD_REFRESH_COOKIE_KEY:
rmsg = sec_refresh_cookie_key__unpack(&pa, raw_len, raw);
if (rmsg == NULL) {
mslog(s, NULL, LOG_ERR, "error unpacking sec-mod data");
ret = ERR_BAD_COMMAND;
goto cleanup;
}
if (rmsg->key.len != sizeof(s->cookie_key)) {
mslog(s, NULL, LOG_ERR, "received corrupt cookie key (%u bytes) from sec-mod", (unsigned)rmsg->key.len);
ret = ERR_BAD_COMMAND;
goto cleanup;
}
memcpy(s->prev_cookie_key, s->cookie_key, sizeof(s->cookie_key));
s->prev_cookie_key_active = 1;
memcpy(s->cookie_key, rmsg->key.data, sizeof(s->cookie_key));
safe_memset(rmsg->key.data, 0, rmsg->key.len);
mslog(s, NULL, LOG_INFO, "refreshed cookie key");
break;
case SM_CMD_AUTH_BAN_IP:{
BanIpReplyMsg reply = BAN_IP_REPLY_MSG__INIT;
@@ -430,6 +406,10 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie
SecAuthSessionReplyMsg *msg = NULL;
char str_ipv4[MAX_IP_STR];
char str_ipv6[MAX_IP_STR];
char str_ip[MAX_IP_STR];
if (cookie == NULL || cookie_size != SID_SIZE)
return -1;
ireq.uptime = time(0)-proc->conn_time;
ireq.has_uptime = 1;
@@ -437,8 +417,8 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie
ireq.has_bytes_in = 1;
ireq.bytes_out = proc->bytes_out;
ireq.has_bytes_out = 1;
ireq.sid.data = proc->sid;
ireq.sid.len = sizeof(proc->sid);
ireq.sid.data = (void*)cookie;
ireq.sid.len = cookie_size;
if (proc->ipv4 &&
human_addr2((struct sockaddr *)&proc->ipv4->rip, proc->ipv4->rip_len,
@@ -452,12 +432,6 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie
ireq.ipv6 = str_ipv6;
}
if (cookie) {
ireq.cookie.data = (void*)cookie;
ireq.cookie.len = cookie_size;
ireq.has_cookie = 1;
}
mslog(s, proc, LOG_DEBUG, "sending msg %s to sec-mod", cmd_request_to_str(SM_CMD_AUTH_SESSION_OPEN));
ret = send_msg16(proc, s->sec_mod_fd_sync, SM_CMD_AUTH_SESSION_OPEN,
@@ -478,19 +452,53 @@ int session_open(main_server_st * s, struct proc_st *proc, const uint8_t *cookie
}
if (msg->reply != AUTH__REP__OK) {
mslog(s, proc, LOG_INFO, "could not initiate session for '%s'", proc->username);
mslog(s, proc, LOG_INFO, "could not initiate session");
return -1;
}
if (msg->username == NULL) {
mslog(s, proc, LOG_INFO, "no username present in session reply");
return -1;
}
strlcpy(proc->username, msg->username, sizeof(proc->username));
if (msg->hostname)
strlcpy(proc->hostname, msg->hostname, sizeof(proc->hostname));
/* override the group name in order to load the correct configuration in
* case his group is specified in the certificate */
if (msg->groupname)
strlcpy(proc->groupname, msg->groupname, sizeof(proc->groupname));
if (msg->config == NULL) {
mslog(s, proc, LOG_INFO, "received invalid configuration for '%s'; could not initiate session", proc->username);
return -1;
}
memcpy(proc->ipv4_seed, &msg->ipv4_seed, sizeof(proc->ipv4_seed));
proc->config = msg->config;
apply_default_config(s, proc, proc->config);
/* check whether the cookie IP matches */
if (proc->config && proc->config->deny_roaming != 0) {
if (msg->ip == NULL) {
return -1;
}
if (human_addr2((struct sockaddr *)&proc->remote_addr, proc->remote_addr_len,
str_ip, sizeof(str_ip), 0) == NULL)
return -1;
if (strcmp(str_ip, msg->ip) != 0) {
mslog(s, proc, LOG_INFO, "user '%s' is re-using cookie from different IP (prev: %s, current: %s); rejecting",
proc->username, msg->ip, str_ip);
return -1;
}
}
return 0;
}
@@ -593,7 +601,7 @@ int run_sec_mod(main_server_st * s, int *sync_fd)
close(sfd[1]);
set_cloexec_flag (fd[0], 1);
set_cloexec_flag (sfd[0], 1);
sec_mod_server(s->main_pool, s->perm_config, p, s->cookie_key, fd[0], sfd[0]);
sec_mod_server(s->main_pool, s->perm_config, p, fd[0], sfd[0]);
exit(0);
} else if (pid > 0) { /* parent */
close(fd[0]);

View File

@@ -40,7 +40,6 @@
#include <vpn.h>
#include <str.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <main-ctl.h>

View File

@@ -55,7 +55,6 @@
#endif
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <main-ban.h>

View File

@@ -57,7 +57,6 @@
#include <main-ban.h>
#include <route-add.h>
#include <worker.h>
#include <cookies.h>
#include <proc-search.h>
#include <tun.h>
#include <grp.h>
@@ -1044,10 +1043,6 @@ static void listen_watcher_cb (EV_P_ ev_io *w, int revents)
close(s->sec_mod_fd);
close(s->sec_mod_fd_sync);
/* clear the cookie key */
safe_memset(s->cookie_key, 0, sizeof(s->cookie_key));
safe_memset(s->prev_cookie_key, 0, sizeof(s->prev_cookie_key));
setproctitle(PACKAGE_NAME"-worker");
kill_on_parent_kill(SIGTERM);
@@ -1207,14 +1202,6 @@ int main(int argc, char** argv)
/* Initialize GnuTLS */
tls_global_init(&creds);
/* this is the key used to sign and verify cookies. It is used
* by sec-mod (for signing) and main (for verification). */
ret = gnutls_rnd(GNUTLS_RND_RANDOM, s->cookie_key, sizeof(s->cookie_key));
if (ret < 0) {
fprintf(stderr, "Error in cookie key generation\n");
exit(1);
}
/* load configuration */
ret = cmd_parser(main_pool, argc, argv, &s->perm_config);
if (ret < 0) {

View File

@@ -49,13 +49,7 @@ extern ev_timer maintainance_watcher;
#define MAIN_MAINTAINANCE_TIME (900)
extern sigset_t sig_default_set;
int cmd_parser (void *pool, int argc, char **argv, struct perm_cfg_st** config);
void reload_cfg_file(void *pool, struct perm_cfg_st* config, unsigned archive);
void clear_old_configs(struct perm_cfg_st* config);
void clear_cfg(struct perm_cfg_st* config);
void write_pid_file(void);
void remove_pid_file(void);
struct listener_st {
ev_io io;
@@ -118,7 +112,7 @@ typedef struct proc_st {
struct sockaddr_storage our_addr; /* our address */
socklen_t our_addr_len;
/* The SID present in the cookie. Used for session control only */
/* The SID which acts as a cookie */
uint8_t sid[SID_SIZE];
unsigned active_sid;
@@ -193,11 +187,6 @@ typedef struct main_server_st {
tls_st *creds;
uint8_t cookie_key[COOKIE_KEY_SIZE];
/* when we rotate keys, this is the previous one active for verification */
uint8_t prev_cookie_key[COOKIE_KEY_SIZE];
unsigned prev_cookie_key_active;
struct listen_list_st listen_list;
struct proc_list_st proc_list;
struct script_list_st script_list;

View File

@@ -402,12 +402,6 @@ ban-reset-time = 300
# between different networks.
cookie-timeout = 300
# Cookie rekey time (in seconds)
# The time after which the key used to encrypt cookies will be
# refreshed. After this time the previous key will also be valid
# for verification until the next rotation cycle.
cookie-rekey-time = 259200
# If this is enabled (not recommended) the cookies will stay
# valid even after a user manually disconnects, and until they
# expire. This may improve roaming with some broken clients.

View File

@@ -39,7 +39,6 @@
#include "str.h"
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <ccan/list/list.h>
@@ -109,42 +108,6 @@ void sec_mod_add_score_to_ip(sec_mod_st *sec, client_entry_st *e, const char *ip
return;
}
static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
{
int ret;
Cookie msg = COOKIE__INIT;
msg.username = entry->acct_info.username;
msg.groupname = entry->acct_info.groupname;
msg.hostname = entry->hostname;
msg.ip = entry->acct_info.remote_ip;
msg.tls_auth_ok = entry->tls_auth_ok;
/* Fixme: possibly we should allow for completely random seeds */
if (sec->config->predictable_ips != 0) {
msg.ipv4_seed = hash_any(entry->acct_info.username, strlen(entry->acct_info.username), 0);
} else {
ret = gnutls_rnd(GNUTLS_RND_NONCE, &msg.ipv4_seed, sizeof(msg.ipv4_seed));
if (ret < 0)
return -1;
}
msg.sid.data = entry->sid;
msg.sid.len = sizeof(entry->sid);
/* this is the time when this cookie must be activated (used to authenticate).
* if not activated by that time it expires */
msg.expiration = time(0) + sec->config->cookie_timeout;
ret =
encrypt_cookie(entry, &sec->dcookie_key, &msg, &entry->cookie,
&entry->cookie_size);
if (ret < 0)
return -1;
return 0;
}
static
int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
{
@@ -153,16 +116,7 @@ int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTH
if (r == AUTH__REP__OK) {
/* fill message */
ret = generate_cookie(sec, entry);
if (ret < 0) {
seclog(sec, LOG_INFO, "cannot generate cookie");
return ret;
}
msg.reply = AUTH__REP__OK;
msg.has_cookie = 1;
msg.cookie.data = entry->cookie;
msg.cookie.len = entry->cookie_size;
msg.user_name = entry->acct_info.username;
@@ -437,13 +391,6 @@ int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMs
return send_failed_session_open_reply(sec, fd);
}
if (req->has_cookie == 0 || (req->cookie.len != e->cookie_size) ||
memcmp(req->cookie.data, e->cookie, e->cookie_size) != 0) {
seclog(sec, LOG_ERR, "cookie error; denied session for user '%s' "SESSION_STR, e->acct_info.username, e->acct_info.psid);
e->status = PS_AUTH_FAILED;
return send_failed_session_open_reply(sec, fd);
}
if (req->ipv4)
strlcpy(e->acct_info.ipv4, req->ipv4, sizeof(e->acct_info.ipv4));
if (req->ipv6)
@@ -460,6 +407,24 @@ int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMs
}
}
rep.username = e->acct_info.username;
rep.groupname = e->acct_info.groupname;
rep.hostname = e->hostname;
rep.ip = e->acct_info.remote_ip;
rep.tls_auth_ok = e->tls_auth_ok;
/* Fixme: possibly we should allow for completely random seeds */
if (sec->config->predictable_ips != 0) {
rep.ipv4_seed = hash_any(e->acct_info.username, strlen(e->acct_info.username), 0);
} else {
ret = gnutls_rnd(GNUTLS_RND_NONCE, &rep.ipv4_seed, sizeof(rep.ipv4_seed));
if (ret < 0)
return -1;
}
rep.sid.data = e->sid;
rep.sid.len = sizeof(e->sid);
rep.reply = AUTH__REP__OK;
lpool = talloc_new(e);

View File

@@ -22,7 +22,6 @@
#include <string.h>
#include <unistd.h>
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <main.h>
#include <common.h>

View File

@@ -180,24 +180,6 @@ int load_pins(struct perm_cfg_st *config, struct pin_st *s)
return 0;
}
static int send_refresh_cookie_key(sec_mod_st * sec, void *key_data, unsigned key_size)
{
SecRefreshCookieKey msg = SEC_REFRESH_COOKIE_KEY__INIT;
int ret;
msg.key.data = key_data;
msg.key.len = key_size;
ret = send_msg16(sec, sec->cmd_fd, SM_CMD_REFRESH_COOKIE_KEY, &msg,
(pack_size_func) sec_refresh_cookie_key__get_packed_size,
(pack_func) sec_refresh_cookie_key__pack);
if (ret < 0) {
seclog(sec, LOG_WARNING, "sec-mod error in sending cookie key");
}
return 0;
}
static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_t * rep,
size_t rep_size)
{
@@ -501,8 +483,6 @@ static void handle_sigterm(int signo)
static void check_other_work(sec_mod_st *sec)
{
time_t now = time(0);
if (need_exit) {
unsigned i;
@@ -516,23 +496,6 @@ static void check_other_work(sec_mod_st *sec)
exit(0);
}
if (sec->config->cookie_rekey_time > 0 && now - sec->cookie_key_last_update > sec->config->cookie_rekey_time) {
uint8_t cookie_key[COOKIE_KEY_SIZE];
int ret;
ret = gnutls_rnd(GNUTLS_RND_RANDOM, cookie_key, sizeof(cookie_key));
if (ret >= 0) {
if (send_refresh_cookie_key(sec, cookie_key, sizeof(cookie_key)) == 0) {
sec->cookie_key_last_update = now;
memcpy(sec->cookie_key, cookie_key, sizeof(cookie_key));
} else {
seclog(sec, LOG_ERR, "could not notify main for new cookie key");
}
} else {
seclog(sec, LOG_ERR, "could not refresh cookie key");
}
}
if (need_reload) {
seclog(sec, LOG_DEBUG, "reloading configuration");
reload_cfg_file(sec, sec->perm_config, 0);
@@ -777,7 +740,7 @@ static int load_keys(sec_mod_st *sec, unsigned force)
* key operations.
*/
void sec_mod_server(void *main_pool, struct perm_cfg_st *perm_config, const char *socket_file,
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd, int cmd_fd_sync)
int cmd_fd, int cmd_fd_sync)
{
struct sockaddr_un sa;
socklen_t sa_len;
@@ -819,11 +782,6 @@ void sec_mod_server(void *main_pool, struct perm_cfg_st *perm_config, const char
exit(1);
}
memcpy(sec->cookie_key, cookie_key, COOKIE_KEY_SIZE);
sec->cookie_key_last_update = time(0);
sec->dcookie_key.data = sec->cookie_key;
sec->dcookie_key.size = COOKIE_KEY_SIZE;
sec->perm_config = talloc_steal(sec, perm_config);
sec->config = sec->perm_config->config;

View File

@@ -21,18 +21,14 @@
#ifndef SEC_MOD_H
# define SEC_MOD_H
#include <cookies.h>
#include <gnutls/abstract.h>
#include <ccan/htable/htable.h>
#include <nettle/base64.h>
#include <tlslib.h>
#define SESSION_STR "(session: %.5s)"
typedef struct sec_mod_st {
gnutls_datum_t dcookie_key; /* the key to generate cookies */
uint8_t cookie_key[COOKIE_KEY_SIZE];
time_t cookie_key_last_update;
struct cfg_st *config;
struct perm_cfg_st *perm_config;
gnutls_privkey_t *key;
@@ -94,8 +90,6 @@ typedef struct client_entry_st {
unsigned status; /* PS_AUTH_ */
char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */
uint8_t *cookie; /* the cookie associated with the session */
unsigned cookie_size;
uint8_t dtls_session_id[GNUTLS_MAX_SESSION_ID];
@@ -146,6 +140,6 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req);
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e);
void sec_mod_server(void *main_pool, struct perm_cfg_st *config, const char *socket_file,
uint8_t cookie_key[COOKIE_KEY_SIZE], int cmd_fd, int cmd_fd_sync);
int cmd_fd, int cmd_fd_sync);
#endif

View File

@@ -104,6 +104,9 @@ inline static const char *proto_to_str(fw_proto_t proto)
#define MIN_NO_COMPRESS_LIMIT 64
#define DEFAULT_NO_COMPRESS_LIMIT 256
/* The time after a disconnection the cookie is valid */
#define DEFAULT_COOKIE_RECON_TIMEOUT 120
/* Timeout (secs) for communication between main and sec-mod */
#define MAIN_SEC_MOD_TIMEOUT 120
@@ -210,7 +213,6 @@ typedef enum {
SM_CMD_AUTH_BAN_IP,
SM_CMD_AUTH_BAN_IP_REPLY,
SM_CMD_AUTH_CLI_STATS,
SM_CMD_REFRESH_COOKIE_KEY,
MAX_SM_MAIN_CMD,
} cmd_request_t;
@@ -314,7 +316,6 @@ struct cfg_st {
unsigned restrict_user_to_routes; /* whether the firewall script will be run for the user */
unsigned deny_roaming; /* whether a cookie is restricted to a single IP */
time_t cookie_timeout; /* in seconds */
time_t cookie_rekey_time; /* in seconds */
time_t session_timeout; /* in seconds */
unsigned persistent_cookies; /* whether cookies stay valid after disconnect */
@@ -478,4 +479,12 @@ enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_
#include <ip-util.h>
void reload_cfg_file(void *pool, struct perm_cfg_st* config, unsigned archive);
void clear_old_configs(struct perm_cfg_st* config);
void clear_cfg(struct perm_cfg_st* config);
void write_pid_file(void);
void remove_pid_file(void);
extern sigset_t sig_default_set;
#endif

View File

@@ -39,7 +39,6 @@
#include <vpn.h>
#include "html.h"
#include <worker.h>
#include <cookies.h>
#include <common.h>
#include <tlslib.h>
@@ -720,19 +719,17 @@ static int recv_auth_reply(worker_st * ws, int sd, char **txt, unsigned *pcounte
ws->sid_set = 1;
}
if (msg->has_cookie == 0 ||
msg->cookie.len == 0 ||
if (msg->has_sid == 0 ||
msg->sid.len != sizeof(ws->cookie) ||
msg->dtls_session_id.len != sizeof(ws->session_id)) {
ret = ERR_AUTH_FAIL;
goto cleanup;
}
ws->cookie = talloc_memdup(ws, msg->cookie.data, msg->cookie.len);
if (ws->cookie) {
ws->cookie_size = msg->cookie.len;
ws->cookie_set = 1;
}
memcpy(ws->cookie, msg->sid.data, msg->sid.len);
ws->cookie_set = 1;
memcpy(ws->session_id, msg->dtls_session_id.data,
msg->dtls_session_id.len);
@@ -813,7 +810,7 @@ void cookie_authenticate_or_exit(worker_st *ws)
/* we have authenticated against sec-mod, we need to complete
* our authentication by forwarding our cookie to main. */
ret = auth_cookie(ws, ws->cookie, ws->cookie_size);
ret = auth_cookie(ws, ws->cookie, sizeof(ws->cookie));
if (ret < 0) {
oclog(ws, LOG_WARNING, "failed cookie authentication attempt");
if (ret == ERR_AUTH_FAIL) {
@@ -880,7 +877,7 @@ int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
{
int ret, size;
char str_cookie[BASE64_ENCODE_RAW_LENGTH(ws->cookie_size)+1];
char str_cookie[BASE64_ENCODE_RAW_LENGTH(sizeof(ws->cookie))+1];
size_t str_cookie_size = sizeof(str_cookie);
char msg[MAX_BANNER_SIZE + 32];
const char *success_msg_head;
@@ -900,7 +897,7 @@ int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
success_msg_foot_size = sizeof(oc_success_msg_foot)-1;
}
oc_base64_encode((char *)ws->cookie, ws->cookie_size,
oc_base64_encode((char *)ws->cookie, sizeof(ws->cookie),
(char *)str_cookie, str_cookie_size);
/* reply */

View File

@@ -36,7 +36,6 @@
#include <vpn.h>
#include <worker.h>
#include <cookies.h>
#include <tlslib.h>
#define HTML_404 "<html><body><h1>404 Not Found</h1></body></html>\r\n"

View File

@@ -370,21 +370,26 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
tmplen--;
}
/* we allow for BASE64_DECODE_LENGTH reporting few bytes more
* than the expected */
nlen = BASE64_DECODE_LENGTH(tmplen);
ws->cookie = talloc_size(ws, nlen);
if (ws->cookie == NULL)
if (nlen < sizeof(ws->cookie) || nlen > sizeof(ws->cookie)+8)
return;
/* we assume that - should be build time optimized */
if (sizeof(ws->buffer) < sizeof(ws->cookie)+8)
abort();
ret =
oc_base64_decode((uint8_t*)p, tmplen,
ws->cookie, &nlen);
if (ret == 0) {
oclog(ws, LOG_DEBUG,
ws->buffer, &nlen);
if (ret == 0 || nlen != sizeof(ws->cookie)) {
oclog(ws, LOG_INFO,
"could not decode cookie: %.*s",
tmplen, p);
ws->cookie_set = 0;
} else {
ws->cookie_size = nlen;
memcpy(ws->cookie, ws->buffer, sizeof(ws->cookie));
ws->auth_state = S_AUTH_COOKIE;
ws->cookie_set = 1;
}

View File

@@ -40,7 +40,6 @@
#include <vpn.h>
#include <worker.h>
#include <cookies.h>
#include <tlslib.h>
#ifdef HAVE_SIGALTSTACK

View File

@@ -37,7 +37,6 @@
#include <worker.h>
#include "common.h"
#include "ipc.pb-c.h"
#include <cookies.h>
#include <tlslib.h>

View File

@@ -54,7 +54,6 @@
#include <vpn.h>
#include "ipc.pb-c.h"
#include <cookies.h>
#include <worker.h>
#include <tlslib.h>

View File

@@ -29,7 +29,6 @@
#include <unistd.h>
#include <net/if.h>
#include <vpn.h>
#include <cookies.h>
#include <tlslib.h>
#include <common.h>
#include <str.h>
@@ -253,8 +252,7 @@ typedef struct worker_st {
unsigned cert_groups_size;
char hostname[MAX_HOSTNAME_SIZE];
uint8_t *cookie;
unsigned cookie_size;
uint8_t cookie[SID_SIZE];
unsigned int cookie_set;