Bug 1234487

Summary: Renegotiation seems partially broken in latest openssl
Product: Red Hat Enterprise Linux 6 Reporter: Tom Lane <tgl>
Component: opensslAssignee: Tomas Mraz <tmraz>
Status: CLOSED ERRATA QA Contact: Alicja Kario <hkario>
Severity: high Docs Contact:
Priority: high    
Version: 6.6CC: bcholler, bruno, hkario, jeharris, ksrot, luvilla, michele, mschuppe, myamazak, praiskup, tlavigne, tmraz
Target Milestone: rcKeywords: Regression
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: openssl-1.0.1e-42.el6 Doc Type: Bug Fix
Doc Text:
The server-side renegotiation support did previously not work as expected under certain circumstances. A PostgreSQL failure of database dumps through TLS connection could occur when the size of the dumped data was larger than the value defined in the ssl_renegotiation_limit setting. The regression that caused this bug has been fixed, and the PostgreSQL database dumps through TLS connection no longer fail in the described situation.
Story Points: ---
Clone Of:
: 1234801 (view as bug list) Environment:
Last Closed: 2015-07-22 07:31:44 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Tom Lane 2015-06-22 16:02:26 UTC
Description of problem:
After updating to last week's openssl security release, Postgres is no longer able to transfer more than about 2GB across an SSL-encrypted connection.

Version-Release number of selected component (if applicable):
openssl-1.0.1e-30.el6_6.11.x86_64
Problem did not occur with openssl-1.0.1e-30.el6_6.9.x86_64

How reproducible:
100%

Steps to Reproduce:
1. Configure a Postgres database with SSL enabled.
2. Create a database having more than 2GB of data in it (doesn't much matter what)
3. pg_dump -h localhost databasename >dumpfile

(must connect to localhost, not via a Unix socket, else SSL isn't used)

Actual results:
After emitting something over 2GB into the dump file, pg_dump fails with
pg_dump: [archiver (db)] query failed: SSL error: unexpected message
pg_dump: [archiver (db)] query was: SET search_path = public, pg_catalog
(the specific query that fails varies depending on the exact test case).

The server-side log looks like
LOG:  SSL error: sslv3 alert unexpected message
LOG:  could not receive data from client: Connection reset by peer
LOG:  unexpected EOF on client connection with an open transaction

Expected results:
Dump should complete successfully.

Additional info:
In my tests, setting ssl_renegotiation_limit = 0 (ie, disabling renegotiation) in postgresql.conf allows the dump to complete.  Curiously, however, changing ssl_renegotiation_limit from its default of 512MB to something else such as 10MB doesn't seem to have any effect on how soon the failure occurs.  In either case several renegotiations should have been completed before failure.  It kind of smells like a 32-bit-counter-overflow problem, but I dunno where such a counter could be.

I've personally reproduced this with current Postgres development tip, and there are reports in the Postgres mailing lists of similar failures with Postgres 8.4.9 and 9.2.13, so it seems pretty much independent of exactly which Postgres version you use.  Also, we are not hearing reports of such failures with any other vendor's OpenSSL.

This is of course not to rule out that the problem could be in Postgres.  I'd be happy to help try to narrow it down, if you can suggest things to test.

Comment 5 Alicja Kario 2015-06-23 13:01:43 UTC
It looks to me as it's the server side initiated renegotiation that is broken.

Simple reproducer:
In console one:
openssl req -x509 -newkey rsa:2048 -keyout localhost.key -out localhost.crt -subj /CN=localhost -nodes -batch -sha256
openssl s_server -key localhost.key -cert localhost.crt

In console two:
openssl s_client

after connection is established, do a renegotiation by entering "R<enter>", the result should be:

depth=0 CN = localhost
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = localhost
verify return:1

Now go back to console one, enter there "R<enter>", the connection will be aborted with following message:
SSL_do_handshake -> 1
ERROR
140398384944968:error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message:s3_pkt.c:1259:SSL alert number 10
140398384944968:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:1346:
shutting down SSL

Comment 9 Tom Lane 2015-06-23 17:06:25 UTC
The test case that Hubert shows may be exhibiting an independent issue.  I've now traced through the behavior seen in Postgres, and confirmed that we are successfully executing multiple renegotiation cycles (started by calling SSL_renegotiate(), and ended by observing that SSL_num_renegotiations() has advanced).  The number of such cycles does not seem to matter.  What seems to be happening is that once the server has transmitted 2GB of data, if there have been renegotiations, then the next SSL_read() call fails with SSLerrmessage() yielding "sslv3 alert unexpected message".

Comment 10 Tom Lane 2015-06-23 18:13:50 UTC
Also, some further information: Postgres 9.4 and later behave differently than previous branches.  In 9.3.x and earlier the code that calls SSL_renegotiate() is structured quite a lot differently, and it seems to fail at the second renegotiation attempt.  So the external symptom looks nearly the same, but it can be triggered with just a little bit of data if you make ssl_renegotiation_limit small but not zero.  What I described above is the behavior in 9.4 and later.  I do not know whether the openssl bug you've acknowledged finding explains both symptoms.

Comment 11 Tomas Mraz 2015-06-24 07:14:17 UTC
I believe the manifestation is different for different Postgres branches but the underlying problem is the same. The renegotiation failure might depend on whether there are data buffered when the renegotiation is triggered. There can be probably cases where the renegotiation succeeds even with the broken openssl package - it depends on ordering and/or packing of the messages sent by the TLS server to the client.

I'll try testing with newer Postgres to be completely sure though.

Comment 12 Alicja Kario 2015-06-24 10:45:15 UTC
(In reply to Tom Lane from comment #9)
> The test case that Hubert shows may be exhibiting an independent issue. 
> I've now traced through the behavior seen in Postgres, and confirmed that we
> are successfully executing multiple renegotiation cycles (started by calling
> SSL_renegotiate(),

It's always that the client sends the Client Hello request to the server to renegotiate.

But for server initiated renegotiation, server sends a hello_request first. This message is what causes the failure on client side, as a response the client sends an unexpected message alert to the server and closes the connection. The server will then report _alert_ unexpected message to the application.

In other words, there are two different error messages: "alert unexpected message" and "unexpected message". Please check if you see the former at the server and the latter at the client.

(In reply to Tomas Mraz from comment #11)
> I believe the manifestation is different for different Postgres branches but
> the underlying problem is the same. The renegotiation failure might depend
> on whether there are data buffered when the renegotiation is triggered.
> There can be probably cases where the renegotiation succeeds even with the
> broken openssl package - it depends on ordering and/or packing of the
> messages sent by the TLS server to the client.
> 
> I'll try testing with newer Postgres to be completely sure though.

There is a bug in OpenSSL where the application data and handshakes can't be intertwined, and I don't believe it is fixed: https://rt.openssl.org/Ticket/Display.html?id=3712&user=guest&pass=guest

but it did exist for a long time in OpenSSL, so the package update shouldn't trigger postgresql failures

Comment 14 Tomas Mraz 2015-06-24 14:00:46 UTC
I've tested the fixed packages with postgreSQL-9.4 and the pg_dump completes fine there.

Comment 16 Tom Lane 2015-06-24 14:12:50 UTC
(In reply to Hubert Kario from comment #12)
> In other words, there are two different error messages: "alert unexpected
> message" and "unexpected message". Please check if you see the former at the
> server and the latter at the client.

See the log snippets in the initial report.  The text after "SSL error: " is verbatim from SSLerrmessage() on each end.  The server-side report is not quite what you say here.

> There is a bug in OpenSSL where the application data and handshakes can't be
> intertwined, and I don't believe it is fixed:
> https://rt.openssl.org/Ticket/Display.html?id=3712&user=guest&pass=guest
> 
> but it did exist for a long time in OpenSSL, so the package update shouldn't
> trigger postgresql failures

Agreed, that one is unlikely to be our immediate problem.

Comment 17 Alicja Kario 2015-06-24 14:44:31 UTC
(In reply to Tom Lane from comment #16)
> (In reply to Hubert Kario from comment #12)
> > In other words, there are two different error messages: "alert unexpected
> > message" and "unexpected message". Please check if you see the former at the
> > server and the latter at the client.
> 
> See the log snippets in the initial report.  The text after "SSL error: " is
> verbatim from SSLerrmessage() on each end.  The server-side report is not
> quite what you say here.

but it matches exactly what I provided in comment #5: "sslv3 alert unexpected message", the important distinction is presence or absence of "alert" in the error message.

Comment 24 errata-xmlrpc 2015-07-22 07:31:44 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHBA-2015-1398.html