3

I'm trying to post HTTP POST via HttpClient to a server with client authentication enabled. Here is my code

public class Send2Remote {

private static String sslMode = null;
private static String clientKeyStore = null;
private static String clientStoreType = null;
private static String clientStorePW = null;

private static String trustKeyStore = null;
private static String trustStoreType = null;
private static String trustStorePW = null;

public Send2Remote(String sslmode, String clientKS, String clientST, String clientTPW, 
        String trustKS, String trustST, String trustSPW) {
    sslMode = sslmode;
    clientKeyStore = clientKS;
    clientStoreType = clientST;
    clientStorePW = clientTPW;

    trustKeyStore = trustKS;
    trustStoreType = trustST;
    trustStorePW = trustSPW;
}

private final class X509HostnameVerifierImplementation implements X509HostnameVerifier {
    @Override
    public void verify(String host, SSLSocket ssl) throws IOException {
    }

    @Override
    public void verify(String host, X509Certificate cert) throws SSLException {
    }

    @Override
    public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
    }

    @Override
    public boolean verify(String s, SSLSession sslSession) {
        return true;
    }
}

public String post(String uRL, List<NameValuePair> formparams) {        
    SSLContext sslContext = null;
    KeyManagerFactory kmf = null;
    TrustManagerFactory tmf = null;
    KeyStore ks = null;
    KeyStore tks = null;
    try {           
        sslContext = SSLContext.getInstance(sslMode);
        kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        tmf = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

        ks = KeyStore.getInstance(clientStoreType);
        tks = KeyStore.getInstance(trustStoreType);

        ks.load(new FileInputStream(clientKeyStore), clientStorePW.toCharArray());
        tks.load(new FileInputStream(trustKeyStore), trustStorePW.toCharArray());

        kmf.init(ks, clientStorePW.toCharArray());
        tmf.init(tks);

        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException | UnrecoverableKeyException | KeyManagementException e1) {
        Log4j.log.error("Error occurred: " + e1.getClass() + ":" + e1.getMessage() + ", Full Stacktrace: " + new Gson().toJson(e1.getStackTrace()));
        return null;
    }

    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslContext, new X509HostnameVerifierImplementation());

    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
            .<ConnectionSocketFactory> create().register("https", sslsf)
            .build();

    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
            socketFactoryRegistry);
    CloseableHttpClient httpclient = HttpClients.custom()
            .setConnectionManager(cm).build();

    HttpPost httppost = new HttpPost(uRL);

    UrlEncodedFormEntity uefEntity;
    String returnCode = null;
    try {
        uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
        httppost.setEntity(uefEntity);

        CloseableHttpResponse response = httpclient.execute(httppost);
        try {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                returnCode = EntityUtils.toString(entity, "UTF-8");
            }
        } finally {
            response.close();
        }
    } catch (ClientProtocolException e) {
        Log4j.log.error("Error occurred: " + e.getClass() + ":" + e.getMessage() + ", Full Stacktrace: " + new Gson().toJson(e.getStackTrace()));
        return null;
    } catch (UnsupportedEncodingException e1) {
        Log4j.log.error("Error occurred: " + e1.getClass() + ":" + e1.getMessage() + ", Full Stacktrace: " + new Gson().toJson(e1.getStackTrace()));
        return null;
    } catch (IOException e) {
        Log4j.log.error("Error occurred: " + e.getClass() + ":" + e.getMessage() + ", Full Stacktrace: " + new Gson().toJson(e.getStackTrace()));
        return null;
    } finally {
        try {
            httpclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            close(httpclient);
        }
    }
    return returnCode;
}

public void close(Closeable io) {
    if (io != null) {
        try {
            io.close();
        } catch (IOException ignore) {
        }
    }
}

} 

When I execute it with my own keystores, I got exception while posting message

class javax.net.ssl.SSLHandshakeException:java.net.SocketException: Unrecognized Windows Sockets error: 0: recv failed

And server admin gave me part of his log

[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, WRITE: TLSv1.2 Handshake, length = 96
[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, waiting for close_notify or alert: state 1
[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, Exception while waiting for close java.net.SocketException: Unrecognized Windows Sockets error: 0: recv failed
[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O %% Invalidated:  [Session-18, SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384]
[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, SEND TLSv1.2 ALERT:  fatal, description = handshake_failure
[2017/8/21   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, WRITE: TLSv1.2 Alert, length = 80
[2017/8/20   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, Exception sending alert: java.net.SocketException: Unrecognized Windows Sockets error: 0: socket write error
[2017/8/20   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, called closeSocket()
[2017/8/20   20:10:16:477 CST] 000000f7 SystemOut     O WebContainer : 20, handling exception: javax.net.ssl.SSLHandshakeException: java.net.SocketException: Unrecognized Windows Sockets error: 0: recv failed

Server and I added each other's certificate into own trust keystore, so it should not be the issue of trusting each other. But I can't find other thread that could solve this issue too.

halfer
  • 19,824
  • 17
  • 99
  • 186
user6309529
  • 153
  • 1
  • 3
  • 16

2 Answers2

2

Possibly this can cause an issue:

Server has both IPv4 and IPv6 enabled?

Cause:

The Java Virtual Machine (JVM) can have problems opening or closing sockets at the operating system level when both IPv4 and IPv6 are enabled on a Windows server.

Probable fix:

JVM will need to run over IPv4, if possible. To do this add this set the following JVM option:
-Djava.net.preferIPv4Stack=true

Rizwan
  • 2,369
  • 22
  • 27
  • I asked server admin and he put this line into startup arguments and restarted, but this same problem persist – user6309529 Aug 22 '17 at 03:17
  • @user6309529 put the same argument on the Client machine which opening the connection with server. – Rizwan Aug 22 '17 at 03:27
  • Added but still same so far, sad – user6309529 Aug 22 '17 at 03:46
  • @user6309529 Need for diagnosis. Please can you trace enable the log at client and server and post the complete stack trace both at server and client. Also, if you can track the request if it is hittting the server via any other client like openssl or browser with the certificate being installed to exception/trusted. See what's the behaviour in that case – Rizwan Aug 22 '17 at 05:05
  • @user6309529 can you check the Network sniffing via wireshark [https://www.wireshark.org/ ], this can give more idea whether any kind of timeout or connection abruptly being closed? – Rizwan Aug 22 '17 at 08:33
  • hmm, I'll try to check with SSL debug enabled. it will going to take a while I guess. – user6309529 Aug 23 '17 at 03:56
0

I got the '0: recv failed' message. I was reading the socket from one thread and writing to it on another. I rewrote the code to always read/write the socket from the same thread and I didn't have the issue any more.

codeDr
  • 1,535
  • 17
  • 20
  • I have a wierd feeling that this is the cause in my case. We have a multithreaded app and looks like this is causing the application to give this error. Any idea what “Unrecognized Windows Socket Error:socket write error” .was this your error code ?? – Don Woodward Feb 05 '21 at 06:10
  • @DonWoodward I got the 'recv failed' error. I suspect that if it's possible to disrupt the read side with write from a different thread, then it's equal possible to disrupt the write from reading from a different thread. I wouldn't recommend read/write the socket from different threads on windows. – codeDr Feb 06 '21 at 12:56