Copyright (C) 2000-2012 Free Software Foundation, Inc.
See the end for copying conditions.
-* Version 3.1.0pre0 (released 2012-08-05)
+* Version 3.1.0 (unreleased)
** libgnutls: Added direct support for TPM as a cryptographic module
in gnutls/tpm.h.
gnutls_x509_trust_list_add_trust_file: Added
gnutls_x509_trust_list_add_trust_mem: Added
gnutls_pk_to_sign: Added
+gnutls_handshake_timeout: Added
gnutls_pubkey_verify_hash: Deprecated (use gnutls_pubkey_verify_hash2)
gnutls_pubkey_verify_data: Deprecated (use gnutls_pubkey_verify_data2)
FUNCS += functions/gnutls_bye.short
FUNCS += functions/gnutls_handshake
FUNCS += functions/gnutls_handshake.short
+FUNCS += functions/gnutls_handshake_timeout
+FUNCS += functions/gnutls_handshake_timeout.short
FUNCS += functions/gnutls_rehandshake
FUNCS += functions/gnutls_rehandshake.short
FUNCS += functions/gnutls_alert_get
@showfuncdesc{gnutls_handshake}
+@showfuncdesc{gnutls_handshake_timeout}
+
The handshake process doesn't ensure the verification
of the peer's identity. When certificates are in use,
this can be done, either after the handshake is complete, or during
*/
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
/* Perform the TLS handshake */
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
*/
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
*/
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
*/
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
*/
do
{
- ret = gnutls_handshake (session);
+ ret = gnutls_handshake_timeout (session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
static ssize_t
_gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
- gnutls_pull_func pull_func)
+ gnutls_pull_func pull_func, unsigned int ms)
{
ssize_t i, ret;
uint8_t *ptr;
if (recv_size > max_size)
recv_size = max_size;
+ session->internals.direction = 0;
+
+ if (ms)
+ {
+ ret = _gnutls_io_check_recv(session, ms);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+ }
+
*bufel = _mbuffer_alloc (0, max_size);
if (*bufel == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
ptr = (*bufel)->msg.data;
-
- session->internals.direction = 0;
-
+
reset_errno (session);
i = pull_func (fd, ptr, recv_size);
static ssize_t
_gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel,
- size_t size, gnutls_pull_func pull_func)
+ size_t size, gnutls_pull_func pull_func, unsigned int ms)
{
size_t left;
ssize_t i = 0;
size_t max_size = _gnutls_get_max_decrypted_data(session);
uint8_t *ptr;
gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
+ int ret;
+ struct timespec t1, t2;
+ unsigned int diff;
+
+ session->internals.direction = 0;
*bufel = _mbuffer_alloc (0, MAX(max_size, size));
if (!*bufel)
}
ptr = (*bufel)->msg.data;
- session->internals.direction = 0;
-
left = size;
while (left > 0)
{
+ if (ms)
+ {
+ ret = _gnutls_io_check_recv(session, ms);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ gettime(&t1);
+ }
+
reset_errno (session);
i = pull_func (fd, &ptr[size - left], left);
if (i == 0)
break; /* EOF */
}
-
+
left -= i;
(*bufel)->msg.size += i;
+
+ if (ms && left)
+ {
+ gettime(&t2);
+ diff = _dtls_timespec_sub_ms(&t2, &t1);
+ if (diff < ms)
+ ms -= diff;
+ else
+ return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ }
}
finish:
*/
static ssize_t
_gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
- size_t size, gnutls_pull_func pull_func)
+ size_t size, gnutls_pull_func pull_func, unsigned int ms)
{
if (IS_DTLS (session))
/* Size is not passed, since a whole datagram will be read. */
- return _gnutls_dgram_read (session, bufel, pull_func);
+ return _gnutls_dgram_read (session, bufel, pull_func, ms);
else
- return _gnutls_stream_read (session, bufel, size, pull_func);
+ return _gnutls_stream_read (session, bufel, size, pull_func, ms);
}
static ssize_t
* This is not a general purpose function. It returns EXACTLY the data requested,
* which are stored in a local (in the session) buffer.
*
+ * If the @ms parameter is non zero then this function will return before
+ * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
+ *
*/
ssize_t
_gnutls_io_read_buffered (gnutls_session_t session, size_t total,
- content_type_t recv_type)
+ content_type_t recv_type, unsigned int ms)
{
ssize_t ret = 0;
size_t min;
{
ret =
_gnutls_read (session, &bufel, readsize,
- session->internals.pull_func);
+ session->internals.pull_func, ms);
/* return immediately if we got an interrupt or eagain
* error.
handshake_buffer_st * hsk, unsigned int optional)
{
int ret;
+ time_t tleft = 0;
ret = get_last_packet(session, htype, hsk, optional);
if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
int _gnutls_record_buffer_get (content_type_t type,
gnutls_session_t session, uint8_t * data,
size_t length, uint8_t seq[8]);
-ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t);
+ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t, unsigned int ms);
int _gnutls_io_clear_peeked_data (gnutls_session_t session);
ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
ssize_t
_gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type,
- gnutls_handshake_description_t htype);
+ gnutls_handshake_description_t htype);
#define _gnutls_handshake_io_buffer_clear( session) \
_mbuffer_head_clear( &session->internals.handshake_send_buffer); \
**/
int
gnutls_handshake (gnutls_session_t session)
+{
+ return gnutls_handshake_timeout( session, 0);
+}
+
+/**
+ * gnutls_handshake_timeout:
+ * @session: is a #gnutls_session_t structure.
+ * @sec: is a timeout value in seconds
+ *
+ * This function is identical to the gnutls_handshake() but
+ * it also ensures that the handshake is completed within
+ * the provided timeout value.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, %GNUTLS_E_TIMED_OUT on timeout, otherwise a negative error code.
+ **/
+int
+gnutls_handshake_timeout (gnutls_session_t session, unsigned int sec)
{
int ret;
record_parameters_st *params;
+ if (sec > 0)
+ session->internals.handshake_endtime = gnutls_time(0) + sec;
+ else
+ session->internals.handshake_endtime = 0;
+
/* sanity check. Verify that there are priorities setup.
*/
if (session->internals.priorities.protocol.algorithms == 0)
unsigned int cb_tls_unique_len;
unsigned char cb_tls_unique[MAX_VERIFY_DATA_SIZE];
+
+ unsigned int handshake_endtime; /* end time in seconds */
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
static int recv_headers( gnutls_session_t session, content_type_t type,
- gnutls_handshake_description_t htype, struct tls_record_st* record)
+ gnutls_handshake_description_t htype,
+ struct tls_record_st* record,
+ unsigned int ms)
{
int ret;
gnutls_datum_t raw; /* raw headers */
record->header_size = record->packet_size = RECORD_HEADER_SIZE(session);
if ((ret =
- _gnutls_io_read_buffered (session, record->header_size, -1)) != record->header_size)
+ _gnutls_io_read_buffered (session, record->header_size, -1, ms)) != record->header_size)
{
if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
return ret;
/* This will receive record layer packets and add them to
* application_data_buffer and handshake_data_buffer.
+ *
+ * If the htype is not -1 then handshake timeouts
+ * will be enforced.
*/
ssize_t
_gnutls_recv_in_buffers (gnutls_session_t session, content_type_t type,
record_parameters_st *record_params;
record_state_st *record_state;
struct tls_record_st record;
+ time_t now, tleft = 0;
begin:
record_state = &record_params->read;
+ if (htype != -1 && session->internals.handshake_endtime > 0)
+ {
+ now = gnutls_time(0);
+ if (now < session->internals.handshake_endtime)
+ tleft = (session->internals.handshake_endtime - now) * 1000;
+ else
+ return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ }
+
/* receive headers */
- ret = recv_headers(session, type, htype, &record);
+ ret = recv_headers(session, type, htype, &record, tleft);
if (ret < 0)
{
ret = gnutls_assert_val_fatal(ret);
else
packet_sequence = &record_state->sequence_number;
+ if (htype != -1 && session->internals.handshake_endtime > 0)
+ {
+ now = gnutls_time(0);
+ if (now < session->internals.handshake_endtime)
+ tleft = (session->internals.handshake_endtime - now) * 1000;
+ else
+ return gnutls_assert_val(GNUTLS_E_TIMEDOUT);
+ }
+
/* Read the packet data and insert it to record_recv_buffer.
*/
ret =
_gnutls_io_read_buffered (session, record.packet_size,
- record.type);
+ record.type, tleft);
if (ret != record.packet_size)
{
gnutls_assert();
int gnutls_bye (gnutls_session_t session, gnutls_close_request_t how);
int gnutls_handshake (gnutls_session_t session);
+
+#define GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT 60
+ int gnutls_handshake_timeout (gnutls_session_t session, unsigned int sec);
int gnutls_rehandshake (gnutls_session_t session);
gnutls_alert_description_t gnutls_alert_get (gnutls_session_t session);
gnutls_pkcs11_privkey_set_pin_function;
gnutls_certificate_set_pin_function;
gnutls_x509_crt_set_pin_function;
+ gnutls_handshake_timeout;
} GNUTLS_3_0_0;
GNUTLS_PRIVATE {
gl_fd_to_handle (socket->fd));
do
{
- ret = gnutls_handshake (socket->session);
+ ret = gnutls_handshake_timeout (socket->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
if (ret < 0)
{