From c37149dec7dbc2ff2bccfa643792080c3c86ce18 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 25 Oct 2017 15:55:49 +0200 Subject: 8757 fixes session cookie handling by implementing okHttpClient and custom cookiejar, enables TLS 1.2 on old devices, restricts allowed cipher suites on new devices in order to harden tls based communication --- app/build.gradle | 1 + .../java/se/leap/bitmaskclient/ProviderAPI.java | 407 ++++++++++++++------- app/src/main/AndroidManifest.xml | 3 +- .../java/se/leap/bitmaskclient/BitmaskApp.java | 17 + .../main/java/se/leap/bitmaskclient/Dashboard.java | 51 ++- .../java/se/leap/bitmaskclient/SrpCredentials.java | 26 ++ .../se/leap/bitmaskclient/SrpRegistrationData.java | 42 +++ .../leap/bitmaskclient/TLSCompatSocketFactory.java | 133 +++++++ .../bitmaskclient/userstatus/SessionDialog.java | 15 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 11 files changed, 534 insertions(+), 165 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/BitmaskApp.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/SrpCredentials.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/SrpRegistrationData.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/TLSCompatSocketFactory.java (limited to 'app') diff --git a/app/build.gradle b/app/build.gradle index 2614c6fb..7f838cdf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -60,6 +60,7 @@ dependencies { compile 'com.intellij:annotations:12.0' compile 'com.google.code.gson:gson:2.4' compile 'org.thoughtcrime.ssl.pinning:AndroidPinning:1.0.0' + compile 'com.squareup.okhttp3:okhttp:3.9.0' compile 'mbanje.kurt:fabbutton:1.1.4' compile 'com.android.support:support-annotations:25.3.1' compile 'com.android.support:support-v4:26.0.0-alpha1' diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java index a1b1b383..4805456c 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderAPI.java @@ -16,31 +16,89 @@ */ package se.leap.bitmaskclient; -import android.app.*; -import android.content.*; -import android.content.res.*; -import android.os.*; +import android.app.IntentService; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.os.ResultReceiver; +import android.support.annotation.NonNull; import android.util.Base64; -import org.json.*; -import org.thoughtcrime.ssl.pinning.util.*; - -import java.io.*; -import java.math.*; -import java.net.*; -import java.security.*; -import java.security.cert.*; -import java.security.interfaces.*; -import java.util.*; - -import javax.net.ssl.*; - -import se.leap.bitmaskclient.ProviderListContent.*; -import se.leap.bitmaskclient.eip.*; +import org.json.JSONException; +import org.json.JSONObject; +import org.thoughtcrime.ssl.pinning.util.PinningHelper; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.net.ConnectException; +import java.net.CookieHandler; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.net.UnknownServiceException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +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.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import okhttp3.CipherSuite; +import okhttp3.ConnectionSpec; +import okhttp3.Cookie; +import okhttp3.CookieJar; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.TlsVersion; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import se.leap.bitmaskclient.eip.Constants; +import se.leap.bitmaskclient.eip.EIP; import se.leap.bitmaskclient.userstatus.SessionDialog; import se.leap.bitmaskclient.userstatus.User; import se.leap.bitmaskclient.userstatus.UserStatus; +import static se.leap.bitmaskclient.R.string.certificate_error; +import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; +import static se.leap.bitmaskclient.R.string.error_json_exception_user_message; +import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; +import static se.leap.bitmaskclient.R.string.keyChainAccessError; +import static se.leap.bitmaskclient.R.string.malformed_url; +import static se.leap.bitmaskclient.R.string.server_unreachable_message; +import static se.leap.bitmaskclient.R.string.service_is_down_error; + /** * Implements HTTP api methods used to manage communications with the provider server. *

@@ -79,7 +137,8 @@ public class ProviderAPI extends IntentService { PROVIDER_OK = 11, PROVIDER_NOK = 12, CORRECTLY_DOWNLOADED_EIP_SERVICE = 13, - INCORRECTLY_DOWNLOADED_EIP_SERVICE = 14; + INCORRECTLY_DOWNLOADED_EIP_SERVICE = 14, + INITIALIZATION_ERROR = 15; private static boolean CA_CERT_DOWNLOADED = false, @@ -93,11 +152,15 @@ public class ProviderAPI extends IntentService { private static String provider_api_url; private static String provider_ca_cert_fingerprint; private Resources resources; - public static void stop() { go_ahead = false; } + private final MediaType JSON + = MediaType.parse("application/json; charset=utf-8"); + private OkHttpClient okHttpClient; + private String initializationError = null; + public ProviderAPI() { super(TAG); } @@ -106,10 +169,9 @@ public class ProviderAPI extends IntentService { public void onCreate() { super.onCreate(); - preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE); resources = getResources(); - CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); + initOkHttpClient(); } public static String lastProviderMainUrl() { @@ -120,13 +182,19 @@ public class ProviderAPI extends IntentService { return last_danger_on; } - private String formatErrorMessage(final int toast_string_id) { - return "{ \"" + ERRORS + "\" : \"" + getResources().getString(toast_string_id) + "\" }"; - } @Override protected void onHandleIntent(Intent command) { final ResultReceiver receiver = command.getParcelableExtra(RECEIVER_KEY); + + if (initializationError != null) { + Bundle result = new Bundle(); + result.putString(SessionDialog.ERRORS.INITIALIZATION_ERROR.toString(), initializationError); + result.putBoolean(RESULT_KEY, false); + receiver.send(INITIALIZATION_ERROR, result); + return; + } + String action = command.getAction(); Bundle parameters = command.getBundleExtra(PARAMETERS); if (provider_api_url == null && preferences.contains(Provider.KEY)) { @@ -190,6 +258,96 @@ public class ProviderAPI extends IntentService { } } + private String formatErrorMessage(final int toastStringId) { + return "{ \"" + ERRORS + "\" : \"" + getResources().getString(toastStringId) + "\" }"; + } + + private JSONObject getErrorMessageAsJson(final int toastStringId) { + try { + return new JSONObject(formatErrorMessage(toastStringId)); + } catch (JSONException e) { + e.printStackTrace(); + return new JSONObject(); + } + } + + private void initOkHttpClient() { + try { + + ConnectionSpec spec = getConnectionSpec(); + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + initSSLSocketFactory(clientBuilder); + clientBuilder.cookieJar(getCookieJar()) + .connectionSpecs(Collections.singletonList(spec)); + okHttpClient = clientBuilder.build(); + + } catch (IllegalStateException e) { + e.printStackTrace(); + //initializationError = String.format(formatErrorMessage(keyChainAccessError), e.getLocalizedMessage()); + initializationError = String.format(getResources().getString(keyChainAccessError), e.getLocalizedMessage()); + } catch (KeyStoreException e) { + e.printStackTrace(); + //initializationError = String.format(formatErrorMessage(keyChainAccessError), e.getLocalizedMessage()); + initializationError = String.format(getResources().getString(keyChainAccessError), e.getLocalizedMessage()); + } catch (KeyManagementException e) { + e.printStackTrace(); + //initializationError = String.format(formatErrorMessage(keyChainAccessError), e.getLocalizedMessage()); + initializationError = String.format(getResources().getString(keyChainAccessError), e.getLocalizedMessage()); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + //initializationError = formatErrorMessage(error_no_such_algorithm_exception_user_message); + initializationError = getResources().getString(error_no_such_algorithm_exception_user_message); + } catch (CertificateException e) { + e.printStackTrace(); + initializationError = getResources().getString(certificate_error); + } catch (UnknownHostException e) { + e.printStackTrace(); + initializationError = getResources().getString(server_unreachable_message); + } catch (IOException e) { + e.printStackTrace(); + initializationError = getResources().getString(error_io_exception_user_message); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } + } + + @NonNull + private ConnectionSpec getConnectionSpec() { + ConnectionSpec.Builder connectionSpecbuilder = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_3); + //FIXME: restrict connection further to the following recommended cipher suites for ALL supported API levels + //figure out how to use bcjsse for that purpose + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) + connectionSpecbuilder.cipherSuites( + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + ); + return connectionSpecbuilder.build(); + } + + @NonNull + private CookieJar getCookieJar() { + return new CookieJar() { + private final HashMap> cookieStore = new HashMap<>(); + + @Override + public void saveFromResponse(HttpUrl url, List cookies) { + cookieStore.put(url.host(), cookies); + } + + @Override + public List loadForRequest(HttpUrl url) { + List cookies = cookieStore.get(url.host()); + return cookies != null ? cookies : new ArrayList(); + } + }; + } + + private Bundle tryToRegister(Bundle task) { Bundle result = new Bundle(); int progress = 0; @@ -310,20 +468,33 @@ public class ProviderAPI extends IntentService { } private Bundle authFailedNotification(JSONObject result, String username) { - Bundle user_notification_bundle = new Bundle(); - try { - JSONObject error_message = result.getJSONObject(ERRORS); - String error_type = error_message.keys().next().toString(); - String message = error_message.get(error_type).toString(); - user_notification_bundle.putString(getResources().getString(R.string.user_message), message); - } catch (JSONException e) { + Bundle userNotificationBundle = new Bundle(); + Object baseErrorMessage = result.opt(ERRORS); + if (baseErrorMessage != null) { + if (baseErrorMessage instanceof JSONObject) { + try { + JSONObject errorMessage = result.getJSONObject(ERRORS); + String errorType = errorMessage.keys().next().toString(); + String message = errorMessage.get(errorType).toString(); + userNotificationBundle.putString(getResources().getString(R.string.user_message), message); + } catch (JSONException e) { + e.printStackTrace(); + } + } else if (baseErrorMessage instanceof String) { + try { + String errorMessage = result.getString(ERRORS); + userNotificationBundle.putString(getResources().getString(R.string.user_message), errorMessage); + } catch (JSONException e) { + e.printStackTrace(); + } + } } if (!username.isEmpty()) - user_notification_bundle.putString(SessionDialog.USERNAME, username); - user_notification_bundle.putBoolean(RESULT_KEY, false); + userNotificationBundle.putString(SessionDialog.USERNAME, username); + userNotificationBundle.putBoolean(RESULT_KEY, false); - return user_notification_bundle; + return userNotificationBundle; } /** @@ -374,10 +545,8 @@ public class ProviderAPI extends IntentService { * @return response from authentication server */ private JSONObject sendAToSRPServer(String server_url, String username, String clientA) { - Map parameters = new HashMap(); - parameters.put("login", username); - parameters.put("A", clientA); - return sendToServer(server_url + "/sessions.json", "POST", parameters); + SrpCredentials srpCredentials = new SrpCredentials(username, clientA); + return sendToServer(server_url + "/sessions.json", "POST", srpCredentials.toString()); } /** @@ -389,10 +558,9 @@ public class ProviderAPI extends IntentService { * @return response from authentication server */ private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) { - Map parameters = new HashMap(); - parameters.put("client_auth", new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - return sendToServer(server_url + "/sessions/" + username + ".json", "PUT", parameters); + String m1json = "{\"client_auth\":\"" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)+ "\"}"; + return sendToServer(server_url + "/sessions/" + username + ".json", "PUT", m1json); } /** @@ -405,100 +573,52 @@ public class ProviderAPI extends IntentService { * @return response from authentication server */ private JSONObject sendNewUserDataToSRPServer(String server_url, String username, String salt, String password_verifier) { - Map parameters = new HashMap(); - parameters.put("user[login]", username); - parameters.put("user[password_salt]", salt); - parameters.put("user[password_verifier]", password_verifier); - return sendToServer(server_url + "/users.json", "POST", parameters); + return sendToServer(server_url + "/users.json", "POST", new SrpRegistrationData(username, salt, password_verifier).toString()); } - /** - * Executes an HTTP request expecting a JSON response. - * - * @param url - * @param request_method - * @param parameters - * @return response from authentication server - */ - private JSONObject sendToServer(String url, String request_method, Map parameters) { - JSONObject json_response; - HttpsURLConnection urlConnection = null; - try { - InputStream is = null; - urlConnection = (HttpsURLConnection) new URL(url).openConnection(); - urlConnection.setRequestMethod(request_method); - String locale = Locale.getDefault().getLanguage() + Locale.getDefault().getCountry(); - urlConnection.setRequestProperty("Accept-Language", locale); - urlConnection.setChunkedStreamingMode(0); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); + private JSONObject sendToServer(String url, String request_method, String jsonString) { + Response response; + JSONObject responseJson = new JSONObject(); - DataOutputStream writer = new DataOutputStream(urlConnection.getOutputStream()); - writer.writeBytes(formatHttpParameters(parameters)); - writer.close(); + RequestBody jsonBody = RequestBody.create(JSON, jsonString); - is = urlConnection.getInputStream(); - String plain_response = new Scanner(is).useDelimiter("\\A").next(); - json_response = new JSONObject(plain_response); - } catch (IOException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } catch (JSONException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } catch (KeyManagementException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } catch (KeyStoreException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } catch (CertificateException e) { - json_response = getErrorMessage(urlConnection); - e.printStackTrace(); - } + Request request = new Request.Builder() + .url(url) + .method(request_method, jsonBody) + .build(); - return json_response; - } + try { + response = okHttpClient.newCall(request).execute(); - private JSONObject getErrorMessage(HttpsURLConnection urlConnection) { - JSONObject error_message = new JSONObject(); - if (urlConnection != null) { - InputStream error_stream = urlConnection.getErrorStream(); - if (error_stream != null) { - String error_response = new Scanner(error_stream).useDelimiter("\\A").next(); - try { - error_message = new JSONObject(error_response); - } catch (JSONException e) { - e.printStackTrace(); - } - urlConnection.disconnect(); + InputStream inputStream = response.body().byteStream(); + Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); + if (scanner.hasNext()) { + String plain_response = scanner.next(); + responseJson = new JSONObject(plain_response); } - } - return error_message; - } - - private String formatHttpParameters(Map parameters) throws UnsupportedEncodingException { - StringBuilder result = new StringBuilder(); - boolean first = true; - Iterator parameter_iterator = parameters.keySet().iterator(); - while (parameter_iterator.hasNext()) { - if (first) - first = false; - else - result.append("&&"); - - String key = parameter_iterator.next(); - String value = parameters.get(key); - - result.append(URLEncoder.encode(key, "UTF-8")); - result.append("="); - result.append(URLEncoder.encode(value, "UTF-8")); + } catch (JSONException e) { + responseJson = getErrorMessageAsJson(error_json_exception_user_message); + } catch (NullPointerException npe) { + responseJson = getErrorMessageAsJson(error_json_exception_user_message); + } catch (UnknownHostException e) { + responseJson = getErrorMessageAsJson(server_unreachable_message); + } catch (MalformedURLException e) { + responseJson = getErrorMessageAsJson(malformed_url); + } catch (SocketTimeoutException e) { + responseJson = getErrorMessageAsJson(server_unreachable_message); + } catch (SSLHandshakeException e) { + responseJson = getErrorMessageAsJson(certificate_error); + } catch (ConnectException e) { + responseJson = getErrorMessageAsJson(service_is_down_error); + } catch (UnknownServiceException e) { + //unable to find acceptable protocols - tlsv1.2 not enabled? + responseJson = getErrorMessageAsJson(error_no_such_algorithm_exception_user_message); + } catch (IOException e) { + responseJson = getErrorMessageAsJson(error_io_exception_user_message); } - return result.toString(); + return responseJson; } @@ -561,7 +681,7 @@ public class ProviderAPI extends IntentService { result.putBoolean(RESULT_KEY, false); } } catch (JSONException e) { - String reason_to_fail = formatErrorMessage(R.string.malformed_url); + String reason_to_fail = formatErrorMessage(malformed_url); result.putString(ERRORS, reason_to_fail); result.putBoolean(RESULT_KEY, false); } @@ -705,7 +825,7 @@ public class ProviderAPI extends IntentService { result = danger_on ? downloadWithoutCA(url_string) : formatErrorMessage(R.string.error_security_pinnedcertificate); } else - result = formatErrorMessage(R.string.error_io_exception_user_message); + result = formatErrorMessage(error_io_exception_user_message); } return result; @@ -735,19 +855,19 @@ public class ProviderAPI extends IntentService { url_connection.addRequestProperty(LeapSRPSession.AUTHORIZATION_HEADER, "Token token = " + LeapSRPSession.getToken()); json_file_content = new Scanner(url_connection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { - json_file_content = formatErrorMessage(R.string.malformed_url); + json_file_content = formatErrorMessage(malformed_url); } catch (SocketTimeoutException e) { - json_file_content = formatErrorMessage(R.string.server_unreachable_message); + json_file_content = formatErrorMessage(server_unreachable_message); } catch (SSLHandshakeException e) { if (provider_url != null) { json_file_content = downloadWithProviderCA(string_url, danger_on); } else { - json_file_content = formatErrorMessage(R.string.certificate_error); + json_file_content = formatErrorMessage(certificate_error); } } catch (ConnectException e) { - json_file_content = formatErrorMessage(R.string.service_is_down_error); + json_file_content = formatErrorMessage(service_is_down_error); } catch (FileNotFoundException e) { - json_file_content = formatErrorMessage(R.string.malformed_url); + json_file_content = formatErrorMessage(malformed_url); } catch (Exception e) { if (provider_url != null && danger_on) { json_file_content = downloadWithProviderCA(string_url, danger_on); @@ -764,6 +884,7 @@ public class ProviderAPI extends IntentService { * @param danger_on true to download CA certificate in case it has not been downloaded. * @return an empty string if it fails, the url content if not. */ + //FIXME: refactor and use okHttpClient instead! private String downloadWithProviderCA(String url_string, boolean danger_on) { String json_file_content = ""; @@ -781,13 +902,13 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); - json_file_content = formatErrorMessage(R.string.server_unreachable_message); + json_file_content = formatErrorMessage(server_unreachable_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. if (danger_on) { json_file_content = downloadWithoutCA(url_string); } else { - json_file_content = formatErrorMessage(R.string.certificate_error); + json_file_content = formatErrorMessage(certificate_error); } } catch (KeyStoreException e) { // TODO Auto-generated catch block @@ -800,11 +921,12 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } catch (NoSuchElementException e) { e.printStackTrace(); - json_file_content = formatErrorMessage(R.string.server_unreachable_message); + json_file_content = formatErrorMessage(server_unreachable_message); } return json_file_content; } + @Deprecated private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { String provider_cert_string = preferences.getString(Provider.CA_CERT, ""); @@ -828,9 +950,15 @@ public class ProviderAPI extends IntentService { return context.getSocketFactory(); } + private void initSSLSocketFactory(OkHttpClient.Builder builder) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException, IllegalStateException, NoSuchProviderException { + TLSCompatSocketFactory sslCompatFactory = new TLSCompatSocketFactory(preferences.getString(Provider.CA_CERT, "")); + sslCompatFactory.initSSLSocketFactory(builder); + } + /** * Downloads the string that's in the url with any certificate. */ + // FIXME: refactor and use okHttpClient instead! private String downloadWithoutCA(String url_string) { String string = ""; try { @@ -869,11 +997,11 @@ public class ProviderAPI extends IntentService { System.out.println("String ignoring certificate = " + string); } catch (FileNotFoundException e) { e.printStackTrace(); - string = formatErrorMessage(R.string.malformed_url); + string = formatErrorMessage(malformed_url); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. e.printStackTrace(); - string = formatErrorMessage(R.string.certificate_error); + string = formatErrorMessage(certificate_error); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -889,6 +1017,7 @@ public class ProviderAPI extends IntentService { * * @return true if there were no exceptions */ + //FIXME: refactor and use okHttpClient instead! private boolean logOut() { String delete_url = provider_api_url + "/logout"; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 67fd0a1a..d751d9f0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,10 +27,11 @@ android:maxSdkVersion="18"/> from okttp3 source code example + TrustManager[] trustManagers = tmf.getTrustManagers(); + if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { + throw new IllegalStateException("Unexpected default trust managers:" + + Arrays.toString(trustManagers)); + } + + trustManager = trustManagers[0]; + + // Create an SSLContext that uses our TrustManager + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, tmf.getTrustManagers(), null); + + } + + + @Override + public String[] getDefaultCipherSuites() { + return internalSSLSocketFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return internalSSLSocketFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket() throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); + } + + private Socket enableTLSOnSocket(Socket socket) { + if(socket != null && (socket instanceof SSLSocket)) { + ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"}); + ((SSLSocket)socket).setEnabledCipherSuites(getSupportedCipherSuites()); + } + return socket; + + + } + + + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java index 7dbbe059..88dec39b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java @@ -23,10 +23,13 @@ import android.view.*; import android.widget.*; import butterknife.*; +import se.leap.bitmaskclient.ProviderAPI; import se.leap.bitmaskclient.VpnFragment; import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.R; +import static android.view.View.VISIBLE; + /** * Implements the log in dialog, currently without progress dialog. *

@@ -47,7 +50,8 @@ public class SessionDialog extends DialogFragment { public static enum ERRORS { USERNAME_MISSING, PASSWORD_INVALID_LENGTH, - RISEUP_WARNING + RISEUP_WARNING, + INITIALIZATION_ERROR } @InjectView(R.id.user_message) @@ -117,8 +121,11 @@ public class SessionDialog extends DialogFragment { if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString())) password_field.setError(getString(R.string.error_not_valid_password_user_message)); else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) { - user_message.setVisibility(TextView.VISIBLE); + user_message.setVisibility(VISIBLE); user_message.setText(R.string.login_riseup_warning); + } else if (arguments.containsKey(ERRORS.INITIALIZATION_ERROR.toString())) { + user_message.setVisibility(VISIBLE); + user_message.setText(String.valueOf(arguments.get(ERRORS.INITIALIZATION_ERROR.toString()))); } if (arguments.containsKey(USERNAME)) { String username = arguments.getString(USERNAME); @@ -129,8 +136,8 @@ public class SessionDialog extends DialogFragment { } if (arguments.containsKey(getString(R.string.user_message))) { user_message.setText(arguments.getString(getString(R.string.user_message))); - user_message.setVisibility(View.VISIBLE); - } else if (user_message.getVisibility() != TextView.VISIBLE) + user_message.setVisibility(VISIBLE); + } else if (user_message.getVisibility() != VISIBLE) user_message.setVisibility(View.GONE); if (!username_field.getText().toString().isEmpty() && password_field.isFocusable()) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 7f0670b8..09bac1ef 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -38,7 +38,7 @@ Inténtalo de nuevo: error en el cliente HTTP Inténtalo de nuevo: error de E/S Inténtalo de nuevo: respuesta mal formada del servidor - Actualiza Bitmask + Algoritmo de cifrado no encontrado. Por favor actualice su sistema operativo! Registrarse/Iniciar sesión Iniciar sesión Cerrar sesión diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 06c80f12..b1fce0ad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -37,7 +37,7 @@ Try again: Client HTTP error Try again: I/O error Try again: Bad response from the server - Update the app + Encryption algorithm not found. Please update your OS! Sign Up/Log In Log In Log Out -- cgit v1.2.3