|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Copyright (C) 2001-2016 Free Software Foundation, Inc.
|
|
Packit |
549fdc |
* Copyright (C) 2015-2017 Red Hat, Inc.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Author: Nikos Mavrogiannopoulos, Simon Josefsson
|
|
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 |
/* Functions that relate to the TLS hello extension parsing.
|
|
Packit |
549fdc |
* Hello extensions are packets appended in the TLS hello packet, and
|
|
Packit |
549fdc |
* allow for extra functionality.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#include "gnutls_int.h"
|
|
Packit |
549fdc |
#include "extensions.h"
|
|
Packit |
549fdc |
#include "errors.h"
|
|
Packit |
549fdc |
#include "ext/max_record.h"
|
|
Packit |
549fdc |
#include <ext/server_name.h>
|
|
Packit |
549fdc |
#include <ext/srp.h>
|
|
Packit |
549fdc |
#include <ext/heartbeat.h>
|
|
Packit |
549fdc |
#include <ext/session_ticket.h>
|
|
Packit |
549fdc |
#include <ext/safe_renegotiation.h>
|
|
Packit |
549fdc |
#include <ext/signature.h>
|
|
Packit |
549fdc |
#include <ext/safe_renegotiation.h>
|
|
Packit |
549fdc |
#include <ext/ecc.h>
|
|
Packit |
549fdc |
#include <ext/status_request.h>
|
|
Packit |
549fdc |
#include <ext/ext_master_secret.h>
|
|
Packit |
549fdc |
#include <ext/srtp.h>
|
|
Packit |
549fdc |
#include <ext/alpn.h>
|
|
Packit |
549fdc |
#include <ext/dumbfw.h>
|
|
Packit |
549fdc |
#include <ext/etm.h>
|
|
Packit |
549fdc |
#include <num.h>
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static void
|
|
Packit |
549fdc |
unset_ext_data(gnutls_session_t session, const struct extension_entry_st *, unsigned idx);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int ext_register(extension_entry_st * mod);
|
|
Packit |
549fdc |
static void unset_resumed_ext_data(gnutls_session_t session, const struct extension_entry_st *, unsigned idx);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static extension_entry_st const *extfunc[MAX_EXT_TYPES+1] = {
|
|
Packit |
549fdc |
&ext_mod_max_record_size,
|
|
Packit |
549fdc |
&ext_mod_ext_master_secret,
|
|
Packit |
549fdc |
&ext_mod_etm,
|
|
Packit |
549fdc |
#ifdef ENABLE_OCSP
|
|
Packit |
549fdc |
&ext_mod_status_request,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
&ext_mod_server_name,
|
|
Packit |
549fdc |
&ext_mod_sr,
|
|
Packit |
549fdc |
#ifdef ENABLE_SRP
|
|
Packit |
549fdc |
&ext_mod_srp,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
#ifdef ENABLE_HEARTBEAT
|
|
Packit |
549fdc |
&ext_mod_heartbeat,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
#ifdef ENABLE_SESSION_TICKETS
|
|
Packit |
549fdc |
&ext_mod_session_ticket,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
&ext_mod_supported_ecc,
|
|
Packit |
549fdc |
&ext_mod_supported_ecc_pf,
|
|
Packit |
549fdc |
&ext_mod_sig,
|
|
Packit |
549fdc |
#ifdef ENABLE_DTLS_SRTP
|
|
Packit |
549fdc |
&ext_mod_srtp,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
#ifdef ENABLE_ALPN
|
|
Packit |
549fdc |
&ext_mod_alpn,
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
/* This must be the last extension registered.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
&ext_mod_dumbfw,
|
|
Packit |
549fdc |
NULL
|
|
Packit |
549fdc |
};
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static const extension_entry_st *
|
|
Packit |
549fdc |
_gnutls_ext_ptr(gnutls_session_t session, uint16_t type, gnutls_ext_parse_type_t parse_type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
const extension_entry_st *e;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i=0;i<session->internals.rexts_size;i++) {
|
|
Packit |
549fdc |
if (session->internals.rexts[i].type == type) {
|
|
Packit |
549fdc |
e = &session->internals.rexts[i];
|
|
Packit |
549fdc |
goto done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++) {
|
|
Packit |
549fdc |
if (extfunc[i]->type == type) {
|
|
Packit |
549fdc |
e = extfunc[i];
|
|
Packit |
549fdc |
goto done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return NULL;
|
|
Packit |
549fdc |
done:
|
|
Packit |
549fdc |
if (parse_type == GNUTLS_EXT_ANY || e->parse_type == parse_type) {
|
|
Packit |
549fdc |
return e;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
return NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_ext_get_name:
|
|
Packit |
549fdc |
* @ext: is a TLS extension numeric ID
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Convert a TLS extension numeric ID to a printable string.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: a pointer to a string that contains the name of the
|
|
Packit |
549fdc |
* specified cipher, or %NULL.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
const char *gnutls_ext_get_name(unsigned int ext)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
size_t i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++)
|
|
Packit |
549fdc |
if (extfunc[i]->type == ext)
|
|
Packit |
549fdc |
return extfunc[i]->name;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if the extension @type provided has been requested
|
|
Packit |
549fdc |
* by us (in client side). In that case it returns zero,
|
|
Packit |
549fdc |
* otherwise a negative error value.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_extension_list_check(gnutls_session_t session, uint16_t type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < session->internals.used_exts_size; i++) {
|
|
Packit |
549fdc |
if (type == session->internals.used_exts[i]->type)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Adds the extension we want to send in the extensions list.
|
|
Packit |
549fdc |
* This list is used in client side to check whether the (later) received
|
|
Packit |
549fdc |
* extensions are the ones we requested.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* In server side, this list is used to ensure we don't send
|
|
Packit |
549fdc |
* extensions that we didn't receive a corresponding value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns zero if failed, non-zero on success.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned _gnutls_extension_list_add(gnutls_session_t session, const struct extension_entry_st *e, unsigned check_dup)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (check_dup) {
|
|
Packit |
549fdc |
for (i=0;i<session->internals.used_exts_size;i++) {
|
|
Packit |
549fdc |
if (session->internals.used_exts[i]->type == e->type)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.used_exts_size < MAX_EXT_TYPES) {
|
|
Packit |
549fdc |
session->internals.used_exts[session->
|
|
Packit |
549fdc |
internals.used_exts_size]
|
|
Packit |
549fdc |
= e;
|
|
Packit |
549fdc |
session->internals.used_exts_size++;
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
_gnutls_handshake_log
|
|
Packit |
549fdc |
("extensions: Increase MAX_EXT_TYPES\n");
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
void _gnutls_extension_list_add_sr(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
_gnutls_extension_list_add(session, &ext_mod_sr, 1);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_parse_extensions(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_ext_parse_type_t parse_type,
|
|
Packit |
549fdc |
const uint8_t * data, int data_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int next, ret;
|
|
Packit |
549fdc |
int pos = 0;
|
|
Packit |
549fdc |
uint16_t type;
|
|
Packit |
549fdc |
const uint8_t *sdata;
|
|
Packit |
549fdc |
const extension_entry_st *ext;
|
|
Packit |
549fdc |
uint16_t size;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (data_size == 0)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
DECR_LENGTH_RET(data_size, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
next = _gnutls_read_uint16(data);
|
|
Packit |
549fdc |
pos += 2;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
DECR_LENGTH_RET(data_size, next, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (next == 0 && data_size == 0) /* field is present, but has zero length? Ignore it. */
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
else if (data_size > 0) /* forbid unaccounted data */
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
do {
|
|
Packit |
549fdc |
DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
type = _gnutls_read_uint16(&data[pos]);
|
|
Packit |
549fdc |
pos += 2;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->security_parameters.entity == GNUTLS_CLIENT) {
|
|
Packit |
549fdc |
if ((ret =
|
|
Packit |
549fdc |
_gnutls_extension_list_check(session, type)) < 0) {
|
|
Packit |
549fdc |
_gnutls_debug_log("EXT[%p]: Received unexpected extension '%s/%d'\n", session,
|
|
Packit |
549fdc |
gnutls_ext_get_name(type), (int)type);
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
DECR_LENGTH_RET(next, 2, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
size = _gnutls_read_uint16(&data[pos]);
|
|
Packit |
549fdc |
pos += 2;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
DECR_LENGTH_RET(next, size, GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
sdata = &data[pos];
|
|
Packit |
549fdc |
pos += size;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, type, parse_type);
|
|
Packit |
549fdc |
if (ext == NULL || ext->recv_func == NULL) {
|
|
Packit |
549fdc |
_gnutls_handshake_log
|
|
Packit |
549fdc |
("EXT[%p]: Ignoring extension '%s/%d'\n", session,
|
|
Packit |
549fdc |
gnutls_ext_get_name(type), type);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
continue;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->security_parameters.entity == GNUTLS_SERVER) {
|
|
Packit |
549fdc |
ret = _gnutls_extension_list_add(session, ext, 1);
|
|
Packit |
549fdc |
if (ret == 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
_gnutls_handshake_log
|
|
Packit |
549fdc |
("EXT[%p]: Parsing extension '%s/%d' (%d bytes)\n",
|
|
Packit |
549fdc |
session, gnutls_ext_get_name(type), type,
|
|
Packit |
549fdc |
size);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if ((ret = ext->recv_func(session, sdata, size)) < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
while (next > 2);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* forbid leftovers */
|
|
Packit |
549fdc |
if (next > 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static
|
|
Packit |
549fdc |
int send_extension(gnutls_session_t session, const extension_entry_st *p,
|
|
Packit |
549fdc |
gnutls_buffer_st *extdata, gnutls_ext_parse_type_t parse_type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int size_pos, appended, ret;
|
|
Packit |
549fdc |
size_t size_prev;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (p->send_func == NULL)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (parse_type != GNUTLS_EXT_ANY
|
|
Packit |
549fdc |
&& p->parse_type != parse_type)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* ensure we don't send something twice (i.e, overriden extensions in
|
|
Packit |
549fdc |
* client), and ensure we are sending only what we received in server. */
|
|
Packit |
549fdc |
ret = _gnutls_extension_list_check(session, p->type);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->security_parameters.entity == GNUTLS_SERVER) {
|
|
Packit |
549fdc |
if (ret < 0) /* not advertized */
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
if (ret == 0) /* already sent */
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_buffer_append_prefix(extdata, 16, p->type);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
size_pos = extdata->length;
|
|
Packit |
549fdc |
ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
size_prev = extdata->length;
|
|
Packit |
549fdc |
ret = p->send_func(session, extdata);
|
|
Packit |
549fdc |
if (ret < 0 && ret != GNUTLS_E_INT_RET_0) {
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* returning GNUTLS_E_INT_RET_0 means to send an empty
|
|
Packit |
549fdc |
* extension of this type.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
appended = extdata->length - size_prev;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (appended > 0 || ret == GNUTLS_E_INT_RET_0) {
|
|
Packit |
549fdc |
if (ret == GNUTLS_E_INT_RET_0)
|
|
Packit |
549fdc |
appended = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* write the real size */
|
|
Packit |
549fdc |
_gnutls_write_uint16(appended,
|
|
Packit |
549fdc |
&extdata->data[size_pos]);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* add this extension to the extension list
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (session->security_parameters.entity == GNUTLS_CLIENT)
|
|
Packit |
549fdc |
_gnutls_extension_list_add(session, p, 0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
_gnutls_handshake_log
|
|
Packit |
549fdc |
("EXT[%p]: Sending extension %s (%d bytes)\n",
|
|
Packit |
549fdc |
session, p->name, appended);
|
|
Packit |
549fdc |
} else if (appended == 0)
|
|
Packit |
549fdc |
extdata->length -= 4; /* reset type and size */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_gen_extensions(gnutls_session_t session,
|
|
Packit |
549fdc |
gnutls_buffer_st * extdata,
|
|
Packit |
549fdc |
gnutls_ext_parse_type_t parse_type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int size;
|
|
Packit |
549fdc |
int pos, ret;
|
|
Packit |
549fdc |
size_t i, init_size = extdata->length;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
pos = extdata->length; /* we will store length later on */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_buffer_append_prefix(extdata, 16, 0);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i=0; i < session->internals.rexts_size; i++) {
|
|
Packit |
549fdc |
ret = send_extension(session, &session->internals.rexts[i], extdata, parse_type);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* send_extension() ensures we don't send duplicates, in case
|
|
Packit |
549fdc |
* of overriden extensions */
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++) {
|
|
Packit |
549fdc |
ret = send_extension(session, extfunc[i], extdata, parse_type);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* remove any initial data, and the size of the header */
|
|
Packit |
549fdc |
size = extdata->length - init_size - 2;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (size > UINT16_MAX) /* sent too many extensions */
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (size > 0)
|
|
Packit |
549fdc |
_gnutls_write_uint16(size, &extdata->data[pos]);
|
|
Packit |
549fdc |
else if (size == 0)
|
|
Packit |
549fdc |
extdata->length -= 2; /* the length bytes */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return size;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Global deinit and init of global extensions */
|
|
Packit |
549fdc |
int _gnutls_ext_init(void)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return GNUTLS_E_SUCCESS;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
void _gnutls_ext_deinit(void)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++) {
|
|
Packit |
549fdc |
if (extfunc[i]->free_struct != 0) {
|
|
Packit |
549fdc |
gnutls_free((void*)extfunc[i]->name);
|
|
Packit |
549fdc |
gnutls_free((void*)extfunc[i]);
|
|
Packit |
549fdc |
extfunc[i] = NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static
|
|
Packit |
549fdc |
int ext_register(extension_entry_st * mod)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
while(extfunc[i] != NULL) {
|
|
Packit |
549fdc |
i++;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (i >= MAX_EXT_TYPES-1) {
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
extfunc[i] = mod;
|
|
Packit |
549fdc |
extfunc[i+1] = NULL;
|
|
Packit |
549fdc |
return GNUTLS_E_SUCCESS;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Packing of extension data (for use in resumption) */
|
|
Packit |
549fdc |
static int pack_extension(gnutls_session_t session, const extension_entry_st *extp,
|
|
Packit |
549fdc |
gnutls_buffer_st *packed)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
int size_offset;
|
|
Packit |
549fdc |
int cur_size;
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t data;
|
|
Packit |
549fdc |
int rval = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_ext_get_session_data(session, extp->type,
|
|
Packit |
549fdc |
&data);
|
|
Packit |
549fdc |
if (ret >= 0 && extp->pack_func != NULL) {
|
|
Packit |
549fdc |
BUFFER_APPEND_NUM(packed, extp->type);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
size_offset = packed->length;
|
|
Packit |
549fdc |
BUFFER_APPEND_NUM(packed, 0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cur_size = packed->length;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = extp->pack_func(data, packed);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
rval = 1;
|
|
Packit |
549fdc |
/* write the actual size */
|
|
Packit |
549fdc |
_gnutls_write_uint32(packed->length - cur_size,
|
|
Packit |
549fdc |
packed->data + size_offset);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return rval;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int _gnutls_ext_pack(gnutls_session_t session, gnutls_buffer_st *packed)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned int i;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
int total_exts_pos;
|
|
Packit |
549fdc |
int exts = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
total_exts_pos = packed->length;
|
|
Packit |
549fdc |
BUFFER_APPEND_NUM(packed, 0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < session->internals.used_exts_size; i++) {
|
|
Packit |
549fdc |
ret = pack_extension(session, session->internals.used_exts[i], packed);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(ret);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ret > 0)
|
|
Packit |
549fdc |
exts++;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
_gnutls_write_uint32(exts, packed->data + total_exts_pos);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static void
|
|
Packit |
549fdc |
_gnutls_ext_set_resumed_session_data(gnutls_session_t session,
|
|
Packit |
549fdc |
uint16_t type,
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
const struct extension_entry_st *ext;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].type == type
|
|
Packit |
549fdc |
|| (!session->internals.ext_data[i].resumed_set && !session->internals.ext_data[i].set)) {
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].resumed_set != 0)
|
|
Packit |
549fdc |
unset_resumed_ext_data(session, ext, i);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
session->internals.ext_data[i].type = type;
|
|
Packit |
549fdc |
session->internals.ext_data[i].resumed_priv = data;
|
|
Packit |
549fdc |
session->internals.ext_data[i].resumed_set = 1;
|
|
Packit |
549fdc |
return;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int _gnutls_ext_unpack(gnutls_session_t session, gnutls_buffer_st * packed)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i, ret;
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t data;
|
|
Packit |
549fdc |
int max_exts = 0;
|
|
Packit |
549fdc |
uint16_t type;
|
|
Packit |
549fdc |
int size_for_type, cur_pos;
|
|
Packit |
549fdc |
const struct extension_entry_st *ext;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
BUFFER_POP_NUM(packed, max_exts);
|
|
Packit |
549fdc |
for (i = 0; i < max_exts; i++) {
|
|
Packit |
549fdc |
BUFFER_POP_NUM(packed, type);
|
|
Packit |
549fdc |
BUFFER_POP_NUM(packed, size_for_type);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cur_pos = packed->length;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY);
|
|
Packit |
549fdc |
if (ext == NULL || ext->unpack_func == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_PARSING_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = ext->unpack_func(packed, &data);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* verify that unpack read the correct bytes */
|
|
Packit |
549fdc |
cur_pos = cur_pos - packed->length;
|
|
Packit |
549fdc |
if (cur_pos /* read length */ != size_for_type) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_PARSING_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
_gnutls_ext_set_resumed_session_data(session, type, data);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
error:
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static void
|
|
Packit |
549fdc |
unset_ext_data(gnutls_session_t session, const struct extension_entry_st *ext, unsigned idx)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (session->internals.ext_data[idx].set == 0)
|
|
Packit |
549fdc |
return;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ext && ext->deinit_func && session->internals.ext_data[idx].priv != NULL)
|
|
Packit |
549fdc |
ext->deinit_func(session->internals.ext_data[idx].priv);
|
|
Packit |
549fdc |
session->internals.ext_data[idx].set = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
_gnutls_ext_unset_session_data(gnutls_session_t session,
|
|
Packit |
549fdc |
uint16_t type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
const struct extension_entry_st *ext;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].type == type) {
|
|
Packit |
549fdc |
unset_ext_data(session, ext, i);
|
|
Packit |
549fdc |
return;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static void unset_resumed_ext_data(gnutls_session_t session, const struct extension_entry_st *ext, unsigned idx)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (session->internals.ext_data[idx].resumed_set == 0)
|
|
Packit |
549fdc |
return;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ext && ext->deinit_func && session->internals.ext_data[idx].resumed_priv) {
|
|
Packit |
549fdc |
ext->deinit_func(session->internals.ext_data[idx].resumed_priv);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
session->internals.ext_data[idx].resumed_set = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Deinitializes all data that are associated with TLS extensions.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
void _gnutls_ext_free_session_data(gnutls_session_t session)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned int i;
|
|
Packit |
549fdc |
const struct extension_entry_st *ext;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (!session->internals.ext_data[i].set && !session->internals.ext_data[i].resumed_set)
|
|
Packit |
549fdc |
continue;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, session->internals.ext_data[i].type, GNUTLS_EXT_ANY);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
unset_ext_data(session, ext, i);
|
|
Packit |
549fdc |
unset_resumed_ext_data(session, ext, i);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* This function allows an extension to store data in the current session
|
|
Packit |
549fdc |
* and retrieve them later on. We use functions instead of a pointer to a
|
|
Packit |
549fdc |
* private pointer, to allow API additions by individual extensions.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
_gnutls_ext_set_session_data(gnutls_session_t session, uint16_t type,
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned int i;
|
|
Packit |
549fdc |
const struct extension_entry_st *ext;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ext = _gnutls_ext_ptr(session, type, GNUTLS_EXT_ANY);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].type == type ||
|
|
Packit |
549fdc |
(!session->internals.ext_data[i].set && !session->internals.ext_data[i].resumed_set)) {
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].set != 0) {
|
|
Packit |
549fdc |
unset_ext_data(session, ext, i);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
session->internals.ext_data[i].type = type;
|
|
Packit |
549fdc |
session->internals.ext_data[i].priv = data;
|
|
Packit |
549fdc |
session->internals.ext_data[i].set = 1;
|
|
Packit |
549fdc |
return;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_ext_get_session_data(gnutls_session_t session,
|
|
Packit |
549fdc |
uint16_t type, gnutls_ext_priv_data_t * data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].set != 0 &&
|
|
Packit |
549fdc |
session->internals.ext_data[i].type == type)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
*data =
|
|
Packit |
549fdc |
session->internals.ext_data[i].priv;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
_gnutls_ext_get_resumed_session_data(gnutls_session_t session,
|
|
Packit |
549fdc |
uint16_t type,
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t * data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < MAX_EXT_TYPES; i++) {
|
|
Packit |
549fdc |
if (session->internals.ext_data[i].resumed_set != 0
|
|
Packit |
549fdc |
&& session->internals.ext_data[i].type == type) {
|
|
Packit |
549fdc |
*data =
|
|
Packit |
549fdc |
session->internals.ext_data[i].resumed_priv;
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_ext_register:
|
|
Packit |
549fdc |
* @name: the name of the extension to register
|
|
Packit |
549fdc |
* @type: the numeric id of the extension
|
|
Packit |
549fdc |
* @parse_type: the parse type of the extension (see gnutls_ext_parse_type_t)
|
|
Packit |
549fdc |
* @recv_func: a function to receive the data
|
|
Packit |
549fdc |
* @send_func: a function to send the data
|
|
Packit |
549fdc |
* @deinit_func: a function deinitialize any private data
|
|
Packit |
549fdc |
* @pack_func: a function which serializes the extension's private data (used on session packing for resumption)
|
|
Packit |
549fdc |
* @unpack_func: a function which will deserialize the extension's private data
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will register a new extension type. The extension will remain
|
|
Packit |
549fdc |
* registered until gnutls_global_deinit() is called. If the extension type
|
|
Packit |
549fdc |
* is already registered then %GNUTLS_E_ALREADY_REGISTERED will be returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Each registered extension can store temporary data into the gnutls_session_t
|
|
Packit |
549fdc |
* structure using gnutls_ext_set_data(), and they can be retrieved using
|
|
Packit |
549fdc |
* gnutls_ext_get_data().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function is not thread safe.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_ext_register(const char *name, int type, gnutls_ext_parse_type_t parse_type,
|
|
Packit |
549fdc |
gnutls_ext_recv_func recv_func, gnutls_ext_send_func send_func,
|
|
Packit |
549fdc |
gnutls_ext_deinit_data_func deinit_func, gnutls_ext_pack_func pack_func,
|
|
Packit |
549fdc |
gnutls_ext_unpack_func unpack_func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
extension_entry_st *tmp_mod;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++) {
|
|
Packit |
549fdc |
if (extfunc[i]->type == type)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
tmp_mod = gnutls_calloc(1, sizeof(*tmp_mod));
|
|
Packit |
549fdc |
if (tmp_mod == NULL)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
tmp_mod->name = gnutls_strdup(name);
|
|
Packit |
549fdc |
tmp_mod->free_struct = 1;
|
|
Packit |
549fdc |
tmp_mod->type = type;
|
|
Packit |
549fdc |
tmp_mod->parse_type = parse_type;
|
|
Packit |
549fdc |
tmp_mod->recv_func = recv_func;
|
|
Packit |
549fdc |
tmp_mod->send_func = send_func;
|
|
Packit |
549fdc |
tmp_mod->deinit_func = deinit_func;
|
|
Packit |
549fdc |
tmp_mod->pack_func = pack_func;
|
|
Packit |
549fdc |
tmp_mod->unpack_func = unpack_func;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = ext_register(tmp_mod);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_free((void*)tmp_mod->name);
|
|
Packit |
549fdc |
gnutls_free(tmp_mod);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_session_ext_register:
|
|
Packit |
549fdc |
* @session: the session for which this extension will be set
|
|
Packit |
549fdc |
* @name: the name of the extension to register
|
|
Packit |
549fdc |
* @type: the numeric id of the extension
|
|
Packit |
549fdc |
* @parse_type: the parse type of the extension (see gnutls_ext_parse_type_t)
|
|
Packit |
549fdc |
* @recv_func: a function to receive the data
|
|
Packit |
549fdc |
* @send_func: a function to send the data
|
|
Packit |
549fdc |
* @deinit_func: a function deinitialize any private data
|
|
Packit |
549fdc |
* @pack_func: a function which serializes the extension's private data (used on session packing for resumption)
|
|
Packit |
549fdc |
* @unpack_func: a function which will deserialize the extension's private data
|
|
Packit |
549fdc |
* @flags: must be zero or flags from %gnutls_ext_flags_t
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will register a new extension type. The extension will be
|
|
Packit |
549fdc |
* only usable within the registered session. If the extension type
|
|
Packit |
549fdc |
* is already registered then %GNUTLS_E_ALREADY_REGISTERED will be returned,
|
|
Packit |
549fdc |
* unless the flag %GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL is specified. The latter
|
|
Packit |
549fdc |
* flag when specified can be used to override certain extensions introduced
|
|
Packit |
549fdc |
* after 3.6.0. It is expected to be used by applications which handle
|
|
Packit |
549fdc |
* custom extensions that are not currently supported in GnuTLS, but direct
|
|
Packit |
549fdc |
* support for them may be added in the future.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Each registered extension can store temporary data into the gnutls_session_t
|
|
Packit |
549fdc |
* structure using gnutls_ext_set_data(), and they can be retrieved using
|
|
Packit |
549fdc |
* gnutls_ext_get_data().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.5.5
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_session_ext_register(gnutls_session_t session,
|
|
Packit |
549fdc |
const char *name, int type, gnutls_ext_parse_type_t parse_type,
|
|
Packit |
549fdc |
gnutls_ext_recv_func recv_func, gnutls_ext_send_func send_func,
|
|
Packit |
549fdc |
gnutls_ext_deinit_data_func deinit_func, gnutls_ext_pack_func pack_func,
|
|
Packit |
549fdc |
gnutls_ext_unpack_func unpack_func, unsigned flags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
extension_entry_st tmp_mod;
|
|
Packit |
549fdc |
extension_entry_st *exts;
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* reject handling any extensions which modify the TLS handshake
|
|
Packit |
549fdc |
* in any way, or are mapped to an exported API. */
|
|
Packit |
549fdc |
for (i = 0; extfunc[i] != NULL; i++) {
|
|
Packit |
549fdc |
if (extfunc[i]->type == type) {
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_EXT_FLAG_OVERRIDE_INTERNAL)) {
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
|
|
Packit |
549fdc |
} else if (extfunc[i]->cannot_be_overriden) {
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
memset(&tmp_mod, 0, sizeof(extension_entry_st));
|
|
Packit |
549fdc |
tmp_mod.free_struct = 1;
|
|
Packit |
549fdc |
tmp_mod.type = type;
|
|
Packit |
549fdc |
tmp_mod.parse_type = parse_type;
|
|
Packit |
549fdc |
tmp_mod.recv_func = recv_func;
|
|
Packit |
549fdc |
tmp_mod.send_func = send_func;
|
|
Packit |
549fdc |
tmp_mod.deinit_func = deinit_func;
|
|
Packit |
549fdc |
tmp_mod.pack_func = pack_func;
|
|
Packit |
549fdc |
tmp_mod.unpack_func = unpack_func;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
exts = gnutls_realloc(session->internals.rexts, (session->internals.rexts_size+1)*sizeof(*exts));
|
|
Packit |
549fdc |
if (exts == NULL) {
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
session->internals.rexts = exts;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
memcpy(&session->internals.rexts[session->internals.rexts_size], &tmp_mod, sizeof(extension_entry_st));
|
|
Packit |
549fdc |
session->internals.rexts_size++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_ext_set_data:
|
|
Packit |
549fdc |
* @session: a #gnutls_session_t opaque pointer
|
|
Packit |
549fdc |
* @type: the numeric id of the extension
|
|
Packit |
549fdc |
* @data: the private data to set
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function allows an extension handler to store data in the current session
|
|
Packit |
549fdc |
* and retrieve them later on. The set data will be deallocated using
|
|
Packit |
549fdc |
* the gnutls_ext_deinit_data_func.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void
|
|
Packit |
549fdc |
gnutls_ext_set_data(gnutls_session_t session, unsigned type,
|
|
Packit |
549fdc |
gnutls_ext_priv_data_t data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
_gnutls_ext_set_session_data(session, type, data);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_ext_get_data:
|
|
Packit |
549fdc |
* @session: a #gnutls_session_t opaque pointer
|
|
Packit |
549fdc |
* @type: the numeric id of the extension
|
|
Packit |
549fdc |
* @data: a pointer to the private data to retrieve
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function retrieves any data previously stored with gnutls_ext_set_data().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_ext_get_data(gnutls_session_t session,
|
|
Packit |
549fdc |
unsigned type, gnutls_ext_priv_data_t *data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return _gnutls_ext_get_session_data(session, type, data);
|
|
Packit |
549fdc |
}
|