Adding a method to change the initial DTLS retransmission timer value.
This allows an application to override the default of 1 second, which
is what's instructed in RFC 6347 but is not an absolute requirement.
Change-Id: I0bbb16e31990fbcab44a29325b6ec7757d5789e5
Reviewed-on: https://boringssl-review.googlesource.com/7930
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 1d0b486..c7b2581 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -487,6 +487,16 @@
* and zero on failure. */
OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu);
+/* DTLSv1_set_initial_timeout_duration sets the initial duration for a DTLS
+ * handshake timeout.
+ *
+ * This duration overrides the default of 1 second, which is the strong
+ * recommendation of RFC 6347 (see section 4.2.4.1). However, there may exist
+ * situations where a shorter timeout would be beneficial, such as for
+ * time-sensitive applications. */
+OPENSSL_EXPORT void DTLSv1_set_initial_timeout_duration(SSL *ssl,
+ unsigned duration_ms);
+
/* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a
* timeout in progress, it sets |*out| to the time remaining and returns one.
* Otherwise, it returns zero.
@@ -3882,6 +3892,10 @@
struct ssl3_state_st *s3; /* SSLv3 variables */
struct dtls1_state_st *d1; /* DTLSv1 variables */
+ /* initial_timeout_duration_ms is the default DTLS timeout duration in
+ * milliseconds. It's used to initialize the timer any time it's restarted. */
+ unsigned initial_timeout_duration_ms;
+
/* callback that allows applications to peek at protocol messages */
void (*msg_callback)(int write_p, int version, int content_type,
const void *buf, size_t len, SSL *ssl, void *arg);
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index e48fbf1..dc3c640 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -157,17 +157,26 @@
return cipher->algorithm_enc != SSL_RC4 && cipher->algorithm_enc != SSL_eNULL;
}
+void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) {
+ ssl->initial_timeout_duration_ms = duration_ms;
+}
+
void dtls1_start_timer(SSL *ssl) {
- /* If timer is not set, initialize duration with 1 second */
+ /* If timer is not set, initialize duration (by default, 1 second) */
if (ssl->d1->next_timeout.tv_sec == 0 && ssl->d1->next_timeout.tv_usec == 0) {
- ssl->d1->timeout_duration = 1;
+ ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
}
/* Set timeout to current time */
get_current_time(ssl, &ssl->d1->next_timeout);
/* Add duration to current time */
- ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration;
+ ssl->d1->next_timeout.tv_sec += ssl->d1->timeout_duration_ms / 1000;
+ ssl->d1->next_timeout.tv_usec += (ssl->d1->timeout_duration_ms % 1000) * 1000;
+ if (ssl->d1->next_timeout.tv_usec >= 1000000) {
+ ssl->d1->next_timeout.tv_sec++;
+ ssl->d1->next_timeout.tv_usec -= 1000000;
+ }
BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
&ssl->d1->next_timeout);
}
@@ -230,9 +239,9 @@
}
void dtls1_double_timeout(SSL *ssl) {
- ssl->d1->timeout_duration *= 2;
- if (ssl->d1->timeout_duration > 60) {
- ssl->d1->timeout_duration = 60;
+ ssl->d1->timeout_duration_ms *= 2;
+ if (ssl->d1->timeout_duration_ms > 60000) {
+ ssl->d1->timeout_duration_ms = 60000;
}
dtls1_start_timer(ssl);
}
@@ -241,7 +250,7 @@
/* Reset everything */
ssl->d1->num_timeouts = 0;
memset(&ssl->d1->next_timeout, 0, sizeof(struct timeval));
- ssl->d1->timeout_duration = 1;
+ ssl->d1->timeout_duration_ms = ssl->initial_timeout_duration_ms;
BIO_ctrl(SSL_get_rbio(ssl), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0,
&ssl->d1->next_timeout);
/* Clear retransmission buffer */
diff --git a/ssl/internal.h b/ssl/internal.h
index ce9175c..2c0bda3 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -956,8 +956,8 @@
* timeout. */
struct timeval next_timeout;
- /* Timeout duration */
- unsigned short timeout_duration;
+ /* timeout_duration_ms is the timeout duration in milliseconds. */
+ unsigned timeout_duration_ms;
} DTLS1_STATE;
extern const SSL3_ENC_METHOD TLSv1_enc_data;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 3135db6..1713c08 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -369,6 +369,10 @@
ssl->min_version = ctx->min_version;
ssl->max_version = ctx->max_version;
+ /* RFC 6347 states that implementations SHOULD use an initial timer value of
+ * 1 second. */
+ ssl->initial_timeout_duration_ms = 1000;
+
ssl->options = ctx->options;
ssl->mode = ctx->mode;
ssl->max_cert_list = ctx->max_cert_list;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 5effa58..c3ff33b 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -1317,6 +1317,10 @@
return false;
}
}
+ if (config->initial_timeout_duration_ms > 0) {
+ DTLSv1_set_initial_timeout_duration(ssl.get(),
+ config->initial_timeout_duration_ms);
+ }
int sock = Connect(config->port);
if (sock == -1) {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5b746c6..e212108 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4583,6 +4583,24 @@
60 * time.Second,
}
+// shortTimeouts is an alternate set of timeouts which would occur if the
+// initial timeout duration was set to 250ms.
+var shortTimeouts = []time.Duration{
+ 250 * time.Millisecond,
+ 500 * time.Millisecond,
+ 1 * time.Second,
+ 2 * time.Second,
+ 4 * time.Second,
+ 8 * time.Second,
+ 16 * time.Second,
+ 32 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+ 60 * time.Second,
+}
+
func addDTLSRetransmitTests() {
// Test that this is indeed the timeout schedule. Stress all
// four patterns of handshake.
@@ -4659,6 +4677,31 @@
},
flags: []string{"-async"},
})
+
+ // Test the timeout schedule when a shorter initial timeout duration is set.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "DTLS-Retransmit-Short-Client",
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async", "-initial-timeout-duration-ms", "250"},
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "DTLS-Retransmit-Short-Server",
+ config: Config{
+ Bugs: ProtocolBugs{
+ TimeoutSchedule: shortTimeouts[:len(shortTimeouts)-1],
+ },
+ },
+ resumeSession: true,
+ flags: []string{"-async", "-initial-timeout-duration-ms", "250"},
+ })
}
func addExportKeyingMaterialTests() {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 67a017d..81b34d3 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -148,6 +148,7 @@
&TestConfig::expect_server_key_exchange_hash },
{ "-expect-key-exchange-info",
&TestConfig::expect_key_exchange_info },
+ { "-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms },
};
} // namespace
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index fe117d8..919fc29 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -104,6 +104,7 @@
bool use_sparse_dh_prime = false;
int expect_key_exchange_info = 0;
bool use_old_client_cert_callback = false;
+ int initial_timeout_duration_ms = 0;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);