Обсуждение: SSL renegotiation is broken

Поиск
Список
Период
Сортировка

SSL renegotiation is broken

От
Albe Laurenz
Дата:
It seems that SSL renegotiation between the JDBC driver and
the PostgreSQL server is broken and has been forever, or at least
for a while.

I tried this test program:

public class PGConn {
    public static void main(String[] args) throws ClassNotFoundException, java.sql.SQLException, java.io.IOException {
        Class.forName("org.postgresql.Driver");
        java.sql.Connection conn =
java.sql.DriverManager.getConnection("jdbc:postgresql://hostname/dbname?user=me&password=pwd&ssl&sslfactory=org.postgresql.ssl.NonValidatingFactory");
        java.sql.Statement stmt = conn.createStatement();
        stmt.execute("SET ssl_renegotiation_limit='3kB'");
        System.out.println("First SELECT.");
        stmt.executeQuery("SELECT repeat('0123456789', 900)").close();
        System.out.println("Second SELECT.");
        stmt.executeQuery("SELECT repeat('0123456789', 900)").close();
        conn.close();
        System.out.println("Done.");
    }
}

The result is:

First SELECT.
Second SELECT.
Exception in thread "main" org.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:283)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:570)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:406)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:286)
    at PGConn.main(PGConn.java:19)
Caused by: javax.net.ssl.SSLException: Received fatal alert: unexpected_message
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1979)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1086)
    at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1725)
    at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:122)
    at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:970)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:341)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:901)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:837)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1023)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:891)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
    at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:143)
    at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:112)
    at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:71)
    at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:282)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1803)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    ... 4 more

I can reproduce this with the following software versions:
Client side:
   Windows, JDBC driver postgresql-9.1-901.jdbc4, java full version "1.7.0_71-b14"
   Linux, JDBC driver postgresql-9.4-1200.jdbc41, java full version "1.7.0_75-mockbuild_2015_01_08_20_32-b00"
Server side:
   Windows: PostgreSQL 9.4.0 with OpenSSL 1.0.1j
   Linux: PostgreSQL 9.3.6, 9.4.1, git HEAD with OpenSSL 1.0.1e

All of these Java and OpenSSL versions are recent enough to adhere to RFC 5746.

There must be a software bug somewhere.
I am trying to debug this, but don't know a lot aboult TLS, so
if somebody can shed light on this, I'd be grateful.

Yours,
Laurenz Albe

Re: SSL renegotiation is broken

От
Heikki Linnakangas
Дата:
On 02/11/2015 05:02 PM, Albe Laurenz wrote:
> It seems that SSL renegotiation between the JDBC driver and
> the PostgreSQL server is broken and has been forever, or at least
> for a while.

Hah, we're just discussing similar issues over at pgsql-hackers :-).

> I can reproduce this with the following software versions:
> Client side:
>     Windows, JDBC driver postgresql-9.1-901.jdbc4, java full version "1.7.0_71-b14"
>     Linux, JDBC driver postgresql-9.4-1200.jdbc41, java full version "1.7.0_75-mockbuild_2015_01_08_20_32-b00"
> Server side:
>     Windows: PostgreSQL 9.4.0 with OpenSSL 1.0.1j
>     Linux: PostgreSQL 9.3.6, 9.4.1, git HEAD with OpenSSL 1.0.1e
>
> All of these Java and OpenSSL versions are recent enough to adhere to RFC 5746.
>
> There must be a software bug somewhere.

I could reproduce this too, thanks for the test case. It looks like an
OpenSSL bug to me.

> I am trying to debug this, but don't know a lot aboult TLS, so
> if somebody can shed light on this, I'd be grateful.

I've been reading on the subject in the last few days, and I think I'm
enough up to speed now to understand this. I launched the test program
in a debugger to see what messages are exchanged during the renegotiation.

Renegotiation at the protocol level is always initiated by the Client.
When the server wants to initiate it, it just sends a message to the
client that means "hey, could you begin renegotiation, please?". The
actual handshake goes something like this:

C: ClientHello
S: ServerHello (or a bunch of other messages?)
S: ServerHelloDone
C: ClientKeyExchange
C: ChangeCipherSpec
C: Finished
S: ChangeCipherSpec
S: Finished

Now, what happens in this test case is that the client also sends
ApplicationData messages between the ClientHello and Finished steps,
interleaved with the above handshake messages. According to the TLS
spec, that is allowed, but OpenSSL get confused by it.

I can't come up with any way to work around that, unfortunately :-(.
- Heikki



Re: SSL renegotiation is broken

От
Albe Laurenz
Дата:
Heikki Linnakangas wrote:
> On 02/11/2015 05:02 PM, Albe Laurenz wrote:
>> It seems that SSL renegotiation between the JDBC driver and
>> the PostgreSQL server is broken and has been forever, or at least
>> for a while.
> 
> Hah, we're just discussing similar issues over at pgsql-hackers :-).

> I could reproduce this too, thanks for the test case. It looks like an
> OpenSSL bug to me.

> I've been reading on the subject in the last few days, and I think I'm
> enough up to speed now to understand this. I launched the test program
> in a debugger to see what messages are exchanged during the renegotiation.
> 
> Renegotiation at the protocol level is always initiated by the Client.
> When the server wants to initiate it, it just sends a message to the
> client that means "hey, could you begin renegotiation, please?". The
> actual handshake goes something like this:
> 
> C: ClientHello
> S: ServerHello (or a bunch of other messages?)
> S: ServerHelloDone
> C: ClientKeyExchange
> C: ChangeCipherSpec
> C: Finished
> S: ChangeCipherSpec
> S: Finished
> 
> Now, what happens in this test case is that the client also sends
> ApplicationData messages between the ClientHello and Finished steps,
> interleaved with the above handshake messages. According to the TLS
> spec, that is allowed, but OpenSSL get confused by it.
> 
> I can't come up with any way to work around that, unfortunately :-(.

Thanks for that, my further analysis corroborates your findings.

I have opened a bug with OpenSSL:
http://rt.openssl.org/Ticket/Display.html?id=3712&user=guest&pass=guest

But even if they fix it, it will take some time until Linux distributions
like RHEL will ship with a fixed version.

So it looks like the only option is for Java clients to run with
"ssl_renegotiation_limit=0" for the time being.

Yours,
Laurenz Albe