SOAP Web service not accepting the request because of incompatible TLS - java

I'm trying to make a third-party SOAP service call that uses HTTPS from local (development environment) AEM 5.6.1. The SOAP service accepts the requests with a minimum TLS Protocols of TLSv1.1.
I have AEM 5.6.1 that uses JDK7 and for JDK7 the default TLSv1.
To achieve the minimum acceptable TLS. I tried the below two approaches:
Approach 1:
Made AEM start with -Dhttps.protocols=TLSv1.2
Approach 2:
Updated the SSLContext to update TLS.
SSLContext context = null;
try {
context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, new java.security.SecureRandom());
SSLContext.setDefault(context);
LOGGER.info("Currecnt TLS:" + SSLContext.getDefault().getProtocol());
}catch (Exception e){
LOGGER.error("Error while updating TLS:",e);
}
First one doesn't work will, but the other one to update the TLS protocol for AEM to TLSv1.2.
But I'm still unable to access the service. The error remains the same.
Error:
The required TLS connection level has not been met. SSL Protocol level: TLSv1
Reference:
https://stackoverflow.com/a/42291244/4802007
https://stackoverflow.com/a/32346644/4802007
I would like to know 2 things here,
Am'I missing anything that is stopping the proper TLS update.
Is there any way to update the TLS only for this particular service, instead of changing it globally.
Thanks

This is a bug in CQ 5.5/5.6. The core issue boils down to the fact that in older CQ version SSLv3 was not allowed to be disabled by config and therefore TLS parameters never took effect.
You need to contact Daycare support and ask for a hotfix for your version.
Alternatively, check out this HF from your package share account: HOTFIX-5220 as this may have the fix for your TLS issue.
AEM 6.0 released a hotfix for this issue available via package share. Use your login and search for HOTFIX-5238 under 6.0 and ask Daycare for a back port or a compatible package for your version of AEM if the above mentioned hot fix does not work for you.

Related

How to add JVM argument `-Dcom.ibm.mq.cfg.useIBMCipherMappings=false` to IBM MQ?

Recently I've been migrated to IBM MQ v8 to IBM MQ v9 (v9.1.2.0 specifically). I used SSL to communicate with the broker. So as per Deprecated CipherSpecs document, IBM has deprecated number of cipher suites that came up with MQ 8 and seems all of the cipher suites I've been using, have been deprecated with v9 upward. Therefore, I've implemented new TLS cipher suites to work with my application which runs on a Oracle JVM (version 1.8.0_211). Ever since I'm getting following exception in the application though;
com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2400'.
at com.ibm.mq.MQManagedConnectionJ11.constructMQCD(MQManagedConnectionJ11.java:1437)
at com.ibm.mq.MQManagedConnectionJ11.constructCNO(MQManagedConnectionJ11.java:1537)
at com.ibm.mq.MQManagedConnectionJ11.<init>(MQManagedConnectionJ11.java:221)
... (Omitted the rest)
When I dig about the reason, found that's a problem with IBM MQ cipher suites and Oracle JRE cipher suite name mismatch. But I did refer TLS CipherSpecs and CipherSuites in IBM MQ classes for JMS document to map cipher suite names. I used some of Equivalent CipherSuite (Oracle JRE) column values in my application that already available in IBM MQ as well. But still getting the issue.
After I found this answer that advises to add this -Dcom.ibm.mq.cfg.useIBMCipherMappings=false argument to IBM MQ's JRE (As I understand). This might allow IBM MQ to use Oracle complied cipher suite names. My question is,
How to add this JVM argument -Dcom.ibm.mq.cfg.useIBMCipherMappings=false to IBM MQ JRE?
This Problem Connecting a Java Client (JMS) to a IBM MQ question suggests that the same parameter needed to be added to the application as a system property System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false"), but it didn't make any different.
Java connection to WMQ 8 question also states the same solution, but doesn't mention how to add this JVM argument to IBM MQ.
Update 1
I did some research about how to add a JVM argument to IBM MQ. But I was only able to find a solutions for Websphere application server.
CipherSuite I'm currently using in the application is;
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (Oracle JRE complied)
IBM MQ has respective;
ECDHE_ECDSA_AES_128_CBC_SHA256 (IBM MQ complied)
Update 2
After creating a key.kdb file with ikeyman tool with the stash option queue manager can successfully read the certificates in it. Also, I've included a self-signed certificate labeled with ibmwebspheremq<lowercase_queue_manage_name>. But now I'm getting a different exception in the client side;
Exception in thread "main" com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2059'.
at com.ibm.mq.MQManagedConnectionJ11.<init>(MQManagedConnectionJ11.java:255)
at com.ibm.mq.MQClientManagedConnectionFactoryJ11._createManagedConnection(MQClientManagedConnectionFactoryJ11.java:450)
at com.ibm.mq.MQClientManagedConnectionFactoryJ11.createManagedConnection(MQClientManagedConnectionFactoryJ11.java:487)
at com.ibm.mq.StoredManagedConnection.<init>(StoredManagedConnection.java:97)
and in the MQ log I can find this entry;
AMQ9637E: Channel is lacking a certificate.
with some explanation.
After working for while, I was able resolve this issue. Since the beginning I had this certificate configuration issue in the application side. Even after creating self-signed certificate labeled after ibmwebspheremq<queue_manager_name> and shared the extracted certificates with the client application using ikeyman tool, AMQ9637E: Channel is lacking a certificate. occurred.
In a nutshell, to resolve this issue entirely, I did the following;
Update the client MQ dependency to com.ibm.mq.allclient:v9.1.2.0. If you're using maven, use following dependency (MQC91: IBM MQ Clients).
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.allclient</artifactId>
<version>9.1.2.0</version>
</dependency>
Now, if the application runs on an Oracle JVM, we should convince the MQ client lib to use Oracle JVM complied cipher suite names. To do that, either add this -Dcom.ibm.mq.cfg.useIBMCipherMappings=false as a JVM flag or add this System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false") as a system property.
Select a appropriate cipher suite to communicate with the MQ. This TLS CipherSpecs and CipherSuites in IBM MQ classes for JMS document would be helpful as IBM has deprecated number of weak cipher specs IBMMQ 9 onwards.
I would suggest to use ECDHE_* cipher specs as they provide Ephemeral Keys to maintain Forward Secrecy.
Then, using ikeyman GUI tool, I created a self-signed certificate labeled after ibmwebspheremq<queue_manager_name> name and instead of extracting the .arm file, I export the certificate as .jks files. Both keystore.jks and truststore.jks files exported from the same certificate. After, attached them to the application using system properties;
System.setProperty("javax.net.ssl.trustStore", "truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "<password>");
System.setProperty("javax.net.ssl.keyStore", "keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "<password>");
With this configuration, SSL handshake issue went away, but the IBM MQ was still asking for user authentication with a user name and password. In order to provide them, should add these properties to MQEnvironment,
MQEnvironment.properties.put(com.ibm.mq.constants.CMQC.USER_ID_PROPERTY, "<user_name>");
MQEnvironment.properties.put(com.ibm.mq.constants.CMQC.PASSWORD_PROPERTY, "<password>");
These credentials were system credentials in my case.
If you simply want to skip user authentication like this, you can update IBMMQ config to skip credential check using runmqsc CLI tool like this (Refer this Turning on connection authentication on a queue manager document),
ALTER QMGR CONNAUTH(USE.PW)
DEFINE AUTHINFO(USE.PW) +
AUTHTYPE(IDPWOS) +
FAILDLAY(10) +
CHCKLOCL(OPTIONAL) +
CHCKCLNT(OPTIONAL)
REFRESH SECURITY TYPE(CONNAUTH)
Note that CHCKCLNT value needed to set as OPTIONAL to ignore client user credential check. IBM MQ should start to work with the client application whilst SSL enabled after these configurations.
Kudos to #JoshMc for the support to resolve this issue.
Note: Adding answer to capture information provided to OP in comments that have been removed.
See the following IBM MQ Knowledge center page for a table showing cert type compatibility with MQ v9.1:
IBM MQ 9.1.x/IBM MQ/Securing/Confidentiality of messages/Enabling CipherSpecs
The ciphers with ECDHE_ECDSA require a suite b cert for the queue manager. If using a client cert for your application it will also need to be suite b.
Note that you can use ECDHE_RSA ciphers with non-suite b certs.
The stash file (key.sth for example) is used by the queue manager to access the kdb file. The java equivalent on the client end is you specifying the jks password.

TLS 1.1 # TLS 1.2 on httpclientandroidlib

During developing Android application I faced a problem with SSL connection in android lower than KIT KAT.
Application is using ch.boye.httpclientandroidlib to connect. When I tried to get httpConnection I'm getting error:
here was error during executing http request.
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
In Android newest than KIT KAT everything works fine.
I'm trying to use solution sugested in here but i have a problem with casting types from ch.boye.httpclientandroidlib to apache elements in my current implemetations.
Is there any solution for using this library for android lower than KIT KAT?
I found a solution to this same issue here... using the class TlsSniSocketFactory (you'll have to also download IgnoreSSLTrustManager and SelfSignedTrustManager from the same "util" folder) and add it to your project.
Then register the new scheme on your SchemeRegistry object like so:
schemeRegistry.register(new Scheme("https", new TlsSniSocketFactory(), port));
My issue was my web service is set to use TLS 1.2 only.
Android devices running Android 4.4.4 and below do not automatically enable TLS 1.2 so you have to manually enable it (IMPORTANT * devices older than Android 4.1 cannot support TLS 1.2 at all, so this solution wont work for those older devices)
Late answer but hopefully helps someone
Cheers

Disabling Client-Initiated SSL Renegotiation in Jboss 7.1.1

Setting up the context:
In java 8 (precisely 8b98), in order to deal with Client-Initiated Renegotiation causing vulnerability to Denial of Service attack, an un-documented flag was rolled out named jdk.tls.rejectClientInitiatedRenegotiation as a part of Transport Layer Security which could disable client initiated renegotiations.
jdk.tls.rejectClientInitiatedRenegotiation = true
Server which i'm using is JBoss 7.1.1 which supports 7. However java 8 supporting servers are JBoss EAP & Wildfly. I'm reluctant to switch to these new server.
Now My challenge is to implement this property somehow in Java 7. Any sort of guidance will be highly appreciated.
Indeed Java 7 doesn't support this option. Maybe an acceptable behavior could be the Interoperable mode as in Description of Phase 2 Fix of the JSSE 7, which means enabling renegotiation for "good" clients ?
My exact answer is to switch to OpenSSL implementation, particularly the one with the hard-coded renegotiation denial, then you get rid of the JSSE implementation which doesn't support your hard-to-find option.
First, you need OpenSSL 0.9.8l which just denies all client renegotiations.
After that enable the Native Connectors on JBOSS 7.1 and configure as said in this documentation.
web archive links :
http://web.archive.org/web/20201019212829/https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html
http://web.archive.org/web/20201027040002/https://www.openssl.org/news/secadv/20091111.txt
http://web.archive.org/web/20201123225554/https://docs.jboss.org/author/display/AS71/Admin%20Guide.html

Java http clients and POODLE

Regarding the POODLE vulnerability, if I understand it correctly, it requires a client that automatically downgrades TLS protocol to SSLv3 when failing to establish a secure channel with a server using higher version protocol advertised by the server.
Do the common java HTTP client libraries, specifically javax.net.ssl.HttpsURLConnection and Apache HttpClient, automatically downgrade the TLS protocol when failing to establish TLS session with a server? If not, am I correct that they are immune from he POODLE attack unless either (a) the server only supports SSLv3, or (b) a logic at a higher level performs the downgrade?
I'm looking for something like http://blog.hagander.net/archives/222-A-few-short-notes-about-PostgreSQL-and-POODLE.html but for Java clients.
Apache HttpClient does not implement any of the TLS protocol aspects. It relies on JSSE APIs to do TLS/SSL handshaking and to establish secure SSL sessions. With the exception of SSL hostname verification logic, as far as TLS/SSL is concerned Apache HttpClient is as secure (or as vulnerable) as the JRE it is running in.
Update: HttpClient 4.3 by default always uses TLS, so, unless one explicitly configures it to use SSLv3 HttpClient should not be vulnerable to exploits based on POODLE.
This turned out to be wrong. One MUST explicitly remove SSLv3 from the list of supported protocols!
SSLContext sslContext = SSLContexts.custom()
.useTLS() // Only this turned out to be not enough
.build();
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(
sslContext,
new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sf)
.build();
Update 2: As of version 4.3.6 HttpClient disables all versions of SSL (including SSLv3) by default.
You MUST disable SSL v3.0 on java clients if you use https.
This can be done by adding this property on java 6/7:
-Dhttps.protocols="TLSv1"
And for Java 8 :
-Dhttps.protocols="TLSv1,TLSv1.1,TLSv1.2"
-Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
Source :
http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html
Apache HttpClient 4.3.6 disables SSLv3 by default.
Here's an excerpt from Apache HC 4.3.6 release notes
Release 4.3.6
HttpClient 4.3.6 (GA) is a maintenance release that fixes several
problems with HttpClient OSGi bundle as well as some other issues
reported since release 4.3.5.
Please note that as of this release HttpClient disables all versions
of SSL (including SSLv3) in favor of the TLS protocol by default.
Those users who wish to continue using SSLv3 need to explicitly
enable support for it.
Users of all HttpClient versions are advised to upgrade.
Changelog:
SSLv3 protocol is disabled by default Contributed by Oleg Kalnichevski
Update: If you are running on JVM having version >= Java 1.8 Update 31 SSLv3 is disabled by default.Check out the release notes
After spending considerable time trying to figure out why TLSv1.2 was being used despite setting -Dhttps.protocols="TLSv1" we finally found this post.
The magic flag is indeed -Djdk.tls.client.protocols="TLSv1" and our Apache Axis 1.4 client works again.
So in case you move from Java 7 to Java 8 you may need to add this flag as pre JAVA 8 used TLSv1 as default whereas JAVA 8 uses TLSv1.2
Thanks!

HttpClient supporting multiple TLS protocols

We're writing an app that must communicate with a few servers using HTTPS.
It needs to communicate with AWS (using the AWS libraries) and also with some of our internal services that use TLS 1.2.
I started off by changing my HttpClient to use a TLS 1.2 SSLContext:
public static SchemeRegistry buildSchemeRegistry() throws Exception {
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(createKeyManager(), createTrustManager(), new SecureRandom());
final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(sslContext)));
return schemeRegistry;
}
and injecting this SchemeRegistry into the DefaultHttpClient object (via spring), but doing that I get errors from AWS and so I assume (I may be wrong) that AWS doesn't support TLS 1.2 (I don't get this message if I just use the normal DefaultHttpClient):
AmazonServiceException: Status Code: 403, AWS Service: AmazonSimpleDB, AWS Request ID: 5d91d65f-7158-91b6-431d-56e1c76a844c, AWS Error Code: InvalidClientTokenId, AWS Error Message: The AWS Access Key Id you provided does not exist in our records.
If I try to have two HttpClients defined in spring, one that uses TLS 1.2 and one that is the default, I get the following error, which I assume means that Spring doesn't like instantiating and autowiring two HttpClient objects:
SEVERE: Servlet /my-refsvc threw load() exception
java.lang.NullPointerException
at com.company.project.refsvc.base.HttpsClientFactory.<clinit>(BentoHttpsClientFactory.java:25)
...
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031)
at
...
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
I haven't used HTTPS much in java so could you kind people give me some advice please?
1) How would I get Spring to allow two HttpClient objects and for one to be wired to the AWS stuff beans and the other to be wired to the other beans for accessing the TLS1.2 services
2) Or is it possible to change the one HttpClient object to be able to try TLS1.2 (via SSLContext, or the SchemeRegistry or something) and if that fails then try TLS1.1 or 1.0?
3) If both are possible, what would be the 'better' way of doing it?
TLS has an in-built mechanism to negotiate which version of the protocol is to be used. From RFC 5246 (Appendix E):
TLS versions 1.0, 1.1, and 1.2, and SSL 3.0 are very similar, and
use compatible ClientHello messages; thus, supporting all of them
is relatively easy. Similarly, servers can easily handle clients
trying to use future versions of TLS as long as the ClientHello
format remains compatible, and the client supports the highest
protocol version available in the server.
A TLS 1.2 client who wishes to negotiate with such older servers
will send a normal TLS 1.2 ClientHello, containing { 3, 3 } (TLS
1.2) in ClientHello.client_version. If the server does not support this version, it will respond with a ServerHello containing an
older version number. If the client agrees to use this version,
the negotiation will proceed as appropriate for the negotiated
protocol.
In addition, changing the version number in SSLContext.getInstance(...) only changes which protocols are enabled by default. Setting the actual protocol versions is done with SSLSocket.setEnabledProtocols(...) (see this question). I'm not sure about the rest of the libraries you're using, but it's possible that it sets the enabled protocols somewhere.
There are a few possibilities:
What you're doing in your createKeyManager() differs from the default behaviour. If the service is using client-certificate authentication, bad configuration there would certainly lead to a 403 error.
(Less likely, I guess, but hard to say without seeing your createKeyManager() and createTrustManager()). Perhaps the server you're using isn't compatible with TLS 1.2 and the version negotiation mechanism. There is this comment in sun.security.ssl.SSLContextImpl:
SSL/TLS protocols specify the forward compatibility and version
roll-back attack protections, however, a number of SSL/TLS server
vendors did not implement these aspects properly, and some current
SSL/TLS servers may refuse to talk to a TLS 1.1 or later client.

Categories

Resources