From 4af793036f6ef4f0a1078e5d7155426a98d50e37 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 7 Sep 2013 20:40:59 -0400 Subject: [PATCH 1/4] Do not include a timestamp in the ClientHello Random field. Instead, send random bytes. While the gmt_unix_time record was added in an ostensible attempt to mitigate the dangers of a bad RNG, its presence leaks the host's view of the current time in the clear. This minor leak can help fingerprint TLS instances across networks and protocols... and what's worse, it's doubtful thet the gmt_unix_time record does any good at all for its intended purpose, since: * It's quite possible to open two TLS connections in one second. * If the PRNG output is prone to repeat itself, ephemeral * handshakes (and who knows what else besides) are broken. --- ssl/d1_clnt.c | 6 ++---- ssl/s23_clnt.c | 6 ++---- ssl/s3_clnt.c | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index a6ed09c51..bfde14e09 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -773,7 +773,7 @@ int dtls1_client_hello(SSL *s) unsigned char *buf; unsigned char *p,*d; unsigned int i,j; - unsigned long Time,l; + unsigned long l; SSL_COMP *comp; buf=(unsigned char *)s->init_buf->data; @@ -801,9 +801,7 @@ int dtls1_client_hello(SSL *s) for (i=0;p[i]=='\0' && is3->client_random);i++) ; if (i==sizeof(s->s3->client_random)) { - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4); + RAND_pseudo_bytes(p,sizeof(s->s3->client_random)); } /* Do the message type and length last */ diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 47673e740..c9ef0f5cf 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -274,7 +274,7 @@ static int ssl23_client_hello(SSL *s) unsigned char *buf; unsigned char *p,*d; int i,ch_len; - unsigned long Time,l; + unsigned long l; int ssl2_compat; int version = 0, version_major, version_minor; #ifndef OPENSSL_NO_COMP @@ -355,9 +355,7 @@ static int ssl23_client_hello(SSL *s) #endif p=s->s3->client_random; - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE) <= 0) return -1; if (version == TLS1_2_VERSION) diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 344e2eb1a..1b5401125 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -655,7 +655,7 @@ int ssl3_client_hello(SSL *s) unsigned char *buf; unsigned char *p,*d; int i; - unsigned long Time,l; + unsigned long l; #ifndef OPENSSL_NO_COMP int j; SSL_COMP *comp; @@ -680,9 +680,7 @@ int ssl3_client_hello(SSL *s) /* else use the pre-loaded session */ p=s->s3->client_random; - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE) <= 0) goto err; /* Do the message type and length last */ From f4c93b46edb51da71f09eda99e83eaf193a33c08 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 16 Sep 2013 13:32:54 -0400 Subject: [PATCH 2/4] Do not include a timestamp in the ServerHello Random field. Instead, send random bytes. --- ssl/d1_srvr.c | 6 ++---- ssl/s3_srvr.c | 7 ++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 29421da9a..5b0c86a3a 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -912,15 +912,13 @@ int dtls1_send_server_hello(SSL *s) unsigned char *p,*d; int i; unsigned int sl; - unsigned long l,Time; + unsigned long l; if (s->state == SSL3_ST_SW_SRVR_HELLO_A) { buf=(unsigned char *)s->init_buf->data; p=s->s3->server_random; - Time=(unsigned long)time(NULL); /* Time */ - l2n(Time,p); - RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4); + RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE); /* Do the message type and length last */ d=p= &(buf[DTLS1_HM_HEADER_LENGTH]); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index bfb848054..511f5bef4 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1193,12 +1193,9 @@ int ssl3_get_client_hello(SSL *s) * server_random before calling tls_session_secret_cb in order to allow * SessionTicket processing to use it in key derivation. */ { - unsigned long Time; unsigned char *pos; - Time=(unsigned long)time(NULL); /* Time */ - pos=s->s3->server_random; - l2n(Time,pos); - if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0) + pos=s->s3->server_random; + if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE) <= 0) { al=SSL_AD_INTERNAL_ERROR; goto f_err; From 3da721dac9382c48812c8eba455528fd59af2eef Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 9 Oct 2013 10:28:42 -0400 Subject: [PATCH 3/4] Refactor {client,server}_random to call an intermediate function I'll be using this to make an option for randomizing the time. --- ssl/d1_clnt.c | 2 +- ssl/d1_srvr.c | 2 +- ssl/s23_clnt.c | 9 ++++++++- ssl/s3_clnt.c | 3 ++- ssl/s3_srvr.c | 4 ++-- ssl/ssl_locl.h | 1 + 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index bfde14e09..556ac9ccc 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -801,7 +801,7 @@ int dtls1_client_hello(SSL *s) for (i=0;p[i]=='\0' && is3->client_random);i++) ; if (i==sizeof(s->s3->client_random)) { - RAND_pseudo_bytes(p,sizeof(s->s3->client_random)); + ssl_fill_hello_random(s,0,p,sizeof(s->s3->client_random)); } /* Do the message type and length last */ diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 5b0c86a3a..9563066bd 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -918,7 +918,7 @@ int dtls1_send_server_hello(SSL *s) { buf=(unsigned char *)s->init_buf->data; p=s->s3->server_random; - RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE); + ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE); /* Do the message type and length last */ d=p= &(buf[DTLS1_HM_HEADER_LENGTH]); diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index c9ef0f5cf..01e492adf 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -269,6 +269,13 @@ static int ssl23_no_ssl2_ciphers(SSL *s) return 1; } +/* Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 + * on failure, 1 on success. */ +int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, int len) + { + return RAND_pseudo_bytes(result, len); + } + static int ssl23_client_hello(SSL *s) { unsigned char *buf; @@ -355,7 +362,7 @@ static int ssl23_client_hello(SSL *s) #endif p=s->s3->client_random; - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE) <= 0) + if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) return -1; if (version == TLS1_2_VERSION) diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 1b5401125..a6b3c01af 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -680,7 +680,8 @@ int ssl3_client_hello(SSL *s) /* else use the pre-loaded session */ p=s->s3->client_random; - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE) <= 0) + + if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) goto err; /* Do the message type and length last */ diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 511f5bef4..508239fce 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1194,8 +1194,8 @@ int ssl3_get_client_hello(SSL *s) * SessionTicket processing to use it in key derivation. */ { unsigned char *pos; - pos=s->s3->server_random; - if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE) <= 0) + pos=s->s3->server_random; + if (ssl_fill_hello_random(s,1,pos,SSL3_RANDOM_SIZE) <= 0) { al=SSL_AD_INTERNAL_ERROR; goto f_err; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 1b98947e6..96ce9a724 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -847,6 +847,7 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher); STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); int ssl_verify_alarm_type(long type); void ssl_load_ciphers(void); +int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len); int ssl2_enc_init(SSL *s, int client); int ssl2_generate_key_material(SSL *s); From 2583270191a8b27eed303c03ece1da97b9b69fd3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 9 Oct 2013 10:37:53 -0400 Subject: [PATCH 4/4] Control sending time with SSL_SEND_{CLIENT,SERVER}RANDOM_MODE (I'd rather use an option, but it appears that the options field is full.) Now, we send the time in the gmt_unix_time field if the appropriate one of these mode options is set, but randomize the field if the flag is not set. --- ssl/s23_clnt.c | 17 ++++++++++++++++- ssl/ssl.h | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 01e492adf..65d2c26ad 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -273,7 +273,22 @@ static int ssl23_no_ssl2_ciphers(SSL *s) * on failure, 1 on success. */ int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, int len) { - return RAND_pseudo_bytes(result, len); + int send_time = 0; + if (len < 4) + return 0; + if (server) + send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0; + else + send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0; + if (send_time) + { + unsigned long Time = time(NULL); + unsigned char *p = result; + l2n(Time, p); + return RAND_pseudo_bytes(p, len-4); + } + else + return RAND_pseudo_bytes(result, len); } static int ssl23_client_hello(SSL *s) diff --git a/ssl/ssl.h b/ssl/ssl.h index 593579ed3..ae852bf01 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -641,6 +641,12 @@ struct ssl_session_st * TLS only.) "Released" buffers are put onto a free-list in the context * or just freed (depending on the context's setting for freelist_max_len). */ #define SSL_MODE_RELEASE_BUFFERS 0x00000010L +/* Send the current time in the Random fields of the ClientHello and + * ServerHello records for compatibility with hypothetical implementations + * that require it. + */ +#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L +#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L /* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, * they cannot be used to clear bits. */