Commit 49968440 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

PR: 2115

Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Approved by: steve@openssl.org

Add Renegotiation extension to DTLS, fix DTLS ClientHello processing bug.
parent 606c46fb
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -764,6 +764,24 @@ int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen)
		p+=i;
		l=i;

	/* Copy the finished so we can use it for
	 * renegotiation checks
	 */
	if(s->type == SSL_ST_CONNECT)
		{
		OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
		memcpy(s->s3->previous_client_finished, 
		       s->s3->tmp.finish_md, i);
		s->s3->previous_client_finished_len=i;
		}
	else
		{
		OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
		memcpy(s->s3->previous_server_finished, 
		       s->s3->tmp.finish_md, i);
		s->s3->previous_server_finished_len=i;
		}

#ifdef OPENSSL_SYS_WIN16
		/* MSVC 1.5 does not clear the top bytes of the word unless
		 * I do this.
+9 −1
Original line number Diff line number Diff line
@@ -636,6 +636,14 @@ int dtls1_client_hello(SSL *s)
			}
		*(p++)=0; /* Add the NULL method */

#ifndef OPENSSL_NO_TLSEXT
		if ((p = ssl_add_clienthello_dtlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
			{
			SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
			goto err;
			}
#endif		

		l=(p-d);
		d=buf;

+191 −0
Original line number Diff line number Diff line
@@ -382,3 +382,194 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
	(void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
	return 1;
	}

#ifndef OPENSSL_NO_TLSEXT
unsigned char *ssl_add_clienthello_dtlsext(SSL *s, unsigned char *p, unsigned char *limit)
	{
	int extdatalen = 0;
	unsigned char *ret = p;
	int el;

	ret+=2;
	
	if (ret>=limit) return NULL; /* this really never occurs, but ... */

	/* Renegotiate extension */
	if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
		{
		SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
		return NULL;
		}

	if((limit - p - 4 - el) < 0) return NULL;
	  
	s2n(TLSEXT_TYPE_renegotiate,ret);
	s2n(el,ret);

	if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
		{
		SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
		return NULL;
		}

	ret += el;

	if ((extdatalen = ret-p-2)== 0) 
		return p;

	s2n(extdatalen,p);

	return ret;
	}

int ssl_parse_clienthello_dtlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
	{
	unsigned short type;
	unsigned short size;
	unsigned short len;
	unsigned char *data = *p;
	int renegotiate_seen = 0;

	if (data >= (d+n-2))
		{
		if (s->new_session
			&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
			{
			/* We should always see one extension: the renegotiate extension */
	 		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
			*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
			return 0;
			}
		return 1;
		}
	n2s(data,len);

	if (data > (d+n-len)) 
		return 1;

	while (data <= (d+n-4))
		{
		n2s(data,type);
		n2s(data,size);
		
		if (data+size > (d+n))
	   		return 1;
		
		if (type == TLSEXT_TYPE_renegotiate)
			{
			if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
				return 0;
			renegotiate_seen = 1;
			}
		
		data+=size;
		}

	if (s->new_session && !renegotiate_seen
		&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
		{
		*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
	 	SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
		return 0;
		}

	*p = data;
	return 1;
	}

unsigned char *ssl_add_serverhello_dtlsext(SSL *s, unsigned char *p, unsigned char *limit)
	{
	int extdatalen = 0;
	unsigned char *ret = p;
	
	ret+=2;
	
	if (ret>=limit) return NULL; /* this really never occurs, but ... */
	
	if(s->s3->send_connection_binding)
		{
		int el;

		if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
			{
			SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
			return NULL;
			}

		if((limit - p - 4 - el) < 0) return NULL;
          
		s2n(TLSEXT_TYPE_renegotiate,ret);
		s2n(el,ret);

		if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
			{
			SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
			return NULL;
			}

		ret += el;
		}

	if ((extdatalen = ret-p-2)== 0) 
		return p;

	s2n(extdatalen,p);

	return ret;
	}

int ssl_parse_serverhello_dtlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
	{
	unsigned short type;
	unsigned short size;
	unsigned short len;
	unsigned char *data = *p;
	int renegotiate_seen = 0;
	
	if (data >= (d+n-2))
		{
		if (s->new_session
			&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
			{
			/* We should always see one extension: the renegotiate extension */
	 		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
			*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
			return 0;
			}
		return 1;
		}
	n2s(data,len);
	
	if (data > (d+n-len)) 
		return 1;
	
	while (data <= (d+n-4))
		{
		n2s(data,type);
		n2s(data,size);
		
		if (data+size > (d+n))
	   		return 1;
		
		if (type == TLSEXT_TYPE_renegotiate)
			{
			if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
				return 0;
			renegotiate_seen = 1;
			}
		
		data+=size;
		}

	if (s->new_session && !renegotiate_seen
		&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
		{
		*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
	 	SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
		return 0;
		}

	*p = data;
	return 1;
	}
#endif
+10 −0
Original line number Diff line number Diff line
@@ -749,6 +749,8 @@ int dtls1_send_server_hello(SSL *s)
		p+=sl;

		/* put the cipher */
		if (s->s3->tmp.new_cipher == NULL)
			return -1;
		i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
		p+=i;

@@ -762,6 +764,14 @@ int dtls1_send_server_hello(SSL *s)
			*(p++)=s->s3->tmp.new_compression->id;
#endif

#ifndef OPENSSL_NO_TLSEXT
		if ((p = ssl_add_serverhello_dtlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
			{
			SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
			return -1;
			}
#endif

		/* do the header */
		l=(p-d);
		d=buf;
+12 −1
Original line number Diff line number Diff line
@@ -915,7 +915,7 @@ int ssl3_get_server_hello(SSL *s)

#ifndef OPENSSL_NO_TLSEXT
	/* TLS extensions*/
	if (s->version > SSL3_VERSION)
	if (s->version > SSL3_VERSION && s->version != DTLS1_VERSION && s->version != DTLS1_BAD_VER)
		{
		if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
			{
@@ -929,6 +929,17 @@ int ssl3_get_server_hello(SSL *s)
				goto err;
			}
		}

	/* DTLS extensions */
	if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
	{
		if (!ssl_parse_serverhello_dtlsext(s,&p,d,n, &al))
		{
			/* 'al' set by ssl_parse_serverhello_dtlsext */
			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
			goto f_err;
		}
	}
#endif

	if (p != (d+n))
Loading