I need to use SSLV3 on android 8. I use direct socket connection. I do not use http connection. My server only supports SSLV3 and for reasons I can not change the server side. I need a solution on the client side. Android 8 does not support ssl (https://developer.android.com/about/versions/oreo/android-8.0-changes.html). Could someone help me solve this problem?
25766-26143/xx.com.xxx E/GeneralError: cipherSuite SSL_RSA_WITH_RC4_128_SHA is not supported.
java.lang.IllegalArgumentException: cipherSuite SSL_RSA_WITH_RC4_128_SHA is not supported.
at com.android.org.conscrypt.NativeCrypto.checkEnabledCipherSuites(NativeCrypto.java:968)
at com.android.org.conscrypt.SSLParametersImpl.setEnabledCipherSuites(SSLParametersImpl.java:264)
at com.android.org.conscrypt.OpenSSLSocketImpl.setEnabledCipherSuites(OpenSSLSocketImpl.java:895)
at xxx.com.xxx.communication.TrustAllSSLSocketFactory.createSocket(TrustAllSSLSocketFactory.java:128)
Related
I am using android nv-websocket-client library (both 2.0 and 1.31 versions) and I am trying to open a wss: connection; however, the connection fails with 503 Service not available error message.
Upon investigating I found that HAProxy requires the clients to use the SNI extension, otherwise such error is returned regardless of the Host: header (I am using HAProxy as a loadbalancer).
Upon investigating further (with tcpdump/wireshark) I found that the client does not send SNI, a wrong certificate is returned (for a different domain), yet the client continues with the TLS connection and actually sends the HTTP request (as if no certificate checking was performed?).
My code is basically:
ws = new WebSocketFactory().createSocket(wsurl);
ws.addHeader("Authorization", "Bearer " + Config.getToken());
ws.addListener(this);
ws.connectAsynchronously();
I didn't find an easy way to set up the SSLSocketFactory, however it seems to me that the code in nv-websocket-client just uses the SSLSocketFactory.getDefault(), which should be correct? SSLCertificateSocketFactory seems to be deprecated in favour of this approach.
Am I missing some key piece about SSL setup, is this and Android bug or is this and Android 'feature'?
DefaultHttpClient in Android 5.0 Lollipop seems to be broken. It can not set the connection to some sites that were successfully set by previous versions of Android.
For example I try to connect to https://uralsg.megafon.ru
//Create httpclient like in https://stackoverflow.com/questions/18523784/ssl-tls-protocols-and-cipher-suites-with-the-androidhttpclient
HttpClient client = new DefaultHttpClient(manager, params);
HttpGet httpGet = new HttpGet("https://uralsg.megafon.ru");
HttpResponse client = httpclient.execute(httpGet);
This code works in Android 2.3-4.4, but fails on Android 5.0 (devices and emulator) with error Connection closed by peer.
Of course this is understandable because Android 5.0 tries to connect this old server with TLSv1.2 and modern ciphers and it does not support them.
Ok, using the sample code in SSL/TLS protocols and cipher suites with the AndroidHttpClient we limit the protocol and cipher to TLSv1 and SSL_RSA_WITH_RC4_128_MD5. Now it fails with a different error:
javax.net.ssl.SSLHandshakeException: Handshake failed
caused by
error:140943FC:SSL routines:SSL3_READ_BYTES:sslv3 alert bad record mac
(external/openssl/ssl/s3_pkt.c:1286 0x7f74c1ef16e0:0x00000003)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake
And of course this code runs smoothly on Android 2.3-4.4.
I examined the traffic with wireshark:
302 4002.147873000 192.168.156.30 83.149.32.13 TLSv1 138 Client Hello
303 4002.185362000 83.149.32.13 192.168.156.30 TLSv1 133 Server Hello
304 4002.186700000 83.149.32.13 192.168.156.30 TLSv1 1244 Certificate
305 4002.186701000 83.149.32.13 192.168.156.30 TLSv1 63 Server Hello Done
307 4002.188117000 192.168.156.30 83.149.32.13 TLSv1 364 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
308 4002.240695000 83.149.32.13 192.168.156.30 TLSv1 61 Alert (Level: Fatal, Description: Bad Record MAC)
You can see that connection was established but server alerted because it probably could not decode encrypted handshake message.
I didn't manage to connect to https://uralsg.megafon.ru using HttpClient on Android 5.0. Stock browser does connect it though. Android 2.3-4.4 connects this site in any way without any difficulties.
Is there any way to make it possible for HttpClient to connect such sites? This is only one example, I am sure there are plenty of legacy servers that couldn't be connected by Android 5.0 and HttpClient.
update: it turned out to be a bug in the back-end, not android 5, though indeed with the cipher in question.
I had the same problem. For me it turned out to be the cipher TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 which was chosen from android 5's (updated) set of default ciphers.
As soon as i removed it from the client list of acceptable ciphers, connections worked again.
The android 5 change log mentions:
AES-GCM (AEAD) cipher suites are now enabled,
I'm pretty sure this is the culprit. As soon as TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 is preferred (by the server), the connection will fail.
Note that TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 works.
My guess is that either the Android implementation of TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 is buggy, or the one of the server you're talking to.
Solutions:
Remove TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 from the available ciphers on the server (no app redeployment needed).
Remove TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 from the list of ciphers the client offers (during the CLIENT_HELLO).
You can do that on the client side by implementing your own SSLSocketFactory and calling
sslSocket.setEnabledCipherSuites(String[] suites);
on SSLSocket creation.
edit: note that this isn't necessarily an android bug, it might be that the server implementation is faulty. if your problem is indeed caused by the cipher, please leave a comment on the android bug tracker](https://code.google.com/p/android/issues/detail?id=81603). thank you!
I tried changing the cipherSuites in a custom socket factory, but that did not help. In my case, I had to remove the TLSv1.1 and TLSv1.2 protocols from the socket's EnabledProtocols. It appears that some older servers do not handle the protocol negotiation for the new protocols very well. There are various examples out there for creating a custom socket factory, such as How to override the cipherlist sent to the server by Android when using HttpsURLConnection?, and other ones for Apache sockets. That being done, I just called the following AdjustSocket method to remove the protocols.
private void AdjustSocket(Socket socket)
{
String[] protocols = ((SSLSocket) socket).getSSLParameters().getProtocols();
ArrayList<String> protocolList = new ArrayList<String>(Arrays.asList(protocols));
for (int ii = protocolList.size() - 1; ii >= 0; --ii )
{
if ((protocolList.get(ii).contains("TLSv1.1")) || (protocolList.get(ii).contains("TLSv1.2")))
protocolList.remove(ii);
}
protocols = protocolList.toArray(new String[protocolList.size()]);
((SSLSocket)socket).setEnabledProtocols(protocols);
}
I have two domains: foo.net and bar.com. They both have SSL certificates, and they work well in all desktop and mobile browsers. They are hosted on the same server configured with nginx.
However, when I make a request to a domain from within a native android app, it somehow gets the certificate from the wrong domain! This results in an IO Exception:
request = new HttpPost("https://foo.net/api/v1/baz");
request.setHeader("Authorization", "user:pass");
response = httpClient.execute(request);
...
javax.net.ssl.SSLException: hostname in certificate didn't match: <foo.net> != <bar.com> OR <bar.com> OR <www.bar.com>
What would cause android/java to try using the certificate from bar.com when every other measure seems to indicate that the server is correctly configured? Nothing appears in the nginx access or error log. There is no mention of bar.com anywhere in my android project.
Edit: I'm not sure why, but it appears that the server is using the certificate for bar.com for the server IP https://198.245.xx.xxx
The most likely cause for this problem is that the server uses Server Name Indication to choose which certificate to send. If the client doesn't support SNI, the server cannot choose which certificate to send during the SSL/TLS handshake (before any HTTP traffic is sent). SNI is required when you want to use multiple certificates on the same IP address and port, but not all clients support it (notoriously, IE on any version of Windows XP, and a number of mobile browsers).
You're also visibly using the Apache HTTP Client library (not HttpsURLConnection, for which there can be SNI support with some Android versions.
Support for SNI in the Apache HTTP Client library is quite recent, and certainly hasn't made it into the Android stack.
You may find the workaround described in this article useful (although it seems only to work for Android 4.2+).
Another two options would be:
to use a distinct IP address for each host (so as not to need SNI), if you're in control of server, or
to use another HTTP Client library (e.g. HttpsURLConnection).
A solution for Apache, more like a trick:
the SSL certificates are loaded based on the vhost name from /etc/apache2/sites-enabled. So, to trick that check make sure the problematic certificate is loaded first (remember that the vhosts are loaded by name).
It looks like the certificate of foo.net is misconfigured, and is using the same hostname as bar.com
Try to run an online certificate validation tool, like https://www.digicert.com/help/ on foo.net, just to be sure.
I think that you need to regenerate the certificate of foo.net with the right hostname, or reconfigure ngix to make sure that nginx serve the right certificate for the right host.
I am new to SSL. I need to implement SSL connection between two Android devices via TCP.
Is there any example how to do it? How can I create SSLServerSocket?
I tried to set property for default keystore, for using SSLServerSocket
System.setProperty("javax.net.ssl.keyStore", "my_keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
this doesn't help.
I'm able to create SSLServerSocket, but on accept() it fails with following exception:
"SSLException: Could not find any key store entries to support the enabled cipher suites"
Also I use certificate of a proper type on Android: BKS
Thanks in advance.
This is not different than using SSL sockets on any platform, refer to the JSSE reference. The only thing to watch out is that you need to have the phones on the same network (if local), and your carrier might be filtering/blocking inbound connections if on 3G, etc. Also keep in mind that mobile devices can change their IP when re-connecting, etc., so a fixed IP might not work.
In android app I am developing I need to make connection to https server.
Client has provided me with 2 files mycert.pem and mykey.pem, which I think is certificate and public keystrore of server.
I need to make secure connection using HttpsURLConnection and verify host name of server to avoid man in middle attack. I have little understanding about making https connection and cryptography terms. Most of tutorial I came across uses HttpClient and they trust all host. Can someone point me in right direction how to use .pem files to make a secure https connection using HttpsURLConnection and verify hostname.
Thanks in advance.
OK done by using following
httpsConn.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
I am using BROWSER_COMPATIBLE_HOSTNAME_VERIFIER, I hope it works well.