diff --git a/plugin.xml b/plugin.xml
index 239893d..aedd4f1 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -81,5 +81,7 @@
+
+
\ No newline at end of file
diff --git a/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java b/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java
index 9d4250d..e50bcb5 100644
--- a/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java
+++ b/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java
@@ -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 cerFiles = new ArrayList();
+ 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 {
diff --git a/src/android/com/synconset/CordovaHTTP/HTTP.java b/src/android/com/synconset/CordovaHTTP/HTTP.java
index 66dfe30..abefd70 100644
--- a/src/android/com/synconset/CordovaHTTP/HTTP.java
+++ b/src/android/com/synconset/CordovaHTTP/HTTP.java
@@ -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;
}
diff --git a/src/android/com/synconset/CordovaHTTP/HTTPGet.java b/src/android/com/synconset/CordovaHTTP/HTTPGet.java
index 5cd4386..a7ac1a9 100644
--- a/src/android/com/synconset/CordovaHTTP/HTTPGet.java
+++ b/src/android/com/synconset/CordovaHTTP/HTTPGet.java
@@ -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
diff --git a/src/android/com/synconset/CordovaHTTP/HTTPPost.java b/src/android/com/synconset/CordovaHTTP/HTTPPost.java
index 3f3b9ef..8cc4bed 100644
--- a/src/android/com/synconset/CordovaHTTP/HTTPPost.java
+++ b/src/android/com/synconset/CordovaHTTP/HTTPPost.java
@@ -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);
diff --git a/src/android/com/synconset/CordovaHTTP/VeryTrustingHostnameVerifier.java b/src/android/com/synconset/CordovaHTTP/VeryTrustingHostnameVerifier.java
new file mode 100644
index 0000000..9368ea2
--- /dev/null
+++ b/src/android/com/synconset/CordovaHTTP/VeryTrustingHostnameVerifier.java
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/src/android/com/synconset/CordovaHTTP/VeryTrustingTrustManager.java b/src/android/com/synconset/CordovaHTTP/VeryTrustingTrustManager.java
new file mode 100644
index 0000000..f711946
--- /dev/null
+++ b/src/android/com/synconset/CordovaHTTP/VeryTrustingTrustManager.java
@@ -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];
+ }
+}
\ No newline at end of file
diff --git a/src/ios/CordovaHTTP.m b/src/ios/CordovaHTTP.m
index e747c66..b6630c1 100644
--- a/src/ios/CordovaHTTP.m
+++ b/src/ios/CordovaHTTP.m
@@ -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];
}
diff --git a/www/cordovaHTTP.js b/www/cordovaHTTP.js
index ebf364f..f8155b1 100644
--- a/www/cordovaHTTP.js
+++ b/www/cordovaHTTP.js
@@ -7,19 +7,14 @@
var exec = require('cordova/exec');
var http = {
- SSLPinningMode: {
- None: 0,
- Certificate: 1,
- PublicKey: 2
- },
setAuthorizationHeaderWithUsernameAndPassword: function(username, password, success, failure) {
return exec(success, failure, "CordovaHTTP", "setAuthorizationHeaderWithUsernameAndPassword", [username, password]);
},
setHeader: function(header, value, success, failure) {
return exec(success, failure, "CordovaHTTP", "setHeader", [header, value]);
},
- setSSLPinningMode: function(mode, success, failure) {
- return exec(success, failure, "CordovaHTTP", "setSSLPinningMode", [mode]);
+ enableSSLPinning: function(success, failure) {
+ return exec(success, failure, "CordovaHTTP", "enableSSLPinning", []);
},
validateEntireCertificateChain: function(validateChain, success, failure) {
return exec(success, failure, "CordovaHTTP", "validateEntireCertificateChain", [validateChain]);
@@ -114,15 +109,14 @@ if (angular) {
}
var cordovaHTTP = {
- SSLPinningMode: http.SSLPinningMode,
setAuthorizationHeaderWithUsernameAndPassword: function(username, password) {
return makePromise(http.setAuthorizationHeaderWithUsernameAndPassword, [username, password]);
},
setHeader: function(header, value) {
return makePromise(http.setHeader, [header, value]);
},
- setSSLPinningMode: function(mode) {
- return makePromise(http.setSSLPinningMode, [mode]);
+ enableSSLPinning: function() {
+ return makePromise(http.enableSSLPinning, []);
},
validateEntireCertificateChain: function(validateChain) {
return makePromise(http.validateEntireCertificateChain, [validateChain]);