In order to secure my Thrift server against the recently discovered SSLv3 vulnerability, I explicitly stated which protocols should be enabled for the server socket:
TServerSocket socket = TSSLTransportFactory.getServerSocket(...);
SSLServerSocket sslServerSocket = (SSLServerSocket) socket.getServerSocket;
sslServerSocket.setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
However, even though a check using the TestSSLServer lists only TLSv1.1 and TLSv1.2, I'm still able to connect with OpenSSL using SSLv3:
openssl s_client -connect localhost:1111 -ssl3
How can I entirely disable SSLv3 on Thrift, so it fails during the SSL handshake already?
It seems I misinterpreted the openssl client output. Even though there is CONNECTED(00000003) on the first line, the error message follows:
140535757866656:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number:s3_pkt.c:337:
It is, therefore, not possible to connect to the server; the code snippet presented in the question works fine.
Related
I have simple HTTPS server and simple client for it.
The server is using keystore with self-signed certificate. The client also added this certificate to its cacerts truststore.
I am supposed to write tests that the communication between the client and the server can be done using different versions of TLS.
Are the acceptable TLS versions something that I should be setting up on the server side, or the client side, or both? Any advices are appreciated!
I am using the Bot Connector REST API and am having trouble with the Kik channel. When I try to respond to a message, I am receiving this error:
javax.net.ssl.SSLException: hostname in certificate didn't match: <kik.botframework.com> != <*.azurewebsites.net> OR <*.azurewebsites.net> OR <*.scm.azurewebsites.net> OR <*.azure-mobile.net> OR <*.scm.azure-mobile.net>
The service URL I am using is "https://kik.botframework.com".
I am running this off of a local server at the moment. I did not have any trouble connecting with the Skype channel in this configuration, but Kik is giving me trouble.
I don't exactly have a solution, but I can explain what is the reason behind this and what you may have to double check on your side.
So, in short, this is happening because of SNI (Server Name Indication) and because of the client's inability to support SNI.
Check this answer for some insight into this issue https://serverfault.com/questions/594368/openssl-returns-different-ssl-certificate-to-that-shown-by-chrome
In this case, the same IP is hosting a bunch of domains and certificates. Most of the modern browsers support SNI and will be able to detect this and show you the right certificate (try firefox).
However, when the SSL client of a server is trying to do a handshake (without specifying 'server name'/'host name') it doesn't know which certificate to fetch, and hence fetches the core certificate.
Solution?
The client should 'indicate' that this is the host name and then it'll fetch the right certificate.
Example:
openssl s_client -connect dev.botframework.com:443
VS
openssl s_client -servername dev.botframework.com -connect dev.botframework.com:443
How to Solve this?
Skip the host name verification phase. Disabling SSL Certificate Validation in Spring RestTemplate or another Example:
Registry<ConnectionSocketFactory> registry = RegistryBuilder. <ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", new SSLConnectionSocketFactory(SSLContexts.createDefault(), new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})).build();
The problem ended up being that the version of the HttpClient library being used my server is fairly old (4.2.5) and did not support Server Name Indication. I was able to patch it to support SNI as per here: Server Name Indication (SNI) Support. Thanks to Arka for pointing out what the issue likely was.
I have a Java program that connects to a webserver using SSL/TLS, and sends various HTTP requests over that connection. The server is localhost and is using a self-signed cert, but my code is using custom TrustManagers, and ignores invalid certificates. It has worked perfectly until now.
The only difference on the server is that it used to run jboss 6 and is now running jboss 7. I'm not sure if this is a configuration issue, or whether there is a problem with my code, but I get the same errors if I try to connect using other Java-based programs like WebScarab or ZAP.
In any case, is there anything I can do to my code to get around this problem? Here is the error in full:
Received fatal alert: handshake_failure
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(Unknown Source)
Here are the debug messages before the failure:
main, WRITE: TLSv1 Handshake, length = 75
main, WRITE: SSLv2 client hello message, length = 101
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
So I found the problem. There might be a bug in Java, but the client seems to initiate a TLSv1 Handshake, but then sends an SSLv2 client hello message, at which point the server rejects the connection.
This happens even if you create your SSLContext with an instance of TLS:
SSLContext sslContext = SSLContext.getInstance("TLS");
The solution is to set a system property before any connection attempts are made:
System.setProperty("https.protocols", "TLSv1");
There are probably other solutions to it, but this one worked for me.
The info you provide is very little as well as your stack trace.
I'll take a guess here.
What I suspect is that in the new server the protocol is TLSv1 while your clients try to connect with SSLv3 (or less) and as a result the handshake fails.
Change you clients to use higher version of TLS
or
Make your webserver support SSLv3 as well. I know how to do this in Tomcat but not in JBoss.
If this doesn't work update the post with more info (and a full stack trace).
You should enable ssl debug info -Djavax.net.debug=ssl
Was this ever resolved?
I had the exact same problem, essentially I was receiving a handshake exception immediately following the clientHello. So The chain of events was
I would present my certificate to the server
Server would imediately respond with a handshake failure. (I would not even get a Server Hello back).
Eventually I found that the server was requiring a stronger encryption/decryption algorithm than what I Was supplying in the initial handshake phase (Ie. Client and Server could not agree on a mutual encryption algorithm to use for the ssl communication).
I need to install the Unlimited Java JCE (Java Cryptography Extension Policy). There are export rules on using this, so if you ship your code overseas that may have implications..however this is what solved my problem.
This link explains how to install the updated policies
http://suhothayan.blogspot.com/2012/05/how-to-install-java-cryptography.html
This was also a great link that helped me understand exactly what was going on
https://support.f5.com/kb/en-us/solutions/public/15000/200/sol15292.html#id
This may or may not be the issue, but when the handshake fails immediately after the client Hello, it looks like the client and the server can not agree on something (in many cases its the encryption algorithms that they will mutually need to communicate).
You are seeing this error most probably because the keystore that your JBoss 6 had access to is not accessible to your JBoss 7 instance.
What I would recommend is the following.
Your self-signed server certificate must be imported into a truststore
keytool -import -alias gridserver -file server.crt -storepass $YOUR_PASSWORD_HERE -keystore server.keystore
Add the following properties to your run.conf
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=server.keystore
-Djavax.net.debug=ssl # very verbose debug. Turn this off after everything looks good.
-Djavax.net.ssl.keyStorePassword=$YOUR_PASSWORD_HERE
-Djavax.net.ssl.trustStorePassword=$YOUR_PASSWORD_HERE
The stack trace is from you client code and your client 'Received [a] fatal alert'. In other words, the SSL error happened in Jboss, not your client.
Your client side custom TrustManagers have therefore nothing to do with it. My wild guess is that your new Jboss 7 is configured to require client certificate and your client did not present any.
To debug your SSL connection, use openssl and try this:
openssl s_client -connect jboss.server.com:443
or is it is an SSLV3 server
openssl s_client -connect jboss.server.com:443 -ssl3
This should print a lot of interesting information.
I think this is related to a Java 7 bug. It is hard to be sure without more details.
For me solution was : System.setProperty("https.protocols", "TLSv1.1,TLSv1.2");
Is it possible to send sslv2 hello messages?? When I try initiating ssl handshake with a remote server, the default version is TLS. I need to test if the serve accepts sslv2, therefore, I need to force my Java program to send sslv2 hello message. Is this possible? How? Please note that I need to this for testing only. I am not doing a real Java application.
Sun/Oracle Java has never supported SSLv2. It did support the SSLv2ClientHello message, for compatibility purposes, to negotiate SSLv3 or higher, but that was withdrawn in I think 1.7. IBM Java used to support SSLv2 but I can't speak for current versions.
SSLV2 is not supported, if you need to force SSLv2Hello messages you can set a system property :
System.setProperty("https.protocols", "SSLv3,SSLv2Hello");
Or you can manage your sockets directly :
SSLContext context = SSLContext.getInstance("TLSv1");
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sock = (SSLSocket) sslsocketfactory.createSocket("hostserver", 443);
String[] protocols = {"SSLv2Hello", "SSLv3", "TLSv1"};
I have a client written in C# and server in JAVA. So, when I'm trying to connect I got error in server javax.net.ssl.SSLHandshakeException: no cipher suites in common and in C# "EOF or 0 bytes".
[C#]:
TcpClient tc = new TcpClient(server, 1337);
using (sslStream = new SslStream(tc.GetStream())){ }
[JAVA]:
SSLServerSocketFactory ssocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket server = (SSLServerSocket) ssocketFactory.createServerSocket(1337);
server.setEnabledCipherSuites(server.getEnabledCipherSuites());
And JAVA launch properties:
-Djavax.net.ssl.trustStore=Certificatename -Djavax.net.ssl.trustStorePassword=thereisapw -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol -Djavax.net.debug=ssl TCPServer
The truststore defines how you're going to trust remote certificates that are presented to you. The keystore is for the certificates you have (and for which you have the private key). (More details about the difference here. The terminology about "keystore" can be confusing, since it can have two meanings).
Here, you're trying to run a server, but you haven't set up your own certificate. You need to import/create a certificate in a keystore and use it as a keystore.
If you don't specify a keystore, the server won't be able to find a cert/key. As a result, it won't be able to use any of the cipher suites enabled by default.
I'm not sure where you got this from, but you don't need it: -Djava.protocol.handler.pkgs=com.sun.net.ssl.internal.www.protocol