tracker issue : CF-4204403

select a category, or use search below
(searches all categories and all time range)
Title:

cfhttp tag running under CF2018 is causing error `I/O Exception: Received fatal alert: bad_certificate` when https mutual authentication

| View in Tracker

Status/Resolution/Reason: To Track//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 /

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:

Could anyone please acknowledge/confirm the status of the ticket ? Just to reiterate, please consider following points 1. It is not a java keystore issue because using the same keystore ,simple Java application can connect to the endpoint fine. 2. It is not a problem with permission of coldfusion service because from the same coldfusion application,same cfm page it works when using pure Java 3.It is not a problem with any coldfusion settings or JVM arguments because again pure Java code from cfm page is working 4.If we provide the clientcert and clientpassword,then also it works so it is not a certificate issue. 5. To add further,the same java keystore is working fine using CF2016 as well. The issue here is that when using cfhttp,it is not finding the certificate.
Comment by Adam v.
30816 | May 24, 2019 03:52:05 AM GMT
Thanks for reporting the bug. We are verifying this at our end. Nitin
Comment by Nitin K.
30817 | May 24, 2019 05:00:49 AM GMT
Hi Adam,   I tried your scenario in my end: * I setup an endpoint with a keystore. * I imported the truststore to ColdFusion's cacert file * I gave the jvm flags as mentioned by you * Then i tried to hit the endpoint. It successfully made the connection. Can you recheck with different jre's for both CF2016 and CF2018? If the issue still persists, we may have to go on a call to check the exact issue.   Thanks, Kailash
Comment by Kailash B.
31356 | September 23, 2019 01:57:28 PM GMT