2021-10-07 15:48:52 +02:00
|
|
|
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
|
|
|
|
//
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
2021-09-07 16:44:16 +02:00
|
|
|
|
package org.pgpainless.cli.commands;
|
|
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.fail;
|
|
|
|
|
|
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.PrintStream;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
|
|
|
|
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
|
|
|
|
import org.bouncycastle.util.io.Streams;
|
|
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
|
|
import org.junit.jupiter.api.BeforeAll;
|
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
import org.pgpainless.cli.PGPainlessCLI;
|
|
|
|
|
import org.pgpainless.cli.TestUtils;
|
|
|
|
|
import sop.exception.SOPGPException;
|
|
|
|
|
|
|
|
|
|
public class DetachInbandSignatureAndMessageTest {
|
|
|
|
|
|
|
|
|
|
private PrintStream originalSout;
|
|
|
|
|
private static File tempDir;
|
|
|
|
|
private static File certFile;
|
|
|
|
|
|
|
|
|
|
private static final String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
|
|
|
|
"Version: BCPG v1.64\n" +
|
|
|
|
|
"\n" +
|
|
|
|
|
"mFIEXhtfCBMIKoZIzj0DAQcCAwTGSFMBUOSLusXS8hdNHbdK3gN8hS7jd4ky7Czl\n" +
|
|
|
|
|
"mSti+oVyRJUwQAFZJ1NMsg1H8flSJP1/9YbHd9FBU4bHKGKPtBE8ZW1pbEBlbWFp\n" +
|
|
|
|
|
"bC51c2VyPoh1BBMTCgAdBQJeG18IAhsjBRYCAwEABAsJCAcFFQoJCAsCHgEACgkQ\n" +
|
|
|
|
|
"VzbmkxrPNwz8rAD/S/VCQc5NJLArgTDkgrt3Q573HiYfrIQo1uk3dwV15WIBAMiq\n" +
|
|
|
|
|
"oDmRMb8jzOBv6FGW4P5WAubPdnAvDD7XmArD+TSeuFYEXhtfCBIIKoZIzj0DAQcC\n" +
|
|
|
|
|
"AwTgWDWmHJLQUQ35Qg/rINmUhkUhj1E4O5t6Y2PipbqlGfDufLmIKnX40BoJPS4G\n" +
|
|
|
|
|
"HW7U0QXfwSaTXa1BAaNsMUomAwEIB4h1BBgTCgAdBQJeG18IAhsMBRYCAwEABAsJ\n" +
|
|
|
|
|
"CAcFFQoJCAsCHgEACgkQVzbmkxrPNwxOcwEA19Fnhw7XwpQoT61Fqg54vroAwTZ3\n" +
|
|
|
|
|
"T5A+LOdevAtzNOUA/RWeKfOGk6D+vKYRNpMJyqsHi/vBeKwXoeN0n6HuExVF\n" +
|
|
|
|
|
"=a1W7\n" +
|
|
|
|
|
"-----END PGP PUBLIC KEY BLOCK-----";
|
|
|
|
|
|
|
|
|
|
@BeforeAll
|
|
|
|
|
public static void createTempDir() throws IOException {
|
|
|
|
|
tempDir = TestUtils.createTempDirectory();
|
|
|
|
|
|
|
|
|
|
certFile = new File(tempDir, "cert.asc");
|
|
|
|
|
assertTrue(certFile.createNewFile());
|
|
|
|
|
try (FileOutputStream out = new FileOutputStream(certFile)) {
|
|
|
|
|
ByteArrayInputStream in = new ByteArrayInputStream(CERT.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
Streams.pipeAll(in, out);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@BeforeEach
|
|
|
|
|
public void saveSout() {
|
|
|
|
|
this.originalSout = System.out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@AfterEach
|
|
|
|
|
public void restoreSout() {
|
|
|
|
|
System.setOut(originalSout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static final String CLEAR_SIGNED_MESSAGE = "-----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 music’s 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-----";
|
|
|
|
|
|
|
|
|
|
private static final String CLEAR_SIGNED_SIGNATURE = "-----BEGIN PGP SIGNATURE-----\n" +
|
|
|
|
|
"\n" +
|
|
|
|
|
"iHUEARMKAB0WIQRPZlxNwsRmC8ZCXkFXNuaTGs83DAUCYJ/x5gAKCRBXNuaTGs83\n" +
|
|
|
|
|
"DFRwAP9/4wMvV3WcX59Clo7mkRce6iwW3VBdiN+yMu3tjmHB2wD/RfE28Q1v4+eo\n" +
|
|
|
|
|
"ySNgbyvqYYsNr0fnBwaG3aaj+u5ExiE=\n" +
|
|
|
|
|
"=Z2SO\n" +
|
|
|
|
|
"-----END PGP SIGNATURE-----";
|
|
|
|
|
|
|
|
|
|
private static final String CLEAR_SIGNED_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 music’s tongue\n" +
|
|
|
|
|
"Unfold the imagined happiness that both\n" +
|
|
|
|
|
"Receive in either by this dear encounter.";
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
public void detachInbandSignatureAndMessage() 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
|
2021-09-07 17:30:40 +02:00
|
|
|
|
File tempSigFile = new File(tempDir, "sig.out");
|
2021-09-07 16:44:16 +02:00
|
|
|
|
PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + tempSigFile.getAbsolutePath()});
|
|
|
|
|
|
|
|
|
|
// 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);
|
2021-09-07 17:30:40 +02:00
|
|
|
|
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);
|
2021-09-07 16:44:16 +02:00
|
|
|
|
} 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
|
|
|
|
|
@ExpectSystemExitWithStatus(SOPGPException.OutputExists.EXIT_CODE)
|
2021-09-07 17:30:40 +02:00
|
|
|
|
public void existingSignatureOutCausesException() throws IOException {
|
2021-09-07 16:44:16 +02:00
|
|
|
|
// 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
|
2021-09-07 17:30:40 +02:00
|
|
|
|
File existingSigFile = new File(tempDir, "sig.existing");
|
|
|
|
|
assertTrue(existingSigFile.createNewFile());
|
2021-09-07 16:44:16 +02:00
|
|
|
|
PGPainlessCLI.main(new String[] {"detach-inband-signature-and-message", "--signatures-out=" + existingSigFile.getAbsolutePath()});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|