From b65be932bdcd417c45c3e9af83584e6a5635f350 Mon Sep 17 00:00:00 2001 From: Andrew Stephan Date: Mon, 24 Mar 2014 19:36:09 -0400 Subject: [PATCH] got ssl pinning to work when hardcoded --- .../synconset/CordovaHTTP/CordovaHTTP.java | 61 +++++++++++++++++-- .../com/synconset/CordovaHTTP/HTTP.java | 10 ++- .../com/synconset/CordovaHTTP/HTTPGet.java | 33 ++++++---- .../com/synconset/CordovaHTTP/HTTPPost.java | 8 ++- 4 files changed, 92 insertions(+), 20 deletions(-) diff --git a/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java b/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java index 74f852a..9d4250d 100644 --- a/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java +++ b/src/android/com/synconset/CordovaHTTP/CordovaHTTP.java @@ -3,8 +3,22 @@ */ package com.synconset; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyManagementException; +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.cert.X509Certificate; import java.util.Iterator; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; + import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaInterface; import org.apache.cordova.CordovaPlugin; @@ -18,12 +32,14 @@ import android.util.Base64; public class CordovaHTTP extends CordovaPlugin { private static final String TAG = "CordovaHTTP"; + private SSLContext sslContext; private JSONObject globalHeaders; @Override public void initialize(CordovaInterface cordova, CordovaWebView webView) { super.initialize(cordova, webView); this.globalHeaders = new JSONObject(); + this.sslContext = null; } @Override @@ -33,22 +49,28 @@ 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, callbackContext); + HTTPGet get = new HTTPGet(urlString, params, headers, this.sslContext, 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, callbackContext); + HTTPPost post = new HTTPPost(urlString, params, headers, this.sslContext, 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("downloadFile")) { - + } else if (action.equals("setSSLPinningMode")) { + int mode = args.getInt(0); + try { + this.setSSLPinningMode(mode); + callbackContext.success(); + } catch(Exception e) { + callbackContext.error("There was an error setting up ssl pinning"); + } } else { return false; } @@ -60,6 +82,37 @@ public class CordovaHTTP extends CordovaPlugin { loginInfo = "Basic " + Base64.encodeToString(loginInfo.getBytes(), Base64.NO_WRAP); 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(); + } + + // Create a KeyStore containing our trusted CAs + String keyStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + keyStore.load(null, null); + keyStore.setCertificateEntry("ca", ca); + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init(keyStore); + + // Create an SSLContext that uses our TrustManager + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + } private void addToJSONObject(JSONObject object, JSONObject objectToAdd) throws JSONException { Iterator i = objectToAdd.keys(); diff --git a/src/android/com/synconset/CordovaHTTP/HTTP.java b/src/android/com/synconset/CordovaHTTP/HTTP.java index fa5a541..66dfe30 100644 --- a/src/android/com/synconset/CordovaHTTP/HTTP.java +++ b/src/android/com/synconset/CordovaHTTP/HTTP.java @@ -15,6 +15,8 @@ import java.io.BufferedReader; import java.net.URLConnection; +import javax.net.ssl.SSLContext; + import java.util.Iterator; import android.util.Log; @@ -27,12 +29,14 @@ public class HTTP { private String urlString; private JSONObject params; private JSONObject headers; + private SSLContext sslContext; private CallbackContext callbackContext; - public HTTP(String urlString, JSONObject params, JSONObject headers, CallbackContext callbackContext) { + public HTTP(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) { this.urlString = urlString; this.params = params; this.headers = headers; + this.sslContext = sslContext; this.callbackContext = callbackContext; } @@ -60,6 +64,10 @@ public class HTTP { this.headers = headers; } + protected SSLContext getSSLContext() { + return this.sslContext; + } + 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 0df0358..5cd4386 100644 --- a/src/android/com/synconset/CordovaHTTP/HTTPGet.java +++ b/src/android/com/synconset/CordovaHTTP/HTTPGet.java @@ -9,6 +9,7 @@ import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import org.apache.cordova.CallbackContext; import org.json.JSONException; @@ -17,8 +18,8 @@ import org.json.JSONObject; import android.util.Log; public class HTTPGet extends HTTP implements Runnable { - public HTTPGet(String urlString, JSONObject params, JSONObject headers, CallbackContext callbackContext) { - super(urlString, params, headers, callbackContext); + public HTTPGet(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) { + super(urlString, params, headers, sslContext, callbackContext); } @Override @@ -26,15 +27,14 @@ public class HTTPGet extends HTTP implements Runnable { JSONObject params = this.getParams(); String urlString = this.getUrlString(); CallbackContext callbackContext = this.getCallbackContext(); - JSONObject response = new JSONObject(); InputStream is = null; HttpsURLConnection conn = null; try { - if (params.length() > 0) { + if (params.length() > 0) { urlString = urlString + "?" + this.getQueryString(); } - URL url = new URL(urlString); + URL url = new URL(urlString); conn = (HttpsURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setDoInput(true); @@ -42,14 +42,23 @@ public class HTTPGet extends HTTP implements Runnable { this.addHeaders(conn); conn.connect(); int status = conn.getResponseCode(); - Log.d(TAG, "The response is: " + status); - is = conn.getInputStream(); - String responseData = this.readInputStream(is); - response.put("status", status); - response.put("data", responseData); - callbackContext.success(response); + if (status >= 200 && status < 300) { + is = conn.getInputStream(); + String responseData = this.readInputStream(is); + JSONObject response = new JSONObject(); + response.put("status", status); + response.put("data", responseData); + callbackContext.success(response); + } else { + is = conn.getErrorStream(); + String responseData = this.readInputStream(is); + JSONObject response = new JSONObject(); + response.put("status", status); + response.put("error", responseData); + callbackContext.error(response); + } } catch (MalformedURLException e) { - this.respondWithError(callbackContext, "There is an error with the url"); + this.respondWithError(callbackContext, "There is an error with the url"); } catch (JSONException e) { this.respondWithError(callbackContext, "There was an error with the params, headers or generating the response"); } catch (IOException e) { diff --git a/src/android/com/synconset/CordovaHTTP/HTTPPost.java b/src/android/com/synconset/CordovaHTTP/HTTPPost.java index 41f46f5..3f3b9ef 100644 --- a/src/android/com/synconset/CordovaHTTP/HTTPPost.java +++ b/src/android/com/synconset/CordovaHTTP/HTTPPost.java @@ -12,6 +12,7 @@ import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import org.apache.cordova.CallbackContext; import org.json.JSONException; @@ -20,8 +21,8 @@ import org.json.JSONObject; import android.util.Log; public class HTTPPost extends HTTP implements Runnable { - public HTTPPost(String urlString, JSONObject params, JSONObject headers, CallbackContext callbackContext) { - super(urlString, params, headers, callbackContext); + public HTTPPost(String urlString, JSONObject params, JSONObject headers, SSLContext sslContext, CallbackContext callbackContext) { + super(urlString, params, headers, sslContext, callbackContext); } @Override @@ -34,6 +35,7 @@ public class HTTPPost extends HTTP implements Runnable { try { URL url = new URL(urlString); conn = (HttpsURLConnection)url.openConnection(); + conn.setSSLSocketFactory(this.getSSLContext().getSocketFactory()); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); @@ -50,7 +52,6 @@ public class HTTPPost extends HTTP implements Runnable { conn.connect(); int status = conn.getResponseCode(); - Log.d(TAG, "The response is: " + status); if (status >= 200 && status < 300) { is = conn.getInputStream(); String responseData = this.readInputStream(is); @@ -71,6 +72,7 @@ public class HTTPPost extends HTTP implements Runnable { } catch (JSONException e) { this.respondWithError(callbackContext, "There was an error with the params, headers or generating the response"); } catch (IOException e) { + Log.d(TAG, e.getMessage()); this.respondWithError(callbackContext, "There was an error with the request"); } finally { if (is != null) {