From 98377b34f180b1c155f3c7822440d848507d6e5e Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 29 Jun 2023 19:23:40 +0200 Subject: [PATCH] Base WebOfTrust on PGPCertificateStore instead of PGPCertificateDirectory --- .../kotlin/org/pgpainless/wot/cli/WotCLI.kt | 35 ++++++++++++++++--- .../kotlin/org/pgpainless/wot/WebOfTrust.kt | 32 +++++++++++++---- .../org/pgpainless/wot/WebOfTrustTest.java | 12 +++---- .../testfixtures/TestCertificateStores.java | 32 ++++++++--------- 4 files changed, 78 insertions(+), 33 deletions(-) diff --git a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt index a4a0172c..ea89898f 100644 --- a/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt +++ b/pgpainless-wot-cli/src/main/kotlin/org/pgpainless/wot/cli/WotCLI.kt @@ -4,9 +4,14 @@ package org.pgpainless.wot.cli +import org.pgpainless.certificate_store.PGPainlessCertD import org.pgpainless.util.DateUtil import org.pgpainless.wot.cli.subcommands.* import org.pgpainless.wot.dijkstra.sq.ReferenceTime +import pgp.cert_d.PGPCertificateDirectory +import pgp.cert_d.PGPCertificateStoreAdapter +import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory +import pgp.certificate_store.PGPCertificateStore import picocli.CommandLine import picocli.CommandLine.* import java.io.File @@ -28,13 +33,22 @@ class WotCLI: Callable { @Option(names = ["--trust-root", "-r"], required = true) var trustRoot: Array = arrayOf() - @Option(names = ["--keyring", "-k"], description = ["Specify a keyring file."], required = true) - var keyring: File? = null + @ArgGroup(exclusive = true, multiplicity = "1") + lateinit var certificateSource: CertificateSource + + class CertificateSource { + @Option(names = ["--keyring", "-k"], description = ["Specify a keyring file."], required = true) + var keyring: File? = null + + @Option(names = ["--cert-d"], description = ["Specify a pgp-cert-d base directory."], required = true) + var pgpCertD: File? = null + + @Option(names = ["--gpg"], description = ["Read trust roots and keyring from GnuPG."]) + var gpg = false + } + /* - @Option(names = ["--gpg"], description = ["Read trust roots and keyring from GnuPG."]) - var gpg = false - @Option(names = ["--network"], description = ["Look for missing certificates on a key server or the WKD."]) var keyServer = "hkps://keyserver.ubuntu.com" @@ -60,6 +74,17 @@ class WotCLI: Callable { } } + fun getCertificateStore(): PGPCertificateStore { + requireNotNull(certificateSource.pgpCertD) { + "Currently, only --cert-d is supported." + } + val certD = PGPainlessCertD.fileBased( + certificateSource.pgpCertD, + InMemorySubkeyLookupFactory()) + + return PGPCertificateStoreAdapter(certD) + } + /** * Execute the command. * diff --git a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt b/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt index 44a9acb7..0faffb32 100644 --- a/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt +++ b/pgpainless-wot/src/main/kotlin/org/pgpainless/wot/WebOfTrust.kt @@ -25,29 +25,49 @@ import org.pgpainless.wot.util.CertificationFactory.Companion.fromCertification import org.pgpainless.wot.util.CertificationFactory.Companion.fromDelegation import org.slf4j.LoggerFactory import pgp.cert_d.PGPCertificateDirectory +import pgp.cert_d.PGPCertificateStoreAdapter +import pgp.cert_d.SpecialNames +import pgp.certificate_store.PGPCertificateStore import pgp.certificate_store.certificate.Certificate import java.io.IOException import java.util.* -class WebOfTrust(private val certificateStore: PGPCertificateDirectory) { +/** + * Create a [WebOfTrust] based on a [PGPCertificateStore] instance. + * + * @param certificateStore certificate store + */ +class WebOfTrust(private val certificateStore: PGPCertificateStore) { + + /** + * Create a [WebOfTrust] based on a [PGPCertificateDirectory] instance, which gets adapted to the + * [PGPCertificateStore] interface. + * + * @param certificateDirectory PGP-Certificate-Directory instance + */ + constructor(certificateDirectory: PGPCertificateDirectory): this(PGPCertificateStoreAdapter(certificateDirectory)) lateinit var network: Network fun initialize() { + val certificates = getAllCertificatesFromTheStore() + network = fromCertificates(certificates, PGPainless.getPolicy(), now()) + } + + private fun getAllCertificatesFromTheStore(): Sequence { var trustRoot: Certificate? = null try { - trustRoot = certificateStore.trustRootCertificate + trustRoot = certificateStore.getCertificate(SpecialNames.TRUST_ROOT) } catch (e: NoSuchElementException) { // ignore } val certificates = if (trustRoot == null) { - certificateStore.items().asSequence() + certificateStore.certificates.asSequence() } else { - sequenceOf(trustRoot) + certificateStore.items().asSequence() + sequenceOf(trustRoot) + certificateStore.certificates.asSequence() } - - network = fromCertificates(certificates, PGPainless.getPolicy(), now()) + return certificates } companion object { diff --git a/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java b/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java index 55cdf81f..d3976864 100644 --- a/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java +++ b/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java @@ -35,8 +35,8 @@ public class WebOfTrustTest { @Test public void testWithTwoNodesAndOneDelegation() throws BadDataException, IOException, InterruptedException { - PGPCertificateDirectory store = TestCertificateStores.oneDelegationGraph(); - WebOfTrust wot = new WebOfTrust(store); + PGPCertificateDirectory certD = TestCertificateStores.oneDelegationGraph(); + WebOfTrust wot = new WebOfTrust(certD); wot.initialize(); Network network = wot.getNetwork(); @@ -52,8 +52,8 @@ public class WebOfTrustTest { @Test public void testWithCrossSignedCertificates() throws BadDataException, IOException, InterruptedException { - PGPCertificateDirectory store = TestCertificateStores.disconnectedGraph(); - WebOfTrust wot = new WebOfTrust(store); + PGPCertificateDirectory certD = TestCertificateStores.disconnectedGraph(); + WebOfTrust wot = new WebOfTrust(certD); wot.initialize(); Network network = wot.getNetwork(); @@ -140,8 +140,8 @@ public class WebOfTrustTest { @Test public void testWotCreationOfEmptyCertificates() { - PGPCertificateDirectory store = TestCertificateStores.emptyGraph(); - WebOfTrust wot = new WebOfTrust(store); + PGPCertificateDirectory certD = TestCertificateStores.emptyGraph(); + WebOfTrust wot = new WebOfTrust(certD); wot.initialize(); Network network = wot.getNetwork(); diff --git a/pgpainless-wot/src/testFixtures/java/org/pgpainless/wot/testfixtures/TestCertificateStores.java b/pgpainless-wot/src/testFixtures/java/org/pgpainless/wot/testfixtures/TestCertificateStores.java index ad11b5df..ec9b684e 100644 --- a/pgpainless-wot/src/testFixtures/java/org/pgpainless/wot/testfixtures/TestCertificateStores.java +++ b/pgpainless-wot/src/testFixtures/java/org/pgpainless/wot/testfixtures/TestCertificateStores.java @@ -29,37 +29,37 @@ public class TestCertificateStores { public static PGPCertificateDirectory disconnectedGraph() throws BadDataException, IOException, InterruptedException { - PGPCertificateDirectory wotStore = createInMemoryStore(); + PGPCertificateDirectory certD = createInMemoryCertificateDirectory(); - wotStore.insertTrustRoot(getTestVector("cross_signed/foobankCaCert.asc"), merger); - wotStore.insert(getTestVector("cross_signed/foobankEmployeeCert.asc"), merger); - wotStore.insert(getTestVector("cross_signed/foobankAdminCert.asc"), merger); - wotStore.insert(getTestVector("cross_signed/barbankCaCert.asc"), merger); - wotStore.insert(getTestVector("cross_signed/barbankEmployeeCert.asc"), merger); + certD.insertTrustRoot(getTestVector("cross_signed/foobankCaCert.asc"), merger); + certD.insert(getTestVector("cross_signed/foobankEmployeeCert.asc"), merger); + certD.insert(getTestVector("cross_signed/foobankAdminCert.asc"), merger); + certD.insert(getTestVector("cross_signed/barbankCaCert.asc"), merger); + certD.insert(getTestVector("cross_signed/barbankEmployeeCert.asc"), merger); - return wotStore; + return certD; } public static PGPCertificateDirectory emptyGraph() { - PGPCertificateDirectory wotStore = createInMemoryStore(); + PGPCertificateDirectory certD = createInMemoryCertificateDirectory(); - return wotStore; + return certD; } public static PGPCertificateDirectory oneDelegationGraph() throws BadDataException, IOException, InterruptedException { - PGPCertificateDirectory wotStore = createInMemoryStore(); - wotStore.insert(getTestVector("cross_signed/foobankAdminCert.asc"), merger); - wotStore.insert(getTestVector("cross_signed/barbankCaCert.asc"), merger); + PGPCertificateDirectory certD = createInMemoryCertificateDirectory(); + certD.insert(getTestVector("cross_signed/foobankAdminCert.asc"), merger); + certD.insert(getTestVector("cross_signed/barbankCaCert.asc"), merger); - return wotStore; + return certD; } - private static PGPCertificateDirectory createInMemoryStore() { + private static PGPCertificateDirectory createInMemoryCertificateDirectory() { SubkeyLookup subkeyLookup = new InMemorySubkeyLookup(); KeyMaterialReaderBackend readerBackend = new KeyMaterialReader(); PGPCertificateDirectory.Backend backend = new InMemoryCertificateDirectoryBackend(readerBackend); - PGPCertificateDirectory store = new PGPCertificateDirectory(backend, subkeyLookup); - return store; + PGPCertificateDirectory certD = new PGPCertificateDirectory(backend, subkeyLookup); + return certD; } private static InputStream requireResource(String resourceName) {