I am trying to make api calls from my apache tomcat7 server running jdk1.6 (on an aws ec2) to aws api gateway private endpoints inside my vpc. Such private endpoints only allow TLSv1.2. I am using jdk1.6.45 (which does not have TLSv1.2 support OOTB) and there is no possibility of upgrading due to other constraints. I am attempting to use bouncy castle jce and jsse providers so that I can create https connections to the api gateway using HttpsUrlConnection object.
I am having issues with the registration of bouncy castle providers when I try to make api calls. It seems to be some kind of issue with finding an ECDH algorithm.
Here is the stacktrace:
WARNING: Client raised fatal(2) internal_error(80) alert: Failed to read record
org.bouncycastle.tls.crypto.TlsCryptoException: cannot calculate secret
at org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDomain.calculateECDHAgreement(Unknown Source)
at org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDH.calculateSecret(Unknown Source)
at org.bouncycastle.tls.TlsECDHEKeyExchange.generatePreMasterSecret(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.establishMasterSecret(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.dart.flett.bl.BLGats.getInboxOutBox(BLGats.java:32)
at com.dart.flett.bl.BLInbox.makeInboxOutboxCall(BLInbox.java:497)
at com.solvefastinc.fe.gwt.server.FECoreFacade.aggregateInboxGATS(FECoreFacade.java:1817)
at com.solvefastinc.fe.gwt.server.FEFormServiceImpl.aggregateInboxGATS(FEFormServiceImpl.java:417)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:561)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:208)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.solvefastinc.flett.servletfilter.GWTNoCacheFilter.doFilter(GWTNoCacheFilter.java:56)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.security.NoSuchAlgorithmException: Algorithm ECDH not available
at javax.crypto.KeyAgreement.getInstance(DashoA13*..)
at org.bouncycastle.jcajce.util.DefaultJcaJceHelper.createKeyAgreement(Unknown Source)
at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.calculateKeyAgreement(Unknown Source)
... 51 more
org.bouncycastle.tls.crypto.TlsCryptoException: cannot calculate secret
at org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDomain.calculateECDHAgreement(Unknown Source)
at org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDH.calculateSecret(Unknown Source)
at org.bouncycastle.tls.TlsECDHEKeyExchange.generatePreMasterSecret(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.establishMasterSecret(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.dart.flett.bl.BLGats.getInboxOutBox(BLGats.java:32)
at com.dart.flett.bl.BLInbox.makeInboxOutboxCall(BLInbox.java:497)
at com.solvefastinc.fe.gwt.server.FECoreFacade.aggregateInboxGATS(FECoreFacade.java:1817)
at com.solvefastinc.fe.gwt.server.FEFormServiceImpl.aggregateInboxGATS(FEFormServiceImpl.java:417)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:561)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:208)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.solvefastinc.flett.servletfilter.GWTNoCacheFilter.doFilter(GWTNoCacheFilter.java:56)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.security.NoSuchAlgorithmException: Algorithm ECDH not available
at javax.crypto.KeyAgreement.getInstance(DashoA13*..)
at org.bouncycastle.jcajce.util.DefaultJcaJceHelper.createKeyAgreement(Unknown Source)
at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.calculateKeyAgreement(Unknown Source)
... 51 more
Here is what I have done so far taken from posts with similar issues:
- I have moved placed bouncy castle libraries bcprov-ext-jdk15on-162.jar, bcpkix-jdk15on-162.jar, bctls-jdk15on-162.jar in JAVA_HOME/jre/security/ext and have added lines
security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.3=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
to my java.security file. I have also printed registered providers to console and can see that both BC and BCJSSE providers in the list below
SUN
BC
BCJSSE
SunRsaSign
SunJSSE
SunJCE
SunJGSS
SunSASL
XMLDSig
SunPCSC
SunMSCAPI
I have saved unlimited strength crypto extensions into java security folder
I dug into the bouncy castle source code and found the following code is failing, which I tried myself in my https client.
try {
KeyAgreement ka = KeyAgreement.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
}
catch ( Exception e) {
e.printStackTrace();
}
It seems to have some issue parsing my provider jar in the ext folder though I got them directly from here https://www.bouncycastle.org/latest_releases.html
I have also compared the checksum of this jar to ensure its authenticity as suggested here: https://github.com/bcgit/bc-java/issues/514
Here is the stacktrace:
java.security.NoSuchProviderException: JCE cannot authenticate the provider BC
at javax.crypto.SunJCE_b.a(DashoA13*..)
at javax.crypto.KeyAgreement.getInstance(DashoA13*..)
at com.solvefastinc.flett.comm.GATSApiService.connect(GATSApiService.java:109)
at com.dart.flett.bl.BLInbox.makeInboxOutboxCall(BLInbox.java:496)
at com.solvefastinc.fe.gwt.server.FECoreFacade.aggregateInboxGATS(FECoreFacade.java:1817)
at com.solvefastinc.fe.gwt.server.FEFormServiceImpl.aggregateInboxGATS(FEFormServiceImpl.java:417)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:561)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:208)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processPost(RemoteServiceServlet.java:248)
at com.google.gwt.user.server.rpc.AbstractRemoteServiceServlet.doPost(AbstractRemoteServiceServlet.java:62)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at com.solvefastinc.flett.servletfilter.GWTNoCacheFilter.doFilter(GWTNoCacheFilter.java:56)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.util.jar.JarException: Cannot parse file:/C:/Program%20Files/Java/jdk1.6.0_45/jre/lib/ext/bcprov-ext-jdk15on-162.jar
at javax.crypto.SunJCE_c.a(DashoA13*..)
at javax.crypto.SunJCE_b.b(DashoA13*..)
at javax.crypto.SunJCE_b.a(DashoA13*..)
... 36 more
- I have printed out available cipher suites to ensure that the ones packaged with JDK1.6 are supported by aws api gateway. An can see that
* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
in the list below are supported by both
Default Cipher
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CCM
TLS_DHE_RSA_WITH_AES_128_CCM_8
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CCM
TLS_DHE_RSA_WITH_AES_256_CCM_8
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CCM
TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_CCM
TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
* TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
* TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_ECDSA_WITH_NULL_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
* TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
* TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_NULL_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
* TLS_RSA_WITH_AES_128_CBC_SHA
* TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CCM
TLS_RSA_WITH_AES_128_CCM_8
* TLS_RSA_WITH_AES_128_GCM_SHA256
* TLS_RSA_WITH_AES_256_CBC_SHA
* TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_256_CCM
TLS_RSA_WITH_AES_256_CCM_8
* TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_NULL_SHA
TLS_RSA_WITH_NULL_SHA256
Here is my code sample showing the request made. Note: I am trusting all certificates for this as the api will not be made available over the internet and also due to the fact that aws doesn't provide the signed certificate for api gateway apis.
TrustManager trm = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String
authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String
authType) {}
};
SSLContext sc = SSLContext.getInstance("TLSv1.2",new BouncyCastleJsseProvider());
sc.init(null, new TrustManager[] {trm} SecureRandom.getInstance("DEFAULT", "BC"));
conn = (HttpsURLConnection) this.gatsUrl.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(30000);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
According to everything I've read including bouncy castle documentation and other issues, the code above should work once both providers are registered.