flesh out security warning dialog

This commit is contained in:
Vincent Breitmoser 2017-04-25 16:44:13 +02:00
parent c1ba764ce8
commit 1868aed53b
6 changed files with 563 additions and 0 deletions

View file

@ -18,10 +18,228 @@
package org.sufficientlysecure.keychain.remote.ui;
import java.io.Serializable;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.remote.ui.SecurityProblemPresenter.RemoteSecurityProblemView;
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
public class RemoteSecurityProblemDialogActivity extends FragmentActivity {
public static final String EXTRA_PACKAGE_NAME = "package_name";
public static final String EXTRA_SECURITY_PROBLEM = "security_problem";
private SecurityProblemPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.presenter = new SecurityProblemPresenter(getBaseContext());
if (savedInstanceState == null) {
RemoteRegisterDialogFragment frag = new RemoteRegisterDialogFragment();
frag.show(getSupportFragmentManager(), "requestKeyDialog");
}
}
@Override
protected void onStart() {
super.onStart();
Intent intent = getIntent();
String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
Serializable keySecurityProblem = intent.getSerializableExtra(EXTRA_SECURITY_PROBLEM);
presenter.setupFromIntentData(packageName, keySecurityProblem);
}
public static class RemoteRegisterDialogFragment extends DialogFragment {
private SecurityProblemPresenter presenter;
private RemoteSecurityProblemView mvpView;
private Button buttonGotIt;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
ContextThemeWrapper theme = ThemeChanger.getDialogThemeWrapper(activity);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(theme);
@SuppressLint("InflateParams")
View view = LayoutInflater.from(theme).inflate(R.layout.remote_security_issue_dialog, null, false);
alert.setView(view);
buttonGotIt = (Button) view.findViewById(R.id.button_allow);
setupListenersForPresenter();
mvpView = createMvpView(view);
return alert.create();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
presenter = ((RemoteSecurityProblemDialogActivity) getActivity()).presenter;
presenter.setView(mvpView);
}
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (presenter != null) {
presenter.onCancel();
}
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (presenter != null) {
presenter.setView(null);
presenter = null;
}
}
@NonNull
private RemoteSecurityProblemView createMvpView(View view) {
final LinearLayout insecureWarningLayout = (LinearLayout) view.findViewById(R.id.insecure_warning_layout);
final ImageView iconClientApp = (ImageView) view.findViewById(R.id.icon_client_app);
final TextView explanationText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_text);
final TextView recommendText = (TextView) insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_text);
final View recommendLayout = insecureWarningLayout.findViewById(R.id.dialog_insecure_recommend_layout);
return new RemoteSecurityProblemView() {
@Override
public void finishAsCancelled() {
FragmentActivity activity = getActivity();
if (activity == null) {
return;
}
activity.setResult(RESULT_CANCELED);
activity.finish();
}
@Override
public void setTitleClientIcon(Drawable drawable) {
iconClientApp.setImageDrawable(drawable);
}
/* specialized layouts, for later?
private void inflateWarningContentLayout(int dialog_insecure_mdc) {
insecureWarningLayout.removeAllViews();
getLayoutInflater(null).inflate(dialog_insecure_mdc, insecureWarningLayout);
}
*/
private void showGeneric(@StringRes int explanationStringRes) {
explanationText.setText(explanationStringRes);
recommendLayout.setVisibility(View.GONE);
}
private void showGenericWithRecommendation(
@StringRes int explanationStringRes, @StringRes int recommendationStringRes) {
explanationText.setText(explanationStringRes);
recommendText.setText(recommendationStringRes);
recommendLayout.setVisibility(View.VISIBLE);
}
@Override
public void showLayoutMissingMdc() {
showGenericWithRecommendation(R.string.insecure_msg_mdc, R.string.insecure_recom_mdc);
}
@Override
public void showLayoutInsecureSymmetric(int symmetricAlgorithm) {
showGeneric(R.string.insecure_msg_unidentified_key);
}
@Override
public void showLayoutInsecureHashAlgorithm(int hashAlgorithm) {
showGeneric(R.string.insecure_msg_unidentified_key);
}
@Override
public void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength) {
String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null);
explanationText.setText(
getString(R.string.insecure_msg_bitstrength, algorithmName,
Integer.toString(bitStrength), "2010"));
recommendText.setText(R.string.insecure_recom_new_key);
recommendText.setVisibility(View.VISIBLE);
}
@Override
public void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength) {
String algorithmName = KeyFormattingUtils.getAlgorithmInfo(algorithmId, null, null);
explanationText.setText(
getString(R.string.insecure_msg_bitstrength, algorithmName,
Integer.toString(bitStrength), "2010"));
recommendText.setText(R.string.insecure_recom_new_key);
recommendText.setVisibility(View.VISIBLE);
}
@Override
public void showLayoutEncryptNotWhitelistedCurve(String curveOid) {
showGeneric(R.string.insecure_msg_not_whitelisted_curve);
}
@Override
public void showLayoutSignNotWhitelistedCurve(String curveOid) {
showGeneric(R.string.insecure_msg_not_whitelisted_curve);
}
@Override
public void showLayoutEncryptUnidentifiedKeyProblem() {
showGeneric(R.string.insecure_msg_unidentified_key);
}
@Override
public void showLayoutSignUnidentifiedKeyProblem() {
showGeneric(R.string.insecure_msg_unidentified_key);
}
};
}
private void setupListenersForPresenter() {
buttonGotIt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
presenter.onClickGotIt();
}
});
}
}
}

View file

@ -0,0 +1,140 @@
package org.sufficientlysecure.keychain.remote.ui;
import java.io.Serializable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureHashAlgorithm;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureSymmetricAlgorithm;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.MissingMdc;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.SymmetricAlgorithmProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.UnidentifiedKeyProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.UsageType;
import org.sufficientlysecure.keychain.util.Log;
class SecurityProblemPresenter {
private final PackageManager packageManager;
private RemoteSecurityProblemView view;
SecurityProblemPresenter(Context context) {
packageManager = context.getPackageManager();
}
public void setView(RemoteSecurityProblemView view) {
this.view = view;
}
void setupFromIntentData(String packageName, Serializable securityProblem) {
if (securityProblem instanceof KeySecurityProblem) {
// setupFromKeySecurityProblem((KeySecurityProblem) securityProblem);
} else if (securityProblem instanceof SymmetricAlgorithmProblem) {
setupFromNonKeySecurityProblem((SymmetricAlgorithmProblem) securityProblem);
} else if (securityProblem instanceof InsecureHashAlgorithm) {
setupFromInsecureHashAlgorithm((InsecureHashAlgorithm) securityProblem);
} else {
throw new IllegalArgumentException("Unhandled security problem type!");
}
try {
setPackageInfo(packageName);
} catch (NameNotFoundException e) {
throw new IllegalStateException("Unable to find info of calling app!", e);
}
}
/*
private void setupFromKeySecurityProblem(KeySecurityProblem keySecurityProblem) {
if (keySecurityProblem instanceof InsecureBitStrength) {
InsecureBitStrength problem = (InsecureBitStrength) keySecurityProblem;
if (problem.usageType == UsageType.ENCRYPT) {
view.showLayoutEncryptInsecureBitsize(problem.algorithm, problem.bitStrength);
} else if (problem.usageType == UsageType.SIGN) {
view.showLayoutSignInsecureBitsize(problem.algorithm, problem.bitStrength);
} else {
throw new IllegalStateException("Should never happen here!");
}
} else if (keySecurityProblem instanceof NotWhitelistedCurve) {
NotWhitelistedCurve problem = (NotWhitelistedCurve) keySecurityProblem;
if (problem.usageType == UsageType.ENCRYPT) {
view.showLayoutEncryptNotWhitelistedCurve(problem.curveOid);
} else if (problem.usageType == UsageType.SIGN) {
view.showLayoutSignNotWhitelistedCurve(problem.curveOid);
} else {
throw new IllegalStateException("Should never happen here!");
}
} else if (keySecurityProblem instanceof UnidentifiedKeyProblem) {
if (keySecurityProblem.usageType == UsageType.ENCRYPT) {
view.showLayoutEncryptUnidentifiedKeyProblem();
} else if (keySecurityProblem.usageType == UsageType.SIGN) {
view.showLayoutSignUnidentifiedKeyProblem();
} else {
throw new IllegalStateException("Should never happen here!");
}
} else {
throw new IllegalArgumentException("Unhandled key security problem type!");
}
}
*/
private void setupFromNonKeySecurityProblem(SymmetricAlgorithmProblem securityProblem) {
if (securityProblem instanceof MissingMdc) {
view.showLayoutMissingMdc();
} else if (securityProblem instanceof InsecureSymmetricAlgorithm) {
InsecureSymmetricAlgorithm insecureSymmetricAlgorithm = (InsecureSymmetricAlgorithm) securityProblem;
view.showLayoutInsecureSymmetric(insecureSymmetricAlgorithm.symmetricAlgorithm);
} else {
throw new IllegalArgumentException("Unhandled symmetric algorithm problem type!");
}
}
private void setupFromInsecureHashAlgorithm(InsecureHashAlgorithm securityProblem) {
view.showLayoutInsecureHashAlgorithm(securityProblem.hashAlgorithm);
}
private void setPackageInfo(String packageName) throws NameNotFoundException {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
Drawable appIcon = packageManager.getApplicationIcon(applicationInfo);
// CharSequence appName = packageManager.getApplicationLabel(applicationInfo);
view.setTitleClientIcon(appIcon);
}
void onClickGotIt() {
view.finishAsCancelled();
}
void onCancel() {
view.finishAsCancelled();
}
interface RemoteSecurityProblemView {
void finishAsCancelled();
void setTitleClientIcon(Drawable drawable);
void showLayoutEncryptInsecureBitsize(int algorithmId, int bitStrength);
void showLayoutEncryptNotWhitelistedCurve(String curveOid);
void showLayoutEncryptUnidentifiedKeyProblem();
void showLayoutSignInsecureBitsize(int algorithmId, int bitStrength);
void showLayoutSignNotWhitelistedCurve(String curveOid);
void showLayoutSignUnidentifiedKeyProblem();
void showLayoutMissingMdc();
void showLayoutInsecureSymmetric(int symmetricAlgorithm);
void showLayoutInsecureHashAlgorithm(int hashAlgorithm);
}
}

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/remote_security_issue_dialog">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceLarge"
android:text="Security Warning"
android:id="@+id/dialog_title"
/>
<TextView
android:id="@+id/api_register_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="The key this message was sent by is using an outdated algorithm, and is no longer considered secure!"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="The algorithm in use is DSA 1024 bit, which has been considered insecure since 2010."
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAppearance="?android:textAppearanceMedium"
android:text="Recommended Action"
android:id="@+id/dialog_title_2"
/>
<TextView
android:id="@+id/api_register_text_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="The key in use is insecure, and cannot be updated. To communicate securely, the sender must create a new key!"
/>
</merge>

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="@layout/remote_security_issue_dialog">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceLarge"
android:text="@string/dialog_insecure_title"
android:id="@+id/dialog_title"
/>
<TextView
android:id="@+id/dialog_insecure_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="The key this message was sent by is using an outdated algorithm, and is no longer considered secure!\n\nThe algorithm in use is DSA 1024 bit, which has been considered insecure since 2010."
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/dialog_insecure_recommend_layout">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAppearance="?android:textAppearanceMedium"
android:text="@string/dialog_insecure_recommend_title"
android:id="@+id/dialog_title_2"
/>
<TextView
android:id="@+id/dialog_insecure_recommend_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="The key in use is insecure, and cannot be updated. To communicate securely, the sender must create a new key!"
/>
</LinearLayout>
</merge>

View file

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:layout_marginTop="24dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:elevation="4dp"
android:background="?attr/colorPrimary"
android:gravity="center_horizontal"
tools:targetApi="lollipop">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:src="@drawable/link_24dp"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/icon_client_app"
tools:src="@drawable/apps_k9"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<!-- The parent properly determines the height of this scroll view, it is *not* useless -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="ifContentScrolls"
tools:ignore="UselessParent">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="24dp"
android:paddingBottom="16dp"
android:id="@+id/insecure_warning_layout"
>
<include layout="@layout/dialog_insecure_generic" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end"
android:padding="8dp"
tools:layout_marginBottom="50dp"
style="?buttonBarStyle">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Got it"
android:id="@+id/button_allow"
style="?buttonBarButtonStyle" />
</LinearLayout>
</LinearLayout>

View file

@ -1853,4 +1853,12 @@
<string name="key_expiry_text">"This key expired on <b>%1$s</b>."</string>
<string name="dialog_insecure_title">Security Warning</string>
<string name="dialog_insecure_recommend_title">Recommended Action</string>
<string name="insecure_msg_bitstrength">"The key this message was sent from is using an outdated algorithm, that is no longer considered secure!\n\nThe algorithm in use is %1$s with %2$s bitstrength, which has been considered insecure since %3$s."</string>
<string name="insecure_recom_new_key">The key in use is insecure, and cannot be updated. To communicate securely, the sender must create a new key!</string>
<string name="insecure_msg_not_whitelisted_curve">"This "</string>
<string name="insecure_msg_unidentified_key">"The key used to "</string>
<string name="insecure_recom_mdc">The sender of this message should update their OpenPGP software.</string>
<string name="insecure_msg_mdc">This message was encrypted with an insecure encryption mechanism. The encrypted message did not include a Modification Detection Code (MDC), which is necessary to ensure message integrity.</string>
</resources>