SSL intermittent problem when using DH-based ciphers in Java 7 with Linux
Hello,
I am facing an intermittent problem when a SSL client (tested with a Perl 5.1.12 client and a bash+openssl 0.9.8r client) sends multiple messages to a Java SSL server. I have found the problem occurs with Java 7 (1.7.0_15-b03) on Linux (tested on RHEL 6 2.6.32-358.el6.x86_64 and Ubuntu 12.04 LTS), on Mac OS 10.7.5 and Mac OS 10.8.2 on the server side, and regardless of the operating system on the server side. The problem doesn't occur when using a OpenSolaris server. No problem occurs with a Java 6-based server, on any of the mentioned OSes.
Description: after the client has sent a few hundred messages, the client receives an SSL handshake error and a SSLHandshakeException is thrown on the server. The problem seems to be related to the use of Diffie-Hellman-based ciphers: if I force the use of a RSA cipher, no problem occurs.
Here is a setup that replicates the problem. Create a keypair in a java keystore, and run this server:
package edu.berkeley.ist.scratch;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class EchoSSLServer {
public static void main(String[] arstring) {
try {
SSLServerSocketFactory sslserversocketfactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket =
(SSLServerSocket) sslserversocketfactory.createServerSocket(9999);
while (true) {
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println(string);
System.out.flush();
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
Then, run either this Perl client:
use strict;
use IO::Socket::SSL;
my $count=0;
while (1) {
# simple HTTP client -----------------------------------------------
my $sock = IO::Socket::SSL->new(
# where to connect
PeerHost => "<hostname>",
PeerPort => "9999",
# certificate verification
SSL_verify_mode => SSL_VERIFY_NONE,
) or die "failed connect or ssl handshake: $!,$SSL_ERROR";
print $sock "Hello";
$sock->close();
$count++;
print "$count\n";
}
or this bash+openssl client:
count=0
while [ 1 -eq 1 ]
do
echo "Hello" | openssl s_client -connect localhost:9999 >/dev/null
if [ $? -ne 0 ]; then
exit 1
fi
((count+=1))
echo $count
done
After a few hundered iterations, you will see something like this on the client side:
failed connect or ssl handshake: ,IO::Socket::INET6 configuration failederror:00000000:lib(0):func(0):reason(0) at ssl-client.pl line 6.
And this on the server side:
javax.net.ssl.SSLHandshakeException: Invalid Padding length: 81
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1886)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:974)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at edu.berkeley.ist.scratch.EchoSSLServer.main(EchoSSLServer.java:67)
Caused by: javax.crypto.BadPaddingException: Invalid Padding length: 81
at sun.security.ssl.CipherBox.removePadding(CipherBox.java:684)
at sun.security.ssl.CipherBox.decrypt(CipherBox.java:423)
at sun.security.ssl.InputRecord.decrypt(InputRecord.java:154)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:969)
... 11 more
After enabling debug logging for SSL handshake, I see this:
main, READ: SSL v2, contentType = Handshake, translated length = 89
*** ClientHello, TLSv1
RandomCookie: GMT: 0 bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 75, 180, 53, 239, 108, 51, 69, 35, 182, 61, 245, 71, 68, 28, 211 }
Session ID: {}
Cipher Suites: [TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_SEED_CBC_SHA, TLS_DHE_DSS_WITH_SEED_CBC_SHA, TLS_RSA_WITH_SEED_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_RSA_EXPORT_WITH_RC4_40_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods: { 0 }
***
%% Initialized: [Session-232, SSL_NULL_WITH_NULL_NULL]
%% Negotiating: [Session-232, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA]
*** ServerHello, TLSv1
RandomCookie: GMT: 1361908238 bytes = { 210, 137, 20, 192, 173, 40, 205, 3, 242, 185, 80, 19, 198, 183, 44, 63, 3, 149, 97, 175, 153, 239, 243, 97, 92, 200, 110, 212 }
Session ID: {81, 45, 18, 14, 137, 154, 98, 252, 20, 124, 81, 4, 214, 8, 231, 121, 175, 133, 142, 252, 20, 12, 99, 201, 24, 9, 83, 15, 239, 34, 39, 61}
Cipher Suite: SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
Cipher suite: SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=localhost, OU=IST, O="University of California, Berkeley", L=Berkeley, ST=CA, C=US
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 1024 bits
modulus: 100318692587772653487949066254487989918157604545853798061718708748206860158041498924763974217777890645501700365160396601829010852095657193155138078345180085242824268946142257050055468216742995753689139662471328635164222926500994444770172537176817688500963591823961418447303232823489913199105654849046538472289
public exponent: 65537
Validity: [From: Mon Feb 25 11:43:44 PST 2013,
To: Thu Feb 20 11:43:44 PST 2014]
Issuer: CN=localhost, OU=IST, O="University of California, Berkeley", L=Berkeley, ST=CA, C=US
SerialNumber: [ 2cba5851]
Certificate Extensions: 1
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: EC 0B B0 6A 3F 7E D1 9A FD 97 E7 DD C5 7C 00 1E ...j?...........
0010: BD 35 5D 31 .5]1
]
]
]
Algorithm: [SHA256withRSA]
Signature:
0000: 4D C2 29 84 58 2B D6 D2 47 D9 A9 45 68 54 80 9C M.).X+..G..EhT..
0010: 9F CD B1 4D FD 9E B6 AC 74 DF F8 B2 B6 16 BB 9C ...M....t.......
0020: 55 F9 60 DF 3E 86 9E AE 84 65 DC 59 86 92 84 EC U.`.>....e.Y....
0030: F7 7F D2 EE 39 53 26 87 3F B8 69 9E 58 20 C5 75 ....9S&.?.i.X .u
0040: A8 38 23 78 85 2D 61 F8 19 15 8F 5F C6 BF 08 6C .8#x.-a...._...l
0050: DA AD F5 C3 B2 84 67 B3 D4 A2 3C 88 D8 B4 15 15 ......g...<.....
0060: 10 10 B5 D1 8F 93 2F F4 62 D8 A2 24 74 C2 27 1F ....../.b..$t.'.
0070: 33 E4 1C 6A 0C 61 1F DB DC E5 4C F3 B0 83 46 CB 3..j.a....L...F.
]
***
*** Diffie-Hellman ServerKeyExchange
DH Modulus: { 233, 230, 66, 89, 157, 53, 95, 55, 201, 127, 253, 53, 103, 18, 11, 142, 37, 201, 205, 67, 233, 39, 179, 169, 103, 15, 190, 197, 216, 144, 20, 25, 34, 210, 195, 179, 173, 36, 128, 9, 55, 153, 134, 157, 30, 132, 106, 171, 73, 250, 176, 173, 38, 210, 206, 106, 34, 33, 157, 71, 11, 206, 125, 119, 125, 74, 33, 251, 233, 194, 112, 181, 127, 96, 112, 2, 243, 206, 248, 57, 54, 148, 207, 69, 238, 54, 136, 193, 26, 140, 86, 171, 18, 122, 61, 175 }
DH Base: { 48, 71, 10, 213, 160, 5, 251, 20, 206, 45, 157, 205, 135, 227, 139, 199, 209, 177, 197, 250, 203, 174, 203, 233, 95, 25, 10, 167, 163, 29, 35, 196, 219, 188, 190, 6, 23, 69, 68, 64, 26, 91, 44, 2, 9, 101, 216, 194, 189, 33, 113, 211, 102, 132, 69, 119, 31, 116, 186, 8, 77, 32, 41, 216, 60, 28, 21, 133, 71, 243, 169, 241, 162, 113, 91, 226, 61, 81, 174, 77, 62, 90, 31, 106, 112, 100, 243, 22, 147, 58, 52, 109, 63, 82, 146, 82 }
Server DH Public Key: { 172, 67, 73, 181, 25, 206, 209, 77, 79, 31, 226, 46, 83, 69, 140, 140, 22, 195, 111, 42, 172, 99, 197, 235, 173, 157, 97, 136, 79, 75, 116, 206, 222, 83, 158, 57, 134, 161, 188, 133, 1, 207, 15, 220, 98, 36, 187, 164, 222, 202, 244, 16, 77, 55, 212, 165, 120, 146, 239, 61, 5, 118, 28, 83, 254, 68, 1, 221, 73, 103, 218, 108, 174, 252, 122, 71, 71, 31, 195, 106, 87, 23, 53, 162, 130, 82, 44, 61, 9, 149, 25, 50, 93, 91, 9, 76 }
Signed with a DSA or RSA public key
*** ServerHelloDone
main, WRITE: TLSv1 Handshake, length = 1185
main, READ: TLSv1 Handshake, length = 102
*** ClientKeyExchange, DH
DH Public key: { 40, 45, 195, 251, 225, 147, 146, 211, 158, 138, 201, 109, 148, 41, 22, 10, 146, 233, 14, 87, 55, 145, 189, 247, 21, 113, 123, 26, 198, 8, 225, 169, 164, 202, 107, 59, 148, 133, 111, 72, 128, 82, 20, 47, 223, 39, 108, 44, 36, 17, 31, 170, 126, 254, 201, 192, 233, 192, 67, 155, 77, 194, 190, 155, 70, 169, 219, 48, 55, 236, 150, 214, 255, 183, 255, 87, 253, 228, 7, 231, 211, 72, 14, 159, 156, 34, 22, 133, 64, 21, 163, 97, 80, 3, 67, 165 }
SESSION KEYGEN:
PreMaster Secret:
0000: 00 90 1E 38 9D 9E 79 DD 7B 1F B5 0C 7A 58 82 38 ...8..y.....zX.8
0010: 8E 19 8A CD A0 A3 EF A1 DC 3B B1 3E FC 35 C8 97 .........;.>.5..
0020: 1E AF 62 4A 7C 95 52 6B A0 8E A6 94 25 D1 20 06 ..bJ..Rk....%. .
0030: 77 6B 7A 19 7A C7 D8 12 DF 61 97 5E 8E 10 40 E2 wkz.z....a.^..@.
0040: 3B FA A5 64 9B EA D8 50 9C 35 84 36 31 12 04 B2 ;..d...P.5.61...
0050: 4D CE 33 BB 9D E1 8A 2C 99 38 13 99 78 75 8F BF M.3....,.8..xu..
CONNECTION KEYGEN:
Client Nonce:
0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0010: 5D 4B B4 35 EF 6C 33 45 23 B6 3D F5 47 44 1C D3 ]K.5.l3E#.=.GD..
Server Nonce:
0000: 51 2D 12 0E D2 89 14 C0 AD 28 CD 03 F2 B9 50 13 Q-.......(....P.
0010: C6 B7 2C 3F 03 95 61 AF 99 EF F3 61 5C C8 6E D4 ..,?..a....a\.n.
Master Secret:
0000: 6D 72 A2 A0 98 23 31 53 0F 02 E9 8A 95 8A 6E B2 mr...#1S......n.
0010: 4E 61 4F 04 37 16 4C FB D5 3C DC 89 38 5A 30 37 NaO.7.L..<..8Z07
0020: AB E3 E0 4D 36 01 68 1B C1 D6 33 A7 C0 CB FD 1C ...M6.h...3.....
Client MAC write Secret:
0000: 38 45 A5 8C BA 1D 04 9E 19 21 3F C1 2F 1C A0 82 8E.......!?./...
0010: 93 8E 89 88 ....
Server MAC write Secret:
0000: C8 26 BC FA 05 EC DA 66 56 98 31 87 79 87 F3 37 .&.....fV.1.y..7
0010: CC 7B 09 A3 ....
Client write key:
0000: EA E5 A4 37 30 55 20 61 14 51 09 DF 50 EC 8A 94 ...70U a.Q..P...
0010: E4 4A BD 84 0B D4 7E 9D .J......
Server write key:
0000: A3 5C C0 D0 03 49 8E BA 1C 62 88 BF 98 61 10 CC .\...I...b...a..
0010: 57 E6 72 BB 3B 88 9F 3E W.r.;..>
Client write IV:
0000: 64 A7 95 AA F7 61 82 7B d....a..
Server write IV:
0000: A8 62 ED B7 C9 8C 1D 76 .b.....v
main, READ: TLSv1 Change Cipher Spec, length = 1
main, READ: TLSv1 Handshake, length = 40
%% Invalidated: [Session-232, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = handshake_failure
main, WRITE: TLSv1 Alert, length = 2
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Invalid Padding length: 81
javax.net.ssl.SSLHandshakeException: Invalid Padding length: 81
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1886)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:974)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at edu.berkeley.ist.scratch.EchoSSLServer.main(EchoSSLServer.java:67)
Caused by: javax.crypto.BadPaddingException: Invalid Padding length: 81
at sun.security.ssl.CipherBox.removePadding(CipherBox.java:684)
at sun.security.ssl.CipherBox.decrypt(CipherBox.java:423)
at sun.security.ssl.InputRecord.decrypt(InputRecord.java:154)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:969)
... 11 more
The problem goes away if I force the use of a RSA-based cipher, such as SSL_RSA_WITH_3DES_EDE_CBC_SHA.
Has anyone else experienced this problems? Although it is intermittent, it can be replicated at will, it's just a matter of waiting until a few hundred messages (always less than 2000, in my experience) have been exchanged. On Java 6, even if I force the use of DH-based ciphers, no problem occurs.
Thanks to anyone that can help,
Francesco