How can I pin a certificate with Square OKHTTP? - android

I think I need to create a new SSL Socket Factory?
Also, I don't want to use the global SSL Context (https://github.com/square/okhttp/issues/184) for obvious reasons.
thanks!
EDIT:
As of okhttp 2.1.0 you can pin certificates very easily.
See the source code here to get started

UPDATE FOR OKHTTP 3.0
OKHTTP 3.0 has built-in support for pinning certificates. Start off by pasting the following code:
String hostname = "yourdomain.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
client.newCall(request).execute();
This will fail because AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA is not a valid hash of your certificate. The exception thrown will have the correct hashes of your certificate:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
Peer certificate chain:
sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=publicobject.com, OU=PositiveSSL
sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA
sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority
sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root
Pinned certificates for publicobject.com:
sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
at okhttp3.CertificatePinner.check(CertificatePinner.java)
at okhttp3.Connection.upgradeToTls(Connection.java)
at okhttp3.Connection.connect(Connection.java)
at okhttp3.Connection.connectAndSetOwner(Connection.java)
Make sure you add these to your CertificatePinner object, and you have successfully pinned your certificate:
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.add("publicobject.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
.add("publicobject.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")
.add("publicobject.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=")
.build();
EVERYTHING PAST HERE IS FOR OLDER (2.x) VERSIONS OF OKHTTP
After reading this blog post I was able to modify the concept for use with OkHttp. You should use at least version 2.0 if you want to avoid using a global SSL context.
This modification applies only to the current instance of OkHttp, and changes that instance so that it only accepts certificates from the certificate specified. If you want other certificates (such as one from Twitter) to be accepted, you simply need to create a new OkHttp instance without the modifications described below.
1. Creating a TrustStore
In order to pin a certificate, you first need to create a truststore containing this certificate. To create the truststore we will use this handy script from nelenkov slightly modified for our purposes:
#!/bin/bash
if [ "$#" -ne 3 ]; then
echo "Usage: importcert.sh <CA cert PEM file> <bouncy castle jar> <keystore pass>"
exit 1
fi
CACERT=$1
BCJAR=$2
SECRET=$3
TRUSTSTORE=mytruststore.bks
ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`
if [ -f $TRUSTSTORE ]; then
rm $TRUSTSTORE || exit 1
fi
echo "Adding certificate to $TRUSTSTORE..."
keytool -import -v -trustcacerts -alias $ALIAS \
-file $CACERT \
-keystore $TRUSTSTORE -storetype BKS \
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath $BCJAR \
-storepass $SECRET
echo ""
echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
To run this script you need 3 things:
Make sure keytool (included in Android SDK) is on your $PATH.
Make sure you have the latest BouncyCastle jar file download in the same dir as the script. (Download here)
The certificate you want to pin.
Now run the script
./gentruststore.sh your_cert.pem bcprov-jdk15on-150.jar your_secret_pass
Type 'yes' to trust the certificate, and when complete mytruststore.bks will be generated in your current dir.
2. Apply your TrustStore to your Android project
Create a directory raw under your res folder. Copy mytruststore.bks here.
Now here's a very simple class that pins your cert to OkHttp
import android.content.Context;
import android.util.Log;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.InputStream;
import java.io.Reader;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
/**
* Created by martin on 02/06/14.
*/
public class Pinning {
Context context;
public static String TRUST_STORE_PASSWORD = "your_secret";
private static final String ENDPOINT = "https://api.yourdomain.com/";
public Pinning(Context c) {
this.context = c;
}
private SSLSocketFactory getPinnedCertSslSocketFactory(Context context) {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mytruststore);
trusted.load(in, TRUST_STORE_PASSWORD.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trusted);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
} catch (Exception e) {
Log.e("MyApp", e.getMessage(), e);
}
return null;
}
public void makeRequest() {
try {
OkHttpClient client = new OkHttpClient();
client.setSslSocketFactory(getPinnedCertSslSocketFactory(context));
Request request = new Request.Builder()
.url(ENDPOINT)
.build();
Response response = client.newCall(request).execute();
Log.d("MyApp", response.body().string());
} catch (Exception e) {
Log.e("MyApp", e.getMessage(), e);
}
}
}
As you can see we instantiate a new instance of OkHttpClient and call setSslSocketFactory, passing in a SSLSocketFactory with our custom truststore. Make sure you set TRUST_STORE_PASSWORD to the password you passed into the shell script. Your OkHttp instance should now only accept the certificate you specified.

This is easier than I thought with OkHttp.
Follow these steps:
1. Get the public sha1 keys.
The OkHttp documentation gives us a clear way to do this complete with sample code. In case it goes away, here it is pasted in below:
For example, to pin https://publicobject.com, start with a broken
configuration:
String hostname = "publicobject.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha1/BOGUSPIN")
.build();
OkHttpClient client = new OkHttpClient();
client.setCertificatePinner(certificatePinner);
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
client.newCall(request).execute();
As expected, this fails with a certificate pinning exception:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
Peer certificate chain:
sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=: CN=publicobject.com, OU=PositiveSSL
sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=: CN=COMODO RSA Domain Validation Secure Server CA
sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=: CN=COMODO RSA Certification Authority
sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=: CN=AddTrust External CA Root
Pinned certificates for publicobject.com:
sha1/BOGUSPIN
at com.squareup.okhttp.CertificatePinner.check(CertificatePinner.java)
at com.squareup.okhttp.Connection.upgradeToTls(Connection.java)
at com.squareup.okhttp.Connection.connect(Connection.java)
at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java)
Follow up by pasting the public key hashes from the exception into the certificate pinner's configuration:
Side note: If you are doing this on Android you will get a separate exception if you are doing this on a UI thread, so make sure you do this on a background thread.
2. Configure your OkHttp Client:
OkHttpClient client = new OkHttpClient();
client.setCertificatePinner(new CertificatePinner.Builder()
.add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build());
That's all there is to it!

If you don't have access to the domain (restricted access for example) and cant test bogus hash, but you have certificate file you can use openssl to retrieve it:
openssl x509 -in cert.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

To expand on the sample source code #Michael-barany shared, I have done some testing and it appears to be a misleading code sample. In the sample the code the exception noted 4 sha1 hashes from the certificate chain exception:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
Peer certificate chain:
sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=: CN=publicobject.com, OU=PositiveSSL
sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=: CN=COMODO RSA Domain Validation Secure Server CA
sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=: CN=COMODO RSA Certification Authority
sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=: CN=AddTrust External CA Root
then subsequently added all 4 sha1 public key hashes to the CertificatePinner Builder.
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("publicobject.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=")
.add("publicobject.com", "sha1/SXxoaOSEzPC6BgGmxAt/EAcsajw=")
.add("publicobject.com", "sha1/blhOM3W9V/bVQhsWAcLYwPU6n24=")
.add("publicobject.com", "sha1/T5x9IXmcrQ7YuQxXnxoCmeeQ84c=")
.build();
However, given tests I have performed and reviewing the code, only the first valid one would be interpreted, so you would be best suited to only include ONE of the hashes returned. You could use the most specific hash "DmxUShsZuNiqPQsX2Oi9uv2sCnw" for the precise site certificate... or you could use the most broad hash "T5x9IXmcrQ7YuQxXnxoCmeeQ84c" for the CA Root based on your desired security posture.

I found the example mentioned in Unknown certificate authority section of this link developer.android.com/training/articles/security-ssl very useful.
The SSLSocketFactory returned in context.getSocketFactory() can be then used to set to OkHttpClient in setSslSocketFactory() method.
Note : The Unknown certificate authority section also mentions the link to download a cert file to use and check this code.
Here is the sample method I've written to obtain the SSLSocketFactory
private SSLSocketFactory getSslSocketFactory() {
try {
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = getApplicationContext().getResources().openRawResource(R.raw.loadder);
Certificate ca = null;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} catch (CertificateException e) {
e.printStackTrace();
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
if (ca == null)
return 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);
return context.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Later I'm just setting this to OkHttpClient like this
httpClient.setSslSocketFactory(sslSocketFactory);
and then make the https call
httpClient.newCall(requestBuilder.build()).enqueue(callback);

Related

Android OkHttp TLS Mutual Auth - Client doesn't send Certificate to Server

I need some help with Android OkHttp client/server application. The problem is the following: it seems like my Android client doesn't send any certificate to the server after receiving a Certificate Request.
Here is my Android code:
private static SSLContext getContext(InputStream keystoreInputStream){
SSLContext sslContext = null;
try{
//==========
try {
// The keystore contains the CA cert and the Client cert
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try {
keyStore.load(keystoreInputStream, "MYPASS".toCharArray());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ksIn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
sslContext = SSLContext.getInstance("TLS");
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(keyStore, "MYPASS".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), tmf.getTrustManagers(), null);
} catch (Exception e) {
e.printStackTrace();
}
//==========
}catch (Exception e){
}
return sslContext;
}
And This is the wireshark session between Android Client (192.168.1.72) and Server (192.168.1.79):
Wireshark TLS session - CLIENT CERTIFICATE (empty)
As you can see the Server sends a Certificate Request but the client sends Certificate with lenght 0. Can you explain me how can I fix this? Thanks.
I finally found out that the problem was in my KeyStore and TrustStore files, they just were malformed.
I just tried to regenerate them using these simple passages:
Create a txt file containing your client certificate and the key (just copy-paste the key after the certificate).
Generate the KeyStore:
openssl pkcs12 -export -in <GENERATED_TXT_FILE> -out <MY_KEY_STORE>.pkcs12 -name <ALIAS> -noiter -nomaciter
Generate the TrustStore:
keytool -import -file <CA_CERT_FILE> -alias <ALIAS> -keystore <MY_TRUST_STORE>
I also referred to this implementation of an SSLTrustManagerHelper : SSLTrustManagerHelper class, I leave it here as I found it clean and easily understandable.
First off try the existing setup with a URL like https://server.cryptomix.com/secure. It should print out the client certificate that you send.
Secondly, you can implement a KeyManager yourself and see what is going on, even if it just decorates the Android KeyManager and logs the calls.
https://github.com/yschimke/okhttp/blob/c2d570dcf9c989a95f49f6b97d5df3488c191f73/regression-test/src/androidTest/java/okhttp/regression/keys/ClientAuthAndroidTest.java#L56
Lastly, you can try on the JDK for comparison. In this scenario you can enable SSL logging to see what is going on, but don't expect the same behaviour between JSSE and Android's Conscrypt provider.

HTTPS programmatically on Android (trusts all certs) [duplicate]

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

download image from server with https protocol in android [duplicate]

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

WebDav, Certificate not Trusted [duplicate]

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

accepting HTTPS connections with self-signed certificates

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

Categories

Resources