title: OkHttp3 - unable to find valid certification path to requested target
body: <p>In my app I use retrofit2(2.9.0) with OkHttp3(3.14.4). I want to add tls client certificate to all of my requests to some api. I've got the certificate in a <code>.p12</code> file. I read the file, loaded into X509Certificate class then I used the <code>.addTrustedCertificate(certificate)</code> method. The certificate is correct I tried it using curl. Unfortunately when I run the code I get an exception.</p>
  <pre><code>Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
      at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:320)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:263)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:258)
      at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:641)
      at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:460)
      at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:360)
      at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
      at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
      at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
      at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:177)
      at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
      at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
      at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
      at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
      at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)
      at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300)
      at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
      at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
      at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
      at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
      at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
      at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:213)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
      at okhttp3.RealCall.execute(RealCall.java:81)
      at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
      at com.jakewharton.retrofit2.adapter.reactor.ExecuteSinkConsumer.accept(ExecuteSinkConsumer.java:39)
      at com.jakewharton.retrofit2.adapter.reactor.ExecuteSinkConsumer.accept(ExecuteSinkConsumer.java:24)
      at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:94)
      at reactor.core.publisher.Flux.subscribe(Flux.java:8143)
      at com.jakewharton.retrofit2.adapter.reactor.BodyFlux.subscribe(BodyFlux.java:36)
      at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194)
      at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
      at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
      at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
      at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
      at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
      at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
      at java.base/java.lang.Thread.run(Thread.java:834)
  Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
      at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
      at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:290)
      at java.base/sun.security.validator.Validator.validate(Validator.java:264)
      at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
      at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222)
      at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129)
      at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:625)
      ... 47 more
  Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
      at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
      at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
      at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
      at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
      ... 53 more
  
  Process finished with exit code 1
  </code></pre>
  <p>my code looks like this</p>
  <pre><code>val fileName = &quot;certyficate.p12&quot;
  val file = File(fileName)
  val inputStream = file.inputStream()
  val p12 = KeyStore.getInstance(&quot;pkcs12&quot;)
  val password = &quot;password&quot;
  p12.load(inputStream, password.toCharArray())
  val alias = p12.aliases().nextElement()
  val certificate = p12.getCertificate(alias) as X509Certificate
  val ob = ObjectMapper().registerModule(KotlinModule())
  val hostname = &quot;https://myapi.com&quot;
  val timeout = 5L
  val okHttpClient = OkHttpClient.Builder()
      .connectTimeout(timeout, TimeUnit.SECONDS)
      .readTimeout(timeout, TimeUnit.SECONDS)
      .writeTimeout(timeout, TimeUnit.SECONDS)
      .apply {
              addInterceptor(HttpLoggingInterceptor().apply {
                  level = HttpLoggingInterceptor.Level.BODY
              })
      }
      .apply {
              val clientCertificate = HandshakeCertificates
                  .Builder()
                  .addTrustedCertificate(certificate)
                  .build()
              sslSocketFactory(clientCertificate.sslSocketFactory(), clientCertificate.trustManager())
      }
      .build()
  
  val retrofit = Retrofit.Builder()
      .baseUrl(hostname)
      .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(
          io.reactivex.schedulers.Schedulers.io()
      ))
      .addCallAdapterFactory(ReactorCallAdapterFactory.createWithScheduler(Schedulers.newElastic(
          MyApi::class.java.name
      )))
      .addConverterFactory(JacksonConverterFactory.create(ob))
      .client(okHttpClient)
      .build()
  
  val p = retrofit.create(MyApi::class.java)
  val res = p.doRequest().block()
  println(res)
  </code></pre>
  <p>What's a possible reason? how to correctly use client certificates when using OkHttp3 ?</p>
  <p>EDIT after I added <code>.addPlatformTrustedCertificates()</code> I get</p>
  <pre><code>Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
      at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
      at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
      at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:307)
      at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:285)
      at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:180)
      at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
      at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
      at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
      at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
      at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:336)
      at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:300)
      at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:185)
      at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
      at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
      at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
      at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
      at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:213)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
      at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
      at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
      at okhttp3.RealCall.execute(RealCall.java:81)
      at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
      at com.jakewharton.retrofit2.adapter.reactor.ExecuteSinkConsumer.accept(ExecuteSinkConsumer.java:39)
      at com.jakewharton.retrofit2.adapter.reactor.ExecuteSinkConsumer.accept(ExecuteSinkConsumer.java:24)
      at reactor.core.publisher.FluxCreate.subscribe(FluxCreate.java:94)
      at reactor.core.publisher.Flux.subscribe(Flux.java:8143)
      at com.jakewharton.retrofit2.adapter.reactor.BodyFlux.subscribe(BodyFlux.java:36)
      at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194)
      at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
      at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
      at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
      at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
      at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
      at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
  at java.base/java.lang.Thread.run(Thread.java:834)
  </code></pre>
  <p>I run with <code>javax.net.debug=ssl,handshake</code> and found in my logs</p>
  <pre><code>javax.net.ssl|DEBUG|12|my.app.MyApi-2|2021-03-03 14:00:09.656 CET|CertificateMessage.java:290|No X.509 certificate for client authentication, use empty Certificate message instead
  javax.net.ssl|DEBUG|12|my.app.MyApi-2|2021-03-03 14:00:09.656 CET|CertificateMessage.java:321|Produced client Certificate handshake message (
  &quot;Certificates&quot;: &lt;empty list&gt;
  )
  </code></pre>
  <p>also my build.gradle</p>
  <pre><code>compile group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.9.0'
  compile group: 'com.squareup.retrofit2', name: 'converter-jackson', version: '2.9.0'
  compile group: 'com.squareup.retrofit2', name: 'adapter-rxjava2', version: '2.9.0'
  compile group: 'com.jakewharton.retrofit', name: 'retrofit2-reactor-adapter', version: '2.1.0'
  compile group: 'com.squareup.okhttp3', name: 'okhttp-tls', version: '3.14.4'
  </code></pre>