[openssl-dev] [openssl.org #3712] TLS Renegotiation with Java is broken
Albe Laurenz via RT
rt at openssl.org
Wed Feb 18 20:12:09 UTC 2015
I ran into this problem while connecting to a PostgreSQL server (PostgreSQL uses OpenSSL
for SSL support) with a Java client using the PostgreSQL JDBC driver (which uses
the Java Secure Socket Extension which is part of Oracle's Java Runtime Environment).
Since database connections are potentially long-lived, the PostgreSQL server will
trigger a renegotiation after a certain amount of data has been exchanged via the
TLS channel; this amount is configurable with the parameter "ssl_renegotiation_limit".
This renegotiation is always aborted by OpenSSL with the error "unexpected record".
I could reproduce the problem with OpenSSL 1.0.1e on Linux and OpenSSL 1.0.1j on
Windows using Oracle JRE 1.7.0_71 and 1.7.0_75 on the client side.
The protocol version in effect is TLS 1.2 (0x303).
I will describe the problem in more detail below, but my conclusion is that OpenSSL
violates RFC 5246 (TLS 1.2) and RFC 4346 (TLS 1.1) since it chokes on an "Application
Data" record received right after it has sent a "Server Hello Done" record.
At this point OpenSSL waits for a "Client Certificate" or a "Client Key Exchange" record
and is not ready to receive application data.
However, RFC 5246 and RFC 4346 state at the end of chapter 6.2.1:
Note: Data of different TLS Record layer content types MAY be
interleaved. Application data is generally of lower precedence for
transmission than other content types. However, records MUST be
delivered to the network in the same order as they are protected by
the record layer. Recipients MUST receive and process interleaved
application layer traffic during handshakes subsequent to the first
one on a connection.
The last sentence clearly puts the blame on OpenSSL.
This seems to be an addition in TLS 1.1 since it cannot be found in RFC 2246.
The problem is likely not restricted to PostgreSQL, but a generic problem that
will affect all renegotiations between JSSE and OpenSSL.
The only workaround is to disable renegotiation, but that will reduce the
security of the communication.
Yours,
Laurenz Albe
Detailed analysis using OpenSSL 1.0.1e on RedHat Enterprise Linux 6:
The OpenSSL error is thrown in this part of the code:
https://github.com/openssl/openssl/blob/master/ssl/s3_pkt.c#L1601
(the code does not seem to have changed substantially since 1.0.1e).
The stack trace at the time is like this:
#0 ssl3_read_bytes (s=0x228d6a0, type=22, buf=0x231ee20 "\016", len=4, peek=0) at s3_pkt.c:1421
#1 0x00000039d402dac2 in ssl3_get_message (s=0x228d6a0, st1=8576, stn=8577, mt=-1, max=102400, ok=0x7fffe6bcfe1c) at s3_both.c:457
#2 0x00000039d401e36a in ssl3_check_client_hello (s=0x228d6a0) at s3_srvr.c:873
#3 0x00000039d40219db in ssl3_accept (s=0x228d6a0) at s3_srvr.c:572
#4 0x00000039d402c9a8 in ssl3_read_bytes (s=0x228d6a0, type=23, buf=0xd9b4e0 "P", len=8192, peek=0) at s3_pkt.c:1342
#5 0x00000039d4027ec0 in ssl3_read_internal (s=0x228d6a0, buf=0xd9b4e0, len=8192, peek=0) at s3_lib.c:4273
#6 0x0000000000698df1 in be_tls_read (port=0x228d490, ptr=0xd9b4e0, len=8192) at be-secure-openssl.c:572
#7 0x00000000006880d3 in secure_read (port=0x228d490, ptr=0xd9b4e0, len=8192) at be-secure.c:135
[...]
s->version is 0x301 (TLS 1.2), and s->state is 0x2180 (SSL3_ST_SR_CERT_A).
I put SSL_CTX_set_info_callback and SSL_CTX_set_msg_callback into the PostgreSQL source,
and the output looks as follows:
info_callback: SSL_accept:SSL renegotiate ciphers
msg_callback: write 0x303 handshake 00...
info_callback: SSL_accept:SSLv3 write hello request A
info_callback: SSL_accept:SSLv3 flush data
info_callback: SSL_accept:SSLv3 write hello request C
info_callback: SSL_accept:before accept initialization
msg_callback: read 0x303 handshake 01...
info_callback: SSL_accept:SSLv3 read client hello A
msg_callback: write 0x303 handshake 02...
info_callback: SSL_accept:SSLv3 write server hello A
msg_callback: write 0x303 handshake 0B...
info_callback: SSL_accept:SSLv3 write certificate A
msg_callback: write 0x303 handshake 0C...
info_callback: SSL_accept:SSLv3 write key exchange A
msg_callback: write 0x303 handshake 0E...
info_callback: SSL_accept:SSLv3 write server done A
info_callback: SSL_accept:SSLv3 flush data
msg_callback: write 0x303 alert 02...
info_callback: SSL3 alert write:fatal:unexpected_message
info_callback: SSL_accept:error in SSLv3 read client certificate A
I used Wireshark to capture the network communication, and the result
looks like this (the offending "Application Data" record must be number 44):
No. Source Destination Protocol Length Info
28 Java client OpenSSL server TLSv1.2 203 Application Data
29 OpenSSL server Java client TLSv1.2 235 Application Data
30 OpenSSL server Java client TLSv1.2 219 Application Data
31 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1199 Ack=3272 Win=65536 Len=0
32 OpenSSL server Java client TCP 1514 [TCP segment of a reassembled PDU]
33 OpenSSL server Java client TCP 1514 [TCP segment of a reassembled PDU]
34 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1199 Ack=6192 Win=65536 Len=0
35 OpenSSL server Java client TCP 1514 [TCP segment of a reassembled PDU]
36 OpenSSL server Java client TCP 1514 [TCP segment of a reassembled PDU]
37 OpenSSL server Java client TCP 1514 [TCP segment of a reassembled PDU]
38 OpenSSL server Java client TLSv1.2 1031 Application Data
39 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1199 Ack=11549 Win=65536 Len=0
40 OpenSSL server Java client TLSv1.2 139 Encrypted Handshake Message
41 OpenSSL server Java client TLSv1.2 1003 Application Data
42 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1199 Ack=12583 Win=64512 Len=0
43 Java client OpenSSL server TLSv1.2 443 Encrypted Handshake Message
44 Java client OpenSSL server TLSv1.2 203 Application Data
45 OpenSSL server Java client TCP 60 5432→49860 [ACK] Seq=12583 Ack=1737 Win=22144 Len=0
46 OpenSSL server Java client TLSv1.2 1514 Encrypted Handshake Message, Encrypted Handshake Message
47 OpenSSL server Java client TLSv1.2 342 Encrypted Handshake Message
48 OpenSSL server Java client TLSv1.2 139 Encrypted Alert
49 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1737 Ack=14416 Win=65536 Len=0
50 OpenSSL server Java client TCP 60 5432→49860 [FIN, ACK] Seq=14416 Ack=1737 Win=22144 Len=0
51 Java client OpenSSL server TCP 54 49860→5432 [ACK] Seq=1737 Ack=14417 Win=65536 Len=0
52 Java client OpenSSL server TLSv1.2 203 Encrypted Handshake Message
53 OpenSSL server Java client TCP 60 5432→49860 [RST] Seq=14417 Win=0 Len=0
This is the Java program I use to reproduce the problem:
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=username&password=pwd&ssl&sslfactory=org.postgresql.ssl.NonValidatingFactory");
java.sql.Statement stmt = conn.createStatement();
stmt.execute("SET ssl_renegotiation_limit='3kB'");
stmt.executeQuery("SELECT repeat('0123456789', 900)").close();
stmt.executeQuery("SELECT repeat('0123456789', 900)").close();
conn.close();
}
}
More information about the openssl-dev
mailing list