I want to have a SSL encrypted TCP server on the android device and a client on the computer which will connect to the device.
I create a SSLServerSocket on the Android device with an own keystore.
final KeyStore localTrustStore = KeyStore.getInstance("BKS"); //NON-NLS
final InputStream in = context.getResources().openRawResource(R.raw.syncapp);
localTrustStore.load(in, "secret".toCharArray()); //Keystore pw
in.close();
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); //NON-NLS
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(localTrustStore);
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(localTrustStore, "secret".toCharArray()); //privat key pw
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
serverSocket = sslContext.getServerSocketFactory().createServerSocket(SERVER_PORT);
((SSLServerSocket) serverSocket).setNeedClientAuth(true);
Then I wait for a client to connect. When a client wants to connect a new thread is started and the streams get demanded:
final DataInputStream input = new DataInputStream(this.clientSocket.getInputStream());
final DataOutputStream output = new DataOutputStream(new BufferedOutputStream(clientSocket.getOutputStream()));
First I used this code with USB-Tethering to gain a connection between the computer and the android device. So no Wifi/Network was enabled. Everything worked perfectly.
Then I activated the wifi on the android device and connect to a wlan without internet.
But now the call to getInputStream() seems to take 5 to 10 seconds.
If I deactivate SSL it works perfectly.
If the wlan does connect to the internet there is no delay as well.
I tested this with Android 4.2 and 5.1.
Update: Now I could test this issue with Android 6. And the issue seems to be fixed there...
The Handshake is finished correctly but after that there seems to be some sort of delay on the android device. (The call to getInputStream consumes that time)
Some devs are saying that it will do a DNS reverse lookup which will run into a timeout.
Take a look at the capture, the first connection was made while wifi was disabled. It took 0.3 sec to make the data transfer. Then I just activated the wifi, I didn't connect over the wifi, it still communicates over usb. And it took over 5 sec.
I found the issue here as well, but they are using a client socket. I need a server socket. Does anyone have any idea how to fix this issue?
TLS connection using SSLSocket is slow in Android OS
You are right that there is a reverse DNS lookup that is timing out. In certain Java Runtime Environments, during the handshake with a raw IP address, the SSLContext unnecessarily performs a lookup of the server's IP address. This is to determine if the common name of the server certificate matches. Try using one of the solutions mentioned here:
How to disable Java's SSL Reverse DNS Lookup
Related
I have an SSL-enabled tcp server that can listen to multiple rsyslog clients. Each client has its own certificate that is added in the server's truststore. This setup is working fine. TThe question is whether there is a way to get the client certificate information like CN, location etc. after the socket accepts connection?
Below is the code sample of simple tcp server.
SSLServerSocketFactory sf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = sf.createServerSocket(514);
while(true){
SSLSocket s = (SSL)ss.accept();
// here I need to get client certificate information
}
You need to configure the SSLServerSocket to need or want client authentication, depending on which of those applies. Then you can get the peer certificates out of the SSLSocket's SSLSession, if they were sent.
I created a self-signed certificate (server.crt, server.key, server.p12). I get a Python-Python SSL socket connection using this self-signed certificate working just fine.
Python server:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 10023))
s.listen(5)
s_, fromaddr = s.accept()
connstream = ssl.wrap_socket(s_,
server_side=True,
certfile="server.crt",
keyfile="server.key")
data = connstream.read()
...
Now, I would like my Android application to talk with my Python server. I can get a non SSL connection going. I'm not sure how to proceed with self-signed certificates. My understanding is that I have to store the certificate in Java's truststore. I am having difficulty finding examples of doing this within the Android app (programmatically) using a trusted certificate file (e.g. the crt?). Obviously, the scope of this trust is limited to the app only, and is not intended to be a permanent solution.
Java client (on Android):
SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = ssf.createSocket(HOST, PORT);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("hello from java!");
out.flush();
...
When I try to connect I get the following error on the server:
ssl.SSLError: [Errno 1] _ssl.c:499: error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert certificate unknown
export crt file at server
import crt file from asserts or file at Android code
set up crt with TrustManagerFactory at Android code
init SSLContext with TrustManagerFactory
this is reference on official document
I have an Android app which uses a Java TCP client to connect to a Java TCP application server.
In some cases I noticed firewalls or routers that block the port I am using can cause issues so I am trying to use a secure connection.
I have tried using the examples from this link:
SSLServerSocket but I am always getting a connection timeout.
Server code:
ServerSocketFactory sslServerSocketFactory = SSLServerSocketFactory.getDefault();
serverSocket = sslServerSocketFactory.createServerSocket(port, backlog);
Socket socket = serverSocket.accept(); ---> in a new thread
Client code:
SocketFactory socketFactory = SSLSocketFactory.getDefault();
clientSocket = socketFactory.createSocket();
clientSocket.connect(new InetSocketAddress(host, port), READ_TIMEOUT); ---> timeout on this line
I also tried the more complicated examples in the link but all resulted in a timeout.
I really want to understand what's wrong with this very simple example.
If it's not the way to work with SSL (I see no mention of certificates in this code at all, which I think is necessary in SSL) then why is it given as a working example?
Any help would be appreciated.
I have some code to connect to a remote server using the Java NIO libraries. I wrote the code to connect asynchronously with callbacks, and it works great when the host is just a regular TCP server. But when the server uses SSL, it appears that I have to make a bunch of modifications. What I want to do is set up SSL only to the point where it checks to see if the server certificate is valid, i.e. issued by a certificate authority and not expired. I do not want to do anything more extensive than that (like name checking). In other words I just want very basic SSL behavior. Also, I plan to run this on Android, so I really can't do a whole lot of fumbling with external keystores and all that on the client side. I want to do everything I have to internally to the app. If I can avoid any external cert files that would be great.
I'm stuck as to what exactly I need to do in order to proceed. I found some NIO socket setup code here as follows:
private void setupSecurity() {
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextInt();
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.jks"), "KeyStorePassword".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(clientKeyStore, "KeyInKeystorePassword".toCharArray());
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), secureRandom);
}
And after this, there is a bunch of apparently horrendous SSL handshke code that must be implemented manually. The problem with the above code is that I have no idea what I am supposed to have inside the client.jks file. I don't want to have to have some sort of keystore file to begin with.
I found a library called Naga that claims to implement SSL sockets, but it doesn't work on an SSL socket server I have set up - I get an exception:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Any suggestions on how to proceed?
You need to use the SSLEngine, which is no joke in itself, and I'm not sure it works correctly on Android, although I am open to correction. The SSLEngine is a state machine and takes a lot of implementing. Frankly having done it I would forget it and use SSLSockets.
This was actually discussed before here: SSH library for Java.
I ended up using Java Secure Channel (JSCH) which is documented here: JSCH javadoc
The initial problem we encountered was that a regular FTPs download started failing due to an untrusted server certificate. This prompted us to wonder whether the certificate had been updated without the counterparty notifying us so we wanted to download the current certificate and compare it to the one we have in our keystore.
This seems to be a trickier problem than we had anticipated. The usual suspects (firefox, filezilla, ...) did not seem up to the task of connecting to an FTPs server through an FTP proxy so out of curiosity I started playing around with a more low level java approach. I can not for the life of me get it to work though.
First (overly simplistic) java attempt:
// create proxy connection
SocketFactory plainFactory = SocketFactory.getDefault();
Socket proxy = plainFactory.createSocket(proxyServer, proxyPort);
// create ssl connection on top of it?
SSLSocketFactory sslFactory = getSocketFactory();
SSLSocket socket = (SSLSocket) sslFactory.createSocket(proxy, server, port, true);
This approach obviously does not work.
Next I started playing around with ftp4j (http://www.sauronsoftware.it/projects/ftp4j/) it seems to have a clean and accessible codebase:
FTPClient client = new FTPClient();
client.setConnector(new FTPProxyConnector(proxyHost, proxyPort));
client.getConnector().setConnectionTimeout(0);
client.getConnector().setReadTimeout(0);
client.setSSLSocketFactory(getSocketFactory());
// also tried SECURITY_FTPS
client.setSecurity(FTPClient.SECURITY_FTPES);
client.connect(server, port);
This outputs:
REPLY: 220 Blue Coat FTP Service
SEND: USER anonymous
REPLY: 530-User Access denied.
REPLY: 530-
REPLY: 530-Usage: USER username#hostname
REPLY: 331 PASS userpassword
Exception in thread "main" java.io.IOException: Invalid proxy response
The proxy server has optional authentication and on our development servers we generally use "user#host" without proxy authentication. As such I assume the username, hostname and password are those of the remote server?
So I tried adding the remote parameters, this does not work:
REPLY: 220 Blue Coat FTP Service
SEND: USER test#ftps.example.com
Exception in thread "main" java.io.IOException: FTPConnection closed
Adding the proxy user to match the bluecoat format does not seem to work either:
USER %u#%h %s
PASS %p
ACCT %w
Any help with either of these two problems would be most welcome:
how to retrieve the server certificate from an ftps server through an ftp proxy
how to connect to an ftps server through an ftp proxy in java
You might want to try Apache Net commons libs.
Here is a similar thread that uses that Net Commons library
Net commons also has a fully functional FTP Client Example so you can test with something you know works.