Title:
cfhttp tag running under CF2018 is causing error `I/O Exception: Received fatal alert: bad_certificate` when https mutual authentication
| View in TrackerStatus/Resolution/Reason: Closed/Fixed/PRHaveInfo
Reporter/Name(from Bugbase): Adam v. / ()
Created: 05/21/2019
Components: Net Protocols, HTTP
Versions: 2018
Failure Type: Incorrectly functioning
Found In Build/Fixed In Build: 2018.0.03.314033 / 13.0
Priority/Frequency: Normal / All users will encounter
Locale/System: English / Win 2016
Vote Count: 0
Problem Description: issue/bug with cfhttp tag running under CF2018 is causing error `I/O Exception: Received fatal alert: bad_certificate` .In CF2018 using cfhttp tag for an endpoint which requires client certificate authentication(https mutual authentication) is causing error I/O Exception: Received fatal alert: bad_certificate even though the Java keystore is configured correctly.This issue does not happen in CF2016 but is happening in CF2018 .Also calling the same endpoint using java classes also works fine.
Steps to Reproduce:
We are getting I/O Exception: Received fatal alert: bad_certificate error with endpoints require client certificate authentication.The code used is
<cftry>
<cfhttp method="post" port="443" url="<https endpoint with client certificate auth configured>">
<cfhttpparam type="body" value="">
</cfhttp>
<cfdump var="#cfhttp#">
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
We have all the necessary certificates configured in the Java Keystore.The java keystore we are using is exactly same in all the web servers . So we have Cf2016 servers and CF2018 both using same 'cacerts' file.And in coldfusion jvm.config it is set using JVM argument -Djavax.net.ssl.keyStore=D:/ColdFusion2018/jre/lib/security/cacerts -Djavax.net.ssl.keyStorePassword=changeit
It works fine with CF2016 server but does not work with CF2018 .
We have added java verbose logging by adding argument to jvm.config -Djavax.net.debug=ssl,handshake,verbose
And in coldfusion-error.log we see
javax.net.ssl|DEBUG|C8|ajp-nio-8018-exec-9|2019-05-15 04:15:24.851 CAT|CertificateRequest.java:651|Consuming CertificateRequest handshake message (
"CertificateRequest": {
"certificate types": [rsa_sign, dss_sign, ecdsa_sign]
"supported signature algorithms": [ecdsa_secp512r1_sha512, rsa_pkcs1_sha512, ecdsa_secp384r1_sha384, rsa_pkcs1_sha384, ecdsa_secp256r1_sha256, rsa_pkcs1_sha256, dsa_sha256, ecdsa_sha224, rsa_sha224, dsa_sha224, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
"certificate authorities": [CN====redacted=====]
}
)
javax.net.ssl|WARNING|C8|ajp-nio-8018-exec-9|2019-05-15 04:15:24.851 CAT|CertificateRequest.java:691|No available client authentication
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.472 CAT|CertificateMessage.java:291|No X.509 certificate for client authentication, use empty Certificate message instead
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.473 CAT|CertificateMessage.java:322|Produced client Certificate handshake message (
"Certificates": <empty list>
)
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.475 CAT|ECDHClientKeyExchange.java:401|Produced ECDHE ClientKeyExchange handshake message (
"ECDH ClientKeyExchange": {
"ecdh public": {
===== Redacted===== 4
},
}
)
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.486 CAT|ChangeCipherSpec.java:109|Produced ChangeCipherSpec message
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.487 CAT|Finished.java:395|Produced client Finished handshake message (
"Finished": {
"verify data": {
===Redacted========
}'}
)
javax.net.ssl|DEBUG|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.559 CAT|Alert.java:232|Received alert message (
"Alert": {
"level" : "fatal",
"description": "bad_certificate"
}
)
javax.net.ssl|ERROR|C4|ajp-nio-8018-exec-6|2019-05-08 19:23:04.561 CAT|TransportContext.java:313|Fatal (BAD_CERTIFICATE): Received fatal alert: bad_certificate (
"throwable" : {
javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:128)
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:279)
at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:181)
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 org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
at coldfusion.tagext.net.HTTPContextSSLFactoryDelegate.createLayeredSocket(HTTPContextSSLFactoryDelegate.java:64)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:141)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at coldfusion.tagext.net.HttpTag.createConnection(HttpTag.java:1936)
at coldfusion.tagext.net.HttpTag.connHelper(HttpTag.java:1126)
at coldfusion.tagext.net.HttpTag.doEndTag(HttpTag.java:1274)
at cfcallFailingWalletEndpoints2ecfm2078153070.runPage(E:\WWW\Live\VoucherEngine\check\callFailingWalletEndpoints.cfm:12)
at coldfusion.runtime.CfJspPage.invoke(CfJspPage.java:262)
at coldfusion.tagext.lang.IncludeTag.handlePageInvoke(IncludeTag.java:729)
at coldfusion.tagext.lang.IncludeTag.doStartTag(IncludeTag.java:565)
at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:65)
at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:557)
at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:43)
at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
at coldfusion.filter.PathFilter.invoke(PathFilter.java:162)
at coldfusion.filter.IpFilter.invoke(IpFilter.java:45)
at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:96)
at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:60)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
at coldfusion.CfmServlet.service(CfmServlet.java:226)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:311)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:46)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:47)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
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.intergral.fusionreactor.j2ee.filterchain.WrappedFilterChain.doFilter(WrappedFilterChain.java:134)
at com.intergral.fusionreactor.j2ee.filter.FusionReactorRequestHandler.doNext(FusionReactorRequestHandler.java:764)
at com.intergral.fusionreactor.j2ee.filter.FusionReactorRequestHandler.doHttpServletRequest(FusionReactorRequestHandler.java:344)
at com.intergral.fusionreactor.j2ee.filter.FusionReactorRequestHandler.doFusionRequest(FusionReactorRequestHandler.java:207)
at com.intergral.fusionreactor.j2ee.filter.FusionReactorRequestHandler.handle(FusionReactorRequestHandler.java:801)
at com.intergral.fusionreactor.j2ee.filter.FusionReactorCoreFilter.doFilter(FusionReactorCoreFilter.java:36)
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.intergral.fusionreactor.j2ee.filterchain.WrappedFilterChain.doFilter(WrappedFilterChain.java:71)
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.intergral.fusionreactor.agent.filter.FusionReactorStaticFilter.doFilter(FusionReactorStaticFilter.java:54)
at com.intergral.fusionreactor.agent.pointcuts.NewFilterChainPointCut$1.invoke(NewFilterChainPointCut.java:41)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:491)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:422)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:764)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1388)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)}
To further isolate the issue,We called the endpoint using java and that works fine
<cfscript>
try {
objURL = createObject("java", "java.net.URL");
ret = objURL.init("<https-mutualauth-endpoint>");
connection= objURL.openConnection();
ins = connection.getInputStream();
isr = new InputStreamReader(ins);
inreader = new BufferedReader(isr);
inputLine =inreader.readLine();
while (inputLine != null)
{
WriteOutput(inputLine);
inputLine =inreader.readLine();
}
} catch (any e) {
WriteDump(var="#e#");
rethrow;
} finally {
in.close();
con.disconnect();
}
</cfscript>
<cftry>
<cfhttp method="post" port="443" url="<https-mutualauth-endpoint>">
<cfhttpparam type="body" value="">
</cfhttp>
<cfdump var="#cfhttp#">
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>
using CFHTTP gives error bad_certificate but calling directly from java using java.net.URL.openConnection() from the same cfm page works fine.
To summarise
- same code using CFHTTP with same java keystore(cacerts) works from CF 2016
- using java.net.URL.openConnection() works fine from the same cfm page
- using clientcert and clientcertpassword with cfhttp works
So using cfhttp tag with cf2018 does not find the client certificate from the java keystore.
Actual Result:I/O Exception: Received fatal alert: bad_certificate
Expected Result:Http 200
Any Workarounds:specifying the clientcert and clientpassword is working but we cannot use that as we are getting the url dynamically and multiple endpoints are called
Attachments:
Comments: