pgpainless/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CleartextSignatureVerificat...

211 lines
9.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2021 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless;
import org.pgpainless.exception.WrongConsumingMethodException;
import org.pgpainless.key.TestKeys;
import org.pgpainless.signature.CertificateValidator;
import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.signature.SignatureVerifier;
import org.pgpainless.decryption_verification.cleartext_signatures.CleartextSignatureProcessor;
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy;
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
import org.pgpainless.util.ArmorUtils;
import org.pgpainless.util.TestUtils;
public class CleartextSignatureVerificationTest {
public static final byte[] MESSAGE_BODY = ("Ah, Juliet, if the measure of thy joy\n" +
"Be heaped like mine, and that thy skill be more\n" +
"To blazon it, then sweeten with thy breath\n" +
"This neighbor air, and let rich musics tongue\n" +
"Unfold the imagined happiness that both\n" +
"Receive in either by this dear encounter.").getBytes(StandardCharsets.UTF_8);
public static final byte[] MESSAGE_SIGNED = ("-----BEGIN PGP SIGNED MESSAGE-----\n" +
"Hash: SHA512\n" +
"\n" +
"Ah, Juliet, if the measure of thy joy\n" +
"Be heaped like mine, and that thy skill be more\n" +
"To blazon it, then sweeten with thy breath\n" +
"This neighbor air, and let rich musics tongue\n" +
"Unfold the imagined happiness that both\n" +
"Receive in either by this dear encounter.\n" +
"-----BEGIN PGP SIGNATURE-----\n" +
"\n" +
"iHUEARMKAB0WIQRPZlxNwsRmC8ZCXkFXNuaTGs83DAUCYJ/x5gAKCRBXNuaTGs83\n" +
"DFRwAP9/4wMvV3WcX59Clo7mkRce6iwW3VBdiN+yMu3tjmHB2wD/RfE28Q1v4+eo\n" +
"ySNgbyvqYYsNr0fnBwaG3aaj+u5ExiE=\n" +
"=Z2SO\n" +
"-----END PGP SIGNATURE-----").getBytes(StandardCharsets.UTF_8);
public static final byte[] SIGNATURE = ("-----BEGIN PGP SIGNATURE-----\n" +
"\n" +
"iHUEARMKAB0WIQRPZlxNwsRmC8ZCXkFXNuaTGs83DAUCYJ/x5gAKCRBXNuaTGs83\n" +
"DFRwAP9/4wMvV3WcX59Clo7mkRce6iwW3VBdiN+yMu3tjmHB2wD/RfE28Q1v4+eo\n" +
"ySNgbyvqYYsNr0fnBwaG3aaj+u5ExiE=\n" +
"=Z2SO\n" +
"-----END PGP SIGNATURE-----").getBytes(StandardCharsets.UTF_8);
@Test
public void cleartextSignVerification_InMemoryMultiPassStrategy() throws IOException, PGPException {
PGPPublicKeyRing signingKeys = TestKeys.getEmilPublicKeyRing();
ConsumerOptions options = new ConsumerOptions()
.addVerificationCert(signingKeys);
InMemoryMultiPassStrategy multiPassStrategy = MultiPassStrategy.keepMessageInMemory();
CleartextSignatureProcessor processor = PGPainless.verifyCleartextSignedMessage()
.onInputStream(new ByteArrayInputStream(MESSAGE_SIGNED))
.withStrategy(multiPassStrategy)
.withOptions(options);
OpenPgpMetadata result = processor.process();
assertTrue(result.isVerified());
PGPSignature signature = result.getVerifiedSignatures().values().iterator().next();
assertEquals(signature.getKeyID(), signingKeys.getPublicKey().getKeyID());
assertArrayEquals(MESSAGE_BODY, multiPassStrategy.getBytes());
}
@Test
public void cleartextSignVerification_FileBasedMultiPassStrategy() throws IOException, PGPException {
PGPPublicKeyRing signingKeys = TestKeys.getEmilPublicKeyRing();
ConsumerOptions options = new ConsumerOptions()
.addVerificationCert(signingKeys);
File tempDir = TestUtils.createTempDirectory();
File file = new File(tempDir, "file");
MultiPassStrategy multiPassStrategy = MultiPassStrategy.writeMessageToFile(file);
CleartextSignatureProcessor processor = PGPainless.verifyCleartextSignedMessage()
.onInputStream(new ByteArrayInputStream(MESSAGE_SIGNED))
.withStrategy(multiPassStrategy)
.withOptions(options);
OpenPgpMetadata result = processor.process();
assertTrue(result.isVerified());
PGPSignature signature = result.getVerifiedSignatures().values().iterator().next();
assertEquals(signature.getKeyID(), signingKeys.getPublicKey().getKeyID());
FileInputStream fileIn = new FileInputStream(file);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
Streams.pipeAll(fileIn, bytes);
fileIn.close();
assertArrayEquals(MESSAGE_BODY, bytes.toByteArray());
}
@Test
public void verifySignatureDetached() throws IOException, PGPException {
PGPPublicKeyRing signingKeys = TestKeys.getEmilPublicKeyRing();
PGPSignature signature = SignatureUtils.readSignatures(SIGNATURE).get(0);
PGPPublicKey signingKey = signingKeys.getPublicKey(signature.getKeyID());
SignatureVerifier.initializeSignatureAndUpdateWithSignedData(signature, new ByteArrayInputStream(MESSAGE_BODY), signingKey);
CertificateValidator.validateCertificateAndVerifyInitializedSignature(signature, signingKeys, PGPainless.getPolicy());
}
public static void main(String[] args) throws IOException {
// CHECKSTYLE:OFF
PGPPublicKeyRing keys = TestKeys.getEmilPublicKeyRing();
System.out.println(ArmorUtils.toAsciiArmoredString(keys));
System.out.println(new String(MESSAGE_SIGNED));
System.out.println(new String(MESSAGE_BODY));
System.out.println(new String(SIGNATURE));
// CHECKSTYLE:ON
}
@Test
public void testOutputOfSigVerification() throws IOException, PGPException {
PGPSignature signature = SignatureUtils.readSignatures(SIGNATURE).get(0);
ConsumerOptions options = new ConsumerOptions()
.addVerificationCert(TestKeys.getEmilPublicKeyRing())
.addVerificationOfDetachedSignature(signature);
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(MESSAGE_BODY))
.withOptions(options);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Streams.pipeAll(decryptionStream, out);
decryptionStream.close();
OpenPgpMetadata metadata = decryptionStream.getResult();
assertEquals(1, metadata.getVerifiedSignatures().size());
}
@Test
public void consumingCleartextSignedMessageWithNormalAPIThrowsWrongConsumingMethodException() throws IOException, PGPException {
PGPPublicKeyRing certificate = TestKeys.getEmilPublicKeyRing();
ConsumerOptions options = new ConsumerOptions()
.addVerificationCert(certificate);
assertThrows(WrongConsumingMethodException.class, () ->
PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(MESSAGE_SIGNED))
.withOptions(options));
}
@Test
public void consumingInlineSignedMessageWithCleartextSignedVerificationApiThrowsWrongConsumingMethodException() throws PGPException, IOException {
String inlineSignedMessage = "-----BEGIN PGP MESSAGE-----\n" +
"Version: PGPainless\n" +
"\n" +
"kA0DAQoTVzbmkxrPNwwBy8BJYgAAAAAAQWgsIEp1bGlldCwgaWYgdGhlIG1lYXN1\n" +
"cmUgb2YgdGh5IGpveQpCZSBoZWFwZWQgbGlrZSBtaW5lLCBhbmQgdGhhdCB0aHkg\n" +
"c2tpbGwgYmUgbW9yZQpUbyBibGF6b24gaXQsIHRoZW4gc3dlZXRlbiB3aXRoIHRo\n" +
"eSBicmVhdGgKVGhpcyBuZWlnaGJvciBhaXIsIGFuZCBsZXQgcmljaCBtdXNpY+KA\n" +
"mXMgdG9uZ3VlClVuZm9sZCB0aGUgaW1hZ2luZWQgaGFwcGluZXNzIHRoYXQgYm90\n" +
"aApSZWNlaXZlIGluIGVpdGhlciBieSB0aGlzIGRlYXIgZW5jb3VudGVyLoh1BAET\n" +
"CgAGBQJhK2q9ACEJEFc25pMazzcMFiEET2ZcTcLEZgvGQl5BVzbmkxrPNwxr8gD+\n" +
"MDfg+qccpsoJVgHIW8mRPBQowXDyw+oNHsf28ii+/pEBAO/RXhFkZBPzlfDJMJVT\n" +
"UwJJeuna1R4yOoWjq0zqRvrg\n" +
"=dBiV\n" +
"-----END PGP MESSAGE-----\n";
PGPPublicKeyRing certificate = TestKeys.getEmilPublicKeyRing();
ConsumerOptions options = new ConsumerOptions()
.addVerificationCert(certificate);
assertThrows(WrongConsumingMethodException.class, () ->
PGPainless.verifyCleartextSignedMessage()
.onInputStream(new ByteArrayInputStream(inlineSignedMessage.getBytes(StandardCharsets.UTF_8)))
.withStrategy(new InMemoryMultiPassStrategy())
.withOptions(options)
.process());
}
}