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

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.

Related

Okhttp 3 (android) : connecting to ip address with self signed ssl

I am currently attempting to connect to a server which has no domain name and is only reachable by its ip address. I previously attempted to do it by using the library volley, but after spending a day of research I couldn't figure out why the ssl handshake wouldn't work. after switching to Okhttp I got the warning:
javax.net.ssl.SSLPeerUnverifiedException: Hostname 185.101.92.193 not verified:
certificate: sha256/QMgPlAslWrBi1dd/P17AKxJCniO2RfHQ5MufVO5Xji4=
DN: 1.2.840.113549.1.9.1=#1619626c61636b6a61636b34323636323440676d61696c2e636f6d,CN=185.101.92.193,O=Internet Widgits Pty Ltd,L=Berlin,ST=Berlin,C=DE
subjectAltNames: []
Now this problem has already been addressed on github: https://github.com/square/okhttp/issues/1467
I have "resolved" the problem with the following code (look at HostnameVerifier at the bottom):
// loading CAs from an InputStream
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream cert = context.getResources().openRawResource(R.raw.servercert);
Certificate ca;
try {
ca = cf.generateCertificate(cert);
} finally {
cert.close();
}
// creating a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// creating a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// creating an SSLSocketFactory that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
client = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory())
.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String s, SSLSession sslSession) {
if(s.equals(myIPAddress)){
return true;
}else{
return false;
}
}
})
.build();
}catch (Exception e){
e.printStackTrace();
}
Now this kinda looks like bad practice to me and my actual question is: what problems could arise from implementing the HostnameVerifier like this (security-wise) and how could I solve this matter in a more sophisticated way?
There is nothing to do with the domain name, the only issue is that your application (android) can't verify the certificate because it's private (self signed certificate). What you did in your code is just trying to bypass the validation process by overriding the SSLFactory and created a new one that uses your CAs.
Check android documentation below:
https://developer.android.com/training/articles/security-ssl.html#CommonProblems
You can continue of what you have. or buy a certificate and then there is no need for this code at all.

ssl android certificate with volley

i have implemented the certificate and keystore to my app and succeeded in making request to my server , but now i want to accept another server's HTTPS (for online payment) to be able to integrate it in my app but volley says that it doesn't accept it , can i accept this domain without their keystore
and this is my code for accepting my server's certificate
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 = getApplicationContext().getResources().openRawResource(R.raw.keystore);
try {
// Initialize the keystore with the provided trusted certificates
// Provide the password of the keystore
trusted.load(in, KEYSTORE_PASSWORD);
} finally {
in.close();
}
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trusted);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory sf = context.getSocketFactory();
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}

SSL Pinning Certificate

public static SSLContext getSSL() {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
AssetManager assetManager = App.getAppContext()
.getAssets();
InputStream caInput = assetManager.open("cert.pem");
java.security.cert.X509Certificate ca = null;
try {
ca = (java.security.cert.X509Certificate) cf
.generateCertificate(caInput);
} catch (Exception er) {
} finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca",
ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context;
} catch (Exception e1) {
return null;
}
}
Ok this is how i do SSL Pinning in my Android application, and it all works perfect. So, What is the problem I have? I have cert.pem in my assets folder, what If I want to update my certificate? I will have to publish a new app on the store just for that. I dont want to do that, I want to know whats best way to handle such issue? Shall I download the certificate from somewhere and use it, or is there a way I can specify it via google play store and it can read it from there instead of assets folder? My goal is to avoid publishing new android app everytime i change the certificate.
The point of certificate pinning is to mitigate man-in-the-middle (MITM) attacks. If you download the pinned certificate from a non-pinned source, you're not really any better off preventing MITM as this download source becomes MITM target.
Therefore, just ship your app with the pinnings you want.
Options to mitigate the update issue:
Self-generate or purchase a certificate with a long validity period so you don't have to update that often.
If you are using a purchased CA-backed certificate, don't pin the certificate itself but the CA's root certificate that is valid for decades. Of course this enables MITM with a certificate for your domain signed with that CA, but at least you're reducing the number of CAs you need to trust to only one.

Configuring SSL client certificate in android app for client authentication in web server on tomcat

I installed apache server locally on my computer and running . I started with SSL server certificate for server authentication. To do this i added the server keystore path to the server.xml file of the tomcat and server certificate to truststore of SSL context in android app.Its working perfectly fine.
Now I need to configure the same for client authentication. For that I created a client keystore and stored that keystore in the resources/raw folder of android app and put that in keystore of the android app.
I created keystore for server and client using the below commands .
keytool -genkey -alias server -keyalg RSA -keystore server.jks
keytool -genkey -alias client -keyalg RSA -keystore client.jks
keytool -export -file server.cert -keystore server.jks -storepass password -alias server
keytool -export -file client.cert -keystore client.jks -storepass password -alias client
So i created 2 keystores , one for client and other for server , client.jks and server.jks . And i have client.cer and server.cer certificates exported from the corresponding keystore.
Client (Android application code) used to configure the SSL context . I have stored client.jks and server.cer files in the res/raw folder and referring that in the below code.
public HttpClient myHttpsClient() {
HttpClient client = null;
char[] passphrase = "password".toCharArray();
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertificateFactory clientcf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(R.raw.server);
InputStream clientcert = context.getResources().openRawResource(R.raw.client);
Certificate ca;
Certificate clientca;
try {
clientca = clientcf.generateCertificate(clientcert);
ca = cf.generateCertificate(caInput);
System.out.println("ca="+ ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
clientcert.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStoreclient = KeyStore.getInstance(keyStoreType);
keyStoreclient.load(null, null);
keyStoreclient.setCertificateEntry("ca", clientca);
// Create a KeyStore containing our trusted CAs
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String kmfAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlgorithm);
kmf.init(keyStoreclient,passphrase);
// 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(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
MySSLSocketFactory socketFactory = new MySSLSocketFactory(context);//,new BrowserCompatHostnameVerifier());
client = createHttps(socketFactory);
} catch (Exception e) {
e.printStackTrace();
}
return client;
Now the server is configured as below .
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false" truststoreFile="/Users/prabhuraj/client.cer"
truststorePass="password" disableUploadTimeout="true" enableLookups="false" maxThreads="25"
port="8443" keystoreFile="/Users/prabhuraj/server.jks" keystorePass="password"
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https"
secure="true" sslProtocol="TLS" />
After configuring as above. SSL handshake is failing . Can someone please let me know whether i am configuring wrongly? Thanks in advance.
You didnt use your KeyManagerFactory to init SSLContext,
change:
context.init(null, tmf.getTrustManagers(), null);
to
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
However, your certificate used for client auth, will need it's private key. Look at this post for explaination: https://stackoverflow.com/a/11199270/2762154

How can I pin a certificate with Square OKHTTP?

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);

Categories

Resources