aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-10-08 13:53:58 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-10-08 13:53:58 +0200
commitfe8db664a86a35b18ec62ddaaa82cf7aafff1e4d (patch)
tree374247dfbb6748a7a2ca9ecca4b4a33476844b9e /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
parentf6de2712d3edef9837a53da5d78a9daa28639af4 (diff)
downloadopen-keychain-fe8db664a86a35b18ec62ddaaa82cf7aafff1e4d.tar.gz
open-keychain-fe8db664a86a35b18ec62ddaaa82cf7aafff1e4d.tar.bz2
open-keychain-fe8db664a86a35b18ec62ddaaa82cf7aafff1e4d.zip
pgpdecryptverify: refactor signature verification state into SignatureChecker subclass
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java275
1 files changed, 141 insertions, 134 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
index 4f3f323a5..d613b08eb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java
@@ -207,22 +207,18 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
updateProgress(R.string.progress_decompressing_data, 80, 100);
}
- // all we want to see is a OnePassSignatureList followed by LiteralData
- if (!(o instanceof PGPOnePassSignatureList)) {
+ SignatureChecker signatureChecker = new SignatureChecker();
+ if ( ! signatureChecker.initializeOnePassSignature(o, log, indent)) {
log.add(LogType.MSG_VL_ERROR_MISSING_SIGLIST, indent);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) o;
- SignatureData signatureData = findAvailableSignature(sigList);
-
- if (signatureData == null) {
+ if ( ! signatureChecker.isInitialized()) {
log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
- Log.d(Constants.TAG, "Failed to find signature with available key in signed-literal message");
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signatureData.signingKey.getFingerprint());
+ String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signatureChecker.getSigningFingerprint());
if (!(input.getRequiredSignerFingerprint().equals(fingerprint))) {
log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent);
Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + input.getRequiredSignerFingerprint() +
@@ -230,16 +226,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
-
- PGPOnePassSignature signature = sigList.get(signatureData.signatureIndex);
- signatureResultBuilder.initValid(signatureData.signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signatureData.signingKey.getPublicKey());
-
o = pgpF.nextObject();
if (!(o instanceof PGPLiteralData)) {
@@ -258,38 +244,18 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
byte[] buffer = new byte[1 << 16];
while ((length = dataIn.read(buffer)) > 0) {
out.write(buffer, 0, length);
- signature.update(buffer, 0, length);
+ signatureChecker.updateSignatureData(buffer, 0, length);
}
updateProgress(R.string.progress_verifying_signature, 95, 100);
log.add(LogType.MSG_VL_CLEAR_SIGNATURE_CHECK, indent + 1);
o = pgpF.nextObject();
- if ( ! (o instanceof PGPSignatureList) ) {
- log.add(LogType.MSG_VL_ERROR_NO_SIGNATURE, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
- PGPSignatureList signatureList = (PGPSignatureList) o;
- if (signatureList.size() <= signatureData.signatureIndex) {
- log.add(LogType.MSG_VL_ERROR_NO_SIGNATURE, indent);
+ if ( ! signatureChecker.verifySignature(o, log, indent) ) {
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- // PGPOnePassSignature and PGPSignature packets are "bracketed",
- // so we need to take the last-minus-index'th element here
- PGPSignature messageSignature = signatureList.get(signatureList.size() -1 -signatureData.signatureIndex);
-
- // Verify signature and check binding signatures
- boolean validSignature = signature.verify(messageSignature);
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
-
- signatureResultBuilder.setValidSignature(validSignature);
-
- OpenPgpSignatureResult signatureResult = signatureResultBuilder.build();
+ OpenPgpSignatureResult signatureResult = signatureChecker.getSignatureResult();
if (signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_CONFIRMED
&& signatureResult.getResult() != OpenPgpSignatureResult.RESULT_VALID_UNCONFIRMED) {
@@ -364,7 +330,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
}
- OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder();
JcaPGPObjectFactory plainFact;
@@ -411,8 +376,6 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_PREP_STREAMS, indent);
- SignatureData signatureData = null;
-
log.add(LogType.MSG_DC_CLEAR, indent);
indent += 1;
@@ -429,41 +392,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
plainFact = fact;
}
- // resolve leading signature data
- PGPOnePassSignature signature = null;
- if (dataChunk instanceof PGPOnePassSignatureList) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1);
- currentProgress += 2;
- updateProgress(R.string.progress_processing_signature, currentProgress, 100);
-
- PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
- signatureData = findAvailableSignature(sigList);
-
- if (signatureData != null) {
- // key found in our database!
- signature = sigList.get(signatureData.signatureIndex);
- signatureResultBuilder.initValid(signatureData.signingKey);
-
- JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
- new JcaPGPContentVerifierBuilderProvider()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
- signature.init(contentVerifierBuilderProvider, signatureData.signingKey.getPublicKey());
- } else {
- // no key in our database -> return "unknown pub key" status including the first key id
- if (!sigList.isEmpty()) {
- signatureResultBuilder.setSignatureAvailable(true);
- signatureResultBuilder.setKnownKey(false);
- signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
- }
- }
-
- // check for insecure signing key
- // TODO: checks on signingRing ?
- if (signatureData != null && ! PgpSecurityConstants.isSecureKey(signatureData.signingKey)) {
- log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
- signatureResultBuilder.setInsecure(true);
- }
-
+ SignatureChecker signatureChecker = new SignatureChecker();
+ if (signatureChecker.initializeOnePassSignature(dataChunk, log, indent +1)) {
dataChunk = plainFact.nextObject();
}
@@ -544,16 +474,8 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
return result;
}
- int endProgress;
- if (signature != null) {
- endProgress = 90;
- } else if (esResult != null && esResult.encryptedData.isIntegrityProtected()) {
- endProgress = 95;
- } else {
- endProgress = 100;
- }
ProgressScaler progressScaler =
- new ProgressScaler(mProgressable, currentProgress, endProgress, 100);
+ new ProgressScaler(mProgressable, currentProgress, 95, 100);
InputStream dataIn = literalData.getInputStream();
@@ -568,9 +490,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
// update signature buffer if signature is also present
- if (signature != null) {
- signature.update(buffer, 0, length);
- }
+ signatureChecker.updateSignatureData(buffer, 0, length);
alreadyWritten += length;
if (wholeSize > 0) {
@@ -587,40 +507,17 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
metadata = new OpenPgpMetadata(
originalFilename, mimeType, literalData.getModificationTime().getTime(), alreadyWritten, charset);
- if (signatureData != null) {
- updateProgress(R.string.progress_verifying_signature, 90, 100);
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
+ if (signatureChecker.isInitialized()) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
Object o = plainFact.nextObject();
- if ( ! (o instanceof PGPSignatureList) ) {
- log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
- PGPSignatureList signatureList = (PGPSignatureList) o;
- if (signatureList.size() <= signatureData.signatureIndex) {
- log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
- return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
- }
-
- // PGPOnePassSignature and PGPSignature packets are "bracketed",
- // so we need to take the last-minus-index'th element here
- PGPSignature messageSignature = signatureList.get(signatureList.size() -1 - signatureData.signatureIndex);
- // Verify signature
- boolean validSignature = signature.verify(messageSignature);
- if (validSignature) {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
- } else {
- log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
- }
+ boolean signatureCheckOk = signatureChecker.verifySignature(o, log, indent+1);
- // check for insecure hash algorithms
- if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
- log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
- signatureResultBuilder.setInsecure(true);
+ if (!signatureCheckOk) {
+ return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- signatureResultBuilder.setValidSignature(validSignature);
}
indent -= 1;
@@ -635,7 +532,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent);
return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
}
- } else if (signature == null) {
+ } else if ( ! signatureChecker.isInitialized() ) {
// If no signature is present, we *require* an MDC!
// Handle missing integrity protection like failed integrity protection!
// The MDC packet can be stripped by an attacker!
@@ -652,7 +549,7 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
result.setCachedCryptoInputParcel(cryptoInput);
- result.setSignatureResult(signatureResultBuilder.build());
+ result.setSignatureResult(signatureChecker.getSignatureResult());
result.setDecryptionResult(decryptionResultBuilder.build());
result.setDecryptionMetadata(metadata);
@@ -1279,21 +1176,131 @@ public class PgpDecryptVerifyOperation extends BaseOperation<PgpDecryptVerifyInp
}
- public SignatureData findAvailableSignature(PGPOnePassSignatureList sigList) {
- // go through all signatures (should be just one), make sure we have
- // the key and it matches the one we’re looking for
- for (int i = 0; i < sigList.size(); ++i) {
- try {
- long sigKeyId = sigList.get(i).getKeyID();
- CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
- );
- return new SignatureData(signingRing.getPublicKey(sigKeyId), i);
- } catch (ProviderHelper.NotFoundException e) {
- Log.d(Constants.TAG, "key not found, trying next signature...");
+ private class SignatureChecker {
+
+ OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
+
+ private CanonicalizedPublicKey signingKey;
+ // we use the signatureIndex instead of the signature itself here for two reasons:
+ // 1) the signature may be either of type PGPSignature or PGPOnePassSignature (which have no common ancestor)
+ // 2) in case of the latter, we need the signatureIndex to know which PGPSignature to use later on
+ private int signatureIndex;
+
+ PGPOnePassSignature signature;
+
+ boolean initializeOnePassSignature(Object dataChunk, OperationLog log, int indent) throws PGPException {
+
+ if ( ! (dataChunk instanceof PGPOnePassSignatureList) ) {
+ return false;
+ }
+
+ // resolve leading signature data
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent +1);
+
+ PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
+ findAvailableSignature(sigList);
+
+ if (signingKey != null) {
+
+ // key found in our database!
+ signature = sigList.get(signatureIndex);
+ signatureResultBuilder.initValid(signingKey);
+
+ JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
+ new JcaPGPContentVerifierBuilderProvider()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
+ signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey());
+
+ // TODO: checks on signingRing ?
+ if ( ! PgpSecurityConstants.isSecureKey(signingKey)) {
+ log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ } else if (!sigList.isEmpty()) {
+
+ signatureResultBuilder.setSignatureAvailable(true);
+ signatureResultBuilder.setKnownKey(false);
+ signatureResultBuilder.setKeyId(sigList.get(0).getKeyID());
+
+ }
+
+ return true;
+
+ }
+
+ public boolean isInitialized() {
+ return signingKey != null;
+ }
+
+ private void findAvailableSignature(PGPOnePassSignatureList sigList) {
+ // go through all signatures (should be just one), make sure we have
+ // the key and it matches the one we’re looking for
+ for (int i = 0; i < sigList.size(); ++i) {
+ try {
+ long sigKeyId = sigList.get(i).getKeyID();
+ CanonicalizedPublicKeyRing signingRing = mProviderHelper.getCanonicalizedPublicKeyRing(
+ KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId)
+ );
+ signatureIndex = i;
+ signingKey = signingRing.getPublicKey(sigKeyId);
+ return;
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.d(Constants.TAG, "key not found, trying next signature...");
+ }
}
}
- return null;
+
+ public void updateSignatureData(byte[] buf, int off, int len) {
+ if (signature != null) {
+ signature.update(buf, off, len);
+ }
+ }
+
+ boolean verifySignature(Object o, OperationLog log, int indent) throws PGPException {
+
+ if ( ! (o instanceof PGPSignatureList) ) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+ PGPSignatureList signatureList = (PGPSignatureList) o;
+ if (signatureList.size() <= signatureIndex) {
+ log.add(LogType.MSG_DC_ERROR_NO_SIGNATURE, indent);
+ return false;
+ }
+
+ // PGPOnePassSignature and PGPSignature packets are "bracketed",
+ // so we need to take the last-minus-index'th element here
+ PGPSignature messageSignature = signatureList.get(signatureList.size() -1 - signatureIndex);
+
+ // Verify signature
+ boolean validSignature = signature.verify(messageSignature);
+ if (validSignature) {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1);
+ } else {
+ log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1);
+ }
+
+ // check for insecure hash algorithms
+ if (!PgpSecurityConstants.isSecureHashAlgorithm(signature.getHashAlgorithm())) {
+ log.add(LogType.MSG_DC_INSECURE_HASH_ALGO, indent + 1);
+ signatureResultBuilder.setInsecure(true);
+ }
+
+ signatureResultBuilder.setValidSignature(validSignature);
+
+ return true;
+
+ }
+
+ public byte[] getSigningFingerprint() {
+ return signingKey.getFingerprint();
+ }
+
+ public OpenPgpSignatureResult getSignatureResult() {
+ return signatureResultBuilder.build();
+ }
+
}
public SignatureData findAvailableSignature(PGPSignatureList sigList) {