Files
ocserv/src/cookies.c
T
Nikos Mavrogiannopoulos b1af6f2829 enabling cisco-client-compat allows 'stealing' of processes.
This change puts a proc_st that its client has terminated to a "zombie"
state. That state will allow a client that connects later using the
same TLS session ID to reclaim it. That way clients that try to authenticate
by sending their credentials in different sessions can still authenticate with
ocserv. That however puts more trust to worker processes (as the main
process has no way of telling whether a TLS session is certainly
resumed).
2014-01-18 15:06:10 +01:00

154 lines
3.6 KiB
C

/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* 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 <ip-lease.h>
#include <main.h>
#include <cookies.h>
int decrypt_cookie(main_server_st * s, const uint8_t* cookie, unsigned cookie_size,
struct stored_cookie_st* sc)
{
gnutls_datum_t iv = { (void*)cookie, COOKIE_IV_SIZE };
int ret;
uint8_t tag[COOKIE_MAC_SIZE];
gnutls_cipher_hd_t h;
gnutls_datum_t key = { (void*)s->cookie_key, sizeof(s->cookie_key) };
if (cookie_size != COOKIE_SIZE)
return -1;
ret = gnutls_cipher_init(&h, GNUTLS_CIPHER_AES_128_GCM, &key, &iv);
if (ret < 0)
return -1;
cookie += COOKIE_IV_SIZE;
ret = gnutls_cipher_decrypt2(h, cookie, sizeof(*sc), sc, sizeof(*sc));
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = gnutls_cipher_tag(h, tag, sizeof(tag));
if (ret < 0) {
ret = -1;
goto cleanup;
}
cookie += sizeof(*sc);
if (memcmp(tag, cookie, COOKIE_MAC_SIZE) != 0) {
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
gnutls_cipher_deinit(h);
return ret;
}
int encrypt_cookie(main_server_st * s, const struct stored_cookie_st* sc,
uint8_t* cookie, unsigned cookie_size)
{
uint8_t _iv[COOKIE_IV_SIZE];
gnutls_cipher_hd_t h;
gnutls_datum_t iv = { _iv, sizeof(_iv) };
gnutls_datum_t key = { (void*)s->cookie_key, sizeof(s->cookie_key) };
int ret;
if (cookie_size != COOKIE_SIZE)
return -1;
ret = gnutls_rnd(GNUTLS_RND_NONCE, _iv, sizeof(_iv));
if (ret < 0)
return -1;
ret = gnutls_cipher_init(&h, GNUTLS_CIPHER_AES_128_GCM, &key, &iv);
if (ret < 0)
return -1;
memcpy(cookie, _iv, COOKIE_IV_SIZE);
cookie += COOKIE_IV_SIZE;
ret = gnutls_cipher_encrypt2(h, sc, sizeof(*sc), cookie, sizeof(*sc));
if (ret < 0) {
ret = -1;
goto cleanup;
}
cookie += sizeof(*sc);
ret = gnutls_cipher_tag(h, cookie, COOKIE_MAC_SIZE);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
gnutls_cipher_deinit(h);
return ret;
}
int generate_cookie(main_server_st *s, struct proc_st* proc)
{
int ret;
struct stored_cookie_st sc;
ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->dtls_session_id, sizeof(proc->dtls_session_id));
if (ret < 0)
return -1;
proc->dtls_session_id_size = sizeof(proc->dtls_session_id);
memcpy(sc.username, proc->username, sizeof(proc->username));
memcpy(sc.groupname, proc->groupname, sizeof(proc->groupname));
memcpy(sc.hostname, proc->hostname, sizeof(proc->hostname));
memcpy(sc.session_id, proc->dtls_session_id, sizeof(proc->dtls_session_id));
sc.expiration = time(0) + s->config->cookie_validity;
memcpy(sc.ipv4_seed, SA_IN_U8_P(&proc->ipv4->lip), 4);
ret = encrypt_cookie(s, &sc, proc->cookie, sizeof(proc->cookie));
if (ret < 0)
return -1;
return 0;
}