Document DTLS timeout API and add current_time_cb hook.

This is so the tests needn't be sensitive to the clock. It is, unfortunately, a
test-only hook, but the DTLS retransmit/timeout logic more-or-less requires it
currently. Use this hook to, for now, freeze the clock at zero. This makes the
tests deterministic.

It might be worth designing a saner API in the future. The current one,
notably, requires that the caller's clock be compatible with the one we
internally use. It's also not clear whether the caller needs to call
DTLSv1_handle_timeout or can just rely on the state machine doing it internally
(as it does do). But mock clocks are relatively tame and WebRTC wants to
compile against upstream OpenSSL for now, so we're limited in how much new API
we can build.

Change-Id: I7aad51570596f69275ed0fc1a8892393e4b7ba13
Reviewed-on: https://boringssl-review.googlesource.com/3210
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2015-01-26 00:22:12 -05:00 committed by Adam Langley
parent 868c7ef1f4
commit 377fc3160c
4 changed files with 52 additions and 19 deletions

View File

@ -87,18 +87,6 @@ extern "C" {
#ifndef OPENSSL_NO_SSL_INTERN
#if defined(OPENSSL_WINDOWS)
/* Because of Windows header issues, we can't get the normal declaration of
* timeval. */
typedef struct OPENSSL_timeval_st {
long tv_sec;
long tv_usec;
} OPENSSL_timeval;
#else
#include <sys/time.h>
typedef struct timeval OPENSSL_timeval;
#endif
typedef struct dtls1_bitmap_st
{
/* map is a bit mask of the last 64 sequence numbers. Bit

View File

@ -361,6 +361,18 @@ struct ssl_session_st {
char extended_master_secret;
};
#if defined(OPENSSL_WINDOWS)
/* Because of Windows header issues, we can't get the normal declaration of
* timeval. */
typedef struct OPENSSL_timeval_st {
long tv_sec;
long tv_usec;
} OPENSSL_timeval;
#else
#include <sys/time.h>
typedef struct timeval OPENSSL_timeval;
#endif
/* SSL_OP_LEGACY_SERVER_CONNECT allows initial connection to servers that don't
* support RI */
#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L
@ -893,6 +905,10 @@ struct ssl_ctx_st {
/* If not NULL, session key material will be logged to this BIO for debugging
* purposes. The format matches NSS's and is readable by Wireshark. */
BIO *keylog_bio;
/* current_time_cb, if not NULL, is the function to use to get the current
* time. It sets |*out_clock| to the current time. */
void (*current_time_cb)(SSL *ssl, OPENSSL_timeval *out_clock);
};
#define SSL_SESS_CACHE_OFF 0x0000
@ -1596,8 +1612,26 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTRL_FALLBACK_SCSV 120
/* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a
* timeout in progress, it sets |*((OPENSSL_timeval*)arg)| to the time remaining
* and returns one. Otherwise, it returns zero.
*
* When the timeout expires, call |DTLSv1_handle_timeout| to handle the
* retransmit behavior.
*
* NOTE: This function must be queried again whenever the handshake state
* machine changes, including when |DTLSv1_handle_timeout| is called. */
#define DTLSv1_get_timeout(ssl, arg) \
SSL_ctrl(ssl, DTLS_CTRL_GET_TIMEOUT, 0, (void *)arg)
/* DTLSv1_handle_timeout is called when a DTLS handshake timeout expires. If no
* timeout had expired, it returns 0. Otherwise, it retransmits the previous
* flight of handshake messages and returns 1. If too many timeouts had expired
* without progress or an error occurs, it returns -1.
*
* NOTE: The caller's external timer should be compatible with the one |ssl|
* queries within some fudge factor. Otherwise, the call will be a no-op, but
* |DTLSv1_get_timeout| will return an updated timeout. */
#define DTLSv1_handle_timeout(ssl) \
SSL_ctrl(ssl, DTLS_CTRL_HANDLE_TIMEOUT, 0, NULL)

View File

@ -72,7 +72,7 @@
#include "ssl_locl.h"
static void get_current_time(OPENSSL_timeval *t);
static void get_current_time(SSL *ssl, OPENSSL_timeval *out_clock);
static OPENSSL_timeval *dtls1_get_timeout(SSL *s, OPENSSL_timeval *timeleft);
static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
static int dtls1_handshake_write(SSL *s);
@ -272,7 +272,7 @@ void dtls1_start_timer(SSL *s) {
}
/* Set timeout to current time */
get_current_time(&s->d1->next_timeout);
get_current_time(s, &s->d1->next_timeout);
/* Add duration to current time */
s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
@ -289,7 +289,7 @@ static OPENSSL_timeval *dtls1_get_timeout(SSL *s, OPENSSL_timeval *timeleft) {
}
/* Get current time */
get_current_time(&timenow);
get_current_time(s, &timenow);
/* If timer already expired, set remaining time to 0 */
if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
@ -396,14 +396,19 @@ int dtls1_handle_timeout(SSL *s) {
return dtls1_retransmit_buffered_messages(s);
}
static void get_current_time(OPENSSL_timeval *t) {
static void get_current_time(SSL *ssl, OPENSSL_timeval *out_clock) {
if (ssl->ctx->current_time_cb != NULL) {
ssl->ctx->current_time_cb(ssl, out_clock);
return;
}
#if defined(OPENSSL_WINDOWS)
struct _timeb time;
_ftime(&time);
t->tv_sec = time.time;
t->tv_usec = time.millitm * 1000;
out_clock->tv_sec = time.time;
out_clock->tv_usec = time.millitm * 1000;
#else
gettimeofday(t, NULL);
gettimeofday(out_clock, NULL);
#endif
}

View File

@ -228,6 +228,10 @@ static unsigned psk_server_callback(SSL *ssl, const char *identity,
return config->psk.size();
}
static void current_time_cb(SSL *ssl, OPENSSL_timeval *out_clock) {
memset(out_clock, 0, sizeof(*out_clock));
}
static SSL_CTX *setup_ctx(const TestConfig *config) {
SSL_CTX *ssl_ctx = NULL;
DH *dh = NULL;
@ -278,6 +282,8 @@ static SSL_CTX *setup_ctx(const TestConfig *config) {
ssl_ctx->tlsext_channel_id_enabled_new = 1;
ssl_ctx->current_time_cb = current_time_cb;
DH_free(dh);
return ssl_ctx;