Changing OpenSSL library in Android app for HttpClient
I have compiled libcrypto.so and libssl.so for Android and put the files in a folder jniLibs...
This won't work.
Android utilizes OpenSSL 1.0.0 and provides it in /system
. Zygote starts at boot and loads the down level version of OpenSSL (its like init
- all Android processes are forked from it).
When your process is forked from Zygote, your 1.0.1 version is never loaded because 1.0.0 is already loaded from Zygote. You never know there's a problem because the down level version provides all the symbols you need (its binary compatible).
You need to write a wrapper shared object. The wrapper shared object must link against the static versions of OpenSSL 1.0.1 (libcrypto.a
and libssl.a
). Your wrapper must export unique symbols, like My_OpenSSL_add_all_algorithms
and My_SSL_load_error_strings
. Internally, your shared object can refer to the undecorated names, OpenSSL_add_all_algorithms
and SSL_load_error_strings
.
So your shared object would look like so (also see GCC's Visibility page):
#if __GNUC__ >= 4
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define DLL_PUBLIC
#define DLL_LOCAL
#endif
DLL_PUBLIC void My_OpenSSL_add_all_algorithms() {
return (void)OpenSSL_add_all_algorithms();
}
DLL_PUBLIC void My_SSL_load_error_strings() {
return (void)SSL_load_error_strings();
}
...
Then, compile with the -fvisibility=hidden
flag and link against libcrypto.a
and libssl.a
. Only the functions marked with DLL_PUBLIC
will be exported and callable through JNI.
I don't think the #if __GNUC__ >= 4
is needed because the cross compiler tools provided by Android are GCC 4.0 above. In fact, I think its currently GCC 4.8.
Changing OpenSSL library in Android app for HttpClient
This question is tougher. Once you provide the updated OpenSSL in your shared wrapper, I don't know how you would get Android's HttpClient
to use it.
The worse case answer: you might need to fork Android and provide an updated OpenSSL.
A potentially better solution: rip the HttpClient
code, put it in your own package, and then be sure you shared object is used by port of the source code.
Cannot load prebuilt OpenSSL library in Android project
Turned out that structure of my jniLibs was something like:
arm64-v8a
include
...
lib
libcrypto.so
libssl.so
x86
include
...
lib
...
opposed to:
arm64-v8a
include
...
libcrypto.so
libssl.so
x86
include
...
...
Which solves initial problem.
How to use Apache http-client 4.5.x used by external library on Android
You can not directly replace classes included in the Android framework. The only solution is to use a different namespace. This is why Spongy Castle uses org.spongycastle.*
instead of org.bouncycastle.*
, and the project you linked uses cz.msebera.android.httpclient.*
instead of org.apache.http.*
.
Unfortunately, this means that you have to change every reference to http-client in your library.
Since the release of Android Jetpack, the SDK includes Jetifier, a tool to translate
references in libraries bytecode at buildtime. There is a standalone version, and it can use custom mapping config.
In you case this would imply:
- Create a custom config translating
org.apache.http
tocz.msebera.android.httpclient
- Convert your standard Java library
- Use the transformed library and the third party port of http-client
Another possible solution to convert the library would be to use Jar Jar.
How to pass unsafe HttpClient to Volley request in Android
I found and it is working for me, Please let me know anything wrong here. Here is the code need to add to make a call.
final String url = "YOUR URL";
RequestQueue queue = Volley.newRequestQueue(this, getHttpStack(url));
// prepare the Request
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// display response
Log.e("test", "Response" + response.toString());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("test", "Error.Response: " + error.getMessage());
}
}
);
queue.add(getRequest);
Here is the methods, need to add in code.
private HurlStack getHttpStack(String urlToValidate) {
URL url = null;
try {
url = new URL(urlToValidate);
} catch (MalformedURLException e) {
e.printStackTrace();
}
final String baseUrl = url.getAuthority();
return new HurlStack() {
@Override
protected HttpURLConnection createConnection(final java.net.URL url)
throws IOException {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super
.createConnection(url);
try {
httpsURLConnection
.setSSLSocketFactory(handleSSLHandshake(httpsURLConnection));
httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
//return true;
HostnameVerifier hv =
HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(baseUrl, session);
}
});
} catch (Exception e) {
e.printStackTrace();
}
return httpsURLConnection;
}
};
}
@SuppressLint("TrulyRandom")
public static SSLSocketFactory handleSSLHandshake(HttpsURLConnection connection) {
try {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
Log.e("test", "RETURN TRUE: ");
return true;
}
});
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory newFactory = sc.getSocketFactory();
connection.setSSLSocketFactory(newFactory);
} catch (Exception ignored) {
}
return connection.getSSLSocketFactory();
}
An HTTPS Client for Android that doesn't use native_ssl
This is a work around - not a solution.
We just could not afford spending any more resources on this issue...
We've dodged the bullet by splitting the upload procedure to 2 steps:
First step (which requires the Client-certificate) takes all the metadata and returns an upload token (expires in 30 seconds).
Second step does not require the certificate, but uses the upload token to perform upload (still over SSL).
Application crashes in loading C++ jni library dynamically linked with openss-1.0.1h
It looks like you have two problems. First is linking against OpenSSL; and second is actually finding the library in the APK.
I am using a C++ library, which is dynamically linked with openss-1.0.1 h libraries...
Here is your first problem. Android's equivalent of init
is zygote
. Zygote loads the platform's version of OpenSSL. When Zygote forks to start your app, you app gets the already linked version of OpenSSL, which is likely 0.9.8. Since your app is built against 1.0.1, you will crash at runtime because 0.9.8 and 1.0.0 are not binary compatible.
To resolve this, you have to build a wrapper shared object that links against the static version of the OpenSSL library. Then, when you need to make an OpenSSL call, you expose it through your wrapper. For example, you might have a GetSslContext
that wraps the calls to OpenSSL's SSLv23_method
, SSL_CTX_new
, SSL_CTX_set_options
, etc.
This avoids calling into Zygote's downlevel OpenSSL. Its also documented on the OpenSSL wiki at OpenSSL and Android.
"could not find libssl.so.1.0.0 needed by libABC.so"
Here is your second problem. First, create a wrapper shared object as described above. Second, place your shared objects in the proper directory. The shared wrapper should be placed in the lib/
directory. I believe you can also have specialized versions of the library in subdirectories. For example, lib/
would be a generic fallback, while lib/armv7-a/
would be a shared object built specifically for ARMv7a.
You can find the libraries at runtime with the ApplicationInfo class and its nativeLibDir method:
public String nativeLibraryDir
Full path to the directory where native JNI libraries are stored.
Also see Android's JNI Tips and the Native Libraries section.
System.loadLibrary("ssl");
System.loadLibrary("crypto");
Related, libssl
depends upon libcrypto
, so it should be:
static {
System.loadLibrary("crypto");
System.loadLibrary("ssl");
}
But you should probably avoid it and use a wrapper shared object.
Related Topics
Sending Http Post Request with Android
Why Do Variable Names Often Start with the Letter 'M'
Convert a String to a Byte Array and Then Back to the Original String
Recyclerview Painfully Slow to Load Cached Images Form Picasso
Android Webview Always Returns Null for JavaScript Getelementbyid on Loadurl
Google Cloud Messaging: Don't Receive Alerts When iOS App Is in Background
Simple Sso - Using Custom Authentication - Cas or Some Oauth or Openid Server
How to Create My Own Appender in Log4J
Android Resource Not Found Exception
What Does Transitive = True in Gradle Exactly Do (W.R.T. Crashlytics)
Proguard and Reflection in Android
Apache Http Client or Urlconnection