From 47e521be01da6b8664ea5f3a14d6fcfb682f2e8e Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 8 Aug 2022 14:00:50 +0200 Subject: [PATCH 1/4] Adopt changes from cert-d-java and pgpainless-core --- .../main/java/pgp/cert_d/cli/PGPCertDCli.java | 2 -- .../certificate_store/CertificateReader.java | 22 ------------------- .../certificate_store/KeyFactory.java | 5 +++++ .../certificate_store/KeyReader.java | 16 ++++++++++---- ...redPGPCertificateDirectoryAdapterTest.java | 3 +-- .../SharedPGPCertificateDirectoryTest.java | 13 +++++------ version.gradle | 2 +- 7 files changed, 25 insertions(+), 38 deletions(-) delete mode 100644 pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/CertificateReader.java 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 e87944e..355c999 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 @@ -4,7 +4,6 @@ package pgp.cert_d.cli; -import org.pgpainless.certificate_store.CertificateReader; import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter; import pgp.cert_d.BaseDirectoryProvider; @@ -62,7 +61,6 @@ public class PGPCertDCli { certificateDirectory = new SharedPGPCertificateDirectoryImpl( baseDirectory, - new CertificateReader(), new KeyReader()); subkeyLookup = new DatabaseSubkeyLookup( SqliteSubkeyLookupDaoImpl.forDatabaseFile(new File(baseDirectory, "_pgpainless_subkey_map.db"))); diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/CertificateReader.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/CertificateReader.java deleted file mode 100644 index 5e3068a..0000000 --- a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/CertificateReader.java +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.certificate_store; - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.pgpainless.PGPainless; -import pgp.certificate_store.Certificate; -import pgp.certificate_store.CertificateReaderBackend; - -public class CertificateReader implements CertificateReaderBackend { - - @Override - public Certificate readCertificate(InputStream inputStream) throws IOException { - final PGPPublicKeyRing certificate = PGPainless.readKeyRing().publicKeyRing(inputStream); - return CertificateFactory.certificateFromPublicKeyRing(certificate); - } -} diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyFactory.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyFactory.java index aa461b0..64ebf10 100644 --- a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyFactory.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyFactory.java @@ -22,6 +22,11 @@ public class KeyFactory { public static Key keyFromSecretKeyRing(PGPSecretKeyRing secretKeyRing) { return new Key() { + @Override + public String getFingerprint() { + return getCertificate().getFingerprint(); + } + @Override public Certificate getCertificate() { PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeyRing); diff --git a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyReader.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyReader.java index c18569b..bc8f371 100644 --- a/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyReader.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/KeyReader.java @@ -4,9 +4,11 @@ package org.pgpainless.certificate_store; +import org.bouncycastle.openpgp.PGPKeyRing; +import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.pgpainless.PGPainless; -import pgp.certificate_store.Key; +import pgp.certificate_store.KeyMaterial; import pgp.certificate_store.KeyReaderBackend; import pgp.certificate_store.exception.BadDataException; @@ -16,8 +18,14 @@ import java.io.InputStream; public class KeyReader implements KeyReaderBackend { @Override - public Key readKey(InputStream data) throws IOException, BadDataException { - final PGPSecretKeyRing key = PGPainless.readKeyRing().secretKeyRing(data); - return KeyFactory.keyFromSecretKeyRing(key); + public KeyMaterial read(InputStream data) throws IOException, BadDataException { + final PGPKeyRing keyRing = PGPainless.readKeyRing().keyRing(data); + if (keyRing instanceof PGPPublicKeyRing) { + return CertificateFactory.certificateFromPublicKeyRing((PGPPublicKeyRing) keyRing); + } else if (keyRing instanceof PGPSecretKeyRing) { + return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) keyRing); + } else { + throw new BadDataException(); + } } } diff --git a/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryAdapterTest.java b/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryAdapterTest.java index d5cc211..5a42690 100644 --- a/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryAdapterTest.java +++ b/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryAdapterTest.java @@ -26,7 +26,6 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.pgpainless.certificate_store.CertificateReader; import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter; import pgp.cert_d.InMemorySubkeyLookup; @@ -51,7 +50,7 @@ public class SharedPGPCertificateDirectoryAdapterTest { @BeforeEach public void setupInstance() throws IOException, NotAStoreException { adapter = new SharedPGPCertificateDirectoryAdapter( - new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()), + new SharedPGPCertificateDirectoryImpl(tempDir(), new KeyReader()), new InMemorySubkeyLookup()); store = adapter; } diff --git a/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryTest.java b/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryTest.java index c43f749..d6a4902 100644 --- a/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryTest.java +++ b/pgpainless-cert-d/src/test/java/org/pgpainless/cert_d/SharedPGPCertificateDirectoryTest.java @@ -32,7 +32,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.certificate_store.CertificateReader; import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.generation.KeySpec; @@ -59,9 +58,9 @@ public class SharedPGPCertificateDirectoryTest { private static Stream provideTestSubjects() throws IOException, NotAStoreException { return Stream.of( - new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()), + new SharedPGPCertificateDirectoryImpl(tempDir(), new KeyReader()), new CachingSharedPGPCertificateDirectoryWrapper( - new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader())) + new SharedPGPCertificateDirectoryImpl(tempDir(), new KeyReader())) ); } @@ -76,7 +75,7 @@ public class SharedPGPCertificateDirectoryTest { public void simpleInsertGet(SharedPGPCertificateDirectory directory) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, BadDataException, InterruptedException, BadNameException { - PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice", null); + PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice"); PGPPublicKeyRing cert = PGPainless.extractCertificate(key); OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert); ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); @@ -133,7 +132,7 @@ public class SharedPGPCertificateDirectoryTest { BadDataException, InterruptedException { assumeTrue(directory.getLock() instanceof FileLockingMechanism); - PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice", null); + PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice"); PGPPublicKeyRing cert = PGPainless.extractCertificate(key); ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); @@ -150,7 +149,7 @@ public class SharedPGPCertificateDirectoryTest { throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, BadDataException, InterruptedException, BadNameException { - PGPSecretKeyRing trustRootKey = PGPainless.generateKeyRing().modernKeyRing("Alice", null); + PGPSecretKeyRing trustRootKey = PGPainless.generateKeyRing().modernKeyRing("Alice"); PGPPublicKeyRing trustRootCert = PGPainless.extractCertificate(trustRootKey); OpenPgpFingerprint trustRootFingerprint = OpenPgpFingerprint.of(trustRootCert); ByteArrayInputStream trustRootCertIn = new ByteArrayInputStream(trustRootCert.getEncoded()); @@ -159,7 +158,7 @@ public class SharedPGPCertificateDirectoryTest { final int certificateCount = 3; Map certificateMap = new HashMap<>(); for (int i = 0; i < certificateCount; i++) { - PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice", null); + PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice"); PGPPublicKeyRing cert = PGPainless.extractCertificate(key); OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert); certificateMap.put(fingerprint.toString().toLowerCase(), cert); diff --git a/version.gradle b/version.gradle index a7ce230..90264e0 100644 --- a/version.gradle +++ b/version.gradle @@ -12,7 +12,7 @@ allprojects { logbackVersion = '1.2.11' junitVersion = '5.8.2' mockitoVersion = '4.5.1' - pgpainlessVersion = '1.2.1' + pgpainlessVersion = '1.3.5-SNAPSHOT' pgpCertDJavaVersion = '0.1.2-SNAPSHOT' picocliVersion = '4.6.3' } From 338530b1bc6e0665635a661c2bd734edece38de3 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 8 Aug 2022 15:03:54 +0200 Subject: [PATCH 2/4] Fix duplicate logging binding problem --- pgpainless-cert-d-cli/build.gradle | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pgpainless-cert-d-cli/build.gradle b/pgpainless-cert-d-cli/build.gradle index 2dcb9f9..4c64b45 100644 --- a/pgpainless-cert-d-cli/build.gradle +++ b/pgpainless-cert-d-cli/build.gradle @@ -4,6 +4,7 @@ plugins { id 'application' + id "com.github.johnrengelman.shadow" version "6.1.0" } group 'org.pgpainless' @@ -18,7 +19,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" // Logging - testImplementation "ch.qos.logback:logback-classic:$logbackVersion" + implementation ("org.slf4j:slf4j-nop:$slf4jVersion") // pgp.cert.d using PGPainless implementation project(":pgpainless-cert-d") @@ -36,8 +37,13 @@ test { mainClassName = 'pgp.cert_d.cli.PGPCertDCli' +application { + mainClass = mainClassName +} + +/* jar { - dependsOn(":pgpainless-cert-d:assemble") + dependsOn(":pgpainless-cert-d:jar") manifest { attributes 'Main-Class': "$mainClassName" } @@ -52,4 +58,5 @@ jar { exclude "META-INF/*.RSA" } } + */ From 6a16d0cff554cc9eaf2b3a306904cb1d44fdc49d Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 8 Aug 2022 15:04:22 +0200 Subject: [PATCH 3/4] Implement armor option for export command --- .../java/pgp/cert_d/cli/commands/Export.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Export.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Export.java index 555d169..8a9027a 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Export.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Export.java @@ -4,6 +4,7 @@ package pgp.cert_d.cli.commands; +import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.util.io.Streams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,28 +14,40 @@ import picocli.CommandLine; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.util.Iterator; @CommandLine.Command(name = "export", resourceBundle = "msg_export") public class Export implements Runnable { - private static final Logger LOGGER = LoggerFactory.getLogger(Get.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Export.class); + + @CommandLine.Option(names = {"-a", "--armor"}) + boolean armor = false; @Override public void run() { Iterator certificates = PGPCertDCli.getCertificateDirectory() .getCertificates(); + OutputStream out = armor ? new ArmoredOutputStream(System.out) : System.out; while (certificates.hasNext()) { try { Certificate certificate = certificates.next(); InputStream inputStream = certificate.getInputStream(); - Streams.pipeAll(inputStream, System.out); + Streams.pipeAll(inputStream, out); inputStream.close(); } catch (IOException e) { LOGGER.error("IO Error", e); System.exit(-1); } } + if (armor) { + try { + out.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } } From 3267a330bfd702adb84c0225d489207231a531f1 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 8 Aug 2022 15:04:34 +0200 Subject: [PATCH 4/4] Implement very basic list command --- .../main/java/pgp/cert_d/cli/PGPCertDCli.java | 4 ++- .../java/pgp/cert_d/cli/commands/List.java | 29 +++++++++++++++++++ .../src/main/resources/msg_list.properties | 11 +++++++ .../src/main/resources/msg_list_de.properties | 11 +++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/List.java create mode 100644 pgpainless-cert-d-cli/src/main/resources/msg_list.properties create mode 100644 pgpainless-cert-d-cli/src/main/resources/msg_list_de.properties 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 355c999..f742d01 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 @@ -12,6 +12,7 @@ import pgp.cert_d.cli.commands.Export; import pgp.cert_d.cli.commands.Get; import pgp.cert_d.cli.commands.Insert; import pgp.cert_d.cli.commands.Import; +import pgp.cert_d.cli.commands.List; import pgp.cert_d.cli.commands.Setup; import pgp.cert_d.jdbc.sqlite.DatabaseSubkeyLookup; import pgp.cert_d.jdbc.sqlite.SqliteSubkeyLookupDaoImpl; @@ -32,7 +33,8 @@ import java.sql.SQLException; Insert.class, Import.class, Get.class, - Setup.class + Setup.class, + List.class } ) public class PGPCertDCli { diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/List.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/List.java new file mode 100644 index 0000000..8c888c2 --- /dev/null +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/List.java @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d.cli.commands; + +import pgp.cert_d.cli.PGPCertDCli; +import pgp.certificate_store.Certificate; +import picocli.CommandLine; + +import java.util.Iterator; + +@CommandLine.Command(name = "list", + resourceBundle = "msg_list" +) +public class List implements Runnable { + + @Override + public void run() { + Iterator certificates = PGPCertDCli.getCertificateDirectory() + .getCertificates(); + while (certificates.hasNext()) { + Certificate certificate = certificates.next(); + // CHECKSTYLE:OFF + System.out.println(certificate.getFingerprint()); + // CHECKSTYLE:ON + } + } +} diff --git a/pgpainless-cert-d-cli/src/main/resources/msg_list.properties b/pgpainless-cert-d-cli/src/main/resources/msg_list.properties new file mode 100644 index 0000000..f58dd82 --- /dev/null +++ b/pgpainless-cert-d-cli/src/main/resources/msg_list.properties @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2022 Paul Schaub +# +# SPDX-License-Identifier: Apache-2.0 +usage.header=List all certificates in the directory +store=Overwrite the default certificate directory path + +# Generic TODO: Remove when bumping picocli to 4.7.0 +usage.synopsisHeading=Usage:\u0020 +usage.commandListHeading = %nCommands:%n +usage.optionListHeading = %nOptions:%n +usage.footerHeading=Powered by picocli%n diff --git a/pgpainless-cert-d-cli/src/main/resources/msg_list_de.properties b/pgpainless-cert-d-cli/src/main/resources/msg_list_de.properties new file mode 100644 index 0000000..2385597 --- /dev/null +++ b/pgpainless-cert-d-cli/src/main/resources/msg_list_de.properties @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2022 Paul Schaub +# +# SPDX-License-Identifier: Apache-2.0 +usage.header=Liste alle Zertifikate im Verzeichnis auf +store=Überschreibe den Standardpfad des Zertifikatsverzeichnisses + +# Generic TODO: Remove when bumping picocli to 4.7.0 +usage.synopsisHeading=Aufruf:\u0020 +usage.commandListHeading=%nBefehle:%n +usage.optionListHeading = %nOptionen:%n +usage.footerHeading=Powered by Picocli%n