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.........
    ...


Reply via email to