odnoklassniki/one-nio

Unable to connect to https://api.kucoin.com due to javax.net.ssl.SSLException: error:0A000410:SSL routines::sslv3 alert handshake failure

essessen1 opened this issue · 0 comments

Hi folks. I am not sure if this is the right place to raise this but I thought I would create an issue none the less. Please feel free to move it to the appropriate place or close it out if this is not an issue.
I was attempting to use the HttpClient provided by one nio but I was unable to get it to connect to https://api.kucoin.com. The client works with other servers that I have tried with but for this one server, it fails. I tried with both one-nio-1.5.0.jar and the latest one-nio-1.6.1.jar. For 1.5.0, I used openssl1.1 and for 1.6.1, I used openssl3.0. I cloned the repo and built it myself and ensured that the libonenio.so object exists in the jar and then compiled it with my client code shown below.

import one.nio.http.HttpClient;
import one.nio.http.HttpException;
import one.nio.net.ConnectionString;
import one.nio.pool.PoolException;

import java.io.IOException;

public class MyHttpClient {

    public HttpClient client;

    public MyHttpClient(String hostPort) {
        this.client = new HttpClient(new ConnectionString(hostPort));
    }

    public void syncGet(String path) {
        try {
            System.out.println(this.client.get(path));
        } catch (InterruptedException | PoolException | IOException | HttpException e) {
            throw new RuntimeException(e);
        }
    }
}

However, I always ran into the following error when attempting to connect to the server:

Testing Kucoin connection
Exception in thread "main" java.lang.RuntimeException: one.nio.pool.PoolException: SocketPool[api.kucoin.com:443] createObject failed: javax.net.ssl.SSLException: error:0A000410:SSL routines::sslv3 alert handshake failure
	at util.http.MyHttpClient.syncGet(MyHttpClient.java:24)

From the error message, it looks like the issue might be with sslv3. It's possible that the server here doesn't support sslv3 but my question is why is one.nio/openssl using SSLV3 to connect to the server? I would have thought that it would use TLSv1.2. I tried to forcefully disable sslv3 in but was still unsuccessful. I modified ssl.c as shown below.
https://wiki.openssl.org/index.php/List_of_SSL_OP_Flags

src/one/nio/net/native/ssl.c

JNIEXPORT jlong JNICALL
Java_one_nio_net_NativeSslContext_ctxNew(JNIEnv* env, jclass cls) {
    AppData* appData = create_app_data();
    if (appData == NULL) {
        throw_by_name(env, "javax/net/ssl/SSLException", "Cannot allocate SSL app data");
        return 0;
    }

    SSL_CTX* ctx = SSL_CTX_new(TLS_method());
    if (ctx == NULL) {
        free_app_data(appData);
        throw_ssl_exception(env);
        return 0;
    }

    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
    fprintf(stderr, "\nSetting options to disable compression and ssl v3\n");
    unsigned long currOptions = SSL_CTX_get_options(ctx);
    fprintf(stderr, "\nCurrent options(pre set): %d\n", currOptions);
    SSL_CTX_clear_options(ctx, currOptions); // Disable TLSv1.3 compat mode.

    currOptions = SSL_CTX_get_options(ctx);
    fprintf(stderr, "\nCurrent options(post clear): %d\n", currOptions);
    currOptions |= SSL_OP_BIT(17); // Disable compression.
    currOptions |= SSL_OP_BIT(25); // Disable SSL V3.
    currOptions |= SSL_OP_BIT(29); // Disable TLSv1.3
    SSL_CTX_set_options(ctx, currOptions);
    fprintf(stderr, "\nCurrent options(post set): %d\n", SSL_CTX_get_options(ctx));
    fprintf(stderr, "\nSuccessfully set options to disable compression and ssl v3\n");


    // Disable read-ahead until premature socket close is fixed
    // SSL_CTX_set_read_ahead(ctx, 1);
    SSL_CTX_set_info_callback(ctx, ssl_info_callback);
    SSL_CTX_set_app_data(ctx, appData);

    setup_dh_params(ctx);
    setup_ecdh_params(ctx);

    return (jlong)(intptr_t)ctx;
}

The output looks as follows:

Testing Kucoin connection

Setting options to disable compression and ssl v3

Current options(pre set): 1179648

Current options(post clear): 0

Current options(post set): 570556416

Successfully set options to disable compression and ssl v3
Exception in thread "main" java.lang.RuntimeException: one.nio.pool.PoolException: SocketPool[api.kucoin.com:443] createObject failed: javax.net.ssl.SSLException: error:0A000410:SSL routines::sslv3 alert handshake failure
	at util.http.MyHttpClient.syncGet(MyHttpClient.java:24)

570556416 === 0b100010000000100000000000000000 (17th, 25th and 29th bit are set)

[ubuntu@ip-10-20-82-90 ~]$ openssl s_client -connect api.kucoin.com:443 -tls1_2
CONNECTED(00000003)
depth=1 C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = "Cloudflare, Inc.", CN = kucoin.com
verify return:1

....

No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2746 bytes and written 296 bytes
Verification error: unable to get local issuer certificate
---
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Server public key is 256 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-ECDSA-CHACHA20-POLY1305

I would be really grateful if someone can help me out with this. Please do let me know if this is a known issue which has workarounds. I went through the issues posted previously but was unable to find any that matched this.