SSL pinning now finds any cer files in the assets folder. Now can allow invalid certs

This commit is contained in:
Andrew Stephan
2014-03-26 11:56:49 -04:00
parent b65be932bd
commit d4fce7751d
9 changed files with 123 additions and 56 deletions
@@ -15,9 +15,12 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.ArrayList;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.HostnameVerifier;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
@@ -27,12 +30,15 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.res.AssetManager;
import android.util.Base64;
import android.util.Log;
public class CordovaHTTP extends CordovaPlugin {
private static final String TAG = "CordovaHTTP";
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private JSONObject globalHeaders;
@Override
@@ -40,6 +46,7 @@ public class CordovaHTTP extends CordovaPlugin {
super.initialize(cordova, webView);
this.globalHeaders = new JSONObject();
this.sslContext = null;
this.hostnameVerifier = null;
}
@Override
@@ -49,28 +56,34 @@ public class CordovaHTTP extends CordovaPlugin {
JSONObject params = args.getJSONObject(1);
JSONObject headers = args.getJSONObject(2);
this.addToJSONObject(headers, this.globalHeaders);
HTTPGet get = new HTTPGet(urlString, params, headers, this.sslContext, callbackContext);
HTTPGet get = new HTTPGet(urlString, params, headers, this.sslContext, this.hostnameVerifier, callbackContext);
cordova.getThreadPool().execute(get);
} else if (action.equals("post")) {
String urlString = args.getString(0);
JSONObject params = args.getJSONObject(1);
JSONObject headers = args.getJSONObject(2);
this.addToJSONObject(headers, this.globalHeaders);
HTTPPost post = new HTTPPost(urlString, params, headers, this.sslContext, callbackContext);
HTTPPost post = new HTTPPost(urlString, params, headers, this.sslContext, this.hostnameVerifier, callbackContext);
cordova.getThreadPool().execute(post);
} else if (action.equals("setAuthorizationHeaderWithUsernameAndPassword")) {
String username = args.getString(0);
String password = args.getString(1);
this.setAuthorizationHeaderWithUsernameAndPassword(username, password);
callbackContext.success();
} else if (action.equals("setSSLPinningMode")) {
int mode = args.getInt(0);
} else if (action.equals("enableSSLPinning")) {
try {
this.setSSLPinningMode(mode);
this.enableSSLPinning();
callbackContext.success();
} catch(Exception e) {
callbackContext.error("There was an error setting up ssl pinning");
}
} else if (action.equals("allowInvalidCertificates")) {
try {
boolean allow = args.getBoolean(0);
this.allowInvalidCertificates(allow);
} catch(Exception e) {
callbackContext.error("There was an error allowing or disallowing invalide certificates");
}
} else {
return false;
}
@@ -83,26 +96,40 @@ public class CordovaHTTP extends CordovaPlugin {
globalHeaders.put("Authorization", loginInfo);
}
private void setSSLPinningMode(int mode) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// 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 in = cordova.getActivity().getAssets().open("PCA-3G5.cer");
InputStream caInput = new BufferedInputStream(in);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
private void enableSSLPinning() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
AssetManager assetManager = cordova.getActivity().getAssets();
String[] files = assetManager.list("");
int index;
ArrayList<String> cerFiles = new ArrayList<String>();
for (int i = 0; i < files.length; i++) {
index = files[i].lastIndexOf('.');
if (index != -1) {
if (files[i].substring(index).equals(".cer")) {
cerFiles.add(files[i]);
}
}
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
for (int i = 0; i < cerFiles.size(); i++) {
InputStream in = cordova.getActivity().getAssets().open(cerFiles.get(i));
InputStream caInput = new BufferedInputStream(in);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
keyStore.setCertificateEntry(cerFiles.get(i), ca);
}
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
@@ -112,6 +139,19 @@ public class CordovaHTTP extends CordovaPlugin {
// Create an SSLContext that uses our TrustManager
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
hostnameVerifier = null;
}
private void allowInvalidCertificates(boolean allow) throws NoSuchAlgorithmException, KeyManagementException {
if (allow) {
VeryTrustingTrustManager vttm = new VeryTrustingTrustManager();
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{vttm}, null);
hostnameVerifier = new VeryTrustingHostnameVerifier();
} else {
sslContext = null;
hostnameVerifier = null;
}
}
private void addToJSONObject(JSONObject object, JSONObject objectToAdd) throws JSONException {
@@ -16,6 +16,7 @@ import java.io.BufferedReader;
import java.net.URLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.HostnameVerifier;
import java.util.Iterator;
@@ -30,14 +31,16 @@ public class HTTP {
private JSONObject params;
private JSONObject headers;
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private CallbackContext callbackContext;
public HTTP(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) {
public HTTP(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, HostnameVerifier hostnameVerifier, CallbackContext callbackContext) {
this.urlString = urlString;
this.params = params;
this.headers = headers;
this.sslContext = sslContext;
this.callbackContext = callbackContext;
this.hostnameVerifier = hostnameVerifier;
}
protected String getUrlString() {
@@ -68,6 +71,10 @@ public class HTTP {
return this.sslContext;
}
protected HostnameVerifier getHostnameVerifier() {
return this.hostnameVerifier;
}
protected CallbackContext getCallbackContext() {
return this.callbackContext;
}
@@ -10,6 +10,7 @@ import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.HostnameVerifier;
import org.apache.cordova.CallbackContext;
import org.json.JSONException;
@@ -18,8 +19,8 @@ import org.json.JSONObject;
import android.util.Log;
public class HTTPGet extends HTTP implements Runnable {
public HTTPGet(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) {
super(urlString, params, headers, sslContext, callbackContext);
public HTTPGet(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, HostnameVerifier hostnameVerifier, CallbackContext callbackContext) {
super(urlString, params, headers, sslContext, hostnameVerifier, callbackContext);
}
@Override
@@ -13,6 +13,7 @@ import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.HostnameVerifier;
import org.apache.cordova.CallbackContext;
import org.json.JSONException;
@@ -21,8 +22,8 @@ import org.json.JSONObject;
import android.util.Log;
public class HTTPPost extends HTTP implements Runnable {
public HTTPPost(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) {
super(urlString, params, headers, sslContext, callbackContext);
public HTTPPost(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, HostnameVerifier hostnameVerifier, CallbackContext callbackContext) {
super(urlString, params, headers, sslContext, hostnameVerifier, callbackContext);
}
@Override
@@ -35,7 +36,14 @@ public class HTTPPost extends HTTP implements Runnable {
try {
URL url = new URL(urlString);
conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(this.getSSLContext().getSocketFactory());
HostnameVerifier hostnameVerifier = this.getHostnameVerifier();
if (hostnameVerifier != null) {
conn.setHostnameVerifier(hostnameVerifier);
}
SSLContext context = this.getSSLContext();
if (context != null) {
conn.setSSLSocketFactory(this.getSSLContext().getSocketFactory());
}
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
@@ -0,0 +1,11 @@
package com.synconset;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
public class VeryTrustingHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
@@ -0,0 +1,18 @@
package com.synconset;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import javax.net.ssl.X509TrustManager;
public class VeryTrustingTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException, IllegalArgumentException { }
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException, IllegalArgumentException { }
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
+5 -19
View File
@@ -5,7 +5,7 @@
@implementation CordovaHTTP
- (void) setAuthorizationHeaderWithUsernameAndPassword:(CDVInvokedUrlCommand*)command {
- (void)setAuthorizationHeaderWithUsernameAndPassword:(CDVInvokedUrlCommand*)command {
NSString *username = [command.arguments objectAtIndex:0];
NSString *password = [command.arguments objectAtIndex:1];
@@ -15,7 +15,7 @@
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
- (void) setHeader:(CDVInvokedUrlCommand*)command {
- (void)setHeader:(CDVInvokedUrlCommand*)command {
NSString *header = [command.arguments objectAtIndex:0];
NSString *value = [command.arguments objectAtIndex:1];
@@ -25,24 +25,10 @@
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
- (void) setSSLPinningMode:(CDVInvokedUrlCommand*)command {
CDVPluginResult* pluginResult = nil;
int pinningMode = [[command.arguments objectAtIndex:0] integerValue];
if (pinningMode == 0) {
[HTTPManager sharedClient].securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
} else if (pinningMode == 1) {
[HTTPManager sharedClient].securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
} else if (pinningMode == 2) {
[HTTPManager sharedClient].securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
} else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Requested SSL Pinning Mode is Unknown"];
}
if (pluginResult == nil) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
}
- (void)enableSSLPinning:(CDVInvokedUrlCommand*)command {
[HTTPManager sharedClient].securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}