aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-03-18 21:12:31 +0100
committerVincent Breitmoser <valodim@mugenguild.com>2015-03-18 21:12:31 +0100
commitd46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2 (patch)
tree034ef267e71613dedfd74183a1ac7d7f4414813c
parentaca54e31eae450e7deec54cca6654ee202c7a90f (diff)
downloadopen-keychain-d46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2.tar.gz
open-keychain-d46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2.tar.bz2
open-keychain-d46fc3740bbfc3bac0b1133a3e9d47c7ce3e06e2.zip
yubikey certifications!
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java44
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java76
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java151
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java149
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/NfcOperationsParcel.java81
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java80
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java89
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java10
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml2
15 files changed, 475 insertions, 240 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
index ebf0dc70b..140e03764 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -30,6 +30,8 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation;
+import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation.PgpCertifyResult;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
@@ -38,6 +40,8 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException
import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel.NfcSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log;
@@ -73,10 +77,6 @@ public class CertifyOperation extends BaseOperation {
mProviderHelper.getCanonicalizedSecretKeyRing(parcel.mMasterKeyId);
log.add(LogType.MSG_CRT_UNLOCK, 1);
certificationKey = secretKeyRing.getSecretKey();
- if (certificationKey.getSecretKeyType() == SecretKeyType.DIVERT_TO_CARD) {
- log.add(LogType.MSG_CRT_ERROR_DIVERT, 2);
- return new CertifyResult(CertifyResult.RESULT_ERROR, log);
- }
// certification is always with the master key id, so use that one
String passphrase = getCachedPassphrase(parcel.mMasterKeyId, parcel.mMasterKeyId);
@@ -102,6 +102,8 @@ public class CertifyOperation extends BaseOperation {
int certifyOk = 0, certifyError = 0, uploadOk = 0, uploadError = 0;
+ NfcSignOperationsBuilder allRequiredInput = new NfcSignOperationsBuilder(parcel.getSignatureTime());
+
// Work through all requested certifications
for (CertifyAction action : parcel.mCertifyActions) {
@@ -122,28 +124,21 @@ public class CertifyOperation extends BaseOperation {
CanonicalizedPublicKeyRing publicRing =
mProviderHelper.getCanonicalizedPublicKeyRing(action.mMasterKeyId);
- UncachedKeyRing certifiedKey = null;
- if (action.mUserIds != null) {
- log.add(LogType.MSG_CRT_CERTIFY_UIDS, 2, action.mUserIds.size(),
- KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+ PgpCertifyOperation op = new PgpCertifyOperation();
+ PgpCertifyResult result = op.certify(certificationKey, publicRing,
+ log, 2, action, parcel.getSignatureData(), parcel.getSignatureTime());
- certifiedKey = certificationKey.certifyUserIds(
- publicRing, action.mUserIds, null, null);
+ if (!result.success()) {
+ certifyError += 1;
+ continue;
}
-
- if (action.mUserAttributes != null) {
- log.add(LogType.MSG_CRT_CERTIFY_UATS, 2, action.mUserAttributes.size(),
- KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
-
- certifiedKey = certificationKey.certifyUserAttributes(
- publicRing, action.mUserAttributes, null, null);
+ if (result.nfcInputRequired()) {
+ NfcOperationsParcel requiredInput = result.getRequiredInput();
+ allRequiredInput.addAll(requiredInput);
+ continue;
}
- if (certifiedKey == null) {
- certifyError += 1;
- log.add(LogType.MSG_CRT_WARN_CERT_FAILED, 3);
- }
- certifiedKeys.add(certifiedKey);
+ certifiedKeys.add(result.getCertifiedRing());
} catch (NotFoundException e) {
certifyError += 1;
@@ -152,6 +147,11 @@ public class CertifyOperation extends BaseOperation {
}
+ if ( ! allRequiredInput.isEmpty()) {
+ log.add(LogType.MSG_CRT_NFC_RETURN, 1);
+ return new CertifyResult(log, allRequiredInput.build());
+ }
+
log.add(LogType.MSG_CRT_SAVING, 1);
// Check if we were cancelled
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
index 94684851a..33591fa03 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.os.Parcel;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
import org.sufficientlysecure.keychain.ui.LogDisplayActivity;
import org.sufficientlysecure.keychain.ui.LogDisplayFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
@@ -30,16 +31,19 @@ import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener;
import org.sufficientlysecure.keychain.ui.util.Notify.Showable;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
-public class CertifyResult extends OperationResult {
-
+public class CertifyResult extends InputPendingResult {
int mCertifyOk, mCertifyError, mUploadOk, mUploadError;
public CertifyResult(int result, OperationLog log) {
super(result, log);
}
+ public CertifyResult(OperationLog log, NfcOperationsParcel requiredInput) {
+ super(log, requiredInput);
+ }
+
public CertifyResult(int result, OperationLog log, int certifyOk, int certifyError, int uploadOk, int uploadError) {
- this(result, log);
+ super(result, log);
mCertifyOk = certifyOk;
mCertifyError = certifyError;
mUploadOk = uploadOk;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
new file mode 100644
index 000000000..b681aba60
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/InputPendingResult.java
@@ -0,0 +1,76 @@
+package org.sufficientlysecure.keychain.operations.results;
+
+
+import android.os.Parcel;
+
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
+
+
+public class InputPendingResult extends OperationResult {
+
+ // the fourth bit indicates a "data pending" result! (it's also a form of non-success)
+ public static final int RESULT_PENDING = RESULT_ERROR + 8;
+
+ public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16;
+ public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32;
+
+ final NfcOperationsParcel mRequiredInput;
+ final Long mKeyIdPassphraseNeeded;
+
+ public InputPendingResult(int result, OperationLog log) {
+ super(result, log);
+ mRequiredInput = null;
+ mKeyIdPassphraseNeeded = null;
+ }
+
+ public InputPendingResult(OperationLog log, NfcOperationsParcel requiredInput) {
+ super(RESULT_PENDING_NFC, log);
+ mRequiredInput = requiredInput;
+ mKeyIdPassphraseNeeded = null;
+ }
+
+ public InputPendingResult(OperationLog log, long keyIdPassphraseNeeded) {
+ super(RESULT_PENDING_PASSPHRASE, log);
+ mRequiredInput = null;
+ mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
+ }
+
+ public InputPendingResult(Parcel source) {
+ super(source);
+ mRequiredInput = source.readParcelable(getClass().getClassLoader());
+ mKeyIdPassphraseNeeded = source.readInt() != 0 ? source.readLong() : null;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeParcelable(mRequiredInput, 0);
+ if (mKeyIdPassphraseNeeded != null) {
+ dest.writeInt(1);
+ dest.writeLong(mKeyIdPassphraseNeeded);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public boolean isPending() {
+ return (mResult & RESULT_PENDING) == RESULT_PENDING;
+ }
+
+ public boolean isNfcPending() {
+ return (mResult & RESULT_PENDING_NFC) == RESULT_PENDING_NFC;
+ }
+
+ public boolean isPassphrasePending() {
+ return (mResult & RESULT_PENDING_PASSPHRASE) == RESULT_PENDING_PASSPHRASE;
+ }
+
+ public NfcOperationsParcel getNfcOperationsParcel() {
+ return mRequiredInput;
+ }
+
+ public long getPassphraseKeyId() {
+ return mKeyIdPassphraseNeeded;
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index 068e314d5..989fb395e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -697,9 +697,9 @@ public abstract class OperationResult implements Parcelable {
MSG_CRT_ERROR_MASTER_NOT_FOUND (LogLevel.ERROR, R.string.msg_crt_error_master_not_found),
MSG_CRT_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_crt_error_nothing),
MSG_CRT_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_crt_error_unlock),
- MSG_CRT_ERROR_DIVERT (LogLevel.ERROR, R.string.msg_crt_error_divert),
MSG_CRT (LogLevel.START, R.string.msg_crt),
MSG_CRT_MASTER_FETCH (LogLevel.DEBUG, R.string.msg_crt_master_fetch),
+ MSG_CRT_NFC_RETURN (LogLevel.OK, R.string.msg_crt_nfc_return),
MSG_CRT_SAVE (LogLevel.DEBUG, R.string.msg_crt_save),
MSG_CRT_SAVING (LogLevel.DEBUG, R.string.msg_crt_saving),
MSG_CRT_SUCCESS (LogLevel.OK, R.string.msg_crt_success),
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
index 23e8094b9..5a0a51ee5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
@@ -31,6 +31,7 @@ public class SignEncryptResult extends OperationResult {
public static final int RESULT_PENDING = RESULT_ERROR + 8;
+
public PgpSignEncryptResult getPending() {
for (PgpSignEncryptResult sub : mResults) {
if (sub.isPending()) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index df409902f..c4d0d488e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -202,8 +202,26 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
}
- public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext,
- Map<ByteBuffer,byte[]> signedHashes, Date creationTimestamp)
+ public PGPSignatureGenerator getCertSignatureGenerator(Map<ByteBuffer, byte[]> signedHashes) {
+ PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
+ PgpConstants.CERTIFY_HASH_ALGO, signedHashes);
+
+ if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
+ throw new PrivateKeyNotUnlockedException();
+ }
+
+ PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
+ try {
+ signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
+ return signatureGenerator;
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return null;
+ }
+ }
+
+ public PGPSignatureGenerator getDataSignatureGenerator(int hashAlgo, boolean cleartext,
+ Map<ByteBuffer, byte[]> signedHashes, Date creationTimestamp)
throws PgpGeneralException {
if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
throw new PrivateKeyNotUnlockedException();
@@ -259,135 +277,6 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
}
}
- /**
- * Certify the given pubkeyid with the given masterkeyid.
- *
- * @param publicKeyRing Keyring to add certification to.
- * @param userIds User IDs to certify
- * @return A keyring with added certifications
- */
- public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing,
- List<String> userIds,
- HashMap<ByteBuffer,byte[]> signedHashes, Date creationTimestamp) {
- if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
- throw new PrivateKeyNotUnlockedException();
- }
- if (!isMasterKey()) {
- throw new AssertionError("tried to certify with non-master key, this is a programming error!");
- }
- if (publicKeyRing.getMasterKeyId() == getKeyId()) {
- throw new AssertionError("key tried to self-certify, this is a programming error!");
- }
-
- // create a signatureGenerator from the supplied masterKeyId and passphrase
- PGPSignatureGenerator signatureGenerator;
- {
- PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
- PgpConstants.CERTIFY_HASH_ALGO, signedHashes);
-
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- try {
- signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
- }
-
- { // supply signatureGenerator with a SubpacketVector
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- if (creationTimestamp != null) {
- spGen.setSignatureCreationTime(false, creationTimestamp);
- Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp);
- }
- PGPSignatureSubpacketVector packetVector = spGen.generate();
- signatureGenerator.setHashedSubpackets(packetVector);
- }
-
- // get the master subkey (which we certify for)
- PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
-
- // fetch public key ring, add the certification and return it
- try {
- for (String userId : userIds) {
- PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
- publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
- }
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
-
- PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
-
- return new UncachedKeyRing(ring);
- }
-
- /**
- * Certify the given user attributes with the given masterkeyid.
- *
- * @param publicKeyRing Keyring to add certification to.
- * @param userAttributes User IDs to certify, or all if null
- * @return A keyring with added certifications
- */
- public UncachedKeyRing certifyUserAttributes(CanonicalizedPublicKeyRing publicKeyRing,
- List<WrappedUserAttribute> userAttributes,
- HashMap<ByteBuffer,byte[]> signedHashes, Date creationTimestamp) {
- if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) {
- throw new PrivateKeyNotUnlockedException();
- }
- if (!isMasterKey()) {
- throw new AssertionError("tried to certify with non-master key, this is a programming error!");
- }
- if (publicKeyRing.getMasterKeyId() == getKeyId()) {
- throw new AssertionError("key tried to self-certify, this is a programming error!");
- }
-
- // create a signatureGenerator from the supplied masterKeyId and passphrase
- PGPSignatureGenerator signatureGenerator;
- {
- PGPContentSignerBuilder contentSignerBuilder = getContentSignerBuilder(
- PgpConstants.CERTIFY_HASH_ALGO, signedHashes);
-
- signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
- try {
- signatureGenerator.init(PGPSignature.DEFAULT_CERTIFICATION, mPrivateKey);
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
- }
-
- { // supply signatureGenerator with a SubpacketVector
- PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
- if (creationTimestamp != null) {
- spGen.setSignatureCreationTime(false, creationTimestamp);
- Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp);
- }
- PGPSignatureSubpacketVector packetVector = spGen.generate();
- signatureGenerator.setHashedSubpackets(packetVector);
- }
-
- // get the master subkey (which we certify for)
- PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey();
-
- // fetch public key ring, add the certification and return it
- try {
- for (WrappedUserAttribute userAttribute : userAttributes) {
- PGPUserAttributeSubpacketVector vector = userAttribute.getVector();
- PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey);
- publicKey = PGPPublicKey.addCertification(publicKey, vector, sig);
- }
- } catch (PGPException e) {
- Log.e(Constants.TAG, "signing error", e);
- return null;
- }
-
- PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicKeyRing.getRing(), publicKey);
-
- return new UncachedKeyRing(ring);
- }
-
static class PrivateKeyNotUnlockedException extends RuntimeException {
// this exception is a programming error which happens when an operation which requires
// the private key is called without a previous call to unlock()
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java
new file mode 100644
index 000000000..3c9daadbb
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java
@@ -0,0 +1,149 @@
+package org.sufficientlysecure.keychain.pgp;
+
+
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
+import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel.NfcSignOperationsBuilder;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.Log;
+
+
+public class PgpCertifyOperation {
+
+ public PgpCertifyResult certify(
+ CanonicalizedSecretKey secretKey,
+ CanonicalizedPublicKeyRing publicRing,
+ OperationLog log,
+ int indent,
+ CertifyAction action,
+ Map<ByteBuffer,byte[]> signedHashes,
+ Date creationTimestamp) {
+
+ if (!secretKey.isMasterKey()) {
+ throw new AssertionError("tried to certify with non-master key, this is a programming error!");
+ }
+ if (publicRing.getMasterKeyId() == secretKey.getKeyId()) {
+ throw new AssertionError("key tried to self-certify, this is a programming error!");
+ }
+
+ // create a signatureGenerator from the supplied masterKeyId and passphrase
+ PGPSignatureGenerator signatureGenerator = secretKey.getCertSignatureGenerator(signedHashes);
+
+ { // supply signatureGenerator with a SubpacketVector
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+ if (creationTimestamp != null) {
+ spGen.setSignatureCreationTime(false, creationTimestamp);
+ Log.d(Constants.TAG, "For NFC: set sig creation time to " + creationTimestamp);
+ }
+ PGPSignatureSubpacketVector packetVector = spGen.generate();
+ signatureGenerator.setHashedSubpackets(packetVector);
+ }
+
+ // get the master subkey (which we certify for)
+ PGPPublicKey publicKey = publicRing.getPublicKey().getPublicKey();
+
+ NfcSignOperationsBuilder requiredInput = new NfcSignOperationsBuilder(creationTimestamp);
+
+ try {
+ if (action.mUserIds != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UIDS, 2, action.mUserIds.size(),
+ KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ // fetch public key ring, add the certification and return it
+ for (String userId : action.mUserIds) {
+ try {
+ PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, userId, sig);
+ } catch (NfcInteractionNeeded e) {
+ requiredInput.addHash(e.hashToSign, e.hashAlgo);
+ }
+ }
+
+ }
+
+ if (action.mUserAttributes != null) {
+ log.add(LogType.MSG_CRT_CERTIFY_UATS, 2, action.mUserAttributes.size(),
+ KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId));
+
+ // fetch public key ring, add the certification and return it
+ for (WrappedUserAttribute userAttribute : action.mUserAttributes) {
+ PGPUserAttributeSubpacketVector vector = userAttribute.getVector();
+ try {
+ PGPSignature sig = signatureGenerator.generateCertification(vector, publicKey);
+ publicKey = PGPPublicKey.addCertification(publicKey, vector, sig);
+ } catch (NfcInteractionNeeded e) {
+ requiredInput.addHash(e.hashToSign, e.hashAlgo);
+ }
+ }
+
+ }
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "signing error", e);
+ return new PgpCertifyResult();
+ }
+
+ if (!requiredInput.isEmpty()) {
+ return new PgpCertifyResult(requiredInput.build());
+ }
+
+ PGPPublicKeyRing ring = PGPPublicKeyRing.insertPublicKey(publicRing.getRing(), publicKey);
+ return new PgpCertifyResult(new UncachedKeyRing(ring));
+
+ }
+
+ public static class PgpCertifyResult {
+
+ final NfcOperationsParcel mRequiredInput;
+ final UncachedKeyRing mCertifiedRing;
+
+ PgpCertifyResult() {
+ mRequiredInput = null;
+ mCertifiedRing = null;
+ }
+
+ PgpCertifyResult(NfcOperationsParcel requiredInput) {
+ mRequiredInput = requiredInput;
+ mCertifiedRing = null;
+ }
+
+ PgpCertifyResult(UncachedKeyRing certifiedRing) {
+ mRequiredInput = null;
+ mCertifiedRing = certifiedRing;
+ }
+
+ public boolean success() {
+ return mCertifiedRing != null || mRequiredInput != null;
+ }
+
+ public boolean nfcInputRequired() {
+ return mRequiredInput != null;
+ }
+
+ public UncachedKeyRing getCertifiedRing() {
+ return mCertifiedRing;
+ }
+
+ public NfcOperationsParcel getRequiredInput() {
+ return mRequiredInput;
+ }
+
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
index 2e515137a..7253d9b18 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java
@@ -44,8 +44,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
@@ -283,7 +281,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
try {
boolean cleartext = input.isCleartextSignature() && input.isEnableAsciiArmorOutput() && !enableEncryption;
- signatureGenerator = signingKey.getSignatureGenerator(
+ signatureGenerator = signingKey.getDataSignatureGenerator(
input.getSignatureHashAlgorithm(), cleartext,
input.getCryptoData(), input.getSignatureTime());
} catch (PgpGeneralException e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
index 485d5de72..63a7bf371 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java
@@ -22,8 +22,10 @@ import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
+import java.util.Map;
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
@@ -42,9 +44,9 @@ public class CertifyActionsParcel implements Parcelable {
public ArrayList<CertifyAction> mCertifyActions = new ArrayList<>();
public CryptoInputParcel mCryptoInput;
- public CertifyActionsParcel(Date operationTime, long masterKeyId) {
+ public CertifyActionsParcel(CryptoInputParcel cryptoInput, long masterKeyId) {
mMasterKeyId = masterKeyId;
- mCryptoInput = new CryptoInputParcel(operationTime);
+ mCryptoInput = cryptoInput != null ? cryptoInput : new CryptoInputParcel(new Date());
mLevel = CertifyLevel.DEFAULT;
}
@@ -70,6 +72,14 @@ public class CertifyActionsParcel implements Parcelable {
destination.writeSerializable(mCertifyActions);
}
+ public Map<ByteBuffer, byte[]> getSignatureData() {
+ return mCryptoInput.getCryptoData();
+ }
+
+ public Date getSignatureTime() {
+ return mCryptoInput.getSignatureTime();
+ }
+
public static final Creator<CertifyActionsParcel> CREATOR = new Creator<CertifyActionsParcel>() {
public CertifyActionsParcel createFromParcel(final Parcel source) {
return new CertifyActionsParcel(source);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index bd047518d..05d80b4e0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.service;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -26,6 +27,7 @@ import android.support.v4.app.FragmentManager;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/NfcOperationsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/NfcOperationsParcel.java
index 5d35e94e0..b9ee9e6ca 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/NfcOperationsParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/input/NfcOperationsParcel.java
@@ -1,5 +1,7 @@
package org.sufficientlysecure.keychain.service.input;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import android.os.Parcel;
@@ -14,13 +16,14 @@ public class NfcOperationsParcel implements Parcelable {
public Date mSignatureTime;
public final NfcOperationType mType;
- public final byte[][] mInputHash;
- public final int[] mSignAlgo;
+ public final byte[][] mInputHashes;
+ public final int[] mSignAlgos;
- private NfcOperationsParcel(NfcOperationType type, byte[] inputHash, int signAlgo, Date signatureTime) {
+ private NfcOperationsParcel(NfcOperationType type, byte[][] inputHashes,
+ int[] signAlgos, Date signatureTime) {
mType = type;
- mInputHash = new byte[][] { inputHash };
- mSignAlgo = new int[] { signAlgo };
+ mInputHashes = inputHashes;
+ mSignAlgos = signAlgos;
mSignatureTime = signatureTime;
}
@@ -29,11 +32,11 @@ public class NfcOperationsParcel implements Parcelable {
{
int count = source.readInt();
- mInputHash = new byte[count][];
- mSignAlgo = new int[count];
+ mInputHashes = new byte[count][];
+ mSignAlgos = new int[count];
for (int i = 0; i < count; i++) {
- mInputHash[i] = source.createByteArray();
- mSignAlgo[i] = source.readInt();
+ mInputHashes[i] = source.createByteArray();
+ mSignAlgos[i] = source.readInt();
}
}
@@ -43,11 +46,13 @@ public class NfcOperationsParcel implements Parcelable {
public static NfcOperationsParcel createNfcSignOperation(
byte[] inputHash, int signAlgo, Date signatureTime) {
- return new NfcOperationsParcel(NfcOperationType.NFC_SIGN, inputHash, signAlgo, signatureTime);
+ return new NfcOperationsParcel(NfcOperationType.NFC_SIGN,
+ new byte[][] { inputHash }, new int[] { signAlgo }, signatureTime);
}
public static NfcOperationsParcel createNfcDecryptOperation(byte[] inputHash) {
- return new NfcOperationsParcel(NfcOperationType.NFC_DECRYPT, inputHash, 0, null);
+ return new NfcOperationsParcel(NfcOperationType.NFC_DECRYPT,
+ new byte[][] { inputHash }, null, null);
}
@Override
@@ -58,10 +63,10 @@ public class NfcOperationsParcel implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType.ordinal());
- dest.writeInt(mInputHash.length);
- for (int i = 0; i < mInputHash.length; i++) {
- dest.writeByteArray(mInputHash[i]);
- dest.writeInt(mSignAlgo[i]);
+ dest.writeInt(mInputHashes.length);
+ for (int i = 0; i < mInputHashes.length; i++) {
+ dest.writeByteArray(mInputHashes[i]);
+ dest.writeInt(mSignAlgos[i]);
}
if (mSignatureTime != null) {
dest.writeInt(1);
@@ -82,4 +87,50 @@ public class NfcOperationsParcel implements Parcelable {
}
};
+ public static class NfcSignOperationsBuilder {
+ Date mSignatureTime;
+ ArrayList<Integer> mSignAlgos = new ArrayList<>();
+ ArrayList<byte[]> mInputHashes = new ArrayList<>();
+
+ public NfcSignOperationsBuilder(Date signatureTime) {
+ mSignatureTime = signatureTime;
+ }
+
+ public NfcOperationsParcel build() {
+ byte[][] inputHashes = new byte[mInputHashes.size()][];
+ mInputHashes.toArray(inputHashes);
+ int[] signAlgos = new int[mSignAlgos.size()];
+ for (int i = 0; i < mSignAlgos.size(); i++) {
+ signAlgos[i] = mSignAlgos.get(i);
+ }
+
+ return new NfcOperationsParcel(NfcOperationType.NFC_SIGN,
+ inputHashes, signAlgos, mSignatureTime);
+ }
+
+ public void addHash(byte[] hash, int algo) {
+ mInputHashes.add(hash);
+ mSignAlgos.add(algo);
+ }
+
+ public void addAll(NfcOperationsParcel input) {
+ if (!mSignatureTime.equals(input.mSignatureTime)) {
+ throw new AssertionError("input times must match, this is a programming error!");
+ }
+ if (input.mType != NfcOperationType.NFC_SIGN) {
+ throw new AssertionError("operation types must match, this is a progrmming error!");
+ }
+
+ Collections.addAll(mInputHashes, input.mInputHashes);
+ for (int signAlgo : input.mSignAlgos) {
+ mSignAlgos.add(signAlgo);
+ }
+ }
+
+ public boolean isEmpty() {
+ return mInputHashes.isEmpty();
+ }
+
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
index 049c6976d..acb6b0b85 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java
@@ -56,7 +56,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel;
import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.ui.adapter.MultiUserIdsAdapter;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
@@ -66,14 +66,11 @@ import org.sufficientlysecure.keychain.util.Preferences;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Date;
-public class CertifyKeyFragment extends LoaderFragment
+public class CertifyKeyFragment extends CryptoOperationFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
- public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
-
private CheckBox mUploadKeyCheckbox;
ListView mUserIds;
@@ -102,9 +99,6 @@ public class CertifyKeyFragment extends LoaderFragment
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- // Start out with a progress indicator.
- setContentShown(false);
-
mPubMasterKeyIds = getActivity().getIntent().getLongArrayExtra(CertifyKeyActivity.EXTRA_KEY_IDS);
if (mPubMasterKeyIds == null) {
Log.e(Constants.TAG, "List of key ids to certify missing!");
@@ -114,6 +108,7 @@ public class CertifyKeyFragment extends LoaderFragment
mPassthroughMessenger = getActivity().getIntent().getParcelableExtra(
KeychainIntentService.EXTRA_MESSENGER);
+ mPassthroughMessenger = null; // TODO remove, development hack
// preselect certify key id if given
long certifyKeyId = getActivity().getIntent().getLongExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, Constants.key.none);
@@ -143,9 +138,7 @@ public class CertifyKeyFragment extends LoaderFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
- View root = super.onCreateView(inflater, superContainer, savedInstanceState);
-
- View view = inflater.inflate(R.layout.certify_key_fragment, getContainer());
+ View view = inflater.inflate(R.layout.certify_key_fragment, null);
mCertifyKeySpinner = (CertifyKeySpinner) view.findViewById(R.id.certify_key_spinner);
mUploadKeyCheckbox = (CheckBox) view.findViewById(R.id.sign_key_upload_checkbox);
@@ -173,7 +166,7 @@ public class CertifyKeyFragment extends LoaderFragment
Notify.showNotify(getActivity(), getString(R.string.select_key_to_certify),
Notify.Style.ERROR);
} else {
- initiateCertifying();
+ cryptoOperation();
}
}
});
@@ -183,7 +176,7 @@ public class CertifyKeyFragment extends LoaderFragment
mUploadKeyCheckbox.setChecked(false);
}
- return root;
+ return view;
}
@Override
@@ -307,7 +300,6 @@ public class CertifyKeyFragment extends LoaderFragment
}
mUserIdsAdapter.swapCursor(matrix);
- setContentShown(true, isResumed());
}
@Override
@@ -315,50 +307,17 @@ public class CertifyKeyFragment extends LoaderFragment
mUserIdsAdapter.swapCursor(null);
}
- /**
- * handles the UI bits of the signing process on the UI thread
- */
- private void initiateCertifying() {
- // get the user's passphrase for this key (if required)
- String passphrase;
- try {
- passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId);
- } catch (PassphraseCacheService.KeyNotFoundException e) {
- Log.e(Constants.TAG, "Key not found!", e);
- getActivity().finish();
- return;
- }
- if (passphrase == null) {
- Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
- intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, mSignMasterKeyId);
- startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
- // bail out; need to wait until the user has entered the passphrase before trying again
- } else {
- startCertifying();
- }
+ protected void cryptoOperation() {
+ cryptoOperation((CryptoInputParcel) null);
}
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CODE_PASSPHRASE: {
- if (resultCode == Activity.RESULT_OK && data != null) {
- String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
- startCertifying();
- }
- return;
- }
-
- default: {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
+ protected void cryptoOperation(String passphrase) {
+ cryptoOperation((CryptoInputParcel) null);
}
- /**
- * kicks off the actual signing process on a background thread
- */
- private void startCertifying() {
+ @Override
+ protected void cryptoOperation(CryptoInputParcel cryptoInput) {
// Bail out if there is not at least one user id selected
ArrayList<CertifyAction> certifyActions = mUserIdsAdapter.getSelectedCertifyActions();
if (certifyActions.isEmpty()) {
@@ -370,7 +329,7 @@ public class CertifyKeyFragment extends LoaderFragment
Bundle data = new Bundle();
{
// fill values for this action
- CertifyActionsParcel parcel = new CertifyActionsParcel(new Date(), mSignMasterKeyId);
+ CertifyActionsParcel parcel = new CertifyActionsParcel(cryptoInput, mSignMasterKeyId);
parcel.mCertifyActions.addAll(certifyActions);
data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel);
@@ -390,14 +349,21 @@ public class CertifyKeyFragment extends LoaderFragment
} else {
// Message is received after signing is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(),
- getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) {
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ getActivity(), getString(R.string.progress_certifying),
+ ProgressDialog.STYLE_SPINNER, true) {
public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
+ // handle messages by KeychainIntentCryptoServiceHandler first
super.handleMessage(message);
+ // handle pending messages
+ if (handlePendingMessage(message)) {
+ return;
+ }
+
if (message.arg1 == MessageStatus.OKAY.ordinal()) {
Bundle data = message.getData();
+
CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
Intent intent = new Intent();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java
new file mode 100644
index 000000000..a1d70b011
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CryptoOperationFragment.java
@@ -0,0 +1,89 @@
+package org.sufficientlysecure.keychain.ui;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.support.v4.app.Fragment;
+
+import org.sufficientlysecure.keychain.operations.results.CertifyResult;
+import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler.MessageStatus;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.NfcOperationsParcel;
+
+
+public abstract class CryptoOperationFragment extends Fragment {
+
+ public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
+ public static final int REQUEST_CODE_NFC = 0x00008002;
+
+ private void startPassphraseDialog(long subkeyId) {
+ Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
+ intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId);
+ startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
+ }
+
+ private void initiateNfcInput(NfcOperationsParcel nfcOps) {
+ Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
+ intent.putExtra(NfcOperationActivity.EXTRA_PIN, "123456");
+ intent.putExtra(NfcOperationActivity.EXTRA_NFC_OPS, nfcOps);
+ startActivityForResult(intent, REQUEST_CODE_NFC);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case REQUEST_CODE_PASSPHRASE: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
+ cryptoOperation(passphrase);
+ }
+ return;
+ }
+
+ case REQUEST_CODE_NFC: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ CryptoInputParcel cryptoInput =
+ data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
+ cryptoOperation(cryptoInput);
+ return;
+ }
+ break;
+ }
+
+ default: {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+ }
+
+ public boolean handlePendingMessage(Message message) {
+
+ if (message.arg1 == MessageStatus.OKAY.ordinal()) {
+ Bundle data = message.getData();
+
+ InputPendingResult result = data.getParcelable(CertifyResult.EXTRA_RESULT);
+
+ if (result != null && result.isPending()) {
+ if (result.isPassphrasePending()) {
+ startPassphraseDialog(result.getPassphraseKeyId());
+ return true;
+ } else if (result.isNfcPending()) {
+ NfcOperationsParcel requiredInput = result.getNfcOperationsParcel();
+ initiateNfcInput(requiredInput);
+ return true;
+ } else {
+ throw new RuntimeException("Unhandled pending result!");
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected abstract void cryptoOperation(CryptoInputParcel cryptoInput);
+ protected abstract void cryptoOperation(String passphrase);
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
index c1403d748..f226e71c0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcOperationActivity.java
@@ -182,17 +182,17 @@ public class NfcOperationActivity extends BaseActivity {
case NFC_DECRYPT:
- for (int i = 0; i < mNfcOperations.mInputHash.length; i++) {
- byte[] hash = mNfcOperations.mInputHash[i];
+ for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) {
+ byte[] hash = mNfcOperations.mInputHashes[i];
byte[] decryptedSessionKey = nfcDecryptSessionKey(hash);
resultData.addCryptoData(hash, decryptedSessionKey);
}
break;
case NFC_SIGN:
- for (int i = 0; i < mNfcOperations.mInputHash.length; i++) {
- byte[] hash = mNfcOperations.mInputHash[i];
- int algo = mNfcOperations.mSignAlgo[i];
+ for (int i = 0; i < mNfcOperations.mInputHashes.length; i++) {
+ byte[] hash = mNfcOperations.mInputHashes[i];
+ int algo = mNfcOperations.mSignAlgos[i];
byte[] signedHash = nfcCalculateSignature(hash, algo);
resultData.addCryptoData(hash, signedHash);
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index f1c14bd32..2eb167c8c 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -1099,9 +1099,9 @@
<string name="msg_crt_error_master_not_found">"Master key not found!"</string>
<string name="msg_crt_error_nothing">"No keys certified!"</string>
<string name="msg_crt_error_unlock">"Error unlocking master key!"</string>
- <string name="msg_crt_error_divert">"Certification with NFC is not (yet) supported!"</string>
<string name="msg_crt">"Certifying keyrings"</string>
<string name="msg_crt_master_fetch">"Fetching certifying master key"</string>
+ <string name="msg_crt_nfc_return">"Returning for NFC input"</string>
<string name="msg_crt_save">"Saving certified key %s"</string>
<string name="msg_crt_saving">"Saving keyrings"</string>
<string name="msg_crt_unlock">"Unlocking master key"</string>