diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java index 1913444e..77ad92bb 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java @@ -155,6 +155,7 @@ public final class DecryptionStreamFactory { if (openPgpIn.isAsciiArmored()) { ArmoredInputStream armoredInputStream = ArmoredInputStreamFactory.get(openPgpIn); if (armoredInputStream.isClearText()) { + resultBuilder.setCleartextSigned(); return parseCleartextSignedMessage(armoredInputStream); } else { outerDecodingStream = armoredInputStream; diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java index 7c589c2c..2d9feb33 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java @@ -40,6 +40,7 @@ public class OpenPgpMetadata { private final String fileName; private final Date modificationDate; private final StreamEncoding fileEncoding; + private final boolean cleartextSigned; public OpenPgpMetadata(Set recipientKeyIds, SubkeyIdentifier decryptionKey, @@ -51,7 +52,8 @@ public class OpenPgpMetadata { List invalidDetachedSignatures, String fileName, Date modificationDate, - StreamEncoding fileEncoding) { + StreamEncoding fileEncoding, + boolean cleartextSigned) { this.recipientKeyIds = Collections.unmodifiableSet(recipientKeyIds); this.decryptionKey = decryptionKey; @@ -64,6 +66,7 @@ public class OpenPgpMetadata { this.fileName = fileName; this.modificationDate = modificationDate; this.fileEncoding = fileEncoding; + this.cleartextSigned = cleartextSigned; } /** @@ -269,6 +272,15 @@ public class OpenPgpMetadata { return fileEncoding; } + /** + * Return true if the message was signed using the cleartext signature framework. + * + * @return true if cleartext signed. + */ + public boolean isCleartextSigned() { + return cleartextSigned; + } + public static Builder getBuilder() { return new Builder(); } @@ -282,6 +294,7 @@ public class OpenPgpMetadata { private String fileName; private StreamEncoding fileEncoding; private Date modificationDate; + private boolean cleartextSigned = false; private final List verifiedInbandSignatures = new ArrayList<>(); private final List verifiedDetachedSignatures = new ArrayList<>(); @@ -324,29 +337,38 @@ public class OpenPgpMetadata { return this; } + public Builder addVerifiedInbandSignature(SignatureVerification signatureVerification) { + this.verifiedInbandSignatures.add(signatureVerification); + return this; + } + + public Builder addVerifiedDetachedSignature(SignatureVerification signatureVerification) { + this.verifiedDetachedSignatures.add(signatureVerification); + return this; + } + + public Builder addInvalidInbandSignature(SignatureVerification signatureVerification, SignatureValidationException e) { + this.invalidInbandSignatures.add(new SignatureVerification.Failure(signatureVerification, e)); + return this; + } + + public Builder addInvalidDetachedSignature(SignatureVerification signatureVerification, SignatureValidationException e) { + this.invalidDetachedSignatures.add(new SignatureVerification.Failure(signatureVerification, e)); + return this; + } + + public Builder setCleartextSigned() { + this.cleartextSigned = true; + return this; + } + public OpenPgpMetadata build() { return new OpenPgpMetadata( recipientFingerprints, decryptionKey, sessionKey, compressionAlgorithm, verifiedInbandSignatures, invalidInbandSignatures, verifiedDetachedSignatures, invalidDetachedSignatures, - fileName, modificationDate, fileEncoding); - } - - public void addVerifiedInbandSignature(SignatureVerification signatureVerification) { - this.verifiedInbandSignatures.add(signatureVerification); - } - - public void addVerifiedDetachedSignature(SignatureVerification signatureVerification) { - this.verifiedDetachedSignatures.add(signatureVerification); - } - - public void addInvalidInbandSignature(SignatureVerification signatureVerification, SignatureValidationException e) { - this.invalidInbandSignatures.add(new SignatureVerification.Failure(signatureVerification, e)); - } - - public void addInvalidDetachedSignature(SignatureVerification signatureVerification, SignatureValidationException e) { - this.invalidDetachedSignatures.add(new SignatureVerification.Failure(signatureVerification, e)); + fileName, modificationDate, fileEncoding, cleartextSigned); } } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CleartextSignatureVerificationTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CleartextSignatureVerificationTest.java index 12596988..521dd558 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CleartextSignatureVerificationTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CleartextSignatureVerificationTest.java @@ -94,6 +94,7 @@ public class CleartextSignatureVerificationTest { OpenPgpMetadata result = decryptionStream.getResult(); assertTrue(result.isVerified()); + assertTrue(result.isCleartextSigned()); PGPSignature signature = result.getVerifiedSignatures().values().iterator().next(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java index 7c44f307..152f4c33 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/DecryptAndVerifyMessageTest.java @@ -6,6 +6,7 @@ package org.pgpainless.decryption_verification; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; @@ -68,6 +69,7 @@ public class DecryptAndVerifyMessageTest { assertTrue(metadata.isEncrypted()); assertTrue(metadata.isSigned()); + assertFalse(metadata.isCleartextSigned()); assertTrue(metadata.isVerified()); assertEquals(CompressionAlgorithm.ZLIB, metadata.getCompressionAlgorithm()); assertEquals(SymmetricKeyAlgorithm.AES_256, metadata.getSymmetricKeyAlgorithm()); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSigned.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSigned.java index 0e979ead..0b2f5d7d 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSigned.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/SignedMessageVerificationWithoutCertIsStillSigned.java @@ -41,6 +41,7 @@ public class SignedMessageVerificationWithoutCertIsStillSigned { OpenPgpMetadata metadata = verificationStream.getResult(); + assertFalse(metadata.isCleartextSigned()); assertTrue(metadata.isSigned(), "Message is signed, even though we miss the verification cert."); assertFalse(metadata.isVerified(), "Message is not verified because we lack the verification cert."); } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java index 4c813efe..b9539ed5 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/DecryptImpl.java @@ -16,16 +16,15 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.util.io.Streams; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.decryption_verification.ConsumerOptions; import org.pgpainless.decryption_verification.DecryptionStream; import org.pgpainless.decryption_verification.OpenPgpMetadata; +import org.pgpainless.decryption_verification.SignatureVerification; import org.pgpainless.exception.MissingDecryptionMethodException; import org.pgpainless.exception.WrongPassphraseException; -import org.pgpainless.key.SubkeyIdentifier; import org.pgpainless.util.Passphrase; import sop.DecryptionResult; import sop.ReadyWithResult; @@ -151,12 +150,8 @@ public class DecryptImpl implements Decrypt { OpenPgpMetadata metadata = decryptionStream.getResult(); List verificationList = new ArrayList<>(); - for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) { - PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey); - verificationList.add(new Verification( - signature.getCreationTime(), - verifiedSigningKey.getSubkeyFingerprint().toString(), - verifiedSigningKey.getPrimaryKeyFingerprint().toString())); + for (SignatureVerification signatureVerification : metadata.getVerifiedInbandSignatures()) { + verificationList.add(map(signatureVerification)); } if (!consumerOptions.getCertificates().isEmpty()) { @@ -178,4 +173,10 @@ public class DecryptImpl implements Decrypt { } }; } + + private Verification map(SignatureVerification sigVerification) { + return new Verification(sigVerification.getSignature().getCreationTime(), + sigVerification.getSigningKey().getSubkeyFingerprint().toString(), + sigVerification.getSigningKey().getPrimaryKeyFingerprint().toString()); + } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedVerifyImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedVerifyImpl.java index d4db494f..81cb08ff 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedVerifyImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/DetachedVerifyImpl.java @@ -12,13 +12,12 @@ import java.util.List; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.util.io.Streams; import org.pgpainless.PGPainless; import org.pgpainless.decryption_verification.ConsumerOptions; import org.pgpainless.decryption_verification.DecryptionStream; import org.pgpainless.decryption_verification.OpenPgpMetadata; -import org.pgpainless.key.SubkeyIdentifier; +import org.pgpainless.decryption_verification.SignatureVerification; import sop.Verification; import sop.exception.SOPGPException; import sop.operation.DetachedVerify; @@ -75,12 +74,8 @@ public class DetachedVerifyImpl implements DetachedVerify { OpenPgpMetadata metadata = decryptionStream.getResult(); List verificationList = new ArrayList<>(); - for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) { - PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey); - verificationList.add(new Verification( - signature.getCreationTime(), - verifiedSigningKey.getSubkeyFingerprint().toString(), - verifiedSigningKey.getPrimaryKeyFingerprint().toString())); + for (SignatureVerification signatureVerification : metadata.getVerifiedDetachedSignatures()) { + verificationList.add(map(signatureVerification)); } if (!options.getCertificates().isEmpty()) { @@ -94,4 +89,10 @@ public class DetachedVerifyImpl implements DetachedVerify { throw new SOPGPException.BadData(e); } } + + private Verification map(SignatureVerification sigVerification) { + return new Verification(sigVerification.getSignature().getCreationTime(), + sigVerification.getSigningKey().getSubkeyFingerprint().toString(), + sigVerification.getSigningKey().getPrimaryKeyFingerprint().toString()); + } } diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineVerifyImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineVerifyImpl.java index 7c1f7ce2..7c31f44b 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineVerifyImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/InlineVerifyImpl.java @@ -4,20 +4,6 @@ package org.pgpainless.sop; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.util.io.Streams; -import org.pgpainless.PGPainless; -import org.pgpainless.decryption_verification.ConsumerOptions; -import org.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.decryption_verification.OpenPgpMetadata; -import org.pgpainless.key.SubkeyIdentifier; -import sop.ReadyWithResult; -import sop.Verification; -import sop.exception.SOPGPException; -import sop.operation.InlineVerify; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -25,6 +11,19 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; +import org.bouncycastle.util.io.Streams; +import org.pgpainless.PGPainless; +import org.pgpainless.decryption_verification.ConsumerOptions; +import org.pgpainless.decryption_verification.DecryptionStream; +import org.pgpainless.decryption_verification.OpenPgpMetadata; +import org.pgpainless.decryption_verification.SignatureVerification; +import sop.ReadyWithResult; +import sop.Verification; +import sop.exception.SOPGPException; +import sop.operation.InlineVerify; + public class InlineVerifyImpl implements InlineVerify { private final ConsumerOptions options = new ConsumerOptions(); @@ -70,12 +69,12 @@ public class InlineVerifyImpl implements InlineVerify { OpenPgpMetadata metadata = decryptionStream.getResult(); List verificationList = new ArrayList<>(); - for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) { - PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey); - verificationList.add(new Verification( - signature.getCreationTime(), - verifiedSigningKey.getSubkeyFingerprint().toString(), - verifiedSigningKey.getPrimaryKeyFingerprint().toString())); + List verifications = metadata.isCleartextSigned() ? + metadata.getVerifiedDetachedSignatures() : + metadata.getVerifiedInbandSignatures(); + + for (SignatureVerification signatureVerification : verifications) { + verificationList.add(map(signatureVerification)); } if (!options.getCertificates().isEmpty()) { @@ -91,4 +90,10 @@ public class InlineVerifyImpl implements InlineVerify { } }; } + + private Verification map(SignatureVerification sigVerification) { + return new Verification(sigVerification.getSignature().getCreationTime(), + sigVerification.getSigningKey().getSubkeyFingerprint().toString(), + sigVerification.getSigningKey().getPrimaryKeyFingerprint().toString()); + } }