From 1a0635c71e87e39a24bf7e3f2b07016e8fa7f881 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 7 Sep 2021 17:30:40 +0200 Subject: [PATCH] detach-inband-signature-and-message: test --no-armor --- .../java/org/pgpainless/cli/TestUtils.java | 50 +++++++++++------- .../DetachInbandSignatureAndMessageTest.java | 51 +++++++++++++++---- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/TestUtils.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/TestUtils.java index 4f4c73a9..819e85f8 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/TestUtils.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/TestUtils.java @@ -16,6 +16,8 @@ package org.pgpainless.cli; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -26,17 +28,21 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Random; -import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.util.io.Streams; public class TestUtils { + public static final String ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private static final Random RANDOM = new Random(); public static final String ARMOR_PRIVATE_KEY_HEADER = "-----BEGIN PGP PRIVATE KEY BLOCK-----"; public static final byte[] ARMOR_PRIVATE_KEY_HEADER_BYTES = ARMOR_PRIVATE_KEY_HEADER.getBytes(StandardCharsets.UTF_8); + public static final String ARMOR_SIGNATURE_HEADER = "-----BEGIN PGP SIGNATURE-----"; + public static final byte[] ARMOR_SIGNATURE_HEADER_BYTES = + ARMOR_SIGNATURE_HEADER.getBytes(StandardCharsets.UTF_8); public static File createTempDirectory() throws IOException { String name = randomString(10); @@ -58,30 +64,40 @@ public class TestUtils { } public static void assertSignatureEquals(byte[] sig1, byte[] sig2) throws IOException { - ByteArrayInputStream sigIn1 = new ByteArrayInputStream(sig1); - ByteArrayInputStream sigIn2 = new ByteArrayInputStream(sig2); + InputStream sigIn1 = PGPUtil.getDecoderStream(new ByteArrayInputStream(sig1)); + InputStream sigIn2 = PGPUtil.getDecoderStream(new ByteArrayInputStream(sig2)); assertSignatureEquals(sigIn1, sigIn2); } public static void assertSignatureEquals(InputStream sig1, InputStream sig2) throws IOException { - ArmoredInputStream armor1; - ArmoredInputStream armor2; - if (sig1 instanceof ArmoredInputStream) { - armor1 = (ArmoredInputStream) sig1; - } else { - armor1 = new ArmoredInputStream(sig1); - } - if (sig2 instanceof ArmoredInputStream) { - armor2 = (ArmoredInputStream) sig2; - } else { - armor2 = new ArmoredInputStream(sig2); - } ByteArrayOutputStream bout1 = new ByteArrayOutputStream(); ByteArrayOutputStream bout2 = new ByteArrayOutputStream(); - Streams.pipeAll(armor1, bout1); - Streams.pipeAll(armor2, bout2); + Streams.pipeAll(sig1, bout1); + Streams.pipeAll(sig2, bout2); assertArrayEquals(bout1.toByteArray(), bout2.toByteArray()); } + + public static void assertSignatureIsArmored(byte[] sig) { + assertTrue(isSignatureArmored(sig), "Signature encoding does not start with armor header.\n" + + "Expected: " + ARMOR_SIGNATURE_HEADER + "\n" + + "Actual: " + new String(sig)); + } + + public static void assertSignatureIsNotArmored(byte[] sig) { + assertFalse(isSignatureArmored(sig), "Signature encoding starts with armor header.\n" + + "Actual: " + new String(sig)); + } + + public static boolean isSignatureArmored(byte[] sig) { + boolean same = true; + for (int i = 0; i < ARMOR_SIGNATURE_HEADER_BYTES.length; i++) { + if (sig[i] != ARMOR_SIGNATURE_HEADER_BYTES[i]) { + same = false; + break; + } + } + return same; + } } diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/DetachInbandSignatureAndMessageTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/DetachInbandSignatureAndMessageTest.java index 8114fde4..605e767b 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/DetachInbandSignatureAndMessageTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/DetachInbandSignatureAndMessageTest.java @@ -44,8 +44,6 @@ public class DetachInbandSignatureAndMessageTest { private PrintStream originalSout; private static File tempDir; private static File certFile; - private static File tempSigFile; - private static File existingSigFile; private static final String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + "Version: BCPG v1.64\n" + @@ -66,11 +64,6 @@ public class DetachInbandSignatureAndMessageTest { public static void createTempDir() throws IOException { tempDir = TestUtils.createTempDirectory(); - tempSigFile = new File(tempDir, "sig.out"); - - existingSigFile = new File(tempDir, "sig.existing"); - assertTrue(existingSigFile.getCanonicalFile().createNewFile()); - certFile = new File(tempDir, "cert.asc"); assertTrue(certFile.createNewFile()); try (FileOutputStream out = new FileOutputStream(certFile)) { @@ -132,6 +125,7 @@ public class DetachInbandSignatureAndMessageTest { System.setOut(new PrintStream(msgOut)); // Detach + File tempSigFile = new File(tempDir, "sig.out"); PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + tempSigFile.getAbsolutePath()}); // Test equality with expected values @@ -139,7 +133,44 @@ public class DetachInbandSignatureAndMessageTest { try (FileInputStream sigIn = new FileInputStream(tempSigFile)) { ByteArrayOutputStream sigBytes = new ByteArrayOutputStream(); Streams.pipeAll(sigIn, sigBytes); - TestUtils.assertSignatureEquals(CLEAR_SIGNED_SIGNATURE, sigBytes.toString()); + String sig = sigBytes.toString(); + TestUtils.assertSignatureIsArmored(sigBytes.toByteArray()); + TestUtils.assertSignatureEquals(CLEAR_SIGNED_SIGNATURE, sig); + } catch (FileNotFoundException e) { + fail("Signature File must have been written.", e); + } + + // Check if produced signature still checks out + System.setIn(new ByteArrayInputStream(msgOut.toByteArray())); + ByteArrayOutputStream verifyOut = new ByteArrayOutputStream(); + System.setOut(new PrintStream(verifyOut)); + PGPainlessCLI.main(new String[] {"verify", tempSigFile.getAbsolutePath(), certFile.getAbsolutePath()}); + + assertEquals("2021-05-15T16:08:06Z 4F665C4DC2C4660BC6425E415736E6931ACF370C 4F665C4DC2C4660BC6425E415736E6931ACF370C\n", verifyOut.toString()); + } + + @Test + public void detachInbandSignatureAndMessageNoArmor() throws IOException { + // Clearsigned In + ByteArrayInputStream clearSignedIn = new ByteArrayInputStream(CLEAR_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8)); + System.setIn(clearSignedIn); + + // Plaintext Out + ByteArrayOutputStream msgOut = new ByteArrayOutputStream(); + System.setOut(new PrintStream(msgOut)); + + // Detach + File tempSigFile = new File(tempDir, "sig.asc"); + PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + tempSigFile.getAbsolutePath(), "--no-armor"}); + + // Test equality with expected values + assertEquals(CLEAR_SIGNED_BODY, msgOut.toString()); + try (FileInputStream sigIn = new FileInputStream(tempSigFile)) { + ByteArrayOutputStream sigBytes = new ByteArrayOutputStream(); + Streams.pipeAll(sigIn, sigBytes); + byte[] sig = sigBytes.toByteArray(); + TestUtils.assertSignatureIsNotArmored(sig); + TestUtils.assertSignatureEquals(CLEAR_SIGNED_SIGNATURE.getBytes(StandardCharsets.UTF_8), sig); } catch (FileNotFoundException e) { fail("Signature File must have been written.", e); } @@ -155,7 +186,7 @@ public class DetachInbandSignatureAndMessageTest { @Test @ExpectSystemExitWithStatus(SOPGPException.OutputExists.EXIT_CODE) - public void existingSignatureOutCausesException() { + public void existingSignatureOutCausesException() throws IOException { // Clearsigned In ByteArrayInputStream clearSignedIn = new ByteArrayInputStream(CLEAR_SIGNED_MESSAGE.getBytes(StandardCharsets.UTF_8)); System.setIn(clearSignedIn); @@ -165,6 +196,8 @@ public class DetachInbandSignatureAndMessageTest { System.setOut(new PrintStream(msgOut)); // Detach + File existingSigFile = new File(tempDir, "sig.existing"); + assertTrue(existingSigFile.createNewFile()); PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + existingSigFile.getAbsolutePath()}); }