diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java index 7fbac8f..501d6ca 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/PGPCertDCli.java @@ -40,7 +40,7 @@ public class PGPCertDCli { scope = CommandLine.ScopeType.INHERIT) File baseDirectory; - static PGPainlessCertD certificateDirectory; + private static PGPainlessCertD certificateDirectory; private int executionStrategy(CommandLine.ParseResult parseResult) { try { @@ -52,10 +52,6 @@ public class PGPCertDCli { } private void initStore() throws NotAStoreException, SQLException { - if (certificateDirectory != null) { - return; - } - if (baseDirectory == null) { baseDirectory = BaseDirectoryProvider.getDefaultBaseDir(); } diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java index 3dfcfb4..d7d29fb 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java @@ -32,7 +32,7 @@ public class Import implements Runnable { for (PGPPublicKeyRing cert : certificates) { ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); Certificate certificate = PGPCertDCli.getCertificateDirectory() - .insert(certIn, MergeCallbacks.mergeWithExisting()); + .insert(certIn, MergeCallbacks.mergeCertificates()); } } catch (IOException e) { LOGGER.error("IO-Error.", e); diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java index 25987d0..c88ead0 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java @@ -24,7 +24,7 @@ public class Insert implements Runnable { public void run() { try { Certificate certificate = PGPCertDCli.getCertificateDirectory() - .insert(System.in, MergeCallbacks.mergeWithExisting()); + .insert(System.in, MergeCallbacks.mergeCertificates()); } catch (IOException e) { LOGGER.error("IO-Error.", e); System.exit(-1); diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java index 2cdc5c4..0178e0a 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java @@ -61,7 +61,7 @@ public class Setup implements Runnable { try { InputStream inputStream = new ByteArrayInputStream(trustRoot.getEncoded()); - PGPCertDCli.getCertificateDirectory().insertTrustRoot(inputStream, MergeCallbacks.overrideExisting()); + PGPCertDCli.getCertificateDirectory().insertTrustRoot(inputStream, MergeCallbacks.overrideKey()); } catch (BadDataException e) { throw new RuntimeException(e); diff --git a/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/InstantiateCLI.java b/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/InstantiateCLI.java deleted file mode 100644 index 6a20ff6..0000000 --- a/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/InstantiateCLI.java +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package pgp.cert_d.cli; - -import org.pgpainless.certificate_store.PGPainlessCertD; - -public class InstantiateCLI { - - public static void resetStore() { - PGPCertDCli.certificateDirectory = null; - } - - public static void setInMemoryStore() { - PGPCertDCli.certificateDirectory = PGPainlessCertD.inMemory(); - } -} diff --git a/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/commands/SetupTest.java b/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/commands/SetupTest.java deleted file mode 100644 index b4664c0..0000000 --- a/pgpainless-cert-d-cli/src/test/java/pgp/cert_d/cli/commands/SetupTest.java +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package pgp.cert_d.cli.commands; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.pgpainless.PGPainless; -import org.pgpainless.certificate_store.PGPainlessCertD; -import org.pgpainless.key.OpenPgpFingerprint; -import org.pgpainless.key.info.KeyInfo; -import org.pgpainless.key.protection.UnlockSecretKey; -import org.pgpainless.util.Passphrase; -import pgp.cert_d.cli.InstantiateCLI; -import pgp.cert_d.cli.PGPCertDCli; -import pgp.certificate_store.certificate.Key; -import pgp.certificate_store.certificate.KeyMaterial; -import pgp.certificate_store.exception.BadDataException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class SetupTest { - - private PGPainlessCertD store; - - @BeforeEach - public void setup() { - InstantiateCLI.setInMemoryStore(); - store = PGPCertDCli.getCertificateDirectory(); - } - - @AfterEach - public void teardown() { - InstantiateCLI.resetStore(); - store = null; - } - - @Test - public void testSetupGeneratesTrustRoot() - throws BadDataException, IOException { - assertNull(store.getTrustRoot()); - - PGPCertDCli.main(new String[] {"setup"}); - KeyMaterial trustRoot = store.getTrustRoot(); - assertNotNull(trustRoot); - assertTrue(trustRoot instanceof Key); - - // Check that key has no password - PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(trustRoot.getInputStream()); - assertTrue(KeyInfo.isDecrypted(secretKeys.getSecretKey())); - } - - @Test - public void testSetupWithPassword() - throws BadDataException, IOException, PGPException { - assertNull(store.getTrustRoot()); - - PGPCertDCli.main(new String[] {"setup", "--with-password", "sw0rdf1sh"}); - KeyMaterial trustRoot = store.getTrustRoot(); - assertNotNull(trustRoot); - assertTrue(trustRoot instanceof Key); - - // Check that key is encrypted - PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(trustRoot.getInputStream()); - assertTrue(KeyInfo.isEncrypted(secretKeys.getSecretKey())); - // Check that password matches - assertNotNull(UnlockSecretKey.unlockSecretKey( - secretKeys.getSecretKey(), Passphrase.fromPassword("sw0rdf1sh"))); - } - - @Test - public void testSetupImportFromStdin() - throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, - BadDataException, IOException { - assertNull(store.getTrustRoot()); - - PGPSecretKeyRing trustRoot = PGPainless.generateKeyRing() - .modernKeyRing("trust-root"); - OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(trustRoot); - String armored = PGPainless.asciiArmor(trustRoot); - ByteArrayInputStream trustRootIn = new ByteArrayInputStream( - armored.getBytes(Charset.forName("UTF8"))); - - InputStream originalStdin = System.in; - System.setIn(trustRootIn); - PGPCertDCli.main(new String[] {"setup", "--import-from-stdin"}); - System.setIn(originalStdin); - - KeyMaterial importedTrustRoot = store.getTrustRoot(); - assertEquals(fingerprint.toString().toLowerCase(), importedTrustRoot.getFingerprint()); - } - - @Test - public void testSetupOverridesExistingTrustRoot() - throws BadDataException, IOException { - assertNull(store.getTrustRoot()); - - PGPCertDCli.main(new String[] {"setup"}); - KeyMaterial trustRoot = store.getTrustRoot(); - assertNotNull(trustRoot); - String fingerprint = trustRoot.getFingerprint(); - - // Override trust-root by calling setup again - PGPCertDCli.main(new String[] {"setup"}); - trustRoot = store.getTrustRoot(); - assertNotNull(trustRoot); - - assertNotEquals(fingerprint, trustRoot.getFingerprint()); - } -} diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyMaterialReader.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyMaterialReader.java index 112bf18..409a9fe 100644 --- a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyMaterialReader.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyMaterialReader.java @@ -19,17 +19,7 @@ public class KeyMaterialReader implements KeyMaterialReaderBackend { @Override public KeyMaterial read(InputStream data, Long tag) throws IOException, BadDataException { - PGPKeyRing keyMaterial; - try { - keyMaterial = PGPainless.readKeyRing().keyRing(data); - } catch (IOException e) { - if (e.getMessage().contains("unknown object in stream") || - e.getMessage().contains("unexpected end of file in armored stream.")) { - throw new BadDataException(); - } else { - throw e; - } - } + PGPKeyRing keyMaterial = PGPainless.readKeyRing().keyRing(data); if (keyMaterial instanceof PGPSecretKeyRing) { return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) keyMaterial, tag); } else if (keyMaterial instanceof PGPPublicKeyRing) { diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java index cbd3a44..6e84f26 100644 --- a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java @@ -16,6 +16,7 @@ import pgp.certificate_store.certificate.KeyMaterialMerger; import pgp.certificate_store.exception.BadDataException; import java.io.IOException; +import java.util.Arrays; import java.util.Iterator; public class MergeCallbacks { @@ -26,13 +27,11 @@ public class MergeCallbacks { * * @return merging callback */ - public static KeyMaterialMerger mergeWithExisting() { + public static KeyMaterialMerger mergeCertificates() { return new KeyMaterialMerger() { @Override - public KeyMaterial merge(KeyMaterial data, KeyMaterial existing) - throws IOException { - // Simple cases: one is null -> return other + public KeyMaterial merge(KeyMaterial data, KeyMaterial existing) throws IOException { if (data == null) { return existing; } @@ -47,66 +46,51 @@ public class MergeCallbacks { PGPKeyRing mergedKeyRing; if (existingKeyRing instanceof PGPPublicKeyRing) { - mergedKeyRing = mergeWithCert((PGPPublicKeyRing) existingKeyRing, updatedKeyRing); + PGPPublicKeyRing existingCert = (PGPPublicKeyRing) existingKeyRing; + if (updatedKeyRing instanceof PGPPublicKeyRing) { + mergedKeyRing = PGPPublicKeyRing.join(existingCert, (PGPPublicKeyRing) updatedKeyRing); + } else if (updatedKeyRing instanceof PGPSecretKeyRing) { + PGPPublicKeyRing updatedPublicKeys = PGPainless.extractCertificate((PGPSecretKeyRing) updatedKeyRing); + PGPPublicKeyRing mergedPublicKeys = PGPPublicKeyRing.join(existingCert, updatedPublicKeys); + updatedKeyRing = PGPSecretKeyRing.replacePublicKeys((PGPSecretKeyRing) updatedKeyRing, mergedPublicKeys); + mergedKeyRing = updatedKeyRing; + } else { + throw new IOException(new BadDataException()); + } } else if (existingKeyRing instanceof PGPSecretKeyRing) { - mergedKeyRing = mergeWithKey(existingKeyRing, updatedKeyRing); + PGPSecretKeyRing existingKey = (PGPSecretKeyRing) existingKeyRing; + PGPPublicKeyRing existingCert = PGPainless.extractCertificate(existingKey); + if (updatedKeyRing instanceof PGPPublicKeyRing) { + PGPPublicKeyRing updatedCert = (PGPPublicKeyRing) updatedKeyRing; + PGPPublicKeyRing mergedCert = PGPPublicKeyRing.join(existingCert, updatedCert); + mergedKeyRing = PGPSecretKeyRing.replacePublicKeys(existingKey, mergedCert); + } else if (updatedKeyRing instanceof PGPSecretKeyRing) { + PGPSecretKeyRing updatedKey = (PGPSecretKeyRing) updatedKeyRing; + if (!Arrays.equals(existingKey.getEncoded(), updatedKey.getEncoded())) { + // Merging secret keys is not supported. + return existing; + } + mergedKeyRing = existingKeyRing; + } else { + throw new IOException(new BadDataException()); + } } else { throw new IOException(new BadDataException()); } printOutDifferences(existingKeyRing, mergedKeyRing); - return toKeyMaterial(mergedKeyRing); + if (mergedKeyRing instanceof PGPPublicKeyRing) { + return CertificateFactory.certificateFromPublicKeyRing((PGPPublicKeyRing) mergedKeyRing, null); + } else { + return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) mergedKeyRing, null); + } } catch (PGPException e) { throw new RuntimeException(e); } } - private PGPKeyRing mergeWithCert(PGPPublicKeyRing existingKeyRing, PGPKeyRing updatedKeyRing) - throws PGPException, IOException { - PGPKeyRing mergedKeyRing; - PGPPublicKeyRing existingCert = existingKeyRing; - if (updatedKeyRing instanceof PGPPublicKeyRing) { - mergedKeyRing = PGPPublicKeyRing.join(existingCert, (PGPPublicKeyRing) updatedKeyRing); - } else if (updatedKeyRing instanceof PGPSecretKeyRing) { - PGPPublicKeyRing updatedPublicKeys = PGPainless.extractCertificate((PGPSecretKeyRing) updatedKeyRing); - PGPPublicKeyRing mergedPublicKeys = PGPPublicKeyRing.join(existingCert, updatedPublicKeys); - updatedKeyRing = PGPSecretKeyRing.replacePublicKeys((PGPSecretKeyRing) updatedKeyRing, mergedPublicKeys); - mergedKeyRing = updatedKeyRing; - } else { - throw new IOException(new BadDataException()); - } - return mergedKeyRing; - } - - private PGPKeyRing mergeWithKey(PGPKeyRing existingKeyRing, PGPKeyRing updatedKeyRing) - throws PGPException, IOException { - PGPKeyRing mergedKeyRing; - PGPSecretKeyRing existingKey = (PGPSecretKeyRing) existingKeyRing; - PGPPublicKeyRing existingCert = PGPainless.extractCertificate(existingKey); - if (updatedKeyRing instanceof PGPPublicKeyRing) { - PGPPublicKeyRing updatedCert = (PGPPublicKeyRing) updatedKeyRing; - PGPPublicKeyRing mergedCert = PGPPublicKeyRing.join(existingCert, updatedCert); - mergedKeyRing = PGPSecretKeyRing.replacePublicKeys(existingKey, mergedCert); - } else if (updatedKeyRing instanceof PGPSecretKeyRing) { - // Merging keys is not supported - mergedKeyRing = existingKeyRing; - } else { - throw new IOException(new BadDataException()); - } - return mergedKeyRing; - } - - private KeyMaterial toKeyMaterial(PGPKeyRing mergedKeyRing) - throws IOException { - if (mergedKeyRing instanceof PGPPublicKeyRing) { - return CertificateFactory.certificateFromPublicKeyRing((PGPPublicKeyRing) mergedKeyRing, null); - } else { - return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) mergedKeyRing, null); - } - } - private void printOutDifferences(PGPKeyRing existingCert, PGPKeyRing mergedCert) { int numSigsBefore = countSigs(existingCert); int numSigsAfter = countSigs(mergedCert); @@ -161,7 +145,23 @@ public class MergeCallbacks { }; } - public static KeyMaterialMerger overrideExisting() { + /** + * Return an implementation of {@link KeyMaterialMerger} that ignores the existing certificate and instead + * returns the first instance. + * + * @return overriding callback + */ + public static KeyMaterialMerger overrideCertificate() { + // noinspection Convert2Lambda + return new KeyMaterialMerger() { + @Override + public KeyMaterial merge(KeyMaterial data, KeyMaterial existing) { + return data; + } + }; + } + + public static KeyMaterialMerger overrideKey() { // noinspection Convert2Lambda return new KeyMaterialMerger() { @Override diff --git a/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/KeyMaterialReaderTest.java b/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/KeyMaterialReaderTest.java deleted file mode 100644 index 327abdc..0000000 --- a/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/KeyMaterialReaderTest.java +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.certificate_store; - -import org.junit.jupiter.api.Test; -import pgp.certificate_store.certificate.Certificate; -import pgp.certificate_store.certificate.Key; -import pgp.certificate_store.certificate.KeyMaterial; -import pgp.certificate_store.exception.BadDataException; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.Charset; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class KeyMaterialReaderTest { - - private static final String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "Comment: B21A ABBF 15DF 0FDA 3742 4DE9 AD00 8384 AD0A 064C\n" + - "Comment: Volodymyr Zelenskyy \n" + - "\n" + - "xVgEYwdKchYJKwYBBAHaRw8BAQdARSvx9BDpV0AoNYTmN/wrZXQAB7VzOV0rKEQc\n" + - "OkhbP5wAAP0QE5FCIOvzea7wu3Yw3LDMmOOgMaWXngYp0948VPP2+xM7wsARBB8W\n" + - "CgCDBYJjB0pyBYkFn6YAAwsJBwkQrQCDhK0KBkxHFAAAAAAAHgAgc2FsdEBub3Rh\n" + - "dGlvbnMuc2VxdW9pYS1wZ3Aub3JnpqJFBi2xLa0V4D9k4rlmibhIsMRlcvK/MK83\n" + - "Hjfh2CIDFQoIApsBAh4BFiEEshqrvxXfD9o3Qk3prQCDhK0KBkwAAIwNAP41uywA\n" + - "z+qaRhWoj0stYmmefok4WHXk34jfameTopO1LAEA6L6/crPYzIcAZraaz0s5AM/2\n" + - "OvJZR8LaBSj92uBDbAzNJlZvbG9keW15ciBaZWxlbnNreXkgPHplbGVuc2t5eUBn\n" + - "b3YudWE+wsAUBBMWCgCGBYJjB0pyBYkFn6YAAwsJBwkQrQCDhK0KBkxHFAAAAAAA\n" + - "HgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnuD/qrSefYHLBUQ70qQhb\n" + - "cClzXkMQCoGO4S3WJzib/IADFQoIApkBApsBAh4BFiEEshqrvxXfD9o3Qk3prQCD\n" + - "hK0KBkwAAL8DAP42+z1sDJlv64PW4iq2ODYcdY1NSptjzfiQ2hyodNBFpgD+Mkiv\n" + - "9e2bFvlRj2Q5Brypy3ZwKvGtikUe3s+NlKMPlgTHWARjB0pyFgkrBgEEAdpHDwEB\n" + - "B0BNjMb280vf8zNJ/YAtcc6nLe8uCSTtxKKHF0Go9kU+VgABAKTAn5oiixsRxfEb\n" + - "k1I6WQbIGk/XNPZ241k65WRdg1qODvXCwMUEGBYKATcFgmMHSnIFiQWfpgAJEK0A\n" + - "g4StCgZMRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ9el\n" + - "oLUj9wUjbwI91PYFiLbcIMYw+G2w85rw5nLaXzHEApsCvqAEGRYKAG8FgmMHSnIJ\n" + - "EDWWq2wLl0UaRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + - "Z622EwAZW4CP32L2ysCphw7DasyPOdBpDsiMv2LB7dz8FiEEZQkoZquL7+v7NBoA\n" + - "NZarbAuXRRoAAOu3AP0X6dEVabI84d7t4AwRpmEiShSum9CJiODSs580lzkjlAD/\n" + - "QOGSIE5iO155kPudwi8ubif+v4tXe4Ro++tIP85bTQ8WIQSyGqu/Fd8P2jdCTemt\n" + - "AIOErQoGTAAAScwBAJ2A8vuK0wEMQHhVJR1lcjUaUm7EoBVuplF85dFipXjuAP40\n" + - "bwvHajjg8wFLo8pwAATBd2gnNYXXDK7J2WwiZPAKAcddBGMHSnISCisGAQQBl1UB\n" + - "BQEBB0DG0ue4giLkEecm/qz1wPQQBIl5v18/9M0SrMUk/M16agMBCAcAAP9Z4R+9\n" + - "tmG3aUKOB9nwN1t4N1GnbYCmaZzTn3uJXLetYBFTwsAGBBgWCgB4BYJjB0pyBYkF\n" + - "n6YACRCtAIOErQoGTEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBn\n" + - "cC5vcmfZNJZA/uU2jCW1zQzCT9oK5hj0sL2taNvDFlLtkMCNqwKbDBYhBLIaq78V\n" + - "3w/aN0JN6a0Ag4StCgZMAAAlKwD/eUEbC8MoIitKulDZawtlC0rSITXtQJqUkGNc\n" + - "ujTPgIAA/1p/Y3sHn4nhmYcVX902BRXBp8YMD/cHQWZkWPhvM9YF\n" + - "=3nhb\n" + - "-----END PGP PRIVATE KEY BLOCK-----\n"; - - private static final String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "Comment: B21A ABBF 15DF 0FDA 3742 4DE9 AD00 8384 AD0A 064C\n" + - "Comment: Volodymyr Zelenskyy \n" + - "\n" + - "xjMEYwdKchYJKwYBBAHaRw8BAQdARSvx9BDpV0AoNYTmN/wrZXQAB7VzOV0rKEQc\n" + - "OkhbP5zCwBEEHxYKAIMFgmMHSnIFiQWfpgADCwkHCRCtAIOErQoGTEcUAAAAAAAe\n" + - "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmemokUGLbEtrRXgP2TiuWaJ\n" + - "uEiwxGVy8r8wrzceN+HYIgMVCggCmwECHgEWIQSyGqu/Fd8P2jdCTemtAIOErQoG\n" + - "TAAAjA0A/jW7LADP6ppGFaiPSy1iaZ5+iThYdeTfiN9qZ5Oik7UsAQDovr9ys9jM\n" + - "hwBmtprPSzkAz/Y68llHwtoFKP3a4ENsDM0mVm9sb2R5bXlyIFplbGVuc2t5eSA8\n" + - "emVsZW5za3l5QGdvdi51YT7CwBQEExYKAIYFgmMHSnIFiQWfpgADCwkHCRCtAIOE\n" + - "rQoGTEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcme4P+qt\n" + - "J59gcsFRDvSpCFtwKXNeQxAKgY7hLdYnOJv8gAMVCggCmQECmwECHgEWIQSyGqu/\n" + - "Fd8P2jdCTemtAIOErQoGTAAAvwMA/jb7PWwMmW/rg9biKrY4Nhx1jU1Km2PN+JDa\n" + - "HKh00EWmAP4ySK/17ZsW+VGPZDkGvKnLdnAq8a2KRR7ez42Uow+WBM4zBGMHSnIW\n" + - "CSsGAQQB2kcPAQEHQE2MxvbzS9/zM0n9gC1xzqct7y4JJO3EoocXQaj2RT5WwsDF\n" + - "BBgWCgE3BYJjB0pyBYkFn6YACRCtAIOErQoGTEcUAAAAAAAeACBzYWx0QG5vdGF0\n" + - "aW9ucy5zZXF1b2lhLXBncC5vcmfXpaC1I/cFI28CPdT2BYi23CDGMPhtsPOa8OZy\n" + - "2l8xxAKbAr6gBBkWCgBvBYJjB0pyCRA1lqtsC5dFGkcUAAAAAAAeACBzYWx0QG5v\n" + - "dGF0aW9ucy5zZXF1b2lhLXBncC5vcmetthMAGVuAj99i9srAqYcOw2rMjznQaQ7I\n" + - "jL9iwe3c/BYhBGUJKGari+/r+zQaADWWq2wLl0UaAADrtwD9F+nRFWmyPOHe7eAM\n" + - "EaZhIkoUrpvQiYjg0rOfNJc5I5QA/0DhkiBOYjteeZD7ncIvLm4n/r+LV3uEaPvr\n" + - "SD/OW00PFiEEshqrvxXfD9o3Qk3prQCDhK0KBkwAAEnMAQCdgPL7itMBDEB4VSUd\n" + - "ZXI1GlJuxKAVbqZRfOXRYqV47gD+NG8Lx2o44PMBS6PKcAAEwXdoJzWF1wyuydls\n" + - "ImTwCgHOOARjB0pyEgorBgEEAZdVAQUBAQdAxtLnuIIi5BHnJv6s9cD0EASJeb9f\n" + - "P/TNEqzFJPzNemoDAQgHwsAGBBgWCgB4BYJjB0pyBYkFn6YACRCtAIOErQoGTEcU\n" + - "AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfZNJZA/uU2jCW1\n" + - "zQzCT9oK5hj0sL2taNvDFlLtkMCNqwKbDBYhBLIaq78V3w/aN0JN6a0Ag4StCgZM\n" + - "AAAlKwD/eUEbC8MoIitKulDZawtlC0rSITXtQJqUkGNcujTPgIAA/1p/Y3sHn4nh\n" + - "mYcVX902BRXBp8YMD/cHQWZkWPhvM9YF\n" + - "=o64m\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - - private final KeyMaterialReader reader = new KeyMaterialReader(); - private final Charset UTF8 = Charset.forName("UTF8"); - - @Test - public void readBadDataTest() { - assertThrows(BadDataException.class, () -> reader.read( - new ByteArrayInputStream(CERT.substring(0, CERT.length() - 100).getBytes(UTF8)), null)); - } - - @Test - public void readIncompleteDataTest() { - assertThrows(BadDataException.class, () -> reader.read( - new ByteArrayInputStream("ThisIsNotOpenPGPDataAtAllLol".getBytes(UTF8)), null)); - } - - @Test - public void readKeyTest() throws BadDataException, IOException { - KeyMaterial keyMaterial = reader.read(new ByteArrayInputStream(KEY.getBytes(UTF8)), 12L); - assertNotNull(keyMaterial); - assertTrue(keyMaterial instanceof Key); - Key key = (Key) keyMaterial; - assertEquals("b21aabbf15df0fda37424de9ad008384ad0a064c", key.getFingerprint()); - assertEquals(12L, key.getTag()); - Certificate certificate = key.getCertificate(); - assertEquals(key.getFingerprint(), certificate.getFingerprint()); - assertEquals(key.getTag(), certificate.getTag()); - assertEquals(key.getSubkeyIds(), certificate.getSubkeyIds()); - } - - @Test - public void readCertTest() throws BadDataException, IOException { - KeyMaterial keyMaterial = reader.read(new ByteArrayInputStream(CERT.getBytes(UTF8)), null); - assertNotNull(keyMaterial); - assertTrue(keyMaterial instanceof Certificate); - Certificate certificate = (Certificate) keyMaterial; - assertEquals("b21aabbf15df0fda37424de9ad008384ad0a064c", certificate.getFingerprint()); - assertNull(certificate.getTag()); - assertSame(certificate, certificate.asCertificate()); - } -} diff --git a/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/MergeCallbacksTest.java b/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/MergeCallbacksTest.java deleted file mode 100644 index 6101154..0000000 --- a/pgpainless-cert-d/src/test/java/org/pgpainless/certificate_store/MergeCallbacksTest.java +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.certificate_store; - -import org.bouncycastle.util.io.Streams; -import org.junit.jupiter.api.Test; -import pgp.certificate_store.certificate.KeyMaterial; -import pgp.certificate_store.certificate.KeyMaterialMerger; -import pgp.certificate_store.exception.BadDataException; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertSame; - -public class MergeCallbacksTest { - - private static final String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "Version: PGPainless\n" + - "Comment: 8E0F C503 D081 002A 2BC8 60A1 1CFC 3439 106D 1DD1\n" + - "Comment: Marge Simpson \n" + - "\n" + - "lFgEYwdeTxYJKwYBBAHaRw8BAQdA/culAZNfjpo8NyfJv9ggwUJBY/9Ps27wRzj1\n" + - "3i5Y/akAAQCel3XRH2ERU2+6C4kJEb3YXNtbH3CHJhkP+co3JQBJygz0tCBNYXJn\n" + - "ZSBTaW1wc29uIDxtYXJnZUBzaW1wc29uLnR2PoiPBBMWCgBBBQJjB15QCRAc/DQ5\n" + - "EG0d0RYhBI4PxQPQgQAqK8hgoRz8NDkQbR3RAp4BApsBBRYCAwEABAsJCAcFFQoJ\n" + - "CAsCmQEAAC34AP9jqFThNA0FeNxEEh+BKA/diGkxsAZaI0HscLeuoECOoAD9FjcO\n" + - "1TtI0UjF1wvRAGuoL6PrgNQ/kAE++zyzaXlbDAKcXQRjB15QEgorBgEEAZdVAQUB\n" + - "AQdAHQPnqtZwENOdLiD19wgjUpo/U0pJ4s/HCjgUQrFro38DAQgHAAD/VrXgi8fE\n" + - "UUAVLn+C3GXCJV0CBnCvLvMn6QwDUIbi1sgQF4h1BBgWCgAdBQJjB15QAp4BApsM\n" + - "BRYCAwEABAsJCAcFFQoJCAsACgkQHPw0ORBtHdGDdgD8DS1IyA0j4mnKPw93BLLn\n" + - "Wkt6Tc8tEc1Yy3fddhaGXXMBAIMu6ww43TM2EdQM/2orh8MhDZaBdDnD4egQ1ES4\n" + - "zxYJnFgEYwdeUBYJKwYBBAHaRw8BAQdAw/Pfecs1QEMAuTY8wGqEgpigYFx6GLHS\n" + - "qpgJkVds4hsAAP9JZ3XgkUguI4tUO9CyGCwxfBoUv1+F+XlYoxlyZV0M2A4qiNUE\n" + - "GBYKAH0FAmMHXlACngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjB15Q\n" + - "AAoJEO8Ou9qRn4/Lk4ABAOTUMLOTPL9svmyoHmeVKYh4pL92/+zrsNL2Kh8BX7/F\n" + - "APsE3/N3J5MB2ZEyzNSU84STG3Aqa+2I2u4w58CeL8eRCAAKCRAc/DQ5EG0d0QBm\n" + - "AQDvHR1I/B4VBqMu44wcw1czqqFojv1KQMETnLCfU5Q4cwD+Mt6mNoXADACcnw2P\n" + - "3u5u3NoFQ0v2vFSaCoBxVzUQrgo=\n" + - "=OKv0\n" + - "-----END PGP PRIVATE KEY BLOCK-----"; - private static final String KEY_WITH_SIG = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "Version: PGPainless\n" + - "Comment: 8E0F C503 D081 002A 2BC8 60A1 1CFC 3439 106D 1DD1\n" + - "Comment: Marge Simpson \n" + - "\n" + - "lFgEYwdeTxYJKwYBBAHaRw8BAQdA/culAZNfjpo8NyfJv9ggwUJBY/9Ps27wRzj1\n" + - "3i5Y/akAAQCel3XRH2ERU2+6C4kJEb3YXNtbH3CHJhkP+co3JQBJygz0iHUEHxYK\n" + - "ACcFAmMHXlAJEBz8NDkQbR3RFiEEjg/FA9CBACoryGChHPw0ORBtHdEAAEI4AP4w\n" + - "H667enh2czzfH8n4NeluivHQIavx6THn40MELAiBQQD/T3IdrTn0YDVmfdAGmCPL\n" + - "lNjOxPDus5SESpLuS6A7IAi0IE1hcmdlIFNpbXBzb24gPG1hcmdlQHNpbXBzb24u\n" + - "dHY+iI8EExYKAEEFAmMHXlAJEBz8NDkQbR3RFiEEjg/FA9CBACoryGChHPw0ORBt\n" + - "HdECngECmwEFFgIDAQAECwkIBwUVCgkICwKZAQAALfgA/2OoVOE0DQV43EQSH4Eo\n" + - "D92IaTGwBlojQexwt66gQI6gAP0WNw7VO0jRSMXXC9EAa6gvo+uA1D+QAT77PLNp\n" + - "eVsMApxdBGMHXlASCisGAQQBl1UBBQEBB0AdA+eq1nAQ050uIPX3CCNSmj9TSkni\n" + - "z8cKOBRCsWujfwMBCAcAAP9WteCLx8RRQBUuf4LcZcIlXQIGcK8u8yfpDANQhuLW\n" + - "yBAXiHUEGBYKAB0FAmMHXlACngECmwwFFgIDAQAECwkIBwUVCgkICwAKCRAc/DQ5\n" + - "EG0d0YN2APwNLUjIDSPiaco/D3cEsudaS3pNzy0RzVjLd912FoZdcwEAgy7rDDjd\n" + - "MzYR1Az/aiuHwyENloF0OcPh6BDURLjPFgmcWARjB15QFgkrBgEEAdpHDwEBB0DD\n" + - "8995yzVAQwC5NjzAaoSCmKBgXHoYsdKqmAmRV2ziGwAA/0lndeCRSC4ji1Q70LIY\n" + - "LDF8GhS/X4X5eVijGXJlXQzYDiqI1QQYFgoAfQUCYwdeUAKeAQKbAgUWAgMBAAQL\n" + - "CQgHBRUKCQgLXyAEGRYKAAYFAmMHXlAACgkQ7w672pGfj8uTgAEA5NQws5M8v2y+\n" + - "bKgeZ5UpiHikv3b/7Ouw0vYqHwFfv8UA+wTf83cnkwHZkTLM1JTzhJMbcCpr7Yja\n" + - "7jDnwJ4vx5EIAAoJEBz8NDkQbR3RAGYBAO8dHUj8HhUGoy7jjBzDVzOqoWiO/UpA\n" + - "wROcsJ9TlDhzAP4y3qY2hcAMAJyfDY/e7m7c2gVDS/a8VJoKgHFXNRCuCg==\n" + - "=WrKH\n" + - "-----END PGP PRIVATE KEY BLOCK-----"; - private static final String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "Version: PGPainless\n" + - "Comment: 8E0F C503 D081 002A 2BC8 60A1 1CFC 3439 106D 1DD1\n" + - "Comment: Marge Simpson \n" + - "\n" + - "mDMEYwdeTxYJKwYBBAHaRw8BAQdA/culAZNfjpo8NyfJv9ggwUJBY/9Ps27wRzj1\n" + - "3i5Y/am0IE1hcmdlIFNpbXBzb24gPG1hcmdlQHNpbXBzb24udHY+iI8EExYKAEEF\n" + - "AmMHXlAJEBz8NDkQbR3RFiEEjg/FA9CBACoryGChHPw0ORBtHdECngECmwEFFgID\n" + - "AQAECwkIBwUVCgkICwKZAQAALfgA/2OoVOE0DQV43EQSH4EoD92IaTGwBlojQexw\n" + - "t66gQI6gAP0WNw7VO0jRSMXXC9EAa6gvo+uA1D+QAT77PLNpeVsMArg4BGMHXlAS\n" + - "CisGAQQBl1UBBQEBB0AdA+eq1nAQ050uIPX3CCNSmj9TSkniz8cKOBRCsWujfwMB\n" + - "CAeIdQQYFgoAHQUCYwdeUAKeAQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJEBz8NDkQ\n" + - "bR3Rg3YA/A0tSMgNI+Jpyj8PdwSy51pLek3PLRHNWMt33XYWhl1zAQCDLusMON0z\n" + - "NhHUDP9qK4fDIQ2WgXQ5w+HoENREuM8WCbgzBGMHXlAWCSsGAQQB2kcPAQEHQMPz\n" + - "33nLNUBDALk2PMBqhIKYoGBcehix0qqYCZFXbOIbiNUEGBYKAH0FAmMHXlACngEC\n" + - "mwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjB15QAAoJEO8Ou9qRn4/Lk4AB\n" + - "AOTUMLOTPL9svmyoHmeVKYh4pL92/+zrsNL2Kh8BX7/FAPsE3/N3J5MB2ZEyzNSU\n" + - "84STG3Aqa+2I2u4w58CeL8eRCAAKCRAc/DQ5EG0d0QBmAQDvHR1I/B4VBqMu44wc\n" + - "w1czqqFojv1KQMETnLCfU5Q4cwD+Mt6mNoXADACcnw2P3u5u3NoFQ0v2vFSaCoBx\n" + - "VzUQrgo=\n" + - "=mKjW\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - private static final String CERT_WITH_SIG = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "Version: PGPainless\n" + - "Comment: 8E0F C503 D081 002A 2BC8 60A1 1CFC 3439 106D 1DD1\n" + - "Comment: Marge Simpson \n" + - "\n" + - "mDMEYwdeTxYJKwYBBAHaRw8BAQdA/culAZNfjpo8NyfJv9ggwUJBY/9Ps27wRzj1\n" + - "3i5Y/amIdQQfFgoAJwUCYwdeUAkQHPw0ORBtHdEWIQSOD8UD0IEAKivIYKEc/DQ5\n" + - "EG0d0QAAQjgA/jAfrrt6eHZzPN8fyfg16W6K8dAhq/HpMefjQwQsCIFBAP9Pch2t\n" + - "OfRgNWZ90AaYI8uU2M7E8O6zlIRKku5LoDsgCLQgTWFyZ2UgU2ltcHNvbiA8bWFy\n" + - "Z2VAc2ltcHNvbi50dj6IjwQTFgoAQQUCYwdeUAkQHPw0ORBtHdEWIQSOD8UD0IEA\n" + - "KivIYKEc/DQ5EG0d0QKeAQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAAAt+AD/Y6hU\n" + - "4TQNBXjcRBIfgSgP3YhpMbAGWiNB7HC3rqBAjqAA/RY3DtU7SNFIxdcL0QBrqC+j\n" + - "64DUP5ABPvs8s2l5WwwCuDgEYwdeUBIKKwYBBAGXVQEFAQEHQB0D56rWcBDTnS4g\n" + - "9fcII1KaP1NKSeLPxwo4FEKxa6N/AwEIB4h1BBgWCgAdBQJjB15QAp4BApsMBRYC\n" + - "AwEABAsJCAcFFQoJCAsACgkQHPw0ORBtHdGDdgD8DS1IyA0j4mnKPw93BLLnWkt6\n" + - "Tc8tEc1Yy3fddhaGXXMBAIMu6ww43TM2EdQM/2orh8MhDZaBdDnD4egQ1ES4zxYJ\n" + - "uDMEYwdeUBYJKwYBBAHaRw8BAQdAw/Pfecs1QEMAuTY8wGqEgpigYFx6GLHSqpgJ\n" + - "kVds4huI1QQYFgoAfQUCYwdeUAKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYK\n" + - "AAYFAmMHXlAACgkQ7w672pGfj8uTgAEA5NQws5M8v2y+bKgeZ5UpiHikv3b/7Ouw\n" + - "0vYqHwFfv8UA+wTf83cnkwHZkTLM1JTzhJMbcCpr7Yja7jDnwJ4vx5EIAAoJEBz8\n" + - "NDkQbR3RAGYBAO8dHUj8HhUGoy7jjBzDVzOqoWiO/UpAwROcsJ9TlDhzAP4y3qY2\n" + - "hcAMAJyfDY/e7m7c2gVDS/a8VJoKgHFXNRCuCg==\n" + - "=H6OY\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - - private static final KeyMaterialReader reader = new KeyMaterialReader(); - - @Test - public void testOverrideExisting() throws IOException, BadDataException { - KeyMaterialMerger merger = MergeCallbacks.overrideExisting(); - KeyMaterial existing = parse(CERT); - KeyMaterial update = parse(KEY); - - assertSame(update, merger.merge(update, existing)); - } - - @Test - public void testOverrideExistingNull() throws IOException, BadDataException { - KeyMaterialMerger merger = MergeCallbacks.overrideExisting(); - KeyMaterial existing = null; - KeyMaterial update = parse(KEY); - - assertSame(update, merger.merge(update, existing)); - } - - @Test - public void testOverrideExistingWithNull() throws IOException, BadDataException { - KeyMaterialMerger merger = MergeCallbacks.overrideExisting(); - KeyMaterial existing = parse(CERT); - KeyMaterial update = null; - - assertNull(merger.merge(update, existing)); - } - - @Test - public void testMergeExistingCertWithSelf() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT); - KeyMaterial update = parse(CERT); - - assertEncodingEquals(existing, merger.merge(update, existing)); - } - - @Test - public void testMergeExistingCertWithNull() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT); - - assertEncodingEquals(existing, merger.merge(null, existing)); - } - - - @Test - public void testMergeNullWithCert() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial update = parse(CERT); - - assertEncodingEquals(update, merger.merge(update, null)); - } - - @Test - public void testMergeCertWithUpdate() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT); - KeyMaterial update = parse(CERT_WITH_SIG); - - assertEncodingEquals(update, merger.merge(update, existing)); - } - - @Test - public void testMergeUpdateWithCert() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT_WITH_SIG); - KeyMaterial update = parse(CERT); - - assertEncodingEquals(existing, merger.merge(update, existing)); - } - - @Test - public void testMergeKeyWithCert() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(KEY); - KeyMaterial update = parse(CERT); - - assertEncodingEquals(existing, merger.merge(update, existing)); - } - - @Test - public void testMergeCertWithKey() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT); - KeyMaterial update = parse(KEY); - - assertEncodingEquals(update, merger.merge(update, existing)); - } - - @Test - public void testMergeKeyWithUpdateCert() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(KEY); - KeyMaterial update = parse(CERT_WITH_SIG); - KeyMaterial expected = parse(KEY_WITH_SIG); - assertEncodingEquals(expected, merger.merge(update, existing)); - } - - @Test - public void testMergeUpdateCertWithKey() throws BadDataException, IOException { - KeyMaterialMerger merger = MergeCallbacks.mergeWithExisting(); - KeyMaterial existing = parse(CERT_WITH_SIG); - KeyMaterial update = parse(KEY); - KeyMaterial expected = parse(KEY_WITH_SIG); - - assertEncodingEquals(expected, merger.merge(update, existing)); - } - - private static KeyMaterial parse(String encoding) throws BadDataException, IOException { - return reader.read(new ByteArrayInputStream(encoding.getBytes(Charset.forName("UTF8"))), null); - } - - private static void assertEncodingEquals(KeyMaterial one, KeyMaterial two) throws IOException { - ByteArrayOutputStream oneOut = new ByteArrayOutputStream(); - ByteArrayOutputStream twoOut = new ByteArrayOutputStream(); - - Streams.pipeAll(one.getInputStream(), oneOut); - Streams.pipeAll(two.getInputStream(), twoOut); - - assertArrayEquals(oneOut.toByteArray(), twoOut.toByteArray()); - } -} diff --git a/version.gradle b/version.gradle index 982e05b..45efb59 100644 --- a/version.gradle +++ b/version.gradle @@ -13,7 +13,7 @@ allprojects { junitVersion = '5.8.2' mockitoVersion = '4.5.1' pgpainlessVersion = '1.3.5' - pgpCertDJavaVersion = '0.2.0' + pgpCertDJavaVersion = '0.1.2-SNAPSHOT' picocliVersion = '4.6.3' } }