You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Joe Orton <jo...@redhat.com> on 2009/11/05 15:01:26 UTC

TLS renegotiation attack, mod_ssl and OpenSSL

With reference to the issue described here:

http://www.ietf.org/mail-archive/web/tls/current/msg03948.html

Considering the impact on mod_ssl, I'm making these assumptions:

1. no HTTP/SSL client initiates a renegotiation of its own accord

2. many mod_ssl configurations do not require a renegotiation to be 
performed at all

3. some mod_ssl configurations, typically requiring client cert auth in 
a per-directory/location context, do require the server to initiate a 
renegotiation.

The longer term plan to fix the vulnerability is to upgrade all clients 
and servers to support a new TLS extension which allows renegotiations 
to be performed securely.

Disabling renegotiation completely and unconditionally at SSL toolkit 
level will break a significant number of installs - I don't think we 
could deploy that change.  

In the short term, I think it would be useful to have a new SSL_OP_* 
flag which enables rejection of a client-initiated handshake in an SSL 
server.  This will fix the issue for 90% of sites without breaking the 
remaining 10% (case 3 above), and is a change that can be deployed 
everywhere.

Regards, Joe

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Colm MacCárthaigh <co...@allcosts.net>.
2009/11/6 Colm MacCárthaigh <co...@allcosts.net>:
> On Thu, Nov 5, 2009 at 6:01 AM, Joe Orton <jo...@redhat.com> wrote
>> 3. some mod_ssl configurations, typically requiring client cert auth in
>> a per-directory/location context, do require the server to initiate a
>> renegotiation.
>
> For this, shouldn't it be sufficient for us to discard any pending
> input that arrived prior to the reneg?

To answer my own question; No, it's not, never mind.

-- 
Colm

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Colm MacCárthaigh <co...@allcosts.net>.
On Thu, Nov 5, 2009 at 6:01 AM, Joe Orton <jo...@redhat.com> wrote
> 3. some mod_ssl configurations, typically requiring client cert auth in
> a per-directory/location context, do require the server to initiate a
> renegotiation.

For this, shouldn't it be sufficient for us to discard any pending
input that arrived prior to the reneg?

-- 
Colm

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Peter Sylvester <pe...@edelweb.fr>.
Hi

Isn't the real simple cause the possiblity to 'upgrade'
an "anonymous" session to a client authenticated one
initiated by the server after seeing a request to
a ressource and the problem that the client cannot
repeat the request.

In case of a GET et consorts, the result of the request
is already protected by the new ciphersuite, so the
*attacker* cannot do much more that DOS, or
(one could respond with a redirect to the same resource
to see whether it really comes from the client)

In case of a POST et consorts I think one should simply
reject the request since it seems always possible to have
the post initiated already from an appropriate security
context. Either the form is in the same directory,
or the whole thing is on another virtual server, i.e.
the client has switched already.

This are my 3 quarks.
Peter Sylvester

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Ruediger Pluem <rp...@apache.org>.

On 11/05/2009 11:03 PM, Dirk-Willem van Gulik wrote:
> Joe Orton wrote:
> 
>> * we can detect in mod_ssl when the client is renegotiating by using the
>> callback installed using SSL_CTX_set_info_callback(), in conjunction
>> with suitable flags in the SSLConnRec to detect the cases where this is
>> either a server-initiated renegotiation or the initial handshake on the
>> connection.
> 
> This seems to work for me - i.e. it calls back exactly when needed
> (rather than EAGAIN like break bubbling up in kernel_io.c) - and it
> _also_ seems to cover the other types of re-negotiation (i.e. other than
> for a Cert) which actually worry me a lot more.
> 
> For the record - this MiM can be done with _all_ type of
> (re)negotiations - for all parameters right ?

As far as I understand it: Yes. One of the examples was regarding cipher spec
renegotiations and I see no reasons why other renegotiations beyond cert and
cipher spec shouldn't be vulnerable.

Regards

Rüdiger

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
Joe Orton wrote:

> * we can detect in mod_ssl when the client is renegotiating by using the
> callback installed using SSL_CTX_set_info_callback(), in conjunction
> with suitable flags in the SSLConnRec to detect the cases where this is
> either a server-initiated renegotiation or the initial handshake on the
> connection.

This seems to work for me - i.e. it calls back exactly when needed 
(rather than EAGAIN like break bubbling up in kernel_io.c) - and it 
_also_ seems to cover the other types of re-negotiation (i.e. other than 
for a Cert) which actually worry me a lot more.

For the record - this MiM can be done with _all_ type of 
(re)negotiations - for all parameters right ?

Thanks,

Dw.

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
Ruediger Pluem wrote:

> I guess how much in the cert case also depends on the clients browser settings
> and its user (does it send a certificate even though the original request
> by the browser did not request one?)

Yes - the 'SSLClient require' on / or VHost level is fine.

> Note that mod_ssl is not part of 1.3.x but a separate project.

Aye - Ralf's problem :)

> So only 2.0.x might be worth a thought.

Does anyone care ?

Dw

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Ruediger Pluem <rp...@apache.org>.

On 11/06/2009 10:58 PM, Dirk-Willem van Gulik wrote:
> So what are the next steps here ?
> 
> -    Joe's patch is final.
> 
> -    Give the community the advice 'immediately' - with a website
>     update and an email to announce:
> 
>     Apache httpd is affected by CVE-XXXX (The SSL Injectin
>     or MiM attack).
> 
>     We strongly urge you to upgrade to OpenSSL 0.9.8l; and be
>     prepared to deploy 0.9.8m as it becomes available.
> 
>     For those who are not able to upgrade swiftly and/or for those
>     who need detailed logging - we recommend that you roll out
>     this patch (URL) as soon as possible.

I guess no one who needs server triggered renegotiation in its configuration
can upgrade to 0.9.8l as to my understanding *all* renegotiations
are simply turned off in 0.9.8l. So these people can only go with
our patch or a fresh release of httpd and are still *vulnerable* in those URL
spaces that are somehow "protected" by these renegotiations.
I guess how much in the cert case also depends on the clients browser settings
and its user (does it send a certificate even though the original request
by the browser did not request one?)

>     If you are unable to patch and unable to roll our a newer
>     version of OpenSSL then we recommend that you ensure that
>     you limit your configuratin to a single 'SSLClient require'
>     or 'SSLClient none' at VirtualHost/Sever level and remove
>     all other (re)negotiation changes. However this does NOT
>     fully protect you - it just curtails authentication.
> 
>     A version with this patch, Apache 2.2.15, is currently
>     beeing readied; there are no plans for a backport to
>     1.3.X at this time.
> 
> -    Check how much we have on the roster in - and either release
>     a 2.x with just this CVE - or a more wrapped up one ?
> 
> Do we need to backport this for the 1.3.42 branch ?

Note that mod_ssl is not part of 1.3.x but a separate project.
So only 2.0.x might be worth a thought.

Regards

Rüdiger


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
So what are the next steps here ?

-	Joe's patch is final.

-	Give the community the advice 'immediately' - with a website
	update and an email to announce:

	Apache httpd is affected by CVE-XXXX (The SSL Injectin
	or MiM attack).

	We strongly urge you to upgrade to OpenSSL 0.9.8l; and be
	prepared to deploy 0.9.8m as it becomes available.

	For those who are not able to upgrade swiftly and/or for those
	who need detailed logging - we recommend that you roll out
	this patch (URL) as soon as possible.

	If you are unable to patch and unable to roll our a newer
	version of OpenSSL then we recommend that you ensure that
	you limit your configuratin to a single 'SSLClient require'
	or 'SSLClient none' at VirtualHost/Sever level and remove
	all other (re)negotiation changes. However this does NOT
	fully protect you - it just curtails authentication.

	A version with this patch, Apache 2.2.15, is currently
	beeing readied; there are no plans for a backport to
	1.3.X at this time.

-	Check how much we have on the roster in - and either release
	a 2.x with just this CVE - or a more wrapped up one ?

Do we need to backport this for the 1.3.42 branch ?

Thanks,

Dw.

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Ruediger Pluem <rp...@apache.org>.

On 11/09/2009 10:39 AM, Boyle Owen wrote:
>> -----Original Message-----
>> From: Dirk-Willem van Gulik [mailto:dirkx@webweaving.org] 
>> Sent: Saturday, November 07, 2009 12:28 AM
>> To: dev@httpd.apache.org
>> Subject: Re: TLS renegotiation attack, mod_ssl and OpenSSL
>>
>> +1 from me. (FreeBSD, Solaris). Test with and without certs (firefox, 
>> safari, openssl tool). Tested with renegotion break script openssl.
> 
> Can I just verify what is supposed to happen with the break script test?
> 
> I have built 2.2.14 with 0.9.8l on Solaris 10. I do:
> 
> 	$ openssl -connect wibble:443
> 	...
> 	GET / HTTP/1.1  =20
> 	Host:wibble
> 	R
> 	RENEGOTIATING
> 
> Then the connection hangs and I get no further data back from the
> server. On http://wibble/server-status, I see:
> 
> 	6-0 17718 0/1/1 R 0.14 31 90 0.0 0.00 0.00 ? ? ..reading..
> 
> Is this the intended behaviour? I thought it was supposed to drop the
> connection?

Dirks tests are about the httpd patch

(http://www.apache.org/dist/httpd/patches/apply_to_2.2.14/CVE-2009-3555-2.2.patch)

which drops the connection. Not sure what openssl 0.9.8l does or what
the intended behaviour is. You might need to ask on the openssl dev list
about that.

Regards

Rüdiger


RE: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Boyle Owen <Ow...@six-group.com>.
> -----Original Message-----
> From: Dirk-Willem van Gulik [mailto:dirkx@webweaving.org] 
> Sent: Saturday, November 07, 2009 12:28 AM
> To: dev@httpd.apache.org
> Subject: Re: TLS renegotiation attack, mod_ssl and OpenSSL
> 
> +1 from me. (FreeBSD, Solaris). Test with and without certs (firefox, 
> safari, openssl tool). Tested with renegotion break script openssl.

Can I just verify what is supposed to happen with the break script test?

I have built 2.2.14 with 0.9.8l on Solaris 10. I do:

	$ openssl -connect wibble:443
	...
	GET / HTTP/1.1  =20
	Host:wibble
	R
	RENEGOTIATING

Then the connection hangs and I get no further data back from the
server. On http://wibble/server-status, I see:

	6-0 17718 0/1/1 R 0.14 31 90 0.0 0.00 0.00 ? ? ..reading..

Is this the intended behaviour? I thought it was supposed to drop the
connection?

Rgds,
Owen Boyle
Disclaimer: Any disclaimer attached to this message may be ignored. 
 
This message is for the named person's use only. It may contain confidential, proprietary or legally privileged information. If you receive this message in error, please notify the sender urgently and then immediately delete the message and any copies of it from your system. Please also immediately destroy any hardcopies of the message. 
The sender's company reserves the right to monitor all e-mail communications through their networks.

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
Joe Orton wrote:
> On Fri, Nov 06, 2009 at 03:09:22AM +0000, Joe Orton wrote:
>> A second hack, slightly less rough hack:
>
> I committed this in r833582 with some minor changes.  Joe

+1 from me. (FreeBSD, Solaris). Test with and without certs (firefox, 
safari, openssl tool). Tested with renegotion break script openssl.

Thanks,

Dw

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Fri, Nov 06, 2009 at 03:09:22AM +0000, Joe Orton wrote:
> A second hack, slightly less rough hack:

I committed this in r833582 with some minor changes.  Joe

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dr Stephen Henson <sh...@oss-institute.org>.
Dirk-Willem van Gulik wrote:
> 
> So I guess the one thing we need now is to double check with the OpenSSL
> folks if the basic concept of this patch covers all basis. I.e. really
> sees every possible renegotiate - regardless of what or from where
> initiated. I am a bit worried that OpenSSL may have to clean an
> abstraction layer perhaps.
> 

I can only comment about *this* OpenSSL folk ;-)

I only found out about this issue yesterday and I'm on vacation until early next
week so I've only been following this in outline.

The normal session resumption can be performed using s_client and the -sess_out
and -sess_in options so check that works normally if you haven't already. That
should be checked with -no_ticket too to check stateful resumption (stateless is
default for newer versions of OpenSSL).

Steve.
-- 
Dr Stephen N. Henson. Senior Technical/Cryptography Advisor,
Open Source Software Institute: www.oss-institute.org
OpenSSL Core team: www.openssl.org

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
Joe Orton wrote:

 > On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:

 >> Here is a very rough first hack (for discussion/testing
 >> purposes only!):
 >
 > A second hack, slightly less rough hack:

Lovely - and that works exactly as I'd expect; and does also 'drop' the 
connection with the openssl s_client 'R' re-negotiate forcing as well.

So I guess the one thing we need now is to double check with the OpenSSL 
folks if the basic concept of this patch covers all bases. I.e. really 
sees every possible renegotiate - regardless of what or from where 
initiated. I am a bit worried that OpenSSL may have to clean an 
abstraction layer perhaps.

To recap (and verify my understanding - we register an info callback and 
then track the connection stat:

+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
...
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+    /* If the reneg state is to reject renegotiations, check the SSL
+     * state machine and move to ABORT if a Client Hello is being
+     * read. */
+    if ((where & SSL_CB_ACCEPT_LOOP) &&
+                 scr->reneg_state == RENEG_REJECT) {
+        int state = SSL_get_state(ssl);
+
+        if (state == SSL3_ST_SR_CLNT_HELLO_A
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
+            scr->reneg_state = RENEG_ABORT;
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
+                          "rejecting client initiated renegotiation");
+        }
+    }
+    /* If the first handshake is complete, change state to reject any
+     * subsequent client-initated renegotiation. */
+    else if (where & SSL_CB_HANDSHAKE_DONE &&
+                       scr->reneg_state == RENEG_INIT) {
+        scr->reneg_state = RENEG_REJECT;
+    }

And we then check this state on every read/write in the bio read/write 
callbacks:

  static int bio_filter_out_write/read(BIO *bio, const char *in, int inl)
  {
      bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);

+    /* Abort early if the client has initiated a renegotiation. */
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        outctx->rc = APR_ECONNABORTED;
+        return -1;
+    }

So it owuld be useful to have confirmed from the OpenSSL experts that 
this gives is visibility of each and every stage change.

And then we're good.

Dw.



Index: ssl_private.h
===================================================================
--- ssl_private.h    (revision 832979)
+++ ssl_private.h    (working copy)
@@ -335,6 +335,20 @@
      int is_proxy;
      int disabled;
      int non_ssl_request;
+
+    /* Track the handshake/renegotiation state for the connection so
+     * that all client-initiated renegotiations can be rejected, as a
+     * partial fix for CVE-2009-3555. */
+    enum {
+        RENEG_INIT = 0, /* Before initial handshake */
+        RENEG_REJECT, /* After initial handshake; any client-initiated
+                       * renegotiation should be rejected */
+        RENEG_ALLOW, /* A server-initated renegotiation is taking
+                      * place (as dictated by configuration) */
+        RENEG_ABORT /* Renegotiation initiated by client, abort the
+                     * connection */
+    } reneg_state;
+
      server_rec *server;
  } SSLConnRec;

@@ -618,7 +632,7 @@
  int          ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
  SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, 
int, int *);
  void         ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
-void         ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, 
int);
+void         ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int);
  #ifndef OPENSSL_NO_TLSEXT
  int          ssl_callback_ServerNameIndication(SSL *, int *, 
modssl_ctx_t *);
  #endif
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c    (revision 832979)
+++ ssl_engine_init.c    (working copy)
@@ -520,10 +520,7 @@
      SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
      SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);

-    if (s->loglevel >= APLOG_DEBUG) {
-        /* this callback only logs if LogLevel >= info */
-        SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
-    }
+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
  }

  static void ssl_init_ctx_verify(server_rec *s,
Index: ssl_engine_io.c
===================================================================
--- ssl_engine_io.c    (revision 832979)
+++ ssl_engine_io.c    (working copy)
@@ -103,6 +103,7 @@
      ap_filter_t        *pInputFilter;
      ap_filter_t        *pOutputFilter;
      int                nobuffer; /* non-zero to prevent buffering */
+    SSLConnRec         *config;
  } ssl_filter_ctx_t;

  typedef struct {
@@ -193,7 +194,13 @@
  static int bio_filter_out_write(BIO *bio, const char *in, int inl)
  {
      bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
-
+
+    /* Abort early if the client has initiated a renegotiation. */
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        outctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+
      /* when handshaking we'll have a small number of bytes.
       * max size SSL will pass us here is about 16k.
       * (16413 bytes to be exact)
@@ -476,6 +483,12 @@
      if (!in)
          return 0;

+    /* Abort early if the client has initiated a renegotiation. */
+    if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        inctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+
      /* In theory, OpenSSL should flush as necessary, but it is known
       * not to do so correctly in some cases; see PR 46952.
       *
@@ -1699,6 +1712,8 @@

      filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t));

+    filter_ctx->config          = myConnConfig(c);
+
      filter_ctx->nobuffer        = 0;
      filter_ctx->pOutputFilter   = ap_add_output_filter(ssl_io_filter,
                                                         filter_ctx, r, c);
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c    (revision 832979)
+++ ssl_engine_kernel.c    (working copy)
@@ -733,6 +733,10 @@
                                         (unsigned char *)&id,
                                         sizeof(id));

+            /* Toggle the renegotiation state to allow the new
+             * handshake to proceed. */
+            sslconn->reneg_state = RENEG_ALLOW;
+
              SSL_renegotiate(ssl);
              SSL_do_handshake(ssl);

@@ -754,6 +758,8 @@
              SSL_set_state(ssl, SSL_ST_ACCEPT);
              SSL_do_handshake(ssl);

+            sslconn->reneg_state = RENEG_REJECT;
+
              if (SSL_get_state(ssl) != SSL_ST_OK) {
                  ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                "Re-negotiation handshake failed: "
@@ -1814,76 +1820,55 @@
      return;
  }

-/*
- * This callback function is executed while OpenSSL processes the
- * SSL handshake and does SSL record layer stuff. We use it to
- * trace OpenSSL's processing in out SSL logfile.
- */
-void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int 
where, int rc)
+/* Dump debugginfo trace to the log file. */
+static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, server_rec *s,
+                              conn_rec *c, int where, int rc)
  {
-    conn_rec *c;
-    server_rec *s;
-    SSLSrvConfigRec *sc;
-
      /*
-     * find corresponding server
+     * create the various trace messages
       */
-    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
-        return;
+    if (where & SSL_CB_HANDSHAKE_START) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: start", SSL_LIBRARY_NAME);
      }
-
-    s = mySrvFromConn(c);
-    if (!(sc = mySrvConfig(s))) {
-        return;
+    else if (where & SSL_CB_HANDSHAKE_DONE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: done", SSL_LIBRARY_NAME);
      }
-
-    /*
-     * create the various trace messages
-     */
-    if (s->loglevel >= APLOG_DEBUG) {
-        if (where & SSL_CB_HANDSHAKE_START) {
+    else if (where & SSL_CB_LOOP) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Loop: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_READ) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Read: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_WRITE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Write: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_ALERT) {
+        char *str = (where & SSL_CB_READ) ? "read" : "write";
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Alert: %s:%s:%s",
+                     SSL_LIBRARY_NAME, str,
+                     SSL_alert_type_string_long(rc),
+                     SSL_alert_desc_string_long(rc));
+    }
+    else if (where & SSL_CB_EXIT) {
+        if (rc == 0) {
              ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: start", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_HANDSHAKE_DONE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: done", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_LOOP) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Loop: %s",
+                         "%s: Exit: failed in %s",
                           SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
          }
-        else if (where & SSL_CB_READ) {
+        else if (rc < 0) {
              ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Read: %s",
+                         "%s: Exit: error in %s",
                           SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
          }
-        else if (where & SSL_CB_WRITE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Write: %s",
-                         SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-        }
-        else if (where & SSL_CB_ALERT) {
-            char *str = (where & SSL_CB_READ) ? "read" : "write";
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Alert: %s:%s:%s",
-                         SSL_LIBRARY_NAME, str,
-                         SSL_alert_type_string_long(rc),
-                         SSL_alert_desc_string_long(rc));
-        }
-        else if (where & SSL_CB_EXIT) {
-            if (rc == 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: failed in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-            else if (rc < 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: error in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-        }
      }

      /*
@@ -1903,6 +1888,60 @@
      }
  }

+/*
+ * This callback function is executed while OpenSSL processes the SSL
+ * handshake and does SSL record layer stuff.  It's used to trap
+ * client-initiated renegotiations, and for dumping everything to the
+ * log.
+ */
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+{
+    conn_rec *c;
+    server_rec *s;
+    SSLSrvConfigRec *sc;
+    SSLConnRec *scr;
+
+    /*
+     * find corresponding server
+     */
+    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
+        return;
+    }
+
+    scr = myConnConfig(c);
+    if (!scr) {
+        return;
+    }
+
+    /* If the reneg state is to reject renegotiations, check the SSL
+     * state machine and move to ABORT if a Client Hello is being
+     * read. */
+    if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) {
+        int state = SSL_get_state(ssl);
+
+        if (state == SSL3_ST_SR_CLNT_HELLO_A
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
+            scr->reneg_state = RENEG_ABORT;
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
+                          "rejecting client initiated renegotiation");
+        }
+    }
+    /* If the first handshake is complete, change state to reject any
+     * subsequent client-initated renegotiation. */
+    else if (where & SSL_CB_HANDSHAKE_DONE && scr->reneg_state == 
RENEG_INIT) {
+        scr->reneg_state = RENEG_REJECT;
+    }
+
+    s = mySrvFromConn(c);
+    if (!(sc = mySrvConfig(s))) {
+        return;
+    }
+
+    if (s->loglevel >= APLOG_DEBUG) {
+        log_tracing_state(ssl, s, c, where, rc);
+    }
+}
+
  #ifndef OPENSSL_NO_TLSEXT
  /*
   * This callback function is executed when OpenSSL encounters an extended


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dirk-Willem van Gulik <di...@webweaving.org>.
Joe Orton wrote:
> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:

>> Here is a very rough first hack (for discussion/testing purposes only!):
>
> A second hack, slightly less rough hack:

Lovely - and that works exactly as I'd expect; and does also 'dro' the 
connection with the openssl s_client 'R' re-negotiate forcing as well.

So I guess the one thing we need now is to double check with the OpenSSL 
folks if the basic concept of this patch covers all basis. I.e. really 
sees every possible renegotiate - regardless of what or from where 
initiated. I am a bit worried that OpenSSL may have to clean an 
abstraction layer perhaps.

To recap (and verify my understanding - we register an info callback and 
then track the connection stat:

+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
...
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+    /* If the reneg state is to reject renegotiations, check the SSL
+     * state machine and move to ABORT if a Client Hello is being
+     * read. */
+    if ((where & SSL_CB_ACCEPT_LOOP) &&
+                 scr->reneg_state == RENEG_REJECT) {
+        int state = SSL_get_state(ssl);
+
+        if (state == SSL3_ST_SR_CLNT_HELLO_A
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
+            scr->reneg_state = RENEG_ABORT;
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
+                          "rejecting client initiated renegotiation");
+        }
+    }
+    /* If the first handshake is complete, change state to reject any
+     * subsequent client-initated renegotiation. */
+    else if (where & SSL_CB_HANDSHAKE_DONE &&
+                       scr->reneg_state == RENEG_INIT) {
+        scr->reneg_state = RENEG_REJECT;
+    }

And we then check this state on every read/write in the bio read/write 
callbacks:

  static int bio_filter_out_write/read(BIO *bio, const char *in, int inl)
  {
      bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);

+    /* Abort early if the client has initiated a renegotiation. */
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        outctx->rc = APR_ECONNABORTED;
+        return -1;
+    }

So it owuld be useful to have confirmed from the OpenSSL experts that 
this gives is visibility of each and every stage change.

And then we're good.

Dw.



Index: ssl_private.h
===================================================================
--- ssl_private.h	(revision 832979)
+++ ssl_private.h	(working copy)
@@ -335,6 +335,20 @@
      int is_proxy;
      int disabled;
      int non_ssl_request;
+
+    /* Track the handshake/renegotiation state for the connection so
+     * that all client-initiated renegotiations can be rejected, as a
+     * partial fix for CVE-2009-3555. */
+    enum {
+        RENEG_INIT = 0, /* Before initial handshake */
+        RENEG_REJECT, /* After initial handshake; any client-initiated
+                       * renegotiation should be rejected */
+        RENEG_ALLOW, /* A server-initated renegotiation is taking
+                      * place (as dictated by configuration) */
+        RENEG_ABORT /* Renegotiation initiated by client, abort the
+                     * connection */
+    } reneg_state;
+
      server_rec *server;
  } SSLConnRec;

@@ -618,7 +632,7 @@
  int          ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
  SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, 
int, int *);
  void         ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
-void         ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, 
int);
+void         ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int);
  #ifndef OPENSSL_NO_TLSEXT
  int          ssl_callback_ServerNameIndication(SSL *, int *, 
modssl_ctx_t *);
  #endif
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c	(revision 832979)
+++ ssl_engine_init.c	(working copy)
@@ -520,10 +520,7 @@
      SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
      SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);

-    if (s->loglevel >= APLOG_DEBUG) {
-        /* this callback only logs if LogLevel >= info */
-        SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
-    }
+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
  }

  static void ssl_init_ctx_verify(server_rec *s,
Index: ssl_engine_io.c
===================================================================
--- ssl_engine_io.c	(revision 832979)
+++ ssl_engine_io.c	(working copy)
@@ -103,6 +103,7 @@
      ap_filter_t        *pInputFilter;
      ap_filter_t        *pOutputFilter;
      int                nobuffer; /* non-zero to prevent buffering */
+    SSLConnRec         *config;
  } ssl_filter_ctx_t;

  typedef struct {
@@ -193,7 +194,13 @@
  static int bio_filter_out_write(BIO *bio, const char *in, int inl)
  {
      bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
-
+
+    /* Abort early if the client has initiated a renegotiation. */
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        outctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+
      /* when handshaking we'll have a small number of bytes.
       * max size SSL will pass us here is about 16k.
       * (16413 bytes to be exact)
@@ -476,6 +483,12 @@
      if (!in)
          return 0;

+    /* Abort early if the client has initiated a renegotiation. */
+    if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        inctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+
      /* In theory, OpenSSL should flush as necessary, but it is known
       * not to do so correctly in some cases; see PR 46952.
       *
@@ -1699,6 +1712,8 @@

      filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t));

+    filter_ctx->config          = myConnConfig(c);
+
      filter_ctx->nobuffer        = 0;
      filter_ctx->pOutputFilter   = ap_add_output_filter(ssl_io_filter,
                                                         filter_ctx, r, c);
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c	(revision 832979)
+++ ssl_engine_kernel.c	(working copy)
@@ -733,6 +733,10 @@
                                         (unsigned char *)&id,
                                         sizeof(id));

+            /* Toggle the renegotiation state to allow the new
+             * handshake to proceed. */
+            sslconn->reneg_state = RENEG_ALLOW;
+
              SSL_renegotiate(ssl);
              SSL_do_handshake(ssl);

@@ -754,6 +758,8 @@
              SSL_set_state(ssl, SSL_ST_ACCEPT);
              SSL_do_handshake(ssl);

+            sslconn->reneg_state = RENEG_REJECT;
+
              if (SSL_get_state(ssl) != SSL_ST_OK) {
                  ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                                "Re-negotiation handshake failed: "
@@ -1814,76 +1820,55 @@
      return;
  }

-/*
- * This callback function is executed while OpenSSL processes the
- * SSL handshake and does SSL record layer stuff. We use it to
- * trace OpenSSL's processing in out SSL logfile.
- */
-void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int 
where, int rc)
+/* Dump debugginfo trace to the log file. */
+static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, server_rec *s,
+                              conn_rec *c, int where, int rc)
  {
-    conn_rec *c;
-    server_rec *s;
-    SSLSrvConfigRec *sc;
-
      /*
-     * find corresponding server
+     * create the various trace messages
       */
-    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
-        return;
+    if (where & SSL_CB_HANDSHAKE_START) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: start", SSL_LIBRARY_NAME);
      }
-
-    s = mySrvFromConn(c);
-    if (!(sc = mySrvConfig(s))) {
-        return;
+    else if (where & SSL_CB_HANDSHAKE_DONE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: done", SSL_LIBRARY_NAME);
      }
-
-    /*
-     * create the various trace messages
-     */
-    if (s->loglevel >= APLOG_DEBUG) {
-        if (where & SSL_CB_HANDSHAKE_START) {
+    else if (where & SSL_CB_LOOP) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Loop: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_READ) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Read: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_WRITE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Write: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_ALERT) {
+        char *str = (where & SSL_CB_READ) ? "read" : "write";
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Alert: %s:%s:%s",
+                     SSL_LIBRARY_NAME, str,
+                     SSL_alert_type_string_long(rc),
+                     SSL_alert_desc_string_long(rc));
+    }
+    else if (where & SSL_CB_EXIT) {
+        if (rc == 0) {
              ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: start", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_HANDSHAKE_DONE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: done", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_LOOP) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Loop: %s",
+                         "%s: Exit: failed in %s",
                           SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
          }
-        else if (where & SSL_CB_READ) {
+        else if (rc < 0) {
              ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Read: %s",
+                         "%s: Exit: error in %s",
                           SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
          }
-        else if (where & SSL_CB_WRITE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Write: %s",
-                         SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-        }
-        else if (where & SSL_CB_ALERT) {
-            char *str = (where & SSL_CB_READ) ? "read" : "write";
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Alert: %s:%s:%s",
-                         SSL_LIBRARY_NAME, str,
-                         SSL_alert_type_string_long(rc),
-                         SSL_alert_desc_string_long(rc));
-        }
-        else if (where & SSL_CB_EXIT) {
-            if (rc == 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: failed in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-            else if (rc < 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: error in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-        }
      }

      /*
@@ -1903,6 +1888,60 @@
      }
  }

+/*
+ * This callback function is executed while OpenSSL processes the SSL
+ * handshake and does SSL record layer stuff.  It's used to trap
+ * client-initiated renegotiations, and for dumping everything to the
+ * log.
+ */
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+{
+    conn_rec *c;
+    server_rec *s;
+    SSLSrvConfigRec *sc;
+    SSLConnRec *scr;
+
+    /*
+     * find corresponding server
+     */
+    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
+        return;
+    }
+
+    scr = myConnConfig(c);
+    if (!scr) {
+        return;
+    }
+
+    /* If the reneg state is to reject renegotiations, check the SSL
+     * state machine and move to ABORT if a Client Hello is being
+     * read. */
+    if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) {
+        int state = SSL_get_state(ssl);
+
+        if (state == SSL3_ST_SR_CLNT_HELLO_A
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
+            scr->reneg_state = RENEG_ABORT;
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
+                          "rejecting client initiated renegotiation");
+        }
+    }
+    /* If the first handshake is complete, change state to reject any
+     * subsequent client-initated renegotiation. */
+    else if (where & SSL_CB_HANDSHAKE_DONE && scr->reneg_state == 
RENEG_INIT) {
+        scr->reneg_state = RENEG_REJECT;
+    }
+
+    s = mySrvFromConn(c);
+    if (!(sc = mySrvConfig(s))) {
+        return;
+    }
+
+    if (s->loglevel >= APLOG_DEBUG) {
+        log_tracing_state(ssl, s, c, where, rc);
+    }
+}
+
  #ifndef OPENSSL_NO_TLSEXT
  /*
   * This callback function is executed when OpenSSL encounters an extended


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Wed, Jan 27, 2010 at 10:41:02PM +0000, Dr Stephen Henson wrote:
> FYI the initial documentation is here:
> 
> http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html#SECURE_RENEGOTIATION
> 
> there are currently only two flags to set in an SSL/SSL_CTX structure. Though
> servers might want to make use of SSL_get_secure_renegotiation_support() too.

Thanks a lot for doing all that work!

I've added an "SSLInsecureRenegotiation" directive which will flip that 
flag on, here: http://svn.apache.org/viewvc?rev=906039&view=rev

It seems to all work as expected with 1.0.0 beta 5.

Regards, Joe

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Dr Stephen Henson <sh...@oss-institute.org>.
fredk2 wrote:
> Hi,
> 
> 
> Joe Orton wrote:
>> On Tue, Nov 10, 2009 at 03:19:39PM +0100, Jean-Marc Desperrier wrote:
>>> Joe Orton wrote:
>>>> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
>>>>>>  On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
>>>>>>>  >  * we can detect in mod_ssl when the client is renegotiating by
>>>>>> using the
>>>>>>>  >  callback installed using SSL_CTX_set_info_callback(), in
>>>>>> conjunction
>>>>>>>  >  with suitable flags in the SSLConnRec to detect the cases where
>>>>>> this is
>>>>>>>  >  either a server-initiated renegotiation or the initial handshake
>>>>>> on the
>>>>>>>  >  connection.
>>>>>>  Here is a very rough first hack (for discussion/testing purposes
>>>>> only!):
>>>> A second hack, slightly less rough hack:
>>> Joe, instead of hard coding this, a very nice solution would be to have  
>>> a new directive "SSLServerRenegociation Allow" or even more flexible  
>>> "SSLRenegociation disabled/serveronly/enabled" with disabled as default  
>>> value.
>> Yes, sure.  What is possible in mod_ssl will depend on what interfaces 
>> OpenSSL will expose for this, which is not yet clear.
>>
>> Regards, Joe
>>
>>
> 
> Now that 0.9.8m-beta1 is available, what is likely to happen with Apache
> 2.2.15?
> I looked at the svn tree, but I could not see if anyone was working on
> adding this excellent idea for a new directive SSLRenegociation
> disabled/serveronly/enabled.
> If the server does not require renegotiation it seems perfect if the apache
> closed the connection upon receipt of the R instead of the current 5 min
> (default) timeout wait.
> 

FYI the initial documentation is here:

http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html#SECURE_RENEGOTIATION

there are currently only two flags to set in an SSL/SSL_CTX structure. Though
servers might want to make use of SSL_get_secure_renegotiation_support() too.

Steve.
-- 
Dr Stephen N. Henson. Senior Technical/Cryptography Advisor,
Open Source Software Institute: www.oss-institute.org
OpenSSL Core team: www.openssl.org

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by fredk2 <fr...@gmail.com>.
Hi,


Joe Orton wrote:
> 
> On Tue, Nov 10, 2009 at 03:19:39PM +0100, Jean-Marc Desperrier wrote:
>> Joe Orton wrote:
>>> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
>>>> >  On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
>>>>> >  >  * we can detect in mod_ssl when the client is renegotiating by
>>>>> using the
>>>>> >  >  callback installed using SSL_CTX_set_info_callback(), in
>>>>> conjunction
>>>>> >  >  with suitable flags in the SSLConnRec to detect the cases where
>>>>> this is
>>>>> >  >  either a server-initiated renegotiation or the initial handshake
>>>>> on the
>>>>> >  >  connection.
>>>> >
>>>> >  Here is a very rough first hack (for discussion/testing purposes
>>>> only!):
>>> A second hack, slightly less rough hack:
>>
>> Joe, instead of hard coding this, a very nice solution would be to have  
>> a new directive "SSLServerRenegociation Allow" or even more flexible  
>> "SSLRenegociation disabled/serveronly/enabled" with disabled as default  
>> value.
> 
> Yes, sure.  What is possible in mod_ssl will depend on what interfaces 
> OpenSSL will expose for this, which is not yet clear.
> 
> Regards, Joe
> 
> 

Now that 0.9.8m-beta1 is available, what is likely to happen with Apache
2.2.15?
I looked at the svn tree, but I could not see if anyone was working on
adding this excellent idea for a new directive SSLRenegociation
disabled/serveronly/enabled.
If the server does not require renegotiation it seems perfect if the apache
closed the connection upon receipt of the R instead of the current 5 min
(default) timeout wait.

Thank you - Fred
-- 
View this message in context: http://old.nabble.com/TLS-renegotiation-attack%2C-mod_ssl-and-OpenSSL-tp26215127p27328884.html
Sent from the Apache HTTP Server - Dev mailing list archive at Nabble.com.


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Tue, Nov 10, 2009 at 03:19:39PM +0100, Jean-Marc Desperrier wrote:
> Joe Orton wrote:
>> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
>>> >  On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
>>>> >  >  * we can detect in mod_ssl when the client is renegotiating by using the
>>>> >  >  callback installed using SSL_CTX_set_info_callback(), in conjunction
>>>> >  >  with suitable flags in the SSLConnRec to detect the cases where this is
>>>> >  >  either a server-initiated renegotiation or the initial handshake on the
>>>> >  >  connection.
>>> >
>>> >  Here is a very rough first hack (for discussion/testing purposes only!):
>> A second hack, slightly less rough hack:
>
> Joe, instead of hard coding this, a very nice solution would be to have  
> a new directive "SSLServerRenegociation Allow" or even more flexible  
> "SSLRenegociation disabled/serveronly/enabled" with disabled as default  
> value.

Yes, sure.  What is possible in mod_ssl will depend on what interfaces 
OpenSSL will expose for this, which is not yet clear.

Regards, Joe

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Jean-Marc Desperrier <jm...@free.fr>.
Joe Orton wrote:
> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
>> >  On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
>>> >  >  * we can detect in mod_ssl when the client is renegotiating by using the
>>> >  >  callback installed using SSL_CTX_set_info_callback(), in conjunction
>>> >  >  with suitable flags in the SSLConnRec to detect the cases where this is
>>> >  >  either a server-initiated renegotiation or the initial handshake on the
>>> >  >  connection.
>> >
>> >  Here is a very rough first hack (for discussion/testing purposes only!):
> A second hack, slightly less rough hack:

Joe, instead of hard coding this, a very nice solution would be to have 
a new directive "SSLServerRenegociation Allow" or even more flexible 
"SSLRenegociation disabled/serveronly/enabled" with disabled as default 
value.

This would allow sites that need server renegotiation to make it quite 
more secure, by using a strategy similar to what is suggested here :
https://issues.apache.org/bugzilla/show_bug.cgi?id=39243#c7
"The obvious answer for an 'upload' style operation is to ensure they 
never hit your upload page without going through a simpler front page 
which first enforces the renegotation.  This can be your upload form page."

So the server would first direct the user to a "SSLRenegociation 
serveronly" page that is conceived so that request to it can not be 
abused, and use "SSLRenegociation enabled" for all unsafe locations, the 
user accessing them only when his connection has already been upgraded 
to use client certs (this is similar to what Peter suggested already).

The only weak point in that solution is that Apache seems to require 
renegotiation in quite a few case where it should not be really 
necessary. But as any case of Apache requiring renegotiation will break 
anyone using the more radical option of fully disabling renegotiation 
I'll open a separate message for this.

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
> On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
> > * we can detect in mod_ssl when the client is renegotiating by using the 
> > callback installed using SSL_CTX_set_info_callback(), in conjunction 
> > with suitable flags in the SSLConnRec to detect the cases where this is 
> > either a server-initiated renegotiation or the initial handshake on the 
> > connection.
> 
> Here is a very rough first hack (for discussion/testing purposes only!):

A second hack, slightly less rough hack:

Index: ssl_private.h
===================================================================
--- ssl_private.h	(revision 832979)
+++ ssl_private.h	(working copy)
@@ -335,6 +335,20 @@
     int is_proxy;
     int disabled;
     int non_ssl_request;
+
+    /* Track the handshake/renegotiation state for the connection so
+     * that all client-initiated renegotiations can be rejected, as a
+     * partial fix for CVE-2009-3555. */
+    enum { 
+        RENEG_INIT = 0, /* Before initial handshake */
+        RENEG_REJECT, /* After initial handshake; any client-initiated
+                       * renegotiation should be rejected */
+        RENEG_ALLOW, /* A server-initated renegotiation is taking
+                      * place (as dictated by configuration) */
+        RENEG_ABORT /* Renegotiation initiated by client, abort the
+                     * connection */
+    } reneg_state;
+    
     server_rec *server;
 } SSLConnRec;
 
@@ -618,7 +632,7 @@
 int          ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
 SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *);
 void         ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
-void         ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, int);
+void         ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int);
 #ifndef OPENSSL_NO_TLSEXT
 int          ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
 #endif
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c	(revision 832979)
+++ ssl_engine_init.c	(working copy)
@@ -520,10 +520,7 @@
     SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
 
-    if (s->loglevel >= APLOG_DEBUG) {
-        /* this callback only logs if LogLevel >= info */
-        SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
-    }
+    SSL_CTX_set_info_callback(ctx, ssl_callback_Info);
 }
 
 static void ssl_init_ctx_verify(server_rec *s,
Index: ssl_engine_io.c
===================================================================
--- ssl_engine_io.c	(revision 832979)
+++ ssl_engine_io.c	(working copy)
@@ -103,6 +103,7 @@
     ap_filter_t        *pInputFilter;
     ap_filter_t        *pOutputFilter;
     int                nobuffer; /* non-zero to prevent buffering */
+    SSLConnRec         *config;
 } ssl_filter_ctx_t;
 
 typedef struct {
@@ -193,7 +194,13 @@
 static int bio_filter_out_write(BIO *bio, const char *in, int inl)
 {
     bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
-
+    
+    /* Abort early if the client has initiated a renegotiation. */
+    if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        outctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+    
     /* when handshaking we'll have a small number of bytes.
      * max size SSL will pass us here is about 16k.
      * (16413 bytes to be exact)
@@ -476,6 +483,12 @@
     if (!in)
         return 0;
 
+    /* Abort early if the client has initiated a renegotiation. */
+    if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
+        inctx->rc = APR_ECONNABORTED;
+        return -1;
+    }
+
     /* In theory, OpenSSL should flush as necessary, but it is known
      * not to do so correctly in some cases; see PR 46952.
      *
@@ -1699,6 +1712,8 @@
 
     filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t));
 
+    filter_ctx->config          = myConnConfig(c);
+
     filter_ctx->nobuffer        = 0;
     filter_ctx->pOutputFilter   = ap_add_output_filter(ssl_io_filter,
                                                        filter_ctx, r, c);
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c	(revision 832979)
+++ ssl_engine_kernel.c	(working copy)
@@ -733,6 +733,10 @@
                                        (unsigned char *)&id,
                                        sizeof(id));
 
+            /* Toggle the renegotiation state to allow the new
+             * handshake to proceed. */
+            sslconn->reneg_state = RENEG_ALLOW;
+            
             SSL_renegotiate(ssl);
             SSL_do_handshake(ssl);
 
@@ -754,6 +758,8 @@
             SSL_set_state(ssl, SSL_ST_ACCEPT);
             SSL_do_handshake(ssl);
 
+            sslconn->reneg_state = RENEG_REJECT;
+
             if (SSL_get_state(ssl) != SSL_ST_OK) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "Re-negotiation handshake failed: "
@@ -1814,76 +1820,55 @@
     return;
 }
 
-/*
- * This callback function is executed while OpenSSL processes the
- * SSL handshake and does SSL record layer stuff. We use it to
- * trace OpenSSL's processing in out SSL logfile.
- */
-void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+/* Dump debugginfo trace to the log file. */
+static void log_tracing_state(MODSSL_INFO_CB_ARG_TYPE ssl, server_rec *s,
+                              conn_rec *c, int where, int rc)
 {
-    conn_rec *c;
-    server_rec *s;
-    SSLSrvConfigRec *sc;
-
     /*
-     * find corresponding server
+     * create the various trace messages
      */
-    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
-        return;
+    if (where & SSL_CB_HANDSHAKE_START) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: start", SSL_LIBRARY_NAME);
     }
-
-    s = mySrvFromConn(c);
-    if (!(sc = mySrvConfig(s))) {
-        return;
+    else if (where & SSL_CB_HANDSHAKE_DONE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Handshake: done", SSL_LIBRARY_NAME);
     }
-
-    /*
-     * create the various trace messages
-     */
-    if (s->loglevel >= APLOG_DEBUG) {
-        if (where & SSL_CB_HANDSHAKE_START) {
+    else if (where & SSL_CB_LOOP) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Loop: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_READ) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Read: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_WRITE) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Write: %s",
+                     SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
+    }
+    else if (where & SSL_CB_ALERT) {
+        char *str = (where & SSL_CB_READ) ? "read" : "write";
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "%s: Alert: %s:%s:%s",
+                     SSL_LIBRARY_NAME, str,
+                     SSL_alert_type_string_long(rc),
+                     SSL_alert_desc_string_long(rc));
+    }
+    else if (where & SSL_CB_EXIT) {
+        if (rc == 0) {
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: start", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_HANDSHAKE_DONE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Handshake: done", SSL_LIBRARY_NAME);
-        }
-        else if (where & SSL_CB_LOOP) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Loop: %s",
+                         "%s: Exit: failed in %s",
                          SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
         }
-        else if (where & SSL_CB_READ) {
+        else if (rc < 0) {
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Read: %s",
+                         "%s: Exit: error in %s",
                          SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
         }
-        else if (where & SSL_CB_WRITE) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Write: %s",
-                         SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-        }
-        else if (where & SSL_CB_ALERT) {
-            char *str = (where & SSL_CB_READ) ? "read" : "write";
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                         "%s: Alert: %s:%s:%s",
-                         SSL_LIBRARY_NAME, str,
-                         SSL_alert_type_string_long(rc),
-                         SSL_alert_desc_string_long(rc));
-        }
-        else if (where & SSL_CB_EXIT) {
-            if (rc == 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: failed in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-            else if (rc < 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                             "%s: Exit: error in %s",
-                             SSL_LIBRARY_NAME, SSL_state_string_long(ssl));
-            }
-        }
     }
 
     /*
@@ -1903,6 +1888,60 @@
     }
 }
 
+/*
+ * This callback function is executed while OpenSSL processes the SSL
+ * handshake and does SSL record layer stuff.  It's used to trap
+ * client-initiated renegotiations, and for dumping everything to the
+ * log.
+ */
+void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc)
+{
+    conn_rec *c;
+    server_rec *s;
+    SSLSrvConfigRec *sc;
+    SSLConnRec *scr;
+
+    /*
+     * find corresponding server
+     */
+    if (!(c = (conn_rec *)SSL_get_app_data((SSL *)ssl))) {
+        return;
+    }
+
+    scr = myConnConfig(c);
+    if (!scr) {
+        return;
+    }
+
+    /* If the reneg state is to reject renegotiations, check the SSL
+     * state machine and move to ABORT if a Client Hello is being
+     * read. */
+    if ((where & SSL_CB_ACCEPT_LOOP) && scr->reneg_state == RENEG_REJECT) {
+        int state = SSL_get_state(ssl);
+        
+        if (state == SSL3_ST_SR_CLNT_HELLO_A 
+            || state == SSL23_ST_SR_CLNT_HELLO_A) {
+            scr->reneg_state = RENEG_ABORT;
+            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
+                          "rejecting client initiated renegotiation");
+        }
+    }
+    /* If the first handshake is complete, change state to reject any
+     * subsequent client-initated renegotiation. */
+    else if (where & SSL_CB_HANDSHAKE_DONE && scr->reneg_state == RENEG_INIT) {
+        scr->reneg_state = RENEG_REJECT;
+    }
+
+    s = mySrvFromConn(c);
+    if (!(sc = mySrvConfig(s))) {
+        return;
+    }
+   
+    if (s->loglevel >= APLOG_DEBUG) {
+        log_tracing_state(ssl, s, c, where, rc);
+    }
+}
+
 #ifndef OPENSSL_NO_TLSEXT
 /*
  * This callback function is executed when OpenSSL encounters an extended


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Rainer Jung <ra...@kippdata.de>.
On 06.11.2009 01:12, Joe Orton wrote:
> On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
> FYI - Dirk points out that you can test this using openssl s_client by 
> entering a line with the single character 'R' which s_client treats as a 
> command to initiate a renegotiation.   Joe
> 
> $ openssl s_client ...
> ---
> GET / HTTP/1.1
> Host: localhost
> R
> RENEGOTIATING
> 139919233795736:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:590:

Not sure if everyone is aware:

http://extendedsubset.com/Renegotiating_TLS.pdf

contains such an exposure example using s_client.

Eric Rescorla also explained some more details a few hours ago:

http://www.educatedguesswork.org/2009/11/understanding_the_tls_renegoti.html

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Fri, Nov 06, 2009 at 12:00:06AM +0000, Joe Orton wrote:
> On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
> > * we can detect in mod_ssl when the client is renegotiating by using the 
> > callback installed using SSL_CTX_set_info_callback(), in conjunction 
> > with suitable flags in the SSLConnRec to detect the cases where this is 
> > either a server-initiated renegotiation or the initial handshake on the 
> > connection.
> 
> Here is a very rough first hack (for discussion/testing purposes only!):

FYI - Dirk points out that you can test this using openssl s_client by 
entering a line with the single character 'R' which s_client treats as a 
command to initiate a renegotiation.   Joe

$ openssl s_client ...
---
GET / HTTP/1.1
Host: localhost
R
RENEGOTIATING
139919233795736:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:590:


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Thu, Nov 05, 2009 at 09:31:00PM +0000, Joe Orton wrote:
> * we can detect in mod_ssl when the client is renegotiating by using the 
> callback installed using SSL_CTX_set_info_callback(), in conjunction 
> with suitable flags in the SSLConnRec to detect the cases where this is 
> either a server-initiated renegotiation or the initial handshake on the 
> connection.

Here is a very rough first hack (for discussion/testing purposes only!):

Index: ssl_private.h
===================================================================
--- ssl_private.h	(revision 832979)
+++ ssl_private.h	(working copy)
@@ -335,6 +335,14 @@
     int is_proxy;
     int disabled;
     int non_ssl_request;
+    enum { 
+        RENEG_INIT = 0, /* before initial handshake. */
+        RENEG_ALLOW, /* a server-initated renegotiation is taking place */
+        RENEG_REJECT, /* after initial handshake; any client-initiated
+                       * renegotiation should be rejected. */
+        RENEG_ABORT /* renegotiation initiated by client, abort abort */
+    } reneg_state;
+    
     server_rec *server;
 } SSLConnRec;
 
Index: ssl_engine_init.c
===================================================================
--- ssl_engine_init.c	(revision 832979)
+++ ssl_engine_init.c	(working copy)
@@ -520,7 +520,7 @@
     SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA);
     SSL_CTX_set_tmp_dh_callback(ctx,  ssl_callback_TmpDH);
 
-    if (s->loglevel >= APLOG_DEBUG) {
+    if (1 || s->loglevel >= APLOG_DEBUG) {
         /* this callback only logs if LogLevel >= info */
         SSL_CTX_set_info_callback(ctx, ssl_callback_LogTracingState);
     }
Index: ssl_engine_io.c
===================================================================
--- ssl_engine_io.c	(revision 832979)
+++ ssl_engine_io.c	(working copy)
@@ -190,10 +190,27 @@
     return -1;
 }
 
+static int conn_in_reneg(conn_rec *c)
+{
+    SSLConnRec *scr = myConnConfig(c);
+    
+    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+                  "reneg_state == %s", scr->reneg_state == RENEG_INIT ? "INIT" :
+                  scr->reneg_state == RENEG_REJECT ? "REJECT" :
+                  scr->reneg_state == RENEG_ALLOW ? "ALLOW" : "ABORT");
+
+    return scr->reneg_state == RENEG_ABORT;
+}
+
 static int bio_filter_out_write(BIO *bio, const char *in, int inl)
 {
     bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
-
+    
+    if (conn_in_reneg(outctx->c)) {
+        outctx->rc = APR_EACCES;
+        return -1;
+    }
+    
     /* when handshaking we'll have a small number of bytes.
      * max size SSL will pass us here is about 16k.
      * (16413 bytes to be exact)
@@ -476,6 +493,11 @@
     if (!in)
         return 0;
 
+    if (conn_in_reneg(inctx->f->c)) {
+        inctx->rc = APR_EACCES;
+        return -1;
+    }
+
     /* In theory, OpenSSL should flush as necessary, but it is known
      * not to do so correctly in some cases; see PR 46952.
      *
Index: ssl_engine_kernel.c
===================================================================
--- ssl_engine_kernel.c	(revision 832979)
+++ ssl_engine_kernel.c	(working copy)
@@ -733,6 +733,8 @@
                                        (unsigned char *)&id,
                                        sizeof(id));
 
+            sslconn->reneg_state = RENEG_ALLOW;
+            
             SSL_renegotiate(ssl);
             SSL_do_handshake(ssl);
 
@@ -754,6 +756,8 @@
             SSL_set_state(ssl, SSL_ST_ACCEPT);
             SSL_do_handshake(ssl);
 
+            sslconn->reneg_state = RENEG_REJECT;
+
             if (SSL_get_state(ssl) != SSL_ST_OK) {
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                               "Re-negotiation handshake failed: "
@@ -1824,7 +1828,8 @@
     conn_rec *c;
     server_rec *s;
     SSLSrvConfigRec *sc;
-
+    SSLConnRec *scr;
+    
     /*
      * find corresponding server
      */
@@ -1837,6 +1842,18 @@
         return;
     }
 
+    scr = myConnConfig(c);
+
+    {
+        int state = SSL_get_state(ssl);
+        
+        if (scr->reneg_state == RENEG_REJECT
+            && (state == SSL3_ST_SR_CLNT_HELLO_A
+                || state == SSL23_ST_SR_CLNT_HELLO_A)) {
+            scr->reneg_state = RENEG_ABORT;
+        }
+    }
+    
     /*
      * create the various trace messages
      */
@@ -1900,6 +1917,9 @@
                      ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER"),
                      ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_USEKEYSIZE"),
                      ssl_var_lookup(NULL, s, c, NULL, "SSL_CIPHER_ALGKEYSIZE"));
+        if (scr->reneg_state == RENEG_INIT) {
+            scr->reneg_state = RENEG_REJECT;
+        }
     }
 }
 

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Thu, Nov 05, 2009 at 09:38:23PM +0100, Ruediger Pluem wrote:
> If server triggered renegotiation will not work at all, people will just ignore the
> update or remove it from 0.9.8l in their self patched versions.
> So overall I guess we would be safer with an approach that
> 
> 1. Turns off renegotiation (server and client) by default.
> 2. Allows to turn on server and client triggered renegotiation in a way as proposed
>    by Joe.
> 3. Allow to turn on server triggered renegotiation by a compile time option.

In discussion here, Theo Schlossnagle has suggested (and implemented for 
another SSL server) an approach for (2) which I think we can use for 
mod_ssl, and doesn't require patching OpenSSL:

* we can detect in mod_ssl when the client is renegotiating by using the 
callback installed using SSL_CTX_set_info_callback(), in conjunction 
with suitable flags in the SSLConnRec to detect the cases where this is 
either a server-initiated renegotiation or the initial handshake on the 
connection.

I'll try a patch for this.

Regards, Joe

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Ruediger Pluem <rp...@apache.org>.

On 11/05/2009 06:32 PM, Joe Orton wrote:
> On Thu, Nov 05, 2009 at 03:39:06PM +0000, Ben Laurie wrote:
>> Joe Orton wrote:
>>> In the short term, I think it would be useful to have a new SSL_OP_* 
>>> flag which enables rejection of a client-initiated handshake in an SSL 
>>> server.  This will fix the issue for 90% of sites without breaking the 
>>> remaining 10% (case 3 above), and is a change that can be deployed 
>>> everywhere.
>> Case 3 is vulnerable to attack, though, so I'm afraid you want to break it.
> 
> Sites depend on per-dir-reneg and people will simply not upgrade if we 
> break that - I have tried the "don't do that" response for per-dir-reneg 
> issues enough times over the years that I'm reasonably confident of 
> this.  (Also I'm told that the Postgres SSL support depends on being 
> able to do a periodic reneg, in the wider context)
> 
> Being able to ship a 90% solution now and working on the proper fixes 
> for the remaining 10% is valuable, I think.

I agree with Joe here. See the lengthy discussions we had regarding POST bodies
handling in mod_ssl during renegotiation at

https://issues.apache.org/bugzilla/show_bug.cgi?id=12355
https://issues.apache.org/bugzilla/show_bug.cgi?id=39243

If server triggered renegotiation will not work at all, people will just ignore the
update or remove it from 0.9.8l in their self patched versions.
So overall I guess we would be safer with an approach that

1. Turns off renegotiation (server and client) by default.
2. Allows to turn on server and client triggered renegotiation in a way as proposed
   by Joe.
3. Allow to turn on server triggered renegotiation by a compile time option.

1. This way openssl ships save by default.
2. Consumers of the library can decide to overwrite this behaviour.
3. Packagers can decide to deliver only a "90%" solution if they do not want / cannot
   modify all consumer packages that need server triggered renegotiation.

Some of the attacks rely on specific HTTP mechanisms like connection keep alives and
pipelining. So we might be able to find patches for mod_ssl to solve these specific
cases.

Regards

Rüdiger

Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Joe Orton <jo...@redhat.com>.
On Thu, Nov 05, 2009 at 03:39:06PM +0000, Ben Laurie wrote:
> Joe Orton wrote:
> > In the short term, I think it would be useful to have a new SSL_OP_* 
> > flag which enables rejection of a client-initiated handshake in an SSL 
> > server.  This will fix the issue for 90% of sites without breaking the 
> > remaining 10% (case 3 above), and is a change that can be deployed 
> > everywhere.
> 
> Case 3 is vulnerable to attack, though, so I'm afraid you want to break it.

Sites depend on per-dir-reneg and people will simply not upgrade if we 
break that - I have tried the "don't do that" response for per-dir-reneg 
issues enough times over the years that I'm reasonably confident of 
this.  (Also I'm told that the Postgres SSL support depends on being 
able to do a periodic reneg, in the wider context)

Being able to ship a 90% solution now and working on the proper fixes 
for the remaining 10% is valuable, I think.

Regards, Joe


Re: TLS renegotiation attack, mod_ssl and OpenSSL

Posted by Ben Laurie <be...@links.org>.
Joe Orton wrote:
> With reference to the issue described here:
> 
> http://www.ietf.org/mail-archive/web/tls/current/msg03948.html
> 
> Considering the impact on mod_ssl, I'm making these assumptions:
> 
> 1. no HTTP/SSL client initiates a renegotiation of its own accord
> 
> 2. many mod_ssl configurations do not require a renegotiation to be 
> performed at all
> 
> 3. some mod_ssl configurations, typically requiring client cert auth in 
> a per-directory/location context, do require the server to initiate a 
> renegotiation.
> 
> The longer term plan to fix the vulnerability is to upgrade all clients 
> and servers to support a new TLS extension which allows renegotiations 
> to be performed securely.
> 
> Disabling renegotiation completely and unconditionally at SSL toolkit 
> level will break a significant number of installs - I don't think we 
> could deploy that change.  
> 
> In the short term, I think it would be useful to have a new SSL_OP_* 
> flag which enables rejection of a client-initiated handshake in an SSL 
> server.  This will fix the issue for 90% of sites without breaking the 
> remaining 10% (case 3 above), and is a change that can be deployed 
> everywhere.

Case 3 is vulnerable to attack, though, so I'm afraid you want to break it.

-- 
http://www.apache-ssl.org/ben.html           http://www.links.org/

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff