As per the firm's policy we are required to encrypt communication channels b/w our client processes with MQ server. In our distributed system, we have a few Java processes required to establish connection with MQ. Let me say, process A and B.
A and B run on different virtual machines. They have EXACTLY the same environment including JRE of same version(1.8.0_151-b12), same dependencies, same JCE extension files. We added ssl related JVM parameters to the launching scripts of each process, such as
-Djavax.net.ssl.trustStore
-Djavax.net.ssl.trustStorePassword
-Djavax.net.ssl.keyStore
-Djavax.net.ssl.keyStorePassword
the corresponding trustStore and keyStore files are in place and properly referred to.
A works fine and we observed the SSL handshake and encrypted messages. However, process B failed with messages such as:
ignoring unavailable cipher TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
...
Caused by: java.lang.IllegalArgumentException: Cannot support
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA with currently installed providers
I did spend time checking online and one relevant post is from here : it suggested downloading and upgrading JCE files - the thing is that I already have JCE files (unlimited) installed and those are the same for both processes. I don't think JCE files is the root of the problem.
My question is, does the MQ team also have to install JCE files as well, in order for the client to establish SSL connection? Is the configuration on my end completed, anything I might have missed?
Update: problem solved. See my comments below.
Unlimited Strength Jurisdiction Policy Files were not included and enabled (crypto.policy set to unlimited) by default until 1.8.0_162. At 1.8.0_151 Unlimited Strength Jurisdiction Policy Files were included but not enabled.
Please check that you in fact running Java 1.8.0_151-b12 on both VMs, if you are then make sure the java security file crypto.policy setting on the working VM is identical to the non-working VM.
Related
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.
I have two laptops running the same project on them. Both instances are configured to use Java JDK 6 (same minor version). However one machine is not able to connect to a remote REST service. By running applications with -Djavax.net.debug=all option I came to the conclusion that the issue is with the ClientKeyExchange step as this step does not happen on the problematic laptop.
A post in the IBM developer community suggests that "hardware crypto device being used is not on the supported list". However I have no understanding about "hardware crypto devices".
What I can tell is that "enabled cipher suites", "excluded cipher suites", "cipher suites have been set to" lists printed by means of -Djavax.net.debug=all are the same on both machines.
Using JDK cacerts.
Found the solution. Project is using JAX-RS so calls to external service happened through that framework and because of that I could not dig to the problem since there were no errors. So I tried different approach: tried to access the service by using simple javax.net.ssl.HttpsURLConnection which showed me java.lang.NoClassDefFoundError: Could not initialize class javax.crypto.SunJCE_b and therefore I changed my local_policy.jar and US_export_policy.jar files (thanks to #Charlie Could not initialize class javax.crypto.SunJCE_b)
I think I had changed policy jars on first laptop and forgot to do this on the new laptop.
I have built a JAVA web application which uses SOAP to fetch data from an external database server. This works fine until a few days ago. Now, the connection to the database server is terminated while establishing them.
In my JAVA log file, I found the following sequence of exceptions:
javax.net.ssl.SSLException: Server key
at sun.security.ssl.Handshaker.throwSSLException(Handshaker.java:1260)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:283)
...
Caused by: java.security.spec.InvalidKeySpecException: Unknown KeySpec type: java.security.spec.ECPublicKeySpec
at org.bouncycastle.jce.provider.asymmetric.ec.KeyFactory.engineGeneratePublic(Unknown Source)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
Maybe the provider of the database server has changed their SSL certificate and got another CA chain.
I noticed that the intermediate CA use SHA384withRSA as signature algorithm. (see COMODO, Domain Validation (SHA-2)).
So, what can I do to to make my system running again?
Please ask, if you need further information.
Remark: The same SOAP request from a Windows 7 client works fine. There I noticed, that the Windows 7 client uses TLSv1.2 to establish the SSL connection. The Linux system of my server (see below) uses TLSv1 ,
The configuration of my Java WebServer:
Debian Wheezy
Java: OpenJDK 1.7.0u111
Tomcat 7.0.28
https connector uses JSSE with sslProtocol="TLS"
BIRT Runtime V4.5.0
DTP V1.12.0
org.eclipse.datatools.enablement.oda.ws V1.2.6
Thanks
Friedbert
Solved!
Apparently, the configuration of the tomcat connector did no longer match current security standards.
I had set up the system 2 years ago. But the security requirements have increased in the meantime.
Now I took a recent appliance from turnkey, compared the settings and found a few differences:
JAVA: java.security
security.provider.10=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/nss.cfg
Tomcat7: server.xml /Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
sslProtocol="TLSv1.2" sslEnabledProtocols="TLSv1.2,TLSv1.1,TLSv1"
server="Secret" URIEncoding="UTF-8" (may be, these does not matter)
With these changes, my system works again!
(Disclaimer: I am by no stretch of the imagination a security expert nor a windows expert for that matter)
Setup:
server on our end: java 1.6 (already added bouncycastle to the security file) on windows 2003 server
third party client: windows 2008 server with biztalk
all renegotiation system properties introduced due to the renegotiation attack are "enabled" on the server side (not safe I know)
Ideally we want to fix this at our end but it is possible to propose a fix to the client if necessary.
The client server has to connect to our server over a HTTPS connection but it always fails, wireshark shows the following conversation:
> TLSv1: Client Hello
< TLSv1: Alert (21): Unexpected Message
As per the RFC (http://www.ietf.org/rfc/rfc2246.txt) the alert(21) refers to a failed decryption and from what I can see in wireshark, none of the ciphers proposed by the client are actually supported by JRE 1.6 (as per http://docs.oracle.com/javase/6/docs/technotes/guides/security/SunProviders.html#SupportedCipherSuites)
In an effort to reproduce the error to be able to examine it closer, I tested with some other software:
wfetch on windows xp with "https" selected will perform the initial client handshake in SSLv2, the server will switch to TLSv1 to answer, this works
wfetch on windows xp with configured to use "TLSv1" for the initial handshake will fail in the same way as the biztalk server
wfetch on windows 2008 with configured "https" will use "TLSv1" for the initial handshake and fail in the same way as the biztalk server
IE (on windows xp) will initially try a TLSv1 handshake with the same failed result but immediately tries again using SSLv3 which works
(at this point I figure all microsoft software uses a central configuration available at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel)
firefox uses SSLv3 for the entire conversation, so no problem there
OpenSSL performs an initial handshake in SSLv2, and the server switches to TLSv1 when it answers, no problem there
OpenSSL can be forced to do the initial handshake in TLSv1 as well, it offers a list of 27 ciphers (as opposed to the 11 ciphers proposed by windows-based software) and can connect without a problem
To my untrained eye this reinforces the idea that an incompatible cipher proposition is the root cause where windows only supports cipher suites that are not supported by JVM (for TLSv1).
I have installed bouncy castle as an additional provider in the java.security file to no avail.
I have searched high and low and only found a reference that maybe websphere supports the windows ciphers for TLSv1 but no way of downloading a standalone provider to test it.
JRE 1.7 is not supported by the software we run on our JVM, so upgrading is not an option (perhaps the security provider can be downgraded safely? I haven't found a download for it yet though)
I have found no way to add a cipher to windows short of writing c++ code (I've played around with the above mentioned registry settings without effect).
So in conclusion I wonder if one of the following things would fix it and how they should be accomplished:
add a provider to the jvm that can work with the ciphers for TLSv1 that are proposed by windows
somehow force the client to do the initial handshake in SSLv3 (preferably not SSLv2) or at least retry if the TLSv1 handshake fails
somehow add a JVM-supported cipher for TLSv1 to the client windows
Any other solutions are of course also appreciated.
EDIT
The Java version is Java version (64 bit): 1.6.0_19-b04.
The list of proposed ciphers is:
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
TLS_RSA_EXPORT_WITH_RC4_40_MD5
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
The unlimited strength cryptography policy files are installed. I have tried to set javax.net.debug=all and started the server from the console, no additional output appeared. I have set sun.security.ssl.allowUnsafeRenegotiation=true to no avail.
EDIT 2
It turns out the software we are using uses a custom stack for HTTPs instead of the default. A fix was issued which seems to solve the problem though I don't know exactly which part of the TLS request triggered the error (seeing as most TLSv1 handshakes did succeed).
Thanks for the feedback, it has been an interesting if futile search. Live and learn.
It turns out the software we are using uses a custom stack for HTTPs instead of the default. A fix was issued which seems to solve the problem though I don't know exactly which part of the TLS request triggered the error (seeing as most TLSv1 handshakes did succeed).
Thanks for the feedback, it has been an interesting if futile search. Live and learn.
You could read my article on detecting cipher strength (just to make sure you installed the jce ciphers correctly) . In your question you say you installed unlimited ciphers but then you reference 128 and 40-bit keys. So, I am confused by what you have. Also, could you check the cipher strength on the SSL cert you are trying to connect to and let us know what it is and what the algorithm is? Also, make sure your policy file for JDK has the proper rights to allow unlimited strength.
Finally, can you connect to a "known good" SSL site to verify your client handshakes correctly? (Gmail web for example)
I have a webapp that sends a SOAP request to a 3rd party server. When the request is made on my local computer it works without a problem, but when I deploy my application to my server I get an error with the following causes:
com.sun.xml.messaging.saaj.SOAPExceptionImpl: java.security.PrivilegedActionException: com.sun.xml.messaging.saaj.SOAPExceptionImpl: Message send failed
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: algorithm check failed: MD2withRSA is disabled
I've searched around but I can't find anything relevant to my situation. It's probably worth noting that the request I'm making is to an https url. My computer is running Windows XP and the server is running Slackware Linux. Any ideas what might be causing the server to reject the request?
Check your Java versions on your local machine, and your server.
From here, it seems the jvm 6u17 disabled MD2 as it is insecure, and whatever you connect to is using MD2
MD2withRSA is highly vulnerable and therefore deactivated in Sun... aeh Oracle's JVM. You should ask the owner of the remote service, whether his server supports more secure encryption methods (I think, older Apache HTTPd versions do offer MD2withRSA by default...). In order to resolve this problem without forcing the provider to change the method, you may use your own implementation of the X509TrustManager that accepts the old method.
A Google search on "MD2withRSA" showed this URL as the first hit, that seems to point to a change in a certain Java version. Probably the verasiuons on your local computer and the server do not match.
Newer Java 7 (version 1.7) allows re-enabling MD2 via $JAVA_HOME/jre/lib/security/java.security file. Download and install Java 7 and modify java.security file in text editor as follows
1) Remove MD2 from following property
jdk.certpath.disabledAlgorithms= # MD2
2) Ensure following property is commented out
# jdk.tls.disabledAlgorithms=MD5, SHA1, DSA, RSA keySize < 2048
3) Restart java application
Warning: MD2 is disabled by default in Jdk 7 because it is insecure. However, it can be enabled as described above to support older deployments.