1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-16 17:32:06 +01:00

Remove pgpainless-core dependency from wot-dijkstra

This commit is contained in:
Paul Schaub 2023-06-29 20:18:01 +02:00
parent 98377b34f1
commit cdac41ffa9
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
9 changed files with 120 additions and 42 deletions

View file

@ -8,7 +8,6 @@ import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.algorithm.RevocationState
import org.pgpainless.exception.SignatureValidationException import org.pgpainless.exception.SignatureValidationException
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.info.KeyRingInfo import org.pgpainless.key.info.KeyRingInfo
@ -122,6 +121,11 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
RevocationState.softRevoked(revocation.creationTime) RevocationState.softRevoked(revocation.creationTime)
} }
@JvmStatic
private fun OpenPgpFingerprint.map(): Fingerprint {
return Fingerprint(toString())
}
/** /**
* Class for building the [Flow network][Network] from the given set of OpenPGP keys. * Class for building the [Flow network][Network] from the given set of OpenPGP keys.
* *
@ -133,19 +137,19 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
private val LOGGER = LoggerFactory.getLogger(NetworkBuilder::class.java) private val LOGGER = LoggerFactory.getLogger(NetworkBuilder::class.java)
// certificates keyed by fingerprint // certificates keyed by fingerprint
private val byFingerprint: MutableMap<OpenPgpFingerprint, KeyRingInfo> = HashMap() private val byFingerprint: MutableMap<Fingerprint, KeyRingInfo> = HashMap()
// certificates keyed by (sub-) key-id // certificates keyed by (sub-) key-id
private val byKeyId: MutableMap<Long, MutableList<KeyRingInfo>> = HashMap() private val byKeyId: MutableMap<Long, MutableList<KeyRingInfo>> = HashMap()
// certificate synopses keyed by fingerprint // certificate synopses keyed by fingerprint
private val certSynopsisMap: MutableMap<OpenPgpFingerprint, CertSynopsis> = HashMap() private val certSynopsisMap: MutableMap<Fingerprint, CertSynopsis> = HashMap()
// Issuer -> Targets, edges keyed by issuer // Issuer -> Targets, edges keyed by issuer
private val edges: MutableMap<OpenPgpFingerprint, MutableList<CertificationSet>> = HashMap() private val edges: MutableMap<Fingerprint, MutableList<CertificationSet>> = HashMap()
// Target -> Issuers, edges keyed by target // Target -> Issuers, edges keyed by target
private val reverseEdges: MutableMap<OpenPgpFingerprint, MutableList<CertificationSet>> = HashMap() private val reverseEdges: MutableMap<Fingerprint, MutableList<CertificationSet>> = HashMap()
init { init {
synopsizeCertificates(validatedCertificates) synopsizeCertificates(validatedCertificates)
@ -161,8 +165,9 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
private fun synopsize(cert: KeyRingInfo) { private fun synopsize(cert: KeyRingInfo) {
// index by fingerprint // index by fingerprint
if (!byFingerprint.containsKey(cert.fingerprint)) { val certFingerprint = cert.fingerprint.map()
byFingerprint[cert.fingerprint] = cert if (!byFingerprint.containsKey(certFingerprint)) {
byFingerprint[certFingerprint] = cert
} }
// index by key-ID // index by key-ID
@ -189,7 +194,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
// Some keys are malformed and have no KeyFlags // Some keys are malformed and have no KeyFlags
return return
} }
certSynopsisMap[cert.fingerprint] = CertSynopsis(cert.fingerprint, certSynopsisMap[certFingerprint] = CertSynopsis(certFingerprint,
expirationDate, expirationDate,
revocationStateFromSignature(cert.revocationSelfSignature), revocationStateFromSignature(cert.revocationSelfSignature),
userIds) userIds)
@ -205,7 +210,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
private fun findEdgesWithTarget(validatedTarget: KeyRingInfo) { private fun findEdgesWithTarget(validatedTarget: KeyRingInfo) {
val validatedTargetKeyRing = KeyRingUtils.publicKeys(validatedTarget.keys) val validatedTargetKeyRing = KeyRingUtils.publicKeys(validatedTarget.keys)
val targetFingerprint = OpenPgpFingerprint.of(validatedTargetKeyRing) val targetFingerprint = OpenPgpFingerprint.of(validatedTargetKeyRing).map()
val targetPrimaryKey = validatedTargetKeyRing.publicKey!! val targetPrimaryKey = validatedTargetKeyRing.publicKey!!
val target = certSynopsisMap[targetFingerprint]!! val target = certSynopsisMap[targetFingerprint]!!
@ -231,7 +236,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
?: return ?: return
for (candidate in issuerCandidates) { for (candidate in issuerCandidates) {
val issuerKeyRing = KeyRingUtils.publicKeys(candidate.keys) val issuerKeyRing = KeyRingUtils.publicKeys(candidate.keys)
val issuerFingerprint = OpenPgpFingerprint.of(issuerKeyRing) val issuerFingerprint = OpenPgpFingerprint.of(issuerKeyRing).map()
val issuerSigningKey = issuerKeyRing.getPublicKey(delegation.keyID) val issuerSigningKey = issuerKeyRing.getPublicKey(delegation.keyID)
val issuer = certSynopsisMap[issuerFingerprint] val issuer = certSynopsisMap[issuerFingerprint]
?: continue ?: continue
@ -257,7 +262,7 @@ class WebOfTrust(private val certificateStore: PGPCertificateStore) {
?: continue ?: continue
for (candidate in issuerCandidates) { for (candidate in issuerCandidates) {
val issuerKeyRing = KeyRingUtils.publicKeys(candidate.keys) val issuerKeyRing = KeyRingUtils.publicKeys(candidate.keys)
val issuerFingerprint = OpenPgpFingerprint.of(issuerKeyRing) val issuerFingerprint = OpenPgpFingerprint.of(issuerKeyRing).map()
val issuerSigningKey = issuerKeyRing.getPublicKey(certification.keyID) val issuerSigningKey = issuerKeyRing.getPublicKey(certification.keyID)
?: continue ?: continue
val issuer = certSynopsisMap[issuerFingerprint] val issuer = certSynopsisMap[issuerFingerprint]

View file

@ -12,9 +12,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.wot.dijkstra.sq.CertificationSet; import org.pgpainless.wot.dijkstra.sq.CertificationSet;
import org.pgpainless.wot.dijkstra.sq.Fingerprint;
import org.pgpainless.wot.dijkstra.sq.Network; import org.pgpainless.wot.dijkstra.sq.Network;
import org.pgpainless.wot.testfixtures.TestCertificateStores; import org.pgpainless.wot.testfixtures.TestCertificateStores;
import org.pgpainless.wot.testfixtures.WotTestVectors; import org.pgpainless.wot.testfixtures.WotTestVectors;
@ -23,16 +25,20 @@ import pgp.certificate_store.exception.BadDataException;
public class WebOfTrustTest { public class WebOfTrustTest {
OpenPgpFingerprint fooBankCa = OpenPgpFingerprint.of(WotTestVectors.getTestVectors().getFreshFooBankCaCert()); Fingerprint fooBankCa = fingerprintOf(WotTestVectors.getTestVectors().getFreshFooBankCaCert());
OpenPgpFingerprint fooBankEmployee = OpenPgpFingerprint.of(WotTestVectors.getTestVectors().getFreshFooBankEmployeeCert()); Fingerprint fooBankEmployee = fingerprintOf(WotTestVectors.getTestVectors().getFreshFooBankEmployeeCert());
OpenPgpFingerprint fooBankAdmin = OpenPgpFingerprint.of(WotTestVectors.getTestVectors().getFreshFooBankAdminCert()); Fingerprint fooBankAdmin = fingerprintOf(WotTestVectors.getTestVectors().getFreshFooBankAdminCert());
OpenPgpFingerprint barBankCa = OpenPgpFingerprint.of(WotTestVectors.getTestVectors().getFreshBarBankCaCert()); Fingerprint barBankCa = fingerprintOf(WotTestVectors.getTestVectors().getFreshBarBankCaCert());
OpenPgpFingerprint barBankEmployee = OpenPgpFingerprint.of(WotTestVectors.getTestVectors().getFreshBarBankEmployeeCert()); Fingerprint barBankEmployee = fingerprintOf(WotTestVectors.getTestVectors().getFreshBarBankEmployeeCert());
public WebOfTrustTest() throws IOException { public WebOfTrustTest() throws IOException {
} }
private static Fingerprint fingerprintOf(PGPPublicKeyRing cert) {
return new Fingerprint(OpenPgpFingerprint.of(cert).toString());
}
@Test @Test
public void testWithTwoNodesAndOneDelegation() throws BadDataException, IOException, InterruptedException { public void testWithTwoNodesAndOneDelegation() throws BadDataException, IOException, InterruptedException {
PGPCertificateDirectory certD = TestCertificateStores.oneDelegationGraph(); PGPCertificateDirectory certD = TestCertificateStores.oneDelegationGraph();
@ -87,30 +93,30 @@ public class WebOfTrustTest {
// CHECKSTYLE:ON // CHECKSTYLE:ON
} }
private void assertHasIssuerAndTarget(CertificationSet certifications, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private void assertHasIssuerAndTarget(CertificationSet certifications, Fingerprint issuer, Fingerprint target) {
assertEquals(issuer, certifications.getIssuer().getFingerprint()); assertEquals(issuer, certifications.getIssuer().getFingerprint());
assertEquals(target, certifications.getTarget().getFingerprint()); assertEquals(target, certifications.getTarget().getFingerprint());
} }
private void assertHasEdge(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private void assertHasEdge(Network network, Fingerprint issuer, Fingerprint target) {
assertNotNull(getEdgeFromTo(network, issuer, target), "Expected edge from " + issuer + " to " + target + " but got none."); assertNotNull(getEdgeFromTo(network, issuer, target), "Expected edge from " + issuer + " to " + target + " but got none.");
} }
private void assertHasReverseEdge(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private void assertHasReverseEdge(Network network, Fingerprint issuer, Fingerprint target) {
assertNotNull(getReverseEdgeFromTo(network, issuer, target), "Expected reverse edge to " + target + " from " + issuer + " but got none."); assertNotNull(getReverseEdgeFromTo(network, issuer, target), "Expected reverse edge to " + target + " from " + issuer + " but got none.");
} }
private void assertHasNoEdge(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private void assertHasNoEdge(Network network, Fingerprint issuer, Fingerprint target) {
CertificationSet edge = getEdgeFromTo(network, issuer, target); CertificationSet edge = getEdgeFromTo(network, issuer, target);
assertNull(edge, "Expected no edge from " + issuer + " to " + target + " but got " + edge); assertNull(edge, "Expected no edge from " + issuer + " to " + target + " but got " + edge);
} }
private void assertHasNoReverseEdge(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private void assertHasNoReverseEdge(Network network, Fingerprint issuer, Fingerprint target) {
CertificationSet reverseEdge = getReverseEdgeFromTo(network, issuer, target); CertificationSet reverseEdge = getReverseEdgeFromTo(network, issuer, target);
assertNull(reverseEdge, "Expected no reverse edge on " + target + " from " + issuer + " but got " + reverseEdge); assertNull(reverseEdge, "Expected no reverse edge on " + target + " from " + issuer + " but got " + reverseEdge);
} }
private CertificationSet getEdgeFromTo(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private CertificationSet getEdgeFromTo(Network network, Fingerprint issuer, Fingerprint target) {
List<CertificationSet> edges = network.getEdges().get(issuer); List<CertificationSet> edges = network.getEdges().get(issuer);
if (edges == null) { if (edges == null) {
return null; return null;
@ -124,7 +130,7 @@ public class WebOfTrustTest {
return null; return null;
} }
private CertificationSet getReverseEdgeFromTo(Network network, OpenPgpFingerprint issuer, OpenPgpFingerprint target) { private CertificationSet getReverseEdgeFromTo(Network network, Fingerprint issuer, Fingerprint target) {
List<CertificationSet> revEdges = network.getReverseEdges().get(target); List<CertificationSet> revEdges = network.getReverseEdges().get(target);
if (revEdges == null) { if (revEdges == null) {
return null; return null;

View file

@ -34,9 +34,6 @@ dependencies {
// @Nullable, @Nonnull annotations // @Nullable, @Nonnull annotations
implementation "com.google.code.findbugs:jsr305:3.0.2" implementation "com.google.code.findbugs:jsr305:3.0.2"
// OpenPgpFingerprint, RevocationState
implementation(project(":pgpainless-core"))
} }
test { test {

View file

@ -4,20 +4,18 @@
package org.pgpainless.wot.dijkstra.sq package org.pgpainless.wot.dijkstra.sq
import org.pgpainless.algorithm.RevocationState
import org.pgpainless.key.OpenPgpFingerprint
import java.util.* import java.util.*
/** /**
* A [CertSynopsis] is a proxy object containing information about a certificate. * A [CertSynopsis] is a proxy object containing information about a certificate.
* *
* @param fingerprint [OpenPgpFingerprint] of the certificate * @param fingerprint [Fingerprint] of the certificate
* @param expirationTime optional expiration time of the certificate * @param expirationTime optional expiration time of the certificate
* @param revocationState [RevocationState] denoting whether the certificate is revoked or not * @param revocationState [RevocationState] denoting whether the certificate is revoked or not
* @param userIds [Map] of user-ids on the certificate, along with their revocation states * @param userIds [Map] of user-ids on the certificate, along with their revocation states
*/ */
data class CertSynopsis( data class CertSynopsis(
val fingerprint: OpenPgpFingerprint, val fingerprint: Fingerprint,
val expirationTime: Date?, val expirationTime: Date?,
val revocationState: RevocationState, val revocationState: RevocationState,
val userIds : Map<String, RevocationState>) { val userIds : Map<String, RevocationState>) {

View file

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra.sq
class Fingerprint(fingerprint: String) {
val fingerprint: String
init {
this.fingerprint = fingerprint.uppercase()
}
override fun equals(other: Any?): Boolean {
if (other == null) {
return false
}
return if (other is Fingerprint) {
toString() == other.toString()
} else {
false
}
}
override fun hashCode(): Int {
return toString().hashCode()
}
override fun toString(): String {
return fingerprint.uppercase()
}
}

View file

@ -4,23 +4,21 @@
package org.pgpainless.wot.dijkstra.sq package org.pgpainless.wot.dijkstra.sq
import org.pgpainless.key.OpenPgpFingerprint
/** /**
* A network consists of nodes, and edges between them. * A network consists of nodes, and edges between them.
* For the Web of Trust, nodes consist of [CertSynopses][CertSynopsis], while the edges between the nodes are * For the Web of Trust, nodes consist of [CertSynopses][CertSynopsis], while the edges between the nodes are
* [CertificationSets][CertificationSet]. * [CertificationSets][CertificationSet].
* *
* @constructor creates a new network * @constructor creates a new network
* @param nodes contains a [Map] of [CertSynopsis] keyed by their [OpenPgpFingerprint] * @param nodes contains a [Map] of [CertSynopsis] keyed by their [Fingerprint]
* @param edges [Map] keyed by the [fingerprint][OpenPgpFingerprint] of an issuer, whose values are [Lists][List] containing all edges originating from the issuer. * @param edges [Map] keyed by the [fingerprint][Fingerprint] of an issuer, whose values are [Lists][List] containing all edges originating from the issuer.
* @param reverseEdges [Map] keyed by the [fingerprint][OpenPgpFingerprint] of a target, whose values are [Lists][List] containing all edges pointing to the target * @param reverseEdges [Map] keyed by the [fingerprint][Fingerprint] of a target, whose values are [Lists][List] containing all edges pointing to the target
* @param referenceTime reference time at which the [Network] was built * @param referenceTime reference time at which the [Network] was built
*/ */
class Network( class Network(
val nodes: Map<OpenPgpFingerprint, CertSynopsis>, val nodes: Map<Fingerprint, CertSynopsis>,
val edges: Map<OpenPgpFingerprint, List<CertificationSet>>, val edges: Map<Fingerprint, List<CertificationSet>>,
val reverseEdges: Map<OpenPgpFingerprint, List<CertificationSet>>, val reverseEdges: Map<Fingerprint, List<CertificationSet>>,
val referenceTime: ReferenceTime) { val referenceTime: ReferenceTime) {
companion object { companion object {

View file

@ -15,9 +15,9 @@ import kotlin.math.min
* @param residualDepth residual depth that is decreased each time another edge is appended * @param residualDepth residual depth that is decreased each time another edge is appended
*/ */
class Path( class Path(
val root: CertSynopsis, private val root: CertSynopsis,
val edges: MutableList<Certification>, private val edges: MutableList<Certification>,
var residualDepth: Depth private var residualDepth: Depth
) { ) {
/** /**

View file

@ -9,7 +9,7 @@ package org.pgpainless.wot.dijkstra.sq
* *
* @param paths list of paths * @param paths list of paths
*/ */
class Paths(val paths: MutableList<Item>) { class Paths(private val paths: MutableList<Item>) {
/** /**
* Empty collection of paths. * Empty collection of paths.

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.wot.dijkstra.sq
import java.util.*
/**
* Revocation State of
*/
class RevocationState private constructor(val type: Type, val timestamp: Date?) {
enum class Type {
Soft,
Hard,
None
}
companion object {
@JvmStatic
fun notRevoked(): RevocationState = RevocationState(Type.None, null)
@JvmStatic
fun softRevoked(timestamp: Date): RevocationState = RevocationState(Type.Soft, timestamp)
@JvmStatic
fun hardRevoked(): RevocationState = RevocationState(Type.Hard, null)
}
fun isHardRevocation(): Boolean = type == Type.Hard
fun isSoftRevocation(): Boolean = type == Type.Soft
fun isNotRevoked(): Boolean = type == Type.None
fun isEffective(referenceTime: ReferenceTime): Boolean {
return isHardRevocation() ||
(isSoftRevocation() && referenceTime.timestamp.after(timestamp))
}
}