I am using a Java based Web Server ( PlayFramework 2.2 FWIW - see the very good write up on TLS ), and I want to debug the SSL communication for various devices, eg: Android, to see exactly what is happening on the wire as far as TLS goes. For this I can use Wireshark to decrypt the SSL layer. This works if the server does not create an Ephemeral key, as explained nicely by Steven Iveson:
Important: Ensure the use of a Diffie-Hellman Ephemeral (DHE/EDH) or
RSA Ephemeral cipher suite is not negotiated between the two hosts.
This is indicated by the use of a ServerKeyExchange message. There is
no way to decrypt data where ephemeral ciphers are used.
The Java Secure Sockets Extension Reference Guide section on how to Disable Algorithms points to the jdk.tls.disabledAlgorithms property which I have tried setting directly in the $JAVA_HOME/jre/lib/security/java.security file to
jdk.tls.disabledAlgorithms=DH, ECDH, EDCHE, DiffieHellman
I tried using some of the Java™ Cryptography Architecture
Standard Algorithm Name Documentation as an attempt to select one of those strings, but I have been selecting a bit in the wild.
I tried setting it also using it in code to
java.security.Security.setProperty("jdk.tls.disabledAlgorithms","ECDH, ECDHE, ECDHE_RSA, DiffieHellman")
but that does not seem to stop the the appearance of the ServerKeyExchange messages, as shown in the screenshot of Wireshark 1.11.2 on OSX: . And indeed I don't seem to be able to decrypt the stream.
Any idea what I may be doing wrong?
Not sure if this will help, but try doing it inside a privileged block:
AccessController.doPrivileged(
new PrivilegedExceptionAction[Unit]() {
java.security.Security.setProperty("jdk.tls.disabledAlgorithms","ECDH, ECDHE, ECDHE_RSA, DiffieHellman")
}
)
I was close. The answer seems to be to set the security property as follows:
jdk.tls.disabledAlgorithms=DHE, ECDHE
(I came on that after reading the hot-off-the-press blog post: JDK 8 will use TLS 1.2 as default).
Once that is set on the server, an https connection captured by Wireshark no longer shows the Server Key Exchange message.
It is then possible to decrypt content that went over the wire as shown by this image
I hope this will be useful when trying to analyse what Android cell phones are receiving over the wire.
Related
I have an SSL client certificate. It was working with my app up until one of the Java updates happened at some point in the recent past (maybe as far back as a year). It works with web browsers. It works with curl.
For example, I can do this and it is fine:
curl --cert example.pem https://example.net
Now I cannot get this cert to work with Java. I've gone as far as trying a very minimal app, like SSLPoke from https://gist.github.com/4ndrej/4547029
Putting the cert into the client certs from ControlPanel doesn't do it.
Importing the .pem into a keystore and then pointing at that keystore with -Djavax.net.ssl.trustStore or .keystore doesn't do it.
All I get out of Java is:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
So I can't figure out what is wrong - the way I'm invoking Java? The place I'm putting the certificate? The way I've imported the certificate?
The debug output using -Djava.security.debug=all does not show it using the trustStore/keyStore I specify. It doesn't even show anything about the URL I'm trying to reach.
I'm out of ideas.
Your server is likely using an outdated SSL protocol, that Java is no longer allowing, by default, for security reasons.
Try running Java with this option (e.g. needed for older SQL Server instances):
-Djsse.enableCBCProtection=false
If that doesn't work, maybe the server is using SSLv3, so see this SO question for How to enable SSL 3 in Java.
If any of those work, they are workarounds need to downgrade the SSL security, so you are strongly encouraged to upgrade the server instead, and remove these workarounds again.
In the company that I work we have a server GF 3.1.1 (JDK 6) with CAS which does the authentication of the users in another system. After the last update of Firefox (v. 39x) we are getting the follow information from the browser:
mydomain.com SSL received a weak ephemeral Diffie-Hellman key in
Server Key Exchange handshake message.
And it is not possible to access the site without this workaround or using another browser.
In chrome I can access normally but if I look at the connection properties it says:
Your connection is encrypted with obsolete cryptography.
The connection uses TLS 1.0.
The connection is encrypted using
AES_128_CBC, with SHA1 for message authentication an DHE_RSA as the
key exchange mechanism.
I can't configure all the browsers of our customers or say them only use chrome. Maybe in future chrome can do the same. So my solution is configure the server properly. The problem is that I don't know how can I do that.
I found in GF where I can do the configuration in Configurations > server-config > Network Config > Protocols > http-listner-2 > SSL
Then I found here a blacklist and a whitelist of some ciphers that are recommended to use. I tried to remove all in black and put all those in white. But I still have the issue. I think this list may be out of date.
I appreciate any help.
Finally. I found a solution.
I search a lot and I could find a solution, so I tried to test one by one of the ciphers. So, to work ( I am not saying that is the right way). I had to do this:
At:
Configurations > server-config > Network Config > Protocols > http-listner-2 > SSL
Add all the ciphers available
Remove all the Diffie-Hellman ciphers
Save
After that our application can be opened at any browser again. I hope it may help someone.
For admin:
Configurations > server-config > Service HTTP > Listeners HTTP > admin-listner > SSL
Add all the ciphers available
Remove all the Diffie-Hellman ciphers
Save
Restart
Edit: Comparing with the whitelist here the remaining ciphers that would be part of a new whitelist are:
Whitelist
TLS_RSA_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
I just encountered this problem as well with Chrome and the admin console. The way I got around it was to delete the current ssl certificate for the listener and recreate it using a specific set of ciphers with the --ssl3tlsciphers option. For me it was the admin-listener so first I deleted the current default certificate:
asadmin delete-ssl --type http-listener admin-listener
Then I recreated it using the following command:
asadmin create-ssl --type http-listener --certname s1as --ssl3tlsciphers SSL_RSA_WITH_RC4_128_MD5,SSL_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_DES_CBC_SHA,SSL_RSA_EXPORT_WITH_RC4_40_MD5,SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,TLS_EMPTY_RENEGOTIATION_INFO_SCSV,SSL_RSA_WITH_NULL_MD5,SSL_RSA_WITH_NULL_SHA,SSL_DH_anon_WITH_RC4_128_MD5,TLS_DH_anon_WITH_AES_128_CBC_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,SSL_DH_anon_WITH_DES_CBC_SHA,SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA admin-listener
I noticed that simply deleting the default certificate doesn't remove all references to it in the domain.xml file. I haven't been able to find the proper way to do this. I just used trial and error. Another method is to modify the domain.xml file where the ssl element for the listener is defined and add the attribute "ssl3-tls-ciphers":
<ssl ssl3-tls-ciphers="SSL_RSA_WITH_RC4_128_MD5,SSL_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_DES_CBC_SHA,SSL_RSA_EXPORT_WITH_RC4_40_MD5,SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,TLS_EMPTY_RENEGOTIATION_INFO_SCSV,SSL_RSA_WITH_NULL_MD5,SSL_RSA_WITH_NULL_SHA,SSL_DH_anon_WITH_RC4_128_MD5,TLS_DH_anon_WITH_AES_128_CBC_SHA,SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,SSL_DH_anon_WITH_DES_CBC_SHA,SSL_DH_anon_EXPORT_WITH_RC4_40_MD5,SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA" classname="com.sun.enterprise.security.ssl.GlassfishSSLImpl" cert-nickname="s1as"></ssl>
Both methods require a restart of glassfish.
Thanks, Sertage, that worked!
However, it is also necessary to fix the Protocol for the admin port (usually 4848). (It should, of course, use HTTPS too!)
But, in GF 3.1.2.2, the Protocol 'admin-listener' appears to be kind of pointing to the Protocol 'sec-admin-listener', and that does not have a 'SSL' tab. Changing the SSL parameters the Protocol 'admin-listener' results in an error message, saying 'Could not apply changes. No Configuration found for configs.config.server-config.network-config.protocols.protocol.admin-listener.ssl'. Any suggestions on how to configure the admin port?
After a server change, I get nasty SSL warning in browsers (tested FF & Chrome), when loading an applet, used in an JavaEE Application (Serlvet API 3)
The warning says: "Certificate is not valid, and cannot used to identify the website"
The more detailed warning says: "The certificate authority, who provided the certificate, is not trusted." The messages are translated into english, so please excuse slight differences there. After this message, I get the message of Java, which shows that the Applet is ordinary signed (the dialog with the blue sign). So the Applet is working, only the warning message annoys.
Before I moved to another server, everything was fine and worked. No security warnings or anything else. The Applet is signed, by a certificate, which I requested from an CA. (rapidssl)
The old server environment was just a common web space, offered by 3rd party hoster. Now I moved to my own server, which utilizes XEN for hosting VMs. On one of that internal vm's, our webserver is deployed. According to that, I defined firewall rules to route traffic http/https to the vms.
Also the domain was ported, was purchased at old hoster, and the ip of new server is bound to domain.
I use Tomcat 7 as Application Server on an debian based OS.
In old environment, I could use the specified url in CN of my wildcard cert.(e.g. *.domain.com)
In new environment the basic message says: *.domain.com:port is not a trusted site.
I thought actually, that SSL Certs are independent of the used port. I've read that, on some research too. I also searched here in many threads, but the supposed answers didnt work for me.
The certificate and root cert. are imported to Java's own keystore cacerts. In Tomcat 7, I use the JSSE Implementation for SSL, with properly setup keystore files.
I've tried already this, but as im not that experienced with SSL/TLS Technology, the tried solutions maybe even wont solve my problem:
Disabling SNI in Tomcat 7 (dont work)
Adding Host aliases in server.xml (dont work)
Can anyone clarify, what the actual problem is, or has experienced the same issue ?
#edit: The are no error stacktraces in any logs, which I could provide here, also no exceptions gets thrown.
It came clear, thanks to Khanna111 Gaurav Khanna and jwv, that the certificate chain wasnt setup properly. I thought, if there were any problems with the certificate chain, that the browser will notify me about it. It isn't like that.
As we migrated from old hoster to new server, they provided only the certificates, but without the private key.
As im not that much experinced with SSL, I thought that importing the intermediary certs and the acquired cert is enough.. It is not :)
After stumbling on
intermediate-ca-certificate-in-java (link in comment), I've read this, which solved my problem: why doesn't java send the client certificate during SSL handshake? & external website:Import private key and certificate into Java Key Store (JKS)
I had certkey.key,publiccert.crt, intermediate_primary.cer and secondary_primary.cer Files.
The first step was, to convert the .key and .crt file to DER format, as mentioned in last link
via OpenSSL due to keytool's inability to import a key in an existing keystore
After converting to DER Format, I used the Tool ImportKey and created a new keystore with key/cert contained.
The second step was following the instructions of second link (Bruno's Answer), so it was copy&paste the certificate contents, into a single file. After importing the bundle of certificates into keystore, everything was fine.
I hope this can help anyone else, which is also not that familiar with SSL.
p.s. due to my lack of rep, i cannot mention all sites, I've used.. I'll provide them in comments
Hi I am trying out a simple java http server NanoHTTPD: http://elonen.iki.fi/code/nanohttpd/
Today I try to support it with HTTPS, so I create SSLServerSocket in its NanoHTTPD constructor:
// myServerSocket = new ServerSocket(myTcpPort);
myServerSocket = SSLServerSocketFactory.getDefault().createServerSocket(myTcpPort);
and also supplied javax.net.ssl.keyStore with 2048 bit RSA key
The result is that https connections succeed on MSIE6.0, MSIE8.0, Firefox 9.0.1
However fail on Google Chrome 17.0.963.56 m and Firefox 10.0.1:
from debugging, NanoHTTPD.HTTPSession.decodeHeader method gets only String inLine = "G" barely one single char, while normally here you will expect the standard http header "GET / HTTP/1.1".
So anybody familiar with Firefox could tell what's different in 9.0.1 and 10.0.1 regarding https / ssl? Something made by browsers may be the point. (Of course I am newbie in java ssl programming, please tell me if I am wrong in SSLServerSocket).
I have cross posted this issue:
https://support.mozilla.org/en-US/questions/920116
Thank you all.
The short of it is that your SSL implementation is broken. SSL records can be split in arbitrary ways, and Google and Mozilla changed the way they split theirs to work around some MITM attacks on SSL. Specifically, a 1-byte SSL record is sent before sendinga second SSL record with the rest of the data. It sounds like your SSL implementation is only reading the first record instead of reading all the data.
See http://rt.openssl.org/Ticket/Display.html?id=2635&user=guest&pass=guest and https://bugzilla.mozilla.org/show_bug.cgi?id=665814 and articles like http://www.livehacking.com/2011/10/27/chrome-15-broke-the-wall-street-journal-while-trying-to-beat-the-beast/
I can confirm the SSLEngine from java appears broken by default. The way I can get around it is:
^Cpck0:bin vladimirralev$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-ssl-false-start --use-spdy=off --use-system-ssl
That turns off the weird TLS modes.
It looks like recent SSLEngine will behave correctly if you keep following the instructions it gives you to read a segmented packets. You have to loop through multiple reads (with some intermittent states in between) and you will have the complete chunk eventually.
(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)