diff options
| -rw-r--r-- | assets/urls/bitmask.url | 3 | ||||
| -rw-r--r-- | hosts-for-android-emulator | 1 | ||||
| -rw-r--r-- | src/se/leap/leapclient/ConfigHelper.java | 21 | ||||
| -rw-r--r-- | src/se/leap/leapclient/ConfigurationWizard.java | 5 | ||||
| -rw-r--r-- | src/se/leap/leapclient/Dashboard.java | 4 | ||||
| -rw-r--r-- | src/se/leap/leapclient/LogInDialog.java | 2 | ||||
| -rw-r--r-- | src/se/leap/leapclient/ProviderAPI.java | 193 | ||||
| -rw-r--r-- | src/se/leap/leapclient/ProviderListContent.java | 16 | 
8 files changed, 163 insertions, 82 deletions
diff --git a/assets/urls/bitmask.url b/assets/urls/bitmask.url index 910f040..bc4d59d 100644 --- a/assets/urls/bitmask.url +++ b/assets/urls/bitmask.url @@ -3,5 +3,6 @@  	"assets_json_provider" : "providers/bitmask.net_provider.json",
  	"json_provider" : "https://bitmask.net/provider.json",
  	"cert" : "https://bitmask.net/ca.crt",
 -	"json_eip_service" : "https://api.bitmask.net:4430/1/config/eip-service.json"
 +	"json_eip_service_antiguo" : "https://api.bitmask.net:4430/1/config/eip-service.json",
 +	"json_eip_service" : "https://api.bitmask.net:4430/config/eip-service.json"
  }
\ No newline at end of file diff --git a/hosts-for-android-emulator b/hosts-for-android-emulator index b10103e..ab0cf90 100644 --- a/hosts-for-android-emulator +++ b/hosts-for-android-emulator @@ -1,5 +1,6 @@  127.0.0.1	localhost  10.0.2.2	api.lvh.me +10.0.2.2	lvh.me  # The following lines are desirable for IPv6 capable hosts  ::1     ip6-localhost ip6-loopback diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 78c71cc..7c52629 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -16,6 +16,7 @@ import java.security.cert.CertificateException;  import java.security.cert.CertificateFactory;  import java.security.cert.X509Certificate; +import org.json.JSONArray;  import org.json.JSONException;  import org.json.JSONObject; @@ -44,7 +45,7 @@ public class ConfigHelper {  	public static final String user_directory = "leap_android";  	final public static String provider_main_url = "provider_main_url";  	final public static String danger_on = "danger_on"; -	final public static String api_url_key = "srp_server_url"; +	final public static String api_url_key = "api_uri";  	final public static String username_key = "username";  	final public static String password_key = "password";  	final public static String eip_service_api_path = "/config/eip-service.json"; @@ -63,6 +64,20 @@ public class ConfigHelper {  	final public static int LOGOUT_SUCCESSFUL = 7;  	final public static int LOGOUT_FAILED = 8; +	static String getStringFromSharedPref(String shared_preferences_key) { +		String value = ""; +		String content = shared_preferences.getString(shared_preferences_key, ""); +		try { +			JSONObject json_object = new JSONObject(content); +			JSONArray names = json_object.names(); +			String key = names.getString(0); +			value = json_object.getString(key); +		} catch (JSONException e) { +			value = content; +		} +		return value; +	} +	  	static void saveSharedPref(String shared_preferences_key, JSONObject content) {  		SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -164,8 +179,8 @@ public class ConfigHelper {  			try {  				// Initialize the keystore with the provided trusted certificates  				// Also provide the password of the keystore -				keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); -				//keystore_trusted.load(null, null); +				//keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); +				keystore_trusted.load(null, null);  			} finally {  				leap_keystore.close();  			} diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 9edaa28..3d16521 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -95,7 +95,7 @@ public class ConfigurationWizard extends Activity  	        	boolean custom = false;
  	        	provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString();
  	        	if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list
 -	        		ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom));
 +	        		ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, true)); // By default, it trusts the provider
  	        }
  		} catch (IOException e) {
  			// TODO Auto-generated catch block
 @@ -163,6 +163,7 @@ public class ConfigurationWizard extends Activity  		method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name);
  		method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url);
  		method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url);
 +		method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on);
  		provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters);
  		provider_API_command.putExtra("receiver", providerAPI_result_receiver);
 @@ -191,9 +192,9 @@ public class ConfigurationWizard extends Activity  		Bundle method_and_parameters = new Bundle();
  		method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url);
 +		method_and_parameters.putBoolean(ConfigHelper.danger_on, danger_on);
  		provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters);
 -		provider_API_command.putExtra(ConfigHelper.danger_on, danger_on);
  		provider_API_command.putExtra("receiver", providerAPI_result_receiver);
  		startService(provider_API_command);
 diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a169c9d..577092b 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -23,6 +23,7 @@ import android.view.ViewStub;  import android.widget.CompoundButton;  import android.widget.Switch;  import android.widget.TextView; +import android.widget.Toast;  public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { @@ -195,11 +196,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf  	public void onReceiveResult(int resultCode, Bundle resultData) {  		if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){  			setResult(RESULT_OK); +			Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show();  			//TODO What should we do know?  		}  		else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) {          	setResult(RESULT_CANCELED); -        	finish(); +			Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show();  		}  	} diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 61526c6..74db92e 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -68,6 +68,6 @@ public class LogInDialog extends DialogFragment {  	}  	boolean validPassword(String entered_password) { -		return entered_password.length() > 8; +		return entered_password.length() > 4;  	}  } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 63db18e..04185ed 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,17 +1,26 @@  package se.leap.leapclient; +import java.io.ByteArrayInputStream;  import java.io.IOException; +import java.io.InputStream;  import java.math.BigInteger; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException;  import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate;  import java.util.List;  import java.net.MalformedURLException;  import java.net.URL; -import java.net.UnknownHostException;  import java.util.Scanner;  import javax.net.ssl.HostnameVerifier;  import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext;  import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManagerFactory;  import org.apache.http.HttpEntity;  import org.apache.http.HttpResponse; @@ -36,6 +45,7 @@ import android.app.IntentService;  import android.content.Intent;  import android.os.Bundle;  import android.os.ResultReceiver; +import android.util.Base64;  import android.util.Log;  public class ProviderAPI extends IntentService { @@ -58,7 +68,7 @@ public class ProviderAPI extends IntentService {  		}  		else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) {  			if(downloadNewProviderDotJSON(task)) -				receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); +				receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY);  			else  				receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY);  		} @@ -77,25 +87,21 @@ public class ProviderAPI extends IntentService {  	}  	private boolean downloadJsonFiles(Bundle task) { -		String cert_url = (String) task.get(ConfigHelper.cert_key); -		String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); +		String provider_name = task.getString(ConfigHelper.provider_key); +		String cert_url = task.getString(ConfigHelper.cert_key); +		String eip_service_json_url = task.getString(ConfigHelper.eip_service_key); +		boolean danger_on = task.getBoolean(ConfigHelper.danger_on);  		try { -			String cert_string = getStringFromProvider(cert_url); +			String cert_string = getStringFromProvider(cert_url, danger_on); +			ConfigHelper.addTrustedCertificate(provider_name, cert_string);  			JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}");  			ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); -			JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); +			JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on);  			ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json);  			return true; -		} catch (IOException e) { -			// TODO  -			e.printStackTrace(); -			return false;  		} catch (JSONException e) {  			ConfigHelper.rescueJSONException(e);  			return false; -		} catch(Exception e) { -			e.printStackTrace(); -			return false;  		}  	} @@ -135,7 +141,8 @@ public class ProviderAPI extends IntentService {  				byte[] M1 = client.response(Bbytes);  				byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1);  				if( client.verify(M2) == false ) -					throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); +					//throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); +					return false;  				return true;  			}  			else return false; @@ -199,17 +206,14 @@ public class ProviderAPI extends IntentService {  	private boolean downloadNewProviderDotJSON(Bundle task) {  		boolean custom = true; -		boolean danger_on = ((Boolean)task.get(ConfigHelper.danger_on)).booleanValue(); +		boolean danger_on = task.getBoolean(ConfigHelper.danger_on);  		String provider_main_url = (String) task.get(ConfigHelper.provider_main_url);  		String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_");  		String provider_json_url = guessURL(provider_main_url);  		JSONObject provider_json = null;  		try { -			provider_json = getJSONFromProvider(provider_json_url); -		} catch (IOException e) { -			// It could happen that an https site used a certificate not trusted. -			provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url, danger_on); +			provider_json = getJSONFromProvider(provider_json_url, danger_on);  		} catch (JSONException e) {  			// TODO Auto-generated catch block  			e.printStackTrace(); @@ -223,75 +227,128 @@ public class ProviderAPI extends IntentService {  			ConfigHelper.saveFile(filename, provider_json.toString());  			ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); -			ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); +			ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on));  			return true;  		}  	} -	private JSONObject downloadNewProviderDotJsonWithoutCert( -			String provider_json_url, boolean danger_on) { -		JSONObject provider_json = null; -		try { -			URL provider_url = new URL(provider_json_url); -			String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); -			provider_json = new JSONObject(provider_json_string); -		} catch (MalformedURLException e1) { -			e1.printStackTrace(); -		} catch (UnknownHostException e1) { -			e1.printStackTrace(); -		} catch (IOException e1) { -			if(danger_on) { -				provider_json = downloadNewProviderDotJsonWithoutValidate(provider_json_url); -			} -			else { -				//TODO Show error message advising to check the checkbox if the url is completely trusted. -			} -			e1.printStackTrace(); -		} catch (JSONException e1) { -			e1.printStackTrace(); -		} -		return provider_json; -	} - -	private JSONObject downloadNewProviderDotJsonWithoutValidate( -			String provider_json_url) { -		JSONObject provider_json = null; +	private String getStringFromProviderWithoutValidate( +			URL provider_json_url) { +		 +		String json_string = "";  		HostnameVerifier hostnameVerifier = new HostnameVerifier() { -		    @Override -		    public boolean verify(String hostname, SSLSession session) { -		        HostnameVerifier hostname_verifier = -		            HttpsURLConnection.getDefaultHostnameVerifier(); -		        return hostname_verifier.verify("", session); -		    } +			@Override +			public boolean verify(String hostname, SSLSession session) { +				return true; +			}  		};  		// Tell the URLConnection to use our HostnameVerifier  		try { -			URL url = new URL(provider_json_url);  			HttpsURLConnection urlConnection = -				    (HttpsURLConnection)url.openConnection(); -				urlConnection.setHostnameVerifier(hostnameVerifier); -				String provider_json_string = new Scanner(url.openStream()).useDelimiter("\\A").next(); -				provider_json = new JSONObject(provider_json_string); +					(HttpsURLConnection)provider_json_url.openConnection(); +			urlConnection.setHostnameVerifier(hostnameVerifier); +			json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next();  		} catch (MalformedURLException e) {  			// TODO Auto-generated catch block  			e.printStackTrace();  		} catch (IOException e) {  			// TODO Auto-generated catch block -			e.printStackTrace(); -		} catch (JSONException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			json_string = getStringFromProviderWithCACertAdded(provider_json_url); +			//e.printStackTrace();  		} -		return provider_json; - +		return json_string;  	}  	private String guessURL(String provider_main_url) {  		return provider_main_url + "/provider.json";  	} +	 +	private String getStringFromProvider(String string_url, boolean danger_on) { +		 +		String json_file_content = ""; +		 +		URL provider_url = null; +		try { +			provider_url = new URL(string_url); +			json_file_content = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); +		} catch (MalformedURLException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} catch (IOException e) { +			// TODO SSLHandshakeException +			// This means that we have not added ca.crt to the trusted certificates. +			if(provider_url != null && danger_on) { +				json_file_content = getStringFromProviderWithoutValidate(provider_url); +			} +			//json_file_content = downloadStringFromProviderWithCACertAdded(string_url); +			e.printStackTrace(); +		} +		 +		return json_file_content; +	} + +	private String getStringFromProviderWithCACertAdded(URL url) { +		String json_file_content = ""; +		 +		// Load CAs from an InputStream +		// (could be from a resource or ByteArrayInputStream or ...) +		CertificateFactory cf; +		try { +			cf = CertificateFactory.getInstance("X.509"); + +			String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); +			cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); +			byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); +			InputStream caInput =  new ByteArrayInputStream(cert_bytes); +			java.security.cert.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 context = SSLContext.getInstance("TLS"); +			context.init(null, tmf.getTrustManagers(), null); + +			// Tell the URLConnection to use a SocketFactory from our SSLContext +			HttpsURLConnection urlConnection = +			    (HttpsURLConnection)url.openConnection(); +			urlConnection.setSSLSocketFactory(context.getSocketFactory()); +			json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); +		} catch (CertificateException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} catch (IOException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} catch (KeyStoreException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} catch (NoSuchAlgorithmException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} catch (KeyManagementException e) { +			// TODO Auto-generated catch block +			e.printStackTrace(); +		} +		return json_file_content; +	} -	private String getStringFromProvider(String string_url) throws IOException { +	private String getStringFromProvider_2(String string_url) throws IOException {  		String json_file_content = ""; @@ -306,8 +363,8 @@ public class ProviderAPI extends IntentService {  		return json_file_content;  	} -	private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { -		String json_file_content = getStringFromProvider(json_url); +	private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { +		String json_file_content = getStringFromProvider(json_url, danger_on);  		return new JSONObject(json_file_content);  	} diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index dd227bf..9ed7e9b 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -44,6 +44,7 @@ public class ProviderListContent {          public String provider_json_filename;
          public String eip_service_json_url;
          public String cert_json_url;
 +        public boolean danger_on = false;
          public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) {
          	this.id = id;
 @@ -53,7 +54,7 @@ public class ProviderListContent {              this.cert_json_url = cert_json_url;
          }
 -        public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom) {
 +        public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom, boolean danger_on) {
          	try {
          		byte[] urls_file_bytes = new byte[urls_file_input_stream.available()];
 @@ -62,11 +63,12 @@ public class ProviderListContent {  				JSONObject file_contents = new JSONObject(urls_file_content);
  				id = name;
  				this.name = name;
 -				provider_json_url = (String) file_contents.get("json_provider");
 -				provider_json_filename = (String) file_contents.get("assets_json_provider");
 -				eip_service_json_url = (String) file_contents.get("json_eip_service");
 -				cert_json_url = (String) file_contents.get("cert");
 +				provider_json_url = file_contents.getString("json_provider");
 +				provider_json_filename = file_contents.getString("assets_json_provider");
 +				eip_service_json_url = file_contents.getString("json_eip_service");
 +				cert_json_url = file_contents.getString("cert");
  				this.custom = custom;
 +				this.danger_on = danger_on;
  			} catch (JSONException e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
 @@ -76,7 +78,7 @@ public class ProviderListContent {  			}
          }
 -        public ProviderItem(String name, FileInputStream provider_json, boolean custom) {
 +        public ProviderItem(String name, String provider_json_url, FileInputStream provider_json, boolean custom, boolean danger_on) {
          	try {
          		byte[] urls_file_bytes = new byte[provider_json.available()];
 @@ -85,9 +87,11 @@ public class ProviderListContent {  				JSONObject file_contents = new JSONObject(urls_file_content);
  				id = name;
  				this.name = name;
 +				this.provider_json_url = provider_json_url;
  				eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path;
  				cert_json_url = (String) file_contents.get("ca_cert_uri");
  				this.custom = custom;
 +				this.danger_on = danger_on;
  				if(custom)
  					provider_json_filename = name + "_provider.json".replaceFirst("__", "_");
  			} catch (JSONException e) {
  | 
