My project has been using Android Volley network framework for a long time, but recently I found a SSL 3.0 protocol bug published on the Internet.
I want to know how can I find out what's the TLS version my project used, and how to confirm whether the library is updated.
Here is my source code fragment:
HttpStack stack = new HurlStack();
Network network = new BasicNetwork(stack);
mHttpRequestQueue = new RequestQueue(new NoCache(), network);
mHttpRequestQueue.start();
I think the point is in HurlStack class, and it depends on org.apache.http package, but I can't figure out where TLS/SSL configuration is.
You may modify the version of TLS used in Volley by creating a custom HTTPStack and setting the stack in the Volley.newRequestQueue(context, httpStack) method in Volley.java. Although, you only need to do this for Android versions 16-19. Before v16, TLS 1.2 isn't supported and after v19, TLS 1.2 is enabled by default. So, you should focus on manually setting TLS to 1.2 for Android versions 16-19.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
try {
ProviderInstaller.installIfNeeded(getContext());
} catch (GooglePlayServicesRepairableException e) {
// Indicates that Google Play services is out of date, disabled, etc.
// Prompt the user to install/update/enable Google Play services.
GooglePlayServicesUtil.showErrorNotification(e.getConnectionStatusCode(), getContext());
// Notify the SyncManager that a soft error occurred.
syncResult.stats.numIOExceptions++;
return;
} catch (GooglePlayServicesNotAvailableException e) {
// Indicates a non-recoverable error; the ProviderInstaller is not able
// to install an up-to-date Provider.
// Notify the SyncManager that a hard error occurred.
syncResult.stats.numAuthExceptions++;
return;
}
HttpStack stack = null;
try {
stack = new HurlStack(null, new TLSSocketFactory());
} catch (KeyManagementException e) {
e.printStackTrace();
Log.d("Your Wrapper Class", "Could not create new stack for TLS v1.2");
stack = new HurlStack();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
Log.d("Your Wrapper Class", "Could not create new stack for TLS v1.2");
stack = new HurlStack();
}
requestQueue = Volley.newRequestQueue(context, stack);
} else {
requestQueue = Volley.newRequestQueue(context);
}
And then use a TLSSocketFactory class which extends SSLSocketFactory like the one Florian Krauthan created here, where the v1.2 TLS protocol is enabled: https://gist.github.com/fkrauthan/ac8624466a4dee4fd02f#file-tlssocketfactory-java
On Android the used TLS version mostly depends on the used Android version.
Apache Volley bases on Apache Http Client which bases on HttpsUrlConnection, therefore the standard SSL/TLS SSLSocketFactory is used.
On Android below 4.3 usually only SSLv3 and TLS 1.0 are supported. On later versions TLS 1.1 and 1.2 are often supported but disabled.
Starting with Android 5 TLS 1.1 and TLS 1.2 are supported and enabled by default
#w3bshark's answer worked for me. But Before using that code, Make sure you include the code to update Security Provider. In my case, TLS didn't work until i update security provider. Following is the code to update it.
private void updateAndroidSecurityProvider() {
try {
ProviderInstaller.installIfNeeded(this);
} catch (GooglePlayServicesRepairableException e) {
Log.e("Test321", "PlayServices not installed");
} catch (GooglePlayServicesNotAvailableException e) {
Log.e("Test321", "Google Play Services not available.");
}
}
Related
Good day,
I'm trying to connect to AWS IoT with android using its SDK, no problem with Android 7 and above. But there's a compatibility problem with below versions. This is detailed in this Issue. I tried using Paho as client library but I haven't been able to figure out how to use those certificates with the Socket factory. Any idea how can I use those certificates with some MQTT Client library?
In the Java SDK was pretty easy to connect and no problem at all, I didn't have to use a keystore for that. Why Android needs to use a keystore to manage those certificates?. Should I install those certificates in the security settings as well?
I have tried using this wrapper. But is quite confuse how it uses those keystores. It throws and exception as it can't create it. Using that wrapper I have been able make some modifications and make it run. But it doesn't trigger anything neither onFail or onSuccess.
This is what I have done:
The class SocketFactory can be found here
void MqttSetup() {
CLIENT = new MqttAndroidClient(getBaseContext(), BROKER, MqttClient.generateClientId());
MQTT_CONNECTION_OPTIONS = new MqttConnectOptions();
/**
* SSL broker requires a certificate to authenticate their connection
* Certificate can be found in resources folder /res/raw/
*/
SocketFactory.SocketFactoryOptions socketFactoryOptions = new SocketFactory.SocketFactoryOptions();
try {
socketFactoryOptions.withCaInputStream(getResources().openRawResource(R.raw.keystore));
MQTT_CONNECTION_OPTIONS.setSocketFactory(new SocketFactory(socketFactoryOptions));
} catch (IOException | NoSuchAlgorithmException | KeyStoreException | CertificateException | KeyManagementException | UnrecoverableKeyException e) {
e.printStackTrace();
}
}
void MqttConnect() {
try {
final IMqttToken token = CLIENT.connect(MQTT_CONNECTION_OPTIONS);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
Log.d("mqtt:", "connected, token:" + asyncActionToken.toString());
subscribe(TOPIC, (byte) 1);
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// Something went wrong e.g. connection timeout or firewall problems
Log.d("mqtt:", "not connected" + asyncActionToken.toString());
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
When I try to connect to the broker it seems that it can make a connection as it's registered in the Monitor of Aws IoT. But those listeners don't get triggered and there are no thrown exceptions. I thought that I might not be loading those certificates properly.
I have the next files downloaded from Aws IoT (not sure how to bind them in a keystore and access them):
certificate.pem.crt
private.pem.key
public.pem.key
Thanks.
I need to start a connection using SignalR hubProxy class, everything works fine till API 25 but above 25 it gives this error:
Failed to finalize session : INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113
code I'm Using
HubConnection hubConnection = new HubConnection(hubUrl);
HubProxy hubProxy = hubConnection.createHubProxy("hubName");
try {
SignalRFuture<Void> awaitConnection;
awaitConnection = hubConnection.start(new ServerSentEventsTransport(hubConnection.getLogger()));
awaitConnection.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
I tried to resolve it by following this answer, but it does not provide hubProxy class. so I cannot use it.
Please tell me how to fix this error.
I'm using gottox socket.io java client for an Android chat application. I could connect to both web-socket and Xhr transport in HTTP mode. But when i switch to HTTPS only Xhr mode is working. i used the default SSL Context as below
SocketIO.setDefaultSSLSocketFactory(SSLContext.getInstance("Default"));
This works fine in Xhr mode. But in websocket transport there are no responses or errors.
Update
It might be that with new versions IO.setDefaultSSLContext and IO. setDefaultHostnameVerifier methods are not available. Instead now we can create our own OkHttpClient and set the hostname verifier and ssl socket factory etc on it as mentioned on socket.io-client-java usage. Here is the sniplet from there:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.hostnameVerifier(myHostnameVerifier)
.sslSocketFactory(mySSLContext.getSocketFactory(), myX509TrustManager)
.build(); // default settings for all sockets
IO.setDefaultOkHttpWebSocketFactory(okHttpClient);
IO.setDefaultOkHttpCallFactory(okHttpClient);
Initial Answer:
I had the same issue with io.socket:socket.io-client:0.7.0 version of socket.io library on Android for long. It used to work fine for http protocol, however for https protocol it had trouble establishing connection giving xhr poll errors.
Following solution works for me without modifying the library itself:
// Socket connection
private Socket mSocket;
// Configure options
IO.Options options = new IO.Options();
// ... add more options
// End point https
String yourEndpoint = "https://whatever.yoururl.com"
String yourHostName = "yoururl.com"
// If https, explicitly tell set the sslContext.
if (yourEndpoint.startsWith("https://")) {
try {
// Default settings for all sockets
// Set default ssl context
IO.setDefaultSSLContext(SSLContext.getDefault());
// Set default hostname
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(yourHostName, session);
}
};
IO.setDefaultHostnameVerifier(hostnameVerifier);
// set as an option
options.sslContext = SSLContext.getDefault();
options.hostnameVerifier = hostnameVerifier;
options.secure = true;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
// Instantiate the socket
mSocket = IO.socket(mEndpoint, options);
Hope this helps.
It works but you have to do some modifications on io.socket library.
Instead of using the socketio.jar, import into src folder the io.socket library (You'll find inside socket.io-java-client package). There, you have to edit the WebsocketTransport class.
Here you have the solution
https://github.com/Gottox/socket.io-java-client/issues/60
public WebsocketTransport(URI uri, IOConnection connection) {
super(uri);
this.connection = connection;
SSLContext context = null;
try {
context = SSLContext.getInstance("TLS", "HarmonyJSSE");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
try {
context.init(null, null, null);
} catch (KeyManagementException e) {
e.printStackTrace();
}
if("wss".equals(uri.getScheme()) && context != null) {
this.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(context));
}
}
And remember to call the setDefaultSSLSocketFactory like this:
socket = new SocketIO();
socket.setDefaultSSLSocketFactory(SSLContext.getDefault());
socket.connect("https://www.myHttpsServer.com:443/");
Hope it helps someone ;)
Websocket with SSL working in AndroidAsync. Using that for now.
How can access to wss:// protocol in java ?
i use benkay / java-socket.io.client
but it's not support wss protocol.
i tried use SSLEngine. but it's very hard work.
how can connect to ssl in java ?
I tried change SocketChannel by SSLEngine. but it is not worked.
ssl channel is ok. but i can't wire this original websocket part.
this is source code.
client = SocketChannel.open(remote);
client.configureBlocking(false);
//client.connect(remote);
selector = Selector.open();
this.conn = new WebSocket(client, new LinkedBlockingQueue<ByteBuffer>(), this);
client.register(selector, SelectionKey.OP_READ);
try {
sslClient = new SSLClient(keyStore, storepass.toCharArray(), client);
sslClient.beginHandShake();
startClient()
} catch (Exception e) {
e.printStackTrace();
}
this point uncorret ?? i don't know .. not same the original websocket code.. may problem is this point. how can fix it ??
public void startClient()
{
try
{
while(true)
{
if(selector.select() <= 0)
{
continue;
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
Log.e("key","key");
if(key.isReadable())
{
read(key);
}
it.remove();
}
}
}
catch(Exception e)
{
}
}
and SSLClient is http://rapidant.tistory.com/attachment/cfile25.uf#121346414D45B0960BD01B.zip
key store : change JKS to BKS, not problem.
how can wrap the SocketChannel ?
(Web browser it worked.)
You could check out my fork of the Autobahn WebSocket Library.
Secure WebSockets based upon Autobahn
You don't want to use SSLEngine on Android because it is broken.
I am building an Android Library and have a method getting some information about the device. Our target is to support 2.2 and up but was wondering if there is a way to collect information introduced in later versions (ex device serial in 2.3) and have the application set with version 2.2 to compile.
After searching around I found people using code like:
private static String getHardwareSerial() {
try {
return Build.SERIAL;
} catch (VerifyError e) {
//Android 8 and previous did not have this information
return Build.UNKNOWN;
}
}
However, with this code present, my sample application using our library fails to build when setting the build target to 8. Any suggestions or do we have to live with our clients setting their target to 9 to get this info?
You could do it through reflection:
public static String getHardwareSerial() {
try {
Field serialField = Build.class.getDeclaredField("SERIAL");
return (String)serialField.get(null);
}
catch (NoSuchFieldException nsf) {
}
catch (IllegalAccessException ia) {
}
return Build.UNKNOWN;
}
If the field isn't found (on earlier versions of the OS) it'll throw an exception that will be ignored and then fall through to return Build.UNKNOWN.