Re: [HACKERS] SSL renegotiation

2015-03-23 Thread Florian Weimer
On 02/23/2015 04:01 PM, Albe Laurenz wrote:

 I think you could remove renegotiation from PostgreSQL as long as you
 offer something better than RC4 in the TLS handshake.
 
 I'd say it is best to wait if and how OpenSSL change their API when they
 implement TLS 1.3.
 
 I'd vote against removing renegotiation.

I'm just suggesting that the effort required to fix bugs in this part of
PostgreSQL could be spent better elsewhere.

 If changing the encryption is so useless, whe did the TLS workgroup
 decide to introduce rekeying as a substitute for renegotiation?

Theoretical considerations, mostly.  If rekeying is strictly required
after processing just a few petabytes, the cipher is severely broken and
should no longer be used.

-- 
Florian Weimer / Red Hat Product Security


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2015-02-23 Thread Florian Weimer
On 02/22/2015 02:05 PM, Andres Freund wrote:
 On 2015-02-22 01:27:54 +0100, Emil Lenngren wrote:
 I honestly wonder why postgres uses renegotiation at all. The motivation
 that cryptoanalysis is easier as more data is sent seems quite
 far-fetched.
 
 I don't think so. There's a fair number of algorithms that can/could be
 much easier be attached with lots of data available. Especially if you
 can guess/know/control some of the data.  Additionally renegotiating
 regularly helps to constrain a possible key leagage to a certain amount
 of time. With backend connections often being alive for weeks at a time
 that's not a bad thing.

Renegotiation will be removed from future TLS versions because it is
considered unnecessary with modern ciphers:

  https://github.com/tlswg/tls13-spec/issues/38

If ciphers require rekeying, that mechanism will be provided at the TLS
layer in the future.

I think you could remove renegotiation from PostgreSQL as long as you
offer something better than RC4 in the TLS handshake.

-- 
Florian Weimer / Red Hat Product Security


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2015-02-23 Thread Albe Laurenz
Florian Weimer wrote:
 On 02/22/2015 02:05 PM, Andres Freund wrote:
 On 2015-02-22 01:27:54 +0100, Emil Lenngren wrote:
 I honestly wonder why postgres uses renegotiation at all. The motivation
 that cryptoanalysis is easier as more data is sent seems quite
 far-fetched.

 I don't think so. There's a fair number of algorithms that can/could be
 much easier be attached with lots of data available. Especially if you
 can guess/know/control some of the data.  Additionally renegotiating
 regularly helps to constrain a possible key leagage to a certain amount
 of time. With backend connections often being alive for weeks at a time
 that's not a bad thing.
 
 Renegotiation will be removed from future TLS versions because it is
 considered unnecessary with modern ciphers:
 
   https://github.com/tlswg/tls13-spec/issues/38
 
 If ciphers require rekeying, that mechanism will be provided at the TLS
 layer in the future.
 
 I think you could remove renegotiation from PostgreSQL as long as you
 offer something better than RC4 in the TLS handshake.

I'd say it is best to wait if and how OpenSSL change their API when they
implement TLS 1.3.

I'd vote against removing renegotiation.  At the very least, if the feature
should provide unnecessary and cumbersome with future versions of OpenSSL,
we should retain ssl_renegotiation_limit and change the default to 0.
It might still be of value with older versions.

If changing the encryption is so useless, whe did the TLS workgroup
decide to introduce rekeying as a substitute for renegotiation?

Yours,
Laurenz Albe

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2015-02-23 Thread Andres Freund
On 2015-02-23 15:15:31 +0100, Florian Weimer wrote:
 On 02/22/2015 02:05 PM, Andres Freund wrote:
  On 2015-02-22 01:27:54 +0100, Emil Lenngren wrote:
  I honestly wonder why postgres uses renegotiation at all. The motivation
  that cryptoanalysis is easier as more data is sent seems quite
  far-fetched.
  
  I don't think so. There's a fair number of algorithms that can/could be
  much easier be attached with lots of data available. Especially if you
  can guess/know/control some of the data.  Additionally renegotiating
  regularly helps to constrain a possible key leagage to a certain amount
  of time. With backend connections often being alive for weeks at a time
  that's not a bad thing.
 
 Renegotiation will be removed from future TLS versions because it is
 considered unnecessary with modern ciphers:
 
   https://github.com/tlswg/tls13-spec/issues/38
 
 If ciphers require rekeying, that mechanism will be provided at the TLS
 layer in the future.
 
 I think you could remove renegotiation from PostgreSQL as long as you
 offer something better than RC4 in the TLS handshake.

As far as I understand it, this argument misses an important
point. Without protocol level rekeying, handled by the library in the
background, never changing the session key pretty much breaks PFS. In
http the sessions almost always are short enough that such a
consideration doesn't play a role, but it's far from uncommon to have
database connections that live weeks and transport hundreds of gigabytes
in their lifetime.

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2015-02-23 Thread Henry B Hotz
Renegotiation should be a best practice. Trouble is it's been broken (at the 
protocol level) three times in the last few years so it's a massive hole in 
practice. 

Ideally we should leave the renegotiate in, and only remove it if configure 
detects a broken version of TLS.

Personal email. hbh...@oxy.edu

 On Feb 23, 2015, at 7:01 AM, Albe Laurenz laurenz.a...@wien.gv.at wrote:
 
 I'd say it is best to wait if and how OpenSSL change their API when they
 implement TLS 1.3.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2015-02-22 Thread Andres Freund
On 2015-02-22 01:27:54 +0100, Emil Lenngren wrote:
 I honestly wonder why postgres uses renegotiation at all. The motivation
 that cryptoanalysis is easier as more data is sent seems quite
 far-fetched.

I don't think so. There's a fair number of algorithms that can/could be
much easier be attached with lots of data available. Especially if you
can guess/know/control some of the data.  Additionally renegotiating
regularly helps to constrain a possible key leagage to a certain amount
of time. With backend connections often being alive for weeks at a time
that's not a bad thing.

And it's not just us. E.g. openssh also triggers renegotiations based on
the amount of data sent.

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation and other related woes

2015-02-13 Thread Heikki Linnakangas

On 02/12/2015 01:41 AM, Andres Freund wrote:

Hi,

On 2015-02-05 23:03:02 +0200, Heikki Linnakangas wrote:

On 01/26/2015 12:14 PM, Andres Freund wrote:

Hi,

When working on getting rid of ImmediateInterruptOK I wanted to verify
that ssl still works correctly. Turned out it didn't. But neither did it
in master.

Turns out there's two major things we do wrong:

1) We ignore the rule that once called and returning
SSL_ERROR_WANTS_(READ|WRITE) SSL_read()/write() have to be called
again with the same parameters. Unfortunately that rule doesn't mean
just that the same parameters have to be passed in, but also that we
can't just constantly switch between _read()/write(). Especially
nonblocking backend code (i.e. walsender) and the whole frontend code
violate this rule.


I don't buy that. Googling around, and looking at the man pages, I just
don't see anything to support that claim. I believe it is supported to
switch between reads and writes.


There's at least two implementations that seem to have workaround to
achieve something like that. Apache's mod_ssl and the ssl layer for
libevent.


2) We start renegotiations in be_tls_write() while in nonblocking mode,
but don't properly retry to handle socket readyness. There's a loop
that retries handshakes twenty times (???), but what actually is
needed is to call SSL_get_error() and ensure that there's actually
data available.


Yeah, that's just crazy.

Actually, I don't think we need to call SSL_do_handshake() at all. At least
on modern OpenSSL versions. OpenSSL internally uses a state machine, and
SSL_read() and SSL_write() calls will complete the handshake just as well.


Some blaming seems to show that that's been the case for a long time.


2) is easy enough to fix, but 1) is pretty hard. Before anybody says
that 1) isn't an important rule: It reliably causes connection aborts
within a couple renegotiations. The higher the latency the higher the
likelihood of aborts. Even locally it doesn't take very long to
abort. Errors usually are something like SSL connection has been closed
unexpectedly or SSL Error: sslv3 alert unexpected message and a host
of other similar messages. There's a couple reports of those in the
archives and I've seen many more in client logs.


Yeah, I can reproduce that. There's clearly something wrong.



I believe this is an OpenSSL bug. I traced the unexpected message error to
this code in OpenSSL's s3_read_bytes() function:


Yep, I got to that as well.


case SSL3_RT_APPLICATION_DATA:
/*
 * At this point, we were expecting handshake data, but have
 * application data.  If the library was running inside ssl3_read()
 * (i.e. in_read_app_data is set) and it makes sense to read
 * application data at this point (session renegotiation not yet
 * started), we will indulge it.
 */
if (s-s3-in_read_app_data 
(s-s3-total_renegotiations != 0) 
(((s-state  SSL_ST_CONNECT) 
  (s-state = SSL3_ST_CW_CLNT_HELLO_A) 
  (s-state = SSL3_ST_CR_SRVR_HELLO_A)
 ) || ((s-state  SSL_ST_ACCEPT) 
   (s-state = SSL3_ST_SW_HELLO_REQ_A) 
   (s-state = SSL3_ST_SR_CLNT_HELLO_A)
 )
)) {
s-s3-in_read_app_data = 2;
return (-1);
} else {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
goto f_err;
}


So that quite clearly throws an error, *unless* the original application
call was SSL_read(). As you also concluded, OpenSSL doesn't like it when
SSL_write() is called when it's in renegotiation. I think that's OpenSSL's
fault and it should indulge the application data message even in
SSL_write().


That'd be nice, but I think there were multiple reports to them about
this and there wasn't much of a response. Maybe it's time to try again.


In theory, I guess we should do similar hacks in the server, and always call
SSL_read() before SSL_write(), but it seems to work without it. Or maybe
not; OpenSSL server and client code is not symmetric, so perhaps it works in
server mode without that.


I think we should do it on the server side - got some server side errors
when I cranked up the pg_receivexlog's status interval and set the wal
sender timeout very low.


I've not been able to reproduce any errors on the server side, with my 
latest client-only patch. Not sure why. I would assume that the server 
has the same problem, but perhaps there are some mitigating factors that 
make it impossible or at least less likely there.


I'm planning to commit and backpatch the first two of the attached 
patches. The first is essentially the same as what I've posted before, 
with some minor cleanup. I realized that the hack can be isolated 
completely in fe-secure-openssl.c by putting the kill-switch in the 
custom BIO_read routine, instead of 

Re: [HACKERS] SSL renegotiation and other related woes

2015-02-12 Thread Heikki Linnakangas

On 02/12/2015 01:33 AM, Andres Freund wrote:

On 2015-02-11 14:54:03 +0200, Heikki Linnakangas wrote:

Thoughts? Can you reproduce any errors with this?


I'm on battery right now, so I can't really test much.

Did you test having an actual standby instead of pg_receivexlog? I saw
some slightly different errors there.

Does this patch alone work for you or did you test it together with the
earlier one to fix the renegotiation handling server side when
nonblocking? Because that frequently seemed to error out for me, at
least over actual network. A latch loop + checking for the states seemed
to fix that for me.


This patch alone worked for me.


+* NB: This relies on the calling code to call pqsecure_read(), 
completing
+* the renegotiation handshake, if pqsecure_write() returns 0. Otherwise
+* we'll never make progress.
+*/


I think this should a) refer to the fact that pqSendSome does that in
blocking scenarios b) expand the comment around the pqReadData to
reference that fact.

How are we going to deal with callers using libpq in nonblocking mode. A
client doing a large COPY FROM STDIN to the server using a nonblocking
connection (not a stupid thing to do) could hit this IIUC.


Hmm, that's problematic even without SSL. If you do a large COPY FROM 
STDIN, and the server sends a lot of NOTICEs, the NOTICEs will be 
accumulated in the TCP send and receive buffers until they fill up. 
After that, the server will block on the send, and will stop reading the 
tuple data the client sends, and you get a deadlock. In blocking mode, 
pqSendSome calls pqReadData to avoid that.


I think pqSendSome should call pqReadData() after getting EWOULDBLOCK, 
even in non-blocking mode. It won't completely prevent the problem: it's 
possible that the receive buffer fills up, but the application doesn't 
call pqSendSome() until the socket becomes writeable, which won't happen 
until the client drains the incoming data is drained and unblocks the 
server. But it greatly reduces the risk. In practice that will solve the 
problem for SSL renegotiations.


We should also document that the application should always wait for the 
socket readable condition, in addition to writeable, and call 
pqConsumeInput(). That fixes the issue for good.



Could we perhaps call SSL_peek() when SSL_write() hits WANTS_READ? In
combination with your fix I think that should fix the possibility of
such a deadlock? Especially on the serverside where the socket most of
the time is is in, although emulated, blocking mode that seems easier -
we can just retry afterwards.


Hmm. Not sure what the semantics of SSL_peek() are. At least we'd need 
to call it with a large enough buffer that it would read all the 
incoming data from the OS buffer. I think it would be safer to just call 
SSL_read(). Both the server and libpq have an input buffer that you can 
easily read into at any time.


- Heikki



--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation and other related woes

2015-02-11 Thread Andres Freund
On 2015-02-11 14:54:03 +0200, Heikki Linnakangas wrote:
 Thoughts? Can you reproduce any errors with this?

I'm on battery right now, so I can't really test much.

Did you test having an actual standby instead of pg_receivexlog? I saw
some slightly different errors there.

Does this patch alone work for you or did you test it together with the
earlier one to fix the renegotiation handling server side when
nonblocking? Because that frequently seemed to error out for me, at
least over actual network. A latch loop + checking for the states seemed
to fix that for me.

I'm pretty darn happy that you seem to have found a much less ugly
solution than mine. Although it's only pretty by comparison ;)

 + /*
 +  * To work-around an issue with OpenSSL and renegotiation, we don't
 +  * let SSL_write() to read any incoming data.

superflous to.

 +  * NB: This relies on the calling code to call pqsecure_read(), 
 completing
 +  * the renegotiation handshake, if pqsecure_write() returns 0. Otherwise
 +  * we'll never make progress.
 +  */

I think this should a) refer to the fact that pqSendSome does that in
blocking scenarios b) expand the comment around the pqReadData to
reference that fact.

How are we going to deal with callers using libpq in nonblocking mode. A
client doing a large COPY FROM STDIN to the server using a nonblocking
connection (not a stupid thing to do) could hit this IIUC.

Could we perhaps call SSL_peek() when SSL_write() hits WANTS_READ? In
combination with your fix I think that should fix the possibility of
such a deadlock? Especially on the serverside where the socket most of
the time is is in, although emulated, blocking mode that seems easier -
we can just retry afterwards.

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation and other related woes

2015-02-11 Thread Andres Freund
Hi,

On 2015-02-05 23:03:02 +0200, Heikki Linnakangas wrote:
 On 01/26/2015 12:14 PM, Andres Freund wrote:
 Hi,
 
 When working on getting rid of ImmediateInterruptOK I wanted to verify
 that ssl still works correctly. Turned out it didn't. But neither did it
 in master.
 
 Turns out there's two major things we do wrong:
 
 1) We ignore the rule that once called and returning
 SSL_ERROR_WANTS_(READ|WRITE) SSL_read()/write() have to be called
 again with the same parameters. Unfortunately that rule doesn't mean
 just that the same parameters have to be passed in, but also that we
 can't just constantly switch between _read()/write(). Especially
 nonblocking backend code (i.e. walsender) and the whole frontend code
 violate this rule.
 
 I don't buy that. Googling around, and looking at the man pages, I just
 don't see anything to support that claim. I believe it is supported to
 switch between reads and writes.

There's at least two implementations that seem to have workaround to
achieve something like that. Apache's mod_ssl and the ssl layer for
libevent.

 2) We start renegotiations in be_tls_write() while in nonblocking mode,
 but don't properly retry to handle socket readyness. There's a loop
 that retries handshakes twenty times (???), but what actually is
 needed is to call SSL_get_error() and ensure that there's actually
 data available.
 
 Yeah, that's just crazy.
 
 Actually, I don't think we need to call SSL_do_handshake() at all. At least
 on modern OpenSSL versions. OpenSSL internally uses a state machine, and
 SSL_read() and SSL_write() calls will complete the handshake just as well.

Some blaming seems to show that that's been the case for a long time.

 2) is easy enough to fix, but 1) is pretty hard. Before anybody says
 that 1) isn't an important rule: It reliably causes connection aborts
 within a couple renegotiations. The higher the latency the higher the
 likelihood of aborts. Even locally it doesn't take very long to
 abort. Errors usually are something like SSL connection has been closed
 unexpectedly or SSL Error: sslv3 alert unexpected message and a host
 of other similar messages. There's a couple reports of those in the
 archives and I've seen many more in client logs.
 
 Yeah, I can reproduce that. There's clearly something wrong.

 I believe this is an OpenSSL bug. I traced the unexpected message error to
 this code in OpenSSL's s3_read_bytes() function:

Yep, I got to that as well.

 case SSL3_RT_APPLICATION_DATA:
 /*
  * At this point, we were expecting handshake data, but have
  * application data.  If the library was running inside ssl3_read()
  * (i.e. in_read_app_data is set) and it makes sense to read
  * application data at this point (session renegotiation not yet
  * started), we will indulge it.
  */
 if (s-s3-in_read_app_data 
 (s-s3-total_renegotiations != 0) 
 (((s-state  SSL_ST_CONNECT) 
   (s-state = SSL3_ST_CW_CLNT_HELLO_A) 
   (s-state = SSL3_ST_CR_SRVR_HELLO_A)
  ) || ((s-state  SSL_ST_ACCEPT) 
(s-state = SSL3_ST_SW_HELLO_REQ_A) 
(s-state = SSL3_ST_SR_CLNT_HELLO_A)
  )
 )) {
 s-s3-in_read_app_data = 2;
 return (-1);
 } else {
 al = SSL_AD_UNEXPECTED_MESSAGE;
  SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
 goto f_err;
 }
 
 So that quite clearly throws an error, *unless* the original application
 call was SSL_read(). As you also concluded, OpenSSL doesn't like it when
 SSL_write() is called when it's in renegotiation. I think that's OpenSSL's
 fault and it should indulge the application data message even in
 SSL_write().

That'd be nice, but I think there were multiple reports to them about
this and there wasn't much of a response. Maybe it's time to try again.

 In theory, I guess we should do similar hacks in the server, and always call
 SSL_read() before SSL_write(), but it seems to work without it. Or maybe
 not; OpenSSL server and client code is not symmetric, so perhaps it works in
 server mode without that.

I think we should do it on the server side - got some server side errors
when I cranked up the pg_receivexlog's status interval and set the wal
sender timeout very low.

Greetings,

Andres Freund


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation and other related woes

2015-02-11 Thread Heikki Linnakangas

On 02/05/2015 11:03 PM, Heikki Linnakangas wrote:

On 01/26/2015 12:14 PM, Andres Freund wrote:
Can we work-around that easily? I believe we can. The crucial part is
that we mustn't let SSL_write() to process any incoming application
data. We can achieve that if we always call SSL_read() to drain such
data, before calling SSL_write(). But that's not quite enough; if we're
in renegotiation, SSL_write() might still try to read more data from the
socket that has arrived after the SSL_read() call. Fortunately, we can
easily prevent that by hacking pqsecure_raw_read() to always return
EWOULDBLOCK, when it's called through SSL_write().

The attached patch does that. I've been running your pg_receivexlog test
case with this for about 15 minutes without any errors now, with
ssl_renegotiation_limit=50kB, while before it errored out within seconds.


Here is a simplified version of this patch. It seems to be enough to not 
let SSL_write() to read any data from the socket. No need to call 
SSL_read() first, and the server-side changes I made were only needed 
because of the other patch I had applied.


Thoughts? Can you reproduce any errors with this?


In theory, I guess we should do similar hacks in the server, and always
call SSL_read() before SSL_write(), but it seems to work without it. Or
maybe not; OpenSSL server and client code is not symmetric, so perhaps
it works in server mode without that.


Not included in this patch, but I believe we apply a similar patch to 
the server-side too.


- Heikki

From b78bfbb70127cbe3f360458eb2a97dcc28194fbc Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas heikki.linnakangas@iki.fi
Date: Thu, 5 Feb 2015 22:44:58 +0200
Subject: [PATCH 1/1] Fix sslv3 alert unexpected message errors in SSL
 renegotiation.

There seems to be a bug in OpenSSL renegotiation, so that when SSL_write()
needs to read data to complete the handshake, but it receives application
data instead, it gets confused and throws an unexpected message error. To
work around that, don't let SSL_write() to read data from the socket, even
if some is available. Arrange so that SSL_read() processes all incoming
messages instead.
---
 src/interfaces/libpq/fe-misc.c   | 14 +-
 src/interfaces/libpq/fe-secure-openssl.c | 20 
 src/interfaces/libpq/fe-secure.c |  9 +
 src/interfaces/libpq/libpq-int.h |  2 ++
 4 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 945e283..9dd02d5 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -920,11 +920,15 @@ pqSendSome(PGconn *conn, int len)
 			 * to clear the channel eventually because it's blocked trying to
 			 * send data to us.  (This can happen when we are sending a large
 			 * amount of COPY data, and the server has generated lots of
-			 * NOTICE responses.)  To avoid a deadlock situation, we must be
-			 * prepared to accept and buffer incoming data before we try
-			 * again.  Furthermore, it is possible that such incoming data
-			 * might not arrive until after we've gone to sleep.  Therefore,
-			 * we wait for either read ready or write ready.
+			 * NOTICE responses.)  Another scenario is that SSL renegotiation
+			 * is in progress, and the SSL library needs to read a message
+			 * to complete the handshake, before it can send more data.
+			 *
+			 * To avoid a deadlock situation, we must be prepared to accept
+			 * and buffer incoming data before we try again.  Furthermore, it
+			 * is possible that such incoming data might not arrive until
+			 * after we've gone to sleep.  Therefore, we wait for either read
+			 * ready or write ready.
 			 */
 			if (pqReadData(conn)  0)
 			{
diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c
index a32af34..2e75f3c 100644
--- a/src/interfaces/libpq/fe-secure-openssl.c
+++ b/src/interfaces/libpq/fe-secure-openssl.c
@@ -319,8 +319,28 @@ pgtls_write(PGconn *conn, const void *ptr, size_t len)
 	char		sebuf[256];
 	int			err;
 
+	/*
+	 * To work-around an issue with OpenSSL and renegotiation, we don't
+	 * let SSL_write() to read any incoming data.
+	 *
+	 * If SSL_write() is called, and renegotiation has just been inititated,
+	 * SSL_write() might try to read from the socket to complete the
+	 * handshake. If there was some application data in-flight, it might
+	 * receive the application data instead. That confuses it, and it throws
+	 * an sslv3 alert unexpected message error.
+	 *
+	 * We avoid that setting a kill-switch, pqsecure_block_raw_read, which
+	 * tells pqsecure_raw_read() to not return any data to the caller, even
+	 * if some is available.
+	 *
+	 * NB: This relies on the calling code to call pqsecure_read(), completing
+	 * the renegotiation handshake, if pqsecure_write() returns 0. Otherwise
+	 * we'll never make progress.
+	 */
 	SOCK_ERRNO_SET(0);
+	pqsecure_block_raw_read = true;
 	n = 

Re: [HACKERS] SSL renegotiation and other related woes

2015-02-05 Thread Heikki Linnakangas

On 01/26/2015 12:14 PM, Andres Freund wrote:

Hi,

When working on getting rid of ImmediateInterruptOK I wanted to verify
that ssl still works correctly. Turned out it didn't. But neither did it
in master.

Turns out there's two major things we do wrong:

1) We ignore the rule that once called and returning
SSL_ERROR_WANTS_(READ|WRITE) SSL_read()/write() have to be called
again with the same parameters. Unfortunately that rule doesn't mean
just that the same parameters have to be passed in, but also that we
can't just constantly switch between _read()/write(). Especially
nonblocking backend code (i.e. walsender) and the whole frontend code
violate this rule.


I don't buy that. Googling around, and looking at the man pages, I just 
don't see anything to support that claim. I believe it is supported to 
switch between reads and writes.



2) We start renegotiations in be_tls_write() while in nonblocking mode,
but don't properly retry to handle socket readyness. There's a loop
that retries handshakes twenty times (???), but what actually is
needed is to call SSL_get_error() and ensure that there's actually
data available.


Yeah, that's just crazy.

Actually, I don't think we need to call SSL_do_handshake() at all. At 
least on modern OpenSSL versions. OpenSSL internally uses a state 
machine, and SSL_read() and SSL_write() calls will complete the 
handshake just as well.



2) is easy enough to fix, but 1) is pretty hard. Before anybody says
that 1) isn't an important rule: It reliably causes connection aborts
within a couple renegotiations. The higher the latency the higher the
likelihood of aborts. Even locally it doesn't take very long to
abort. Errors usually are something like SSL connection has been closed
unexpectedly or SSL Error: sslv3 alert unexpected message and a host
of other similar messages. There's a couple reports of those in the
archives and I've seen many more in client logs.


Yeah, I can reproduce that. There's clearly something wrong.

I believe this is an OpenSSL bug. I traced the unexpected message 
error to this code in OpenSSL's s3_read_bytes() function:



case SSL3_RT_APPLICATION_DATA:
/*
 * At this point, we were expecting handshake data, but have
 * application data.  If the library was running inside ssl3_read()
 * (i.e. in_read_app_data is set) and it makes sense to read
 * application data at this point (session renegotiation not yet
 * started), we will indulge it.
 */
if (s-s3-in_read_app_data 
(s-s3-total_renegotiations != 0) 
(((s-state  SSL_ST_CONNECT) 
  (s-state = SSL3_ST_CW_CLNT_HELLO_A) 
  (s-state = SSL3_ST_CR_SRVR_HELLO_A)
 ) || ((s-state  SSL_ST_ACCEPT) 
   (s-state = SSL3_ST_SW_HELLO_REQ_A) 
   (s-state = SSL3_ST_SR_CLNT_HELLO_A)
 )
)) {
s-s3-in_read_app_data = 2;
return (-1);
} else {
al = SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
goto f_err;
}


So that quite clearly throws an error, *unless* the original application 
call was SSL_read(). As you also concluded, OpenSSL doesn't like it when 
SSL_write() is called when it's in renegotiation. I think that's 
OpenSSL's fault and it should indulge the application data message 
even in SSL_write().


Can we work-around that easily? I believe we can. The crucial part is 
that we mustn't let SSL_write() to process any incoming application 
data. We can achieve that if we always call SSL_read() to drain such 
data, before calling SSL_write(). But that's not quite enough; if we're 
in renegotiation, SSL_write() might still try to read more data from the 
socket that has arrived after the SSL_read() call. Fortunately, we can 
easily prevent that by hacking pqsecure_raw_read() to always return 
EWOULDBLOCK, when it's called through SSL_write().


The attached patch does that. I've been running your pg_receivexlog test 
case with this for about 15 minutes without any errors now, with 
ssl_renegotiation_limit=50kB, while before it errored out within seconds.


In theory, I guess we should do similar hacks in the server, and always 
call SSL_read() before SSL_write(), but it seems to work without it. Or 
maybe not; OpenSSL server and client code is not symmetric, so perhaps 
it works in server mode without that.


PS. The server code started renegotiation when it's 1kB from reaching 
ssl_renegotiation_limit. I increased that to 32kB, because in testing, I 
got some SSL failed to renegotiate connection before limit expired 
errors in testing before I did that.


PPS. I did all testing of this patch with my sleeping logic 
simplification patch applied 
(http://www.postgresql.org/message-id/54d3821e.9060...@vmware.com). It 
applies without it too, and I don't think it matters, but I thought 

Re: [HACKERS] SSL renegotiation and other related woes

2015-01-26 Thread Andres Freund
On 2015-01-26 11:14:05 +0100, Andres Freund wrote:
 My testcase for this is just to setup a server with a low
 ssl_renegotiation_limit, generate lots of WAL (wal.sql attached) and
 receive data via pg_receivexlog -n. Usually it'll error out quickly.

...

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services
DROP TABLE IF EXISTS foo_:client_id;
CREATE TABLE foo_:client_id AS SELECT * FROM generate_series(1, 100) a(a), 
generate_series(1, 1) b(b);

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2014-08-25 Thread Alvaro Herrera
Tom Lane wrote:
 Andres Freund and...@2ndquadrant.com writes:
  On 2013-11-15 10:43:23 -0500, Tom Lane wrote:
  Another reason I'm not in a hurry is that the problem we're trying
  to solve doesn't seem to be causing real-world trouble.  So by
  awhile, I'm thinking let's let it get through 9.4 beta testing.
 
  Well, there have been a bunch of customer complaints about it, afair
  that's what made Alvaro look into it in the first place. So it's not a
  victimless bug.
 
 OK, then maybe end-of-beta is too long.  But how much testing will it get
 during development?  I know I never use SSL on development installs.
 How many hackers do?

Just a reminder that I intend to backpatch this (and subsequent fixes).
We've gone over two 9.4 betas now.  Maybe it'd be a good thing if the
beta3 announcement carried a note about enabling SSL with a low
ssl_renegotiation_limit setting.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2014-08-25 Thread Noah Misch
On Mon, Aug 25, 2014 at 11:46:13PM -0400, Alvaro Herrera wrote:
 Tom Lane wrote:
  OK, then maybe end-of-beta is too long.  But how much testing will it get
  during development?  I know I never use SSL on development installs.
  How many hackers do?
 
 Just a reminder that I intend to backpatch this (and subsequent fixes).
 We've gone over two 9.4 betas now.  Maybe it'd be a good thing if the
 beta3 announcement carried a note about enabling SSL with a low
 ssl_renegotiation_limit setting.

To elaborate on my private comments of 2013-10-11, I share Robert's
wariness[1] concerning the magic number of 1024 bytes of renegotiation
headroom.  Use of that number predates your work, but your work turned
exhaustion of that headroom into a FATAL error.  Situations where the figure
is too small will become disruptive, whereas the problem is nearly invisible
today.  Network congestion is a factor, so the lack of complaints during beta
is relatively uninformative.  Disabling renegotiation is a quick workaround,
fortunately, but needing to use that workaround will damage users' fragile
faith in the safety of our minor releases.

My recommendation is to either keep this 9.4-only or do focused load testing
to determine the actual worst-case headroom requirement.

[1] 
http://www.postgresql.org/message-id/ca+tgmozvgmyzlx7e4arq_5nu4uden7wrvg1xjxg_o9c61ch...@mail.gmail.com


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-19 Thread Robert Haas
On Fri, Nov 15, 2013 at 10:49 AM, Andres Freund and...@2ndquadrant.com wrote:
 Another reason I'm not in a hurry is that the problem we're trying
 to solve doesn't seem to be causing real-world trouble.  So by
 awhile, I'm thinking let's let it get through 9.4 beta testing.

 Well, there have been a bunch of customer complaints about it, afair
 that's what made Alvaro look into it in the first place. So it's not a
 victimless bug.

Well, can any of those people try running with this patch?  That'd be
a good way of getting some confidence in it.

Generally, I agree that something needs to be back-patched here.  But
we don't want to create a situation where we fix some people and break
others, and it's not too obvious that we have a way to get there.
Personally, I favor adding some kind of GUC to control the behavior,
but I'm not exactly sure what the shape of it ought to be.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Alvaro Herrera
So I committed this patch without backpatching anything.  There was some
discussion about the exact strategy for backpatching the behavior
change, but no final agreement; the suggestions were

0. Backpatch as an ERROR.  If it causes failures, people is supposed to
change their apps or something.

1. Don't backpatch the ERROR bit at all, so that if the renegotiation
fails we would silently continue just as currently

2. Do spit the message, but only as a WARNING.  Thinks this may end up
causing log disks to fill up.

3. Add it as an ERROR, but make it possible to disable it, presumably
via a new GUC.  So people can see their security problems and hopefuly
fix them, but if they don't, then they can shut it up via server
configuration.  This would entail a GUC variable that exists in existing
branches but not HEAD (we could avoid an upgradability problem of
postgresql.conf files by having a no-op phantom GUC variable in HEAD).

I was reminded of this once more because I just saw a spurious
renegotiation failure in somebody's production setup.  Kind of like a
recurring nightmare which I thought I had already erradicated.

Opinions?  Also, should we wait longer for the new renegotiation code to
be more battle-tested?

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Stephen Frost
Alvaro,

* Alvaro Herrera (alvhe...@2ndquadrant.com) wrote:
 1. Don't backpatch the ERROR bit at all, so that if the renegotiation
 fails we would silently continue just as currently

I'm leaning towards the above at this point.

 I was reminded of this once more because I just saw a spurious
 renegotiation failure in somebody's production setup.  Kind of like a
 recurring nightmare which I thought I had already erradicated.

I saw one yesterday. :(

 Opinions?  Also, should we wait longer for the new renegotiation code to
 be more battle-tested?

I've got a better environment to test this in now and given that I saw
it just yesterday, I'm very interested in addressing it.  I grow tired
of seeing these renegotiation errors.

Thanks!

Stephen


signature.asc
Description: Digital signature


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Andres Freund
On 2013-11-15 10:43:23 -0500, Tom Lane wrote:
 +1 to waiting awhile.  I think if we don't see any problems in
 HEAD, then back-patching as-is would be the best solution.
 The other alternatives are essentially acknowledging that you're
 back-patching something you're afraid isn't production ready.
 Let's not go there.

Agreed. Both on just backpatching it unchanged and waiting for the fix
to prove itself a bit.

 Another reason I'm not in a hurry is that the problem we're trying
 to solve doesn't seem to be causing real-world trouble.  So by
 awhile, I'm thinking let's let it get through 9.4 beta testing.

Well, there have been a bunch of customer complaints about it, afair
that's what made Alvaro look into it in the first place. So it's not a
victimless bug.

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Tom Lane
Alvaro Herrera alvhe...@2ndquadrant.com writes:
 So I committed this patch without backpatching anything. ...
 ... should we wait longer for the new renegotiation code to
 be more battle-tested?

+1 to waiting awhile.  I think if we don't see any problems in
HEAD, then back-patching as-is would be the best solution.
The other alternatives are essentially acknowledging that you're
back-patching something you're afraid isn't production ready.
Let's not go there.

Another reason I'm not in a hurry is that the problem we're trying
to solve doesn't seem to be causing real-world trouble.  So by
awhile, I'm thinking let's let it get through 9.4 beta testing.

regards, tom lane


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Tom Lane
Andres Freund and...@2ndquadrant.com writes:
 On 2013-11-15 10:43:23 -0500, Tom Lane wrote:
 Another reason I'm not in a hurry is that the problem we're trying
 to solve doesn't seem to be causing real-world trouble.  So by
 awhile, I'm thinking let's let it get through 9.4 beta testing.

 Well, there have been a bunch of customer complaints about it, afair
 that's what made Alvaro look into it in the first place. So it's not a
 victimless bug.

OK, then maybe end-of-beta is too long.  But how much testing will it get
during development?  I know I never use SSL on development installs.
How many hackers do?

regards, tom lane


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-11-15 Thread Andres Freund
On 2013-11-15 10:58:19 -0500, Tom Lane wrote:
 Andres Freund and...@2ndquadrant.com writes:
  On 2013-11-15 10:43:23 -0500, Tom Lane wrote:
  Another reason I'm not in a hurry is that the problem we're trying
  to solve doesn't seem to be causing real-world trouble.  So by
  awhile, I'm thinking let's let it get through 9.4 beta testing.
 
  Well, there have been a bunch of customer complaints about it, afair
  that's what made Alvaro look into it in the first place. So it's not a
  victimless bug.
 
 OK, then maybe end-of-beta is too long.  But how much testing will it get
 during development?  I know I never use SSL on development installs.
 How many hackers do?

I guess few. And even fewer will actually have connections that live
long enough to experience renegotiations :/.

I wonder how hard it'd be to rig the buildfarm code to generate ssl
certificates and use them during installcheck. If we'd additionally set
a low renegotiation limit...

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-15 Thread Vik Fearing
On 09/23/2013 10:51 PM, Alvaro Herrera wrote:
 + /* are we in the middle of a renegotiation? */
 + static bool in_ssl_renegotiation = false;
 + 

Since this was committed, I'm getting the following warning:

be-secure.c:105:13: warning: ‘in_ssl_renegotiation’ defined but not used
[-Wunused-variable]

-- 
Vik



-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-01 Thread Alvaro Herrera
Since back branches releases are getting closer, I would like to push
this to all supported branches.  To avoid a compatibility nightmare in
case the new die-on-delayed-renegotiation behavior turns out not to be
so great, I think it would be OK to set the error level to WARNING in
all branches but master (and reset the byte count, to avoid filling the
log).  I would also add a CONTEXT line with the current counter value
and the configured limit, and a HINT to report to pg-hackers.  That way
we will hopefully have more info on problems in the field.

Anybody opposed to this?

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-01 Thread Robert Haas
On Tue, Oct 1, 2013 at 9:16 AM, Alvaro Herrera alvhe...@2ndquadrant.com wrote:
 Since back branches releases are getting closer, I would like to push
 this to all supported branches.  To avoid a compatibility nightmare in
 case the new die-on-delayed-renegotiation behavior turns out not to be
 so great, I think it would be OK to set the error level to WARNING in
 all branches but master (and reset the byte count, to avoid filling the
 log).  I would also add a CONTEXT line with the current counter value
 and the configured limit, and a HINT to report to pg-hackers.  That way
 we will hopefully have more info on problems in the field.

 Anybody opposed to this?

Yes, warning suck.  If things just failed, users would fix them, but
instead they fill up their hard disk, and then things fail much later,
usually when they are asleep in bed.

If we can't feel comfortable with an ERROR, let's not do it at all.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-01 Thread Magnus Hagander
On Tue, Oct 1, 2013 at 4:17 PM, Robert Haas robertmh...@gmail.com wrote:
 On Tue, Oct 1, 2013 at 9:16 AM, Alvaro Herrera alvhe...@2ndquadrant.com 
 wrote:
 Since back branches releases are getting closer, I would like to push
 this to all supported branches.  To avoid a compatibility nightmare in
 case the new die-on-delayed-renegotiation behavior turns out not to be
 so great, I think it would be OK to set the error level to WARNING in
 all branches but master (and reset the byte count, to avoid filling the
 log).  I would also add a CONTEXT line with the current counter value
 and the configured limit, and a HINT to report to pg-hackers.  That way
 we will hopefully have more info on problems in the field.

 Anybody opposed to this?

 Yes, warning suck.  If things just failed, users would fix them, but
 instead they fill up their hard disk, and then things fail much later,
 usually when they are asleep in bed.

 If we can't feel comfortable with an ERROR, let's not do it at all.

In principle, I agree.

However, if we want to do this as a temporary measure to judge impact,
we could do WARNING now and flip it to ERROR in the next minor
release.

However, do we think we'll actually *get* any reports in of it if we
do that? As in would we trust the input? If we do, the it might be
worth doing that. If we don't believe we'll get any input from the
WARNINGs anyway, we might as well flip it to an ERROR. But if we do
flip it to an ERROR, we should have a way to disable that error if, as
Alvaro puts it, we end up breaking too many things.


-- 
 Magnus Hagander
 Me: http://www.hagander.net/
 Work: http://www.redpill-linpro.com/


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-01 Thread Robert Haas
On Tue, Oct 1, 2013 at 10:19 AM, Magnus Hagander mag...@hagander.net wrote:
 If we can't feel comfortable with an ERROR, let's not do it at all.

 In principle, I agree.

 However, if we want to do this as a temporary measure to judge impact,
 we could do WARNING now and flip it to ERROR in the next minor
 release.

I can't imagine that whacking the behavior around multiple times is
going to please very many people.  And, from a practical standpoint,
the time between minor releases is typically on the order of ~3
months.  That's not very long.  The situations in which trouble occurs
are likely to obscure, and a lot of users don't apply every minor
release, or don't apply them in a timely fashion.  So I can't see that
this strategy would increase our confidence very much anyway.  In
other words...

 However, do we think we'll actually *get* any reports in of it if we
 do that? As in would we trust the input?

...no.

  If we do, the it might be
 worth doing that. If we don't believe we'll get any input from the
 WARNINGs anyway, we might as well flip it to an ERROR. But if we do
 flip it to an ERROR, we should have a way to disable that error if, as
 Alvaro puts it, we end up breaking too many things.

A way of disabling the error seems like an awfully good idea.  Since I
know my audience, I won't suggest the obvious method of accomplishing
that goal, but I think we all know what it is.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-10-01 Thread Andres Freund
On 2013-10-01 10:27:14 -0400, Robert Haas wrote:
 On Tue, Oct 1, 2013 at 10:19 AM, Magnus Hagander mag...@hagander.net wrote:
  If we can't feel comfortable with an ERROR, let's not do it at all.
 
  In principle, I agree.
 
  However, if we want to do this as a temporary measure to judge impact,
  we could do WARNING now and flip it to ERROR in the next minor
  release.
 
 I can't imagine that whacking the behavior around multiple times is
 going to please very many people.

If we have to whack it around, it's because there's a bug in either our
usage of openssl or in openssl itself. Neither is particularly unlikely,
but it's not like not erroring or warning out will stop that.

The alternate reason for getting the WARNING/ERROR is that there is
somebody MITMing the connection and explicitly corrupting renegotiation
packets. But that's a reason for making it an ERROR immediately, not
making it silent. I think from the security POV it's pretty clear that we
should make it an error.

So, imo the question is why are we uncomfortable making it an ERROR
immediately? I think the most likely reason for problems is users having
configured ssl_renegotiation_limit absurdly low, like less than what the
particular algorithms used actually need. What about clamping it to 1MB
if != 0? We can't make it an actual error in the backbranches...

   If we do, the it might be
  worth doing that. If we don't believe we'll get any input from the
  WARNINGs anyway, we might as well flip it to an ERROR. But if we do
  flip it to an ERROR, we should have a way to disable that error if, as
  Alvaro puts it, we end up breaking too many things.
 
 A way of disabling the error seems like an awfully good idea.  Since I
 know my audience, I won't suggest the obvious method of accomplishing
 that goal, but I think we all know what it is.

In which scenario would you want to do that? The way to prevent the
ERROR it is to disable renegotiation entirely. And that's already
possible. Anything else seems like papering over security issues.

I guess I am voting for making renegotiation failure an ERROR everywhere
and silently clamp renegotiation_limit to a lower bound of 1MB in the
backbranches while making the (0, 1MB) an error in HEAD.

Greetings,

Andres Freund

-- 
 Andres Freund http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-09-24 Thread Robert Haas
On Mon, Sep 23, 2013 at 4:51 PM, Alvaro Herrera
alvhe...@2ndquadrant.com wrote:
 Here's an updated version; this mainly simplifies code, per comments
 from Andres (things were a bit too baroque in places due to the way the
 code had evolved, and I hadn't gone over it to simplify it).

 The only behavior change is that the renegotiation is requested 1kB
 before the limit is hit: the raise to 1% of the configured limit was
 removed.

What basis do we have for thinking that 1kB is definitely enough to
avoid spurious disconnects?

(I have a bad feeling that you're going to say something along the
lines of well, we tried it a bunch of times, and)

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-09-24 Thread Alvaro Herrera
Robert Haas escribió:
 On Mon, Sep 23, 2013 at 4:51 PM, Alvaro Herrera
 alvhe...@2ndquadrant.com wrote:
  Here's an updated version; this mainly simplifies code, per comments
  from Andres (things were a bit too baroque in places due to the way the
  code had evolved, and I hadn't gone over it to simplify it).
 
  The only behavior change is that the renegotiation is requested 1kB
  before the limit is hit: the raise to 1% of the configured limit was
  removed.
 
 What basis do we have for thinking that 1kB is definitely enough to
 avoid spurious disconnects?

I noticed that the count variable (which is what we use to determine
when to start the renegotiation and eventually kill the connection) is
only incremented when there's successful SSL transmission: it doesn't
count low-level network transmission.  If OpenSSL returns a WANT_READ or
WANT_WRITE error code, that variable is not incremented.  The number of
bytes returned does not include network data transmitted only to satisfy
the renegotiation.

Sadly, with the OpenSSL codebase, there isn't much documented field
experience to go by.  Even something battle-tested such as Apache's
mod_ssl gets this wrong; but apparently they don't care because their
sessions are normally so short-lived that they don't get these problems.

Also, I spent several days trying to understand the OpenSSL codebase to
figure out how this works, and I think there might be bugs in there too,
at least with nonblocking sockets.  I wasn't able to reproduce an actual
failure, though.  Funnily enough, their own test utilities do not stress
this area too much (at least the ones they include in their release
tarballs).

 (I have a bad feeling that you're going to say something along the
 lines of well, we tried it a bunch of times, and)

Well, I did try a few times and saw no failure :-)

I have heard about processes in production environments that are
restarted periodically to avoid SSL failures which they blame on
renegotiation.  Some other guys have ssl_renegotiation_limit=0 because
they know it causes network problems.  I suggest we need to get this
patch out there, so that they can test it; and if 1kB turns out not to
be sufficient, we will have field experience including appropriate error
messages on what is actually going on.  (Right now, the error messages
we get are complaining about completely the wrong thing.)

I mean, if that 1kB limit is the only quarrel you have with this patch,
I'm happy.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-09-24 Thread Robert Haas
On Tue, Sep 24, 2013 at 12:30 PM, Alvaro Herrera
alvhe...@2ndquadrant.com wrote:
 I mean, if that 1kB limit is the only quarrel you have with this patch,
 I'm happy.

You should probably be happy, then.  :-)

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-09-23 Thread Alvaro Herrera
Here's an updated version; this mainly simplifies code, per comments
from Andres (things were a bit too baroque in places due to the way the
code had evolved, and I hadn't gone over it to simplify it).

The only behavior change is that the renegotiation is requested 1kB
before the limit is hit: the raise to 1% of the configured limit was
removed.

The fixup is an incremental on top of the previous version; the other
one is the full v2 patch.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
***
*** 324,344  secure_write(Port *port, void *ptr, size_t len)
  	if (port-ssl)
  	{
  		int			err;
- 		static long renegotiation_count = 0;
  
  		/*
  		 * If SSL renegotiations are enabled and we're getting close to the
  		 * limit, start one now; but avoid it if there's one already in
! 		 * progress.  Request the renegotiation before the limit has actually
! 		 * expired; we give it 1% of the specified limit, or 1kB, whichever is
! 		 * greater.
  		 */
  		if (ssl_renegotiation_limit  !in_ssl_renegotiation 
! 			port-count  Min((ssl_renegotiation_limit - 1) * 1024L,
! 		(long) rint(ssl_renegotiation_limit * 1024L * 0.99)))
  		{
  			in_ssl_renegotiation = true;
  
  			SSL_set_session_id_context(port-ssl, (void *) SSL_context,
  	   sizeof(SSL_context));
  			if (SSL_renegotiate(port-ssl) = 0)
--- 324,352 
  	if (port-ssl)
  	{
  		int			err;
  
  		/*
  		 * If SSL renegotiations are enabled and we're getting close to the
  		 * limit, start one now; but avoid it if there's one already in
! 		 * progress.  Request the renegotiation 1kB before the limit has
! 		 * actually expired.
  		 */
  		if (ssl_renegotiation_limit  !in_ssl_renegotiation 
! 			port-count  (ssl_renegotiation_limit - 1) * 1024L)
  		{
  			in_ssl_renegotiation = true;
  
+ 			/*
+ 			 * The way we determine that a renegotiation has completed is by
+ 			 * observing OpenSSL's internal renegotiation counter.  Make sure
+ 			 * we start out at zero, and assume that the renegotiation is
+ 			 * complete when the counter advances.
+ 			 *
+ 			 * OpenSSL provides SSL_renegotiation_pending(), but this doesn't
+ 			 * seem to work in testing.
+ 			 */
+ 			SSL_clear_num_renegotiations(port-ssl);
+ 
  			SSL_set_session_id_context(port-ssl, (void *) SSL_context,
  	   sizeof(SSL_context));
  			if (SSL_renegotiate(port-ssl) = 0)
***
*** 347,379  secure_write(Port *port, void *ptr, size_t len)
  		 errmsg(SSL failure during renegotiation start)));
  			else
  			{
! int			handshake;
! int			retries = 20;
  
  /*
!  * The way we determine that a renegotiation has completed is
!  * by observing OpenSSL's internal renegotiation counter.
!  * Memoize it when starting the renegotiation, and assume that
!  * the renegotiation is complete when the counter advances.
!  *
!  * OpenSSL provides SSL_renegotiation_pending(), but this
!  * doesn't seem to work in testing.
   */
! renegotiation_count = SSL_num_renegotiations(port-ssl);
! 
! /*
!  * A handshake can fail, so be prepared to retry it, but only a
!  * few times
!  */
! for (;;)
  {
! 	handshake = SSL_do_handshake(port-ssl);
! 	if (handshake  0)
  		break;	/* done */
  	ereport(COMMERROR,
  			(errcode(ERRCODE_PROTOCOL_VIOLATION),
  			 errmsg(SSL handshake failure on renegotiation, retrying)));
! 	if (retries-- = 0)
  		ereport(FATAL,
  (errcode(ERRCODE_PROTOCOL_VIOLATION),
   errmsg(unable to complete SSL handshake)));
--- 355,374 
  		 errmsg(SSL failure during renegotiation start)));
  			else
  			{
! int			retries;
  
  /*
!  * A handshake can fail, so be prepared to retry it, but only
!  * a few times.
   */
! for (retries = 0; retries++;)
  {
! 	if (SSL_do_handshake(port-ssl)  0)
  		break;	/* done */
  	ereport(COMMERROR,
  			(errcode(ERRCODE_PROTOCOL_VIOLATION),
  			 errmsg(SSL handshake failure on renegotiation, retrying)));
! 	if (retries = 20)
  		ereport(FATAL,
  (errcode(ERRCODE_PROTOCOL_VIOLATION),
   errmsg(unable to complete SSL handshake)));
***
*** 427,439  wloop:
  
  		/* is renegotiation complete? */
  		if (in_ssl_renegotiation 
! 			SSL_num_renegotiations(port-ssl)  renegotiation_count)
  		{
  			in_ssl_renegotiation = false;
  			port-count = 0;
- 			/* avoid overflow issues by resetting counter */
- 			SSL_clear_num_renegotiations(port-ssl);
- 			renegotiation_count = SSL_num_renegotiations(port-ssl);
  		}
  
  		/*
--- 422,431 
  
  		/* is renegotiation complete? */
  		if (in_ssl_renegotiation 
! 			SSL_num_renegotiations(port-ssl) = 1)
  		{
  			in_ssl_renegotiation = false;
  			port-count = 0;
  		}
  
  		/*
*** a/src/backend/libpq/be-secure.c
--- 

Re: [HACKERS] SSL renegotiation

2013-09-20 Thread Alvaro Herrera
Here's the patch I propose to handle renegotiation cleanly.  I noticed
in testing that SSL_renegotiate_pending() doesn't seem to actually work
--- if I throw an ereport(FATAL) at the point where I expect the
renegotiation to be complete, it always dies; even if I give it
megabytes of extra traffic while waiting for the renegotiation to
complete.  I suspect this is an OpenSSL bug.  Instead, in this patch I
check the internal renegotiation counter: grab its current value when
starting the renegotiation, and consider it complete when the counter
has advanced.  This works fine.

Another thing not covered by the original code snippet I proposed
upthread is to avoid renegotiating when there was a renegotiation in
progress.  This bug has been observed in the field.

Per discussion, I made it close the connection with a FATAL error if the
limit is reached and the renegotiation hasn't taken place.  To do
otherwise is not acceptable for a security PoV.

Sean Chittenden mentioned that when retrying the handshake, we should be
careful to only do it a few times, not forever, to avoid a malfeasant
from grabbing hold of a connection indefinitely.  I've added that too,
hardcoding the number of retries to 20.

Also, I made this code request a renegotiation slightly before the limit
is actually reached.  I noticed that in some cases some traffic can go
by before the renegotiation is actually completed.  The difference
should be pretty minimal.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services
*** a/src/backend/libpq/be-secure.c
--- b/src/backend/libpq/be-secure.c
***
*** 101,106  char	   *ssl_crl_file;
--- 101,109 
   */
  int			ssl_renegotiation_limit;
  
+ /* are we in the middle of a renegotiation? */
+ static bool in_ssl_renegotiation = false;
+ 
  #ifdef USE_SSL
  static SSL_CTX *SSL_context = NULL;
  static bool ssl_loaded_verify_locations = false;
***
*** 321,350  secure_write(Port *port, void *ptr, size_t len)
  	if (port-ssl)
  	{
  		int			err;
  
! 		if (ssl_renegotiation_limit  port-count  ssl_renegotiation_limit * 1024L)
  		{
  			SSL_set_session_id_context(port-ssl, (void *) SSL_context,
  	   sizeof(SSL_context));
  			if (SSL_renegotiate(port-ssl) = 0)
  ereport(COMMERROR,
  		(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 		 errmsg(SSL renegotiation failure)));
! 			if (SSL_do_handshake(port-ssl) = 0)
! ereport(COMMERROR,
! 		(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 		 errmsg(SSL renegotiation failure)));
! 			if (port-ssl-state != SSL_ST_OK)
! ereport(COMMERROR,
! 		(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 		 errmsg(SSL failed to send renegotiation request)));
! 			port-ssl-state |= SSL_ST_ACCEPT;
! 			SSL_do_handshake(port-ssl);
! 			if (port-ssl-state != SSL_ST_OK)
! ereport(COMMERROR,
! 		(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 		 errmsg(SSL renegotiation failure)));
! 			port-count = 0;
  		}
  
  wloop:
--- 324,384 
  	if (port-ssl)
  	{
  		int			err;
+ 		static long renegotiation_count = 0;
  
! 		/*
! 		 * If SSL renegotiations are enabled and we're getting close to the
! 		 * limit, start one now; but avoid it if there's one already in
! 		 * progress.  Request the renegotiation before the limit has actually
! 		 * expired; we give it 1% of the specified limit, or 1kB, whichever is
! 		 * greater.
! 		 */
! 		if (ssl_renegotiation_limit  !in_ssl_renegotiation 
! 			port-count  Min((ssl_renegotiation_limit - 1) * 1024L,
! 		(long) rint(ssl_renegotiation_limit * 1024L * 0.99)))
  		{
+ 			in_ssl_renegotiation = true;
+ 
  			SSL_set_session_id_context(port-ssl, (void *) SSL_context,
  	   sizeof(SSL_context));
  			if (SSL_renegotiate(port-ssl) = 0)
  ereport(COMMERROR,
  		(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 		 errmsg(SSL failure during renegotiation start)));
! 			else
! 			{
! int			handshake;
! int			retries = 20;
! 
! /*
!  * The way we determine that a renegotiation has completed is
!  * by observing OpenSSL's internal renegotiation counter.
!  * Memoize it when starting the renegotiation, and assume that
!  * the renegotiation is complete when the counter advances.
!  *
!  * OpenSSL provides SSL_renegotiation_pending(), but this
!  * doesn't seem to work in testing.
!  */
! renegotiation_count = SSL_num_renegotiations(port-ssl);
! 
! /*
!  * A handshake can fail, so be prepared to retry it, but only a
!  * few times
!  */
! for (;;)
! {
! 	handshake = SSL_do_handshake(port-ssl);
! 	if (handshake  0)
! 		break;	/* done */
! 	ereport(COMMERROR,
! 			(errcode(ERRCODE_PROTOCOL_VIOLATION),
! 			 errmsg(SSL handshake failure on renegotiation, retrying)));
! 	if (retries-- = 0)
! 		ereport(FATAL,
! (errcode(ERRCODE_PROTOCOL_VIOLATION),
!  errmsg(unable to complete SSL handshake)));
! }
! 			}
  

Re: [HACKERS] SSL renegotiation

2013-07-16 Thread Robert Haas
On Fri, Jul 12, 2013 at 8:51 PM, Noah Misch n...@leadboat.com wrote:
 On Fri, Jul 12, 2013 at 04:32:52PM -0400, Alvaro Herrera wrote:
 Now, should we support the 0.9.6-and-earlier mechanism?  My inclination
 is no; even RHEL 3, the oldest supported Linux distribution, uses 0.9.7
 (Heck, even Red Hat Linux 9, released on 2003).  To see OpenSSL 0.9.6
 you need to go back to Red Hat Linux 7.2, released on 2001 using a Linux
 kernel 2.4.  Surely no one in their right mind would use a current
 Postgres release on such an ancient animal.

 Agreed.  The OpenSSL Project last applied a security fix to 0.9.6 over eight
 years ago.  Compatibility with 0.9.6 has zero or negative value.

+1 from me as well, if any more are needed.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-16 Thread David Fetter
On Fri, Jul 12, 2013 at 08:51:52PM -0400, Noah Misch wrote:
 On Fri, Jul 12, 2013 at 04:32:52PM -0400, Alvaro Herrera wrote:
  Now, should we support the 0.9.6-and-earlier mechanism?  My
  inclination is no; even RHEL 3, the oldest supported Linux
  distribution, uses 0.9.7 (Heck, even Red Hat Linux 9, released on
  2003).  To see OpenSSL 0.9.6 you need to go back to Red Hat Linux
  7.2, released on 2001 using a Linux kernel 2.4.  Surely no one in
  their right mind would use a current Postgres release on such an
  ancient animal.
 
 Agreed.  The OpenSSL Project last applied a security fix to 0.9.6
 over eight years ago.  Compatibility with 0.9.6 has zero or negative
 value.

You've made a persuasive case that we should actively break backward
compatibility here.  Would that be complicated to do?

Cheers,
David.
-- 
David Fetter da...@fetter.org http://fetter.org/
Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
Skype: davidfetter  XMPP: david.fet...@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-16 Thread Noah Misch
On Tue, Jul 16, 2013 at 10:41:44AM -0700, David Fetter wrote:
 On Fri, Jul 12, 2013 at 08:51:52PM -0400, Noah Misch wrote:
  Agreed.  The OpenSSL Project last applied a security fix to 0.9.6
  over eight years ago.  Compatibility with 0.9.6 has zero or negative
  value.
 
 You've made a persuasive case that we should actively break backward
 compatibility here.  Would that be complicated to do?

Nope.  If Alvaro's code change builds under 0.9.6, malfunctioning only at
runtime, I suspect we would add a configure-time version check and possibly
a runtime one as well.

-- 
Noah Misch
EnterpriseDB http://www.enterprisedb.com


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-12 Thread Alvaro Herrera
Troels Nielsen escribió:
 Hi,
 
 These are the relevant bits from Apache2.4's mod_ssl.
 
 [snip]

So this is basically the same thing the Pg code is doing.

 That code supports at least OpenSSL 0.9.7 and later.
 
 Some explanation for it can be found here:
 
 http://books.google.dk/books?id=IIqwAy4qEl0Cpg=PT184lpg=PT184dq=SSL_do_handshakesource=blots=ma632U4vWvsig=d2qqS0svhu4EwIZZaONdHoTulVIhl=ensa=Xei=xdPdUczoDuf34QSzmoDQDgved=0CIIDEOgBMCo
 
 The snippet there is probably the textbook implementation.

Ah, thanks for the pointer.  I notice this book is from 2002 and
documents OpenSSL 0.9.6.

So yeah, that's what both mod_ssl and Pg implement.  However, reading
the text carefully, I see that this snippet is the correct
implementation for 0.9.6 and earlier; the same book, speaking about the
0.9.7 release in the future tense, explains that in that release it will
be much easier to do renegotiations, without getting into precise
details of how exactly is to be done (I suppose the OpenSSL team hadn't
finalized the API yet).  As far as I can understand, what I propose is
the right sequence.

Now, should we support the 0.9.6-and-earlier mechanism?  My inclination
is no; even RHEL 3, the oldest supported Linux distribution, uses 0.9.7
(Heck, even Red Hat Linux 9, released on 2003).  To see OpenSSL 0.9.6
you need to go back to Red Hat Linux 7.2, released on 2001 using a Linux
kernel 2.4.  Surely no one in their right mind would use a current
Postgres release on such an ancient animal.

So I continue to maintain that we should rip the old mechanism out and
replace it with current renegotiation.

Now, I've read a bit more of the code and it seems that we should be
doing SSL_renegotiate() and then check the SSL_renegotiate_pending()
result until it returns that the renegotiation has completed.

 So the original code looks OK. Perhaps the check
 on the return code of the first SSL_do_handshake (and SSL_renegotiate)
 is unnecessary and may lead to unwarranted error messages, though.
 And it may be wrong to continue the renegotiation if
 the state is not SSL_ST_OK after the first SSL_do_handshake.
 
 If the renegotiation fails, I suppose two things can be done:
 1. Quit the connection
 2. Carry on pretending nothing happened.
 
 I think 2. is correct  in the vast majority of cases (as it looks like is
 being done now).
 And in that case: not resetting  port-count will make for a very slow
 and awkward connection as new handshakes will be attempted again and again,
 even if the other party persistently refuse to shake hands.

Good point.  From a security point of view, it seems that the correct
reaction is to close the connection if renegotiation doesn't complete.

Along the same lines, it seems to me that accepting SSLv2 (which doesn't
support renegotiations at all) when renegotiations have been requested
is not a good choice; we should accept only SSLv3 in that case.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-12 Thread Noah Misch
On Fri, Jul 12, 2013 at 04:32:52PM -0400, Alvaro Herrera wrote:
 Now, should we support the 0.9.6-and-earlier mechanism?  My inclination
 is no; even RHEL 3, the oldest supported Linux distribution, uses 0.9.7
 (Heck, even Red Hat Linux 9, released on 2003).  To see OpenSSL 0.9.6
 you need to go back to Red Hat Linux 7.2, released on 2001 using a Linux
 kernel 2.4.  Surely no one in their right mind would use a current
 Postgres release on such an ancient animal.

Agreed.  The OpenSSL Project last applied a security fix to 0.9.6 over eight
years ago.  Compatibility with 0.9.6 has zero or negative value.

-- 
Noah Misch
EnterpriseDB http://www.enterprisedb.com


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-11 Thread Stuart Bishop
On Thu, Jul 11, 2013 at 4:20 AM, Alvaro Herrera
alvhe...@2ndquadrant.com wrote:

 I'm having a look at the SSL support code, because one of our customers
 reported it behaves unstably when the network is unreliable.  I have yet
 to reproduce the exact problem they're having, but while reading the
 code I notice this in be-secure.c:secure_write() :

The recap of my experiences you requested...

I first saw SSL renegotiation failures on Ubuntu 10.04 LTS (Lucid)
with openssl 0.9.8 (something). I think this was because SSL
renegotiation had been disabled due to due to CVE 2009-3555 (affecting
all versions before 0.9.8l). I think the version now in lucid is
0.9.8k with fixes for SSL renegotiation, but I haven't tested this.

The failures I saw with no-renegotiation-SSL for streaming replication
looked like this:

On the master:

2012-06-25 16:16:26 PDT LOG: SSL renegotiation failure
2012-06-25 16:16:26 PDT LOG: SSL error: unexpected record
2012-06-25 16:16:26 PDT LOG: could not send data to client: Connection
reset by peer

On the hot standby:

2012-06-25 11:12:11 PDT FATAL: could not receive data from WAL stream:
SSL error: sslv3 alert unexpected message
2012-06-25 11:12:11 PDT LOG: record with zero length at 1C5/95D2FE00


Now I'm running Ubuntu 12.04 LTS (Precise) with openssl 1.0.1, and I
think all the known renegotiation issues have been dealt with. I still
get failures, but they are less informative:

postgres@[unknown]:19761 2013-03-15 03:55:12 UTC LOG: SSL
renegotiation failure


-- 
Stuart Bishop stu...@stuartbishop.net
http://www.stuartbishop.net/


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-11 Thread Claudio Freire
On Thu, Jul 11, 2013 at 1:13 AM, Sean Chittenden s...@chittenden.org wrote:
 , I suppose two things can be done:

 1. Quit the connection

 With my Infosec hat on, this is the correct option - force the client
 back in to compliance with whatever the stated crypto policy is through
 a reconnection.

 2. Carry on pretending nothing happened.

 This is almost never correct in a security context (all errors or
 abnormalities must boil up).

 I think 2 is correct  in the vast majority of cases (as it looks like
 is being done now).

 That is a correct statement in that most code disregards renegotiation,
 but that is because there is a pragmatic assumption that HTTPS
 connections will be short lived. In the case of PostgreSQL, there is a
 good chance that a connection will be established for weeks or months.
 In the case of Apache, allowing a client to renegotiate every byte would
 be a possible CPU DoS, but I digress


And, allowing the client to refuse to renegotiate leaves the relevant
vulnerability unpatched. Renegotiation was introduced to patch a
vulnerability in which, without renegotiation, there was the
possibility of an attacker gaining knowledge of session keys (and
hence the ability to intercept the stream).

I think 2 is not viable in this context. Only 1.


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-10 Thread Alvaro Herrera
I think this block is better written as:

if (ssl_renegotiation_limit  port-count  ssl_renegotiation_limit * 
1024L)
{
SSL_set_session_id_context(port-ssl, (void *) SSL_context,
   sizeof(SSL_context));
if (SSL_renegotiate(port-ssl) = 0)
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
 errmsg(SSL renegotiation failure in renegotiate)));
else
{
inthandshake;

do {
handshake = SSL_do_handshake(port-ssl);
if (handshake = 0)
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
 errmsg(SSL renegotiation failure in 
handshake, retrying)));
} while (handshake = 0);

if (port-ssl-state != SSL_ST_OK)
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
 errmsg(SSL failed to send renegotiation 
request)));
else
port-count = 0;
}
}

In other words, retry the SSL_do_handshake() until it reports OK, but
not more than that; this seems to give better results in my (admittedly
crude) experiments.  I am unsure about checking port-ssl-state after
the handshake; it's probably pointless, really.

In any case, the old code was calling SSL_do_handshake() even if
SSL_renegotiate() failed; and it was resetting the port-count even if
the handshake failed.  Both of these smell like bugs to me.

-- 
Álvaro Herrerahttp://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training  Services


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers


Re: [HACKERS] SSL renegotiation

2013-07-10 Thread Troels Nielsen
Hi,

These are the relevant bits from Apache2.4's mod_ssl.

SSL_renegotiate(ssl);
SSL_do_handshake(ssl);

if (SSL_get_state(ssl) != SSL_ST_OK) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02225)
  Re-negotiation request failed);
ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r-server);

r-connection-keepalive = AP_CONN_CLOSE;
return HTTP_FORBIDDEN;
}

ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02226)
  Awaiting re-negotiation handshake);

/* XXX: Should replace setting state with SSL_renegotiate(ssl);
 * However, this causes failures in perl-framework currently,
 * perhaps pre-test if we have already negotiated?
 */
#ifdef OPENSSL_NO_SSL_INTERN
SSL_set_state(ssl, SSL_ST_ACCEPT);
#else
ssl-state = SSL_ST_ACCEPT;
#endif
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, APLOGNO(02261)
  Re-negotiation handshake failed: 
  Not accepted by client!?);

r-connection-keepalive = AP_CONN_CLOSE;
return HTTP_FORBIDDEN;
}

That code supports at least OpenSSL 0.9.7 and later.

Some explanation for it can be found here:

http://books.google.dk/books?id=IIqwAy4qEl0Cpg=PT184lpg=PT184dq=SSL_do_handshakesource=blots=ma632U4vWvsig=d2qqS0svhu4EwIZZaONdHoTulVIhl=ensa=Xei=xdPdUczoDuf34QSzmoDQDgved=0CIIDEOgBMCo

The snippet there is probably the textbook implementation.

So the original code looks OK. Perhaps the check
on the return code of the first SSL_do_handshake (and SSL_renegotiate)
is unnecessary and may lead to unwarranted error messages, though.
And it may be wrong to continue the renegotiation if
the state is not SSL_ST_OK after the first SSL_do_handshake.

If the renegotiation fails, I suppose two things can be done:
1. Quit the connection
2. Carry on pretending nothing happened.

I think 2. is correct  in the vast majority of cases (as it looks like is
being done now).
And in that case: not resetting  port-count will make for a very slow
and awkward connection as new handshakes will be attempted again and again,
even if the other party persistently refuse to shake hands.

Kind Regards
Troels Nielsen


On Thu, Jul 11, 2013 at 12:34 AM, Alvaro Herrera
alvhe...@2ndquadrant.comwrote:

 I think this block is better written as:

 if (ssl_renegotiation_limit  port-count 
 ssl_renegotiation_limit * 1024L)
 {
 SSL_set_session_id_context(port-ssl, (void *) SSL_context,
sizeof(SSL_context));
 if (SSL_renegotiate(port-ssl) = 0)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL renegotiation failure in
 renegotiate)));
 else
 {
 inthandshake;

 do {
 handshake = SSL_do_handshake(port-ssl);
 if (handshake = 0)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL renegotiation failure in
 handshake, retrying)));
 } while (handshake = 0);

 if (port-ssl-state != SSL_ST_OK)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL failed to send renegotiation
 request)));
 else
 port-count = 0;
 }
 }

 In other words, retry the SSL_do_handshake() until it reports OK, but
 not more than that; this seems to give better results in my (admittedly
 crude) experiments.  I am unsure about checking port-ssl-state after
 the handshake; it's probably pointless, really.

 In any case, the old code was calling SSL_do_handshake() even if
 SSL_renegotiate() failed; and it was resetting the port-count even if
 the handshake failed.  Both of these smell like bugs to me.

 --
 Álvaro Herrerahttp://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training  Services


 --
 Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
 To make changes to your subscription:
 http://www.postgresql.org/mailpref/pgsql-hackers



Re: [HACKERS] SSL renegotiation

2013-07-10 Thread Sean Chittenden
 If the renegotiation fails

AH! Now I remember. SSL clients can optionally renegotiate, it's not
required to renegotiate the session if the other side chooses not to
(almost certainly due to a bug or limitation in the client's connecting
library). By monkeying with the state, you can explicitly force a client
to renegotiate.

I don't think in code from yesteryear it was portable or possible to see
if the server successfully renegotiated a connection before 0.9.6, so
you just forced the client to renegotiate after the server and ignored
the result. A client pausing for a few extra round trips was probably
never noticed. I'm not saying this is correct, but I think that was the
thinking back in the day.

 , I suppose two things can be done:

 1. Quit the connection

With my Infosec hat on, this is the correct option - force the client
back in to compliance with whatever the stated crypto policy is through
a reconnection.

 2. Carry on pretending nothing happened.

This is almost never correct in a security context (all errors or
abnormalities must boil up).

 I think 2 is correct  in the vast majority of cases (as it looks like
 is being done now).

That is a correct statement in that most code disregards renegotiation,
but that is because there is a pragmatic assumption that HTTPS
connections will be short lived. In the case of PostgreSQL, there is a
good chance that a connection will be established for weeks or months.
In the case of Apache, allowing a client to renegotiate every byte would
be a possible CPU DoS, but I digress

 And in that case: not resetting  port-count will make for a very slow
 and awkward connection as new handshakes will be attempted again and
 again,
 even if the other party persistently refuse to shake hands.

Which could lead to a depletion of random bits. This sounds like a
plausible explanation to me.


Too bad we're stuck using an ill-concieved SSL implementation and can't
use botan[1].

 I think this block is better written as:

 if (ssl_renegotiation_limit  port-count 
 ssl_renegotiation_limit * 1024L)

I don't think the  * 1024L is right.

 {
 SSL_set_session_id_context(port-ssl, (void *)
 SSL_context,
sizeof(SSL_context));
 if (SSL_renegotiate(port-ssl) = 0)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL renegotiation failure in
 renegotiate)));
 else
 {
 inthandshake;

 do {
 handshake = SSL_do_handshake(port-ssl);
 if (handshake = 0)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL renegotiation failure
 in handshake, retrying)));
 } while (handshake = 0);

It's worth noting that for broken SSL implementations or SSL
implementations that refuse to renegotiate, this will be yield a stalled
connection, though at least it will be obvious in the logs. I think this
is the correct approach.

It is probably prudent to set an upper bound on this loop in order to
free up the resource and unblock the client who will appear to be
mysteriously hung for no reason until they look at the PostgreSQL server
logs.

 if (port-ssl-state != SSL_ST_OK)
 ereport(COMMERROR,
 (errcode(ERRCODE_PROTOCOL_VIOLATION),
  errmsg(SSL failed to send
 renegotiation request)));
 else
 port-count = 0;
 }
 }

 In other words, retry the SSL_do_handshake() until it reports OK, but
 not more than that; this seems to give better results in my
 (admittedly
 crude) experiments.  I am unsure about checking port-ssl-state after
 the handshake; it's probably pointless, really.

Correct. In async IO, this would be important, but since the server is
synchronous in its handling of communication, we can remove the if/else
(state != SSL_ST_OK) block.

 In any case, the old code was calling SSL_do_handshake() even if
 SSL_renegotiate() failed; and it was resetting the port-count even if
 the handshake failed.  Both of these smell like bugs to me.

I don't know how SSL_renegotiate() could fail in the past.
SSL_renegotiate(3) should never fail on a well formed implementation
(e.g. ssl/t1_reneg.c @ssl_add_serverhello_renegotiate_ext()).


While we're on the subject of crypto and OpenSSL, we force server
ciphers to be preferred instead of client ciphers:

  SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE);

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

SSL_get_secure_renegotiation_support() would