summaryrefslogtreecommitdiffstats
path: root/lib/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/db.c')
-rw-r--r--lib/db.c417
1 files changed, 417 insertions, 0 deletions
diff --git a/lib/db.c b/lib/db.c
new file mode 100644
index 0000000..4ff7612
--- /dev/null
+++ b/lib/db.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * 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 <https://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains functions that manipulate a database backend for
+ * resumed sessions.
+ */
+
+#include "gnutls_int.h"
+#include "errors.h"
+#include <db.h>
+#include <session_pack.h>
+#include <datum.h>
+#include "ext/server_name.h"
+#include <intprops.h>
+
+/**
+ * gnutls_db_set_retrieve_function:
+ * @session: is a #gnutls_session_t type.
+ * @retr_func: is the function.
+ *
+ * Sets the function that will be used to retrieve data from the
+ * resumed sessions database. This function must return a
+ * gnutls_datum_t containing the data on success, or a gnutls_datum_t
+ * containing null and 0 on failure.
+ *
+ * The datum's data must be allocated using the function
+ * gnutls_malloc().
+ *
+ * The first argument to @retr_func will be null unless
+ * gnutls_db_set_ptr() has been called.
+ **/
+void
+gnutls_db_set_retrieve_function(gnutls_session_t session,
+ gnutls_db_retr_func retr_func)
+{
+ session->internals.db_retrieve_func = retr_func;
+}
+
+/**
+ * gnutls_db_set_remove_function:
+ * @session: is a #gnutls_session_t type.
+ * @rem_func: is the function.
+ *
+ * Sets the function that will be used to remove data from the
+ * resumed sessions database. This function must return 0 on success.
+ *
+ * The first argument to @rem_func will be null unless
+ * gnutls_db_set_ptr() has been called.
+ **/
+void
+gnutls_db_set_remove_function(gnutls_session_t session,
+ gnutls_db_remove_func rem_func)
+{
+ session->internals.db_remove_func = rem_func;
+}
+
+/**
+ * gnutls_db_set_store_function:
+ * @session: is a #gnutls_session_t type.
+ * @store_func: is the function
+ *
+ * Sets the function that will be used to store data in the resumed
+ * sessions database. This function must return 0 on success.
+ *
+ * The first argument to @store_func will be null unless
+ * gnutls_db_set_ptr() has been called.
+ **/
+void
+gnutls_db_set_store_function(gnutls_session_t session,
+ gnutls_db_store_func store_func)
+{
+ session->internals.db_store_func = store_func;
+}
+
+/**
+ * gnutls_db_set_ptr:
+ * @session: is a #gnutls_session_t type.
+ * @ptr: is the pointer
+ *
+ * Sets the pointer that will be provided to db store, retrieve and
+ * delete functions, as the first argument.
+ **/
+void gnutls_db_set_ptr(gnutls_session_t session, void *ptr)
+{
+ session->internals.db_ptr = ptr;
+}
+
+/**
+ * gnutls_db_get_ptr:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Get db function pointer.
+ *
+ * Returns: the pointer that will be sent to db store, retrieve and
+ * delete functions, as the first argument.
+ **/
+void *gnutls_db_get_ptr(gnutls_session_t session)
+{
+ return session->internals.db_ptr;
+}
+
+/**
+ * gnutls_db_set_cache_expiration:
+ * @session: is a #gnutls_session_t type.
+ * @seconds: is the number of seconds.
+ *
+ * Set the expiration time for resumed sessions. The default is 21600
+ * (6 hours) at the time of writing.
+ *
+ * The maximum value that can be set using this function is 604800
+ * (7 days).
+ *
+ **/
+void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds)
+{
+ session->internals.expire_time = seconds;
+ if (session->internals.expire_time > 604800)
+ session->internals.expire_time = 604800;
+}
+
+/**
+ * gnutls_db_get_default_cache_expiration:
+ *
+ * Returns the expiration time (in seconds) of stored sessions for resumption.
+ **/
+unsigned gnutls_db_get_default_cache_expiration(void)
+{
+ return DEFAULT_EXPIRE_TIME;
+}
+
+/**
+ * gnutls_db_check_entry:
+ * @session: is a #gnutls_session_t type.
+ * @session_entry: is the session data (not key)
+ *
+ * This function has no effect.
+ *
+ * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
+ * expired or 0 otherwise.
+ *
+ * Deprecated: This function is deprecated.
+ **/
+int
+gnutls_db_check_entry(gnutls_session_t session,
+ gnutls_datum_t session_entry)
+{
+ return 0;
+}
+
+/**
+ * gnutls_db_check_entry_time:
+ * @entry: is a pointer to a #gnutls_datum_t type.
+ *
+ * This function returns the time that this entry was active.
+ * It can be used for database entry expiration.
+ *
+ * Returns: The time this entry was created, or zero on error.
+ **/
+time_t gnutls_db_check_entry_time(gnutls_datum_t * entry)
+{
+ uint32_t t;
+ uint32_t magic;
+
+ if (entry->size < 8)
+ return gnutls_assert_val(0);
+
+ magic = _gnutls_read_uint32(entry->data);
+
+ if (magic != PACKED_SESSION_MAGIC)
+ return gnutls_assert_val(0);
+
+ t = _gnutls_read_uint32(&entry->data[4]);
+
+ return t;
+}
+
+/**
+ * gnutls_db_check_entry_expire_time:
+ * @entry: is a pointer to a #gnutls_datum_t type.
+ *
+ * This function returns the time that this entry will expire.
+ * It can be used for database entry expiration.
+ *
+ * Returns: The time this entry will expire, or zero on error.
+ *
+ * Since: 3.6.5
+ **/
+time_t gnutls_db_check_entry_expire_time(gnutls_datum_t *entry)
+{
+ uint32_t t;
+ uint32_t e;
+ uint32_t magic;
+
+ if (entry->size < 12)
+ return gnutls_assert_val(0);
+
+ magic = _gnutls_read_uint32(entry->data);
+
+ if (magic != PACKED_SESSION_MAGIC)
+ return gnutls_assert_val(0);
+
+ t = _gnutls_read_uint32(&entry->data[4]);
+ e = _gnutls_read_uint32(&entry->data[8]);
+
+ if (INT_ADD_OVERFLOW(t, e))
+ return gnutls_assert_val(0);
+
+ return t + e;
+}
+
+/* Checks if both db_store and db_retrieve functions have
+ * been set up.
+ */
+static int db_func_is_ok(gnutls_session_t session)
+{
+ if (session->internals.db_store_func != NULL &&
+ session->internals.db_retrieve_func != NULL)
+ return 0;
+ else
+ return GNUTLS_E_DB_ERROR;
+}
+
+/* Stores session data to the db backend.
+ */
+static int
+store_session(gnutls_session_t session,
+ gnutls_datum_t session_id, gnutls_datum_t session_data)
+{
+ int ret = 0;
+
+ if (db_func_is_ok(session) != 0) {
+ return GNUTLS_E_DB_ERROR;
+ }
+
+ if (session_data.data == NULL || session_data.size == 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_SESSION;
+ }
+
+ /* if we can't read why bother writing? */
+ ret = session->internals.db_store_func(session->internals.db_ptr,
+ session_id, session_data);
+
+ return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
+}
+
+int _gnutls_server_register_current_session(gnutls_session_t session)
+{
+ gnutls_datum_t key;
+ gnutls_datum_t content;
+ int ret = 0;
+
+ key.data = session->security_parameters.session_id;
+ key.size = session->security_parameters.session_id_size;
+
+ if (!session->internals.resumable) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_SESSION;
+ }
+
+ if (session->security_parameters.session_id_size == 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_SESSION;
+ }
+
+ ret = _gnutls_session_pack(session, &content);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = store_session(session, key, content);
+ _gnutls_free_datum(&content);
+
+ return ret;
+}
+
+int _gnutls_check_resumed_params(gnutls_session_t session)
+{
+ time_t timestamp = gnutls_time(0);
+ const version_entry_st *vers;
+
+ /* check whether the session is expired */
+ if (timestamp -
+ session->internals.resumed_security_parameters.timestamp >
+ session->internals.expire_time
+ || session->internals.resumed_security_parameters.timestamp >
+ timestamp)
+ return gnutls_assert_val(GNUTLS_E_EXPIRED);
+
+ /* check various parameters applicable to resumption in TLS1.2 or earlier
+ */
+ vers = get_version(session);
+ if (!vers || !vers->tls13_sem) {
+ if (session->internals.resumed_security_parameters.ext_master_secret !=
+ session->security_parameters.ext_master_secret)
+ return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
+
+ if (!_gnutls_server_name_matches_resumed(session))
+ return gnutls_assert_val(GNUTLS_E_INVALID_SESSION);
+ }
+
+ return 0;
+}
+
+int
+_gnutls_server_restore_session(gnutls_session_t session,
+ uint8_t * session_id, int session_id_size)
+{
+ gnutls_datum_t data;
+ gnutls_datum_t key;
+ int ret;
+
+ if (session_id == NULL || session_id_size == 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (session->internals.premaster_set != 0) { /* hack for CISCO's DTLS-0.9 */
+ if (session_id_size ==
+ session->internals.resumed_security_parameters.
+ session_id_size
+ && memcmp(session_id,
+ session->internals.
+ resumed_security_parameters.session_id,
+ session_id_size) == 0)
+ return 0;
+ }
+
+ key.data = session_id;
+ key.size = session_id_size;
+
+ if (db_func_is_ok(session) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_SESSION;
+ }
+
+ data =
+ session->internals.db_retrieve_func(session->internals.db_ptr,
+ key);
+
+ if (data.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_SESSION;
+ }
+
+ ret = gnutls_session_set_data(session, data.data, data.size);
+ gnutls_free(data.data);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* expiration check is performed inside */
+ ret = _gnutls_check_resumed_params(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
+/**
+ * gnutls_db_remove_session:
+ * @session: is a #gnutls_session_t type.
+ *
+ * This function will remove the current session data from the
+ * session database. This will prevent future handshakes reusing
+ * these session data. This function should be called if a session
+ * was terminated abnormally, and before gnutls_deinit() is called.
+ *
+ * Normally gnutls_deinit() will remove abnormally terminated
+ * sessions.
+ **/
+void gnutls_db_remove_session(gnutls_session_t session)
+{
+ gnutls_datum_t session_id;
+ int ret = 0;
+
+ session_id.data = session->security_parameters.session_id;
+ session_id.size = session->security_parameters.session_id_size;
+
+ if (session->internals.db_remove_func == NULL) {
+ gnutls_assert();
+ return /* GNUTLS_E_DB_ERROR */ ;
+ }
+
+ if (session_id.data == NULL || session_id.size == 0) {
+ gnutls_assert();
+ return /* GNUTLS_E_INVALID_SESSION */ ;
+ }
+
+ /* if we can't read why bother writing? */
+ ret = session->internals.db_remove_func(session->internals.db_ptr,
+ session_id);
+ if (ret != 0)
+ gnutls_assert();
+}