mirror of
https://github.com/silkimen/cordova-plugin-advanced-http.git
synced 2026-04-24 00:00:03 +08:00
SSL pinning now finds any cer files in the assets folder. Now can allow invalid certs
This commit is contained in:
@@ -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
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user