Self-Signed Ssl Acceptance on Android

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:

  1. Obtain your server certificate.
  2. Import the server certificate to a keystore as a raw resource in your application. The KeyStore type must be BKS.
  3. Create your own TrustManager in your Java/Android program to load the certificate into a SSLContext.
  4. 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



Leave a reply



Submit