summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man3/DTLS_set_timer_cb.pod40
-rw-r--r--include/openssl/ssl.h6
-rw-r--r--ssl/d1_lib.c49
-rw-r--r--ssl/ssl_locl.h6
-rw-r--r--test/dtlstest.c20
-rw-r--r--util/libssl.num1
-rw-r--r--util/private.num1
7 files changed, 114 insertions, 9 deletions
diff --git a/doc/man3/DTLS_set_timer_cb.pod b/doc/man3/DTLS_set_timer_cb.pod
new file mode 100644
index 0000000000..6e1347213e
--- /dev/null
+++ b/doc/man3/DTLS_set_timer_cb.pod
@@ -0,0 +1,40 @@
+=pod
+
+=head1 NAME
+
+DTLS_timer_cb,
+DTLS_set_timer_cb
+- Set callback for controlling DTLS timer duration
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ typedef unsigned int (*DTLS_timer_cb)(SSL *s, unsigned int timer_us);
+
+ void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb);
+
+=head1 DESCRIPTION
+
+This function sets an optional callback function for controlling the
+timeout interval on the DTLS protocol. The callback function will be
+called by DTLS for every new DTLS packet that is sent.
+
+=head1 RETURN VALUES
+
+Returns void.
+
+=head1 HISTORY
+
+This function was added in OpenSSL 1.1.1
+
+=head1 COPYRIGHT
+
+Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License"). You may not use
+this file except in compliance with the License. You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 248408f691..da1fa0ff35 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2260,6 +2260,12 @@ extern const char SSL_version_str[];
int ERR_load_SSL_strings(void);
+
+typedef unsigned int (*DTLS_timer_cb)(SSL *s, unsigned int timer_us);
+
+void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb);
+
+
# ifdef __cplusplus
}
# endif
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index d839e1ab72..a8ea097825 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -161,6 +161,8 @@ int dtls1_clear(SSL *s)
DTLS_RECORD_LAYER_clear(&s->rlayer);
if (s->d1) {
+ DTLS_timer_cb timer_cb = s->d1->timer_cb;
+
buffered_messages = s->d1->buffered_messages;
sent_messages = s->d1->sent_messages;
mtu = s->d1->mtu;
@@ -170,6 +172,9 @@ int dtls1_clear(SSL *s)
memset(s->d1, 0, sizeof(*s->d1));
+ /* Restore the timer callback from previous state */
+ s->d1->timer_cb = timer_cb;
+
if (s->server) {
s->d1->cookie_len = sizeof(s->d1->cookie);
}
@@ -236,6 +241,8 @@ long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
void dtls1_start_timer(SSL *s)
{
+ unsigned int sec, usec;
+
#ifndef OPENSSL_NO_SCTP
/* Disable timer for SCTP */
if (BIO_dgram_is_sctp(SSL_get_wbio(s))) {
@@ -244,16 +251,34 @@ void dtls1_start_timer(SSL *s)
}
#endif
- /* If timer is not set, initialize duration with 1 second */
+ /*
+ * If timer is not set, initialize duration with 1 second or
+ * a user-specified value if the timer callback is installed.
+ */
if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) {
- s->d1->timeout_duration = 1;
+
+ if (s->d1->timer_cb != NULL)
+ s->d1->timeout_duration_us = s->d1->timer_cb(s, 0);
+ else
+ s->d1->timeout_duration_us = 1000000;
}
/* 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;
+
+ sec = s->d1->timeout_duration_us / 1000000;
+ usec = s->d1->timeout_duration_us - (sec * 1000000);
+
+ s->d1->next_timeout.tv_sec += sec;
+ s->d1->next_timeout.tv_usec += usec;
+
+ if (s->d1->next_timeout.tv_usec >= 1000000) {
+ s->d1->next_timeout.tv_sec++;
+ s->d1->next_timeout.tv_usec -= 1000000;
+ }
+
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
&(s->d1->next_timeout));
}
@@ -318,9 +343,9 @@ int dtls1_is_timer_expired(SSL *s)
void dtls1_double_timeout(SSL *s)
{
- s->d1->timeout_duration *= 2;
- if (s->d1->timeout_duration > 60)
- s->d1->timeout_duration = 60;
+ s->d1->timeout_duration_us *= 2;
+ if (s->d1->timeout_duration_us > 60000000)
+ s->d1->timeout_duration_us = 60000000;
dtls1_start_timer(s);
}
@@ -329,7 +354,7 @@ void dtls1_stop_timer(SSL *s)
/* Reset everything */
memset(&s->d1->timeout, 0, sizeof(s->d1->timeout));
memset(&s->d1->next_timeout, 0, sizeof(s->d1->next_timeout));
- s->d1->timeout_duration = 1;
+ s->d1->timeout_duration_us = 1000000;
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
&(s->d1->next_timeout));
/* Clear retransmission buffer */
@@ -367,7 +392,10 @@ int dtls1_handle_timeout(SSL *s)
return 0;
}
- dtls1_double_timeout(s);
+ if (s->d1->timer_cb != NULL)
+ s->d1->timeout_duration_us = s->d1->timer_cb(s, s->d1->timeout_duration_us);
+ else
+ dtls1_double_timeout(s);
if (dtls1_check_timeout_num(s) < 0)
return -1;
@@ -952,3 +980,8 @@ size_t DTLS_get_data_mtu(const SSL *s)
return mtu;
}
+
+void DTLS_set_timer_cb(SSL *s, DTLS_timer_cb cb)
+{
+ s->d1->timer_cb = cb;
+}
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index a0127cf6a0..59fba61a99 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1624,11 +1624,15 @@ typedef struct dtls1_state_st {
*/
struct timeval next_timeout;
/* Timeout duration */
- unsigned short timeout_duration;
+ unsigned int timeout_duration_us;
+
unsigned int retransmitting;
# ifndef OPENSSL_NO_SCTP
int shutdown_received;
# endif
+
+ DTLS_timer_cb timer_cb;
+
} DTLS1_STATE;
# ifndef OPENSSL_NO_EC
diff --git a/test/dtlstest.c b/test/dtlstest.c
index 1bf173509e..7e511f7d6f 100644
--- a/test/dtlstest.c
+++ b/test/dtlstest.c
@@ -17,6 +17,7 @@
static char *cert = NULL;
static char *privkey = NULL;
+static unsigned int timer_cb_count;
#define NUM_TESTS 2
@@ -40,6 +41,16 @@ static unsigned char certstatus[] = {
#define RECORD_SEQUENCE 10
+static unsigned int timer_cb(SSL *s, unsigned int timer_us)
+{
+ ++timer_cb_count;
+
+ if (timer_us == 0)
+ return 1000000;
+ else
+ return 2 * timer_us;
+}
+
static int test_dtls_unprocessed(int testidx)
{
SSL_CTX *sctx = NULL, *cctx = NULL;
@@ -47,6 +58,8 @@ static int test_dtls_unprocessed(int testidx)
BIO *c_to_s_fbio, *c_to_s_mempacket;
int testresult = 0;
+ timer_cb_count = 0;
+
if (!TEST_true(create_ssl_ctx_pair(DTLS_server_method(),
DTLS_client_method(), &sctx,
&cctx, cert, privkey)))
@@ -64,6 +77,8 @@ static int test_dtls_unprocessed(int testidx)
NULL, c_to_s_fbio)))
goto end;
+ DTLS_set_timer_cb(clientssl1, timer_cb);
+
if (testidx == 1)
certstatus[RECORD_SEQUENCE] = 0xff;
@@ -83,6 +98,11 @@ static int test_dtls_unprocessed(int testidx)
SSL_ERROR_NONE)))
goto end;
+ if (timer_cb_count == 0) {
+ printf("timer_callback was not called.\n");
+ goto end;
+ }
+
testresult = 1;
end:
SSL_free(serverssl1);
diff --git a/util/libssl.num b/util/libssl.num
index 14a70234e3..efbd079f4b 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -469,3 +469,4 @@ SSL_SESSION_set_max_early_data 469 1_1_1 EXIST::FUNCTION:
SSL_SESSION_set1_alpn_selected 470 1_1_1 EXIST::FUNCTION:
SSL_SESSION_set1_hostname 471 1_1_1 EXIST::FUNCTION:
SSL_SESSION_get0_alpn_selected 472 1_1_1 EXIST::FUNCTION:
+DTLS_set_timer_cb 473 1_1_1 EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index a757357801..242de12e5f 100644
--- a/util/private.num
+++ b/util/private.num
@@ -18,6 +18,7 @@ BIO_lookup_type datatype
CRYPTO_EX_dup datatype
CRYPTO_EX_free datatype
CRYPTO_EX_new datatype
+DTLS_timer_cb datatype
EVP_PKEY_gen_cb datatype
EVP_PKEY_METHOD datatype
GEN_SESSION_CB datatype