Commit 82c77c1b authored by Bodo Möller's avatar Bodo Möller
Browse files

Implement known-IV countermeasure.

Fix length checks in ssl3_get_client_hello().

Use s->s3->in_read_app_data differently to fix ssl3_read_internal().
parent ea72ff2d
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -4,6 +4,22 @@

 Changes between 0.9.6c and 0.9.6d  [XX xxx XXXX]

  *) Implement a countermeasure against a vulnerability recently found
     in CBC ciphersuites in SSL 3.0/TLS 1.0: Send an empty fragment
     before application data chunks to avoid the use of known IVs
     with data potentially chosen by the attacker.
     [Bodo Moeller]

  *) Fix length checks in ssl3_get_client_hello().
     [Bodo Moeller]

  *) TLS/SSL library bugfix: use s->s3->in_read_app_data differently
     to prevent ssl3_read_internal() from incorrectly assuming that
     ssl3_read_bytes() found application data while handshake
     processing was enabled when in fact s->s3->in_read_app_data was
     merely automatically cleared during the initial handshake.
     [Bodo Moeller; problem pointed out by Arne Ansper <arne@ats.cyber.ee>]

  *) Fix object definitions for Private and Enterprise: they were not
     recognized in their shortname (=lowercase) representation. Extend
     obj_dat.pl to issue an error when using undefined keywords instead
+11 −7
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@
 * [including the GNU Public Licence.]
 */
/* ====================================================================
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -572,6 +572,7 @@ int ssl3_setup_buffers(SSL *s)
	{
	unsigned char *p;
	unsigned int extra;
	size_t len;

	if (s->s3->rbuf.buf == NULL)
		{
@@ -579,18 +580,21 @@ int ssl3_setup_buffers(SSL *s)
			extra=SSL3_RT_MAX_EXTRA;
		else
			extra=0;
		if ((p=OPENSSL_malloc(SSL3_RT_MAX_PACKET_SIZE+extra))
			== NULL)
		len = SSL3_RT_MAX_PACKET_SIZE + extra;
		if ((p=OPENSSL_malloc(len)) == NULL)
			goto err;
		s->s3->rbuf.buf = p;
		s->s3->rbuf.len = len;
		}

	if (s->s3->wbuf.buf == NULL)
		{
		if ((p=OPENSSL_malloc(SSL3_RT_MAX_PACKET_SIZE))
			== NULL)
		len = SSL3_RT_MAX_PACKET_SIZE;
		len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */
		if ((p=OPENSSL_malloc(len)) == NULL)
			goto err;
		s->s3->wbuf.buf = p;
		s->s3->wbuf.len = len;
		}
	s->packet= &(s->s3->rbuf.buf[0]);
	return(1);
+63 −2
Original line number Diff line number Diff line
@@ -55,6 +55,59 @@
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */
/* ====================================================================
 * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

#include <stdio.h>
#include <openssl/md5.h>
@@ -308,6 +361,14 @@ int ssl3_setup_key_block(SSL *s)
	
	ssl3_generate_key_block(s,p,num);
	
	/* enable vulnerability countermeasure for CBC ciphers with
	 * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) */
	s->s3->need_empty_fragments = 1;
#ifndef NO_RC4
	if ((s->session->cipher != NULL) && ((s->session->cipher->algorithms & SSL_ENC_MASK) == SSL_RC4))
		s->s3->need_empty_fragments = 0;
#endif
		
	return(1);
err:
	SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE);
+11 −7
Original line number Diff line number Diff line
@@ -740,6 +740,7 @@ void ssl3_free(SSL *s)
void ssl3_clear(SSL *s)
	{
	unsigned char *rp,*wp;
	size_t rlen, wlen;

	ssl3_cleanup_key_block(s);
	if (s->s3->tmp.ca_names != NULL)
@@ -757,10 +758,14 @@ void ssl3_clear(SSL *s)

	rp = s->s3->rbuf.buf;
	wp = s->s3->wbuf.buf;
	rlen = s->s3->rbuf.len;
	wlen = s->s3->wbuf.len;

	memset(s->s3,0,sizeof *s->s3);
	if (rp != NULL) s->s3->rbuf.buf=rp;
	if (wp != NULL) s->s3->wbuf.buf=wp;
	s->s3->rbuf.buf = rp;
	s->s3->wbuf.buf = wp;
	s->s3->rbuf.len = rlen;
	s->s3->wbuf.len = wlen;

	ssl_free_wbio_buffer(s);

@@ -1315,13 +1320,12 @@ static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
	if (s->s3->renegotiate) ssl3_renegotiate_check(s);
	s->s3->in_read_app_data=1;
	ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
	if ((ret == -1) && (s->s3->in_read_app_data == 0))
	if ((ret == -1) && (s->s3->in_read_app_data == 2))
		{
		/* ssl3_read_bytes decided to call s->handshake_func, which
		 * called ssl3_read_bytes to read handshake data.
		 * However, ssl3_read_bytes actually found application data
		 * and thinks that application data makes sense here (signalled
		 * by resetting 'in_read_app_data', strangely); so disable
		 * and thinks that application data makes sense here; so disable
		 * handshake processing and try to read application data again. */
		s->in_handshake++;
		ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);
+70 −23
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@
 * [including the GNU Public Licence.]
 */
/* ====================================================================
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
@@ -117,7 +117,7 @@
#include "ssl_locl.h"

static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
			 unsigned int len);
			 unsigned int len, int create_empty_fragment);
static int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
			      unsigned int len);
static int ssl3_get_record(SSL *s);
@@ -162,9 +162,7 @@ static int ssl3_read_n(SSL *s, int n, int max, int extend)

	{
		/* avoid buffer overflow */
		int max_max = SSL3_RT_MAX_PACKET_SIZE - s->packet_length;
		if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
			max_max += SSL3_RT_MAX_EXTRA;
		int max_max = s->s3->rbuf.len - s->packet_length;
		if (max > max_max)
			max = max_max;
	}
@@ -247,14 +245,20 @@ static int ssl3_get_record(SSL *s)
		extra=SSL3_RT_MAX_EXTRA;
	else
		extra=0;
	if (extra != (s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE))
		{
		/* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
		 * set after ssl3_setup_buffers() was done */
		SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_INTERNAL_ERROR);
		return -1;
		}

again:
	/* check if we have the header */
	if (	(s->rstate != SSL_ST_READ_BODY) ||
		(s->packet_length < SSL3_RT_HEADER_LENGTH)) 
		{
		n=ssl3_read_n(s,SSL3_RT_HEADER_LENGTH,
			SSL3_RT_MAX_PACKET_SIZE,0);
		n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
		if (n <= 0) return(n); /* error or non-blocking */
		s->rstate=SSL_ST_READ_BODY;

@@ -509,7 +513,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
		if (i == 0)
			{
			SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
			return(-1);
			return -1;
			}
		}

@@ -521,18 +525,22 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
		else
			nw=n;

		i=do_ssl3_write(s,type,&(buf[tot]),nw);
		i=do_ssl3_write(s, type, &(buf[tot]), nw, 0);
		if (i <= 0)
			{
			s->s3->wnum=tot;
			return(i);
			return i;
			}

		if ((i == (int)n) ||
			(type == SSL3_RT_APPLICATION_DATA &&
			 (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
			{
			return(tot+i);
			/* next chunk of data should get another prepended empty fragment
			 * in ciphersuites with known-IV weakness: */
			s->s3->empty_fragment_done = 0;
			
			return tot+i;
			}

		n-=i;
@@ -541,15 +549,16 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
	}

static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
			 unsigned int len)
			 unsigned int len, int create_empty_fragment)
	{
	unsigned char *p,*plen;
	int i,mac_size,clear=0;
	int prefix_len = 0;
	SSL3_RECORD *wr;
	SSL3_BUFFER *wb;
	SSL_SESSION *sess;

	/* first check is there is a SSL3_RECORD still being written
	/* first check if there is a SSL3_BUFFER still being written
	 * out.  This will happen with non blocking IO */
	if (s->s3->wbuf.left != 0)
		return(ssl3_write_pending(s,type,buf,len));
@@ -563,7 +572,8 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
		/* if it went, fall through and send more stuff */
		}

	if (len == 0) return(len);
	if (len == 0 && !create_empty_fragment)
		return 0;

	wr= &(s->s3->wrec);
	wb= &(s->s3->wbuf);
@@ -579,16 +589,44 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
	else
		mac_size=EVP_MD_size(s->write_hash);

	p=wb->buf;
	/* 'create_empty_fragment' is true only when this function calls itself */
	if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done)
		{
		/* countermeasure against known-IV weakness in CBC ciphersuites
		 * (see http://www.openssl.org/~bodo/tls-cbc.txt) */

		if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA)
			{
			/* recursive function call with 'create_empty_fragment' set;
			 * this prepares and buffers the data for an empty fragment
			 * (these 'prefix_len' bytes are sent out later
			 * together with the actual payload) */
			prefix_len = do_ssl3_write(s, type, buf, 0, 1);
			if (prefix_len <= 0)
				goto err;

			if (s->s3->wbuf.len < prefix_len + SSL3_RT_MAX_PACKET_SIZE)
				{
				/* insufficient space */
				SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_INTERNAL_ERROR);
				goto err;
				}
			}
		
		s->s3->empty_fragment_done = 1;
		}

	p = wb->buf + prefix_len;

	/* write the header */

	*(p++)=type&0xff;
	wr->type=type;

	*(p++)=(s->version>>8);
	*(p++)=s->version&0xff;

	/* record where we are to write out packet length */
	/* field where we are to write out packet length */
	plen=p; 
	p+=2;

@@ -639,19 +677,28 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
	wr->type=type; /* not needed but helps for debugging */
	wr->length+=SSL3_RT_HEADER_LENGTH;

	/* Now lets setup wb */
	wb->left=wr->length;
	if (create_empty_fragment)
		{
		/* we are in a recursive call;
		 * just return the length, don't write out anything here
		 */
		return wr->length;
		}

	/* now let's set up wb */
	wb->left = prefix_len + wr->length;
	wb->offset = 0;

	/* memorize arguments so that ssl3_write_pending can detect bad write retries later */
	s->s3->wpend_tot=len;
	s->s3->wpend_buf=buf;
	s->s3->wpend_type=type;
	s->s3->wpend_ret=len;

	/* we now just need to write the buffer */
	return(ssl3_write_pending(s,type,buf,len));
	return ssl3_write_pending(s,type,buf,len);
err:
	return(-1);
	return -1;
	}

/* if s->s3->wbuf.left != 0, we need to call this */
@@ -1114,7 +1161,7 @@ start:
					)
				))
			{
			s->s3->in_read_app_data=0;
			s->s3->in_read_app_data=2;
			return(-1);
			}
		else
@@ -1200,7 +1247,7 @@ int ssl3_dispatch_alert(SSL *s)
	void (*cb)()=NULL;

	s->s3->alert_dispatch=0;
	i=do_ssl3_write(s,SSL3_RT_ALERT,&s->s3->send_alert[0],2);
	i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0);
	if (i <= 0)
		{
		s->s3->alert_dispatch=1;
Loading