How do I accept a self-signed certificate in Java on Android?
A code sample would be perfect.
I've looked everywhere on the Internet and while some people claim to have found the solution, it either does not work or there is no sample code to back it up.
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.
As EJP correctly commented, "Readers should note that this technique is radically insecure. SSL is not secure unless at least one peer is authenticated. See RFC 2246."
Having said that, here's another way, without any extra classes:
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
private void trustEveryone() {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
public boolean verify(String hostname, SSLSession session) {
return true;
}});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
} catch (Exception e) { // should never happen
e.printStackTrace();
}
}
I faced this issue yesterday, while migrating our company's RESTful API to HTTPS, but using self-signed SSL certificates.
I've looking everywhere, but all the "correct" marked answers I've found consisted of disabling certificate validation, clearly overriding all the sense of SSL.
I finally came to a solution:
Create Local KeyStore
To enable your app to validate your self-signed certificates, you need to provide a custom keystore with the certificates in a manner that Android can trust your endpoint.
The format for such custom keystores is "BKS" from BouncyCastle, so you need the 1.46 version of BouncyCastleProvider that you can download here.
You also need your self-signed certificate, I will assume it's named self_cert.pem.
Now the command for creating your keystore is:
<!-- language: lang-sh -->
$ keytool -import -v -trustcacerts -alias 0 \
-file *PATH_TO_SELF_CERT.PEM* \
-keystore *PATH_TO_KEYSTORE* \
-storetype BKS \
-provider org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath *PATH_TO_bcprov-jdk15on-146.jar* \
-storepass *STOREPASS*
PATH_TO_KEYSTORE points to a file where your keystore will be created. It MUST NOT EXIST.
PATH_TO_bcprov-jdk15on-146.jar.JAR is the path to the downloaded .jar libary.
STOREPASS is your newly created keystore password.
Include KeyStore in your Application
Copy your newly created keystore from PATH_TO_KEYSTORE to res/raw/certs.bks (certs.bks is just the file name; you can use whatever name you wish)
Create a key in res/values/strings.xml with
<!-- language: lang-xml -->
<resources>
...
<string name="store_pass">*STOREPASS*</string>
...
</resources>
Create a this class that inherits DefaultHttpClient
import android.content.Context;
import android.util.Log;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
public class MyHttpClient extends DefaultHttpClient {
private static Context appContext = null;
private static HttpParams params = null;
private static SchemeRegistry schmReg = null;
private static Scheme httpsScheme = null;
private static Scheme httpScheme = null;
private static String TAG = "MyHttpClient";
public MyHttpClient(Context myContext) {
appContext = myContext;
if (httpScheme == null || httpsScheme == null) {
httpScheme = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
httpsScheme = new Scheme("https", mySSLSocketFactory(), 443);
}
getConnectionManager().getSchemeRegistry().register(httpScheme);
getConnectionManager().getSchemeRegistry().register(httpsScheme);
}
private SSLSocketFactory mySSLSocketFactory() {
SSLSocketFactory ret = null;
try {
final KeyStore ks = KeyStore.getInstance("BKS");
final InputStream inputStream = appContext.getResources().openRawResource(R.raw.certs);
ks.load(inputStream, appContext.getString(R.string.store_pass).toCharArray());
inputStream.close();
ret = new SSLSocketFactory(ks);
} catch (UnrecoverableKeyException ex) {
Log.d(TAG, ex.getMessage());
} catch (KeyStoreException ex) {
Log.d(TAG, ex.getMessage());
} catch (KeyManagementException ex) {
Log.d(TAG, ex.getMessage());
} catch (NoSuchAlgorithmException ex) {
Log.d(TAG, ex.getMessage());
} catch (IOException ex) {
Log.d(TAG, ex.getMessage());
} catch (Exception ex) {
Log.d(TAG, ex.getMessage());
} finally {
return ret;
}
}
}
Now simply use an instance of **MyHttpClient** as you would with **DefaultHttpClient** to make your HTTPS queries, and it will use and validate correctly your self-signed SSL certificates.
HttpResponse httpResponse;
HttpPost httpQuery = new HttpPost("https://yourserver.com");
... set up your query ...
MyHttpClient myClient = new MyHttpClient(myContext);
try{
httpResponse = myClient.(peticionHttp);
// Check for 200 OK code
if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
... do whatever you want with your response ...
}
}catch (Exception ex){
Log.d("httpError", ex.getMessage());
}
Unless I missed something, the other answers on this page are DANGEROUS, and are functionally equivalent to not using SSL at all. If you trust self-signed certificates without doing further checks to make sure the certificates are the ones that you are expecting, then anyone can create a self-signed certificate and can pretend to be your server. At that point, you have no real security.
The only legitimate way to do this (without writing a full SSL stack) is to add an additional trusted anchor to be trusted during the certificate verification process. Both involve hard-coding the trusted anchor certificate into your app and adding it to whatever trusted anchors that the OS provides (or else you won't be able to connect to your site if you get a real certificate).
I'm aware of two ways to do this:
Create a custom trust store as described at http://www.ibm.com/developerworks/java/library/j-customssl/#8
Create a custom instance of X509TrustManager and override the getAcceptedIssuers method to return an array that contains your certificate:
public X509Certificate[] getAcceptedIssuers()
{
X509Certificate[] trustedAnchors =
super.getAcceptedIssuers();
/* Create a new array with room for an additional trusted certificate. */
X509Certificate[] myTrustedAnchors = new X509Certificate[trustedAnchors.length + 1];
System.arraycopy(trustedAnchors, 0, myTrustedAnchors, 0, trustedAnchors.length);
/* Load your certificate.
Thanks to http://stackoverflow.com/questions/11857417/x509trustmanager-override-without-allowing-all-certs
for this bit.
*/
InputStream inStream = new FileInputStream("fileName-of-cert");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
inStream.close();
/* Add your anchor cert as the last item in the array. */
myTrustedAnchors[trustedAnchors.length] = cert;
return myTrustedAnchors;
}
Note that this code is completely untested and may not even compile, but should at least steer you in the right direction.
Brian Yarger's answer works in Android 2.2 as well if you modify the bigger createSocket method overload as follows. It took me a while to get self-signed SSLs working.
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
On Android, HttpProtocolParams accepts ProtocolVersion rather than HttpVersion.
ProtocolVersion pv = new ProtocolVersion("HTTP", 1, 1);
HttpProtocolParams.setVersion(params, pv);
#Chris - Posting this as an answer since I can't add comments (yet). I'm wondering if your approach is supposed to work when using a webView. I can't get it do so on Android 2.3 - instead I just get a white screen.
After some more searching, I came across this simple fix for handling SSL errors in a webView which worked like a charm for me.
In the handler I check to see if I'm in a special dev mode and call handler.proceed(), otherwise I call handler.cancel(). This allows me to do development against a self-signed cert on a local website.
There are a-lot alternatives for this use case. If you don't want to have any custom code in your code base such as custom TrustManager I would suggest to try GitHub - SSLContext Kickstart and the following code snippet:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart</artifactId>
<version>6.7.0</version>
</dependency>
SSL configuration
SSLFactory sslFactory = SSLFactory.builder()
.withUnsafeTrustMaterial()
.build();
SSLContext sslContext = sslFactory.getSslContext();
SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();
HttpClient configuration
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", sslSocketFactory, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
HttpClient httpClient = new DefaultHttpClient(ccm, params);
HttpsUrlConnection
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
Related
I am in middle of developing an app in android, which requires me sslhandshake with server, using KSOAP2 libraries.
I am able to achieve the same on http sites, but fails on HTTPS sites,saying "could not validate certificate".
Can anybody help out
Please note that at least prior to 2.3 Android versions don't have the root CA for the RapidSSL CA among others.
You can check the issuer of a problematic certificate with sites such as http://www.digicert.com/help/
Another quick check is to try to load a HTTPs page in the stock browser and see if it complains about the certificate.
If this does not match your situation then ignore this answer.
If you have a certificate signed by this CA you must either
Handle it explicitly in your app by doing something like Danieles answer, but actually also comparing the certificate to a stored one for RapidSSL (or whichever you use).
Add an intermediate certificate to the chain at the web server in question to make the RapidSSL certificate certified by GeoTrust.
Check out
http://code.google.com/p/android/issues/detail?id=10807
https://knowledge.rapidssl.com/support/ssl-certificate-support/index?page=content&id=AR1549
It may be because the site you are trying to access may not have CA. It only may only have self-signed certificate. That is a issue you will get when you dealing with self-signed certificate.
Try these links and show us what you have implemented already
http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html
http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
Can this code be of help?
https://github.com/mixare/mixare/blob/master/src/org/mixare/MixContext.java
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
public boolean verify(String hostname, SSLSession session) {
return true;
}});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
This code is used in mixare.org to accept self-signed certificates.
Please be aware that you are not safe from MITM attacks when using this approach.
HTH,
Daniele
You can Use SelfSignedCertificate. Just use this method as your HTTPClient:
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
I'm trying to make HTTPS connections, using HttpClient lib, but the problem is that, since the certificate isn't signed by a recognized Certificate Authority (CA) like Verisign,GlobalSIgn, etc., listed on the set of Android Trusted Certificates, I keep getting javax.net.ssl.SSLException: Not trusted server certificate.
I've seen solutions where you simply accept all certificates, but what if I want to ask the user?
I want to get a dialog similar to that of the browser, letting the user decide to continue or not. Preferably I'd like to use the same certificatestore as the browser. Any ideas?
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);
The following main steps are required to achieve a secured connection from Certification Authorities which are not considered as trusted by the android platform.
As requested by many users, I've mirrored the most important parts from my blog article here:
Grab all required certificates (root and any intermediate CA’s)
Create a keystore with keytool and the BouncyCastle provider and import the certs
Load the keystore in your android app and use it for the secured connections (I recommend to use the Apache HttpClient instead of the standard java.net.ssl.HttpsURLConnection (easier to understand, more performant)
Grab the certs
You have to obtain all certificates that build a chain from the endpoint certificate the whole way up to the Root CA. This means, any (if present) Intermediate CA certs and also the Root CA cert. You don’t need to obtain the endpoint certificate.
Create the keystore
Download the BouncyCastle Provider and store it to a known location.
Also ensure that you can invoke the keytool command (usually located under the bin folder of your JRE installation).
Now import the obtained certs (don’t import the endpoint cert) into a BouncyCastle formatted keystore.
I didn’t test it, but I think the order of importing the certificates is important. This means, import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.
With the following command a new keystore (if not already present) with the password mysecret will be created and the Intermediate CA certificate will be imported. I also defined the BouncyCastle provider, where it can be found on my file system and the keystore format. Execute this command for each certificate in the chain.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Should output the whole chain:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Now you can copy the keystore as a raw resource in your android app under res/raw/
Use the keystore in your app
First of all we have to create a custom Apache HttpClient that uses our keystore for HTTPS connections:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
We have created our custom HttpClient, now we can use it for secure connections. For example when we make a GET call to a REST resource:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
That's it ;)
If you have a custom/self-signed certificate on server that is not there on device, you can use the below class to load it and use it on client side in Android:
Place the certificate *.crt file in /res/raw so that it is available from R.raw.*
Use below class to obtain an HTTPClient or HttpsURLConnection which will have a socket factory using that certificate :
package com.example.customssl;
import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class CustomCAHttpsProvider {
/**
* Creates a {#link org.apache.http.client.HttpClient} which is configured to work with a custom authority
* certificate.
*
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http Client.
* #throws Exception If there is an error initializing the client.
*/
public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// init ssl socket factory with key store
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
// skip hostname security check if specified
if (allowAllHosts) {
sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
}
// basic http params for client
HttpParams params = new BasicHttpParams();
// normal scheme registry with our ssl socket factory for "https"
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
// create connection manager
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// create http client
return new DefaultHttpClient(cm, params);
}
/**
* Creates a {#link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
* certificate.
*
* #param urlString remote url string.
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http url connection.
* #throws Exception If there is an error initializing the connection.
*/
public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Create a connection from url
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
// skip hostname security check if specified
if (allowAllHosts) {
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
}
return urlConnection;
}
private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
// init a default key store
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// read and add certificate authority
Certificate cert = readCert(context, certRawResId);
keyStore.setCertificateEntry("ca", cert);
return keyStore;
}
private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
// read certificate resource
InputStream caInput = context.getResources().openRawResource(certResourceId);
Certificate ca;
try {
// generate a certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
return ca;
}
}
Key points:
Certificate objects are generated from .crt files.
A default KeyStore is created.
keyStore.setCertificateEntry("ca", cert) is adding certificate to key store under alias "ca". You modify the code to add more certificates (intermediate CA etc).
Main objective is to generate a SSLSocketFactory which can then be used by HTTPClient or HttpsURLConnection.
SSLSocketFactory can be configured further, for example to skip host name verification etc.
More information at : http://developer.android.com/training/articles/security-ssl.html
I was frustrated trying to connect my Android App to my RESTful service using https. Also I was a bit annoyed about all the answers that suggested to disable certificate checking altogether. If you do so, whats the point of https?
After googled about the topic for a while, I finally found this solution where external jars are not needed, just Android APIs. Thanks to Andrew Smith, who posted it on July, 2014
/**
* Set up a connection to myservice.domain using HTTPS. An entire function
* is needed to do this because myservice.domain has a self-signed certificate.
*
* The caller of the function would do something like:
* HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
* InputStream in = urlConnection.getInputStream();
* And read from that "in" as usual in Java
*
* Based on code from:
* https://developer.android.com/training/articles/security-ssl.html#SelfSigned
*/
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
try
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// My CRT file that I put in the assets folder
// I got this file by following these steps:
// * Go to https://littlesvr.ca using Firefox
// * Click the padlock/More/Security/View Certificate/Details/Export
// * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
// The MainActivity.context is declared as:
// public static Context context;
// And initialized in MainActivity.onCreate() as:
// MainActivity.context = getApplicationContext();
InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
Certificate ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
return urlConnection;
}
catch (Exception ex)
{
Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
return null;
}
}
It worked nice for my mockup App.
Google recommends the usage of Android Volley for HTTP/HTTPS connections, since that HttpClient is deprecated. So, you know the right choice :).
And also, NEVER NUKE SSL Certificates (NEVER!!!).
To nuke SSL Certificates, is totally against the purpose of SSL, which is promoting security. There's no sense of using SSL, if you're planning to bomb all SSL certificates that comes. A better solution would be creating a custom TrustManager on your App + using Android Volley for HTTP/HTTPS connections.
Here's a Gist which I created, with a basic LoginApp, performing HTTPS connections, using a Self-Signed Certificate on the server-side, accepted on the App.
Here's also another Gist that may help, for creating Self-Signed SSL Certificates for setting up on your Server and also using the certificate on your App. Very important: you must copy the .crt file which was generated by the script above, to the "raw" directory from your Android project.
The top answer didn´t work for me. After some investigation I found the required information on "Android Developer":
https://developer.android.com/training/articles/security-ssl.html#SelfSigned
Creating an empty implementation of X509TrustManager did the trick:
private static class MyTrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}
...
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] tmlist = {new MyTrustManager()};
context.init(null, tmlist, null);
conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
throw new IOException(e);
} catch (KeyManagementException e)
{
throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();
Please be aware that this empty implementation of TustManager is just an example and using it in a productive environment would cause a severe security threat!
Here's how you can add additional certificates to your KeyStore to avoid this problem: Trusting all certificates using HttpClient over HTTPS
It won't prompt the user like you ask, but it will make it less likely that the user will run into a "Not trusted server certificate" error.
Simplest way for create SSL certificate
Open Firefox (I suppose it's also possible with Chrome, but it's easier for me with FF)
Visit your development site with a self-signed SSL certificate.
Click on the certificate (next to the site name)
Click on "More information"
Click on "View certificate"
Click on "Details"
Click on "Export..."
Choose "X.509 Certificate whith chain (PEM)", select the folder and name to save it and click "Save"
Go to command line, to the directory where you downloaded the pem file and execute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"
Copy the .crt file to the root of the /sdcard folder inside your Android device
Inside your Android device, Settings > Security > Install from storage.
It should detect the certificate and let you add it to the device
Browse to your development site.
The first time it should ask you to confirm the security exception. That's all.
The certificate should work with any browser installed on your Android (Browser, Chrome, Opera, Dolphin...)
Remember that if you're serving your static files from a different domain (we all are page speed bitches) you also need to add the certificate for that domain.
I wrote small library ssl-utils-android to trust particular certificate on Android.
You can simply load any certificate by giving the filename from assets directory.
Usage:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
None of these fixes worked for my develop platform targeting SDK 16, Release 4.1.2, so I found a workaround.
My app stores data on server using "http://www.example.com/page.php?data=somedata"
Recently page.php was moved to "https://www.secure-example.com/page.php" and I keep getting "javax.net.ssl.SSLException: Not trusted server certificate".
Instead of accepting all certificates for only a single page, starting with this guide I solved my problem writing my own page.php published on "http://www.example.com/page.php"
<?php
caronte ("https://www.secure-example.com/page.php");
function caronte($url) {
// build curl request
$ch = curl_init();
foreach ($_POST as $a => $b) {
$post[htmlentities($a)]=htmlentities($b);
}
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));
// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
curl_close ($ch);
echo $server_output;
}
?>
Jan 19th, 2020 Self Signed Certificate ISSUE FIX:
To play video , image , calling webservice for any self signed certificate or connecting to any unsecured url just call this method before performing any action , it will fix your issue regarding certificate issue :
KOTLIN CODE
private fun disableSSLCertificateChecking() {
val hostnameVerifier = object: HostnameVerifier {
override fun verify(s:String, sslSession: SSLSession):Boolean {
return true
}
}
val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
//val acceptedIssuers:Array<X509Certificate> = null
#Throws(CertificateException::class)
override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
#Throws(CertificateException::class)
override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
})
try
{
val sc = SSLContext.getInstance("TLS")
sc.init(null, trustAllCerts, java.security.SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
}
catch (e: KeyManagementException) {
e.printStackTrace()
}
catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
}
Maybe this will helpful... it works on java clients using self-signed certificates (there is no check of the certificate). Be careful and use it only for development cases because that is no secure at all!!
How to ignore SSL certificate errors in Apache HttpClient 4.0
Hope it will works on Android just adding HttpClient library... good luck!!
This is problem resulting from lack of SNI(Server Name Identification) support inA,ndroid 2.x. I was struggling with this problem for a week until I came across the following question, which not only gives a good background of the problem but also provides a working and effective solution devoid of any security holes.
'No peer certificate' error in Android 2.3 but NOT in 4
I'm trying to make HTTPS connections, using HttpClient lib, but the problem is that, since the certificate isn't signed by a recognized Certificate Authority (CA) like Verisign,GlobalSIgn, etc., listed on the set of Android Trusted Certificates, I keep getting javax.net.ssl.SSLException: Not trusted server certificate.
I've seen solutions where you simply accept all certificates, but what if I want to ask the user?
I want to get a dialog similar to that of the browser, letting the user decide to continue or not. Preferably I'd like to use the same certificatestore as the browser. Any ideas?
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);
The following main steps are required to achieve a secured connection from Certification Authorities which are not considered as trusted by the android platform.
As requested by many users, I've mirrored the most important parts from my blog article here:
Grab all required certificates (root and any intermediate CA’s)
Create a keystore with keytool and the BouncyCastle provider and import the certs
Load the keystore in your android app and use it for the secured connections (I recommend to use the Apache HttpClient instead of the standard java.net.ssl.HttpsURLConnection (easier to understand, more performant)
Grab the certs
You have to obtain all certificates that build a chain from the endpoint certificate the whole way up to the Root CA. This means, any (if present) Intermediate CA certs and also the Root CA cert. You don’t need to obtain the endpoint certificate.
Create the keystore
Download the BouncyCastle Provider and store it to a known location.
Also ensure that you can invoke the keytool command (usually located under the bin folder of your JRE installation).
Now import the obtained certs (don’t import the endpoint cert) into a BouncyCastle formatted keystore.
I didn’t test it, but I think the order of importing the certificates is important. This means, import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.
With the following command a new keystore (if not already present) with the password mysecret will be created and the Intermediate CA certificate will be imported. I also defined the BouncyCastle provider, where it can be found on my file system and the keystore format. Execute this command for each certificate in the chain.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Should output the whole chain:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Now you can copy the keystore as a raw resource in your android app under res/raw/
Use the keystore in your app
First of all we have to create a custom Apache HttpClient that uses our keystore for HTTPS connections:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
We have created our custom HttpClient, now we can use it for secure connections. For example when we make a GET call to a REST resource:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
That's it ;)
If you have a custom/self-signed certificate on server that is not there on device, you can use the below class to load it and use it on client side in Android:
Place the certificate *.crt file in /res/raw so that it is available from R.raw.*
Use below class to obtain an HTTPClient or HttpsURLConnection which will have a socket factory using that certificate :
package com.example.customssl;
import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class CustomCAHttpsProvider {
/**
* Creates a {#link org.apache.http.client.HttpClient} which is configured to work with a custom authority
* certificate.
*
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http Client.
* #throws Exception If there is an error initializing the client.
*/
public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// init ssl socket factory with key store
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
// skip hostname security check if specified
if (allowAllHosts) {
sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
}
// basic http params for client
HttpParams params = new BasicHttpParams();
// normal scheme registry with our ssl socket factory for "https"
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
// create connection manager
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// create http client
return new DefaultHttpClient(cm, params);
}
/**
* Creates a {#link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
* certificate.
*
* #param urlString remote url string.
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http url connection.
* #throws Exception If there is an error initializing the connection.
*/
public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Create a connection from url
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
// skip hostname security check if specified
if (allowAllHosts) {
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
}
return urlConnection;
}
private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
// init a default key store
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// read and add certificate authority
Certificate cert = readCert(context, certRawResId);
keyStore.setCertificateEntry("ca", cert);
return keyStore;
}
private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
// read certificate resource
InputStream caInput = context.getResources().openRawResource(certResourceId);
Certificate ca;
try {
// generate a certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
return ca;
}
}
Key points:
Certificate objects are generated from .crt files.
A default KeyStore is created.
keyStore.setCertificateEntry("ca", cert) is adding certificate to key store under alias "ca". You modify the code to add more certificates (intermediate CA etc).
Main objective is to generate a SSLSocketFactory which can then be used by HTTPClient or HttpsURLConnection.
SSLSocketFactory can be configured further, for example to skip host name verification etc.
More information at : http://developer.android.com/training/articles/security-ssl.html
I was frustrated trying to connect my Android App to my RESTful service using https. Also I was a bit annoyed about all the answers that suggested to disable certificate checking altogether. If you do so, whats the point of https?
After googled about the topic for a while, I finally found this solution where external jars are not needed, just Android APIs. Thanks to Andrew Smith, who posted it on July, 2014
/**
* Set up a connection to myservice.domain using HTTPS. An entire function
* is needed to do this because myservice.domain has a self-signed certificate.
*
* The caller of the function would do something like:
* HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
* InputStream in = urlConnection.getInputStream();
* And read from that "in" as usual in Java
*
* Based on code from:
* https://developer.android.com/training/articles/security-ssl.html#SelfSigned
*/
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
try
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// My CRT file that I put in the assets folder
// I got this file by following these steps:
// * Go to https://littlesvr.ca using Firefox
// * Click the padlock/More/Security/View Certificate/Details/Export
// * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
// The MainActivity.context is declared as:
// public static Context context;
// And initialized in MainActivity.onCreate() as:
// MainActivity.context = getApplicationContext();
InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
Certificate ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
return urlConnection;
}
catch (Exception ex)
{
Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
return null;
}
}
It worked nice for my mockup App.
Google recommends the usage of Android Volley for HTTP/HTTPS connections, since that HttpClient is deprecated. So, you know the right choice :).
And also, NEVER NUKE SSL Certificates (NEVER!!!).
To nuke SSL Certificates, is totally against the purpose of SSL, which is promoting security. There's no sense of using SSL, if you're planning to bomb all SSL certificates that comes. A better solution would be creating a custom TrustManager on your App + using Android Volley for HTTP/HTTPS connections.
Here's a Gist which I created, with a basic LoginApp, performing HTTPS connections, using a Self-Signed Certificate on the server-side, accepted on the App.
Here's also another Gist that may help, for creating Self-Signed SSL Certificates for setting up on your Server and also using the certificate on your App. Very important: you must copy the .crt file which was generated by the script above, to the "raw" directory from your Android project.
The top answer didn´t work for me. After some investigation I found the required information on "Android Developer":
https://developer.android.com/training/articles/security-ssl.html#SelfSigned
Creating an empty implementation of X509TrustManager did the trick:
private static class MyTrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}
...
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] tmlist = {new MyTrustManager()};
context.init(null, tmlist, null);
conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
throw new IOException(e);
} catch (KeyManagementException e)
{
throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();
Please be aware that this empty implementation of TustManager is just an example and using it in a productive environment would cause a severe security threat!
Here's how you can add additional certificates to your KeyStore to avoid this problem: Trusting all certificates using HttpClient over HTTPS
It won't prompt the user like you ask, but it will make it less likely that the user will run into a "Not trusted server certificate" error.
Simplest way for create SSL certificate
Open Firefox (I suppose it's also possible with Chrome, but it's easier for me with FF)
Visit your development site with a self-signed SSL certificate.
Click on the certificate (next to the site name)
Click on "More information"
Click on "View certificate"
Click on "Details"
Click on "Export..."
Choose "X.509 Certificate whith chain (PEM)", select the folder and name to save it and click "Save"
Go to command line, to the directory where you downloaded the pem file and execute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"
Copy the .crt file to the root of the /sdcard folder inside your Android device
Inside your Android device, Settings > Security > Install from storage.
It should detect the certificate and let you add it to the device
Browse to your development site.
The first time it should ask you to confirm the security exception. That's all.
The certificate should work with any browser installed on your Android (Browser, Chrome, Opera, Dolphin...)
Remember that if you're serving your static files from a different domain (we all are page speed bitches) you also need to add the certificate for that domain.
I wrote small library ssl-utils-android to trust particular certificate on Android.
You can simply load any certificate by giving the filename from assets directory.
Usage:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
None of these fixes worked for my develop platform targeting SDK 16, Release 4.1.2, so I found a workaround.
My app stores data on server using "http://www.example.com/page.php?data=somedata"
Recently page.php was moved to "https://www.secure-example.com/page.php" and I keep getting "javax.net.ssl.SSLException: Not trusted server certificate".
Instead of accepting all certificates for only a single page, starting with this guide I solved my problem writing my own page.php published on "http://www.example.com/page.php"
<?php
caronte ("https://www.secure-example.com/page.php");
function caronte($url) {
// build curl request
$ch = curl_init();
foreach ($_POST as $a => $b) {
$post[htmlentities($a)]=htmlentities($b);
}
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));
// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
curl_close ($ch);
echo $server_output;
}
?>
Jan 19th, 2020 Self Signed Certificate ISSUE FIX:
To play video , image , calling webservice for any self signed certificate or connecting to any unsecured url just call this method before performing any action , it will fix your issue regarding certificate issue :
KOTLIN CODE
private fun disableSSLCertificateChecking() {
val hostnameVerifier = object: HostnameVerifier {
override fun verify(s:String, sslSession: SSLSession):Boolean {
return true
}
}
val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
//val acceptedIssuers:Array<X509Certificate> = null
#Throws(CertificateException::class)
override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
#Throws(CertificateException::class)
override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
})
try
{
val sc = SSLContext.getInstance("TLS")
sc.init(null, trustAllCerts, java.security.SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
}
catch (e: KeyManagementException) {
e.printStackTrace()
}
catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
}
Maybe this will helpful... it works on java clients using self-signed certificates (there is no check of the certificate). Be careful and use it only for development cases because that is no secure at all!!
How to ignore SSL certificate errors in Apache HttpClient 4.0
Hope it will works on Android just adding HttpClient library... good luck!!
This is problem resulting from lack of SNI(Server Name Identification) support inA,ndroid 2.x. I was struggling with this problem for a week until I came across the following question, which not only gives a good background of the problem but also provides a working and effective solution devoid of any security holes.
'No peer certificate' error in Android 2.3 but NOT in 4
I'm trying to make HTTPS connections, using HttpClient lib, but the problem is that, since the certificate isn't signed by a recognized Certificate Authority (CA) like Verisign,GlobalSIgn, etc., listed on the set of Android Trusted Certificates, I keep getting javax.net.ssl.SSLException: Not trusted server certificate.
I've seen solutions where you simply accept all certificates, but what if I want to ask the user?
I want to get a dialog similar to that of the browser, letting the user decide to continue or not. Preferably I'd like to use the same certificatestore as the browser. Any ideas?
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);
The following main steps are required to achieve a secured connection from Certification Authorities which are not considered as trusted by the android platform.
As requested by many users, I've mirrored the most important parts from my blog article here:
Grab all required certificates (root and any intermediate CA’s)
Create a keystore with keytool and the BouncyCastle provider and import the certs
Load the keystore in your android app and use it for the secured connections (I recommend to use the Apache HttpClient instead of the standard java.net.ssl.HttpsURLConnection (easier to understand, more performant)
Grab the certs
You have to obtain all certificates that build a chain from the endpoint certificate the whole way up to the Root CA. This means, any (if present) Intermediate CA certs and also the Root CA cert. You don’t need to obtain the endpoint certificate.
Create the keystore
Download the BouncyCastle Provider and store it to a known location.
Also ensure that you can invoke the keytool command (usually located under the bin folder of your JRE installation).
Now import the obtained certs (don’t import the endpoint cert) into a BouncyCastle formatted keystore.
I didn’t test it, but I think the order of importing the certificates is important. This means, import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.
With the following command a new keystore (if not already present) with the password mysecret will be created and the Intermediate CA certificate will be imported. I also defined the BouncyCastle provider, where it can be found on my file system and the keystore format. Execute this command for each certificate in the chain.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Should output the whole chain:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Now you can copy the keystore as a raw resource in your android app under res/raw/
Use the keystore in your app
First of all we have to create a custom Apache HttpClient that uses our keystore for HTTPS connections:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
We have created our custom HttpClient, now we can use it for secure connections. For example when we make a GET call to a REST resource:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
That's it ;)
If you have a custom/self-signed certificate on server that is not there on device, you can use the below class to load it and use it on client side in Android:
Place the certificate *.crt file in /res/raw so that it is available from R.raw.*
Use below class to obtain an HTTPClient or HttpsURLConnection which will have a socket factory using that certificate :
package com.example.customssl;
import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class CustomCAHttpsProvider {
/**
* Creates a {#link org.apache.http.client.HttpClient} which is configured to work with a custom authority
* certificate.
*
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http Client.
* #throws Exception If there is an error initializing the client.
*/
public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// init ssl socket factory with key store
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
// skip hostname security check if specified
if (allowAllHosts) {
sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
}
// basic http params for client
HttpParams params = new BasicHttpParams();
// normal scheme registry with our ssl socket factory for "https"
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
// create connection manager
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// create http client
return new DefaultHttpClient(cm, params);
}
/**
* Creates a {#link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
* certificate.
*
* #param urlString remote url string.
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http url connection.
* #throws Exception If there is an error initializing the connection.
*/
public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Create a connection from url
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
// skip hostname security check if specified
if (allowAllHosts) {
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
}
return urlConnection;
}
private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
// init a default key store
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// read and add certificate authority
Certificate cert = readCert(context, certRawResId);
keyStore.setCertificateEntry("ca", cert);
return keyStore;
}
private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
// read certificate resource
InputStream caInput = context.getResources().openRawResource(certResourceId);
Certificate ca;
try {
// generate a certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
return ca;
}
}
Key points:
Certificate objects are generated from .crt files.
A default KeyStore is created.
keyStore.setCertificateEntry("ca", cert) is adding certificate to key store under alias "ca". You modify the code to add more certificates (intermediate CA etc).
Main objective is to generate a SSLSocketFactory which can then be used by HTTPClient or HttpsURLConnection.
SSLSocketFactory can be configured further, for example to skip host name verification etc.
More information at : http://developer.android.com/training/articles/security-ssl.html
I was frustrated trying to connect my Android App to my RESTful service using https. Also I was a bit annoyed about all the answers that suggested to disable certificate checking altogether. If you do so, whats the point of https?
After googled about the topic for a while, I finally found this solution where external jars are not needed, just Android APIs. Thanks to Andrew Smith, who posted it on July, 2014
/**
* Set up a connection to myservice.domain using HTTPS. An entire function
* is needed to do this because myservice.domain has a self-signed certificate.
*
* The caller of the function would do something like:
* HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
* InputStream in = urlConnection.getInputStream();
* And read from that "in" as usual in Java
*
* Based on code from:
* https://developer.android.com/training/articles/security-ssl.html#SelfSigned
*/
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
try
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// My CRT file that I put in the assets folder
// I got this file by following these steps:
// * Go to https://littlesvr.ca using Firefox
// * Click the padlock/More/Security/View Certificate/Details/Export
// * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
// The MainActivity.context is declared as:
// public static Context context;
// And initialized in MainActivity.onCreate() as:
// MainActivity.context = getApplicationContext();
InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
Certificate ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
return urlConnection;
}
catch (Exception ex)
{
Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
return null;
}
}
It worked nice for my mockup App.
Google recommends the usage of Android Volley for HTTP/HTTPS connections, since that HttpClient is deprecated. So, you know the right choice :).
And also, NEVER NUKE SSL Certificates (NEVER!!!).
To nuke SSL Certificates, is totally against the purpose of SSL, which is promoting security. There's no sense of using SSL, if you're planning to bomb all SSL certificates that comes. A better solution would be creating a custom TrustManager on your App + using Android Volley for HTTP/HTTPS connections.
Here's a Gist which I created, with a basic LoginApp, performing HTTPS connections, using a Self-Signed Certificate on the server-side, accepted on the App.
Here's also another Gist that may help, for creating Self-Signed SSL Certificates for setting up on your Server and also using the certificate on your App. Very important: you must copy the .crt file which was generated by the script above, to the "raw" directory from your Android project.
The top answer didn´t work for me. After some investigation I found the required information on "Android Developer":
https://developer.android.com/training/articles/security-ssl.html#SelfSigned
Creating an empty implementation of X509TrustManager did the trick:
private static class MyTrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}
...
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] tmlist = {new MyTrustManager()};
context.init(null, tmlist, null);
conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
throw new IOException(e);
} catch (KeyManagementException e)
{
throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();
Please be aware that this empty implementation of TustManager is just an example and using it in a productive environment would cause a severe security threat!
Here's how you can add additional certificates to your KeyStore to avoid this problem: Trusting all certificates using HttpClient over HTTPS
It won't prompt the user like you ask, but it will make it less likely that the user will run into a "Not trusted server certificate" error.
Simplest way for create SSL certificate
Open Firefox (I suppose it's also possible with Chrome, but it's easier for me with FF)
Visit your development site with a self-signed SSL certificate.
Click on the certificate (next to the site name)
Click on "More information"
Click on "View certificate"
Click on "Details"
Click on "Export..."
Choose "X.509 Certificate whith chain (PEM)", select the folder and name to save it and click "Save"
Go to command line, to the directory where you downloaded the pem file and execute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"
Copy the .crt file to the root of the /sdcard folder inside your Android device
Inside your Android device, Settings > Security > Install from storage.
It should detect the certificate and let you add it to the device
Browse to your development site.
The first time it should ask you to confirm the security exception. That's all.
The certificate should work with any browser installed on your Android (Browser, Chrome, Opera, Dolphin...)
Remember that if you're serving your static files from a different domain (we all are page speed bitches) you also need to add the certificate for that domain.
I wrote small library ssl-utils-android to trust particular certificate on Android.
You can simply load any certificate by giving the filename from assets directory.
Usage:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
None of these fixes worked for my develop platform targeting SDK 16, Release 4.1.2, so I found a workaround.
My app stores data on server using "http://www.example.com/page.php?data=somedata"
Recently page.php was moved to "https://www.secure-example.com/page.php" and I keep getting "javax.net.ssl.SSLException: Not trusted server certificate".
Instead of accepting all certificates for only a single page, starting with this guide I solved my problem writing my own page.php published on "http://www.example.com/page.php"
<?php
caronte ("https://www.secure-example.com/page.php");
function caronte($url) {
// build curl request
$ch = curl_init();
foreach ($_POST as $a => $b) {
$post[htmlentities($a)]=htmlentities($b);
}
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));
// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
curl_close ($ch);
echo $server_output;
}
?>
Jan 19th, 2020 Self Signed Certificate ISSUE FIX:
To play video , image , calling webservice for any self signed certificate or connecting to any unsecured url just call this method before performing any action , it will fix your issue regarding certificate issue :
KOTLIN CODE
private fun disableSSLCertificateChecking() {
val hostnameVerifier = object: HostnameVerifier {
override fun verify(s:String, sslSession: SSLSession):Boolean {
return true
}
}
val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
//val acceptedIssuers:Array<X509Certificate> = null
#Throws(CertificateException::class)
override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
#Throws(CertificateException::class)
override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
})
try
{
val sc = SSLContext.getInstance("TLS")
sc.init(null, trustAllCerts, java.security.SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
}
catch (e: KeyManagementException) {
e.printStackTrace()
}
catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
}
Maybe this will helpful... it works on java clients using self-signed certificates (there is no check of the certificate). Be careful and use it only for development cases because that is no secure at all!!
How to ignore SSL certificate errors in Apache HttpClient 4.0
Hope it will works on Android just adding HttpClient library... good luck!!
This is problem resulting from lack of SNI(Server Name Identification) support inA,ndroid 2.x. I was struggling with this problem for a week until I came across the following question, which not only gives a good background of the problem but also provides a working and effective solution devoid of any security holes.
'No peer certificate' error in Android 2.3 but NOT in 4
I'm trying to make HTTPS connections, using HttpClient lib, but the problem is that, since the certificate isn't signed by a recognized Certificate Authority (CA) like Verisign,GlobalSIgn, etc., listed on the set of Android Trusted Certificates, I keep getting javax.net.ssl.SSLException: Not trusted server certificate.
I've seen solutions where you simply accept all certificates, but what if I want to ask the user?
I want to get a dialog similar to that of the browser, letting the user decide to continue or not. Preferably I'd like to use the same certificatestore as the browser. Any ideas?
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);
The following main steps are required to achieve a secured connection from Certification Authorities which are not considered as trusted by the android platform.
As requested by many users, I've mirrored the most important parts from my blog article here:
Grab all required certificates (root and any intermediate CA’s)
Create a keystore with keytool and the BouncyCastle provider and import the certs
Load the keystore in your android app and use it for the secured connections (I recommend to use the Apache HttpClient instead of the standard java.net.ssl.HttpsURLConnection (easier to understand, more performant)
Grab the certs
You have to obtain all certificates that build a chain from the endpoint certificate the whole way up to the Root CA. This means, any (if present) Intermediate CA certs and also the Root CA cert. You don’t need to obtain the endpoint certificate.
Create the keystore
Download the BouncyCastle Provider and store it to a known location.
Also ensure that you can invoke the keytool command (usually located under the bin folder of your JRE installation).
Now import the obtained certs (don’t import the endpoint cert) into a BouncyCastle formatted keystore.
I didn’t test it, but I think the order of importing the certificates is important. This means, import the lowermost Intermediate CA certificate first and then all the way up to the Root CA certificate.
With the following command a new keystore (if not already present) with the password mysecret will be created and the Intermediate CA certificate will be imported. I also defined the BouncyCastle provider, where it can be found on my file system and the keystore format. Execute this command for each certificate in the chain.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Verify if the certificates were imported correctly into the keystore:
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
Should output the whole chain:
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
Now you can copy the keystore as a raw resource in your android app under res/raw/
Use the keystore in your app
First of all we have to create a custom Apache HttpClient that uses our keystore for HTTPS connections:
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
We have created our custom HttpClient, now we can use it for secure connections. For example when we make a GET call to a REST resource:
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
That's it ;)
If you have a custom/self-signed certificate on server that is not there on device, you can use the below class to load it and use it on client side in Android:
Place the certificate *.crt file in /res/raw so that it is available from R.raw.*
Use below class to obtain an HTTPClient or HttpsURLConnection which will have a socket factory using that certificate :
package com.example.customssl;
import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
public class CustomCAHttpsProvider {
/**
* Creates a {#link org.apache.http.client.HttpClient} which is configured to work with a custom authority
* certificate.
*
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http Client.
* #throws Exception If there is an error initializing the client.
*/
public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// init ssl socket factory with key store
SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);
// skip hostname security check if specified
if (allowAllHosts) {
sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
}
// basic http params for client
HttpParams params = new BasicHttpParams();
// normal scheme registry with our ssl socket factory for "https"
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
// create connection manager
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
// create http client
return new DefaultHttpClient(cm, params);
}
/**
* Creates a {#link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
* certificate.
*
* #param urlString remote url string.
* #param context Application Context
* #param certRawResId R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
* #param allowAllHosts If true then client will not check server against host names of certificate.
* #return Http url connection.
* #throws Exception If there is an error initializing the connection.
*/
public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
boolean allowAllHosts) throws Exception {
// build key store with ca certificate
KeyStore keyStore = buildKeyStore(context, certRawResId);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Create a connection from url
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
// skip hostname security check if specified
if (allowAllHosts) {
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
}
return urlConnection;
}
private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
// init a default key store
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// read and add certificate authority
Certificate cert = readCert(context, certRawResId);
keyStore.setCertificateEntry("ca", cert);
return keyStore;
}
private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {
// read certificate resource
InputStream caInput = context.getResources().openRawResource(certResourceId);
Certificate ca;
try {
// generate a certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
return ca;
}
}
Key points:
Certificate objects are generated from .crt files.
A default KeyStore is created.
keyStore.setCertificateEntry("ca", cert) is adding certificate to key store under alias "ca". You modify the code to add more certificates (intermediate CA etc).
Main objective is to generate a SSLSocketFactory which can then be used by HTTPClient or HttpsURLConnection.
SSLSocketFactory can be configured further, for example to skip host name verification etc.
More information at : http://developer.android.com/training/articles/security-ssl.html
I was frustrated trying to connect my Android App to my RESTful service using https. Also I was a bit annoyed about all the answers that suggested to disable certificate checking altogether. If you do so, whats the point of https?
After googled about the topic for a while, I finally found this solution where external jars are not needed, just Android APIs. Thanks to Andrew Smith, who posted it on July, 2014
/**
* Set up a connection to myservice.domain using HTTPS. An entire function
* is needed to do this because myservice.domain has a self-signed certificate.
*
* The caller of the function would do something like:
* HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
* InputStream in = urlConnection.getInputStream();
* And read from that "in" as usual in Java
*
* Based on code from:
* https://developer.android.com/training/articles/security-ssl.html#SelfSigned
*/
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
try
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// My CRT file that I put in the assets folder
// I got this file by following these steps:
// * Go to https://littlesvr.ca using Firefox
// * Click the padlock/More/Security/View Certificate/Details/Export
// * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
// The MainActivity.context is declared as:
// public static Context context;
// And initialized in MainActivity.onCreate() as:
// MainActivity.context = getApplicationContext();
InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
Certificate ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL(urlString);
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
return urlConnection;
}
catch (Exception ex)
{
Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
return null;
}
}
It worked nice for my mockup App.
Google recommends the usage of Android Volley for HTTP/HTTPS connections, since that HttpClient is deprecated. So, you know the right choice :).
And also, NEVER NUKE SSL Certificates (NEVER!!!).
To nuke SSL Certificates, is totally against the purpose of SSL, which is promoting security. There's no sense of using SSL, if you're planning to bomb all SSL certificates that comes. A better solution would be creating a custom TrustManager on your App + using Android Volley for HTTP/HTTPS connections.
Here's a Gist which I created, with a basic LoginApp, performing HTTPS connections, using a Self-Signed Certificate on the server-side, accepted on the App.
Here's also another Gist that may help, for creating Self-Signed SSL Certificates for setting up on your Server and also using the certificate on your App. Very important: you must copy the .crt file which was generated by the script above, to the "raw" directory from your Android project.
The top answer didn´t work for me. After some investigation I found the required information on "Android Developer":
https://developer.android.com/training/articles/security-ssl.html#SelfSigned
Creating an empty implementation of X509TrustManager did the trick:
private static class MyTrustManager implements X509TrustManager
{
#Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException
{
}
#Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}
...
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] tmlist = {new MyTrustManager()};
context.init(null, tmlist, null);
conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
throw new IOException(e);
} catch (KeyManagementException e)
{
throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();
Please be aware that this empty implementation of TustManager is just an example and using it in a productive environment would cause a severe security threat!
Here's how you can add additional certificates to your KeyStore to avoid this problem: Trusting all certificates using HttpClient over HTTPS
It won't prompt the user like you ask, but it will make it less likely that the user will run into a "Not trusted server certificate" error.
Simplest way for create SSL certificate
Open Firefox (I suppose it's also possible with Chrome, but it's easier for me with FF)
Visit your development site with a self-signed SSL certificate.
Click on the certificate (next to the site name)
Click on "More information"
Click on "View certificate"
Click on "Details"
Click on "Export..."
Choose "X.509 Certificate whith chain (PEM)", select the folder and name to save it and click "Save"
Go to command line, to the directory where you downloaded the pem file and execute "openssl x509 -inform PEM -outform DM -in .pem -out .crt"
Copy the .crt file to the root of the /sdcard folder inside your Android device
Inside your Android device, Settings > Security > Install from storage.
It should detect the certificate and let you add it to the device
Browse to your development site.
The first time it should ask you to confirm the security exception. That's all.
The certificate should work with any browser installed on your Android (Browser, Chrome, Opera, Dolphin...)
Remember that if you're serving your static files from a different domain (we all are page speed bitches) you also need to add the certificate for that domain.
I wrote small library ssl-utils-android to trust particular certificate on Android.
You can simply load any certificate by giving the filename from assets directory.
Usage:
OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
None of these fixes worked for my develop platform targeting SDK 16, Release 4.1.2, so I found a workaround.
My app stores data on server using "http://www.example.com/page.php?data=somedata"
Recently page.php was moved to "https://www.secure-example.com/page.php" and I keep getting "javax.net.ssl.SSLException: Not trusted server certificate".
Instead of accepting all certificates for only a single page, starting with this guide I solved my problem writing my own page.php published on "http://www.example.com/page.php"
<?php
caronte ("https://www.secure-example.com/page.php");
function caronte($url) {
// build curl request
$ch = curl_init();
foreach ($_POST as $a => $b) {
$post[htmlentities($a)]=htmlentities($b);
}
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));
// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec ($ch);
curl_close ($ch);
echo $server_output;
}
?>
Jan 19th, 2020 Self Signed Certificate ISSUE FIX:
To play video , image , calling webservice for any self signed certificate or connecting to any unsecured url just call this method before performing any action , it will fix your issue regarding certificate issue :
KOTLIN CODE
private fun disableSSLCertificateChecking() {
val hostnameVerifier = object: HostnameVerifier {
override fun verify(s:String, sslSession: SSLSession):Boolean {
return true
}
}
val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
//val acceptedIssuers:Array<X509Certificate> = null
#Throws(CertificateException::class)
override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
#Throws(CertificateException::class)
override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
}
})
try
{
val sc = SSLContext.getInstance("TLS")
sc.init(null, trustAllCerts, java.security.SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
}
catch (e: KeyManagementException) {
e.printStackTrace()
}
catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
}
Maybe this will helpful... it works on java clients using self-signed certificates (there is no check of the certificate). Be careful and use it only for development cases because that is no secure at all!!
How to ignore SSL certificate errors in Apache HttpClient 4.0
Hope it will works on Android just adding HttpClient library... good luck!!
This is problem resulting from lack of SNI(Server Name Identification) support inA,ndroid 2.x. I was struggling with this problem for a week until I came across the following question, which not only gives a good background of the problem but also provides a working and effective solution devoid of any security holes.
'No peer certificate' error in Android 2.3 but NOT in 4