I'm trying to connect an Android app to a SSL-enabled server, which uses a self-signed certificate. I've already read through dozens of tutorials and the app is now accepting the certificate & connecting to the server, but I never get any data back.
The original code i used to initialize the socket is this:
//passphrase for keystore
char[] keystorePass="password".toCharArray();
//load own keystore (MyApp just holds reference to application context)
KeyStore keyStore=KeyStore.getInstance("BKS");
keyStore.load(MyApp.getStaticApplicationContext().getResources().openRawResource(R.raw.keystore),keystorePass);
//create a factory
TrustManagerFactory trustManagerFactory=TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//get context
SSLContext sslContext=SSLContext.getInstance("TLS");
//init context
sslContext.init(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
//create the socket
Socket socket=sslContext.getSocketFactory().createSocket("hostname",443);
socket.setKeepAlive(true);
Afterwards, the run loop of the receiver thread uses socket.getInputStream() to access the input stream.
As long as I use an unencrypted connection, this works without a problem. But the secure connection does not retrieve any data from the socket. I've verified this by adding log messages to the receive loop and even used OpenSSL's s_server to check. I retrieved data from the client, but the client never received anything I sent to it.
As a last test, I tried to open a connection to www.google.com:443 like this:
javax.net.SocketFactory fact=SSLSocketFactory.getDefault();
Socket socket=fact.createSocket(_config.getUri().getHost(), _config.getUri().getPort());
Still the same result, connection works but using the InputStream I receive nothing from the server.
Anybody got any ideas?
EDIT:
I'm currently not allowed to answer my own question, but here's the answer:
Well, turns out the problem WAS the receive loop. I relied on InputStream.available() to get the number of bytes to read, but didn't realize it was rather unreliable (always returns 0 for SSL socket). So I switched the receive loop to use the blocking read() instead.
As mentioned above: Turns out the problem WAS the receive loop. I relied on InputStream.available() to get the number of bytes to read, but didn't realize it was rather unreliable (always returns 0 for SSL socket). So I switched the receive loop to use the blocking read() instead.
Related
I am connection to smtp.live.com but when i run program and insert email credentials it asks to use starttls command first what i can do to avoid this exception.
try {
Socket socket1= new Socket("smtp.live.com",587);
again:
while(true) {
Scanner s= new Scanner(System.in);
String from=""; String to=""; String cc=""; String bcc="";
mail[m_count]=new Message();
The problem is here:
Socket socket1 = new Socket("smtp.live.com", 587);
If the port number was 25, that would be fine. The problem is that you are trying to use SSL enabled SMTP, and that requires that you an SSL socket. But that is a bit more complicated ...
However, I think that there is a bigger issue here. The normal way to send / receive emails from Java is to use the javax.mail APIs. But if you are opening a socket (or SSL socket) to the mail server, that implies that you intend to implement the client side of the SMTP specification. Unless you have a really good reason to do that ... it sounds like a waste of effort.
The tutorial link provided by #npinti assumes that you are going to use javax.mail. If you
want to do it the hard way, this tutorial shows you how to use an SSL socket.
Server: Linux
Tested Clients: OS X, CentOS, Windows
Server/Client Programming Language: Java
Server-side
SSLServerSocketFactory sslserversocketfactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket =
(SSLServerSocket) sslserversocketfactory.createServerSocket(9999);
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println(string);
System.out.flush();
}
Server Program executed with this option
-Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456
Certificate: Created with keytool on Linux
keytool -genkey -keystore mySrvKeystore -keyalg RSA
Client Side
....
SocketAddress sa = new InetSocketAddress(ip, port);
....
SSLContext sslContext = SSLContext.getInstance("SSL");
....
sslContext.init(.........., new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
this.clientSock = socketFactory.createSocket();
this.clientSock.connect(sa, this.ConnectTimeout);
this.clientSock.setSoTimeout(this.RecvTimeout);
this.clientSock.setReuseAddress(true);
....
public boolean writeTo(String procname, BufferedOutputStream out, byte[] data)
{....
out.write(data, 0, data.length);
out.flush();
....}
Results: Everything works great but only client program from windows, it gets delayed when write to outputstream.
SSL Socket connection made
Set Output/Input stream
Write data into output stream
flush
... for 4-5 secs, it got stuck here with no reason at this point ...
close
The delay happens on the same java client simple program executing from Windows 7, Windows XP.
Tested from 3 different windows machine.
Everywhere else works great.
So I tried to build SSL simple clients with C and PHP, works great from Windows.
That means only Java clients method is not working.
Does anyone have any idea or similar experience before?
I'v seen some posts suspecting on WINS/DNS, but it seems like it's not the case here.
Also the funny thing is, it's always about 4-5 seconds of delay from every windows machine.
Thanks a lot for your comments in advance.
I've experienced a similar issue. Using tcpdump, I found that the TCP connection from client to server (SYN, SYN-ACK, ACK) happens almost instantaneously, then a mysterious pause, then the client actually sends the data.
The tcpdump output indicates that, immediately after connecting, the client (running on Windows) sends a NetBIOS name request (presumably to find out the name of the server, perhaps so it can choose an appropriate certificate or something) and the server immediately replies with an ICMP response saying the NetBIOS UDP (137) port is unreachable. It looks like the windows client ignores that response. After 1.5 seconds the windows client sends another NetBIOS name request, and the server sends the same ICMP response. After another 1.5 seconds the windows client sends a third and final NetBIOS name request, and the server sends back the same ICMP response. The socket data is finally transmitted 1.5 seconds after that.
So it looks like windows tries three times to determine the NetBIOS name of the server, and waits 1.5 seconds each time. Eventually (after 4.5 seconds) it gives up and sends the data. I think this explains the 4-5 second pause you reported.
One workaround to eliminate the pause is to add a 'hosts' file entry for the server. (It doesn't really matter what hostname you use within that file. The mere presence of an ip address avoids the need for the NetBIOS name resolution.) There are probably other alternatives too (e.g. add the server name to WINS or DNS or something, depending on what your windows machine is using for name resolution).
You're complaining about writing and you're only showing the reading code. What does the writing code look like? If you're not using a buffered stream or writer in the stack to the SSLSocket you can get data size explosions of up to 44 times, which would affect performance severely. I did some extensive testing over the Internet a few years ago and the conclusion was that with properly written code, SSL isn't any worse than 3 times as slow as plaintext.
I have created a ssl socket connection with my server. The server sends me the RC4 key and i use the key to create a cipher and bind it to the input and output streams of the existing socket. I am getting the following error on trying to read from the input stream:
javax.net.ssl.SSLProtocolException: Read error: ssl=0x32fbf8: Failure in SSL library, usually a protocol error
Is it possible that the decryption is not working properly or the RC4 key cipher is not correct. what are the reasons for such an error. I am doing it in an app on android 2.3.3.
One more query, does android 2.3.3 support sslv23(openssl) . If so how can instantiate the same ?(In windows client, i set the session context with the rc4 key and it works perfectly fine)
I am new to java and android and come from VC++ background.
Experts and programmers please enlighten me on my queries. My code is as follows:
sslContext = SSLContext.getInstance("TLS");
/* some code to initialize ssl context */
SSLSocketFactory sslSocketfactory = sslContext.getSocketFactory();
sock = (SSLSocket) sslSocketfactory.createSocket(host,port1);
sock.setSoTimeout(12000);
is = new DataInputStream(new BufferedInputStream(sock.getInputStream(),
16384));
os = sock.getOutputStream();
/* some more code using above mentioned is and os to recieve rc4 key and
write it into a byte array */
SecretKey key2 = new SecretKeySpec(reverserRc4InBytes, 0, reverserRc4InBytes.length, "RC4");
Cipher cipherOS = Cipher.getInstance("RC4");
cipherOS.init(Cipher.ENCRYPT_MODE, key2);
Cipher cipherIS = Cipher.getInstance("RC4");
cipherIS.init(Cipher.DECRYPT_MODE, key2);
cos = new CipherOutputStream(os,cipherOS);
cis = new CipherInputStream(is,cipherIS);
From what I understand, you're first making an SSL/TLS connection to exchange the RC4 key somehow, and then you're using it to encipher and decipher the result, instead of letting the SSL/TLS stack do it all for you. (It's clearly unnecessarily convoluted, and it's not clear how secure this is, since SSL/TLS provides you with more than encryption, in particular with integrity.)
The server is implemented in C and using an existing SSL stack ..
sslv23 to be specific.
SSLv23 isn't really a "stack" (by "stack" I mean an implementation: JSSE, OpenSSL, .Net's Security API, ...). SSLv23 usually refers to SSLv3 where the initial Client Hello message is wrapped in SSLv2 format. This wrapping happens on the client side, for clients that supports both SSLv3 and SSLv3/TLSv1.x. Which versions the server support should be fixed, in particular, you shouldn't need to use that trick if your server supports SSLv3 and above. (Note that the JSSE supports the v2 wrapped Client Hello format, but doesn't actually support SSLv2. I guess this is also the case for Android.)
javax.net.ssl.SSLProtocolException: Read error: ssl=0x32fbf8: Failure
in SSL library, usually a protocol error
This indicates that something incompatible is happening between your server and the client. There can be a few reasons for this:
Your server only supports SSLv2 (not 3). Let's assume your server supports at least SSLv3 (you can check whether the handshake completes using Wireshark, for example.)
There's a more general problem with the SSL/TLS implementation on the server. (You could attempt to connect to it using other tools, such as openssl s_client, at least to see if the connection can be established.)
Your key exchange protocol expects the SSL/TLS connection to end there, while leaving your manual handling of the connection on a plain TCP socket afterwards. You may have to use your Socket as an SSLSocket only during the section where SSL/TLS is used and revert back to the plain Socket afterwards. ()
You can try to establish a plain socket to your server, upgrade it to an SSLSocket using createSocket (Socket s, String host, int port, boolean autoClose) with autoClose=false and get the I/O from the plain socket to do your manual encryption.
I would assume that this should have caused other problems on the SSLSocket side, especially when the server closes its side of the SSL/TLS connection, though. This is just a guess, this approach might work.
Anyway, I don't think the problems you're seeing have anything to do with your using Cipher manually from your SSLSocket's I/O streams, since the exception happens at the underlying layer, which should be hidden as far as the data you read/write there is concerned.
I don't think you have understood your assignment properly. Either you should be using SSL or you need to implement this home-grown cipher.
Or else you should look for a saner job ;-)
I am trying to create a client - server application, the client written in c++ and QT, and the server in java, but I am having a really hard time trying to get ssl encryption working.
The process fails at handshake level, I think. The reason why I am having such a difficult time trying to figure out why it is not working is because, even though the process fails, no errors are reported in either the client or the server. I use the fallowing an the client side, in QT :
this->_uCertificate.fromPath(_DC::DEFAULT_CERT_MAIN_PATH + _DC::DEFAULT_MAIN_CERT_FILE);
this->_socket->addCaCertificate(this->_uCertificate);
//begin connection
this->_socket->connectToHostEncrypted(this->_uServerAdress, this->_uServerPort);
//wait until connection has completed
if(!this->_socket->waitForConnected(_CM::TIMEOUT))
{
this->_lastError = this->_socket->errorString();
return false;
}
//wait for handshake
if ( !this->_socket->waitForEncrypted(_CM::TIMEOUT) ) {
this->_lastError = this->_socket->errorString(); //the error is "No Error"
//return false;
}
It fails when calling the "waitForEncrypted". The function return false, so the process failed, but the error string is "No Error". I have also added a slot for handling the error signal from the socket, but it is never called. On the server side I use :
SSLSocket _sock = (SSLSocket) this._ssocket.accept();
_sock.startHandshake();
........................................
if(this._inputBuffered.read(this._messageBuffer) < 0)
throw new Exception("Error while reading from client");
Again no exceptions are thrown, but it fails at the read command. But on the server side I am no sure if an exception is thrown if the connection / handshake fails, or I should check for the error manually somehow.
I used to have a problem , in the client, when I would receive an error that the common name doesn't match the host, so at least I know that the connection is somewhat working. After I fixed the certificate to include the right common name, I am receiving this none existing error. Does anyone have an idea why it would fail this way, or at least a better debugging method?
Edit I have tried to connect using openSSL and it works. The handshake succeeds, and I can send and receive packets from the server. So the problem seems to be in the client.
It seemed that I had a problem with the way I was loading certificates from file. The method "fromPath" apparently doesn't actually load a cert from file, but returnes a list of certificates. If I add this list to my socket, then it works as it should. I am a bit conscience-stricken that I didn't read the documentation properly.
Edit The reason why it was failing, but still no errors were thrown with signals is because my socket had no valid certificate. When I was calling this->_uCertificate.fromPath(..), the method was returning a list of certificates found at that path, but the object itself was not modified. It still remained a invalid, empty certificate. So when I added that empty certificate in my socket, the only one, when it reached the handshake, It had no valid certificate for the operation. At this point it fails, but no errors are thrown.
But when the objects returned by the .fromPath() methon are added to the socket, then the handshake continues as normal, because now it has valid and non empty cartificates.
The problem of failing to give an error when there's an empty certificate database is now Qt bug QTBUG-17550
Connect your SSL client socket's void QSslSocket::sslErrors ( const QList<QSslError> & errors ) signal to some slot and see if there are any SSL errors reported.
For those who do not want to read a long question here is a short version:
A server has an opened socket for a client. The server gets a request to open a socket from
the same client-IP and client-port. I want to fore the server not to refuse such a request but to close the old socket and open a new one. How can I do ti?
And here is a long (original) question:
I have the following situation. There is an established connection between a server and client. Then an external software (Bonjour) says to my client the it does not see the server in the local network. Well, client does nothing about that because of the following reasons:
If Bonjour does not see the server it does not necessarily means that client cannot see the server.
Even if the client trusts the Bonjour and close the socket it does not improve the situation ("to have no open socket" is worser that "to have a potentially bad socket").
So, client do nothing if server becomes invisible to Bonjour. But than the server re-appears in the Bonjour and Bonjour notify the client about that. In this situation the following situations are possible:
The server reappears on a new IP address. So, the client needs to open a new socket to be able to communicate with the server.
The server reappears on the old IP address. In this case we have two subcases:
2.1. The server was restarted (switched off and then switched on). So, it does not remember the old socket (which is still used by the client). So, client needs to close the old socket and open a new one (on the same server-IP address and the same server-port).
2.2. We had a temporal network problem and the server was running the whole time. So, the old socket is still available for the use. In this case the client does not really need to close the old socket and reopen a new one.
But to simplify my life I decide to close and reopen the socket on the client side in any case (in spite on the fact that it is not really needed in the last described situation).
But I can have problems with that solution. If I close the socket on the client side and than try to reopen a socket from the same client-IP and client-port, server will not accept the call for a new socket. The server will think that such a socket already exists.
Can I write the server in such a way, that it does not refuse such calls. For example, if it (the server) sees that a client send a request for a socket from the same client-IP and client-port, it (server) close the available socket, associated with this client-IP and client-port and than it reopens a new socket.
You can't "reopen" a socket on your server. If the socket already exists and the client is trying to reconnect then you should get an BindException (see your previous question). The scenario that may be possible:
Client Shuts down socket
Server OS "notices" socket is dead on client side and shuts its side down
Client reconnects on the same port, but with a "new" socket
In this case you may consider it be the "same" socket, but it really isn't. That said a strategy you may wish to adopt is to have some sort of map (hash of client IP/port) to whatever mechanism you are using to service the socket or some kind of persistent state data, so that it can simulate a continuation of a previous socket (in the same vein as http sessioning). Something along the lines of:
HashMap<Client, State> sessions = ...;
public void server(){
...
while(true){
Socket socket = server.accept();
Client client = new Client(socket);
State s = sessions.get(client);
if(s == null){
s = new State();
sessions.put(client, s);
}
client.setState(s);
service(client);
}
...
}
and you can adjust the map lookup to define what a "session" means within your application (same client IP, same client IP & client port, some sessionid sent over the wire, etc).
If you are just trying to make it possible for the client to reconnect and force the server to "notice" the client is disconnected, the only real way in Java is to try and read/write data, and if it has been shutdown then it should throw an exception. Therefore as was mentioned in your other question you could add some kind of ack/nak feature to your protocol and add some type of check if you believe the client is disconnected (for example if you haven't read any data in the last N milliseconds, send a message the client must echo within M milliseconds, otherwise it is assumed to be disconnected). You can also try isConnected, isInputShutdown, isOutputShutdown, but I have found those to be unreliable in my own code to indicate the socket state, unless you have closed the socket (i.e. the one you are testing on the server).
The situation you describe is impossible. You can't get a new connect request from the same remote IP:port as an existing connection. The client will not permit it to occur.
Based on the comments:
You cannot write the server in a way that it will close a socket it still thinks is connected and automatically accept the new connection, as application code does not have that kind of control over the TCP stack, nor is there a way to reopen a connection.
The chance of the port numbers being the same between your client restarts is very small.
But still, if that happens, the server will note that that you're trying to set up an already connected socket, and refuse your new connection. There's not much else your client can do in this case besides close your socket, create a new one and try to connect again - and another random port will be selected.
additional note, your server should take some form of action to detect and close dead sockets, if all your server does is read incoming data, the "dead" sockets will never be
closed as they will never be detected as dead.(enabling tcp keepalive is one cheap measure to take against dead sockets staying up for months, though it will take a couple of hours to detect them as such by default.)