From 8fc88b5bab84bebce993a86d7c132656f2943e8f Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 13 Jan 2023 18:50:19 +0100 Subject: [PATCH] Increase test coverage --- .../main/java/sop/external/ExternalSOP.java | 8 +- ...ternalDetachedSignVerifyRoundTripTest.java | 71 +++++++++++++++ .../ExternalEncryptDecryptRoundTripTest.java | 53 ++++++++++++ ...alInlineSignDetachVerifyRoundTripTest.java | 42 +++++++++ .../ExternalInlineSignVerifyTest.java | 86 +++++++++++++++++++ 5 files changed, 258 insertions(+), 2 deletions(-) diff --git a/external-sop/src/main/java/sop/external/ExternalSOP.java b/external-sop/src/main/java/sop/external/ExternalSOP.java index c3ecd00..555c856 100644 --- a/external-sop/src/main/java/sop/external/ExternalSOP.java +++ b/external-sop/src/main/java/sop/external/ExternalSOP.java @@ -302,8 +302,12 @@ public class ExternalSOP implements SOP { } standardIn.close(); - processOut.flush(); - processOut.close(); + try { + processOut.flush(); + processOut.close(); + } catch (IOException e) { + // ignore + } while ((r = processIn.read(buf)) > 0) { outputStream.write(buf, 0 , r); diff --git a/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java b/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java index efe4a68..3354389 100644 --- a/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java @@ -7,12 +7,17 @@ package sop.external; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIf; import sop.Verification; +import sop.enums.SignAs; +import sop.exception.SOPGPException; +import sop.util.UTCUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Date; import java.util.List; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static sop.external.JUtils.assertArrayStartsWith; @@ -41,8 +46,30 @@ public class ExternalDetachedSignVerifyRoundTripTest extends AbstractExternalSOP assertTrue(verificationList.get(0).toString().contains("EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E")); } + @Test + public void signVerifyTextModeWithAliceKey() throws IOException { + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + + byte[] signature = getSop().detachedSign() + .key(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .mode(SignAs.Text) + .data(message) + .toByteArrayAndResult() + .getBytes(); + + List verificationList = getSop().detachedVerify() + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .signatures(signature) + .data(message); + + assertFalse(verificationList.isEmpty()); + assertTrue(verificationList.get(0).toString().contains("EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E")); + } + @Test public void signVerifyWithFreshEncryptedKey() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // --with-key-password not supported + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); byte[] keyPassword = "sw0rdf1sh".getBytes(StandardCharsets.UTF_8); byte[] key = getSop().generateKey() @@ -95,4 +122,48 @@ public class ExternalDetachedSignVerifyRoundTripTest extends AbstractExternalSOP assertFalse(verificationList.isEmpty()); assertTrue(verificationList.get(0).toString().contains("D1A66E1A23B182C9980F788CFBFCC82A015E7330 D1A66E1A23B182C9980F788CFBFCC82A015E7330")); } + + @Test + public void verifyNotAfterThrowsNoSignature() { + ignoreIf("sqop", Is.leq, "0.27.2"); // returns 1 instead of 3 (NO_SIGNATURE) + + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] signature = ("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "iHUEABYKACcFAmPBjZUJEPIxVQxPR+OOFiEE64W7X6M6deFelE5j8jFVDE9H444A\n" + + "ADI/AQC6Bux6WpGYf7HO+QPV/D5iIrqZt9xPLgfUVoNJBmMZZwD+Ib+tn5pSyWUw\n" + + "0K1UgT5roym9Fln8U5W8R03TSbfNiwE=\n" + + "=bxPN\n" + + "-----END PGP SIGNATURE-----").getBytes(StandardCharsets.UTF_8); + Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T16:57:57Z"); + Date beforeSignature = new Date(signatureDate.getTime() - 1000); // 1 sec before sig + + assertThrows(SOPGPException.NoSignature.class, () -> getSop().detachedVerify() + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .notAfter(beforeSignature) + .signatures(signature) + .data(message)); + } + + @Test + public void verifyNotBeforeThrowsNoSignature() { + ignoreIf("sqop", Is.leq, "0.27.2"); // returns 1 instead of 3 (NO_SIGNATURE) + + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] signature = ("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "iHUEABYKACcFAmPBjZUJEPIxVQxPR+OOFiEE64W7X6M6deFelE5j8jFVDE9H444A\n" + + "ADI/AQC6Bux6WpGYf7HO+QPV/D5iIrqZt9xPLgfUVoNJBmMZZwD+Ib+tn5pSyWUw\n" + + "0K1UgT5roym9Fln8U5W8R03TSbfNiwE=\n" + + "=bxPN\n" + + "-----END PGP SIGNATURE-----").getBytes(StandardCharsets.UTF_8); + Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T16:57:57Z"); + Date afterSignature = new Date(signatureDate.getTime() + 1000); // 1 sec after sig + + assertThrows(SOPGPException.NoSignature.class, () -> getSop().detachedVerify() + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .notBefore(afterSignature) + .signatures(signature) + .data(message)); + } } diff --git a/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java b/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java index 2405e66..90f08ba 100644 --- a/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.condition.EnabledIf; import sop.ByteArrayAndResult; import sop.DecryptionResult; import sop.Verification; +import sop.enums.EncryptAs; import sop.exception.SOPGPException; import sop.util.UTCUtil; @@ -100,6 +101,30 @@ public class ExternalEncryptDecryptRoundTripTest extends AbstractExternalSOPTest assertArrayEquals(message, plaintext); } + @Test + public void encryptNoArmorThenArmorThenDecryptRoundTrip() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // Invalid data type + + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = getSop().encrypt() + .withCert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .noArmor() + .plaintext(message) + .getBytes(); + + byte[] armored = getSop().armor() + .data(ciphertext) + .getBytes(); + + ByteArrayAndResult bytesAndResult = getSop().decrypt() + .withKey(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .ciphertext(armored) + .toByteArrayAndResult(); + + byte[] plaintext = bytesAndResult.getBytes(); + assertArrayEquals(message, plaintext); + } + @Test public void encryptSignDecryptVerifyRoundTripAliceTest() throws IOException { byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); @@ -125,8 +150,36 @@ public class ExternalEncryptDecryptRoundTripTest extends AbstractExternalSOPTest assertTrue(verificationList.get(0).toString().contains("EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E")); } + @Test + public void encryptSignAsTextDecryptVerifyRoundTripAliceTest() throws IOException { + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = getSop().encrypt() + .withCert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .signWith(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .mode(EncryptAs.Text) + .plaintext(message) + .getBytes(); + + ByteArrayAndResult bytesAndResult = getSop().decrypt() + .withKey(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .verifyWithCert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .ciphertext(ciphertext) + .toByteArrayAndResult(); + + byte[] plaintext = bytesAndResult.getBytes(); + assertArrayEquals(message, plaintext); + + DecryptionResult result = bytesAndResult.getResult(); + assertNotNull(result.getSessionKey().get()); + List verificationList = result.getVerifications(); + assertEquals(1, verificationList.size()); + assertTrue(verificationList.get(0).toString().contains("EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E")); + } + @Test public void encryptSignDecryptVerifyRoundTripWithFreshEncryptedKeyTest() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); + byte[] keyPassword = "sw0rdf1sh".getBytes(StandardCharsets.UTF_8); byte[] key = getSop().generateKey() .withKeyPassword(keyPassword) diff --git a/external-sop/src/test/java/sop/external/ExternalInlineSignDetachVerifyRoundTripTest.java b/external-sop/src/test/java/sop/external/ExternalInlineSignDetachVerifyRoundTripTest.java index 6a47f46..f49601d 100644 --- a/external-sop/src/test/java/sop/external/ExternalInlineSignDetachVerifyRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/ExternalInlineSignDetachVerifyRoundTripTest.java @@ -16,12 +16,18 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static sop.external.JUtils.arrayStartsWith; +import static sop.external.JUtils.assertArrayStartsWith; @EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") public class ExternalInlineSignDetachVerifyRoundTripTest extends AbstractExternalSOPTest { + private static final byte[] BEGIN_PGP_SIGNATURE = "-----BEGIN PGP SIGNATURE-----\n".getBytes(StandardCharsets.UTF_8); + @Test public void inlineSignThenDetachThenDetachedVerifyTest() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); byte[] inlineSigned = getSop().inlineSign() @@ -46,4 +52,40 @@ public class ExternalInlineSignDetachVerifyRoundTripTest extends AbstractExterna assertFalse(verifications.isEmpty()); } + + @Test + public void inlineSignThenDetachNoArmorThenArmorThenDetachedVerifyTest() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + + byte[] inlineSigned = getSop().inlineSign() + .key(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .data(message) + .getBytes(); + + ByteArrayAndResult bytesAndResult = getSop().inlineDetach() + .noArmor() + .message(inlineSigned) + .toByteArrayAndResult(); + + byte[] plaintext = bytesAndResult.getBytes(); + assertArrayEquals(message, plaintext); + + byte[] signatures = bytesAndResult.getResult() + .getBytes(); + assertFalse(arrayStartsWith(signatures, BEGIN_PGP_SIGNATURE)); + + byte[] armored = getSop().armor() + .data(signatures) + .getBytes(); + assertArrayStartsWith(armored, BEGIN_PGP_SIGNATURE); + + List verifications = getSop().detachedVerify() + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .signatures(armored) + .data(plaintext); + + assertFalse(verifications.isEmpty()); + } } diff --git a/external-sop/src/test/java/sop/external/ExternalInlineSignVerifyTest.java b/external-sop/src/test/java/sop/external/ExternalInlineSignVerifyTest.java index 31687e9..d99270c 100644 --- a/external-sop/src/test/java/sop/external/ExternalInlineSignVerifyTest.java +++ b/external-sop/src/test/java/sop/external/ExternalInlineSignVerifyTest.java @@ -9,13 +9,17 @@ import org.junit.jupiter.api.condition.EnabledIf; import sop.ByteArrayAndResult; import sop.Verification; import sop.enums.InlineSignAs; +import sop.exception.SOPGPException; +import sop.util.UTCUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Date; import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; @EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") public class ExternalInlineSignVerifyTest extends AbstractExternalSOPTest { @@ -27,6 +31,8 @@ public class ExternalInlineSignVerifyTest extends AbstractExternalSOPTest { @Test public void inlineSignVerifyAlice() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); byte[] inlineSigned = getSop().inlineSign() @@ -47,6 +53,8 @@ public class ExternalInlineSignVerifyTest extends AbstractExternalSOPTest { @Test public void inlineSignVerifyAliceNoArmor() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); byte[] inlineSigned = getSop().inlineSign() @@ -68,6 +76,8 @@ public class ExternalInlineSignVerifyTest extends AbstractExternalSOPTest { @Test public void clearsignVerifyAlice() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); byte[] clearsigned = getSop().inlineSign() @@ -86,4 +96,80 @@ public class ExternalInlineSignVerifyTest extends AbstractExternalSOPTest { assertArrayEquals(message, bytesAndResult.getBytes()); assertFalse(bytesAndResult.getResult().isEmpty()); } + + @Test + public void assertNotBeforeThrowsNoSignature() { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + ignoreIf("sqop", Is.leq, "0.27.2"); // returns 1 instead of 3 (NO_SIGNATURE) + + byte[] message = ("-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "owGbwMvMwCX2yTCUx9/9cR/jaZEkBhDwSM3JyddRCM8vyklR5OooZWEQ42JQZ2VK\n" + + "PjjpPacATLmYIsvr1t3xi61KH8ZN8UuGCTMwpPcw/E9jS+vcvPu2gmp4jcRbcSNP\n" + + "FYmW8hmLJdUVrdt1V8w6GM/IMEvN0tP339sNGX4swq8T5p62q3jUfLjpstmcI6Ie\n" + + "sfcfswMA\n" + + "=RDAo\n" + + "-----END PGP MESSAGE-----").getBytes(StandardCharsets.UTF_8); + Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T17:20:47Z"); + Date afterSignature = new Date(signatureDate.getTime() + 1000); // 1 sec before sig + + assertThrows(SOPGPException.NoSignature.class, () -> getSop().inlineVerify() + .notBefore(afterSignature) + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .data(message) + .toByteArrayAndResult()); + } + + @Test + public void assertNotAfterThrowsNoSignature() { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + ignoreIf("sqop", Is.leq, "0.27.2"); // returns 1 instead of 3 (NO_SIGNATURE) + + byte[] message = ("-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "owGbwMvMwCX2yTCUx9/9cR/jaZEkBhDwSM3JyddRCM8vyklR5OooZWEQ42JQZ2VK\n" + + "PjjpPacATLmYIsvr1t3xi61KH8ZN8UuGCTMwpPcw/E9jS+vcvPu2gmp4jcRbcSNP\n" + + "FYmW8hmLJdUVrdt1V8w6GM/IMEvN0tP339sNGX4swq8T5p62q3jUfLjpstmcI6Ie\n" + + "sfcfswMA\n" + + "=RDAo\n" + + "-----END PGP MESSAGE-----").getBytes(StandardCharsets.UTF_8); + Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T17:20:47Z"); + Date beforeSignature = new Date(signatureDate.getTime() - 1000); // 1 sec before sig + + assertThrows(SOPGPException.NoSignature.class, () -> getSop().inlineVerify() + .notAfter(beforeSignature) + .cert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .data(message) + .toByteArrayAndResult()); + } + + @Test + public void signVerifyWithPasswordProtectedKey() throws IOException { + ignoreIf("sqop", Is.leq, "0.26.1"); // inline-sign not supported + + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] keyPassword = "sw0rdf1sh".getBytes(StandardCharsets.UTF_8); + byte[] key = getSop().generateKey() + .userId("Alice ") + .withKeyPassword(keyPassword) + .generate() + .getBytes(); + byte[] cert = getSop().extractCert() + .key(key) + .getBytes(); + + byte[] inlineSigned = getSop().inlineSign() + .withKeyPassword(keyPassword) + .key(key) + .mode(InlineSignAs.binary) + .data(message) + .getBytes(); + + assertFalse(getSop().inlineVerify() + .cert(cert) + .data(inlineSigned) + .toByteArrayAndResult() + .getResult() + .isEmpty()); + } }