Compare commits

...

4 commits

12 changed files with 103 additions and 43 deletions

View file

@ -4,6 +4,7 @@
plugins { plugins {
id 'application' id 'application'
id "com.github.johnrengelman.shadow" version "6.1.0"
} }
group 'org.pgpainless' group 'org.pgpainless'
@ -18,7 +19,7 @@ dependencies {
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
// Logging // Logging
testImplementation "ch.qos.logback:logback-classic:$logbackVersion" implementation ("org.slf4j:slf4j-nop:$slf4jVersion")
// pgp.cert.d using PGPainless // pgp.cert.d using PGPainless
implementation project(":pgpainless-cert-d") implementation project(":pgpainless-cert-d")
@ -36,8 +37,13 @@ test {
mainClassName = 'pgp.cert_d.cli.PGPCertDCli' mainClassName = 'pgp.cert_d.cli.PGPCertDCli'
application {
mainClass = mainClassName
}
/*
jar { jar {
dependsOn(":pgpainless-cert-d:assemble") dependsOn(":pgpainless-cert-d:jar")
manifest { manifest {
attributes 'Main-Class': "$mainClassName" attributes 'Main-Class': "$mainClassName"
} }
@ -52,4 +58,5 @@ jar {
exclude "META-INF/*.RSA" exclude "META-INF/*.RSA"
} }
} }
*/

View file

@ -4,7 +4,6 @@
package pgp.cert_d.cli; package pgp.cert_d.cli;
import org.pgpainless.certificate_store.CertificateReader;
import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.certificate_store.KeyReader;
import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter; import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter;
import pgp.cert_d.BaseDirectoryProvider; import pgp.cert_d.BaseDirectoryProvider;
@ -13,6 +12,7 @@ import pgp.cert_d.cli.commands.Export;
import pgp.cert_d.cli.commands.Get; import pgp.cert_d.cli.commands.Get;
import pgp.cert_d.cli.commands.Insert; import pgp.cert_d.cli.commands.Insert;
import pgp.cert_d.cli.commands.Import; 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.cli.commands.Setup;
import pgp.cert_d.jdbc.sqlite.DatabaseSubkeyLookup; import pgp.cert_d.jdbc.sqlite.DatabaseSubkeyLookup;
import pgp.cert_d.jdbc.sqlite.SqliteSubkeyLookupDaoImpl; import pgp.cert_d.jdbc.sqlite.SqliteSubkeyLookupDaoImpl;
@ -33,7 +33,8 @@ import java.sql.SQLException;
Insert.class, Insert.class,
Import.class, Import.class,
Get.class, Get.class,
Setup.class Setup.class,
List.class
} }
) )
public class PGPCertDCli { public class PGPCertDCli {
@ -62,7 +63,6 @@ public class PGPCertDCli {
certificateDirectory = new SharedPGPCertificateDirectoryImpl( certificateDirectory = new SharedPGPCertificateDirectoryImpl(
baseDirectory, baseDirectory,
new CertificateReader(),
new KeyReader()); new KeyReader());
subkeyLookup = new DatabaseSubkeyLookup( subkeyLookup = new DatabaseSubkeyLookup(
SqliteSubkeyLookupDaoImpl.forDatabaseFile(new File(baseDirectory, "_pgpainless_subkey_map.db"))); SqliteSubkeyLookupDaoImpl.forDatabaseFile(new File(baseDirectory, "_pgpainless_subkey_map.db")));

View file

@ -4,6 +4,7 @@
package pgp.cert_d.cli.commands; package pgp.cert_d.cli.commands;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -13,28 +14,40 @@ import picocli.CommandLine;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator; import java.util.Iterator;
@CommandLine.Command(name = "export", @CommandLine.Command(name = "export",
resourceBundle = "msg_export") resourceBundle = "msg_export")
public class Export implements Runnable { 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 @Override
public void run() { public void run() {
Iterator<Certificate> certificates = PGPCertDCli.getCertificateDirectory() Iterator<Certificate> certificates = PGPCertDCli.getCertificateDirectory()
.getCertificates(); .getCertificates();
OutputStream out = armor ? new ArmoredOutputStream(System.out) : System.out;
while (certificates.hasNext()) { while (certificates.hasNext()) {
try { try {
Certificate certificate = certificates.next(); Certificate certificate = certificates.next();
InputStream inputStream = certificate.getInputStream(); InputStream inputStream = certificate.getInputStream();
Streams.pipeAll(inputStream, System.out); Streams.pipeAll(inputStream, out);
inputStream.close(); inputStream.close();
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("IO Error", e); LOGGER.error("IO Error", e);
System.exit(-1); System.exit(-1);
} }
} }
if (armor) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} }
} }

View file

@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// 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<Certificate> certificates = PGPCertDCli.getCertificateDirectory()
.getCertificates();
while (certificates.hasNext()) {
Certificate certificate = certificates.next();
// CHECKSTYLE:OFF
System.out.println(certificate.getFingerprint());
// CHECKSTYLE:ON
}
}
}

View file

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
#
# 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

View file

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
#
# 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

View file

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// 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);
}
}

View file

@ -22,6 +22,11 @@ public class KeyFactory {
public static Key keyFromSecretKeyRing(PGPSecretKeyRing secretKeyRing) { public static Key keyFromSecretKeyRing(PGPSecretKeyRing secretKeyRing) {
return new Key() { return new Key() {
@Override
public String getFingerprint() {
return getCertificate().getFingerprint();
}
@Override @Override
public Certificate getCertificate() { public Certificate getCertificate() {
PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeyRing); PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeyRing);

View file

@ -4,9 +4,11 @@
package org.pgpainless.certificate_store; package org.pgpainless.certificate_store;
import org.bouncycastle.openpgp.PGPKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import pgp.certificate_store.Key; import pgp.certificate_store.KeyMaterial;
import pgp.certificate_store.KeyReaderBackend; import pgp.certificate_store.KeyReaderBackend;
import pgp.certificate_store.exception.BadDataException; import pgp.certificate_store.exception.BadDataException;
@ -16,8 +18,14 @@ import java.io.InputStream;
public class KeyReader implements KeyReaderBackend { public class KeyReader implements KeyReaderBackend {
@Override @Override
public Key readKey(InputStream data) throws IOException, BadDataException { public KeyMaterial read(InputStream data) throws IOException, BadDataException {
final PGPSecretKeyRing key = PGPainless.readKeyRing().secretKeyRing(data); final PGPKeyRing keyRing = PGPainless.readKeyRing().keyRing(data);
return KeyFactory.keyFromSecretKeyRing(key); if (keyRing instanceof PGPPublicKeyRing) {
return CertificateFactory.certificateFromPublicKeyRing((PGPPublicKeyRing) keyRing);
} else if (keyRing instanceof PGPSecretKeyRing) {
return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) keyRing);
} else {
throw new BadDataException();
}
} }
} }

View file

@ -26,7 +26,6 @@ import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.certificate_store.CertificateReader;
import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.certificate_store.KeyReader;
import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter; import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter;
import pgp.cert_d.InMemorySubkeyLookup; import pgp.cert_d.InMemorySubkeyLookup;
@ -51,7 +50,7 @@ public class SharedPGPCertificateDirectoryAdapterTest {
@BeforeEach @BeforeEach
public void setupInstance() throws IOException, NotAStoreException { public void setupInstance() throws IOException, NotAStoreException {
adapter = new SharedPGPCertificateDirectoryAdapter( adapter = new SharedPGPCertificateDirectoryAdapter(
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()), new SharedPGPCertificateDirectoryImpl(tempDir(), new KeyReader()),
new InMemorySubkeyLookup()); new InMemorySubkeyLookup());
store = adapter; store = adapter;
} }

View file

@ -32,7 +32,6 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.certificate_store.CertificateReader;
import org.pgpainless.certificate_store.KeyReader; import org.pgpainless.certificate_store.KeyReader;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.generation.KeySpec; import org.pgpainless.key.generation.KeySpec;
@ -59,9 +58,9 @@ public class SharedPGPCertificateDirectoryTest {
private static Stream<SharedPGPCertificateDirectory> provideTestSubjects() throws IOException, NotAStoreException { private static Stream<SharedPGPCertificateDirectory> provideTestSubjects() throws IOException, NotAStoreException {
return Stream.of( return Stream.of(
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()), new SharedPGPCertificateDirectoryImpl(tempDir(), new KeyReader()),
new CachingSharedPGPCertificateDirectoryWrapper( 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) public void simpleInsertGet(SharedPGPCertificateDirectory directory)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException,
BadDataException, InterruptedException, BadNameException { BadDataException, InterruptedException, BadNameException {
PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice", null); PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice");
PGPPublicKeyRing cert = PGPainless.extractCertificate(key); PGPPublicKeyRing cert = PGPainless.extractCertificate(key);
OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert); OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert);
ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded());
@ -133,7 +132,7 @@ public class SharedPGPCertificateDirectoryTest {
BadDataException, InterruptedException { BadDataException, InterruptedException {
assumeTrue(directory.getLock() instanceof FileLockingMechanism); assumeTrue(directory.getLock() instanceof FileLockingMechanism);
PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice", null); PGPSecretKeyRing key = PGPainless.generateKeyRing().modernKeyRing("Alice");
PGPPublicKeyRing cert = PGPainless.extractCertificate(key); PGPPublicKeyRing cert = PGPainless.extractCertificate(key);
ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded()); ByteArrayInputStream certIn = new ByteArrayInputStream(cert.getEncoded());
@ -150,7 +149,7 @@ public class SharedPGPCertificateDirectoryTest {
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException,
BadDataException, InterruptedException, BadNameException { BadDataException, InterruptedException, BadNameException {
PGPSecretKeyRing trustRootKey = PGPainless.generateKeyRing().modernKeyRing("Alice", null); PGPSecretKeyRing trustRootKey = PGPainless.generateKeyRing().modernKeyRing("Alice");
PGPPublicKeyRing trustRootCert = PGPainless.extractCertificate(trustRootKey); PGPPublicKeyRing trustRootCert = PGPainless.extractCertificate(trustRootKey);
OpenPgpFingerprint trustRootFingerprint = OpenPgpFingerprint.of(trustRootCert); OpenPgpFingerprint trustRootFingerprint = OpenPgpFingerprint.of(trustRootCert);
ByteArrayInputStream trustRootCertIn = new ByteArrayInputStream(trustRootCert.getEncoded()); ByteArrayInputStream trustRootCertIn = new ByteArrayInputStream(trustRootCert.getEncoded());
@ -159,7 +158,7 @@ public class SharedPGPCertificateDirectoryTest {
final int certificateCount = 3; final int certificateCount = 3;
Map<String, PGPPublicKeyRing> certificateMap = new HashMap<>(); Map<String, PGPPublicKeyRing> certificateMap = new HashMap<>();
for (int i = 0; i < certificateCount; i++) { 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); PGPPublicKeyRing cert = PGPainless.extractCertificate(key);
OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert); OpenPgpFingerprint fingerprint = OpenPgpFingerprint.of(cert);
certificateMap.put(fingerprint.toString().toLowerCase(), cert); certificateMap.put(fingerprint.toString().toLowerCase(), cert);

View file

@ -12,7 +12,7 @@ allprojects {
logbackVersion = '1.2.11' logbackVersion = '1.2.11'
junitVersion = '5.8.2' junitVersion = '5.8.2'
mockitoVersion = '4.5.1' mockitoVersion = '4.5.1'
pgpainlessVersion = '1.2.1' pgpainlessVersion = '1.3.5-SNAPSHOT'
pgpCertDJavaVersion = '0.1.2-SNAPSHOT' pgpCertDJavaVersion = '0.1.2-SNAPSHOT'
picocliVersion = '4.6.3' picocliVersion = '4.6.3'
} }