summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParménides GV <parmegv@sdf.org>2014-10-09 18:16:28 +0200
committerParménides GV <parmegv@sdf.org>2014-10-09 18:22:59 +0200
commit5bb1d3baf93c76e7ec70a8abd5584c33f75383b8 (patch)
treee18229cf5bc51d838d0356887ca744b9910a6b08
parent2b56dd61c0bd9eb6f71405d1d7f07f3051b29601 (diff)
Check self-signed fingerprint.
-rw-r--r--app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java49
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java77
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java1
-rw-r--r--app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java78
4 files changed, 88 insertions, 117 deletions
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
index e729d0bc..c7461d7a 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -43,6 +43,7 @@ import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
@@ -589,21 +590,43 @@ public class ProviderAPI extends IntentService {
return CA_CERT_DOWNLOADED;
}
- private boolean validCertificate(String cert_string) {
- boolean result = false;
- if(!ConfigHelper.checkErroneousDownload(cert_string)) {
- X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string);
- try {
- Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT);
- result = true;
- } catch (CertificateEncodingException e) {
- Log.d(TAG, e.getLocalizedMessage());
- }
- }
+ private boolean validCertificate(String cert_string) {
+ boolean result = false;
+ if(!ConfigHelper.checkErroneousDownload(cert_string)) {
+ X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(cert_string);
+ try {
+ JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
+ String fingerprint = provider_json.getString(Provider.CA_CERT_FINGERPRINT);
+ String encoding = fingerprint.split(":")[0];
+ String expected_fingerprint = fingerprint.split(":")[1];
+ String real_fingerprint = base64toHex(Base64.encodeToString(
+ MessageDigest.getInstance(encoding).digest(certificate.getEncoded()),
+ Base64.DEFAULT));
+
+ result = real_fingerprint.trim().equalsIgnoreCase(expected_fingerprint.trim());
+ } catch (JSONException e) {
+ result = false;
+ } catch (NoSuchAlgorithmException e) {
+ result = false;
+ } catch (CertificateEncodingException e) {
+ result = false;
+ }
+ }
- return result;
+ return result;
+ }
+
+ private String base64toHex(String base64_input) {
+ byte[] byteArray = Base64.decode(base64_input, Base64.DEFAULT);
+ int readBytes = byteArray.length;
+ StringBuffer hexData = new StringBuffer();
+ int onebyte;
+ for (int i=0; i < readBytes; i++) {
+ onebyte = ((0x000000ff & byteArray[i]) | 0xffffff00);
+ hexData.append(Integer.toHexString(onebyte).substring(6));
}
-
+ return hexData.toString();
+ }
private Bundle getAndSetProviderJson(String provider_main_url, boolean danger_on) {
Bundle result = new Bundle();
diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java b/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java
deleted file mode 100644
index 885b5105..00000000
--- a/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright (c) 2013 LEAP Encryption Access Project and contributers
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package se.leap.bitmaskclient;
-
-import java.security.KeyStore;
-
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.SingleClientConnManager;
-import android.content.Context;
-
-/**
- * Implements an HTTP client, enabling LEAP Android app to manage its own runtime keystore or bypass default Android security measures.
- *
- * @author rafa
- *
- */
-public class LeapHttpClient extends DefaultHttpClient {
-
- private static LeapHttpClient client;
-
- /**
- * If the class scope client is null, it creates one and imports, if existing, the main certificate from Shared Preferences.
- * @param context
- * @return the new client.
- */
- public static LeapHttpClient getInstance(String cert_string) {
- if(client == null) {
- if(cert_string != null) {
- ConfigHelper.addTrustedCertificate("provider_ca_certificate", cert_string);
- }
- }
- return client;
- }
-
- @Override
- protected ClientConnectionManager createClientConnectionManager() {
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", newSslSocketFactory(), 443));
-
- return new SingleClientConnManager(getParams(), registry);
- }
-
- /**
- * Uses keystore from ConfigHelper for the SSLSocketFactory.
- * @return
- */
- private SSLSocketFactory newSslSocketFactory() {
- try {
- KeyStore trusted = ConfigHelper.getKeystore();
- SSLSocketFactory sf = new SSLSocketFactory(trusted);
-
- return sf;
- } catch (Exception e) {
- throw new AssertionError(e);
- }
- }
-}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index 5326709f..8d6385e0 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -52,6 +52,7 @@ public final class Provider implements Serializable {
KEY = "provider",
CA_CERT = "ca_cert",
CA_CERT_URI = "ca_cert_uri",
+ CA_CERT_FINGERPRINT = "ca_cert_fingerprint",
NAME = "name",
DESCRIPTION = "description",
DOMAIN = "domain",
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
index ab05bc51..d97a67c8 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -16,16 +16,26 @@
*/
package se.leap.bitmaskclient;
+
+
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.util.Base64;
+import android.util.Log;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
+import java.net.ConnectException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
-import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
@@ -33,10 +43,10 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.net.UnknownHostException;
-import javax.net.ssl.SSLHandshakeException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateEncodingException;
@@ -47,32 +57,23 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import java.util.Scanner;
import java.util.NoSuchElementException;
-
+import java.util.Scanner;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-
import org.apache.http.client.ClientProtocolException;
import org.jboss.security.srp.SRPParameters;
import org.json.JSONException;
import org.json.JSONObject;
-
-import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-import android.app.IntentService;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.util.Base64;
-import android.util.Log;
+import se.leap.bitmaskclient.R;
/**
@@ -545,7 +546,7 @@ public class ProviderAPI extends IntentService {
}
if(!PROVIDER_JSON_DOWNLOADED)
- current_download = getAndSetProviderJson(last_provider_main_url);
+ current_download = getAndSetProviderJson(last_provider_main_url);
if(PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
broadcast_progress(progress++);
PROVIDER_JSON_DOWNLOADED = true;
@@ -596,20 +597,43 @@ public class ProviderAPI extends IntentService {
return CA_CERT_DOWNLOADED;
}
- private boolean validCertificate(String cert_string) {
- boolean result = false;
- if(!ConfigHelper.checkErroneousDownload(cert_string)) {
- X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string);
- try {
- Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT);
- result = true;
- } catch (CertificateEncodingException e) {
- Log.d(TAG, e.getLocalizedMessage());
- }
- }
+ private boolean validCertificate(String cert_string) {
+ boolean result = false;
+ if(!ConfigHelper.checkErroneousDownload(cert_string)) {
+ X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(cert_string);
+ try {
+ JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
+ String fingerprint = provider_json.getString(Provider.CA_CERT_FINGERPRINT);
+ String encoding = fingerprint.split(":")[0];
+ String expected_fingerprint = fingerprint.split(":")[1];
+ String real_fingerprint = base64toHex(Base64.encodeToString(
+ MessageDigest.getInstance(encoding).digest(certificate.getEncoded()),
+ Base64.DEFAULT));
+
+ result = real_fingerprint.trim().equalsIgnoreCase(expected_fingerprint.trim());
+ } catch (JSONException e) {
+ result = false;
+ } catch (NoSuchAlgorithmException e) {
+ result = false;
+ } catch (CertificateEncodingException e) {
+ result = false;
+ }
+ }
- return result;
+ return result;
+ }
+
+ private String base64toHex(String base64_input) {
+ byte[] byteArray = Base64.decode(base64_input, Base64.DEFAULT);
+ int readBytes = byteArray.length;
+ StringBuffer hexData = new StringBuffer();
+ int onebyte;
+ for (int i=0; i < readBytes; i++) {
+ onebyte = ((0x000000ff & byteArray[i]) | 0xffffff00);
+ hexData.append(Integer.toHexString(onebyte).substring(6));
}
+ return hexData.toString();
+ }
private Bundle getAndSetProviderJson(String provider_main_url) {
Bundle result = new Bundle();