Client connecting to an SSL server with Self-Signed Certificates

34,269

Remove SSLv2ClientHello from the list of enabled protocols at the client.

Share:
34,269
Carlos Tasada
Author by

Carlos Tasada

I'm a Software Developer with more than 10 years experience. I've worked in different countries, companies and sectors. As development languages I've used C/C++, Java, Tcl/Tk, PHP, HTML, JavaScript, .... Links: Twitter: @ctasada Blog: http://ctasada.blogspot.com GitHub: https://github.com/ctasada

Updated on July 09, 2022

Comments

  • Carlos Tasada
    Carlos Tasada almost 2 years

    I'm completely stuck here. I've a java client code that needs to connect to an SSL server with self-signed certificates.

    The problem only appears when I disable SSLv2 support in the server side.

        private static DefaultHttpClient createHttpClient(int port) {
        try {
            java.lang.System.setProperty(
                    "sun.security.ssl.allowUnsafeRenegotiation", "true");
    
            // First create a trust manager that won't care.
            X509TrustManager trustManager = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                    // Don't do anything.
                }
    
                public void checkServerTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                    // Don't do anything.
                }
    
                public X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[0];
                }
            };
    
            // Now put the trust manager into an SSLContext.
            // Supported: SSL, SSLv2, SSLv3, TLS, TLSv1, TLSv1.1
            SSLContext sslContext = SSLContext.getInstance("SSLv3");
            sslContext.init(null, new TrustManager[] { trustManager },
                    new SecureRandom());
    
            // Use the above SSLContext to create your socket factory
            // (I found trying to extend the factory a bit difficult due to a
            // call to createSocket with no arguments, a method which doesn't
            // exist anywhere I can find, but hey-ho).
            SSLSocketFactory sf = new SSLSocketFactory(sslContext);
            // Accept any hostname, so the self-signed certificates don't fail
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            // Register our new socket factory with the typical SSL port and the
            // correct protocol name.
            //Scheme httpsScheme = new Scheme("https", sf, port);
            SchemeRegistry schemeRegistry = new SchemeRegistry();
            schemeRegistry.register(new Scheme("https", sf, port));
    
            HttpParams params = new BasicHttpParams();
            ClientConnectionManager cm = new SingleClientConnManager(params,
                    schemeRegistry);
    
            return new DefaultHttpClient(cm, params);
        } catch (Exception ex) {
            Log.error("ERROR Creating SSL Connection: " + ex.getMessage());
    
            return null;
        }
    }
    

    The traces are

    trigger seeding of SecureRandom
    done seeding SecureRandom
    keyStore is : 
    keyStore type is : jks
    keyStore provider is : 
    init keystore
    init keymanager of type SunX509
    trustStore is: /usr/lib/jvm/java-6-openjdk/jre/lib/security/cacerts
    trustStore type is : jks
    trustStore provider is : 
    init truststore
    adding as trusted cert:
    x
    x
    x
    
    trigger seeding of SecureRandom
    done seeding SecureRandom
    2010-12-16 17:25:08,705 [DEBUG][gwt-log][ 5] Connecting: 1
    Allow unsafe renegotiation: true
    Allow legacy hello messages: true
    Is initial handshake: true
    Is secure renegotiation: false
    %% No cached client session
    *** ClientHello, TLSv1
    RandomCookie:  GMT: 1292516708 bytes = { 205, 187, 238, 65, 164, 126, 107, 173, 51, 124, 60, 146, 4, 127, 165, 246, 216, 181, 106, 72, 9, 214, 243, 64, 34, 117, 141, 76 }
    Session ID:  {}
    Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    Compression Methods:  { 0 }
    Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
    Extension ec_point_formats, formats: [uncompressed]
    ***
    [write] MD5 and SHA1 hashes:  len = 177
    0000: 01 00 00 AD 03 01 4D 0A   3D 64 CD BB EE 41 A4 7E  ......M.=d...A..
    xxxxxxx
    00B0: 00                                                 .
    btpool0-0, WRITE: TLSv1 Handshake, length = 177
    [write] MD5 and SHA1 hashes:  len = 173
    0000: 01 03 01 00 84 00 00 00   20 00 00 04 01 00 80 00  ........ .......
    xxxxxxx
    00A0: F6 D8 B5 6A 48 09 D6 F3   40 22 75 8D 4C           ...jH...@"u.L
    btpool0-0, WRITE: SSLv2 client hello message, length = 173
    [Raw write]: length = 175
    0000: 80 AD 01 03 01 00 84 00   00 00 20 00 00 04 01 00  .......... .....
    xxxxxxx
    00A0: 7F A5 F6 D8 B5 6A 48 09   D6 F3 40 22 75 8D 4C     .....jH...@"u.L
    btpool0-0, handling exception: java.net.SocketException: Connection reset
    btpool0-0, SEND TLSv1 ALERT:  fatal, description = unexpected_message
    btpool0-0, WRITE: TLSv1 Alert, length = 2
    btpool0-0, Exception sending alert: java.net.SocketException: Broken pipe
    btpool0-0, called closeSocket()
    btpool0-0, IOException in getSession():  java.net.SocketException: Connection reset
    2010-12-16 17:25:08,890 [DEBUG][gwt-log][ 6] peer not authenticated
    javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
        at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:371)
        at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
        at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:399)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:143)
        at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
        at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:108)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:415)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:731)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:709)
        at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:700)
    
    [Fatal Error] :1:1: Premature end of file.
    Finalizer, called close()
    Finalizer, called closeInternal(true)
    

    On the server side I can see the next traces:

    info sock48 handshake start {before/accept initialization}
    info sock48 accept loop {before/accept initialization}
    info sock48 accept exit {SSLv3 read client hello B}
    error sock48 {wrong version number}
    

    If I enable SSL2 then I see

    info sock47 handshake start {before/accept initialization}
    info sock47 accept loop {before/accept initialization}
    info sock47 accept loop {SSLv3 read client hello A}
    info sock47 accept loop {SSLv3 write server hello A}
    info sock47 accept loop {SSLv3 write certificate A}
    info sock47 accept loop {SSLv3 write server done A}
    info sock47 accept loop {SSLv3 flush data}
    info sock47 accept exit {SSLv3 read client certificate A}
    info sock47 accept exit {SSLv3 read client certificate A}
    info sock47 accept loop {SSLv3 read client key exchange A}
    info sock47 accept loop {SSLv3 read finished A}
    info sock47 accept loop {SSLv3 write change cipher spec A}
    info sock47 accept loop {SSLv3 write finished A}
    info sock47 accept loop {SSLv3 flush data}
    info sock47 handshake done {SSL negotiation finished successfully}
    info sock47 accept exit {SSL negotiation finished successfully}
    info sock47 alert write {close notify}
    

    And everything works fine.

    I also known that's not something on the server side, since connecting with other software works ok.

    Any idea what am I doing wrong?

    Also does anyone known what this "read client hello A/B" means?

    Thanks

    UPDATE - FIXED

    The SSLSocketFactory needs to be replaced by this new TLSSocketFactory.

    public class TLSSocketFactory extends SSLSocketFactory {
    
    private final javax.net.ssl.SSLSocketFactory socketfactory;
    
    public TLSSocketFactory(SSLContext sslContext) {
        super(sslContext);
    
        this.socketfactory = sslContext.getSocketFactory();
    }
    
    public Socket createSocket() throws IOException {
        SSLSocket socket = (SSLSocket) super.createSocket();
    
        socket.setEnabledProtocols(new String[] {"SSLv3, TLSv1"});
    
        return socket;
    }
    
    public Socket createSocket(
            final Socket socket,
            final String host,
            final int port,
            final boolean autoClose
        ) throws IOException, UnknownHostException {
    
        SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
                socket,
                host,
                port,
                autoClose
          );
    
        sslSocket.setEnabledProtocols(new String[] {"SSLv3", "TLSv1"});
    
        getHostnameVerifier().verify(host, sslSocket);
    
        return sslSocket;
    }
    

    }

  • Carlos Tasada
    Carlos Tasada over 13 years
    Thanks for the suggestion. I've created a MySSLSocketFactory which extends SSLSocketFactory and in the createSocket method I'm doing sslSocket.setEnabledProtocols(new String[] {"SSLv3"}); But I don't see any difference. I also tried with System.setProperty("https.protocols", "SSLv3"); Is there any other way to do that?
  • Carlos Tasada
    Carlos Tasada over 13 years
    I found that I was missing to add the TLSv1 to the list :)
  • user207421
    user207421 about 10 years
    @CarlosTasada Well that's not what I said to do, is it? I said to remove SSLv2ClientHello from the list of enabled protocols, not to define your own list from scratch.
  • MMike
    MMike almost 9 years
    @EJP Maybe you should stop stating commands and add some explanation. I feel like I am back in the army when I read your commands(answers)... For me it is unclear why this solves his issue. Yeah, I am absolutely not familiar with SSL/TLS(but I would like to) ..now call me stupid, call me lazy because i do not read the next 20hours through the internet just to know why this solves is issue. Your answers do not provide anything to learn. ;)