|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Author: Nikos Mavrogiannopoulos
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This file is part of GnuTLS.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
549fdc |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
549fdc |
* the License, or (at your option) any later version.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
549fdc |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
549fdc |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
549fdc |
* Lesser General Public License for more details.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* This file contains functions that manipulate a database backend for
|
|
Packit |
549fdc |
* resumed sessions.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#include "gnutls_int.h"
|
|
Packit |
549fdc |
#include "errors.h"
|
|
Packit |
549fdc |
#include <db.h>
|
|
Packit |
549fdc |
#include <session_pack.h>
|
|
Packit |
549fdc |
#include <datum.h>
|
|
Packit |
549fdc |
#include "ext/server_name.h"
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_set_retrieve_function:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @retr_func: is the function.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Sets the function that will be used to retrieve data from the
|
|
Packit |
549fdc |
* resumed sessions database. This function must return a
|
|
Packit |
549fdc |
* gnutls_datum_t containing the data on success, or a gnutls_datum_t
|
|
Packit |
549fdc |
* containing null and 0 on failure.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The datum's data must be allocated using the function
|
|
Packit |
549fdc |
* gnutls_malloc().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The first argument to @retr_func will be null unless
|
|
Packit |
549fdc |
* gnutls_db_set_ptr() has been called.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
gnutls_db_set_retrieve_function(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_db_retr_func retr_func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
session->internals.db_retrieve_func = retr_func;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_set_remove_function:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @rem_func: is the function.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Sets the function that will be used to remove data from the
|
|
Packit |
549fdc |
* resumed sessions database. This function must return 0 on success.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The first argument to @rem_func will be null unless
|
|
Packit |
549fdc |
* gnutls_db_set_ptr() has been called.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
gnutls_db_set_remove_function(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_db_remove_func rem_func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
session->internals.db_remove_func = rem_func;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_set_store_function:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @store_func: is the function
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Sets the function that will be used to store data in the resumed
|
|
Packit |
549fdc |
* sessions database. This function must return 0 on success.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The first argument to @store_func will be null unless
|
|
Packit |
549fdc |
* gnutls_db_set_ptr() has been called.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
gnutls_db_set_store_function(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_db_store_func store_func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
session->internals.db_store_func = store_func;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_set_ptr:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @ptr: is the pointer
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Sets the pointer that will be provided to db store, retrieve and
|
|
Packit |
549fdc |
* delete functions, as the first argument.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void gnutls_db_set_ptr(gnutls_session_t session, void *ptr)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
session->internals.db_ptr = ptr;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_get_ptr:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Get db function pointer.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: the pointer that will be sent to db store, retrieve and
|
|
Packit |
549fdc |
* delete functions, as the first argument.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void *gnutls_db_get_ptr(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return session->internals.db_ptr;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_set_cache_expiration:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @seconds: is the number of seconds.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Set the expiration time for resumed sessions. The default is 3600
|
|
Packit |
549fdc |
* (one hour) at the time of this writing.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
session->internals.expire_time = seconds;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_get_default_cache_expiration:
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns the expiration time (in seconds) of stored sessions for resumption.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
unsigned gnutls_db_get_default_cache_expiration(void)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return DEFAULT_EXPIRE_TIME;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_check_entry:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
* @session_entry: is the session data (not key)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function has no effect.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
|
|
Packit |
549fdc |
* expired or 0 otherwise.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_db_check_entry(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_datum_t session_entry)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_check_entry_time:
|
|
Packit |
549fdc |
* @entry: is a pointer to a #gnutls_datum_t type.
|
|
Packit |
549fdc |
* @t: is the time of the session handshake
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function returns the time that this entry was active.
|
|
Packit |
549fdc |
* It can be used for database entry expiration.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: The time this entry was created, or zero on error.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
time_t gnutls_db_check_entry_time(gnutls_datum_t * entry)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
uint32_t t;
|
|
Packit |
549fdc |
uint32_t magic;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (entry->size < 8)
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
magic = _gnutls_read_uint32(entry->data);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (magic != PACKED_SESSION_MAGIC)
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
t = _gnutls_read_uint32(&entry->data[4]);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return t;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if both db_store and db_retrieve functions have
|
|
Packit |
549fdc |
* been set up.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static int db_func_is_ok(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (session->internals.db_store_func != NULL &&
|
|
Packit |
549fdc |
session->internals.db_retrieve_func != NULL)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
return GNUTLS_E_DB_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Stores session data to the db backend.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static int
|
|
Packit |
549fdc |
store_session(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_datum_t session_id, gnutls_datum_t session_data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int ret = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (db_func_is_ok(session) != 0) {
|
|
Packit |
549fdc |
return GNUTLS_E_DB_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session_data.data == NULL || session_data.size == 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_SESSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* if we can't read why bother writing? */
|
|
Packit |
549fdc |
ret = session->internals.db_store_func(session->internals.db_ptr,
|
|
Packit |
549fdc |
session_id, session_data);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int _gnutls_server_register_current_session(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_datum_t key;
|
|
Packit |
549fdc |
gnutls_datum_t content;
|
|
Packit |
549fdc |
int ret = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
key.data = session->security_parameters.session_id;
|
|
Packit |
549fdc |
key.size = session->security_parameters.session_id_size;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.resumable == RESUME_FALSE) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_SESSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->security_parameters.session_id_size == 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_SESSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_session_pack(session, &content);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = store_session(session, key, content);
|
|
Packit |
549fdc |
_gnutls_free_datum(&content);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int _gnutls_check_resumed_params(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (session->internals.resumed_security_parameters.ext_master_secret !=
|
|
Packit |
549fdc |
session->security_parameters.ext_master_secret)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (!_gnutls_server_name_matches_resumed(session))
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_server_restore_session(gnutls_session_t session,
|
|
Packit |
549fdc |
uint8_t * session_id, int session_id_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_datum_t data;
|
|
Packit |
549fdc |
gnutls_datum_t key;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session_id == NULL || session_id_size == 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.premaster_set != 0) { /* hack for CISCO's DTLS-0.9 */
|
|
Packit |
549fdc |
if (session_id_size ==
|
|
Packit |
549fdc |
session->internals.resumed_security_parameters.
|
|
Packit |
549fdc |
session_id_size
|
|
Packit |
549fdc |
&& memcmp(session_id,
|
|
Packit |
549fdc |
session->internals.
|
|
Packit |
549fdc |
resumed_security_parameters.session_id,
|
|
Packit |
549fdc |
session_id_size) == 0)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
key.data = session_id;
|
|
Packit |
549fdc |
key.size = session_id_size;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (db_func_is_ok(session) != 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_SESSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
data =
|
|
Packit |
549fdc |
session->internals.db_retrieve_func(session->internals.db_ptr,
|
|
Packit |
549fdc |
key);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (data.data == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_SESSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* expiration check is performed inside */
|
|
Packit |
549fdc |
ret = gnutls_session_set_data(session, data.data, data.size);
|
|
Packit |
549fdc |
gnutls_free(data.data);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_check_resumed_params(session);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_db_remove_session:
|
|
Packit |
549fdc |
* @session: is a #gnutls_session_t type.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will remove the current session data from the
|
|
Packit |
549fdc |
* session database. This will prevent future handshakes reusing
|
|
Packit |
549fdc |
* these session data. This function should be called if a session
|
|
Packit |
549fdc |
* was terminated abnormally, and before gnutls_deinit() is called.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Normally gnutls_deinit() will remove abnormally terminated
|
|
Packit |
549fdc |
* sessions.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void gnutls_db_remove_session(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_datum_t session_id;
|
|
Packit |
549fdc |
int ret = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
session_id.data = session->security_parameters.session_id;
|
|
Packit |
549fdc |
session_id.size = session->security_parameters.session_id_size;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.db_remove_func == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return /* GNUTLS_E_DB_ERROR */ ;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session_id.data == NULL || session_id.size == 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return /* GNUTLS_E_INVALID_SESSION */ ;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* if we can't read why bother writing? */
|
|
Packit |
549fdc |
ret = session->internals.db_remove_func(session->internals.db_ptr,
|
|
Packit |
549fdc |
session_id);
|
|
Packit |
549fdc |
if (ret != 0)
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
}
|