Commit eb38b26d authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Update from 1.0.0-stable.

parent 8bbe29f2
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -159,7 +159,8 @@ extern "C" {

#define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the data */

#define BIO_CTRL_DGRAM_SET_TIMEOUT        45
#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT   45 /* Next DTLS handshake timeout to
											  * adjust socket timeouts */

/* modifiers */
#define BIO_FP_READ		0x02
+88 −36
Original line number Diff line number Diff line
@@ -110,8 +110,8 @@ typedef struct bio_dgram_data_st
	unsigned int connected;
	unsigned int _errno;
	unsigned int mtu;
	struct timeval hstimeoutdiff;
	struct timeval hstimeout;
	struct timeval next_timeout;
	struct timeval socket_timeout;
	} bio_dgram_data;

BIO_METHOD *BIO_s_datagram(void)
@@ -174,6 +174,87 @@ static int dgram_clear(BIO *a)
	return(1);
	}

static void dgram_adjust_rcv_timeout(BIO *b)
	{
#if defined(SO_RCVTIMEO)
	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
	int sz = sizeof(int);

	/* Is a timer active? */
	if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
		{
		struct timeval timenow, timeleft;

		/* Read current socket timeout */
#ifdef OPENSSL_SYS_WINDOWS
		int timeout;
		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
					   (void*)&timeout, &sz) < 0)
			{ perror("getsockopt"); }
		else
			{
			data->socket_timeout.tv_sec = timeout / 1000;
			data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
			}
#else
		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 
						&(data->socket_timeout), (void *)&sz) < 0)
			{ perror("getsockopt"); }
#endif

		/* Get current time */
		get_current_time(&timenow);

		/* Calculate time left until timer expires */
		memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
		timeleft.tv_sec -= timenow.tv_sec;
		timeleft.tv_usec -= timenow.tv_usec;
		if (timeleft.tv_usec < 0)
			{
			timeleft.tv_sec--;
			timeleft.tv_usec += 1000000;
			}

		/* Adjust socket timeout if next handhake message timer
		 * will expire earlier.
		 */
		if (data->socket_timeout.tv_sec < timeleft.tv_sec ||
			(data->socket_timeout.tv_sec == timeleft.tv_sec &&
			 data->socket_timeout.tv_usec <= timeleft.tv_usec))
			{
#ifdef OPENSSL_SYS_WINDOWS
			timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
			if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
						   (void*)&timeout, sizeof(timeout)) < 0)
				{ perror("setsockopt"); }
#else
			if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
							sizeof(struct timeval)) < 0)
				{ perror("setsockopt"); }
#endif
			}
		}
#endif
	}

static void dgram_reset_rcv_timeout(BIO *b)
	{
#if defined(SO_RCVTIMEO)
	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
#ifdef OPENSSL_SYS_WINDOWS
	int timeout = data->socket_timeout.tv_sec * 1000 +
				  data->socket_timeout.tv_usec / 1000;
	if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
				   (void*)&timeout, sizeof(timeout)) < 0)
		{ perror("setsockopt"); }
#else
	if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
					sizeof(struct timeval)) < 0)
		{ perror("setsockopt"); }
#endif
#endif
	}

static int dgram_read(BIO *b, char *out, int outl)
	{
	int ret=0;
@@ -191,7 +272,9 @@ static int dgram_read(BIO *b, char *out, int outl)
		 * but this is not universal. Cast to (void *) to avoid
		 * compiler warnings.
		 */
		dgram_adjust_rcv_timeout(b);
		ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen);
		dgram_reset_rcv_timeout(b);

		if ( ! data->connected  && ret > 0)
			BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer);
@@ -206,22 +289,6 @@ static int dgram_read(BIO *b, char *out, int outl)
				}
			memset(&(data->hstimeout), 0, sizeof(struct timeval));
			}
		else
			{
			if (data->hstimeout.tv_sec > 0 || data->hstimeout.tv_usec > 0)
				{
				struct timeval curtime;
				get_current_time(&curtime);

				if (curtime.tv_sec >= data->hstimeout.tv_sec &&
					curtime.tv_usec >= data->hstimeout.tv_usec)
					{
					data->_errno = EAGAIN;
					ret = -1;
					memset(&(data->hstimeout), 0, sizeof(struct timeval));
					}
				}
			}
		}
	return(ret);
	}
@@ -370,22 +437,8 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)

        memcpy(&(data->peer), to, sizeof(struct sockaddr));
        break;
	case BIO_CTRL_DGRAM_SET_TIMEOUT:
		if (num > 0)
			{
			get_current_time(&data->hstimeout);
			data->hstimeout.tv_sec += data->hstimeoutdiff.tv_sec;
			data->hstimeout.tv_usec += data->hstimeoutdiff.tv_usec;
			if (data->hstimeout.tv_usec >= 1000000)
				{
				data->hstimeout.tv_sec++;
				data->hstimeout.tv_usec -= 1000000;
				}
			}
		else
			{
			memset(&(data->hstimeout), 0, sizeof(struct timeval));
			}
	case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
		memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));		
		break;
#if defined(SO_RCVTIMEO)
	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
@@ -402,7 +455,6 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
			sizeof(struct timeval)) < 0)
			{ perror("setsockopt");	ret = -1; }
#endif
		memcpy(&(data->hstimeoutdiff), ptr, sizeof(struct timeval));
		break;
	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
+2 −3
Original line number Diff line number Diff line
@@ -883,7 +883,6 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
int dtls1_read_failed(SSL *s, int code)
	{
	DTLS1_STATE *state;
	BIO *bio;
	int send_alert = 0;

	if ( code > 0)
@@ -892,8 +891,7 @@ int dtls1_read_failed(SSL *s, int code)
		return 1;
		}

	bio = SSL_get_rbio(s);
	if ( ! BIO_dgram_recv_timedout(bio))
	if (!dtls1_is_timer_expired(s))
		{
		/* not a timeout, none of our business, 
		   let higher layers handle this.  in fact it's probably an error */
@@ -906,6 +904,7 @@ int dtls1_read_failed(SSL *s, int code)
		return code;
		}

	dtls1_double_timeout(s);
	state = s->d1;
	state->timeout.num_alerts++;
	if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+9 −9
Original line number Diff line number Diff line
@@ -233,7 +233,7 @@ int dtls1_connect(SSL *s)
			/* every DTLS ClientHello resets Finished MAC */
			ssl3_init_finished_mac(s);

			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_client_hello(s);
			if (ret <= 0) goto end;

@@ -259,7 +259,7 @@ int dtls1_connect(SSL *s)
			if (ret <= 0) goto end;
			else
				{
				BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
				dtls1_stop_timer(s);
				if (s->hit)
					s->state=SSL3_ST_CR_FINISHED_A;
				else
@@ -274,7 +274,7 @@ int dtls1_connect(SSL *s)
			ret = dtls1_get_hello_verify(s);
			if ( ret <= 0)
				goto end;
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
			dtls1_stop_timer(s);
			if ( s->d1->send_cookie) /* start again, with a cookie */
				s->state=SSL3_ST_CW_CLNT_HELLO_A;
			else
@@ -336,7 +336,7 @@ int dtls1_connect(SSL *s)
		case SSL3_ST_CW_CERT_B:
		case SSL3_ST_CW_CERT_C:
		case SSL3_ST_CW_CERT_D:
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_send_client_certificate(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_KEY_EXCH_A;
@@ -345,7 +345,7 @@ int dtls1_connect(SSL *s)

		case SSL3_ST_CW_KEY_EXCH_A:
		case SSL3_ST_CW_KEY_EXCH_B:
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_send_client_key_exchange(s);
			if (ret <= 0) goto end;
			/* EAY EAY EAY need to check for DH fix cert
@@ -367,7 +367,7 @@ int dtls1_connect(SSL *s)

		case SSL3_ST_CW_CERT_VRFY_A:
		case SSL3_ST_CW_CERT_VRFY_B:
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_send_client_verify(s);
			if (ret <= 0) goto end;
			s->state=SSL3_ST_CW_CHANGE_A;
@@ -377,7 +377,7 @@ int dtls1_connect(SSL *s)

		case SSL3_ST_CW_CHANGE_A:
		case SSL3_ST_CW_CHANGE_B:
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_send_change_cipher_spec(s,
				SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
			if (ret <= 0) goto end;
@@ -412,7 +412,7 @@ int dtls1_connect(SSL *s)

		case SSL3_ST_CW_FINISHED_A:
		case SSL3_ST_CW_FINISHED_B:
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
			dtls1_start_timer(s);
			ret=dtls1_send_finished(s,
				SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
				s->method->ssl3_enc->client_finished_label,
@@ -445,7 +445,7 @@ int dtls1_connect(SSL *s)
			ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
				SSL3_ST_CR_FINISHED_B);
			if (ret <= 0) goto end;
			BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
			dtls1_stop_timer(s);

			if (s->hit)
				s->state=SSL3_ST_CW_CHANGE_A;
+109 −0
Original line number Diff line number Diff line
@@ -61,6 +61,11 @@
#include <openssl/objects.h>
#include "ssl_locl.h"

#ifdef OPENSSL_SYS_WIN32
#include <sys/timeb.h>
#endif

static void get_current_time(struct timeval *t);
const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT;

SSL3_ENC_METHOD DTLSv1_enc_data={
@@ -201,3 +206,107 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u)

	return ciph;
	}

void dtls1_start_timer(SSL *s)
	{
	/* If timer is not set, initialize duration with 1 second */
	if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
		{
		s->d1->timeout_duration = 1;
		}
	
	/* Set timeout to current time */
	get_current_time(&(s->d1->next_timeout));

	/* Add duration to current time */
	s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
	BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
	}

struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft)
	{
	struct timeval timenow;

	/* If no timeout is set, just return NULL */
	if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
		{
		return NULL;
		}

	/* Get current time */
	get_current_time(&timenow);

	/* If timer already expired, set remaining time to 0 */
	if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
		(s->d1->next_timeout.tv_sec == timenow.tv_sec &&
		 s->d1->next_timeout.tv_usec <= timenow.tv_usec))
		{
		memset(timeleft, 0, sizeof(struct timeval));
		return timeleft;
		}

	/* Calculate time left until timer expires */
	memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
	timeleft->tv_sec -= timenow.tv_sec;
	timeleft->tv_usec -= timenow.tv_usec;
	if (timeleft->tv_usec < 0)
		{
		timeleft->tv_sec--;
		timeleft->tv_usec += 1000000;
		}

	return timeleft;
	}

int dtls1_is_timer_expired(SSL *s)
	{
	struct timeval timeleft;

	/* Get time left until timeout, return false if no timer running */
	if (dtls1_get_timeout(s, &timeleft) == NULL)
		{
		return 0;
		}

	/* Return false if timer is not expired yet */
	if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0)
		{
		return 0;
		}

	/* Timer expired, so return true */	
	return 1;
	}

void dtls1_double_timeout(SSL *s)
	{
	s->d1->timeout_duration *= 2;
	if (s->d1->timeout_duration > 60)
		s->d1->timeout_duration = 60;
	dtls1_start_timer(s);
	}

void dtls1_stop_timer(SSL *s)
	{
	/* Reset everything */
	memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
	s->d1->timeout_duration = 1;
	BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
	}

static void get_current_time(struct timeval *t)
{
#ifdef OPENSSL_SYS_WIN32
	struct _timeb tb;
	_ftime(&tb);
	t->tv_sec = (long)tb.time;
	t->tv_usec = (long)tb.millitm * 1000;
#elif defined(OPENSSL_SYS_VMS)
	struct timeb tb;
	ftime(&tb);
	t->tv_sec = (long)tb.time;
	t->tv_usec = (long)tb.millitm * 1000;
#else
	gettimeofday(t, NULL);
#endif
}
Loading