DTLS has to maintain timers to retransmit lost packets. This is done
by setting a socket timeout and initiating the retransmission on
return of EAGAIN of a read call. This has a serious drawback when the
peer lost (or an attacker intercepted) a handshake message and keeps
sending application data. The socket timeout and therefor the
retransmission will never occur. This patch adds another timer that
works parallel to the socket timer with the same timeout value, so
that the retransmission can be done even when the peer keeps sending
data.
--- crypto/bio/bio.h 2008-04-02 13:37:23.000000000 +0200
+++ crypto/bio/bio.h 2009-01-28 16:52:24.000000000 +0100
@@ -158,6 +158,7 @@
#define BIO_CTRL_DGRAM_SET_PEER 44 /* Destination for the
data */
+#define BIO_CTRL_DGRAM_SET_TIMEOUT 45
/* modifiers */
#define BIO_FP_READ 0x02
--- crypto/bio/bss_dgram.c 2008-09-15 07:45:36.000000000 +0200
+++ crypto/bio/bss_dgram.c 2009-01-28 16:41:56.000000000 +0100
@@ -104,6 +104,8 @@
unsigned int connected;
unsigned int _errno;
unsigned int mtu;
+ struct timeval hstimeoutdiff;
+ struct timeval hstimeout;
} bio_dgram_data;
BIO_METHOD *BIO_s_datagram(void)
@@ -196,6 +198,22 @@
BIO_set_retry_read(b);
data->_errno = get_last_socket_error();
}
+ memset(&(data->hstimeout), 0, sizeof(struct timeval));
+ }
+ else
+ {
+ if (data->hstimeout.tv_sec > 0 && data->hstimeout.tv_usec
> 0)
+ {
+ struct timeval curtime;
+ gettimeofday(&curtime, NULL);
+ 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);
@@ -345,6 +363,18 @@
memcpy(&(data->peer), to, sizeof(struct sockaddr));
break;
+ case BIO_CTRL_DGRAM_SET_TIMEOUT:
+ if (num > 0)
+ {
+ gettimeofday(&(data->hstimeout), NULL);
+ data->hstimeout.tv_sec += data->hstimeoutdiff.tv_sec;
+ data->hstimeout.tv_usec += data->hstimeoutdiff.tv_usec;
+ }
+ else
+ {
+ memset(&(data->hstimeout), 0, sizeof(struct timeval));
+ }
+ break;
#if defined(SO_RCVTIMEO)
case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
#ifdef OPENSSL_SYS_WINDOWS
@@ -360,6 +390,7 @@
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
--- ssl/d1_clnt.c 2008-06-04 20:35:25.000000000 +0200
+++ ssl/d1_clnt.c 2009-01-28 16:44:26.000000000 +0100
@@ -229,6 +229,7 @@
/* every DTLS ClientHello resets Finished MAC */
ssl3_init_finished_mac(s);
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
1, NULL);
ret=dtls1_client_hello(s);
if (ret <= 0) goto end;
@@ -254,6 +255,7 @@
if (ret <= 0) goto end;
else
{
+ BIO_ctrl(SSL_get_rbio(s),
BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
if (s->hit)
s->state=SSL3_ST_CR_FINISHED_A;
else
@@ -268,6 +270,7 @@
ret = dtls1_get_hello_verify(s);
if ( ret <= 0)
goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
if ( s->d1->send_cookie) /* start again, with a cookie
*/
s->state=SSL3_ST_CW_CLNT_HELLO_A;
else
@@ -329,6 +332,7 @@
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);
ret=dtls1_send_client_certificate(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_CW_KEY_EXCH_A;
@@ -337,6 +341,7 @@
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);
ret=dtls1_send_client_key_exchange(s);
if (ret <= 0) goto end;
l=s->s3->tmp.new_cipher->algorithms;
@@ -359,6 +364,7 @@
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);
ret=dtls1_send_client_verify(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_CW_CHANGE_A;
@@ -368,6 +374,7 @@
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);
ret=dtls1_send_change_cipher_spec(s,
SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
if (ret <= 0) goto end;
@@ -402,6 +409,7 @@
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);
ret=dtls1_send_finished(s,
SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
s->method->ssl3_enc->client_finished_label,
@@ -437,6 +445,7 @@
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);
if (s->hit)
s->state=SSL3_ST_CW_CHANGE_A;
--- ssl/d1_srvr.c 2008-09-14 16:02:01.000000000 +0200
+++ ssl/d1_srvr.c 2009-01-28 16:50:37.000000000 +0100
@@ -247,6 +247,7 @@
case SSL3_ST_SW_HELLO_REQ_B:
s->shutdown=0;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
1, NULL);
ret=dtls1_send_hello_request(s);
if (ret <= 0) goto end;
s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
@@ -267,6 +268,7 @@
s->shutdown=0;
ret=ssl3_get_client_hello(s);
if (ret <= 0) goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
s->new_session = 2;
if ( s->d1->send_cookie)
@@ -280,6 +282,7 @@
case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
1, NULL);
ret = dtls1_send_hello_verify_request(s);
if ( ret <= 0) goto end;
s->d1->send_cookie = 0;
@@ -293,6 +296,7 @@
case SSL3_ST_SW_SRVR_HELLO_A:
case SSL3_ST_SW_SRVR_HELLO_B:
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
1, NULL);
ret=dtls1_send_server_hello(s);
if (ret <= 0) goto end;
@@ -308,6 +312,7 @@
/* Check if it is anon DH */
if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
{
+ BIO_ctrl(SSL_get_rbio(s),
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
ret=dtls1_send_server_certificate(s);
if (ret <= 0) goto end;
}
@@ -349,6 +354,7 @@
)
)
{
+ BIO_ctrl(SSL_get_rbio(s),
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
ret=dtls1_send_server_key_exchange(s);
if (ret <= 0) goto end;
}
@@ -385,6 +391,7 @@
else
{
s->s3->tmp.cert_request=1;
+ BIO_ctrl(SSL_get_rbio(s),
BIO_CTRL_DGRAM_SET_TIMEOUT, 1, NULL);
ret=dtls1_send_certificate_request(s);
if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG
@@ -399,6 +406,7 @@
case SSL3_ST_SW_SRVR_DONE_A:
case SSL3_ST_SW_SRVR_DONE_B:
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
1, NULL);
ret=dtls1_send_server_done(s);
if (ret <= 0) goto end;
s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
@@ -426,6 +434,7 @@
ret = ssl3_check_client_hello(s);
if (ret <= 0)
goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
if (ret == 2)
s->state = SSL3_ST_SR_CLNT_HELLO_C;
else {
@@ -433,6 +442,7 @@
* have not asked for it :-) */
ret=ssl3_get_client_certificate(s);
if (ret <= 0) goto end;
+ BIO_ctrl(SSL_get_rbio(s),
BIO_CTRL_DGRAM_SET_TIMEOUT, 0, NULL);
s->init_num=0;
s->state=SSL3_ST_SR_KEY_EXCH_A;
}
@@ -442,6 +452,7 @@
case SSL3_ST_SR_KEY_EXCH_B:
ret=ssl3_get_client_key_exchange(s);
if (ret <= 0) goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0;
@@ -462,6 +473,7 @@
/* we should decide if we expected this one */
ret=ssl3_get_cert_verify(s);
if (ret <= 0) goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
s->state=SSL3_ST_SR_FINISHED_A;
s->init_num=0;
@@ -472,6 +484,7 @@
ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
SSL3_ST_SR_FINISHED_B);
if (ret <= 0) goto end;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_TIMEOUT,
0, NULL);
if (s->hit)
s->state=SSL_ST_OK;
else
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List openssl-dev@openssl.org
Automated List Manager majord...@openssl.org