From 620959abc65166b25183e2e5a5c3d4a3d3c9d3e4 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 4 Oct 2021 16:28:56 +0200 Subject: [PATCH] Some more pgpainless-sop tests --- .../java/org/pgpainless/sop/VersionImpl.java | 7 +- .../java/org/pgpainless/sop/SignTest.java | 164 ++++++++++++++++++ .../java/org/pgpainless/sop/VersionTest.java | 6 + .../src/main/java/sop/operation/Sign.java | 1 + 4 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java diff --git a/pgpainless-sop/src/main/java/org/pgpainless/sop/VersionImpl.java b/pgpainless-sop/src/main/java/org/pgpainless/sop/VersionImpl.java index adee014f..d12ee599 100644 --- a/pgpainless-sop/src/main/java/org/pgpainless/sop/VersionImpl.java +++ b/pgpainless-sop/src/main/java/org/pgpainless/sop/VersionImpl.java @@ -16,6 +16,7 @@ package org.pgpainless.sop; import java.io.IOException; +import java.io.InputStream; import java.util.Properties; import sop.operation.Version; @@ -32,7 +33,11 @@ public class VersionImpl implements Version { String version; try { Properties properties = new Properties(); - properties.load(getClass().getResourceAsStream("/version.properties")); + InputStream propertiesFileIn = getClass().getResourceAsStream("/version.properties"); + if (propertiesFileIn == null) { + throw new IOException("File version.properties not found."); + } + properties.load(propertiesFileIn); version = properties.getProperty("version"); } catch (IOException e) { version = "DEVELOPMENT"; diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java new file mode 100644 index 00000000..3c0ab9ac --- /dev/null +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/SignTest.java @@ -0,0 +1,164 @@ +/* + * 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.sop; + +import static org.junit.jupiter.api.Assertions.assertEquals; +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 java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.PGPSignature; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.SignatureType; +import org.pgpainless.signature.SignatureUtils; +import sop.SOP; +import sop.Verification; +import sop.enums.SignAs; +import sop.exception.SOPGPException; + +public class SignTest { + + private static SOP sop; + private static byte[] key; + private static byte[] cert; + private static byte[] data; + + @BeforeAll + public static void setup() throws IOException { + sop = new SOPImpl(); + key = sop.generateKey() + .userId("Alice") + .generate() + .getBytes(); + cert = sop.extractCert() + .key(new ByteArrayInputStream(key)) + .getBytes(); + data = "Hello, World\n".getBytes(StandardCharsets.UTF_8); + } + + @Test + public void signArmored() throws IOException { + byte[] signature = sop.sign() + .key(new ByteArrayInputStream(key)) + .data(new ByteArrayInputStream(data)) + .getBytes(); + + assertTrue(new String(signature).startsWith("-----BEGIN PGP SIGNATURE-----")); + + List verifications = sop.verify() + .cert(new ByteArrayInputStream(cert)) + .notAfter(new Date(new Date().getTime() + 10000)) + .notBefore(new Date(new Date().getTime() - 10000)) + .signatures(new ByteArrayInputStream(signature)) + .data(new ByteArrayInputStream(data)); + + assertEquals(1, verifications.size()); + } + + @Test + public void signUnarmored() throws IOException { + byte[] signature = sop.sign() + .key(new ByteArrayInputStream(key)) + .noArmor() + .data(new ByteArrayInputStream(data)) + .getBytes(); + + assertFalse(new String(signature).startsWith("-----BEGIN PGP SIGNATURE-----")); + + List verifications = sop.verify() + .cert(new ByteArrayInputStream(cert)) + .notAfter(new Date(new Date().getTime() + 10000)) + .notBefore(new Date(new Date().getTime() - 10000)) + .signatures(new ByteArrayInputStream(signature)) + .data(new ByteArrayInputStream(data)); + + assertEquals(1, verifications.size()); + } + + @Test + public void rejectSignatureAsTooOld() throws IOException { + byte[] signature = sop.sign() + .key(new ByteArrayInputStream(key)) + .data(new ByteArrayInputStream(data)) + .getBytes(); + + assertThrows(SOPGPException.NoSignature.class, () -> sop.verify() + .cert(new ByteArrayInputStream(cert)) + .notAfter(new Date(new Date().getTime() - 10000)) // Sig is older + .signatures(new ByteArrayInputStream(signature)) + .data(new ByteArrayInputStream(data))); + } + + @Test + public void rejectSignatureAsTooYoung() throws IOException { + byte[] signature = sop.sign() + .key(new ByteArrayInputStream(key)) + .data(new ByteArrayInputStream(data)) + .getBytes(); + + assertThrows(SOPGPException.NoSignature.class, () -> sop.verify() + .cert(new ByteArrayInputStream(cert)) + .notBefore(new Date(new Date().getTime() + 10000)) // Sig is younger + .signatures(new ByteArrayInputStream(signature)) + .data(new ByteArrayInputStream(data))); + } + + @Test + public void mode() throws IOException, PGPException { + byte[] signature = sop.sign() + .mode(SignAs.Text) + .key(new ByteArrayInputStream(key)) + .data(new ByteArrayInputStream(data)) + .getBytes(); + + PGPSignature sig = SignatureUtils.readSignatures(new ByteArrayInputStream(signature)).get(0); + assertEquals(SignatureType.CANONICAL_TEXT_DOCUMENT.getCode(), sig.getSignatureType()); + } + + @Test + public void rejectKeyRingCollection() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { + PGPSecretKeyRing key1 = PGPainless.generateKeyRing().modernKeyRing("Alice", null); + PGPSecretKeyRing key2 = PGPainless.generateKeyRing().modernKeyRing("Bob", null); + PGPSecretKeyRingCollection collection = new PGPSecretKeyRingCollection(Arrays.asList(key1, key2)); + byte[] keys = collection.getEncoded(); + + assertThrows(SOPGPException.BadData.class, () -> sop.sign().key(new ByteArrayInputStream(keys))); + } + + @Test + public void rejectEncryptedKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { + PGPSecretKeyRing key = PGPainless.generateKeyRing() + .modernKeyRing("Alice", "passphrase"); + byte[] bytes = key.getEncoded(); + + assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.sign().key(new ByteArrayInputStream(bytes))); + } + +} diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/VersionTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/VersionTest.java index 02a38217..222fb52e 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/VersionTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/VersionTest.java @@ -16,11 +16,17 @@ package org.pgpainless.sop; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import org.junit.jupiter.api.Test; public class VersionTest { + @Test + public void testGetVersion() { + assertNotNull(new SOPImpl().version().getVersion()); + } + @Test public void assertNameEqualsPGPainless() { assertEquals("PGPainless-SOP", new SOPImpl().version().getName()); diff --git a/sop-java/src/main/java/sop/operation/Sign.java b/sop-java/src/main/java/sop/operation/Sign.java index 1a3f7418..53ba5936 100644 --- a/sop-java/src/main/java/sop/operation/Sign.java +++ b/sop-java/src/main/java/sop/operation/Sign.java @@ -33,6 +33,7 @@ public interface Sign { /** * Sets the signature mode. + * Note: This method has to be called before {@link #key(InputStream)} is called. * * @param mode signature mode * @return builder instance