Blame lib/db.c

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