2

I've been trying to get to add SSL connection with server and unfortunately it doesn't work - still getting javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found..

The order of operation:

  • create certificate by app side

  • send created certificate to server

  • In request we got certificate to use e.g. MIIEpzCCAo+gAwIBAgICALQwDQYJKoZIhvcNAQELBQAwgYAxCzAJBgNVBAYTAlBM[...]6AlW6gjevIU7ZP2lIZWmA9f5uPc3Js1aft3UHmVfdiTaG+rcAVsw+ck7aQ== (ROOT_CA)

  • Next requests are going to be send with attached this certificate (ROOT_CA).

Code responsible for sending with certificate :

    private void retrofitConfiguration(Context context){
            OkHttpClient.Builder client = new OkHttpClient.Builder();
            ProviderInstaller.installIfNeeded(context);
            X509Certificate ca = loadCertificate();
            KeyStore keyStore = createKeyStore(ca);
            TrustManager[] trustManagers = createTrustManager(keyStore);
            SSLContext sslContext = null;
            sslContext = createSSLContext(trustManagers, keyStore);
            X509TrustManager _trustManager = (X509TrustManager) trustManagers[0];
            client.sslSocketFactory(sslContext.getSocketFactory(), _trustManager);
            client.hostnameVerifier(getHostnameVerifier());
            buildRetrofit(client.build());
     }

    private X509Certificate loadCertificate() throws CertificateException {
         CertificateFactory cf = CertificateFactory.getInstance("X.509");
         String ca = ROOT_CA;
         byte[] decoded = Base64.decode(ca);
         return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decoded));
     }

    private KeyStore createKeyStore(X509Certificate ca) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
         String keyStoreType = KeyStore.getDefaultType();
         KeyStore keyStore = KeyStore.getInstance(keyStoreType);
         keyStore.load(null, null);
         keyStore.setCertificateEntry("ca", ca);
         return keyStore;
    }

     private TrustManager[] createTrustManager(KeyStore keyStore) throws NoSuchAlgorithmException, KeyStoreException {
         String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
         TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
         tmf.init(keyStore);
         return tmf.getTrustManagers();
     }

     private SSLContext createSSLContext(TrustManager[] trustManagers, KeyStore keyStore) throws KeyManagementException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
         SSLContext sslContext = SSLContext.getInstance("TLS");

         KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
         kmf.init(keyStore, new char[]{0});
         KeyManager[] keyManagers = kmf.getKeyManagers();

         sslContext.init(keyManagers, trustManagers, null);
         return sslContext;
     }


     private HostnameVerifier getHostnameVerifier() {
         return (hostname, session) -> {
             return true;
         };
     }

I tried to use CustomTrustManager from https://github.com/rfreedman/android-ssl with same result.

I really don't get why it doesn't work at that point.. (went through a lot of other topic like this)

Any help would be greatly appreciated!

UPDATE

Now i am using this method :

 private SSLSocketFactory getSSLSocketFactory()
        throws CertificateException, KeyStoreException, IOException,
        NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException {

    Certificate clientCA = parseClientCertificate();
    KeyStore clientKeyStore = KeyStore.getInstance("BKS");
    clientKeyStore.load(null, null);
    clientKeyStore.setCertificateEntry("clientCA", clientCA);
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
    keyManagerFactory.init(clientKeyStore, null);
    KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();


    Certificate rootCA = parseRootCertificate();
    KeyStore rootKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    rootKeyStore.load(null, null);
    rootKeyStore.setCertificateEntry("rootCA", rootCA);
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(rootKeyStore);
    TrustManager[] managers = tmf.getTrustManagers();

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, managers, null);
    return sslContext.getSocketFactory();
}

And getting javax.net.ssl.SSLHandshakeException: Handshake failed. This connection is to https and I am trying to attach my client cert to requests. (tested with okhttp3 and android 7.1.1). I went through a lot of topic in stack and can not find any working solution.

Full stack trace:

W: javax.net.ssl.SSLHandshakeException: Handshake failed
W:     at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@11746440:54)
W:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:267)
W:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:237)
W:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:148)
W:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186)
W:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
W:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
W:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at com.network.ApiClient.lambda$retrofitConfiguration$0(ApiClient.java:127)
W:     at com.network.ApiClient$$Lambda$1.intercept(Unknown Source)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
W:     at okhttp3.RealCall.execute(RealCall.java:63)
W:     at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
W:     at retrofit2.adapter.rxjava.CallExecuteOnSubscribe.call(CallExecuteOnSubscribe.java:40)
W:     at retrofit2.adapter.rxjava.CallExecuteOnSubscribe.call(CallExecuteOnSubscribe.java:24)
W:     at retrofit2.adapter.rxjava.BodyOnSubscribe.call(BodyOnSubscribe.java:33)
W:     at retrofit2.adapter.rxjava.BodyOnSubscribe.call(BodyOnSubscribe.java:25)
W:     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
W:     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
W:     at rx.Observable.unsafeSubscribe(Observable.java:10346)
W:     at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100)
W:     at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230)
W:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
W:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
W:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
W:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
W:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
W:     at java.lang.Thread.run(Thread.java:761)
W: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7f8f068740: Failure in SSL library, usually a protocol error
W: error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (third_party/openssl/boringssl/src/ssl/tls_record.cc:575 0x7f8f0fb180:0x00000001)
W:     at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
W:     at com.google.android.gms.org.conscrypt.SslWrapper.doHandshake(:com.google.android.gms@11746440:2)
W:     at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@11746440:19)
W:  ... 43 more
W: com.network.errors.RetrofitException: Handshake failed
W:     at com.network.RxErrorHandlingCallAdapterFactory$RxCallAdapterWrapper.asRetrofitException(RxErrorHandlingCallAdapterFactory.java:93)
W:     at com.network.RxErrorHandlingCallAdapterFactory$RxCallAdapterWrapper.access$000(RxErrorHandlingCallAdapterFactory.java:51)
W:     at com.network.RxErrorHandlingCallAdapterFactory$RxCallAdapterWrapper$1.call(RxErrorHandlingCallAdapterFactory.java:71)
W:     at com.network.RxErrorHandlingCallAdapterFactory$RxCallAdapterWrapper$1.call(RxErrorHandlingCallAdapterFactory.java:68)
W:     at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:140)
W:     at retrofit2.adapter.rxjava.BodyOnSubscribe$BodySubscriber.onError(BodyOnSubscribe.java:64)
W:     at retrofit2.adapter.rxjava.CallArbiter.emitError(CallArbiter.java:141)
W:     at retrofit2.adapter.rxjava.CallExecuteOnSubscribe.call(CallExecuteOnSubscribe.java:43)
W:     at retrofit2.adapter.rxjava.CallExecuteOnSubscribe.call(CallExecuteOnSubscribe.java:24)
W:     at retrofit2.adapter.rxjava.BodyOnSubscribe.call(BodyOnSubscribe.java:33)
W:     at retrofit2.adapter.rxjava.BodyOnSubscribe.call(BodyOnSubscribe.java:25)
W:     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
W:     at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
W:     at rx.Observable.unsafeSubscribe(Observable.java:10346)
W:     at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.call(OperatorSubscribeOn.java:100)
W:     at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230)
W:     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
W:     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
W:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
W:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
W:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
W:     at java.lang.Thread.run(Thread.java:761)
W: Caused by: javax.net.ssl.SSLHandshakeException: Handshake failed
W:     at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(:com.google.android.gms@11746440:54)
W:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:267)
W:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:237)
W:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:148)
W:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:186)
W:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
W:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
W:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:212)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at com.network.ApiClient.lambda$retrofitConfiguration$0(ApiClient.java:127)
W:     at com.network.ApiClient$$Lambda$1.intercept(Unknown Source)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
W:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
W:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
W:     at okhttp3.RealCall.execute(RealCall.java:63)
W:     at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
W:     at retrofit2.adapter.rxjava.CallExecuteOnSubscribe.call(CallExecuteOnSubscribe.java:40)
W:  ... 15 more
W: Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7f8f068740: Failure in SSL library, usually a protocol error
W: error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (third_party/openssl/boringssl/src/ssl/tls_record.cc:575 0x7f8f0fb180:0x00000001)
W:     at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
W:     at com.google.android.gms.org.conscrypt.SslWrapper.doHandshake(:com.google.android.gms@11746440:2)
Ikazuchi
  • 403
  • 2
  • 12
  • Its look like https://stackoverflow.com/questions/9249158/why-do-i-get-a-handshake-failure-java-ssl but there is no solution for it. Client certificate is locally generated, send to server, signed by it and return in response. But it looks like keystore ignore it and do not send to server. – Ikazuchi Dec 08 '17 at 09:43
  • getCertificateChain("clientCA") return null – Ikazuchi Dec 08 '17 at 13:14

1 Answers1

0

I got it!!

I had to add this to my KeyStore:

    Certificate[] chain = new Certificate[] {clientCA, rootCA};
    keyStore.setCertificateEntry("clientCA", clientCA);
    keyStore.setCertificateEntry("rootCA", rootCA);
    keyStore.setKeyEntry("keys", getPrivateKey(), password, chain);
Ikazuchi
  • 403
  • 2
  • 12