pengrad / java-telegram-bot-api

Telegram Bot API for Java
https://core.telegram.org/bots
Apache License 2.0
1.79k stars 372 forks source link

java.io.IOException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target #207

Open roabol opened 4 years ago

roabol commented 4 years ago

**The situation is the same as described on 25 April 2019 (https://github.com/pengrad/java-telegram-bot-api/issues/160#issue-437322657). The difference is that we changed the server, a new installation. But from what I understood at the time, what made it work was the custom OkHttpClient. Here is the implementation of the class:

Remembering that this error only happens when my application is on the server, which uses https**

`public class BuilderCustomTelegram {

private final String token;

public BuilderCustomTelegram(String token) { this.token = token; }

public TelegramBot getTelegramBot() { X509TrustManager trustManager; SSLSocketFactory sslSocketFactory;

try {
    trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, new TrustManager[]{trustManager}, null);
    sslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
    throw new RuntimeException(e);
}

OkHttpClient client = new OkHttpClient.Builder()
        .sslSocketFactory(sslSocketFactory, trustManager)
        .build();

TelegramBot bot = new TelegramBot.Builder(token)
        .okHttpClient(client)
        .build();

return bot;

}

private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream in = null; // By convention, 'null' creates an empty key store. keyStore.load(in, password); return keyStore; } catch (IOException e) { throw new AssertionError(e); } }

private X509TrustManager trustManagerForCertificates(InputStream in) throws GeneralSecurityException { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in); if (certificates.isEmpty()) { throw new IllegalArgumentException("expected non-empty set of trusted certificates"); }

// Put the certificates a key store.
char[] password = "password".toCharArray(); // Any password will work.
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
    String certificateAlias = Integer.toString(index++);
    keyStore.setCertificateEntry(certificateAlias, certificate);
}

// Use it to build an X509 trust manager.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

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

}

private InputStream trustedCertificatesInputStream() { // PEM files for root certificates of Comodo and Entrust. These two CAs are sufficient to view // https://publicobject.com (Comodo) and https://squareup.com (Entrust). But they aren't // sufficient to connect to most HTTPS sites including https://godaddy.com and https://visa.com. // Typically developers will need to get a PEM file from their organization's TLS administrator. String comodoRsaCertificationAuthority = ""

And this is the error:

java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at com.pengrad.telegrambot.impl.TelegramBotClient.send(TelegramBotClient.java:67) at com.pengrad.telegrambot.TelegramBot.execute(TelegramBot.java:42) at br.com.portal.web.view.administracao.telegram.teste.TelegramTesteView.enviarPeloTelegramBot(TelegramTesteView.java:123) at br.com.portal.web.view.administracao.telegram.teste.TelegramTesteView.enviar(TelegramTesteView.java:68) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at com.sun.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:153) at com.sun.el.parser.AstValue.invoke(AstValue.java:261) at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:237) at org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40) at org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50) at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:65) at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:124) at javax.faces.event.ActionEvent.processListener(ActionEvent.java:72) at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:490) at javax.faces.component.UICommand.broadcast(UICommand.java:211) at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:847) at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1396) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:58) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:177) at javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:707) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:451) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1636) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:331) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211) at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:81) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211) at br.com.portal.web.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:33) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211) at br.com.sigmax.web.servlet.HSTSFilter.doFilter(HSTSFilter.java:31) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211) at br.com.sigmax.web.servlet.SecurityFilter.doFilter(SecurityFilter.java:69) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:253) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:211) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:257) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238) at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:182) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:156) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:218) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:95) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:260) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:177) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:109) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:88) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:53) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:524) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:89) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:94) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:33) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:114) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:569) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549) at java.base/java.lang.Thread.run(Thread.java:834) 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:321) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1337) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1212) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1155) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:450) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:427) at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:178) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1151) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1062) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402) at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:320) at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:284) at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:169) at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:258) at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114) at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:127) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:257) at okhttp3.RealCall.execute(RealCall.java:93) at com.pengrad.telegrambot.impl.TelegramBotClient.send(TelegramBotClient.java:64) ... 66 more 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:439) at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) 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$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1321) ... 96 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:434) ... 102 more

vitalyster commented 4 years ago

You should not configure custom trust in OkHttp, when you are using defaults it will pick JVM defaults with all root and intermediate system managed certificates and it should be suffice to connect to api.telegram.org.

pengrad commented 4 years ago

@roabol what do you mean "my application is on the server, which uses https"? this error happens when you're connecting to https://api.telegram.org, right?

pengrad commented 4 years ago

@roabol what if you explicitly set api url to http?

TelegramBot bot = new TelegramBot.Builder(token)
                .apiUrl("http://api.telegram.org/bot")
                .build();
roabol commented 4 years ago

@pengrad when I run on my machine, it works normally. The problem only occurs on the server (google GCP) where I have a certificate (letsencrypt). #

I will try this code that you mentioned.

I really imagine that the problem is not in the API. But I'm not sure what to do.

roabol commented 4 years ago

You should not configure custom trust in OkHttp, when you are using defaults it will pick JVM defaults with all root and intermediate system managed certificates and it should be suffice to connect to api.telegram.org.

But with this configuration it already worked. And without doing anything under an https domain it doesn't work

pengrad commented 4 years ago

The problem only occurs on the server (google GCP) where I have a certificate (letsencrypt).

It's not about SSL of your server, it's about certificates that installed in OS (or Java?) which can't work with api.telegram.org. You can try to access other https endpoints (better not google infrastructure) to test are they accessible.

roabol commented 4 years ago

@roabol what if you explicitly set api url to http?

TelegramBot bot = new TelegramBot.Builder(token)
                .apiUrl("http://api.telegram.org/bot")
                .build();

Thanks @pengrad, but it did not work.

pengrad commented 4 years ago

wait, but in code you posted above you use only Comodo certificate in trustedCertificatesInputStream()?

roabol commented 4 years ago

wait, but in code you posted above you use only Comodo certificate in trustedCertificatesInputStream()?

yes, just like that

pengrad commented 4 years ago

hm, but you need certifate from api.telegram.com, it should be from godaddy try this one certificate.txt you need to add "\n" on every line.

and I may get it wrong, so please double check I used this command

echo | openssl s_client -connect telegram.com:443 |\
  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > certificate.txt
pengrad commented 4 years ago

I know you may ask why it worked before - I don't know :)

roabol commented 4 years ago

I know you may ask why it worked before - I don't know :)

yes, how... hehe

I will try now

roabol commented 4 years ago

I reviewed it several times, but it didn't work.

I tried to import the certificate to /usr/java/jdk-11.0.6/lib/security/cacerts and to payara server also in $PAYARA_HOME/glassfish/domains/domain1/config/cacerts.jks, and nothing

pengrad commented 4 years ago

@roabol how about jdk you are using now and before, are they same? can you install different JDKs?

possible to run this:

apt-get install ca-certificates-java

And there are couple of suggestions here https://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore

Make sure after installing correct certificates in system you build bot without custom http client, just: TelegramBot bot = new TelegramBot(TOKEN);

roabol commented 4 years ago

No, I used jdk1.8.0_231, and upgraded to jdk-11.0.6, both from oracle. I can make a simple application in 1.8, to test it, but I can't get my application back to 1.8. I'll do the test and post the result here. Regarding ca-certificates-java, I couldn't find it, I use CentOS 7, so I ran yum search ca-certificates, and I only found ca-certificates.noarch: The Mozilla CA root certificate bundle, which is already installed. Even so, I ran the application as follows: TelegramBot bot = new TelegramBot (TOKEN); and it still didn't work. I had already seen this link that you sent, but I have not tested all alternatives, I will look more closely at them. Thank you for now @pengrad

vitalyster commented 4 years ago

@roabol there is no need to use oracle jdk11 distribution under centos, that is the reason you have broken ca certificates authority. Just switch to openjdk-devel centos jdk package and it will pick correct ca certificates automatically.

roabol commented 4 years ago

@roabol there is no need to use oracle jdk11 distribution under centos, that is the reason you have broken ca certificates authority. Just switch to openjdk-devel centos jdk package and it will pick correct ca certificates automatically.

Thank @vitalyster , I'll try and put the result here!

Abu-Abdullah commented 2 years ago

facing the same issue. trying to use apiUrl("http://api.telegram.org/bot") as suggested above without success it gives me

com.pengrad.telegrambot.TelegramException: java.io.IOException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
        at com.pengrad.telegrambot.impl.UpdatesHandler$1.onFailure(UpdatesHandler.java:87)
        at com.pengrad.telegrambot.impl.UpdatesHandler$1.onFailure(UpdatesHandler.java:49)
        at com.pengrad.telegrambot.impl.TelegramBotClient$1.onResponse(TelegramBotClient.java:55)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at java.base/java.lang.Thread.run(Thread.java:833)

any other hints. im using the lates 6.1.0 with openjdk-17. it was working just fine 5.0.1 and openjdk-11

Abu-Abdullah commented 2 years ago

Following on this case, i have tested the certificate directly using SSLPoke, and it seems working fine:

pi@raspberrypi:~ $ java SSLPoke api.telegram.org 443
Successfully connected

so maybe there is something wrong with the internal OkHttp implementation

Abu-Abdullah commented 2 years ago

ok solved by the same above workaround having custom OkHttpClient, for some reason it didnt work when i tried to import directly in keystore /etc/ssl/certs/java/cacerts

this is how i got it:

openssl s_client -connect api.telegram.org:443 -tls1_3

i still do hope that such thing is implemented internally without any need for such workaround

Abu-Abdullah commented 1 year ago

this case is happening all the time and solved by itself. most probably it is an issue from telegram side and has nothing with this library or others. the same type of error is happening with many other libraries and developers