Big error screen if signature is invalid or key is revoked/expired, also fixes signature status for expired and revoked keys

This commit is contained in:
Dominik Schürmann 2014-10-08 18:31:31 +02:00
parent 2eb776594f
commit 0d6d4653b4
6 changed files with 188 additions and 96 deletions

View File

@ -25,6 +25,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
/** A generic wrapped PGPKeyRing object.
*
@ -76,6 +77,16 @@ public abstract class CanonicalizedKeyRing extends KeyRing {
return getRing().getPublicKey().isRevoked();
}
public boolean isExpired() throws PgpGeneralException {
// Is the master key expired?
Date creationDate = getRing().getPublicKey().getCreationTime();
Date expiryDate = getRing().getPublicKey().getValidSeconds() > 0
? new Date(creationDate.getTime() + getRing().getPublicKey().getValidSeconds() * 1000) : null;
Date now = new Date();
return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
}
public boolean canCertify() throws PgpGeneralException {
return getRing().getPublicKey().isEncryptionKey();
}

View File

@ -103,9 +103,14 @@ public class OpenPgpSignatureResultBuilder {
Log.d(Constants.TAG, "signingRing.getUnorderedUserIds(): " + signingRing.getUnorderedUserIds());
setUserIds(signingRing.getUnorderedUserIds());
// from KEY
setKeyExpired(signingKey.isExpired());
setKeyRevoked(signingKey.isRevoked());
// either master key is expired/revoked or this specific subkey is expired/revoked
try {
setKeyExpired(signingRing.isExpired() || signingKey.isExpired());
setKeyRevoked(signingRing.isRevoked() || signingKey.isRevoked());
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "shouldn't happen!");
setKeyRevoked(true);
}
}
public OpenPgpSignatureResult build() {

View File

@ -112,9 +112,15 @@ public abstract class DecryptFragment extends Fragment {
startActivityForResult(intent, REQUEST_CODE_NFC_DECRYPT);
}
protected void onResult(DecryptVerifyResult decryptVerifyResult) {
/**
*
* @return returns false if signature is invalid, key is revoked or expired.
*/
protected boolean onResult(DecryptVerifyResult decryptVerifyResult) {
final OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
boolean valid = false;
mSignatureKeyId = 0;
mResultLayout.setVisibility(View.VISIBLE);
if (signatureResult != null) {
@ -147,14 +153,9 @@ public abstract class DecryptFragment extends Fragment {
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_VERIFIED);
setSignatureLayoutVisibility(View.VISIBLE);
mSignatureAction.setText(R.string.decrypt_result_action_show);
mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_accounts, 0);
mSignatureLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showKey(mSignatureKeyId);
}
});
setShowAction(mSignatureKeyId);
valid = true;
break;
}
@ -163,25 +164,9 @@ public abstract class DecryptFragment extends Fragment {
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_UNVERIFIED);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(mSignatureAction, mSignatureKeyId);
break;
}
setShowAction(mSignatureKeyId);
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
mSignatureText.setText(R.string.decrypt_result_signature_expired_key);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_EXPIRED);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(mSignatureAction, mSignatureKeyId);
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
mSignatureText.setText(R.string.decrypt_result_signature_revoked_key);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_REVOKED);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(mSignatureAction, mSignatureKeyId);
valid = true;
break;
}
@ -198,6 +183,30 @@ public abstract class DecryptFragment extends Fragment {
lookupUnknownKey(mSignatureKeyId);
}
});
valid = true;
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED: {
mSignatureText.setText(R.string.decrypt_result_signature_expired_key);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_EXPIRED);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(mSignatureKeyId);
valid = false;
break;
}
case OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED: {
mSignatureText.setText(R.string.decrypt_result_signature_revoked_key);
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_REVOKED);
setSignatureLayoutVisibility(View.VISIBLE);
setShowAction(mSignatureKeyId);
valid = false;
break;
}
@ -206,6 +215,8 @@ public abstract class DecryptFragment extends Fragment {
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_INVALID);
setSignatureLayoutVisibility(View.GONE);
valid = false;
break;
}
}
@ -216,7 +227,11 @@ public abstract class DecryptFragment extends Fragment {
KeyFormattingUtils.setStatusImage(getActivity(), mSignatureIcon, mSignatureText, KeyFormattingUtils.STATE_NOT_SIGNED);
mEncryptionText.setText(R.string.decrypt_result_encrypted);
KeyFormattingUtils.setStatusImage(getActivity(), mEncryptionIcon, mEncryptionText, KeyFormattingUtils.STATE_ENCRYPTED);
valid = true;
}
return valid;
}
private void setSignatureLayoutVisibility(int visibility) {
@ -225,10 +240,10 @@ public abstract class DecryptFragment extends Fragment {
mSignatureDivider2.setVisibility(visibility);
}
private void setShowAction(TextView signatureAction, final long signatureKeyId) {
signatureAction.setText(R.string.decrypt_result_action_show);
signatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_accounts, 0);
signatureAction.setOnClickListener(new View.OnClickListener() {
private void setShowAction(final long signatureKeyId) {
mSignatureAction.setText(R.string.decrypt_result_action_show);
mSignatureAction.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_accounts, 0);
mSignatureLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showKey(signatureKeyId);

View File

@ -27,6 +27,8 @@ import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpApi;
@ -44,6 +46,9 @@ public class DecryptTextFragment extends DecryptFragment {
public static final String ARG_CIPHERTEXT = "ciphertext";
// view
private LinearLayout mValidLayout;
private LinearLayout mInvalidLayout;
private Button mInvalidButton;
private TextView mText;
private View mShareButton;
private View mCopyButton;
@ -71,7 +76,9 @@ public class DecryptTextFragment extends DecryptFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.decrypt_text_fragment, container, false);
mValidLayout = (LinearLayout) view.findViewById(R.id.decrypt_text_valid);
mInvalidLayout = (LinearLayout) view.findViewById(R.id.decrypt_text_invalid);
mInvalidButton = (Button) view.findViewById(R.id.decrypt_text_invalid_button);
mText = (TextView) view.findViewById(R.id.decrypt_text_plaintext);
mShareButton = view.findViewById(R.id.action_decrypt_share_plaintext);
mCopyButton = view.findViewById(R.id.action_decrypt_copy_plaintext);
@ -87,6 +94,13 @@ public class DecryptTextFragment extends DecryptFragment {
copyToClipboard(mText.getText().toString());
}
});
mInvalidButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mInvalidLayout.setVisibility(View.GONE);
mValidLayout.setVisibility(View.VISIBLE);
}
});
return view;
}
@ -186,9 +200,18 @@ public class DecryptTextFragment extends DecryptFragment {
pgpResult.createNotify(getActivity()).show();
// display signature result in activity
onResult(pgpResult);
boolean valid = onResult(pgpResult);
if (valid) {
mInvalidLayout.setVisibility(View.GONE);
mValidLayout.setVisibility(View.VISIBLE);
} else {
mInvalidLayout.setVisibility(View.VISIBLE);
mValidLayout.setVisibility(View.GONE);
}
} else {
pgpResult.createNotify(getActivity()).show();
// TODO: show also invalid layout with different text?
}
}
}

View File

@ -6,73 +6,109 @@
<include layout="@layout/decrypt_result_include" />
<ScrollView
android:fillViewport="true"
android:paddingTop="8dp"
android:layout_width="match_parent"
android:scrollbars="vertical"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/decrypt_text_plaintext"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:hint=""
android:textIsSelectable="true" />
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="?android:attr/listDivider" />
<LinearLayout
android:id="@+id/action_decrypt_share_plaintext"
android:visibility="gone"
android:id="@+id/decrypt_text_valid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:text="@string/btn_add_share_decrypted_text"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:layout_weight="1" />
<ScrollView
android:fillViewport="true"
android:paddingTop="8dp"
android:layout_width="match_parent"
android:scrollbars="vertical"
android:layout_height="0dp"
android:layout_weight="1">
<TextView
android:id="@+id/decrypt_text_plaintext"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:hint=""
android:textIsSelectable="true" />
</ScrollView>
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/action_decrypt_copy_plaintext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_copy"
android:layout_gravity="center_vertical"
style="@style/SelectableItem" />
<LinearLayout
android:id="@+id/action_decrypt_share_plaintext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:clickable="true"
style="@style/SelectableItem"
android:orientation="horizontal">
<TextView
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:text="@string/btn_add_share_decrypted_text"
android:drawableRight="@drawable/ic_action_share"
android:drawablePadding="8dp"
android:gravity="center_vertical"
android:layout_weight="1" />
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:gravity="right"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:background="?android:attr/listDivider" />
<ImageButton
android:id="@+id/action_decrypt_copy_plaintext"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="8dp"
android:src="@drawable/ic_action_copy"
android:layout_gravity="center_vertical"
style="@style/SelectableItem" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:visibility="gone"
android:id="@+id/decrypt_text_invalid"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/decrypt_invalid_text"
android:padding="8dp"
android:layout_gravity="center"
android:textColor="@color/android_red_dark" />
<Button
android:id="@+id/decrypt_text_invalid_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_edgy"
android:textColor="@color/android_red_dark"
android:text="@string/decrypt_invalid_button"
android:layout_gravity="center_horizontal" />
</LinearLayout>
</LinearLayout>

View File

@ -277,6 +277,8 @@
<string name="decrypt_result_not_encrypted">"Not Encrypted"</string>
<string name="decrypt_result_action_show">"Show"</string>
<string name="decrypt_result_action_Lookup">"Lookup"</string>
<string name="decrypt_invalid_text">"Either the signature is invalid or the key has been revoked/is expired. You can not be sure who wrote the text. Do you still want to display it?"</string>
<string name="decrypt_invalid_button">"I understand the risks, display it!"</string>
<!-- Add keys -->
<string name="add_keys_section_secure_exchange">"Exchange"</string>