I am using Netty as backend in a Java-based Usenet client. The library is working fine, however, in some circumstances I can't connect to a remote server via SSL, because of exactly this error:
Java: Why does SSL handshake give 'Could not generate DH keypair' exception?
Unfortunately, it seems that for whatever reason this Java error still has not been fixed yet. And since the remote server is not under my control, I need a workaround here. One such "solution", according to the link above, is to avoid DH during SSL handshake at all (not very pretty, but maybe better than nothing).
However, I am no SSL expert, so I am not really sure how I can implement that within Netty; or better: within my solution that is based on Netty. By now I am creating connections as this:
// configure the Netty client
ClientBootstrap bootstrap = new ClientBootstrap(clSockChannelFactory);
// configure the pipeline factory
bootstrap.setPipelineFactory(channelPipelineFactory);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
bootstrap.setOption("child.receiveBufferSizePredictorFactory",
new AdaptiveReceiveBufferSizePredictorFactory());
// start the connection attempt
InetSocketAddress isa = new InetSocketAddress(serverAddress, port);
ChannelFuture future = bootstrap.connect(isa);
...
channel = future.getChannel();
...
Ok, that's fine, but where can I disable cipher suites before I connect the SSL socket, as desribed in the thread above?
Thanks in advance for all your help!
Kind regards, Matthias
PS: By the way, any ideas why this problem has not been addressed in Java yet?
I'm not familiar with Netty, but I would suggest following the approach in the secure chat example.
I'm not sure what default SSL/TLS keys/trust settings you have, but if you don't have a custom SSLContext, try SSLContext.getDefault().
Then, create an SSLEngine using SSLContext.createSSLEngine(). On this SSLEngine, you should be able to enable the cipher suites you want. Assuming you're using the Oracle JRE (or OpenJDK), you'll find the list of cipher suites in the Sun Provider documentation.
After this (this is the Netty-specific part), set an SslHandler using something like this (see Netty example):
pipeline.addLast("ssl", new SslHandler(engine));
Related
I am using io netty version 4.1.19.Final
I am trying to set up a client which will connect to a server using TLS.
I want the netty to perform hostname validation when it receives TLS certificates, but it looks like since I am using a custom trustManager using TLS Trust file path netty skips hostname validation completely.
Is there a way for me to specify a custom trustManager using TLS Trust file path AND have io netty perform hostname validation????
SslContextBuilder builder = SslContextBuilder.forClient();
File trustCertCollection = new File(conf.getTlsTrustCertsFilePath());
builder.trustManager(trustCertCollection);
Netty API:- https://netty.io/4.0/api/io/netty/handler/ssl/SslContextBuilder.html#trustManager-java.io.File-
Full code:-
https://github.com/apache/incubator-pulsar/blob/master/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConnectionPool.java#L97
Can you open a bug in the netty issue tracker and share some reproducer (best would a unit test)?
Unfortunately I'm completely new to SSL. Currently I'm trying to set up a secure connection between a client and a server application in Java and the following code works for me (transmitted data is encrypted), but I don't know if this is a correct and secure solution.
Client side:
socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port);
socket.setUseClientMode(true);
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
socket.startHandshake();
Server side:
sslServerSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(requestPort());
sslServerSocket.setUseClientMode(false);
sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites());
It is not advisable to enable all ciphers/protocols. Better that you enabled only the ciphers and protocols you want. If both server and server is written by you, choose what you want and configure only that.
socket.setEnabledCipherSuites(...);
socket.setEnabledProtocols(...);
Supported ciphers and protocols can be seen in JSSE documentation
Or you can use "jdk.tls.disabledAlgorithm" to control what algs you want to use.
In my project using grpc and java,I am using OpenSSL to make a secure connection between Client and server.
I am able to bring the grpc server up successfully.
The documentation here mentions that the client code for a secure channel is this
ManagedChannel channel = ManagedChannelBuilder.forAddress("myservice.example.com", 443)
.build();
GreeterGrpc.GreeterStub stub = GreeterGrpc.newStub(channel);
I am using the code at client as follows but the below exception is being thrown.
mChannel = ManagedChannelBuilder.forAddress(GrpcConstants.LOCAL_GRPC_CLIENT_IP, GrpcConstants.LOCAL_GRPC_CLIENT_PORT).build();
mEmployerServicesBlockingStub = EmployerServicesGrpc.newBlockingStub(mChannel);
mInviteContactsBlockingStub = InviteContactsGrpc.newBlockingStub(mChannel);
Exception:
Network channel closed
at io.grpc.Status.asRuntimeException(Status.java:431)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:157)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:106)
I tried with the following code also:
mChannel = NettyChannelBuilder.forAddress(GrpcConstants.LOCAL_GRPC_CLIENT_IP, GrpcConstants.LOCAL_GRPC_CLIENT_PORT).sslContext(GrpcSslContexts.forClient().trustManager(file).build()).build();
mEmployerServicesBlockingStub = EmployerServicesGrpc.newBlockingStub(mChannel);
mInviteContactsBlockingStub = InviteContactsGrpc.newBlockingStub(mChannel);
This is also giving the same exception as above. I just gave a null file reference here.
Please let me know which approach should be used for a GoDaddy certificate.
If it is the first approach, what am I missing.
If it is the second approach, which file am I supposed to use for "roots.pem".
Updated.
It looks like the exception is cut off a bit at the top. There may also be a causal exception ("Caused by:") that could be helpful. In either case, this may be similar to another issue, where gRPC "misses" the original error and is now just detecting later failures.
Both approaches to Channel creation should work. If you are using a reverse proxy, I would assume the problem is either the server not supporting AES GCM or ALPN (with HTTP/2). You can use https://www.ssllabs.com/ssltest/ to check for support. For example, Google supports both. If you are contacting a gRPC server directly, I would expect an issue initializing tcnative.
It is probably worth-while to create a GitHub issue to help us in tracking down the true cause.
Whenever I try to connect with SSL from an Android App to a Tcl server, the connection fails. Both systems seem to have a very long list of supported ciphers, but they name them quite differently, so I cannot really tell which is which.
the Tcl error message is:
SSL channel "sock7": error: no shared cipher
the Android error message is:
javax.net.ssl.SSLException: Connection closed by peer
Is there any hope to find a solution for this?
The Tcl code is:
package require tls
::tls::init -ssl2 0 -ssl3 1 -tls1 1 -require 0 -request 0
set mainSock [::tls::socket -server serve 1200]
The Android Code is:
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
SocketFactory sf = SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sf.createSocket("server.de", 1200);
Thanks everybody for help. I have figured it out with your answers.
It seems impossible to use Tcl as a server without any certificates. Not even another Tcl script can connect to the server without certificates. The client can leave out the validity checking, but the server must provide a certificate. This is not stated clearly in the documentation!
Now I can establish a connection with a home-made certificate as stated on page http://wiki.tcl.tk/15244
Unfortunately, I don't (yet) know how to tell Android to not check the validity for now (like -require 0 in Tcl). Maybe I'll just import my own CA into the Android device. Otherwise, I would have to buy a certificate signed by an official CA. Some time in the future, I'll have to do this anyway.
Cipher suites can be named differently but they share the same "value". The error message is explicit in stating that there are no common cipher suites. This could be due to many reasons. Some but not all:
The SSL certificate on the server is based on say ECC versus RSA (different algorithms).
For the TLS protocol enabled, the ends do not have any common cipher suites.
List of cipher suites with their "values":
https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
Since your SSL server does not use any certificates the only possible ciphers are anonymous ciphers suites. Since these are insecure (open to man-in-the-middle attacks) they are not enabled by default for SSLSockets.
Thus the client will only announce support for cipher suites with proper authentication and it will not offer any ciphers usable with your TCL server. This causes the "no shared cipher" error.
If you really want to use such an insecure setup you might have a look at http://www.nickoh.com/emacs_files/ssl-examples/LdapTlsExample.java.txt for an example which uses anonymous cipher suites together with SSLSockets (I did not check if the example works, it as just one of the first hits when searching for support of anon cipher suites).
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.