Hi,
here is an demo to show the problem.
a) The problem is an problem between the key exchange message and the
enabled protocols and the server selected protocol.
b) In this demo it only check if the protocol of the key exchange is
TLSv1.2 while SSLv3 is expected.
c) It also show another issue that the jdk as server does not check if
the received messages matches the selected protocol version.
-> I think this does not open an security issue but should be
verified too, it maybe wanted for compatibility but than it should be
configurable per connection.
Gruß Thomas Lußnig
package demo;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
class CheckPrintStream extends PrintStream {
public CheckPrintStream() { super(System.out); }
@Override public void write(final byte[] buf, final int off, final
int len) {
final String t = new String(buf, off, len);
if(t.contains("RSA ClientKeyExchange")) {
if(t.contains("\"client_version\": TLSv1.2")) {
System.out.println("CHECK Failed");
final int p = t.indexOf("TLSv1.2");
super.write(buf, off, p+7);
super.write('\n');
}
else super.write(buf, off, len);
}
}
}
public class SSLv3_TLSv12 {
static Base64.Decoder b64 = Base64.getDecoder();
static byte[] rsaKey =
b64.decode("MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAI64R+LgQkK7kAMRrJh8IbhwXjl0X579vTPJZGUwltqu5tKMpvQE7LDiPP3TAWD1m5ntXHFZKrhiI2QU5kSVGH8yggzK3eFcz8K8p56MpCcqykgM5R/Nt6LSKx/n3snNKuWIOdgOZzl75JXTLp3Mc4IXNFzut6fKopT7N9NRZaktAgMBAAECgYEAiXuD5E3cBqTgCdTQyuNpKF82pWoxYttTk7uBdujjqS2rNVBA0/iaeZq23lyRi3GNvy4kSxx2RsBjD1oCqDZoLUXRyxYqYr2STYZXdz3hKC7p3E7mT+0DgYFWe3nUSlXLGaSpwgXtiH1xLQZ7/jqCMWwDDTibsVcbJDz/Lb2x1xECQQDwku/XTLphWYaTEzw2MkYMxswYDGxIPEM+3hvpzF4Elr5hAOjSfSa66Og89hyokKn5/uRWZ08YbDIuY+BtihSjAkEAl98NN90Gky3p7Kto+39uT9ltzzzpv1+UCyqkY//Q6BrDzoixiNTQtdEnzkXZwYrqe35kIHHIv6gn0t03LDNX7wJBANkdIwuBmauF6mgNsgePc5zQRR1nCMpgaKfyN+rWn/swOHy/H1/nxu5kiEOMMe0HMgAGw/geoEmATAGF7eOt/FUCQHgTOvg4IMKtQo6E1/RAxI8NceywVH+iqgJKLL+Du0BIKRhaq0NsP7gBLl/AinKjytDpFXExhW9DHHlzvfOMhLECQQDmeLkRneJ/Hh5kK5vtpNgE9V+kLfnN2+QhCIWHztFR9VNNgf3JzfZFCruwldZJnCPIdxAi7CpECsk/Bf2zL6XD");
static byte[] rsaCer =
b64.decode("MIICHjCCAYegAwIBAgIBATANBgkqhkiG9w0BAQsFADBEMQ0wCwYDVQQLEwRDZXJ0MRIwEAYDVQQKEwlzdWNoZS5vcmcxCzAJBgNVBAYTAkRFMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTgxMjA5MjIzMDIwWhcNMTgxMjIxMTIxNzAwWjBEMQ0wCwYDVQQLEwRDZXJ0MRIwEAYDVQQKEwlzdWNoZS5vcmcxCzAJBgNVBAYTAkRFMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAI64R+LgQkK7kAMRrJh8IbhwXjl0X579vTPJZGUwltqu5tKMpvQE7LDiPP3TAWD1m5ntXHFZKrhiI2QU5kSVGH8yggzK3eFcz8K8p56MpCcqykgM5R/Nt6LSKx/n3snNKuWIOdgOZzl75JXTLp3Mc4IXNFzut6fKopT7N9NRZaktAgMBAAGjIDAeMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgP4MA0GCSqGSIb3DQEBCwUAA4GBAGFzQL9URFabGys3clkqn6l/tdTzqn6ncG1dL/rhoO1jPAxqGdf7hJ9iPQjPRpdqJl5aawLx9BtWCkdCNXN+Vk4opaGmVNsmQ1eRbZREYEKVKPNquzDIcimDYveYNPRf9shUcU2Z7eAI/GX/uMSlm4XzL7sL4P0v8M/qfja8EQ46");
static {
Security.setProperty("jdk.tls.disabledAlgorithms", "");
System.setProperty("javax.net.debug","all");
}
static void server(final ServerSocket srv, final String[] suites) {
while(!srv.isClosed()) {
try( SSLSocket s = (SSLSocket)srv.accept();
InputStream i = s.getInputStream();
OutputStream o = s.getOutputStream()) {
s.setUseClientMode(false);
if(suites != null) s.setEnabledCipherSuites(suites);
s.setEnabledProtocols(new String[]{"SSLv3"});
o.write('s');
i.read();
suite = s.getSession().getCipherSuite();
} catch(final Throwable t) { t.printStackTrace(); }
}
}
static SSLContext context(final String keyType) throws Exception {
final PrivateKey key =
KeyFactory.getInstance(keyType).generatePrivate(new
PKCS8EncodedKeySpec(rsaKey));
final CertificateFactory fact =
CertificateFactory.getInstance("X.509");
final Certificate cer = fact.generateCertificate(new
ByteArrayInputStream(rsaCer));
final KeyStore ks =
KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
final char[] pass = "test".toCharArray();
ks.setKeyEntry("a", key, pass, new Certificate[]{cer});
final TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
final KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, pass);
final SSLContext c = SSLContext.getInstance("TLS");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return c;
}
static volatile String suite = null;
static void doCheck(final String[] suites) {
suite = null;
System.out.println("START Suites: "+Arrays.toString(suites));
try {
final SSLContext c = context("RSA");
final SSLSocketFactory csf = c.getSocketFactory();
final SSLServerSocketFactory ssf = c.getServerSocketFactory();
try(final SSLServerSocket srv =
(SSLServerSocket)ssf.createServerSocket(0, 16)) {
if(suites != null) srv.setEnabledCipherSuites(suites);
srv.setEnabledProtocols(new String[]{"SSLv3"});
new Thread(()->server(srv, suites)).start();
try( SSLSocket s =
(SSLSocket)csf.createSocket("localhost", srv.getLocalPort());
InputStream i = s.getInputStream();
OutputStream o = s.getOutputStream()) {
if(suites != null) s.setEnabledCipherSuites(suites);
s.setEnabledProtocols(new
String[]{"SSLv3","TLSv1","TLSv1.1","TLSv1.2"});
o.write('c');
i.read();
} catch(final Throwable t) {
t.printStackTrace(System.out); }
}
} catch(final Throwable t) { t.printStackTrace(System.out);
} finally { System.out.println("DONE Suites:
"+Arrays.toString(suites)+" used "+suite); }
}
public static void main(final String[] argc) throws Exception {
try(final PrintStream check = new CheckPrintStream()) {
System.setErr(check);
doCheck(new
String[]{"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}); // WORKS
doCheck(new String[]{"SSL_RSA_WITH_3DES_EDE_CBC_SHA"
}); // -> Wrong TLSv1.2 in "RSA ClientKeyExchange"
}
}
}
On 10.12.2018 20:58:45, Thomas Lußnig wrote:
Hi,
i am not sure if there is already an bug opened. But i found an error
in the SSL-Socket handling.
If the ssl client socket enabled SSLv3-TLSv1.2 and the server select
SSLv3 the client later on send an
"RSA ClientKeyExchange" with version TLSv1.2. I added the relevant
parts of the debug log.
If there is no bug opened yet i can provide an sample with
client/server that demonstrate the bug
and can maybe used for regression tests.
Gruß Thomas Lußnig
2018-12-10T12:16:41.666
javax.net.ssl|DEBUG|15|https://fqdn/path)|2018-12-10 12:16:41.666
CET|ClientHello.java:651|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "90 B4 FF B0 8E C8 FA 3F D8 15 A3 73 13 78
38 D5 3A FB 49 68 28 ED B1 95 3C 3E 24 0C DD 64 A2 95",
"session id" : "",
"cipher suites" : "[SSL_RSA_WITH_3DES_EDE_CBC_SHA(0x000A),
TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
"compression methods" : "00",
...
2018-12-10T12:16:41.688
javax.net.ssl|DEBUG|15|https://fqdn/path)|2018-12-10 12:16:41.688
CET|ServerHello.java:866|Consuming ServerHello handshake message (
"ServerHello": {
"server version" : "SSLv3",
"random" : "5C 37 37 A9 EA DD D7 67 28 15 D3 DF 5F 3F
13 E2 34 88 93 67 16 FD 4F 76 A6 08 11 BE 36 E3 B4 26",
"session id" : "1D 5F B9 F7 EC DE 8E D9 38 52 AB FF 04 A1
24 1D",
"cipher suite" : "SSL_RSA_WITH_3DES_EDE_CBC_SHA(0x000A)",
"compression methods" : "00",
"extensions" : [
<no extension>
]
}
)
2018-12-10T12:16:41.699
javax.net.ssl|DEBUG|15|https://fqdn/path)|2018-12-10 12:16:41.699
CET|CertificateMessage.java:358|Consuming server Certificate handshake
message (
"Certificates": [
"certificate" : {
"version" : "v3",
"serial number" : "02 6F D4 BA 63 70 2F 13 00 91 5D E4",
"signature algorithm": "SHA256withRSA",
"issuer" : "CN=VR IDENT CLASS 3 CA 2010, OU=VR IDENT,
O=GAD EG, C=DE",
"not before" : "2017-07-20 01:33:58.000 CEST",
...
2018-12-10T12:16:41.854
javax.net.ssl|DEBUG|15|https://fqdn/path)|2018-12-10 12:16:41.853
CET|X509TrustManagerImpl.java:242|Found trusted certificate (
"certificate" : {
"version" : "v3",
"serial number" : "02 6F D4 BA 63 70 2F 13 00 91 5D E4",
...
2018-12-10T12:16:41.856
javax.net.ssl|DEBUG|15|https://fqdn/path)|2018-12-10 12:16:41.856
CET|RSAClientKeyExchange.java:195|Produced RSA ClientKeyExchange
handshake message (
"RSA ClientKeyExchange": {
"client_version": TLSv1.2
"encncrypted": {
0000: 52 2E C4 EB 8C 65 06 77 47 5D 9E 10 56 95 8A 6E
R....e.wG]..V..n
0010: 03 D0 70 8D 73 51 93 F7 8B F7 73 55 25 AC E4 0C
..p.sQ....sU%...
0020: 34 68 26 01 E0 40 64 B5 82 C6 1C 7C 04 81 E3 15
4h&..@d.........
...