mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-23 04:42:06 +01:00
Fix detection of unarmored data in detached signature verification
This commit is contained in:
parent
9b5cc2da5a
commit
458b4f1f78
3 changed files with 112 additions and 13 deletions
|
@ -46,6 +46,7 @@ import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import org.pgpainless.algorithm.EncryptionPurpose;
|
import org.pgpainless.algorithm.EncryptionPurpose;
|
||||||
import org.pgpainless.algorithm.StreamEncoding;
|
import org.pgpainless.algorithm.StreamEncoding;
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import org.pgpainless.exception.FinalIOException;
|
||||||
import org.pgpainless.exception.MessageNotIntegrityProtectedException;
|
import org.pgpainless.exception.MessageNotIntegrityProtectedException;
|
||||||
import org.pgpainless.exception.MissingDecryptionMethodException;
|
import org.pgpainless.exception.MissingDecryptionMethodException;
|
||||||
import org.pgpainless.exception.MissingLiteralDataException;
|
import org.pgpainless.exception.MissingLiteralDataException;
|
||||||
|
@ -154,7 +155,7 @@ public final class DecryptionStreamFactory {
|
||||||
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(decoderStream);
|
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(decoderStream);
|
||||||
// Parse OpenPGP message
|
// Parse OpenPGP message
|
||||||
inputStream = processPGPPackets(objectFactory, 1);
|
inputStream = processPGPPackets(objectFactory, 1);
|
||||||
} catch (EOFException e) {
|
} catch (EOFException | FinalIOException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (MissingLiteralDataException e) {
|
} catch (MissingLiteralDataException e) {
|
||||||
// Not an OpenPGP message.
|
// Not an OpenPGP message.
|
||||||
|
@ -174,7 +175,7 @@ public final class DecryptionStreamFactory {
|
||||||
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(decoderStream);
|
objectFactory = ImplementationFactory.getInstance().getPGPObjectFactory(decoderStream);
|
||||||
inputStream = wrapInVerifySignatureStream(bufferedIn, objectFactory);
|
inputStream = wrapInVerifySignatureStream(bufferedIn, objectFactory);
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw new FinalIOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,18 +196,28 @@ public final class DecryptionStreamFactory {
|
||||||
throw new PGPException("Maximum depth of nested packages exceeded.");
|
throw new PGPException("Maximum depth of nested packages exceeded.");
|
||||||
}
|
}
|
||||||
Object nextPgpObject;
|
Object nextPgpObject;
|
||||||
while ((nextPgpObject = objectFactory.nextObject()) != null) {
|
try {
|
||||||
if (nextPgpObject instanceof PGPEncryptedDataList) {
|
while ((nextPgpObject = objectFactory.nextObject()) != null) {
|
||||||
return processPGPEncryptedDataList((PGPEncryptedDataList) nextPgpObject, depth);
|
if (nextPgpObject instanceof PGPEncryptedDataList) {
|
||||||
|
return processPGPEncryptedDataList((PGPEncryptedDataList) nextPgpObject, depth);
|
||||||
|
}
|
||||||
|
if (nextPgpObject instanceof PGPCompressedData) {
|
||||||
|
return processPGPCompressedData((PGPCompressedData) nextPgpObject, depth);
|
||||||
|
}
|
||||||
|
if (nextPgpObject instanceof PGPOnePassSignatureList) {
|
||||||
|
return processOnePassSignatureList(objectFactory, (PGPOnePassSignatureList) nextPgpObject, depth);
|
||||||
|
}
|
||||||
|
if (nextPgpObject instanceof PGPLiteralData) {
|
||||||
|
return processPGPLiteralData(objectFactory, (PGPLiteralData) nextPgpObject, depth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (nextPgpObject instanceof PGPCompressedData) {
|
} catch (FinalIOException e) {
|
||||||
return processPGPCompressedData((PGPCompressedData) nextPgpObject, depth);
|
throw e;
|
||||||
}
|
} catch (IOException e) {
|
||||||
if (nextPgpObject instanceof PGPOnePassSignatureList) {
|
if (depth == 1 && e.getMessage().contains("unknown object in stream:")) {
|
||||||
return processOnePassSignatureList(objectFactory, (PGPOnePassSignatureList) nextPgpObject, depth);
|
throw new MissingLiteralDataException("No Literal Data Packet found.");
|
||||||
}
|
} else {
|
||||||
if (nextPgpObject instanceof PGPLiteralData) {
|
throw new FinalIOException(e);
|
||||||
return processPGPLiteralData(objectFactory, (PGPLiteralData) nextPgpObject, depth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.exception;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for {@link IOException} indicating that we need to throw this exception up.
|
||||||
|
*/
|
||||||
|
public class FinalIOException extends IOException {
|
||||||
|
|
||||||
|
public FinalIOException(IOException e) {
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.util.io.Streams;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy;
|
||||||
|
|
||||||
|
public class VerifyDetachedSignatureTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verify() throws PGPException, IOException {
|
||||||
|
String signedContent = "Content-Type: multipart/mixed; boundary=\"OSR6TONWKJD9dgyc2XH5AQPNnAs7pdg1t\"\n" +
|
||||||
|
"\n" +
|
||||||
|
"--OSR6TONWKJD9dgyc2XH5AQPNnAs7pdg1t\n" +
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n" +
|
||||||
|
"Content-Transfer-Encoding: quoted-printable\n" +
|
||||||
|
"Content-Language: en-US\n" +
|
||||||
|
"\n" +
|
||||||
|
"NOT encrypted + signed(detached)\n" +
|
||||||
|
"\n" +
|
||||||
|
"\n" +
|
||||||
|
"\n" +
|
||||||
|
"--OSR6TONWKJD9dgyc2XH5AQPNnAs7pdg1t--\n";
|
||||||
|
String signature = "-----BEGIN PGP SIGNATURE-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"iHUEARYIAB0WIQTBZCjWAcs5N4nPYdTDIInNavjWzgUCYgKPzAAKCRDDIInNavjW\n" +
|
||||||
|
"zmdoAP0TdFt1OWqosHhXxt2hNYqZQMc6bgQRpJNL029nRyzkPAD/SoYJ4T+aYEhw\n" +
|
||||||
|
"11qrbXloqkr0G3QaA6/zk31RPMI/bgI=\n" +
|
||||||
|
"=o5Ze\n" +
|
||||||
|
"-----END PGP SIGNATURE-----\n";
|
||||||
|
String pubkey = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"\n" +
|
||||||
|
"mDMEYIucWBYJKwYBBAHaRw8BAQdAew+8mzMWyf3+Pfy49qa60uKV6e5os7de4TdZ\n" +
|
||||||
|
"ceAWUq+0F2RlbmJvbmQ3QGZsb3djcnlwdC50ZXN0iHgEExYKACAFAmCLnFgCGwMF\n" +
|
||||||
|
"FgIDAQAECwkIBwUVCgkICwIeAQIZAQAKCRDDIInNavjWzm3JAQCgFgCEyD58iEa/\n" +
|
||||||
|
"Rw/DYNoQNoZC1lhw1bxBiOcIbtkdBgEAsDFZu3TBavOMKI7KW+vfMBHtRVbkMNpv\n" +
|
||||||
|
"unaAldoabgO4OARgi5xYEgorBgEEAZdVAQUBAQdAB1/Mrq5JGYim4KqGTSK4OESQ\n" +
|
||||||
|
"UwPgK56q0yrkiU9WgyYDAQgHiHUEGBYKAB0FAmCLnFgCGwwFFgIDAQAECwkIBwUV\n" +
|
||||||
|
"CgkICwIeAQAKCRDDIInNavjWzjMgAQCU+R1fItqdY6lt9jXUqipmXuqVaEFPwNA8\n" +
|
||||||
|
"YJ1rIwDwVQEAyUc8162KWzA2iQB5akwLwNr/pLDDtOWwhLUkrBb3mAc=\n" +
|
||||||
|
"=pXF6\n" +
|
||||||
|
"-----END PGP PUBLIC KEY BLOCK-----\n";
|
||||||
|
|
||||||
|
|
||||||
|
DecryptionStream verifier = PGPainless.decryptAndOrVerify()
|
||||||
|
.onInputStream(new ByteArrayInputStream(signedContent.getBytes(StandardCharsets.UTF_8)))
|
||||||
|
.withOptions(
|
||||||
|
new ConsumerOptions()
|
||||||
|
.addVerificationOfDetachedSignatures(new ByteArrayInputStream(signature.getBytes(StandardCharsets.UTF_8)))
|
||||||
|
.addVerificationCerts(PGPainless.readKeyRing().keyRingCollection(pubkey, true).getPgpPublicKeyRingCollection())
|
||||||
|
.setMultiPassStrategy(new InMemoryMultiPassStrategy())
|
||||||
|
);
|
||||||
|
|
||||||
|
Streams.drain(verifier);
|
||||||
|
verifier.close();
|
||||||
|
OpenPgpMetadata metadata = verifier.getResult();
|
||||||
|
assertTrue(metadata.isVerified());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue