Using Client/Server Certificates for Two Way Authentication Ssl Socket on Android

Using client/server certificates for two way authentication SSL socket on Android

Android supports certificates in the BKS, P12 and other formats.

For BKS format:
Use portecle to convert your certificates (.p12 and .crt) to .bks.

You need 2 files in your /res/raw folder:
truststore.bks trust certificate for the server (converted from .cer file)

client.bks/client.p12 - the client certificate (converted from a .p12 file that contains the client certificate and the client key)

import java.io.*;
import java.security.KeyStore;

import javax.net.ssl.*;

import org.apache.http.*;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.*;
import org.apache.http.conn.scheme.*;
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.*;

import android.app.Activity;
import android.os.Bundle;

public class SslTestActivity extends Activity {

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

try {
// setup truststore to provide trust for the server certificate

// load truststore certificate
InputStream clientTruststoreIs = getResources().openRawResource(R.raw.truststore);
KeyStore trustStore = null;
trustStore = KeyStore.getInstance("BKS");
trustStore.load(clientTruststoreIs, "MyPassword".toCharArray());

System.out.println("Loaded server certificates: " + trustStore.size());

// initialize trust manager factory with the read truststore
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);

// setup client certificate

// load client certificate
InputStream keyStoreStream = getResources().openRawResource(R.raw.client);
KeyStore keyStore = null;
keyStore = KeyStore.getInstance("BKS");
keyStore.load(keyStoreStream, "MyPassword".toCharArray());

System.out.println("Loaded client certificates: " + keyStore.size());

// initialize key manager factory with the read client certificate
KeyManagerFactory keyManagerFactory = null;
keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "MyPassword".toCharArray());

// initialize SSLSocketFactory to use the certificates
SSLSocketFactory socketFactory = null;
socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "MyTestPassword2010",
trustStore, null, null);

// Set basic data
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUseExpectContinue(params, true);
HttpProtocolParams.setUserAgent(params, "Android app/1.0.0");

// Make pool
ConnPerRoute connPerRoute = new ConnPerRouteBean(12);
ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);
ConnManagerParams.setMaxTotalConnections(params, 20);

// Set timeout
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, 20 * 1000);
HttpConnectionParams.setSoTimeout(params, 20 * 1000);
HttpConnectionParams.setSocketBufferSize(params, 8192);

// Some client params
HttpClientParams.setRedirecting(params, false);

// Register http/s shemas!
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", socketFactory, 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);
DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params);

HttpGet httpGet = new HttpGet("https://server/path/service.wsdl");
HttpResponse response = sClient.execute(httpGet);
HttpEntity httpEntity = response.getEntity();

InputStream is = httpEntity.getContent();
BufferedReader read = new BufferedReader(new InputStreamReader(is));
String query = null;
while ((query = read.readLine()) != null)
System.out.println(query);

} catch (Exception e) {
e.printStackTrace();
}
}

}

Update:

You can also load .crt files for the trust store directly without converting them to BKS:

    private static KeyStore loadTrustStore(String[] certificateFilenames) {
AssetManager assetsManager = GirdersApp.getInstance().getAssets();

int length = certificateFilenames.length;
List<Certificate> certificates = new ArrayList<Certificate>(length);
for (String certificateFilename : certificateFilenames) {
InputStream is;
try {
is = assetsManager.open(certificateFilename, AssetManager.ACCESS_BUFFER);
Certificate certificate = KeyStoreManager.loadX509Certificate(is);
certificates.add(certificate);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Certificate[] certificatesArray = certificates.toArray(new Certificate[certificates.size()]);
return new generateKeystore(certificatesArray);
}

/**
* Generates keystore congaing the specified certificates.
*
* @param certificates certificates to add in keystore
* @return keystore with the specified certificates
* @throws KeyStoreException if keystore can not be generated.
*/
public KeyStore generateKeystore(Certificate[] certificates) throws RuntimeException {
// construct empty keystore
KeyStore keyStore = KeyStore.getInstance(keyStoreType);

// initialize keystore
keyStore.load(null, null);

// load certificates into keystore
int length = certificates.length;
for (int i = 0; i < length; i++) {
Certificate certificate = certificates[i];
keyStore.setEntry(String.valueOf(i), new KeyStore.TrustedCertificateEntry(certificate),
null);
}
return keyStore;
}

Same goes for the KeyStore with the client certificate, you can use the .p12 file directly without converting it to BKS.

SSL mutual authentication FAIL on Android Client accepts servers certificate but server does not get the client cert

When the server asks for the client certificate, it provides a list of CAs that it will accept certificates signed by. If the client doesn't have a certificate signed by one of them, it won't send a certificate in reply. If the server is configured to require a client certificate, as opposed to just wanting one, it will then close the connection.

So, ensure that the client has a certificate which is acceptable to the server's truststore.

Mutual authentication using Retrofit Android

It looks like your Retrofit ssl configuration does not match how you have configured postman. In postman you have configured it to have a private key and a certificate chain within the client certificate configuration section. The trusted certificates/CA's are empty. Now if we compare that with your retro fit configuration I can see that you have added the certificate.crt file as a trusted certificate instead of a client key material.

It is hard to replicate the exact same situation as we don't posses the certificates, so I am grabbing one from https://badssl.com/ which we can use to easily test this use case.

I am adding the certificates here, but you may need to get a new one from the website itself as they will expire.

You basically need 3 files for this use case:

  1. client private key
  2. client certificate chain
  3. trusted server certificate

1. client private key

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHN18R6x5Oz+u6
SOXLoxIscz5GHR6cDcCLgyPax2XfXHdJs+h6fTy61WGM+aXEhR2SIwbj5997s34m
0MsbvkJrFmn0LHK1fuTLCihEEmxGdCGZA9xrwxFYAkEjP7D8v7cAWRMipYF/JP7V
U7xNUo+QSkZ0sOi9k6bNkABKL3+yP6PqAzsBoKIN5lN/YRLrppsDmk6nrRDo4R3C
D+8JQl9quEoOmL22Pc/qpOjL1jgOIFSE5y3gwbzDlfCYoAL5V+by1vu0yJShTTK8
oo5wvphcFfEHaQ9w5jFg2htdq99UER3BKuNDuL+zejqGQZCWb0Xsk8S5WBuX8l3B
rrg5giqNAgMBAAECggEAVRB/t9b9igmeTlzyQpHPIMvUu3uTpm742JmWpcSe61FA
XmhDzInNdLnIfbnb3p44kj4Coy5PbzKlm01sbNxA4BkiBPE1yen1J/2eU/LJ6QuN
jRjo9drFfR75UWPQ3xu9uJhQY2rocLILXmvy69FlG+ebThh8SPbTMtNaTFMb47An
pk2FrW9+rzPswbklOxls/SDt78usRvfAjslm73IdBTOrbceF+GmYs3/SXz1gu05p
LxY2rhC8piBlqnD/QbXBahZbhjb9SkDFn2typMFZKkJIIKDJaOI2E9tIlZ97/0nZ
txqchMty8IuU9YYAfLXCmj2IEfnvLtL7thLfKLuWAQKBgQDyXBpEgKFzfy2a1AI0
+1qL/u5UN14l7S6/wmyDTgVMXwoxhwPRXWD5PutQ8D6tMfC/y4AYt3OXg1blCvLD
XysNj5SK+dpmQR0SyeWjd9zwxJAXvx0McJefCYd86YGcGhJsuX5bkHIeQlEc6df7
yoqr1480VQx/+Fk1i6Zr0EIUFQKBgQDSbalUOfXZh2EVRQEgf3VoPlxAiwGGQcVT
i+pbjMG3pOwmkVyJZusGtN5HN4Oi7n1oiyfMYGsszKQ5j4TDBGS70pNUzhTv3Vn8
0Vsfz0arJRqJxviiv4FfDmsYXwObNKwOjR+LEn1NUPkOYOLdz1lDuWOu11LE90Dy
Q6hg8WwCmQKBgQDTy5lI9AAjpqh7/XpQQrhGT2qHPjuQeU25Vnbt6GjI7OVDkvHL
LQdpyYprGQgs4s+5TGWNNARYC/cMAh1Ujv5Yw3jUWrR5V73IhZeg20bBQYWKuwDv
thVKblFw377cZAxl51R9QCX6O4oW8mRFLiMxORd0bD6YNrf/CyNMZJraYQKBgAE7
o0JbFJWxtV/qh5cpKAb0VpYKOngO6pkSuMzQhlINJVUUhPZJJBdl9+dy69KIkzOJ
nTIVXotkp5GuxZhe7jgrg7F7g6PkKCLTFzWYgVF/ZihoggxyEs/7xaTe6aZ/KILt
UMH/2bwaPVtYNfwWuu8qpurfWBzPVhIVU2c+AuQBAoGAXMbw10vyiznlhyMFw5kx
SzlBMqJBLJkzQBtpvXuT0lqqxTSNC3N4WxgVOLCHa6HqXiB0790YL8/RWunsXTk2
c7ugThP6iMPNVAycWkIF4vvHTwZ9RCSmEQabRaqGGLz/bhLL3fi3lPGCR+iW2Dxq
GTH3fhaM/pZZGdIC75x/69Y=
-----END PRIVATE KEY-----

2. client certificate chain

-----BEGIN CERTIFICATE-----
MIIEqDCCApCgAwIBAgIUK5Ns4y2CzosB/ZoFlaxjZqoBTIIwDQYJKoZIhvcNAQEL
BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
DVNhbiBGcmFuY2lzY28xDzANBgNVBAoMBkJhZFNTTDExMC8GA1UEAwwoQmFkU1NM
IENsaWVudCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xOTExMjcwMDE5
NTdaFw0yMTExMjYwMDE5NTdaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
Zm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZCYWRTU0wx
IjAgBgNVBAMMGUJhZFNTTCBDbGllbnQgQ2VydGlmaWNhdGUwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDHN18R6x5Oz+u6SOXLoxIscz5GHR6cDcCLgyPa
x2XfXHdJs+h6fTy61WGM+aXEhR2SIwbj5997s34m0MsbvkJrFmn0LHK1fuTLCihE
EmxGdCGZA9xrwxFYAkEjP7D8v7cAWRMipYF/JP7VU7xNUo+QSkZ0sOi9k6bNkABK
L3+yP6PqAzsBoKIN5lN/YRLrppsDmk6nrRDo4R3CD+8JQl9quEoOmL22Pc/qpOjL
1jgOIFSE5y3gwbzDlfCYoAL5V+by1vu0yJShTTK8oo5wvphcFfEHaQ9w5jFg2htd
q99UER3BKuNDuL+zejqGQZCWb0Xsk8S5WBuX8l3Brrg5giqNAgMBAAGjLTArMAkG
A1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMAsGA1UdDwQEAwIF4DANBgkqhkiG
9w0BAQsFAAOCAgEAZBauLzFSOijkDadcippr9C6laHebb0oRS54xAV70E9k5GxfR
/E2EMuQ8X+miRUMXxKquffcDsSxzo2ac0flw94hDx3B6vJIYvsQx9Lzo95Im0DdT
DkHFXhTlv2kjQwFVnEsWYwyGpHMTjanvNkO7sBP9p1bN1qTE3QAeyMZNKWJk5xPl
U298ERar6tl3Z2Cl8mO6yLhrq4ba6iPGw08SENxzuAJW+n8r0rq7EU+bMg5spgT1
CxExzG8Bb0f98ZXMklpYFogkcuH4OUOFyRodotrotm3iRbuvZNk0Zz7N5n1oLTPl
bGPMwBcqaGXvK62NlaRkwjnbkPM4MYvREM0bbAgZD2GHyANBTso8bdWvhLvmoSjs
FSqJUJp17AZ0x/ELWZd69v2zKW9UdPmw0evyVR19elh/7dmtF6wbewc4N4jxQnTq
IItuhIWKWB9edgJz65uZ9ubQWjXoa+9CuWcV/1KxuKCbLHdZXiboLrKm4S1WmMYW
d0sJm95H9mJzcLyhLF7iX2kK6K9ug1y02YCVXBC9WGZc2x6GMS7lDkXSkJFy3EWh
CmfxkmFGwOgwKt3Jd1pF9ftcSEMhu4WcMgxi9vZr9OdkJLxmk033sVKI/hnkPaHw
g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4=
-----END CERTIFICATE-----

3. trusted server certificate

-----BEGIN CERTIFICATE-----
MIIGqDCCBZCgAwIBAgIQCvBs2jemC2QTQvCh6x1Z/TANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMScwJQYDVQQDEx5E
aWdpQ2VydCBTSEEyIFNlY3VyZSBTZXJ2ZXIgQ0EwHhcNMjAwMzIzMDAwMDAwWhcN
MjIwNTE3MTIwMDAwWjBuMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
YTEVMBMGA1UEBxMMV2FsbnV0IENyZWVrMRwwGgYDVQQKExNMdWNhcyBHYXJyb24g
VG9ycmVzMRUwEwYDVQQDDAwqLmJhZHNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDCBOz4jO4EwrPYUNVwWMyTGOtcqGhJsCK1+ZWesSssdj5s
wEtgTEzqsrTAD4C2sPlyyYYC+VxBXRMrf3HES7zplC5QN6ZnHGGM9kFCxUbTFocn
n3TrCp0RUiYhc2yETHlV5NFr6AY9SBVSrbMo26r/bv9glUp3aznxJNExtt1NwMT8
U7ltQq21fP6u9RXSM0jnInHHwhR6bCjqN0rf6my1crR+WqIW3GmxV0TbChKr3sMP
R3RcQSLhmvkbk+atIgYpLrG6SRwMJ56j+4v3QHIArJII2YxXhFOBBcvm/mtUmEAn
hccQu3Nw72kYQQdFVXz5ZD89LMOpfOuTGkyG0cqFAgMBAAGjggNhMIIDXTAfBgNV
HSMEGDAWgBQPgGEcgjFh1S8o541GOLQs4cbZ4jAdBgNVHQ4EFgQUne7Be4ELOkdp
cRh9ETeTvKUbP/swIwYDVR0RBBwwGoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29t
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
awYDVR0fBGQwYjAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NzY2Et
c2hhMi1nNi5jcmwwL6AtoCuGKWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zc2Nh
LXNoYTItZzYuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAEBMCowKAYIKwYBBQUH
AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQIDMHwGCCsG
AQUFBwEBBHAwbjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
MEYGCCsGAQUFBzAChjpodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
cnRTSEEyU2VjdXJlU2VydmVyQ0EuY3J0MAwGA1UdEwEB/wQCMAAwggF+BgorBgEE
AdZ5AgQCBIIBbgSCAWoBaAB2ALvZ37wfinG1k5Qjl6qSe0c4V5UKq1LoGpCWZDaO
HtGFAAABcQhGXioAAAQDAEcwRQIgDfWVBXEuUZC2YP4Si3AQDidHC4U9e5XTGyG7
SFNDlRkCIQCzikrA1nf7boAdhvaGu2Vkct3VaI+0y8p3gmonU5d9DwB2ACJFRQdZ
VSRWlj+hL/H3bYbgIyZjrcBLf13Gg1xu4g8CAAABcQhGXlsAAAQDAEcwRQIhAMWi
Vsi2vYdxRCRsu/DMmCyhY0iJPKHE2c6ejPycIbgqAiAs3kSSS0NiUFiHBw7QaQ/s
GO+/lNYvjExlzVUWJbgNLwB2AFGjsPX9AXmcVm24N3iPDKR6zBsny/eeiEKaDf7U
iwXlAAABcQhGXnoAAAQDAEcwRQIgKsntiBqt8Au8DAABFkxISELhP3U/wb5lb76p
vfenWL0CIQDr2kLhCWP/QUNxXqGmvr1GaG9EuokTOLEnGPhGv1cMkDANBgkqhkiG
9w0BAQsFAAOCAQEA0RGxlwy3Tl0lhrUAn2mIi8LcZ9nBUyfAcCXCtYyCdEbjIP64
xgX6pzTt0WJoxzlT+MiK6fc0hECZXqpkTNVTARYtGkJoljlTK2vAdHZ0SOpm9OT4
RLfjGnImY0hiFbZ/LtsvS2Zg7cVJecqnrZe/za/nbDdljnnrll7C8O5naQuKr4te
uice3e8a4TtviFwS/wdDnJ3RrE83b1IljILbU5SV0X1NajyYkUWS7AnOmrFUUByz
MwdGrM6kt0lfJy/gvGVsgIKZocHdedPeECqAtq7FAJYanOsjNN9RbBOGhbwq0/FP
CC01zojqS10nGowxzOiqyB4m6wytmzf0QwjpMw==
-----END CERTIFICATE-----

There are multiple ways to load these files into your application and transform them into the right ssl materials. With vanilla java you might need to adjust it if your pem files (private key) have different headers. But with the above example the snippet below should work:

Option 1

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.KeyFactory;
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;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

public class App {

public static void main(String[] args) throws Exception {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

InputStream trustedCertificateAsInputStream = Files.newInputStream(Paths.get("badssl-server-certificate.pem"), StandardOpenOption.READ);
Certificate trustedCertificate = certificateFactory.generateCertificate(trustedCertificateAsInputStream);
KeyStore trustStore = createEmptyKeyStore("secret".toCharArray());
trustStore.setCertificateEntry("badssl-server", trustedCertificate);

String privateKeyContent = new String(Files.readAllBytes(Paths.get("private-key-badssl.pem")), Charset.defaultCharset())
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PRIVATE KEY-----", "");

byte[] privateKeyAsBytes = Base64.getDecoder().decode(privateKeyContent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyAsBytes);

InputStream certificateChainAsInputStream = Files.newInputStream(Paths.get("certificate-chain-badssl.pem"), StandardOpenOption.READ);
Certificate certificateChain = certificateFactory.generateCertificate(certificateChainAsInputStream);

KeyStore identityStore = createEmptyKeyStore("secret".toCharArray());
identityStore.setKeyEntry("client", keyFactory.generatePrivate(keySpec), "".toCharArray(), new Certificate[]{certificateChain});

trustedCertificateAsInputStream.close();
certificateChainAsInputStream.close();

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(identityStore, "secret".toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);

SSLSocketFactory socketFactory = sslContext.getSocketFactory();

val okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(socketFactory, trustManagers[0])
.build()

val json = GsonBuilder().setLenient().create()

val retrofit = Retrofit.Builder()
.baseUrl("https://client.badssl.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(json))
.build()
}

public static KeyStore createEmptyKeyStore(char[] keyStorePassword) throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, keyStorePassword);
return keyStore;
}

}

It is a bit verbose, but this should do the trick. I have written this in vanilla java, however your IDEA should be able to convert this easily to kotlin.

There is also an alternative for the above setup, which I made available within my own library, see here: GitHub - SSLContext Kickstart see below for an example usage under option 2.

Option 2

X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("certificate-chain-badssl.pem", "private-key-badssl.pem");
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial("badssl-server-certificate.pem");

SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();

val okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslFactory.getSslSocketFactory(), sslFactory.getTrustManager().get())
.build()

val json = GsonBuilder().setLenient().create()

val retrofit = Retrofit.Builder()
.baseUrl("https://client.badssl.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(json))
.build()

2-way SSL in Android App not working

If we read closely the documentaion we can find out that:

Self-signed certificates throw errors similar to that you have been experiencing. It's not important for self-signed certificates to be trusted to pass without any errors for the server, it will throw a SSLHandshakeException in either case.

To walk-pass this is to assemble a group of trusted CA certificates and add them to your truststore. Then all certificates emitted from that CA will be trusted, which will neglect the need to add them directly inside da truststore file.

Now how to add CA trusted certificates to the truststore:

Set up your own CA here

then:

Given a CA certificate, cacert.pem, in PEM format, you can add the certificate to a JKS truststore (or create a new truststore) by entering the following command:

keytool -import -file cacert.pem -alias CAAlias -keystore truststore.ts -storepass StorePass 

Where CAAlias is a convenient tag that enables you to access this particular CA certificate using the keytool utility. The file, truststore.ts, is a keystore file containing CA certificates—if this file does not already exist, the keytool utility creates one. The StorePass password provides access to the keystore file, truststore.t

Look at to this document.



Related Topics



Leave a reply



Submit