I am working on android application, which requires to communicate with server over ssl. Any good example to work with pkcs12 certificates in android using HttpsUrlConnection
问题:
回答1:
After doing some modifications to the code posted by @EpicPandaForce, i was able to successfully run the code.
Changes:
1. KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
to
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
to get rid of exception: java.security.NoSuchAlgorithmException: X509 KeyManagerFactory not available
2. KeyStore keyStore = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME); //spongyCastle library
to
KeyStore keyStore = KeyStore.getInstance("PKCS12");
and added the provider to Security Class as shown below
Security.addProvider(new BouncyCastleProvider());
to get rid of Exception:java.security.NoSuchProviderException: no such provider: SC
Then Final complete code:
Security.addProvider(new BouncyCastleProvider());
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore)null); //this is where you would add the truststore
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12"); //spongyCastle library
keyStore.load(new FileInputStream("D:\\Documents\\VISA Direct Api\\cabcentralcert.p12"), "cabcentral".toCharArray()); //inputStream to PKCS12
keyManagerFactory.init(keyStore, "cabcentral".toCharArray());
//TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
TrustManager[] trustAllCertManagers = { new X509TrustManager() { // this is vulnerable to MITM attack
@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 new X509Certificate[0];
}
}};
sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCertManagers, new SecureRandom());
URL url = new URL(strUrl);
HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) url.openConnection();
httpsUrlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
System.out.println("Response Code : " + httpsUrlConnection.getResponseCode());
System.out.println("Cipher Suite : " + httpsUrlConnection.getCipherSuite());
回答2:
Indeed, although it's a bit messy.
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore)null); //this is where you would add the truststore
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME); //spongyCastle library
keyStore.load(keyStoreStream, keyStorePassword); //inputStream to PKCS12
keyManagerFactory.init(keyStore, keyStorePassword);
//TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
TrustManager[] trustAllCertManagers = { new X509TrustManager() { // this is vulnerable to MITM attack
@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 new X509Certificate[0];
}
}};
sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCertManagers, new SecureRandom());
URL url = new URL(urlString);
HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) url.openConnection();
httpsUrlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
You need the following dependencies:
compile 'com.madgag.spongycastle:core:1.51.0.0'
compile 'com.madgag.spongycastle:prov:1.51.0.0'
compile 'com.madgag.spongycastle:pkix:1.51.0.0'
This needs a bit of fixing though as even though it initializes the key store (that stores the client certificate in PKCS12), it trusts every certificate rather than use a keystore to find out whether it is a trusted certificate or not (and this is vulnerable to Man-in-the-Middle
attacks).
EDIT: In order to make SpongyCastle work, you need to add a custom application like this:
import org.spongycastle.jce.provider.BouncyCastleProvider;
public class CustomApplication
extends Application {
static {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
@Override
public void onCreate() {
super.onCreate();
}
}
And in AndroidManifest.xml:
<application
android:allowBackup="true"
android:name=".CustomApplication"