Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 3 May 2012 15:25:13 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r234954 - head/crypto/openssl/crypto head/crypto/openssl/crypto/asn1 head/crypto/openssl/crypto/buffer head/crypto/openssl/crypto/pkcs7 head/crypto/openssl/crypto/x509v3 head/crypto/ope...
Message-ID:  <201205031525.q43FPDbE048833@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Thu May  3 15:25:11 2012
New Revision: 234954
URL: http://svn.freebsd.org/changeset/base/234954

Log:
  Fix multiple OpenSSL vulnerabilities.
  
  Security:	CVE-2011-4576, CVE-2011-4619, CVE-2011-4109
  Security:	CVE-2012-0884, CVE-2012-2110
  Security:	FreeBSD-SA-12:01.openssl
  Approved by:	so (bz,simon)

Modified:
  head/crypto/openssl/crypto/asn1/a_d2i_fp.c
  head/crypto/openssl/crypto/buffer/buffer.c
  head/crypto/openssl/crypto/mem.c
  head/crypto/openssl/crypto/pkcs7/pk7_doit.c
  head/crypto/openssl/crypto/x509v3/pcy_map.c
  head/crypto/openssl/crypto/x509v3/pcy_tree.c
  head/crypto/openssl/ssl/s3_enc.c
  head/crypto/openssl/ssl/s3_srvr.c
  head/crypto/openssl/ssl/ssl.h
  head/crypto/openssl/ssl/ssl3.h
  head/crypto/openssl/ssl/ssl_err.c

Changes in other areas also in this revision:
Modified:
  releng/7.4/UPDATING
  releng/7.4/crypto/openssl/crypto/asn1/a_d2i_fp.c
  releng/7.4/crypto/openssl/crypto/buffer/buffer.c
  releng/7.4/crypto/openssl/crypto/mem.c
  releng/7.4/crypto/openssl/crypto/pkcs7/pk7_doit.c
  releng/7.4/crypto/openssl/crypto/x509v3/pcy_map.c
  releng/7.4/crypto/openssl/crypto/x509v3/pcy_tree.c
  releng/7.4/crypto/openssl/ssl/s3_enc.c
  releng/7.4/crypto/openssl/ssl/s3_srvr.c
  releng/7.4/crypto/openssl/ssl/ssl.h
  releng/7.4/crypto/openssl/ssl/ssl3.h
  releng/7.4/crypto/openssl/ssl/ssl_err.c
  releng/7.4/sys/conf/newvers.sh
  releng/8.1/UPDATING
  releng/8.1/crypto/openssl/crypto/asn1/a_d2i_fp.c
  releng/8.1/crypto/openssl/crypto/buffer/buffer.c
  releng/8.1/crypto/openssl/crypto/mem.c
  releng/8.1/crypto/openssl/crypto/pkcs7/pk7_doit.c
  releng/8.1/crypto/openssl/crypto/x509v3/pcy_map.c
  releng/8.1/crypto/openssl/crypto/x509v3/pcy_tree.c
  releng/8.1/crypto/openssl/ssl/s3_enc.c
  releng/8.1/crypto/openssl/ssl/s3_srvr.c
  releng/8.1/crypto/openssl/ssl/ssl.h
  releng/8.1/crypto/openssl/ssl/ssl3.h
  releng/8.1/crypto/openssl/ssl/ssl_err.c
  releng/8.1/sys/conf/newvers.sh
  releng/8.2/UPDATING
  releng/8.2/crypto/openssl/crypto/asn1/a_d2i_fp.c
  releng/8.2/crypto/openssl/crypto/buffer/buffer.c
  releng/8.2/crypto/openssl/crypto/mem.c
  releng/8.2/crypto/openssl/crypto/pkcs7/pk7_doit.c
  releng/8.2/crypto/openssl/crypto/x509v3/pcy_map.c
  releng/8.2/crypto/openssl/crypto/x509v3/pcy_tree.c
  releng/8.2/crypto/openssl/ssl/s3_enc.c
  releng/8.2/crypto/openssl/ssl/s3_srvr.c
  releng/8.2/crypto/openssl/ssl/ssl.h
  releng/8.2/crypto/openssl/ssl/ssl3.h
  releng/8.2/crypto/openssl/ssl/ssl_err.c
  releng/8.2/sys/conf/newvers.sh
  releng/8.3/UPDATING
  releng/8.3/crypto/openssl/crypto/asn1/a_d2i_fp.c
  releng/8.3/crypto/openssl/crypto/buffer/buffer.c
  releng/8.3/crypto/openssl/crypto/mem.c
  releng/8.3/crypto/openssl/crypto/pkcs7/pk7_doit.c
  releng/8.3/crypto/openssl/crypto/x509v3/pcy_map.c
  releng/8.3/crypto/openssl/crypto/x509v3/pcy_tree.c
  releng/8.3/crypto/openssl/ssl/s3_enc.c
  releng/8.3/crypto/openssl/ssl/s3_srvr.c
  releng/8.3/crypto/openssl/ssl/ssl.h
  releng/8.3/crypto/openssl/ssl/ssl3.h
  releng/8.3/crypto/openssl/ssl/ssl_err.c
  releng/8.3/sys/conf/newvers.sh
  releng/9.0/UPDATING
  releng/9.0/crypto/openssl/crypto/asn1/a_d2i_fp.c
  releng/9.0/crypto/openssl/crypto/buffer/buffer.c
  releng/9.0/crypto/openssl/crypto/mem.c
  releng/9.0/crypto/openssl/crypto/pkcs7/pk7_doit.c
  releng/9.0/crypto/openssl/crypto/x509v3/pcy_map.c
  releng/9.0/crypto/openssl/crypto/x509v3/pcy_tree.c
  releng/9.0/crypto/openssl/ssl/s3_enc.c
  releng/9.0/crypto/openssl/ssl/s3_srvr.c
  releng/9.0/crypto/openssl/ssl/ssl.h
  releng/9.0/crypto/openssl/ssl/ssl3.h
  releng/9.0/crypto/openssl/ssl/ssl_err.c
  releng/9.0/sys/conf/newvers.sh
  stable/7/crypto/openssl/crypto/asn1/a_d2i_fp.c
  stable/7/crypto/openssl/crypto/buffer/buffer.c
  stable/7/crypto/openssl/crypto/mem.c
  stable/7/crypto/openssl/crypto/pkcs7/pk7_doit.c
  stable/7/crypto/openssl/crypto/x509v3/pcy_map.c
  stable/7/crypto/openssl/crypto/x509v3/pcy_tree.c
  stable/7/crypto/openssl/ssl/s3_enc.c
  stable/7/crypto/openssl/ssl/s3_srvr.c
  stable/7/crypto/openssl/ssl/ssl.h
  stable/7/crypto/openssl/ssl/ssl3.h
  stable/7/crypto/openssl/ssl/ssl_err.c
  stable/8/crypto/openssl/crypto/asn1/a_d2i_fp.c
  stable/8/crypto/openssl/crypto/buffer/buffer.c
  stable/8/crypto/openssl/crypto/mem.c
  stable/8/crypto/openssl/crypto/pkcs7/pk7_doit.c
  stable/8/crypto/openssl/crypto/x509v3/pcy_map.c
  stable/8/crypto/openssl/crypto/x509v3/pcy_tree.c
  stable/8/crypto/openssl/ssl/s3_enc.c
  stable/8/crypto/openssl/ssl/s3_srvr.c
  stable/8/crypto/openssl/ssl/ssl.h
  stable/8/crypto/openssl/ssl/ssl3.h
  stable/8/crypto/openssl/ssl/ssl_err.c
  stable/9/crypto/openssl/crypto/asn1/a_d2i_fp.c
  stable/9/crypto/openssl/crypto/buffer/buffer.c
  stable/9/crypto/openssl/crypto/mem.c
  stable/9/crypto/openssl/crypto/pkcs7/pk7_doit.c
  stable/9/crypto/openssl/crypto/x509v3/pcy_map.c
  stable/9/crypto/openssl/crypto/x509v3/pcy_tree.c
  stable/9/crypto/openssl/ssl/s3_enc.c
  stable/9/crypto/openssl/ssl/s3_srvr.c
  stable/9/crypto/openssl/ssl/ssl.h
  stable/9/crypto/openssl/ssl/ssl3.h
  stable/9/crypto/openssl/ssl/ssl_err.c

Modified: head/crypto/openssl/crypto/asn1/a_d2i_fp.c
==============================================================================
--- head/crypto/openssl/crypto/asn1/a_d2i_fp.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/asn1/a_d2i_fp.c	Thu May  3 15:25:11 2012	(r234954)
@@ -57,6 +57,7 @@
  */
 
 #include <stdio.h>
+#include <limits.h>
 #include "cryptlib.h"
 #include <openssl/buffer.h>
 #include <openssl/asn1_mac.h>
@@ -143,17 +144,11 @@ static int asn1_d2i_read_bio(BIO *in, BU
 	BUF_MEM *b;
 	unsigned char *p;
 	int i;
-	int ret=-1;
 	ASN1_const_CTX c;
-	int want=HEADER_SIZE;
+	size_t want=HEADER_SIZE;
 	int eos=0;
-#if defined(__GNUC__) && defined(__ia64)
-	/* pathetic compiler bug in all known versions as of Nov. 2002 */
-	long off=0;
-#else
-	int off=0;
-#endif
-	int len=0;
+	size_t off=0;
+	size_t len=0;
 
 	b=BUF_MEM_new();
 	if (b == NULL)
@@ -169,7 +164,7 @@ static int asn1_d2i_read_bio(BIO *in, BU
 			{
 			want-=(len-off);
 
-			if (!BUF_MEM_grow_clean(b,len+want))
+			if (len + want < len || !BUF_MEM_grow_clean(b,len+want))
 				{
 				ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
 				goto err;
@@ -181,7 +176,14 @@ static int asn1_d2i_read_bio(BIO *in, BU
 				goto err;
 				}
 			if (i > 0)
+				{
+				if (len+i < len)
+					{
+					ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
+					goto err;
+					}
 				len+=i;
+				}
 			}
 		/* else data already loaded */
 
@@ -206,6 +208,11 @@ static int asn1_d2i_read_bio(BIO *in, BU
 			{
 			/* no data body so go round again */
 			eos++;
+			if (eos < 0)
+				{
+				ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_HEADER_TOO_LONG);
+				goto err;
+				}
 			want=HEADER_SIZE;
 			}
 		else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC))
@@ -220,10 +227,16 @@ static int asn1_d2i_read_bio(BIO *in, BU
 		else 
 			{
 			/* suck in c.slen bytes of data */
-			want=(int)c.slen;
+			want=c.slen;
 			if (want > (len-off))
 				{
 				want-=(len-off);
+				if (want > INT_MAX /* BIO_read takes an int length */ ||
+					len+want < len)
+						{
+						ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
+						goto err;
+						}
 				if (!BUF_MEM_grow_clean(b,len+want))
 					{
 					ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ERR_R_MALLOC_FAILURE);
@@ -238,11 +251,18 @@ static int asn1_d2i_read_bio(BIO *in, BU
 						    ASN1_R_NOT_ENOUGH_DATA);
 						goto err;
 						}
+					/* This can't overflow because
+					 * |len+want| didn't overflow. */
 					len+=i;
-					want -= i;
+					want-=i;
 					}
 				}
-			off+=(int)c.slen;
+			if (off + c.slen < off)
+				{
+				ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
+				goto err;
+				}
+			off+=c.slen;
 			if (eos <= 0)
 				{
 				break;
@@ -252,9 +272,15 @@ static int asn1_d2i_read_bio(BIO *in, BU
 			}
 		}
 
+	if (off > INT_MAX)
+		{
+		ASN1err(ASN1_F_ASN1_D2I_READ_BIO,ASN1_R_TOO_LONG);
+		goto err;
+		}
+
 	*pb = b;
 	return off;
 err:
 	if (b != NULL) BUF_MEM_free(b);
-	return(ret);
+	return -1;
 	}

Modified: head/crypto/openssl/crypto/buffer/buffer.c
==============================================================================
--- head/crypto/openssl/crypto/buffer/buffer.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/buffer/buffer.c	Thu May  3 15:25:11 2012	(r234954)
@@ -60,6 +60,11 @@
 #include "cryptlib.h"
 #include <openssl/buffer.h>
 
+/* LIMIT_BEFORE_EXPANSION is the maximum n such that (n+3)/3*4 < 2**31. That
+ * function is applied in several functions in this file and this limit ensures
+ * that the result fits in an int. */
+#define LIMIT_BEFORE_EXPANSION 0x5ffffffc
+
 BUF_MEM *BUF_MEM_new(void)
 	{
 	BUF_MEM *ret;
@@ -94,6 +99,11 @@ int BUF_MEM_grow(BUF_MEM *str, int len)
 	char *ret;
 	unsigned int n;
 
+	if (len < 0)
+		{
+		BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
 	if (str->length >= len)
 		{
 		str->length=len;
@@ -105,6 +115,12 @@ int BUF_MEM_grow(BUF_MEM *str, int len)
 		str->length=len;
 		return(len);
 		}
+	/* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
+	if (len > LIMIT_BEFORE_EXPANSION)
+		{
+		BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
 	n=(len+3)/3*4;
 	if (str->data == NULL)
 		ret=OPENSSL_malloc(n);
@@ -130,6 +146,11 @@ int BUF_MEM_grow_clean(BUF_MEM *str, int
 	char *ret;
 	unsigned int n;
 
+	if (len < 0)
+		{
+		BUFerr(BUF_F_BUF_MEM_GROW_CLEAN,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
 	if (str->length >= len)
 		{
 		memset(&str->data[len],0,str->length-len);
@@ -142,6 +163,12 @@ int BUF_MEM_grow_clean(BUF_MEM *str, int
 		str->length=len;
 		return(len);
 		}
+	/* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
+	if (len > LIMIT_BEFORE_EXPANSION)
+		{
+		BUFerr(BUF_F_BUF_MEM_GROW,ERR_R_MALLOC_FAILURE);
+		return 0;
+		}
 	n=(len+3)/3*4;
 	if (str->data == NULL)
 		ret=OPENSSL_malloc(n);

Modified: head/crypto/openssl/crypto/mem.c
==============================================================================
--- head/crypto/openssl/crypto/mem.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/mem.c	Thu May  3 15:25:11 2012	(r234954)
@@ -372,6 +372,10 @@ void *CRYPTO_realloc_clean(void *str, in
 
 	if (num <= 0) return NULL;
 
+	/* We don't support shrinking the buffer. Note the memcpy that copies
+	 * |old_len| bytes to the new buffer, below. */
+	if (num < old_len) return NULL;
+
 	if (realloc_debug_func != NULL)
 		realloc_debug_func(str, NULL, num, file, line, 0);
 	ret=malloc_ex_func(num,file,line);

Modified: head/crypto/openssl/crypto/pkcs7/pk7_doit.c
==============================================================================
--- head/crypto/openssl/crypto/pkcs7/pk7_doit.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/pkcs7/pk7_doit.c	Thu May  3 15:25:11 2012	(r234954)
@@ -420,6 +420,8 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
 		int max;
 		X509_OBJECT ret;
 #endif
+		unsigned char *tkey = NULL;
+		int tkeylen;
 		int jj;
 
 		if ((etmp=BIO_new(BIO_f_cipher())) == NULL)
@@ -461,36 +463,42 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
 
 		if (pcert == NULL)
 			{
+			/* Temporary storage in case EVP_PKEY_decrypt
+			 * overwrites output buffer on error.
+			 */
+			unsigned char *tmp2;
+			tmp2 = OPENSSL_malloc(jj);
+			if (!tmp2)
+				goto err;
+			jj = -1;
+			/* Always attempt to decrypt all cases to avoid
+			 * leaking timing information about a successful
+			 * decrypt.
+			 */
 			for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++)
 				{
+				int tret;
 				ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
-				jj=EVP_PKEY_decrypt(tmp,
+				tret=EVP_PKEY_decrypt(tmp2,
 					M_ASN1_STRING_data(ri->enc_key),
 					M_ASN1_STRING_length(ri->enc_key),
 						pkey);
-				if (jj > 0)
-					break;
+				if (tret > 0)
+					{
+					memcpy(tmp, tmp2, tret);
+					OPENSSL_cleanse(tmp2, tret);
+					jj = tret;
+					}
 				ERR_clear_error();
-				ri = NULL;
-				}
-			if (ri == NULL)
-				{
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
-				      PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
-				goto err;
 				}
+			OPENSSL_free(tmp2);
 			}
 		else
 			{
 			jj=EVP_PKEY_decrypt(tmp,
 				M_ASN1_STRING_data(ri->enc_key),
 				M_ASN1_STRING_length(ri->enc_key), pkey);
-			if (jj <= 0)
-				{
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
-								ERR_R_EVP_LIB);
-				goto err;
-				}
+			ERR_clear_error();
 			}
 
 		evp_ctx=NULL;
@@ -499,24 +507,49 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
 			goto err;
 		if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
 			goto err;
+		/* Generate random key to counter MMA */
+		tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
+		tkey = OPENSSL_malloc(tkeylen);
+		if (!tkey)
+			goto err;
+		if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
+			goto err;
+		/* If we have no key use random key */
+		if (jj <= 0)
+			{
+			OPENSSL_free(tmp);
+			jj = tkeylen;
+			tmp = tkey;
+			tkey = NULL;
+			}
 
-		if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
+		if (jj != tkeylen) {
 			/* Some S/MIME clients don't use the same key
 			 * and effective key length. The key length is
 			 * determined by the size of the decrypted RSA key.
 			 */
 			if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, jj))
 				{
-				PKCS7err(PKCS7_F_PKCS7_DATADECODE,
-					PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
-				goto err;
+				/* As MMA defence use random key instead */
+				OPENSSL_cleanse(tmp, jj);
+				OPENSSL_free(tmp);
+				jj = tkeylen;
+				tmp = tkey;
+				tkey = NULL;
 				}
 		} 
+		ERR_clear_error();
 		if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
 			goto err;
 
 		OPENSSL_cleanse(tmp,jj);
 
+		if (tkey)
+			{
+			OPENSSL_cleanse(tkey, tkeylen);
+			OPENSSL_free(tkey);
+			}
+
 		if (out == NULL)
 			out=etmp;
 		else

Modified: head/crypto/openssl/crypto/x509v3/pcy_map.c
==============================================================================
--- head/crypto/openssl/crypto/x509v3/pcy_map.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/x509v3/pcy_map.c	Thu May  3 15:25:11 2012	(r234954)
@@ -70,8 +70,6 @@ static int ref_cmp(const X509_POLICY_REF
 
 static void policy_map_free(X509_POLICY_REF *map)
 	{
-	if (map->subjectDomainPolicy)
-		ASN1_OBJECT_free(map->subjectDomainPolicy);
 	OPENSSL_free(map);
 	}
 
@@ -95,6 +93,7 @@ int policy_cache_set_mapping(X509 *x, PO
 	{
 	POLICY_MAPPING *map;
 	X509_POLICY_REF *ref = NULL;
+	ASN1_OBJECT *subjectDomainPolicyRef;
 	X509_POLICY_DATA *data;
 	X509_POLICY_CACHE *cache = x->policy_cache;
 	int i;
@@ -153,13 +152,16 @@ int policy_cache_set_mapping(X509 *x, PO
 		if (!sk_ASN1_OBJECT_push(data->expected_policy_set, 
 						map->subjectDomainPolicy))
 			goto bad_mapping;
+                /* map->subjectDomainPolicy will be freed when
+                 * cache->data is freed. Set it to NULL to avoid double-free. */
+                subjectDomainPolicyRef = map->subjectDomainPolicy;
+                map->subjectDomainPolicy = NULL;
 		
 		ref = OPENSSL_malloc(sizeof(X509_POLICY_REF));
 		if (!ref)
 			goto bad_mapping;
 
-		ref->subjectDomainPolicy = map->subjectDomainPolicy;
-		map->subjectDomainPolicy = NULL;
+		ref->subjectDomainPolicy = subjectDomainPolicyRef;
 		ref->data = data;
 
 		if (!sk_X509_POLICY_REF_push(cache->maps, ref))

Modified: head/crypto/openssl/crypto/x509v3/pcy_tree.c
==============================================================================
--- head/crypto/openssl/crypto/x509v3/pcy_tree.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/crypto/x509v3/pcy_tree.c	Thu May  3 15:25:11 2012	(r234954)
@@ -612,6 +612,10 @@ int X509_policy_check(X509_POLICY_TREE *
 		case 2:
 		return 1;
 
+                /* Some internal error */
+		case -1:
+		return -1;
+
 		/* Some internal error */
 		case 0:
 		return 0;
@@ -691,4 +695,3 @@ int X509_policy_check(X509_POLICY_TREE *
 	return 0;
 
 	}
-

Modified: head/crypto/openssl/ssl/s3_enc.c
==============================================================================
--- head/crypto/openssl/ssl/s3_enc.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/ssl/s3_enc.c	Thu May  3 15:25:11 2012	(r234954)
@@ -479,6 +479,9 @@ int ssl3_enc(SSL *s, int send)
 
 			/* we need to add 'i-1' padding bytes */
 			l+=i;
+			/* the last of these zero bytes will be overwritten
+			 * with the padding length. */
+			memset(&rec->input[rec->length], 0, i);
 			rec->length+=i;
 			rec->input[l-1]=(i-1);
 			}

Modified: head/crypto/openssl/ssl/s3_srvr.c
==============================================================================
--- head/crypto/openssl/ssl/s3_srvr.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/ssl/s3_srvr.c	Thu May  3 15:25:11 2012	(r234954)
@@ -235,6 +235,7 @@ int ssl3_accept(SSL *s)
 				}
 
 			s->init_num=0;
+			s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
 
 			if (s->state != SSL_ST_RENEGOTIATE)
 				{
@@ -697,6 +698,14 @@ int ssl3_check_client_hello(SSL *s)
 	int ok;
 	long n;
 
+	/* We only allow the client to restart the handshake once per
+	 * negotiation. */
+	if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
+		{
+		SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
+		return -1;
+		}
+
 	/* this function is called when we really expect a Certificate message,
 	 * so permit appropriate message length */
 	n=s->method->ssl_get_message(s,
@@ -725,6 +734,7 @@ int ssl3_check_client_hello(SSL *s)
 			s->s3->tmp.ecdh = NULL;
 			}
 #endif
+		s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
 		return 2;
 		}
 	return 1;

Modified: head/crypto/openssl/ssl/ssl.h
==============================================================================
--- head/crypto/openssl/ssl/ssl.h	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/ssl/ssl.h	Thu May  3 15:25:11 2012	(r234954)
@@ -1739,6 +1739,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_F_SSL3_CALLBACK_CTRL			 233
 #define SSL_F_SSL3_CHANGE_CIPHER_STATE			 129
 #define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM		 130
+#define SSL_F_SSL3_CHECK_CLIENT_HELLO			 292
 #define SSL_F_SSL3_CLIENT_HELLO				 131
 #define SSL_F_SSL3_CONNECT				 132
 #define SSL_F_SSL3_CTRL					 213
@@ -1974,6 +1975,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_MISSING_TMP_RSA_KEY			 172
 #define SSL_R_MISSING_TMP_RSA_PKEY			 173
 #define SSL_R_MISSING_VERIFY_MESSAGE			 174
+#define SSL_R_MULTIPLE_SGC_RESTARTS			 325
 #define SSL_R_NON_SSLV2_INITIAL_PACKET			 175
 #define SSL_R_NO_CERTIFICATES_RETURNED			 176
 #define SSL_R_NO_CERTIFICATE_ASSIGNED			 177

Modified: head/crypto/openssl/ssl/ssl3.h
==============================================================================
--- head/crypto/openssl/ssl/ssl3.h	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/ssl/ssl3.h	Thu May  3 15:25:11 2012	(r234954)
@@ -333,6 +333,17 @@ typedef struct ssl3_buffer_st
 #define SSL3_FLAGS_DELAY_CLIENT_FINISHED	0x0002
 #define SSL3_FLAGS_POP_BUFFER			0x0004
 #define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
+ 
+/* SSL3_FLAGS_SGC_RESTART_DONE is set when we
+ * restart a handshake because of MS SGC and so prevents us
+ * from restarting the handshake in a loop. It's reset on a
+ * renegotiation, so effectively limits the client to one restart
+ * per negotiation. This limits the possibility of a DDoS
+ * attack where the client handshakes in a loop using SGC to
+ * restart. Servers which permit renegotiation can still be
+ * effected, but we can't prevent that.
+ */
+#define SSL3_FLAGS_SGC_RESTART_DONE		0x0040
 
 typedef struct ssl3_state_st
 	{

Modified: head/crypto/openssl/ssl/ssl_err.c
==============================================================================
--- head/crypto/openssl/ssl/ssl_err.c	Thu May  3 13:08:11 2012	(r234953)
+++ head/crypto/openssl/ssl/ssl_err.c	Thu May  3 15:25:11 2012	(r234954)
@@ -137,6 +137,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
 {ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL),	"SSL3_CALLBACK_CTRL"},
 {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE),	"SSL3_CHANGE_CIPHER_STATE"},
 {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM),	"SSL3_CHECK_CERT_AND_ALGORITHM"},
+{ERR_FUNC(SSL_F_SSL3_CHECK_CLIENT_HELLO),	"SSL3_CHECK_CLIENT_HELLO"},
 {ERR_FUNC(SSL_F_SSL3_CLIENT_HELLO),	"SSL3_CLIENT_HELLO"},
 {ERR_FUNC(SSL_F_SSL3_CONNECT),	"SSL3_CONNECT"},
 {ERR_FUNC(SSL_F_SSL3_CTRL),	"SSL3_CTRL"},
@@ -375,6 +376,7 @@ static ERR_STRING_DATA SSL_str_reasons[]
 {ERR_REASON(SSL_R_MISSING_TMP_RSA_KEY)   ,"missing tmp rsa key"},
 {ERR_REASON(SSL_R_MISSING_TMP_RSA_PKEY)  ,"missing tmp rsa pkey"},
 {ERR_REASON(SSL_R_MISSING_VERIFY_MESSAGE),"missing verify message"},
+{ERR_REASON(SSL_R_MULTIPLE_SGC_RESTARTS) ,"multiple sgc restarts"},
 {ERR_REASON(SSL_R_NON_SSLV2_INITIAL_PACKET),"non sslv2 initial packet"},
 {ERR_REASON(SSL_R_NO_CERTIFICATES_RETURNED),"no certificates returned"},
 {ERR_REASON(SSL_R_NO_CERTIFICATE_ASSIGNED),"no certificate assigned"},



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205031525.q43FPDbE048833>