use info from SecurityProblem class in health card

This commit is contained in:
Vincent Breitmoser 2017-02-14 17:55:06 +01:00
parent fed0fff9d7
commit 1e8d5bdad3
7 changed files with 132 additions and 24 deletions

View file

@ -145,7 +145,7 @@ public class PgpSecurityConstants {
}
@Nullable
private static KeySecurityProblem getKeySecurityProblem(long masterKeyId, long subKeyId, int algorithm,
public static KeySecurityProblem getKeySecurityProblem(long masterKeyId, long subKeyId, int algorithm,
Integer bitStrength, String curveOid) {
switch (algorithm) {
case PublicKeyAlgorithmTags.RSA_GENERAL: {

View file

@ -62,6 +62,10 @@ public class KeyFormattingUtils {
return getAlgorithmInfo(null, algorithm, keySize, oid);
}
public static String getAlgorithmInfo(int algorithm) {
return getAlgorithmInfo(null, algorithm, null, null);
}
/**
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
*/

View file

@ -32,6 +32,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.InsecureBitStrength;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.NotWhitelistedCurve;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.widget.KeyHealthPresenter.KeyHealthClickListener;
import org.sufficientlysecure.keychain.ui.widget.KeyHealthPresenter.KeyHealthMvpView;
import org.sufficientlysecure.keychain.ui.widget.KeyHealthPresenter.KeyHealthStatus;
@ -45,6 +49,9 @@ public class KeyHealthCardView extends CardView implements KeyHealthMvpView, OnC
private final ImageView vExpander;
private final KeyStatusList vKeyStatusList;
private final View vKeyStatusDivider;
private final View vInsecureLayout;
private final TextView vInsecureProblem;
private final TextView vInsecureSolution;
private KeyHealthClickListener keyHealthClickListener;
@ -63,9 +70,13 @@ public class KeyHealthCardView extends CardView implements KeyHealthMvpView, OnC
vKeyStatusDivider = view.findViewById(R.id.key_health_divider);
vKeyStatusList = (KeyStatusList) view.findViewById(R.id.key_health_status_list);
vInsecureLayout = view.findViewById(R.id.key_insecure_layout);
vInsecureProblem = (TextView) view.findViewById(R.id.key_insecure_problem);
vInsecureSolution = (TextView) view.findViewById(R.id.key_insecure_solution);
}
enum KeyHealthDisplayStatus {
private enum KeyHealthDisplayStatus {
OK (R.string.key_health_ok_title, R.string.key_health_ok_subtitle,
R.drawable.ic_check_black_24dp, R.color.android_green_light),
DIVERT (R.string.key_health_divert_title, R.string.key_health_divert_subtitle,
@ -134,6 +145,26 @@ public class KeyHealthCardView extends CardView implements KeyHealthMvpView, OnC
}
}
@Override
public void setPrimarySecurityProblem(KeySecurityProblem securityProblem) {
vInsecureLayout.setVisibility(View.VISIBLE);
if (securityProblem instanceof InsecureBitStrength) {
InsecureBitStrength insecureBitStrength = (InsecureBitStrength) securityProblem;
vInsecureProblem.setText(getResources().getString(R.string.key_insecure_bitstrength_2048_problem,
KeyFormattingUtils.getAlgorithmInfo(insecureBitStrength.algorithm),
Integer.toString(insecureBitStrength.bitStrength)));
vInsecureSolution.setText(R.string.key_insecure_bitstrength_2048_solution);
} else if (securityProblem instanceof NotWhitelistedCurve) {
NotWhitelistedCurve notWhitelistedCurve = (NotWhitelistedCurve) securityProblem;
String curveName = KeyFormattingUtils.getCurveInfo(getContext(), notWhitelistedCurve.curveOid);
vInsecureProblem.setText(getResources().getString(R.string.key_insecure_unknown_curve_problem, curveName));
vInsecureSolution.setText(R.string.key_insecure_unknown_curve_solution);
}
}
@Override
public void onClick(View view) {
if (keyHealthClickListener != null) {

View file

@ -27,6 +27,7 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.ui.widget.KeyStatusList.KeyDisplayStatus;
import org.sufficientlysecure.keychain.ui.widget.SubkeyStatusLoader.KeySubkeyStatus;
import org.sufficientlysecure.keychain.ui.widget.SubkeyStatusLoader.SubKeyItem;
@ -45,8 +46,8 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
if (usability != 0) {
return usability;
}
if (one.mIsSecure ^ two.mIsSecure) {
return one.mIsSecure ? -1 : 1;
if ((one.mSecurityProblem == null) ^ (two.mSecurityProblem == null)) {
return one.mSecurityProblem == null ? -1 : 1;
}
// otherwise, the newer one comes first
return one.newerThan(two) ? -1 : 1;
@ -94,11 +95,19 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
this.subkeyStatus = subkeyStatus;
KeyHealthStatus keyHealthStatus = determineKeyHealthStatus(subkeyStatus);
boolean forceExpanded = keyHealthStatus == KeyHealthStatus.INSECURE;
if (forceExpanded) {
view.setKeyStatus(keyHealthStatus);
view.setShowExpander(false);
displayExpandedInfo(false);
boolean isInsecure = keyHealthStatus == KeyHealthStatus.INSECURE;
if (isInsecure) {
boolean primaryKeySecurityProblem = subkeyStatus.keyCertify.mSecurityProblem != null;
if (primaryKeySecurityProblem) {
view.setKeyStatus(keyHealthStatus);
view.setPrimarySecurityProblem(subkeyStatus.keyCertify.mSecurityProblem);
view.setShowExpander(false);
} else {
view.setKeyStatus(keyHealthStatus);
view.setShowExpander(false);
displayExpandedInfo(false);
}
} else {
view.setKeyStatus(keyHealthStatus);
view.setShowExpander(
@ -116,7 +125,7 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
return KeyHealthStatus.EXPIRED;
}
if (!keyCertify.mIsSecure) {
if (keyCertify.mSecurityProblem != null) {
return KeyHealthStatus.INSECURE;
}
@ -126,7 +135,7 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
return KeyHealthStatus.SPECIAL;
}
if (!keySign.mIsSecure) {
if (keySign.mSecurityProblem != null) {
return KeyHealthStatus.INSECURE;
}
@ -140,8 +149,8 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
SubKeyItem keySign = subkeyStatus.keysSign.get(0);
SubKeyItem keyEncrypt = subkeyStatus.keysEncrypt.get(0);
if (!keySign.mIsSecure && keySign.isValid()
|| !keyEncrypt.mIsSecure && keyEncrypt.isValid()) {
if (keySign.mSecurityProblem != null && keySign.isValid()
|| keyEncrypt.mSecurityProblem != null && keyEncrypt.isValid()) {
return KeyHealthStatus.INSECURE;
}
@ -224,7 +233,7 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
if (subKeyItem.mIsExpired) {
return KeyDisplayStatus.EXPIRED;
}
if (!subKeyItem.mIsSecure) {
if (subKeyItem.mSecurityProblem != null) {
return KeyDisplayStatus.INSECURE;
}
if (subKeyItem.mSecretKeyType == SecretKeyType.GNU_DUMMY) {
@ -243,13 +252,14 @@ public class KeyHealthPresenter implements LoaderCallbacks<KeySubkeyStatus> {
interface KeyHealthMvpView {
void setKeyStatus(KeyHealthStatus keyHealthStatus);
void setShowExpander(boolean showExpander);
void setOnHealthClickListener(KeyHealthClickListener keyHealthClickListener);
void setPrimarySecurityProblem(KeySecurityProblem securityProblem);
void setShowExpander(boolean showExpander);
void showExpandedState(KeyDisplayStatus certifyStatus, KeyDisplayStatus signStatus,
KeyDisplayStatus encryptStatus);
void hideExpandedInfo();
void setOnHealthClickListener(KeyHealthClickListener keyHealthClickListener);
}
interface KeyStatusMvpView {

View file

@ -16,6 +16,8 @@ import android.util.Log;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.PgpSecurityConstants;
import org.sufficientlysecure.keychain.pgp.SecurityProblem.KeySecurityProblem;
import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.ui.widget.SubkeyStatusLoader.KeySubkeyStatus;
@ -30,7 +32,9 @@ class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
Keys.HAS_SECRET,
Keys.EXPIRY,
Keys.IS_REVOKED,
Keys.IS_SECURE
Keys.ALGORITHM,
Keys.KEY_SIZE,
Keys.KEY_CURVE_OID
};
private static final int INDEX_KEY_ID = 0;
private static final int INDEX_CREATION = 1;
@ -40,7 +44,9 @@ class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
private static final int INDEX_HAS_SECRET = 5;
private static final int INDEX_EXPIRY = 6;
private static final int INDEX_IS_REVOKED = 7;
private static final int INDEX_IS_SECURE = 8;
private static final int INDEX_ALGORITHM = 8;
private static final int INDEX_KEY_SIZE = 9;
private static final int INDEX_KEY_CURVE_OID = 10;
private final ContentResolver contentResolver;
@ -71,7 +77,7 @@ class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
ArrayList<SubKeyItem> keysSign = new ArrayList<>();
ArrayList<SubKeyItem> keysEncrypt = new ArrayList<>();
while (cursor.moveToNext()) {
SubKeyItem ski = new SubKeyItem(cursor);
SubKeyItem ski = new SubKeyItem(masterKeyId, cursor);
if (ski.mKeyId == masterKeyId) {
keyCertify = ski;
@ -138,9 +144,9 @@ class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
final SecretKeyType mSecretKeyType;
final boolean mIsRevoked, mIsExpired;
final boolean mCanCertify, mCanSign, mCanEncrypt;
final boolean mIsSecure;
final KeySecurityProblem mSecurityProblem;
SubKeyItem(Cursor cursor) {
SubKeyItem(long masterKeyId, Cursor cursor) {
mPosition = cursor.getPosition();
mKeyId = cursor.getLong(INDEX_KEY_ID);
@ -159,7 +165,12 @@ class SubkeyStatusLoader extends AsyncTaskLoader<KeySubkeyStatus> {
mCanSign = cursor.getInt(INDEX_CAN_SIGN) > 0;
mCanEncrypt = cursor.getInt(INDEX_CAN_ENCRYPT) > 0;
mIsSecure = cursor.getInt(INDEX_IS_SECURE) > 0;
int algorithm = cursor.getInt(INDEX_ALGORITHM);
Integer bitStrength = cursor.isNull(INDEX_KEY_SIZE) ? null : cursor.getInt(INDEX_KEY_SIZE);
String curveOid = cursor.getString(INDEX_KEY_CURVE_OID);
mSecurityProblem = PgpSecurityConstants.getKeySecurityProblem(
masterKeyId, mKeyId, algorithm, bitStrength, curveOid);
}
boolean newerThan(SubKeyItem other) {

View file

@ -79,6 +79,52 @@
android:id="@+id/key_health_divider"
android:background="?android:attr/listDivider" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:id="@+id/key_insecure_layout"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Security Problem"
android:textAppearance="@style/SectionHeader"
android:layout_marginBottom="4dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="@+id/key_insecure_problem"
tools:text="@string/key_insecure_bitstrength_2048_problem" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Suggested Solution"
android:textAppearance="@style/SectionHeader"
android:layout_marginTop="8dp"
android:layout_marginBottom="4dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:id="@+id/key_insecure_solution"
tools:text="@string/key_insecure_bitstrength_2048_solution" />
</LinearLayout>
<org.sufficientlysecure.keychain.ui.widget.KeyStatusList
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -88,8 +134,8 @@
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:visibility="gone"
tools:visibility="visible"
/>
<!--tools:visibility="visible"-->
</LinearLayout>

View file

@ -1855,4 +1855,10 @@
<string name="key_health_partial_stripped_title">"Healthy (Partially Stripped)"</string>
<string name="key_health_partial_stripped_subtitle">"Click for details"</string>
<string name="key_insecure_bitstrength_2048_problem">"This key uses the <b>%1$s</b> algorithm with a strength of <b>%2$s bits</b>. A secure key should have a strength of 2048 bits."</string>
<string name="key_insecure_bitstrength_2048_solution">"This key can\'t be upgraded. For secure communication, the owner must generate a new key."</string>
<string name="key_insecure_unknown_curve_problem">"This key uses the <b>%1$s</b> algorithm, which is not whitelisted."</string>
<string name="key_insecure_unknown_curve_solution">"This key can\'t be upgraded. For secure communication, the owner must generate a new key."</string>
</resources>