How to use client certificate during server connection Handshake?

Asked

Viewed 235 times

1

Hello! I’m trying to perform an authentication on a government server that uses digital certificate. To perform such authentication you need to import the SERPRO certificate strings referring to the server I am trying to access. In addition it is also necessary to send a customer certificate on request to complete Handshake.

I imported the SERPRO certificate chains into my JVM using the keytool:

    $JAVA_HOME/bin/keytool -importcert -trustcacerts -file certificado1.crt -alias AC.SERPRO.certificado1 -cacerts -storepass changeit -noprompt -v
    $JAVA_HOME/bin/keytool -importcert -trustcacerts -file certificado2.crt -alias AC.SERPRO.certificado2 -cacerts -storepass changeit -noprompt -v
    $JAVA_HOME/bin/keytool -importcert -trustcacerts -file certificado3.crt -alias AC.SERPRO.certificado3 -cacerts -storepass changeit -noprompt -v
    $JAVA_HOME/bin/keytool -importcert -trustcacerts -file certificado4.crt -alias AC.SERPRO.certificado4 -cacerts -storepass changeit -noprompt -v

And I’m trying to pass the customer certificate via argument during the execution of the application:

java $JAVA_OPTS
    -Djavax.net.debug=all
    -Djavax.net.ssl.trustStoreType=pkcs12
    -Djavax.net.ssl.trustStore=$JAVA_HOME/lib/security/cacerts
    -Djavax.net.ssl.trustStorePassword=changeit
    -Djavax.net.ssl.keyStoreType=pkcs12
    -Djavax.net.ssl.keyStore=clientCertificate.pfx
    -Djavax.net.ssl.keyStorePassword=clientCertPass
    -jar app.jar

In the code I’m using the okhttp3 to make the GET request to get the server token:

package testes;

import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class ClienteCertificateHandshake {
    
    public static void main(String[] args) throws Exception {
        System.out.println("Running...");
        try {
            new ClienteCertificateHandshake().run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public final void run() {
        try {
            URL url = new URL("https://server.gov.br/authentication");
            Request request = new Request.Builder().url(url).build();
    
            Response response = getClient().newCall(request).execute();
    
            int statusCode = response.code();
            String statusMessage = response.message();
            
            System.out.println("StatusCode => " + statusCode);
            System.out.println("StatusMessage => " + statusMessage);
            
            String bodyString = response.body().string();
            response.body().close();
            
            System.out.println("body => " + bodyString);
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private OkHttpClient getClient() throws IOException {
        long timeout = 120;
        return new OkHttpClient.Builder()
                .connectTimeout(timeout, TimeUnit.SECONDS)
                .readTimeout(timeout, TimeUnit.SECONDS)
                .writeTimeout(timeout, TimeUnit.SECONDS)
                .connectionSpecs(Collections.singletonList(ConnectionSpec.MODERN_TLS))
                .build();
    }
}

But is giving error in the request and Handshake does not end as it should:

app    | Running...
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.214 BRT|null:-1|jdk.tls.keyLimits:  entry = AES/GCM/NoPadding KeyUpdate 2^37. AES/GCM/NOPADDING:KEYUPDATE = *****
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:58.813 BRT|null:-1|Signature algorithm, ed25519, is not supported by the underlying providers
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:58.815 BRT|null:-1|Signature algorithm, ed448, is not supported by the underlying providers
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.827 BRT|null:-1|Ignore, context unavailable extension: cookie
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.874 BRT|null:-1|No session to resume.
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.875 BRT|null:-1|Ignore, context unavailable extension: pre_shared_key
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.887 BRT|null:-1|Produced ClientHello handshake message (
app    | "ClientHello": {
app    |   "client version"      : "TLSv1.2",
app    |   "random"              : "****",
app    |   "session id"          : "****",
app    |   "cipher suites"       : "[TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302), TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F)]",
app    |   "compression methods" : "00",
app    |   "extensions"          : [
app    |     "server_name (0)": {
app    |       type=host_name (0), value=server.gov.br
app    |     },
app    |     ...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.896 BRT|null:-1|Ignore unavailable extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.897 BRT|null:-1|Negotiated protocol version: TLSv1.2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.897 BRT|null:-1|Consumed extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.898 BRT|null:-1|Consumed extension: server_name
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.898 BRT|null:-1|Ignore unavailable extension: max_fragment_length
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.898 BRT|null:-1|Ignore unavailable extension: status_request
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.899 BRT|null:-1|Consumed extension: ec_point_formats
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.899 BRT|null:-1|Ignore unavailable extension: status_request_v2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.900 BRT|null:-1|Ignore unsupported extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.901 BRT|null:-1|Ignore unsupported extension: key_share
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.902 BRT|null:-1|Consumed extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.905 BRT|null:-1|Ignore unsupported extension: pre_shared_key
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:58.905 BRT|null:-1|Ignore impact of unsupported extension: server_name
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.906 BRT|null:-1|Ignore unavailable extension: max_fragment_length
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.906 BRT|null:-1|Ignore unavailable extension: status_request
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:58.907 BRT|null:-1|Ignore impact of unsupported extension: ec_point_formats
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.908 BRT|null:-1|Ignore unavailable extension: application_layer_protocol_negotiation
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.909 BRT|null:-1|Ignore unavailable extension: status_request_v2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.910 BRT|null:-1|Ignore unavailable extension: extended_master_secret
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.911 BRT|null:-1|Ignore unavailable extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.911 BRT|null:-1|Ignore unavailable extension: key_share
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:58.912 BRT|null:-1|Ignore impact of unsupported extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.913 BRT|null:-1|Ignore unavailable extension: pre_shared_key
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.943 BRT|null:-1|Consuming server Certificate handshake message (...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.985 BRT|null:-1|Consuming ECDH ServerKeyExchange handshake message (...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:58.989 BRT|null:-1|Consuming ServerHelloDone handshake message (
app    | <empty>
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.003 BRT|null:-1|Produced ECDHE ClientKeyExchange handshake message (... )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.034 BRT|null:-1|Produced ChangeCipherSpec message
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.035 BRT|null:-1|Produced client Finished handshake message (...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.060 BRT|null:-1|Consuming ChangeCipherSpec message
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.062 BRT|null:-1|Consuming server Finished handshake message (...
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.092 BRT|null:-1|Consuming HelloRequest handshake message (
app    | <empty>
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.095 BRT|null:-1|Ignore, context unavailable extension: cookie
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.104 BRT|null:-1|No session to resume.
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.105 BRT|null:-1|Ignore, context unavailable extension: pre_shared_key
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.108 BRT|null:-1|Produced ClientHello handshake message (
app    | "ClientHello": {
app    |   "client version"      : "TLSv1.2",
app    |   "random"              : "****",
app    |   "session id"          : "****",
app    |   "cipher suites"       : "[TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302), TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F)]",
app    |   "compression methods" : "00",
app    |   "extensions"          : [
app    |     "server_name (0)": {
app    |       type=host_name (0), value=server.gov.br
app    |     },
app    |  ...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.124 BRT|null:-1|Consuming ServerHello handshake message (...)
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.125 BRT|null:-1|Ignore unavailable extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.125 BRT|null:-1|Negotiated protocol version: TLSv1.2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.126 BRT|null:-1|Consumed extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.127 BRT|null:-1|Consumed extension: server_name
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.128 BRT|null:-1|Ignore unavailable extension: max_fragment_length
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.128 BRT|null:-1|Ignore unavailable extension: status_request
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.129 BRT|null:-1|Consumed extension: ec_point_formats
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.129 BRT|null:-1|Ignore unavailable extension: status_request_v2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.130 BRT|null:-1|Ignore unsupported extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.130 BRT|null:-1|Ignore unsupported extension: key_share
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.131 BRT|null:-1|Consumed extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.132 BRT|null:-1|Ignore unsupported extension: pre_shared_key
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.133 BRT|null:-1|Ignore impact of unsupported extension: server_name
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.139 BRT|null:-1|Ignore unavailable extension: max_fragment_length
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.139 BRT|null:-1|Ignore unavailable extension: status_request
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.139 BRT|null:-1|Ignore impact of unsupported extension: ec_point_formats
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.140 BRT|null:-1|Ignore unavailable extension: application_layer_protocol_negotiation
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.141 BRT|null:-1|Ignore unavailable extension: status_request_v2
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.141 BRT|null:-1|Ignore unavailable extension: extended_master_secret
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.142 BRT|null:-1|Ignore unavailable extension: supported_versions
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.142 BRT|null:-1|Ignore unavailable extension: key_share
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.143 BRT|null:-1|Ignore impact of unsupported extension: renegotiation_info
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.144 BRT|null:-1|Ignore unavailable extension: pre_shared_key
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.156 BRT|null:-1|Consuming server Certificate handshake message (... )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.164 BRT|null:-1|Consuming ECDH ServerKeyExchange handshake message (...
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.205 BRT|null:-1|Consuming CertificateRequest handshake message (
app    | "CertificateRequest": {
app    |   "certificate types": [rsa_sign, dss_sign, ecdsa_sign]
app    |   "supported signature algorithms": [rsa_pkcs1_sha512, dsa_sha512, ecdsa_secp521r1_sha512, rsa_pkcs1_sha384, dsa_sha384, ecdsa_secp384r1_sha384, rsa_pkcs1_sha256, dsa_sha256, ecdsa_secp256r1_sha256, rsa_sha224, dsa_sha224, ecdsa_sha224, rsa_pkcs1_sha1, dsa_sha1, ecdsa_sha1]
app    |   "certificate authorities": [CN=SERASA CD SSL V5, O=ICP-Brasil, ...]
app    | }
app    | )
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.208 BRT|null:-1|No X.509 cert selected for RSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.211 BRT|null:-1|Unavailable authentication scheme: rsa_pkcs1_sha512
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.211 BRT|null:-1|No X.509 cert selected for EC
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.211 BRT|null:-1|Unavailable authentication scheme: ecdsa_secp521r1_sha512
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.212 BRT|null:-1|No X.509 cert selected for RSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.212 BRT|null:-1|Unavailable authentication scheme: rsa_pkcs1_sha384
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.213 BRT|null:-1|No X.509 cert selected for EC
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.213 BRT|null:-1|Unavailable authentication scheme: ecdsa_secp384r1_sha384
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.214 BRT|null:-1|No X.509 cert selected for RSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.214 BRT|null:-1|Unavailable authentication scheme: rsa_pkcs1_sha256
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.215 BRT|null:-1|No X.509 cert selected for DSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.215 BRT|null:-1|Unavailable authentication scheme: dsa_sha256
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.216 BRT|null:-1|No X.509 cert selected for EC
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.217 BRT|null:-1|Unavailable authentication scheme: ecdsa_secp256r1_sha256
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.217 BRT|null:-1|No X.509 cert selected for RSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.218 BRT|null:-1|Unavailable authentication scheme: rsa_sha224
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.219 BRT|null:-1|No X.509 cert selected for DSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.219 BRT|null:-1|Unavailable authentication scheme: dsa_sha224
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.220 BRT|null:-1|No X.509 cert selected for EC
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.220 BRT|null:-1|Unavailable authentication scheme: ecdsa_sha224
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.221 BRT|null:-1|No X.509 cert selected for RSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.221 BRT|null:-1|Unavailable authentication scheme: rsa_pkcs1_sha1
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.222 BRT|null:-1|No X.509 cert selected for DSA
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.222 BRT|null:-1|Unavailable authentication scheme: dsa_sha1
app    | javax.net.ssl|ALL|01|main|2020-07-20 17:35:59.223 BRT|null:-1|No X.509 cert selected for EC
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.223 BRT|null:-1|Unavailable authentication scheme: ecdsa_sha1
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.223 BRT|null:-1|No available authentication scheme
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.224 BRT|null:-1|Consuming ServerHelloDone handshake message (
app    | <empty>
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.225 BRT|null:-1|No X.509 certificate for client authentication, use empty Certificate message instead
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.225 BRT|null:-1|Produced client Certificate handshake message (
app    | "Certificates": <empty list>
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.233 BRT|null:-1|Produced ECDHE ClientKeyExchange handshake message (
app    | "ECDH ClientKeyExchange": {
app    |   "ecdh public": {
...
app    |   },
app    | }
app    | )
app    | javax.net.ssl|DEBUG|01|main|2020-07-20 17:35:59.243 BRT|null:-1|Produced ChangeCipherSpec message
app    | javax.net.ssl|WARNING|01|main|2020-07-20 17:35:59.247 BRT|null:-1|handling exception (
app    | "throwable" : {
app    |   javax.net.ssl.SSLException: readApplicationRecord
app    |    at java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(Unknown Source)
app    |    at okio.InputStreamSource.read(JvmOkio.kt:90)
app    |    at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
app    |    at okio.RealBufferedSource.indexOf(RealBufferedSource.kt:449)
app    |    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:333)
app    |    at okhttp3.internal.http1.HeadersReader.readLine(HeadersReader.kt:29)
app    |    at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.kt:178)
app    |    at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:106)
app    |    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
app    |    at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
app    |    at testes.ClienteCertificateHandshake.run(ClienteCertificateHandshake.java:30)
app    |    at testes.ClienteCertificateHandshake.main(Main.java:18)
app    |   Caused by: java.net.SocketException: Broken pipe (Write failed)
app    |    at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
app    |    at java.base/java.net.SocketOutputStream.socketWrite(Unknown Source)
app    |    at java.base/java.net.SocketOutputStream.write(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketOutputRecord.encodeChangeCipherSpec(Unknown Source)
app    |    at java.base/sun.security.ssl.OutputRecord.changeWriteCiphers(Unknown Source)
app    |    at java.base/sun.security.ssl.ChangeCipherSpec$T10ChangeCipherSpecProducer.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.Finished$T12FinishedProducer.onProduceFinished(Unknown Source)
app    |    at java.base/sun.security.ssl.Finished$T12FinishedProducer.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLHandshake.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.ServerHelloDone$ServerHelloDoneConsumer.consume(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLHandshake.consume(Unknown Source)
app    |    at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
app    |    ... 23 more}
app    | 
app    | )
app    | javax.net.ssl|ERROR|01|main|2020-07-20 17:35:59.250 BRT|null:-1|Fatal (UNEXPECTED_MESSAGE): readApplicationRecord (
app    | "throwable" : {
app    |   javax.net.ssl.SSLException: readApplicationRecord
app    |    at java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(Unknown Source)
app    |    at okio.InputStreamSource.read(JvmOkio.kt:90)
app    |    at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
app    |    at okio.RealBufferedSource.indexOf(RealBufferedSource.kt:449)
app    |    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:333)
app    |    at okhttp3.internal.http1.HeadersReader.readLine(HeadersReader.kt:29)
app    |    at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.kt:178)
app    |    at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:106)
app    |    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
app    |    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
app    |    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
app    |    at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
app    |    at testes.ClienteCertificateHandshake.run(ClienteCertificateHandshake.java:30)
app    |    at testes.ClienteCertificateHandshake.Main.main(Main.java:13)
app    |   Caused by: java.net.SocketException: Broken pipe (Write failed)
app    |    at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
app    |    at java.base/java.net.SocketOutputStream.socketWrite(Unknown Source)
app    |    at java.base/java.net.SocketOutputStream.write(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketOutputRecord.encodeChangeCipherSpec(Unknown Source)
app    |    at java.base/sun.security.ssl.OutputRecord.changeWriteCiphers(Unknown Source)
app    |    at java.base/sun.security.ssl.ChangeCipherSpec$T10ChangeCipherSpecProducer.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.Finished$T12FinishedProducer.onProduceFinished(Unknown Source)
app    |    at java.base/sun.security.ssl.Finished$T12FinishedProducer.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLHandshake.produce(Unknown Source)
app    |    at java.base/sun.security.ssl.ServerHelloDone$ServerHelloDoneConsumer.consume(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLHandshake.consume(Unknown Source)
app    |    at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
app    |    at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
app    |    ... 23 more}
app    | 
app    | )
app  exited with code 0

2 answers

0

One way you can do it is to set the Keystore and trustStore in the System class, see if the following code helps you.

try {
    String url = "https://server.gov.br/authentication";
    
    //set keyStore
    System.setProperty("javax.net.ssl.keyStore", "C:\\temp\\yourKeyStore.jks");
    System.setProperty("javax.net.ssl.keyStorePassword", "password");
    System.setProperty("javax.net.ssl.keyStoreType", "JKS");

    //set trustStore
    System.setProperty("javax.net.ssl.trustStore", "C:\\temp\\yourTrustStore.jks");
    System.setProperty("javax.net.ssl.trustPassword", "password");
    System.setProperty("javax.net.ssl.trustType", "JKS");

    HttpsURLConnection con = (HttpsURLConnection) new URL(url).openConnection();
    con.setRequestMethod("POST");

    //add request header
    con.setRequestProperty("Content-Type", "application/json; utf-8");
    con.setRequestProperty("Accept", "application/json");

    con.setDoOutput(true);

    try(OutputStream os = con.getOutputStream()) {
        byte[] input = jsonBody.getBytes("utf-8");
        os.write(input, 0, input.length);
    }

    try(BufferedReader br = new BufferedReader(
            new InputStreamReader(con.getInputStream(), "utf-8"))) {
        StringBuilder response = new StringBuilder();
        String responseLine = null;
        while ((responseLine = br.readLine()) != null) {
            response.append(responseLine.trim());
        }
    }

    con.disconnect();

} catch (Exception e) {
    System.out.println(e);
}

0

[RESOLVED] I was able to solve the problem by importing the Keystore and truststore via code and setting the context. I used as an example an okhttp3 project Issue: https://github.com/square/okhttp/issues/2786 and adjusted to my case and it worked.

package testes;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

public class HttpsClientOkHttp {
    /*
     * // truststore default, caso importe as cadeias de certificados para o truststore default do java
     * private final String truststoreType = KeyStore.getDefaultType();
     * private final String truststorePath = System.getenv("JAVA_HOME") + "/lib/security/cacerts";
     * private final String truststorePassword = "changeit";
     */

    // truststore personalizado usando o keytool a partir das cadeias de certificados do SERPRO
    private final String truststoreType = "JKS";
    private final String truststorePath = "/truststore.jks";
    private final String truststorePassword = "trustorePass";

    private final String keystoreType = "PKCS12";
    private final String keystorePath = "clientCertificate.pfx";
    private final String keystorePassword = "clientCertPass";
    private final String url = "https://server.gov.br/authentication";

    public static void main(String[] args) throws Exception {
        System.out.println("Running...");
        try {
            new HttpsClientOkHttp().run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public final void run() {
        try {
            OkHttpClient httpsClient = createHttpsClient();
            Request request = new Request.Builder().url(url).build();

            Response response = httpsClient.newCall(request).execute();

            if (!response.isSuccessful()) {
                throw new RuntimeException("Unexpected code " + response);
            }

            System.out.println(response.body().string());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public OkHttpClient createHttpsClient() throws Exception {
        long timeout = 120l;
        OkHttpClient httpsClient = new OkHttpClient();
        httpsClient.setConnectTimeout(timeout, TimeUnit.SECONDS);
        httpsClient.setWriteTimeout(timeout, TimeUnit.SECONDS);
        httpsClient.setReadTimeout(timeout, TimeUnit.SECONDS);
        httpsClient.setSslSocketFactory(createSslSocketFactory());
        return httpsClient;
    }

    public SSLSocketFactory createSslSocketFactory() throws Exception {
        try (InputStream keyInputStream = new FileInputStream(keystorePath);
                InputStream trustInputStream = new FileInputStream(truststorePath)) {

            KeyStore clientStore = KeyStore.getInstance(keystoreType);
            char[] clientPassArray = keystorePassword.toCharArray();
            clientStore.load(keyInputStream, clientPassArray);

            KeyStore trustStore = KeyStore.getInstance(truststoreType);
            trustStore.load(trustInputStream, truststorePassword.toCharArray());

            KeyManagerFactory keyManagerFactory = KeyManagerFactory
                    .getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientStore, clientPassArray);
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }

            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(keyManagers, trustManagers, new SecureRandom());

            return sslContext.getSocketFactory();
        } catch (Exception ex) {
            throw ex;
        }
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.