Bug 140356

Summary: [patch] OpenSSL in base: fix CVE-2009-3555
Product: Base System Reporter: Eygene Ryabinkin <rea-fbsd>
Component: binAssignee: Antoine Brodin <antoine>
Status: Closed FIXED    
Severity: Affects Only Me CC: security
Priority: Normal    
Version: 8.0-BETA2   
Hardware: Any   
OS: Any   

Description Eygene Ryabinkin 2009-11-07 13:50:00 UTC
See [1] (not much information just now) and [2].

Fix: The following patch applies to OpenSSL both from HEAD and 8-STABLE.

It completely disables renegotiation inside TLS/SSL sessions and I had
verified that no renegotiations will take place with s_client and
s_server.



It will be very good if __FreeBSD_version will be bumped after this
update, because there are some fixes for the ports that use OpenSSL,
but disable renegotiation by themselves.  These fixes shouldn't be
applied when system OpenSSL will be updated (port was already
updated to 0.9.8k).--bJrjNL5Mj2NjMLCSZh2lsWg88Obj58F7X17FPNvFe9RLIFX6
Content-Type: text/plain; name="fix-cve-2009-3555.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="fix-cve-2009-3555.diff"

From 01c641ca1a88d08fea282f79ff0f1a86d5319ba7 Mon Sep 17 00:00:00 2001
From: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
Date: Sat, 7 Nov 2009 15:45:32 +0300

Obtained-From: http://cvs.openssl.org/chngview?cn=18791
Obtained-From: http://cvs.openssl.org/chngview?cn=18794

Signed-off-by: Eygene Ryabinkin <rea-fbsd@codelabs.ru>
---
 crypto/openssl/CHANGES       |    9 +++++++++
 crypto/openssl/ssl/s3_lib.c  |    3 +++
 crypto/openssl/ssl/s3_pkt.c  |    4 +++-
 crypto/openssl/ssl/s3_srvr.c |    8 ++++++++
 crypto/openssl/ssl/ssl.h     |    1 +
 crypto/openssl/ssl/ssl3.h    |    9 +++++----
 crypto/openssl/ssl/ssl_err.c |    1 +
 7 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/crypto/openssl/CHANGES b/crypto/openssl/CHANGES
index 04d332e..cd445c9 100644
--- a/crypto/openssl/CHANGES
+++ b/crypto/openssl/CHANGES
@@ -2,6 +2,15 @@
  OpenSSL CHANGES
  _______________
 
+ Changes between 0.9.8k and 0.9.8l  [5 Nov 2009]
+
+  *) Disable renegotiation completely - this fixes a severe security
+     problem at the cost of breaking all renegotiation. Renegotiation
+     can be re-enabled by setting
+     OPENSSL_ENABLE_UNSAFE_LEGACY_SESSION_RENEGOTATION at
+     compile-time. This is really not recommended.
+     [Ben Laurie]
+
  Changes between 0.9.8j and 0.9.8k  [25 Mar 2009]
 
   *) Don't set val to NULL when freeing up structures, it is freed up by
diff --git a/crypto/openssl/ssl/s3_lib.c b/crypto/openssl/ssl/s3_lib.c
index 8916a0b..5aa7bb2 100644
--- a/crypto/openssl/ssl/s3_lib.c
+++ b/crypto/openssl/ssl/s3_lib.c
@@ -2592,6 +2592,9 @@ int ssl3_renegotiate(SSL *s)
 	if (s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
 		return(0);
 
+	if (!(s->s3->flags & SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+		return(0);
+
 	s->s3->renegotiate=1;
 	return(1);
 	}
diff --git a/crypto/openssl/ssl/s3_pkt.c b/crypto/openssl/ssl/s3_pkt.c
index 9476dcd..b98b840 100644
--- a/crypto/openssl/ssl/s3_pkt.c
+++ b/crypto/openssl/ssl/s3_pkt.c
@@ -985,6 +985,7 @@ start:
 
 		if (SSL_is_init_finished(s) &&
 			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+			(s->s3->flags & SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) &&
 			!s->s3->renegotiate)
 			{
 			ssl3_renegotiate(s);
@@ -1117,7 +1118,8 @@ start:
 	if ((s->s3->handshake_fragment_len >= 4) &&	!s->in_handshake)
 		{
 		if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
-			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
+			!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
+			(s->s3->flags & SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
 			{
 #if 0 /* worked only because C operator preferences are not as expected (and
        * because this is not really needed for clients except for detecting
diff --git a/crypto/openssl/ssl/s3_srvr.c b/crypto/openssl/ssl/s3_srvr.c
index 80b45eb..79f3706 100644
--- a/crypto/openssl/ssl/s3_srvr.c
+++ b/crypto/openssl/ssl/s3_srvr.c
@@ -718,6 +718,14 @@ int ssl3_get_client_hello(SSL *s)
 #endif
 	STACK_OF(SSL_CIPHER) *ciphers=NULL;
 
+	if (s->new_session
+	    && !(s->s3->flags&SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+		{
+		al=SSL_AD_HANDSHAKE_FAILURE;
+		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+		goto f_err;
+		}
+
 	/* We do this so that we will respond with our native type.
 	 * If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
 	 * This down switching should be handled by a different method.
diff --git a/crypto/openssl/ssl/ssl.h b/crypto/openssl/ssl/ssl.h
index ff8a128..5ef11a3 100644
--- a/crypto/openssl/ssl/ssl.h
+++ b/crypto/openssl/ssl/ssl.h
@@ -1952,6 +1952,7 @@ void ERR_load_SSL_strings(void);
 #define SSL_R_NO_PRIVATE_KEY_ASSIGNED			 190
 #define SSL_R_NO_PROTOCOLS_AVAILABLE			 191
 #define SSL_R_NO_PUBLICKEY				 192
+#define SSL_R_NO_RENEGOTIATION				 318
 #define SSL_R_NO_SHARED_CIPHER				 193
 #define SSL_R_NO_VERIFY_CALLBACK			 194
 #define SSL_R_NULL_SSL_CTX				 195
diff --git a/crypto/openssl/ssl/ssl3.h b/crypto/openssl/ssl/ssl3.h
index 4b1e2e9..a1a19cb 100644
--- a/crypto/openssl/ssl/ssl3.h
+++ b/crypto/openssl/ssl/ssl3.h
@@ -326,10 +326,11 @@ typedef struct ssl3_buffer_st
 #define SSL3_CT_NUMBER			7
 
 
-#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
-#define SSL3_FLAGS_DELAY_CLIENT_FINISHED	0x0002
-#define SSL3_FLAGS_POP_BUFFER			0x0004
-#define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
+#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS		0x0001
+#define SSL3_FLAGS_DELAY_CLIENT_FINISHED		0x0002
+#define SSL3_FLAGS_POP_BUFFER				0x0004
+#define TLS1_FLAGS_TLS_PADDING_BUG			0x0008
+#define SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION	0x0010
 
 typedef struct ssl3_state_st
 	{
diff --git a/crypto/openssl/ssl/ssl_err.c b/crypto/openssl/ssl/ssl_err.c
index 24a994f..ce2a555 100644
--- a/crypto/openssl/ssl/ssl_err.c
+++ b/crypto/openssl/ssl/ssl_err.c
@@ -384,6 +384,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
 {ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED),"no private key assigned"},
 {ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE),"no protocols available"},
 {ERR_REASON(SSL_R_NO_PUBLICKEY)          ,"no publickey"},
+{ERR_REASON(SSL_R_NO_RENEGOTIATION)      ,"no renegotiation"},
 {ERR_REASON(SSL_R_NO_SHARED_CIPHER)      ,"no shared cipher"},
 {ERR_REASON(SSL_R_NO_VERIFY_CALLBACK)    ,"no verify callback"},
 {ERR_REASON(SSL_R_NULL_SSL_CTX)          ,"null ssl ctx"},
-- 
1.6.3.1
How-To-Repeat: 
[1] http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555
[2] http://cvs.openssl.org/fileview?f=openssl-web/news/announce.txt&v=1.52
Comment 1 Colin Percival freebsd_committer freebsd_triage 2009-11-08 00:22:08 UTC
Given that this is a rather obscure issue (not many people use client
certificates) I'd like to wait until there is more consensus about how
this should be fixed -- it may be that the conclusion will be that the
approach taken by the OpenSSL team, of disabling renegotiation, is
not the right solution.

-- 
Colin Percival
Security Officer, FreeBSD | freebsd.org | The power to serve
Founder / author, Tarsnap | tarsnap.com | Online backups for the truly paranoid
Comment 2 Eygene Ryabinkin 2009-11-08 07:00:49 UTC
Colin, good day.

Sat, Nov 07, 2009 at 04:22:08PM -0800, Colin Percival wrote:
> Given that this is a rather obscure issue (not many people use client
> certificates)

Not many?  How you define "many" and what makes you to believe that
client certificates are not in the wide use for the authentication?

Moreover, the issue isn't lies solely in the clients that use
certificates -- MITM can prefix the data with the chosen text
even when client uses no certificates: the talk about per-directory
authentication was about the case when server initiates renegotiation.
But client (MITM) can equally initiate the renegotiation and the initial
HelloRequest from the real client can be used for this.  See "Scenatio:
Client-initiated renegotiation" from the original paper at
  http://extendedsubset.com/Renegotiating_TLS.pdf

> I'd like to wait until there is more consensus about how this should
> be fixed -- it may be that the conclusion will be that the approach
> taken by the OpenSSL team, of disabling renegotiation, is not the
> right solution.

The general answer is also known: there should be some cryptographical
binding between renegotiated session chunks.  TLS WG is trying to
figure out how to do this in the least harmful way.  See, for example,
  https://svn.resiprocate.org/rep/ietf-drafts/ekr/draft-rescorla-tls-renegotiate.txt
and thread on the tls@ietf.org
  http://www.ietf.org/mail-archive/web/tls/current/msg03963.html
-- 
Eygene
 _                ___       _.--.   #
 \`.|\..----...-'`   `-._.-'_.-'`   #  Remember that it is hard
 /  ' `         ,       __.--'      #  to read the on-line manual
 )/' _/     \   `-_,   /            #  while single-stepping the kernel.
 `-'" `"\_  ,_.-;_.-\_ ',  fsc/as   #
     _.-'_./   {_.'   ; /           #    -- FreeBSD Developers handbook
    {_.-``-'         {_/            #
Comment 3 Antoine Brodin freebsd_committer freebsd_triage 2009-12-21 19:30:44 UTC
State Changed
From-To: open->closed

Close: CVE-2009-3555 was fixed in FreeBSD-SA-09:15.ssl 


Comment 4 Antoine Brodin freebsd_committer freebsd_triage 2009-12-21 19:30:44 UTC
Responsible Changed
From-To: freebsd-bugs->antoine

Track.