diff options
author | Parménides GV <parmegv@sdf.org> | 2013-04-24 20:01:28 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2013-04-29 17:09:12 +0200 |
commit | 69389ee7db23ce7182b21da08d227d88d6cfdc46 (patch) | |
tree | b521f6c8b86a153b3a126af4ff28b78283de7e84 | |
parent | bfe2263d6b73159a4f929bc7b1fdeb724c88e8de (diff) |
"Trust completely" checkbox saves that trust for the new provider
entered, so that if in the future the client tries to log in or
whatever, it can use the certificate downloaded when added.
Log in dialog works ok, showing a toast when authentication fails (by
this time, I have not managed to get a correct login due to
dev.bitmask.net problems).
dev.bitmask.net works perfectly, via adding it as a new provider
(MeanderingCode, this is for you ;) ).
All GET requests are done by default Android URL class, which means that
certificates trusted by Android are also trusted by us. If there are
problems when logging in due to certificates, the app is able to use
only the certificate associated to the provider in the moment it was
selected as the chosen provider.
-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 910f0400..bc4d59db 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 b10103ef..ab0cf906 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 78c71cc4..7c52629b 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 9edaa288..3d165211 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 a169c9d4..577092bb 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 61526c69..74db92ea 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 63db18e1..04185eda 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 dd227bfd..9ed7e9bf 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) {
|