diff --git a/pgpainless-wot/build.gradle b/pgpainless-wot/build.gradle index 1ed82f4a..9e877417 100644 --- a/pgpainless-wot/build.gradle +++ b/pgpainless-wot/build.gradle @@ -4,6 +4,7 @@ plugins { id 'java-library' + id 'java-test-fixtures' } group 'org.pgpainless' @@ -13,13 +14,20 @@ repositories { } dependencies { + // JUnit testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + testFixturesImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + testFixturesImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" + testFixturesRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + // Logging testImplementation "ch.qos.logback:logback-classic:$logbackVersion" implementation(project(":pgpainless-core")) + implementation(project(":wot-dijkstra")) // Certificate store api "org.pgpainless:pgp-certificate-store:$certDJavaVersion" diff --git a/pgpainless-wot/src/main/java/org/pgpainless/wot/IterableIterator.java b/pgpainless-wot/src/main/java/org/pgpainless/wot/IterableIterator.java new file mode 100644 index 00000000..978696b9 --- /dev/null +++ b/pgpainless-wot/src/main/java/org/pgpainless/wot/IterableIterator.java @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot; + +import java.util.Iterator; + +/** + * Because an {@link Iterator} is not {@link Iterable} ¯\_(ツ)_/¯. + * @param item + */ +public final class IterableIterator implements Iterable { + + private final Iterator iterator; + + public IterableIterator(Iterator iterator) { + this.iterator = iterator; + } + + @Override + public Iterator iterator() { + return iterator; + } +} diff --git a/pgpainless-wot/src/main/java/org/pgpainless/wot/PrefixedIterator.java b/pgpainless-wot/src/main/java/org/pgpainless/wot/PrefixedIterator.java new file mode 100644 index 00000000..a0456a82 --- /dev/null +++ b/pgpainless-wot/src/main/java/org/pgpainless/wot/PrefixedIterator.java @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot; + +import java.util.Iterator; + +/** + * Returns a new {@link Iterator} with a prepended item. + * @param item type + */ +public class PrefixedIterator implements Iterator { + + private T prefix; + private Iterator iterator; + + public PrefixedIterator(T prefix, Iterator iterator) { + this.prefix = prefix; + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return prefix != null || iterator.hasNext(); + } + + @Override + public T next() { + if (prefix != null) { + T t = prefix; + prefix = null; + return t; + } + return iterator.next(); + } +} diff --git a/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrust.java b/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrust.java index 6c885207..e8b7740f 100644 --- a/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrust.java +++ b/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrust.java @@ -4,15 +4,41 @@ package org.pgpainless.wot; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.bcpg.sig.RevocationReason; import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSignature; +import org.pgpainless.PGPainless; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.algorithm.RevocationState; +import org.pgpainless.key.OpenPgpFingerprint; +import org.pgpainless.key.info.KeyRingInfo; +import org.pgpainless.key.util.RevocationAttributes; +import org.pgpainless.policy.Policy; +import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; +import org.pgpainless.wot.dijkstra.sq.CertSynopsis; +import org.pgpainless.wot.dijkstra.sq.CertificationSet; +import org.pgpainless.wot.dijkstra.sq.Network; +import org.pgpainless.wot.dijkstra.sq.Optional; +import org.pgpainless.wot.dijkstra.sq.ReferenceTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import pgp.certificate_store.certificate.Certificate; import pgp.certificate_store.exception.BadDataException; -import java.io.IOException; - public class WebOfTrust implements CertificateAuthority { + private static final Logger LOGGER = LoggerFactory.getLogger(WebOfTrust.class); + private final WebOfTrustCertificateStore certificateStore; + private Network network; public WebOfTrust(WebOfTrustCertificateStore certificateStore) { this.certificateStore = certificateStore; @@ -22,8 +48,109 @@ public class WebOfTrust implements CertificateAuthority { * Do the heavy lifting of calculating the web of trust. */ public void initialize() throws BadDataException, IOException { - Certificate trustRoot = certificateStore.getTrustRootCertificate(); - // TODO: Implement + Iterator certificates = certificateStore.getAllItems(); + IterableIterator iterable = new IterableIterator<>(certificates); + network = fromCertificates(iterable, PGPainless.getPolicy(), Optional.just(ReferenceTime.now())); + } + + + /** + * Create a {@link Network} from a set of certificates. + * + * @param certificates set of certificates + * @param policy evaluation policy + * @param optReferenceTime reference time for evaluation + * @return network + */ + public static Network fromCertificates( + Iterable certificates, + Policy policy, + Optional optReferenceTime) { + ReferenceTime referenceTime = optReferenceTime.isPresent() ? optReferenceTime.get() : ReferenceTime.now(); + List validCerts = new ArrayList<>(); + for (Certificate cert : certificates) { + try { + PGPPublicKeyRing publicKey = PGPainless.readKeyRing().publicKeyRing(cert.getInputStream()); + // No Certificate data + if (publicKey == null) { + throw new IOException("Certificate " + cert.getFingerprint() + " was null. No certificate data?"); + } + + KeyRingInfo info = new KeyRingInfo(publicKey, policy, referenceTime.getTimestamp()); + if (info.getValidUserIds().isEmpty()) { + LOGGER.warn("Certificate " + cert.getFingerprint() + " has no valid user-ids. Ignore."); + // Ignore invalid cert + // TODO: Allow user-id-less certificates? + } else { + validCerts.add(info); + } + } catch (IOException e) { + LOGGER.warn("Could not parse certificate " + cert.getFingerprint(), e); + } + } + + return fromValidCertificates( + validCerts, + referenceTime + ); + } + + /** + * Create a {@link Network} from a set of validated certificates. + * + * @param validatedCertificates set of validated certificates + * @param referenceTime reference time + * @return network + */ + public static Network fromValidCertificates( + Iterable validatedCertificates, + ReferenceTime referenceTime) { + + Map byFingerprint = new HashMap<>(); + Map> byKeyId = new HashMap<>(); + + Map certSynopsisMap = new HashMap<>(); + + for (KeyRingInfo cert : validatedCertificates) { + // noinspection Java8MapApi + if (byFingerprint.get(cert.getFingerprint()) == null) { + byFingerprint.put(cert.getFingerprint(), cert); + } + List byKeyIdEntry = byKeyId.get(cert.getKeyId()); + + // noinspection Java8MapApi + if (byKeyIdEntry == null) { + byKeyIdEntry = new ArrayList<>(); + byKeyId.put(cert.getKeyId(), byKeyIdEntry); + } + byKeyIdEntry.add(cert); + + certSynopsisMap.put(cert.getFingerprint(), + new CertSynopsis(cert.getFingerprint(), + cert.getExpirationDateForUse(KeyFlag.CERTIFY_OTHER), + revocationStateFromSignature(cert.getRevocationSelfSignature()), + new HashSet<>(cert.getValidUserIds()))); + } + + Map> edges = new HashMap<>(); + Map> reverseEdges = new HashMap<>(); + + return new Network(certSynopsisMap, edges, reverseEdges, referenceTime); + } + + + private static RevocationState revocationStateFromSignature(PGPSignature revocation) { + if (revocation == null) { + return RevocationState.notRevoked(); + } + + RevocationReason revocationReason = SignatureSubpacketsUtil.getRevocationReason(revocation); + if (revocationReason == null) { + return RevocationState.hardRevoked(); + } + + return RevocationAttributes.Reason.isHardRevocation(revocationReason.getRevocationReason()) ? + RevocationState.hardRevoked() : RevocationState.softRevoked(revocation.getCreationTime()); } @Override diff --git a/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrustCertificateStore.java b/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrustCertificateStore.java index e3a94295..914cf95c 100644 --- a/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrustCertificateStore.java +++ b/pgpainless-wot/src/main/java/org/pgpainless/wot/WebOfTrustCertificateStore.java @@ -6,6 +6,11 @@ package org.pgpainless.wot; import pgp.cert_d.PGPCertificateDirectory; import pgp.cert_d.subkey_lookup.SubkeyLookup; +import pgp.certificate_store.exception.BadDataException; + +import java.io.IOException; +import java.util.Iterator; +import pgp.certificate_store.certificate.Certificate; public class WebOfTrustCertificateStore extends PGPCertificateDirectory { @@ -13,4 +18,9 @@ public class WebOfTrustCertificateStore extends PGPCertificateDirectory { super(backend, subkeyLookup); } + public Iterator getAllItems() + throws BadDataException, IOException { + Iterator trustRootAndCerts = new PrefixedIterator<>(getTrustRootCertificate(), items()); + return trustRootAndCerts; + } } diff --git a/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java b/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java new file mode 100644 index 00000000..1abd5e49 --- /dev/null +++ b/pgpainless-wot/src/test/java/org/pgpainless/wot/WebOfTrustTest.java @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot; + +import org.junit.jupiter.api.Test; +import org.pgpainless.wot.testfixtures.TestCertificateStores; +import pgp.certificate_store.exception.BadDataException; + +import java.io.IOException; + +public class WebOfTrustTest { + + @Test + public void testWithCrossSignedCertificates() + throws BadDataException, IOException, InterruptedException { + WebOfTrustCertificateStore store = TestCertificateStores.disconnectedGraph(); + WebOfTrust wot = new WebOfTrust(store); + wot.initialize(); + + // TODO: Test stuff + } +} 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 new file mode 100644 index 00000000..062c3fee --- /dev/null +++ b/pgpainless-wot/src/testFixtures/java/org/pgpainless/wot/testfixtures/TestCertificateStores.java @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.wot.testfixtures; + +import org.opentest4j.TestAbortedException; +import org.pgpainless.certificate_store.KeyMaterialReader; +import org.pgpainless.wot.WebOfTrustCertificateStore; +import pgp.cert_d.PGPCertificateDirectory; +import pgp.cert_d.backend.InMemoryCertificateDirectoryBackend; +import pgp.cert_d.subkey_lookup.InMemorySubkeyLookup; +import pgp.cert_d.subkey_lookup.SubkeyLookup; +import pgp.certificate_store.certificate.KeyMaterial; +import pgp.certificate_store.certificate.KeyMaterialMerger; +import pgp.certificate_store.certificate.KeyMaterialReaderBackend; +import pgp.certificate_store.exception.BadDataException; + +import java.io.IOException; +import java.io.InputStream; + +public class TestCertificateStores { + + private static final KeyMaterialMerger merger = new KeyMaterialMerger() { + @Override + public KeyMaterial merge(KeyMaterial data, KeyMaterial existing) throws IOException { + return data; // Always use newer material + } + }; + + private static InputStream requireResource(String resourceName) { + InputStream inputStream = TestCertificateStores.class.getClassLoader().getResourceAsStream(resourceName); + if (inputStream == null) { + throw new TestAbortedException("Cannot read resource " + resourceName + ": InputStream is null."); + } + return inputStream; + } + + public static WebOfTrustCertificateStore disconnectedGraph() + throws BadDataException, IOException, InterruptedException { + SubkeyLookup subkeyLookup = new InMemorySubkeyLookup(); + KeyMaterialReaderBackend readerBackend = new KeyMaterialReader(); + PGPCertificateDirectory.Backend backend = new InMemoryCertificateDirectoryBackend(readerBackend); + WebOfTrustCertificateStore wotStore = new WebOfTrustCertificateStore(backend, subkeyLookup); + + 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); + + return wotStore; + } + + private static InputStream getTestVector(String testVectorName) { + return requireResource("test_vectors/" + testVectorName); + } +} diff --git a/wot-dijkstra/src/test/resources/test_vectors/README.md b/pgpainless-wot/src/testFixtures/resources/test_vectors/README.md similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/README.md rename to pgpainless-wot/src/testFixtures/resources/test_vectors/README.md diff --git a/wot-dijkstra/src/test/resources/test_vectors/cross_signed/barbankCaCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/barbankCaCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/cross_signed/barbankCaCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/barbankCaCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/cross_signed/barbankEmployeeCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/barbankEmployeeCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/cross_signed/barbankEmployeeCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/barbankEmployeeCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankAdminCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankAdminCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankAdminCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankAdminCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankCaCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankCaCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankCaCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankCaCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankEmployeeCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankEmployeeCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/cross_signed/foobankEmployeeCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/cross_signed/foobankEmployeeCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankCaCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankCaCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankCaCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankCaCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankCaKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankCaKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankCaKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankCaKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankEmployeeCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankEmployeeCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankEmployeeCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankEmployeeCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankEmployeeKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankEmployeeKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/barbankEmployeeKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/barbankEmployeeKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/fakeFoobankEmployeeCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/fakeFoobankEmployeeCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/fakeFoobankEmployeeCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/fakeFoobankEmployeeCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/fakeFoobankEmployeeKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/fakeFoobankEmployeeKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/fakeFoobankEmployeeKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/fakeFoobankEmployeeKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankAdminCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankAdminCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankAdminCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankAdminCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankAdminKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankAdminKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankAdminKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankAdminKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCaCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCaCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCaCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCaCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCaKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCaKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCaKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCaKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCustomerCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCustomerCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCustomerCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCustomerCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCustomerKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCustomerKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankCustomerKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankCustomerKey.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankEmployeeCert.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankEmployeeCert.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankEmployeeCert.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankEmployeeCert.asc diff --git a/wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankEmployeeKey.asc b/pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankEmployeeKey.asc similarity index 100% rename from wot-dijkstra/src/test/resources/test_vectors/freshly_generated/foobankEmployeeKey.asc rename to pgpainless-wot/src/testFixtures/resources/test_vectors/freshly_generated/foobankEmployeeKey.asc diff --git a/wot-dijkstra/src/main/java/org/pgpainless/wot/dijkstra/sq/Network.java b/wot-dijkstra/src/main/java/org/pgpainless/wot/dijkstra/sq/Network.java index 171431c9..8f4392d6 100644 --- a/wot-dijkstra/src/main/java/org/pgpainless/wot/dijkstra/sq/Network.java +++ b/wot-dijkstra/src/main/java/org/pgpainless/wot/dijkstra/sq/Network.java @@ -4,23 +4,12 @@ package org.pgpainless.wot.dijkstra.sq; -import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import javax.annotation.Nonnull; -import org.bouncycastle.bcpg.sig.RevocationReason; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.algorithm.RevocationState; import org.pgpainless.key.OpenPgpFingerprint; -import org.pgpainless.key.info.KeyRingInfo; -import org.pgpainless.key.util.RevocationAttributes; -import org.pgpainless.policy.Policy; -import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; public class Network { @@ -53,78 +42,6 @@ public class Network { referenceTime); } - /** - * Create a {@link Network} from a set of certificates. - * - * @param certificates set of certificates - * @param policy evaluation policy - * @param optReferenceTime reference time for evaluation - * @return network - */ - public static Network fromCertificates( - Iterable certificates, - Policy policy, - Optional optReferenceTime) { - ReferenceTime referenceTime = optReferenceTime.isPresent() ? optReferenceTime.get() : ReferenceTime.now(); - List validCerts = new ArrayList<>(); - for (PGPPublicKeyRing cert : certificates) { - KeyRingInfo info = new KeyRingInfo(cert, policy, referenceTime.getTimestamp()); - if (info.getValidUserIds().isEmpty()) { - // Ignore invalid cert - } else { - validCerts.add(info); - } - } - - return fromValidCertificates( - validCerts, - referenceTime - ); - } - - /** - * Create a {@link Network} from a set of validated certificates. - * - * @param validatedCertificates set of validated certificates - * @param referenceTime reference time - * @return network - */ - public static Network fromValidCertificates( - Iterable validatedCertificates, - ReferenceTime referenceTime) { - - Map byFingerprint = new HashMap<>(); - Map> byKeyId = new HashMap<>(); - - Map certSynopsisMap = new HashMap<>(); - - for (KeyRingInfo cert : validatedCertificates) { - // noinspection Java8MapApi - if (byFingerprint.get(cert.getFingerprint()) == null) { - byFingerprint.put(cert.getFingerprint(), cert); - } - List byKeyIdEntry = byKeyId.get(cert.getKeyId()); - - // noinspection Java8MapApi - if (byKeyIdEntry == null) { - byKeyIdEntry = new ArrayList<>(); - byKeyId.put(cert.getKeyId(), byKeyIdEntry); - } - byKeyIdEntry.add(cert); - - certSynopsisMap.put(cert.getFingerprint(), - new CertSynopsis(cert.getFingerprint(), - cert.getExpirationDateForUse(KeyFlag.CERTIFY_OTHER), - revocationStateFromSignature(cert.getRevocationSelfSignature()), - new HashSet<>(cert.getValidUserIds()))); - } - - Map> edges = new HashMap<>(); - Map> reverseEdges = new HashMap<>(); - - return new Network(certSynopsisMap, edges, reverseEdges, referenceTime); - } - public Map getNodes() { return new HashMap<>(nodes); } @@ -141,17 +58,4 @@ public class Network { return referenceTime; } - private static RevocationState revocationStateFromSignature(PGPSignature revocation) { - if (revocation == null) { - return RevocationState.notRevoked(); - } - - RevocationReason revocationReason = SignatureSubpacketsUtil.getRevocationReason(revocation); - if (revocationReason == null) { - return RevocationState.hardRevoked(); - } - - return RevocationAttributes.Reason.isHardRevocation(revocationReason.getRevocationReason()) ? - RevocationState.hardRevoked() : RevocationState.softRevoked(revocation.getCreationTime()); - } }