accepting HTTPS connections with self-signed certificates
The first thing you need to do is to set the level of verification.
Such levels is not so much:
- ALLOW_ALL_HOSTNAME_VERIFIER
- BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
- STRICT_HOSTNAME_VERIFIER
Although the method setHostnameVerifier() is obsolete for new library apache, but for version in Android SDK is normal.
And so we take ALLOW_ALL_HOSTNAME_VERIFIER
and set it in the method factory SSLSocketFactory.setHostnameVerifier()
.
Next, You need set our factory for the protocol to https. To do this, simply call the SchemeRegistry.register()
method.
Then you need to create a DefaultHttpClient
with SingleClientConnManager
.
Also in the code below you can see that on default will also use our flag (ALLOW_ALL_HOSTNAME_VERIFIER
) by the method HttpsURLConnection.setDefaultHostnameVerifier()
Below code works for me:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
// Example send http request
final String url = "https://encrypted.google.com/";
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
Trust my own self-signed certificate in local network using Android Native, Android Studio and retrofit
Shlomi Katriel's answer was something I had already tried, but it led me to the solution indirectly. Please keep in mind that the only reason I was able to solve this was because I have root access to the server and can do with it as I please.
This
answer was basically the key to solving the whole thing. I will post all the steps in case someone else needs this.
Step 1
Create your self-signed certificate. In my case, I used the openssl utility. It is very important to include the -addext flag. Here is an example taken directly from the answer I linked above:
openssl req \
-newkey rsa:2048 \
-nodes \
-x509 \
-days 36500 -nodes \
-addext "subjectAltName = IP.1:1.2.3.4" \
-keyout /etc/ssl/private/nginx-selfsigned2.key \
-out /etc/ssl/certs/nginx-selfsigned2.crt
Replace 1.2.3.4 with the local ip of your server. This will include the server's local ip in the subjectAltName property of the certificate. Without this, you will keep getting the error "Hostname ... not verified ..."
Using the certificate in a running nginx instance is a different subject which can be done easily and there are plenty of resources online.
Step 2 Open android studio and create a new android resource directory (if you don't already have it) under res
named raw
. Inside this directory, copy the contents of the .crt file that the command above produced.
Step 3 Create an android resource directory under res
named xml
. In there, create a new xml file which in my case I called network_security_config.xml
. In there, I inserted the following:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="@raw/certificate"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
Instead of "certificate", use the filename of the certificate file you copied in step 2.
Step 4 Add android:networkSecurityConfig="@xml/network_security_config"
to the application element in your AndroidManifest.xml
Self-signed SSL acceptance on Android
I have this functionality in exchangeIt, which connects to Microsoft exchange via WebDav. Here's some code to create an HttpClient which will connect to self signed cert's via SSL:
SchemeRegistry schemeRegistry = new SchemeRegistry();
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
The EasySSLSocketFactory is here, and the EasyX509TrustManager is here.
The code for exchangeIt is open source, and hosted on googlecode here, if you have any issues. I'm not actively working on it anymore, but the code should work.
Note that since Android 2.2 the process has changed a bit, so check this to make the code above work.
How to enable a self-signed certificate for SSL sockets on Android?
Yes, you need to add the certificate to a custom KeyStore. It is basically a 4-step process:
- Obtain your server certificate.
- Import the server certificate to a keystore as a raw resource in your application. The KeyStore type must be BKS.
- Create your own TrustManager in your Java/Android program to load the certificate into a SSLContext.
- Use that SSLContext for your SSL connections.
See this link for detailed instructions and sample code:
http://randomizedsort.blogspot.com/2010/09/step-to-step-guide-to-programming.html
Good luck.
Nehc
Android - Obtain self-signed server certificate and add to trusted keystore
The simple solution
Here's a code example of a trust manager callback. From the callback you can either store the self-signed certificates or just accept them right away. But you SHOULD NOT do neither. By accepting self-signed certs, you are subject to connecting to fake or malicious servers which can steal personal data, install malware, and do other nasty things.
The better-than-simple solution
If a server offers a self-signed certificate that you, the developer, trust at compile time, you can bundle the cert into the app like you're already doing. It would be much better if the server had a CA-signed certificate, but if you really need to connect to a server that offers a self-signed cert, this will (have to) do.
A nicer solution
Never accept self-signed certificates in runtime. If you want to allow your users to connect to these kind of servers, you can show a warning message like "proceed at your own risk" before accepting the self-signed cert.
Using Android and a self signed certificate
I solved this problem by creating my own CA and add the public key of the root certificate to the keystore.
It's working like a charm, I just needed to create my own HostnameVerifier
because the I have no hostname to verify.
Related Topics
Android: Move a View on Touch Move (Action_Move)
Android Quick Actions UI Pattern
Difference Between Oncreate() and Onstart()
Android: Want to Set Custom Fonts for Whole Application Not Runtime
Receive Result from Dialogfragment
Manifest Merger Failed with Multiple Errors in Android Studio
How to Dynamically Load a Library at Runtime from an Android Application
How to View the SQLite Database on an Android Device
Gridlayout (Not Gridview) How to Stretch All Children Evenly
How to Programmatically Tell If a Bluetooth Device Is Connected
How to Programmatically Add Views to Views
How to Add an Array or Object to Sharedpreferences on Android
Eclipse Giving Error, Missing R.Java File After Recent Update
Custom Notification Layouts and Text Colors
How to Get Package Name from Anywhere
How to Detect Swipe Direction Between Left/Right and Up/Down