mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-25 04:17:59 +01:00
Checkout wot-dijkstra and pgpainless-wot from wot branch
This commit is contained in:
parent
90626a8a76
commit
2a858baee1
51 changed files with 2580 additions and 0 deletions
30
pgpainless-wot/build.gradle
Normal file
30
pgpainless-wot/build.gradle
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'org.pgpainless'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||||
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||||
|
|
||||||
|
implementation(project(":pgpainless-core"))
|
||||||
|
|
||||||
|
// Certificate store
|
||||||
|
api "org.pgpainless:pgp-certificate-store:$certDJavaVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.wot;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
|
||||||
|
public interface CertificateAuthority {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <pre>true</pre>, if the given binding (certificate and user-id) is correct.
|
||||||
|
* Correct means, that the binding is trustworthy.
|
||||||
|
*
|
||||||
|
* @param certificate OpenPGP certificate
|
||||||
|
* @param userId user-id
|
||||||
|
* @return binding correctness
|
||||||
|
*/
|
||||||
|
boolean isAuthorized(PGPPublicKeyRing certificate, String userId);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.pgpainless.wot;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import pgp.certificate_store.Certificate;
|
||||||
|
import pgp.certificate_store.exception.BadDataException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class WebOfTrust implements CertificateAuthority {
|
||||||
|
|
||||||
|
private final WebOfTrustCertificateStore certificateStore;
|
||||||
|
|
||||||
|
public WebOfTrust(WebOfTrustCertificateStore certificateStore) {
|
||||||
|
this.certificateStore = certificateStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the heavy lifting of calculating the web of trust.
|
||||||
|
*/
|
||||||
|
public void initialize() throws BadDataException, IOException {
|
||||||
|
Certificate trustRoot = certificateStore.getTrustRoot();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAuthorized(PGPPublicKeyRing certificate, String userId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.pgpainless.wot;
|
||||||
|
|
||||||
|
import pgp.certificate_store.Certificate;
|
||||||
|
import pgp.certificate_store.CertificateDirectory;
|
||||||
|
import pgp.certificate_store.MergeCallback;
|
||||||
|
import pgp.certificate_store.exception.BadDataException;
|
||||||
|
import pgp.certificate_store.exception.BadNameException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class WebOfTrustCertificateStore implements CertificateDirectory {
|
||||||
|
|
||||||
|
private final CertificateDirectory certificateDirectory;
|
||||||
|
|
||||||
|
public WebOfTrustCertificateStore(CertificateDirectory certificateDirectory) {
|
||||||
|
this.certificateDirectory = certificateDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Certificate getTrustRoot() throws BadDataException, IOException {
|
||||||
|
try {
|
||||||
|
return getCertificate("trust-root");
|
||||||
|
} catch (BadNameException e) {
|
||||||
|
throw new AssertionError("The underlying certificate directory MUST support getting a trust-root certificate.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate getCertificate(String identifier)
|
||||||
|
throws IOException, BadNameException, BadDataException {
|
||||||
|
return certificateDirectory.getCertificate(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate getCertificateIfChanged(String identifier, String tag)
|
||||||
|
throws IOException, BadNameException, BadDataException {
|
||||||
|
return certificateDirectory.getCertificateIfChanged(identifier, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate insertCertificate(InputStream data, MergeCallback merge)
|
||||||
|
throws IOException, InterruptedException, BadDataException {
|
||||||
|
return certificateDirectory.insertCertificate(data, merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate tryInsertCertificate(InputStream data, MergeCallback merge)
|
||||||
|
throws IOException, BadDataException {
|
||||||
|
return certificateDirectory.tryInsertCertificate(data, merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate insertCertificateBySpecialName(String specialName, InputStream data, MergeCallback merge)
|
||||||
|
throws IOException, InterruptedException, BadDataException, BadNameException {
|
||||||
|
return certificateDirectory.insertCertificateBySpecialName(specialName, data, merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate tryInsertCertificateBySpecialName(String specialName, InputStream data, MergeCallback merge)
|
||||||
|
throws IOException, BadDataException, BadNameException {
|
||||||
|
return certificateDirectory.tryInsertCertificateBySpecialName(specialName, data, merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Certificate> getCertificates() {
|
||||||
|
return certificateDirectory.getCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<String> getFingerprints() {
|
||||||
|
return certificateDirectory.getFingerprints();
|
||||||
|
}
|
||||||
|
}
|
19
wot-dijkstra/QUESTIONS.md
Normal file
19
wot-dijkstra/QUESTIONS.md
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Questions
|
||||||
|
|
||||||
|
## Graph of Certificates or Graph of Subkeys?
|
||||||
|
|
||||||
|
## Persistable Graph or Dynamic Recalculation?
|
||||||
|
|
||||||
|
https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
|
||||||
|
Dijkstra: Outgoing edges "live" in origin, WoT: Incoming edges "live" in target
|
||||||
|
|
||||||
|
When processing incoming edges on certificate (node): origin of incoming nodes (signing key) might not be known -> cannot verify.
|
||||||
|
|
||||||
|
multi-step process:
|
||||||
|
Firstly create intermediate graph with unverified edges, invert edge such that origin owns edges to targets
|
||||||
|
Secondly for edges where origin and target exist, verify signatures
|
||||||
|
|
||||||
|
What information from signatures to cache? Creation date, expiration? Regex, depth, amount!
|
||||||
|
|
||||||
|
What are then nodes? Certs? Bindings?
|
||||||
|
|
30
wot-dijkstra/build.gradle
Normal file
30
wot-dijkstra/build.gradle
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'java-library'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'org.pgpainless'
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||||
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||||
|
|
||||||
|
// @Nullable, @Nonnull annotations
|
||||||
|
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||||
|
|
||||||
|
implementation(project(":pgpainless-core"))
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
public class Cost {
|
||||||
|
|
||||||
|
public static class SimpleCost extends Cost {
|
||||||
|
|
||||||
|
private final double weight;
|
||||||
|
|
||||||
|
public SimpleCost(double weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Double.toString(getWeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof SimpleCost)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SimpleCost other = (SimpleCost) obj;
|
||||||
|
return getWeight() == other.getWeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return (int) getWeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TrustCost extends Cost {
|
||||||
|
|
||||||
|
private final int depth;
|
||||||
|
private final int amount;
|
||||||
|
private final String regex;
|
||||||
|
|
||||||
|
public TrustCost(int depth, int amount, String regex) {
|
||||||
|
this.depth = depth;
|
||||||
|
this.amount = amount;
|
||||||
|
this.regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDepth() {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegex() {
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "d=" + getDepth() + ",a=" + getAmount() + (regex == null ? "" : ",r=" + getRegex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public abstract class Dijkstra<T, E extends Edge<T, C>, C extends Cost> {
|
||||||
|
@Nullable
|
||||||
|
public abstract Path<T, Node<T>, C, E> findPath(Node<T> to);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
public abstract class Edge<T, C extends Cost> implements Comparable<C> {
|
||||||
|
|
||||||
|
protected final Node<T> from;
|
||||||
|
protected final Node<T> to;
|
||||||
|
protected final C cost;
|
||||||
|
|
||||||
|
public Edge(Node<T> from, Node<T> to, C cost) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node<T> getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node<T> getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public C getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class Graph<T, N extends Node<T>, E extends Edge<T, C>, C extends Cost> {
|
||||||
|
|
||||||
|
private final Collection<N> nodes;
|
||||||
|
private final Collection<E> edges;
|
||||||
|
|
||||||
|
public Graph(Collection<N> nodes, Collection<E> edges) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
this.edges = edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<N> getNodes() {
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<E> getEdges() {
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
public class Node<T> {
|
||||||
|
|
||||||
|
private final T item;
|
||||||
|
|
||||||
|
public Node(T item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T getItem() {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(" + getItem().toString() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Node)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node<?> other = (Node<?>) obj;
|
||||||
|
return getItem().equals(other.getItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getItem().hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Path<T, N extends Node<T>, C extends Cost, E extends Edge<T, C>> {
|
||||||
|
|
||||||
|
private final N from;
|
||||||
|
private final N to;
|
||||||
|
|
||||||
|
private final List<E> edges;
|
||||||
|
|
||||||
|
public Path(N from, N to, List<E> edges) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.edges = edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node<T> getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node<T> getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<E> getEdges() {
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(getEdges().toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Path<?, ?, ?, ?> other = (Path<?, ?, ?, ?>) obj;
|
||||||
|
return getFrom().equals(other.getFrom())
|
||||||
|
&& getTo().equals(other.getTo())
|
||||||
|
&& getEdges().equals(other.getEdges());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getFrom().hashCode()
|
||||||
|
+ 13 * getTo().hashCode()
|
||||||
|
+ 31 * getEdges().hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ShortestPathDijkstra<T> extends Dijkstra<T, SimpleEdge<T>, Cost.SimpleCost> {
|
||||||
|
|
||||||
|
private final Node<T> root;
|
||||||
|
private final Graph<T, Node<T>, SimpleEdge<T>, Cost.SimpleCost> graph;
|
||||||
|
private final List<Node<T>> queue = new ArrayList<>();
|
||||||
|
|
||||||
|
private final Map<Node<T>, Double> distances = new HashMap<>();
|
||||||
|
private final Map<Node<T>, SimpleEdge<T>> precursors = new HashMap<>();
|
||||||
|
|
||||||
|
public ShortestPathDijkstra(Graph<T, Node<T>, SimpleEdge<T>, Cost.SimpleCost> graph, Node<T> root) {
|
||||||
|
// INITIALIZE
|
||||||
|
this.graph = graph;
|
||||||
|
this.root = root;
|
||||||
|
for (Node<T> node : graph.getNodes()) {
|
||||||
|
// dist[v] := infinity
|
||||||
|
distances.put(node, Double.MAX_VALUE);
|
||||||
|
|
||||||
|
// precursor[v] := null
|
||||||
|
precursors.put(node, null);
|
||||||
|
}
|
||||||
|
// dist[root] := 0
|
||||||
|
distances.put(root, 0d);
|
||||||
|
|
||||||
|
// Q := set of all nodes in graph
|
||||||
|
queue.addAll(graph.getNodes());
|
||||||
|
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
Node<T> closest = closest();
|
||||||
|
queue.remove(closest);
|
||||||
|
|
||||||
|
for (SimpleEdge<T> edge : graph.getEdges()) {
|
||||||
|
if (!closest.equals(edge.getFrom())) {
|
||||||
|
// Skip non-neighbors
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue.contains(edge.getTo())) {
|
||||||
|
distUpdate(closest, edge.getTo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node<T> closest() {
|
||||||
|
Double minDist = Double.MAX_VALUE;
|
||||||
|
int index = 0;
|
||||||
|
Double dist;
|
||||||
|
for (int i = 0; i < queue.size(); i++) {
|
||||||
|
if ((dist = distances.get(queue.get(i))) <= minDist) {
|
||||||
|
index = i;
|
||||||
|
minDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return queue.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void distUpdate(Node<T> from, Node<T> to) {
|
||||||
|
SimpleEdge<T> edge = getEdgeBetween(from, to);
|
||||||
|
if (edge == null) {
|
||||||
|
// No direct path
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double distance = distances.get(from) + edge.getCost().getWeight();
|
||||||
|
if (distance < distances.get(to)) {
|
||||||
|
distances.put(to, distance);
|
||||||
|
precursors.put(to, edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SimpleEdge<T> getEdgeBetween(Node<T> from, Node<T> to) {
|
||||||
|
for (SimpleEdge<T> edge : graph.getEdges()) {
|
||||||
|
if (!from.equals(edge.getFrom())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to.equals(edge.getTo())) {
|
||||||
|
return edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Path<T, Node<T>, Cost.SimpleCost, SimpleEdge<T>> findPath(Node<T> to) {
|
||||||
|
List<SimpleEdge<T>> pathEdges = new ArrayList<>();
|
||||||
|
Node<T> waypoint = to;
|
||||||
|
|
||||||
|
SimpleEdge<T> edge;
|
||||||
|
while ((edge = precursors.get(waypoint)) != null) {
|
||||||
|
waypoint = precursors.get(waypoint).getFrom();
|
||||||
|
pathEdges.add(0, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathEdges.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Path<>(root, to, pathEdges);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
public class SimpleEdge<T> extends Edge<T, Cost.SimpleCost> {
|
||||||
|
|
||||||
|
public SimpleEdge(Node<T> from, Node<T> to, Double edgeWeight) {
|
||||||
|
super(from, to, new Cost.SimpleCost(edgeWeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getFrom().toString() + " " + getCost() + "> " + getTo().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Cost.SimpleCost o) {
|
||||||
|
return Double.compare(getCost().getWeight(), o.getWeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof SimpleEdge)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SimpleEdge<?> other = (SimpleEdge<?>) obj;
|
||||||
|
|
||||||
|
return getFrom().equals(other.getFrom())
|
||||||
|
&& getTo().equals(other.getTo())
|
||||||
|
&& getCost().equals(other.getCost());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return getFrom().hashCode() + 13 * getTo().hashCode() + 17 * getCost().hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class TrustEdge<T> extends Edge<T, Cost.TrustCost> {
|
||||||
|
|
||||||
|
public TrustEdge(Node<T> from, Node<T> to, Cost.TrustCost cost) {
|
||||||
|
super(from, to, cost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@Nonnull Cost.TrustCost o) {
|
||||||
|
int depthCompare = Double.compare(cost.getDepth(), o.getDepth());
|
||||||
|
if (depthCompare != 0) {
|
||||||
|
return - depthCompare;
|
||||||
|
}
|
||||||
|
return Double.compare(cost.getAmount(), o.getAmount());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class WotDijkstra<T> extends Dijkstra<T, TrustEdge<T>, Cost.TrustCost> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Path<T, Node<T>, Cost.TrustCost, TrustEdge<T>> findPath(Node<T> to) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import org.pgpainless.algorithm.RevocationState;
|
||||||
|
import org.pgpainless.key.OpenPgpFingerprint;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class CertSynopsis {
|
||||||
|
|
||||||
|
private final OpenPgpFingerprint fingerprint;
|
||||||
|
private final Date expirationTime;
|
||||||
|
private final RevocationState revocationState;
|
||||||
|
private final Set<String> userIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link CertSynopsis}.
|
||||||
|
*
|
||||||
|
* @param fingerprint fingerprint of the certificate
|
||||||
|
* @param expirationTime expiration time
|
||||||
|
* @param revocationState revocation state of the certificate
|
||||||
|
* @param userIds set of user-ids
|
||||||
|
*/
|
||||||
|
public CertSynopsis(OpenPgpFingerprint fingerprint,
|
||||||
|
Date expirationTime,
|
||||||
|
RevocationState revocationState,
|
||||||
|
Set<String> userIds) {
|
||||||
|
this.fingerprint = fingerprint;
|
||||||
|
this.expirationTime = expirationTime;
|
||||||
|
this.revocationState = revocationState;
|
||||||
|
this.userIds = userIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the fingerprint of the certificate.
|
||||||
|
*
|
||||||
|
* @return fingerprint
|
||||||
|
*/
|
||||||
|
public OpenPgpFingerprint getFingerprint() {
|
||||||
|
return fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the certificates expiration time.
|
||||||
|
*
|
||||||
|
* @return expiration time
|
||||||
|
*/
|
||||||
|
public Date getExpirationTime() {
|
||||||
|
return expirationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the revocation status of the certificate.
|
||||||
|
*
|
||||||
|
* @return revocation state
|
||||||
|
*/
|
||||||
|
public RevocationState getRevocationState() {
|
||||||
|
return revocationState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link Set} containing all user-ids of the certificate.
|
||||||
|
*
|
||||||
|
* @return user-ids
|
||||||
|
*/
|
||||||
|
public Set<String> userIds() {
|
||||||
|
return new HashSet<>(userIds);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.Exportable;
|
||||||
|
import org.bouncycastle.bcpg.sig.RegularExpression;
|
||||||
|
import org.bouncycastle.bcpg.sig.TrustSignature;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||||
|
|
||||||
|
public class Certification {
|
||||||
|
|
||||||
|
private final CertSynopsis issuer;
|
||||||
|
private final CertSynopsis target;
|
||||||
|
private final Optional<String> userId;
|
||||||
|
|
||||||
|
private final Date creationTime;
|
||||||
|
private final Optional<Date> expirationTime;
|
||||||
|
private final boolean exportable;
|
||||||
|
private final int trustAmount;
|
||||||
|
private final Depth trustDepth;
|
||||||
|
private final RegexSet regex;
|
||||||
|
|
||||||
|
public Certification(
|
||||||
|
CertSynopsis issuer,
|
||||||
|
CertSynopsis target,
|
||||||
|
Optional<String> userId,
|
||||||
|
Date creationTime,
|
||||||
|
Optional<Date> expirationTime,
|
||||||
|
boolean exportable,
|
||||||
|
int trustAmount,
|
||||||
|
Depth trustDepth,
|
||||||
|
RegexSet regex) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
this.target = target;
|
||||||
|
this.userId = userId;
|
||||||
|
this.creationTime = creationTime;
|
||||||
|
this.expirationTime = expirationTime;
|
||||||
|
this.exportable = exportable;
|
||||||
|
this.trustAmount= trustAmount;
|
||||||
|
this.trustDepth = trustDepth;
|
||||||
|
this.regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Certification(CertSynopsis issuer,
|
||||||
|
Optional<String> targetUserId,
|
||||||
|
CertSynopsis target,
|
||||||
|
Date creationTime) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
this.target = target;
|
||||||
|
this.userId = targetUserId;
|
||||||
|
this.creationTime = creationTime;
|
||||||
|
|
||||||
|
this.expirationTime = Optional.empty();
|
||||||
|
this.exportable = true;
|
||||||
|
this.trustDepth = Depth.limited(0);
|
||||||
|
this.trustAmount = 120;
|
||||||
|
this.regex = RegexSet.wildcard();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Certification(CertSynopsis issuer,
|
||||||
|
Optional<String> targetUserId,
|
||||||
|
CertSynopsis target,
|
||||||
|
PGPSignature signature) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
this.target = target;
|
||||||
|
this.userId = targetUserId;
|
||||||
|
this.creationTime = SignatureSubpacketsUtil.getSignatureCreationTime(signature).getTime();
|
||||||
|
this.expirationTime = Optional.maybe(SignatureSubpacketsUtil.getSignatureExpirationTimeAsDate(signature));
|
||||||
|
Exportable exportablePacket = SignatureSubpacketsUtil.getExportableCertification(signature);
|
||||||
|
this.exportable = exportablePacket == null || exportablePacket.isExportable();
|
||||||
|
TrustSignature trustSignaturePacket = SignatureSubpacketsUtil.getTrustSignature(signature);
|
||||||
|
if (trustSignaturePacket == null) {
|
||||||
|
this.trustDepth = Depth.limited(0);
|
||||||
|
this.trustAmount = 120;
|
||||||
|
} else {
|
||||||
|
this.trustDepth = Depth.auto(trustSignaturePacket.getDepth());
|
||||||
|
this.trustAmount = trustSignaturePacket.getTrustAmount();
|
||||||
|
}
|
||||||
|
List<RegularExpression> regularExpressionList = SignatureSubpacketsUtil.getRegularExpressions(signature);
|
||||||
|
this.regex = RegexSet.fromList(regularExpressionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the issuer of the certification.
|
||||||
|
*
|
||||||
|
* @return issuer
|
||||||
|
*/
|
||||||
|
public CertSynopsis getIssuer() {
|
||||||
|
return issuer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the target of the certification.
|
||||||
|
*
|
||||||
|
* @return target
|
||||||
|
*/
|
||||||
|
public CertSynopsis getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the target user-id.
|
||||||
|
*
|
||||||
|
* @return user-id
|
||||||
|
*/
|
||||||
|
public Optional<String> getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the creation time of the certification,
|
||||||
|
*
|
||||||
|
* @return creation time
|
||||||
|
*/
|
||||||
|
public Date getCreationTime() {
|
||||||
|
return creationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the (optional) expiration time of the certification.
|
||||||
|
*
|
||||||
|
* @return optional expiration time
|
||||||
|
*/
|
||||||
|
public Optional<Date> getExpirationTime() {
|
||||||
|
return expirationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the certification is marked as exportable.
|
||||||
|
*
|
||||||
|
* @return exportable
|
||||||
|
*/
|
||||||
|
public boolean isExportable() {
|
||||||
|
return exportable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trust amount of the certification.
|
||||||
|
*
|
||||||
|
* @return trust amount
|
||||||
|
*/
|
||||||
|
public int getTrustAmount() {
|
||||||
|
return trustAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the trust depth of the certification.
|
||||||
|
*
|
||||||
|
* @return trust depth
|
||||||
|
*/
|
||||||
|
public Depth getTrustDepth() {
|
||||||
|
return trustDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the set of regular expressions.
|
||||||
|
*
|
||||||
|
* @return regex set
|
||||||
|
*/
|
||||||
|
public RegexSet getRegexes() {
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class CertificationSet {
|
||||||
|
|
||||||
|
private final CertSynopsis issuer;
|
||||||
|
private final CertSynopsis target;
|
||||||
|
|
||||||
|
private final Map<Optional<String>, List<Certification>> certifications;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty {@link CertificationSet}.
|
||||||
|
*
|
||||||
|
* @param issuer issuer
|
||||||
|
* @param target target
|
||||||
|
* @return empty set
|
||||||
|
*/
|
||||||
|
public static CertificationSet empty(CertSynopsis issuer, CertSynopsis target) {
|
||||||
|
return new CertificationSet(issuer, target, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link CertificationSet} from a single certification.
|
||||||
|
*
|
||||||
|
* @param issuer issuer
|
||||||
|
* @param target target
|
||||||
|
* @param userId user-id
|
||||||
|
* @param certification certification
|
||||||
|
* @return singleton set
|
||||||
|
*/
|
||||||
|
public static CertificationSet fromCertification(
|
||||||
|
CertSynopsis issuer,
|
||||||
|
CertSynopsis target,
|
||||||
|
Optional<String> userId,
|
||||||
|
PGPSignature certification) {
|
||||||
|
|
||||||
|
Map<Optional<String>, List<Certification>> certificationMap = new HashMap<>();
|
||||||
|
List<Certification> certificationList = new ArrayList<>();
|
||||||
|
certificationList.add(new Certification(issuer, userId, target, certification));
|
||||||
|
certificationMap.put(userId, certificationList);
|
||||||
|
|
||||||
|
return new CertificationSet(issuer, target, certificationMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CertificationSet(CertSynopsis issuer,
|
||||||
|
CertSynopsis target,
|
||||||
|
Map<Optional<String>, List<Certification>> certifications) {
|
||||||
|
this.issuer = issuer;
|
||||||
|
this.target = target;
|
||||||
|
this.certifications = new HashMap<>(certifications);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge this {@link CertificationSet} with another instance.
|
||||||
|
* After the operation, this will contain {@link Certification Certifications} from both sets.
|
||||||
|
*
|
||||||
|
* @param other other {@link CertificationSet}
|
||||||
|
*/
|
||||||
|
public void merge(@Nonnull CertificationSet other) {
|
||||||
|
if (other == this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!issuer.getFingerprint().equals(other.issuer.getFingerprint())) {
|
||||||
|
throw new IllegalArgumentException("Issuer fingerprint mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target.getFingerprint().equals(other.target.getFingerprint())) {
|
||||||
|
throw new IllegalArgumentException("Target fingerprint mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Optional<String>, List<Certification>> entry : other.certifications.entrySet()) {
|
||||||
|
for (Certification certification : entry.getValue()) {
|
||||||
|
add(certification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link Certification} into this {@link CertificationSet}.
|
||||||
|
*
|
||||||
|
* @param certification certification
|
||||||
|
*/
|
||||||
|
public void add(@Nonnull Certification certification) {
|
||||||
|
if (!issuer.getFingerprint().equals(certification.getIssuer().getFingerprint())) {
|
||||||
|
throw new IllegalArgumentException("Issuer fingerprint mismatch.");
|
||||||
|
}
|
||||||
|
if (!target.getFingerprint().equals(certification.getTarget().getFingerprint())) {
|
||||||
|
throw new IllegalArgumentException("Target fingerprint mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Certification> certificationsForUserId = certifications.get(certification.getUserId());
|
||||||
|
//noinspection Java8MapApi
|
||||||
|
if (certificationsForUserId == null) {
|
||||||
|
certificationsForUserId = new ArrayList<>();
|
||||||
|
certifications.put(certification.getUserId(), certificationsForUserId);
|
||||||
|
}
|
||||||
|
// TODO: Prevent duplicates, only keep newest timestamped sig?
|
||||||
|
certificationsForUserId.add(certification);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class Depth implements Comparable<Depth> {
|
||||||
|
|
||||||
|
private final Optional<Integer> depth;
|
||||||
|
|
||||||
|
private Depth(Optional<Integer> depth) {
|
||||||
|
this.depth = depth;
|
||||||
|
if (!isUnconstrained() && (getLimit().get() < 0 || getLimit().get() > 255)) {
|
||||||
|
throw new IllegalArgumentException("Depth must be a value between 0 and 255");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Depth unconstrained() {
|
||||||
|
return new Depth(Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Depth limited(int depth) {
|
||||||
|
return new Depth(Optional.just(depth));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Depth auto(int depth) {
|
||||||
|
return depth == 255 ? unconstrained() : limited(depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Integer> getLimit() {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUnconstrained() {
|
||||||
|
return getLimit().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Depth decrease(int value) {
|
||||||
|
if (isUnconstrained()) {
|
||||||
|
return unconstrained();
|
||||||
|
}
|
||||||
|
if (getLimit().get() >= value) {
|
||||||
|
return limited(getLimit().get() - value);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Depth cannot be decreased.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@Nonnull Depth o) {
|
||||||
|
if (isUnconstrained()) {
|
||||||
|
if (o.isUnconstrained()) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (o.isUnconstrained()) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return Integer.compare(getLimit().get(), o.getLimit().get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return isUnconstrained() ? "unconstrained" : getLimit().get().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Depth min(Depth other) {
|
||||||
|
if (compareTo(other) <= 0) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
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.algorithm.RevocationStateType;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
private final Map<OpenPgpFingerprint, CertSynopsis> nodes;
|
||||||
|
private final Map<OpenPgpFingerprint, List<CertificationSet>> edges;
|
||||||
|
private final Map<OpenPgpFingerprint, List<CertificationSet>> reverseEdges;
|
||||||
|
private final ReferenceTime referenceTime;
|
||||||
|
|
||||||
|
public Network(Map<OpenPgpFingerprint, CertSynopsis> nodes,
|
||||||
|
Map<OpenPgpFingerprint, List<CertificationSet>> edges,
|
||||||
|
Map<OpenPgpFingerprint, List<CertificationSet>> reverseEdges,
|
||||||
|
ReferenceTime referenceTime) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
this.edges = edges;
|
||||||
|
this.reverseEdges = reverseEdges;
|
||||||
|
this.referenceTime = referenceTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an empty {@link Network}.
|
||||||
|
*
|
||||||
|
* @param referenceTime reference time for evaluation
|
||||||
|
* @return network
|
||||||
|
*/
|
||||||
|
public static Network empty(@Nonnull ReferenceTime referenceTime) {
|
||||||
|
return new Network(
|
||||||
|
new HashMap<>(),
|
||||||
|
new HashMap<>(),
|
||||||
|
new HashMap<>(),
|
||||||
|
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<PGPPublicKeyRing> certificates,
|
||||||
|
Policy policy,
|
||||||
|
Optional<ReferenceTime> optReferenceTime) {
|
||||||
|
ReferenceTime referenceTime = optReferenceTime.isPresent() ? optReferenceTime.get() : ReferenceTime.now();
|
||||||
|
List<KeyRingInfo> 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<KeyRingInfo> validatedCertificates,
|
||||||
|
ReferenceTime referenceTime) {
|
||||||
|
|
||||||
|
Map<OpenPgpFingerprint, KeyRingInfo> byFingerprint = new HashMap<>();
|
||||||
|
Map<Long, List<KeyRingInfo>> byKeyId = new HashMap<>();
|
||||||
|
|
||||||
|
Map<OpenPgpFingerprint, CertSynopsis> certSynopsisMap = new HashMap<>();
|
||||||
|
|
||||||
|
for (KeyRingInfo cert : validatedCertificates) {
|
||||||
|
//noinspection Java8MapApi
|
||||||
|
if (byFingerprint.get(cert.getFingerprint()) == null) {
|
||||||
|
byFingerprint.put(cert.getFingerprint(), cert);
|
||||||
|
}
|
||||||
|
List<KeyRingInfo> 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<OpenPgpFingerprint, List<CertificationSet>> edges = new HashMap<>();
|
||||||
|
Map<OpenPgpFingerprint, List<CertificationSet>> reverseEdges = new HashMap<>();
|
||||||
|
|
||||||
|
return new Network(certSynopsisMap, edges, reverseEdges, referenceTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<OpenPgpFingerprint, CertSynopsis> getNodes() {
|
||||||
|
return new HashMap<>(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<OpenPgpFingerprint, List<CertificationSet>> getEdges() {
|
||||||
|
return new HashMap<>(edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<OpenPgpFingerprint, List<CertificationSet>> getReverseEdges() {
|
||||||
|
return new HashMap<>(reverseEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReferenceTime getReferenceTime() {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class Optional<T> {
|
||||||
|
|
||||||
|
private final T item;
|
||||||
|
|
||||||
|
public static <T> Optional<T> empty() {
|
||||||
|
return new Optional<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Optional<T> just(@Nonnull T item) {
|
||||||
|
return new Optional<>(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Optional<T> maybe(@Nullable T item) {
|
||||||
|
return item == null ? empty() : just(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional() {
|
||||||
|
this.item = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional(@Nonnull T item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return item == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresent() {
|
||||||
|
return item != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nonnull T get() {
|
||||||
|
if (item == null) {
|
||||||
|
throw new NullPointerException("Item is null.");
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return super.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof Optional)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional other = (Optional) obj;
|
||||||
|
if (isEmpty() && other.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPresent() && isPresent()) {
|
||||||
|
return get().equals(other.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Path {
|
||||||
|
|
||||||
|
private CertSynopsis root;
|
||||||
|
private List<Certification> edges;
|
||||||
|
private Depth residualDepth;
|
||||||
|
|
||||||
|
public Path(CertSynopsis root) {
|
||||||
|
this.root = root;
|
||||||
|
this.edges = new ArrayList<>();
|
||||||
|
this.residualDepth = Depth.unconstrained();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CertSynopsis getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CertSynopsis getTarget() {
|
||||||
|
if (edges.isEmpty()) {
|
||||||
|
return getRoot();
|
||||||
|
} else {
|
||||||
|
return edges.get(edges.size() - 1).getTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CertSynopsis> getCertificates() {
|
||||||
|
List<CertSynopsis> certs = new ArrayList<>();
|
||||||
|
certs.add(getRoot());
|
||||||
|
for (Certification edge : edges) {
|
||||||
|
certs.add(edge.getTarget());
|
||||||
|
}
|
||||||
|
return certs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLength() {
|
||||||
|
return edges.size() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Certification> getCertifications() {
|
||||||
|
return new ArrayList<>(edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Depth getResidualDepth() {
|
||||||
|
return residualDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmount() {
|
||||||
|
if (edges.isEmpty()) {
|
||||||
|
return 120;
|
||||||
|
}
|
||||||
|
int min = 255;
|
||||||
|
for (Certification edge : edges) {
|
||||||
|
min = Math.min(min, edge.getTrustAmount());
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void append(Certification certification) {
|
||||||
|
if (!getTarget().getFingerprint().equals(certification.getIssuer().getFingerprint())) {
|
||||||
|
throw new IllegalArgumentException("Cannot append certification to path: Path's tail is not issuer of the certification.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!residualDepth.isUnconstrained() && residualDepth.getLimit().get() == 0) {
|
||||||
|
throw new IllegalArgumentException("Not enough depth.");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cyclic = getRoot().getFingerprint().equals(certification.getTarget().getFingerprint());
|
||||||
|
for (int i = 0; i < edges.size() && !cyclic; i++) {
|
||||||
|
Certification edge = edges.get(i);
|
||||||
|
|
||||||
|
if (edge.getTarget().getFingerprint().equals(certification.getTarget().getFingerprint())) {
|
||||||
|
if (i == edges.size() - 1) {
|
||||||
|
cyclic = edge.getUserId().equals(certification.getUserId());
|
||||||
|
} else {
|
||||||
|
cyclic = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cyclic) {
|
||||||
|
throw new IllegalArgumentException("Adding the certification to the path would create a cycle.");
|
||||||
|
}
|
||||||
|
|
||||||
|
residualDepth = certification.getTrustDepth().min(residualDepth.decrease(1));
|
||||||
|
edges.add(certification);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Paths {
|
||||||
|
|
||||||
|
private final List<Item> paths = new ArrayList<>();
|
||||||
|
|
||||||
|
public List<Item> getPaths() {
|
||||||
|
return new ArrayList<>(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Path path, int amount) {
|
||||||
|
if (amount <= path.getAmount()) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
this.paths.add(new Item(path, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmount() {
|
||||||
|
int sum = 0;
|
||||||
|
for (Item item : paths) {
|
||||||
|
sum += item.amount;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Item {
|
||||||
|
private final Path path;
|
||||||
|
private final int amount;
|
||||||
|
|
||||||
|
public Item(Path path, int amount) {
|
||||||
|
this.path = path;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface ReferenceTime {
|
||||||
|
|
||||||
|
@Nonnull Date getTimestamp();
|
||||||
|
|
||||||
|
static ReferenceTime now() {
|
||||||
|
final Date now = new Date();
|
||||||
|
return new ReferenceTime() {
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public Date getTimestamp() {
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ReferenceTime timestamp(@Nonnull Date timestamp) {
|
||||||
|
return new ReferenceTime() {
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public Date getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.RegularExpression;
|
||||||
|
|
||||||
|
public class RegexSet {
|
||||||
|
|
||||||
|
private final Set<String> regexStrings;
|
||||||
|
|
||||||
|
private RegexSet(Set<String> regexStrings) {
|
||||||
|
this.regexStrings = regexStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegexSet fromList(@Nonnull List<RegularExpression> regexList) {
|
||||||
|
Set<String> regexStringSet = new HashSet<>();
|
||||||
|
for (RegularExpression regex : regexList) {
|
||||||
|
regexStringSet.add(regex.getRegex());
|
||||||
|
}
|
||||||
|
return new RegexSet(regexStringSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegexSet fromRegex(@Nonnull RegularExpression regex) {
|
||||||
|
return fromList(Collections.singletonList(regex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegexSet wildcard() {
|
||||||
|
return fromList(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(String string) {
|
||||||
|
if (regexStrings.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String regex : regexStrings) {
|
||||||
|
Matcher matcher = Pattern.compile(regex).matcher(string);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class BasicShortestPathDijkstraTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a test graph from a string definition.
|
||||||
|
* The definition might look like this:
|
||||||
|
* <pre>
|
||||||
|
* Alice
|
||||||
|
* Bob -1> Charlie
|
||||||
|
* Charlie -4> Dieter -1> Alice
|
||||||
|
* Dieter -2> Charlie
|
||||||
|
* </pre>
|
||||||
|
* @param definition definition
|
||||||
|
* @return graph
|
||||||
|
*/
|
||||||
|
private Graph<String, Node<String>, SimpleEdge<String>, Cost.SimpleCost> generate(String definition) {
|
||||||
|
Set<Node<String>> nodes = new HashSet<>();
|
||||||
|
Set<SimpleEdge<String>> edges = new HashSet<>();
|
||||||
|
String[] lines = definition.split("\n");
|
||||||
|
for (String line : lines) {
|
||||||
|
line = line.trim();
|
||||||
|
if (line.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] fromTo = line.split(" -\\d+> ");
|
||||||
|
if (fromTo.length == 1) {
|
||||||
|
// Unconnected node
|
||||||
|
nodes.add(new Node<>(fromTo[0]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int searchOffset = 0;
|
||||||
|
for (int i = 0; i < fromTo.length - 1; i++) {
|
||||||
|
Node<String> from = new Node<>(fromTo[i]);
|
||||||
|
nodes.add(from);
|
||||||
|
searchOffset += fromTo[i].length() + " -".length();
|
||||||
|
int costStop = line.indexOf("> ", searchOffset);
|
||||||
|
String costString = line.substring(searchOffset, costStop);
|
||||||
|
Double cost = Double.parseDouble(costString);
|
||||||
|
searchOffset += costString.length() + "> ".length();
|
||||||
|
Node<String> to = new Node<>(fromTo[i + 1]);
|
||||||
|
nodes.add(to);
|
||||||
|
|
||||||
|
edges.add(new SimpleEdge<>(from, to, cost));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Graph<>(nodes, edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path<String, Node<String>, Cost.SimpleCost, SimpleEdge<String>> path(String definition) {
|
||||||
|
definition = definition.trim();
|
||||||
|
String[] fromTo = definition.split(" -\\d+> ");
|
||||||
|
if (fromTo.length == 1) {
|
||||||
|
// Unconnected node
|
||||||
|
Node<String> node = new Node<>(fromTo[0]);
|
||||||
|
return new Path<>(node, node, Collections.singletonList(new SimpleEdge<>(node, node, 0d)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node<String> start = null;
|
||||||
|
Node<String> end = null;
|
||||||
|
List<SimpleEdge<String>> edges = new ArrayList<>();
|
||||||
|
int searchOffset = 0;
|
||||||
|
for (int i = 0; i < fromTo.length - 1; i++) {
|
||||||
|
Node<String> from = new Node<>(fromTo[i]);
|
||||||
|
if (start == null) {
|
||||||
|
start = from;
|
||||||
|
}
|
||||||
|
searchOffset += fromTo[i].length() + " -".length();
|
||||||
|
int costStop = definition.indexOf("> ", searchOffset);
|
||||||
|
String costString = definition.substring(searchOffset, costStop);
|
||||||
|
Double cost = Double.parseDouble(costString);
|
||||||
|
searchOffset += costString.length() + "> ".length();
|
||||||
|
Node<String> to = new Node<>(fromTo[i + 1]);
|
||||||
|
edges.add(new SimpleEdge<>(from, to, cost));
|
||||||
|
end = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path<String, Node<String>, Cost.SimpleCost, SimpleEdge<String>> path = new Path<>(start, end, edges);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void exampleGraphTest() {
|
||||||
|
Graph<String, Node<String>, SimpleEdge<String>, Cost.SimpleCost> g = generate(
|
||||||
|
"Alice\n" +
|
||||||
|
"Bob -1> Charlie\n" +
|
||||||
|
"Bob -3> Dieter -1> Marlene\n" +
|
||||||
|
"Dieter -1> Alice\n" +
|
||||||
|
"Mallory\n");
|
||||||
|
|
||||||
|
Set<Node<String>> expectedNodes = new HashSet<>();
|
||||||
|
expectedNodes.add(new Node<>("Alice"));
|
||||||
|
expectedNodes.add(new Node<>("Bob"));
|
||||||
|
expectedNodes.add(new Node<>("Charlie"));
|
||||||
|
expectedNodes.add(new Node<>("Dieter"));
|
||||||
|
expectedNodes.add(new Node<>("Marlene"));
|
||||||
|
expectedNodes.add(new Node<>("Mallory"));
|
||||||
|
|
||||||
|
assertEquals(expectedNodes, g.getNodes());
|
||||||
|
|
||||||
|
Set<SimpleEdge<String>> expectedEdges = new HashSet<>();
|
||||||
|
expectedEdges.add(new SimpleEdge<>(new Node<>("Bob"), new Node<>("Charlie"), 1d));
|
||||||
|
expectedEdges.add(new SimpleEdge<>(new Node<>("Bob"), new Node<>("Dieter"), 3d));
|
||||||
|
expectedEdges.add(new SimpleEdge<>(new Node<>("Dieter"), new Node<>("Marlene"), 1d));
|
||||||
|
expectedEdges.add(new SimpleEdge<>(new Node<>("Dieter"), new Node<>("Alice"), 1d));
|
||||||
|
|
||||||
|
assertEquals(g.getEdges(), expectedEdges);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emptyNetworkTest() {
|
||||||
|
Graph<String, Node<String>, SimpleEdge<String>, Cost.SimpleCost> graph = generate("");
|
||||||
|
|
||||||
|
Node<String> root = new Node<>("root");
|
||||||
|
Node<String> target = new Node<>("target");
|
||||||
|
ShortestPathDijkstra<String> dijkstra = new ShortestPathDijkstra<>(graph, root);
|
||||||
|
Path<String, Node<String>, Cost.SimpleCost, SimpleEdge<String>> path = dijkstra.findPath(target);
|
||||||
|
|
||||||
|
assertNull(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void pathFindingTest() {
|
||||||
|
Graph<String, Node<String>, SimpleEdge<String>, Cost.SimpleCost> graph = generate(
|
||||||
|
"Pablo\n" +
|
||||||
|
"Root -2> Alice -3> Alexandra\n" +
|
||||||
|
"Root -1> Karlos -1> Alexandra\n" +
|
||||||
|
"Karlos -2> Malte -4> Sven");
|
||||||
|
|
||||||
|
ShortestPathDijkstra<String> dijkstra = new ShortestPathDijkstra<>(graph, new Node<>("Root"));
|
||||||
|
assertEquals(path("Root -1> Karlos -2> Malte -4> Sven"), dijkstra.findPath(new Node<>("Sven")));
|
||||||
|
assertEquals(path("Root -1> Karlos"), dijkstra.findPath(new Node<>("Karlos")));
|
||||||
|
assertEquals(path("Root -1> Karlos -1> Alexandra"), dijkstra.findPath(new Node<>("Alexandra")));
|
||||||
|
|
||||||
|
dijkstra = new ShortestPathDijkstra<>(graph, new Node<>("Karlos"));
|
||||||
|
assertEquals(path("Karlos -2> Malte -4> Sven"), dijkstra.findPath(new Node<>("Sven")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.pgpainless.wot.dijkstra;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
|
||||||
|
public class NodeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void equalsTest() {
|
||||||
|
Node<String> n1 = new Node<>("foo");
|
||||||
|
Node<String> n1_ = new Node<>("foo");
|
||||||
|
Node<String> n2 = new Node<>("bar");
|
||||||
|
|
||||||
|
assertEquals(n1, n1_);
|
||||||
|
assertEquals(n1, n1);
|
||||||
|
assertNotEquals(n1, n2);
|
||||||
|
|
||||||
|
Map<Node<String>, String> map = new HashMap<>();
|
||||||
|
map.put(n1, "foo");
|
||||||
|
map.put(n2, "bar");
|
||||||
|
|
||||||
|
assertEquals("foo", map.get(n1));
|
||||||
|
assertEquals("bar", map.get(n2));
|
||||||
|
assertEquals("foo", map.get(n1_));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class DepthTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnlimitedItem() {
|
||||||
|
Depth depth = Depth.unconstrained();
|
||||||
|
assertTrue(depth.isUnconstrained());
|
||||||
|
assertFalse(depth.getLimit().isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLimitedItem() {
|
||||||
|
Depth limited = Depth.limited(2);
|
||||||
|
assertFalse(limited.isUnconstrained());
|
||||||
|
assertTrue(limited.getLimit().isPresent());
|
||||||
|
assertEquals(2, limited.getLimit().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecreaseUnconstrainedYieldsUnconstrained() {
|
||||||
|
Depth unconstrained = Depth.unconstrained();
|
||||||
|
Depth decreased = unconstrained.decrease(20);
|
||||||
|
assertTrue(decreased.isUnconstrained());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecreaseLimitedYieldsDecreasedLimited() {
|
||||||
|
Depth limited = Depth.limited(1);
|
||||||
|
Depth decreased = limited.decrease(1);
|
||||||
|
assertFalse(decreased.isUnconstrained());
|
||||||
|
assertEquals(0, decreased.getLimit().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecreaseLimitedTooMuchYieldsException() {
|
||||||
|
Depth limited = Depth.limited(0);
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> limited.decrease(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCompareTo() {
|
||||||
|
Depth unlimited = Depth.unconstrained();
|
||||||
|
Depth unlimited2 = Depth.unconstrained();
|
||||||
|
Depth depth2 = Depth.limited(2);
|
||||||
|
Depth depth2_ = Depth.limited(2);
|
||||||
|
Depth depth5 = Depth.limited(5);
|
||||||
|
|
||||||
|
assertEquals(0, unlimited.compareTo(unlimited2));
|
||||||
|
assertTrue(unlimited.compareTo(depth2) > 0);
|
||||||
|
assertTrue(unlimited.compareTo(depth5) > 0);
|
||||||
|
assertTrue(depth2.compareTo(unlimited) < 0);
|
||||||
|
assertTrue(depth2.compareTo(depth5) < 0);
|
||||||
|
assertTrue(depth5.compareTo(depth2) > 0);
|
||||||
|
assertEquals(0, depth2.compareTo(depth2_));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoUnconstrained() {
|
||||||
|
Depth depth = Depth.auto(255);
|
||||||
|
assertTrue(depth.isUnconstrained());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAutoLimited() {
|
||||||
|
Depth depth = Depth.auto(120);
|
||||||
|
assertFalse(depth.isUnconstrained());
|
||||||
|
assertEquals(120, depth.getLimit().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOutOfBounds() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Depth.limited(-1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Depth.limited(256));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Depth.auto(-1));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> Depth.auto(256));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToStringUnconstrained() {
|
||||||
|
assertEquals("unconstrained", Depth.unconstrained().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToStringLimited() {
|
||||||
|
assertEquals("1", Depth.limited(1).toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class NetworkTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyNetworkIsEmpty() {
|
||||||
|
ReferenceTime referenceTime = ReferenceTime.now();
|
||||||
|
Network network = Network.empty(referenceTime);
|
||||||
|
|
||||||
|
assertTrue(network.getNodes().isEmpty());
|
||||||
|
assertTrue(network.getEdges().isEmpty());
|
||||||
|
assertTrue(network.getReverseEdges().isEmpty());
|
||||||
|
assertEquals(referenceTime, network.getReferenceTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNetworkFromCertificates() {
|
||||||
|
ReferenceTime referenceTime = ReferenceTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,275 @@
|
||||||
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.algorithm.Trustworthiness;
|
||||||
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
|
import org.pgpainless.signature.subpackets.CertificationSubpackets;
|
||||||
|
import org.pgpainless.util.Passphrase;
|
||||||
|
|
||||||
|
public class WotTestVectors {
|
||||||
|
|
||||||
|
private static WotTestVectors INSTANCE = null;
|
||||||
|
|
||||||
|
public static WotTestVectors getTestVectors() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new WotTestVectors();
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshFooBankCaKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankCaKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshFooBankCaCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankCaCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFooBankCaPassphrase() {
|
||||||
|
return "superS3cureP4ssphrase";
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecretKeyRingProtector getFooBankCaProtector() {
|
||||||
|
return SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(getFooBankCaPassphrase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshFooBankEmployeeKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankEmployeeKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshFooBankEmployeeCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankEmployeeCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFooBankEmployeePassphrase() {
|
||||||
|
return "iLoveWorking@FooBank";
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecretKeyRingProtector getFooBankEmployeeProtector() {
|
||||||
|
return SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(getFooBankEmployeePassphrase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshFooBankAdminKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankAdminKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshFooBankAdminCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankAdminCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFooBankAdminPassphrase() {
|
||||||
|
return "keepFooBankSecure";
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecretKeyRingProtector getFooBankAdminProtector() {
|
||||||
|
return SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword(getFooBankAdminPassphrase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshFooBankCustomerKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankCustomerKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshFooBankCustomerCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/foobankCustomerCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshBarBankCaKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/barbankCaKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshBarBankCaCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/barbankCaCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshBarBankEmployeeKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/barbankEmployeeKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshBarBankEmployeeCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/barbankEmployeeCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing getFreshFakeFooBankEmployeeKey() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().secretKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/fakeFoobankEmployeeKey.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getFreshFakeFooBankEmployeeCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("test_vectors/freshly_generated/fakeFoobankEmployeeCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getCrossSignedBarBankCaCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("cross_signed/barbankCaCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getCrossSignedBarBankEmployeeCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("cross_signed/barbankEmployeeCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getCrossSignedFooBankAdminCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("cross_signed/foobankAdminCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getCrossSignedFooBankCaCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("cross_signed/foobankCaCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPPublicKeyRing getCrossSignedFooBankEmployeeCert() throws IOException {
|
||||||
|
return PGPainless.readKeyRing().publicKeyRing(getTestResourceInputStream("cross_signed/foobankEmployeeCert.asc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate cross signed test vectors from freshly generated
|
||||||
|
public void crossSign() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing freshFooBankCaKey = getFreshFooBankCaKey();
|
||||||
|
PGPPublicKeyRing freshFooBankCaCert = getFreshFooBankCaCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshFooBankEmployeeKey = getFreshFooBankEmployeeKey();
|
||||||
|
PGPPublicKeyRing freshFooBankEmployeeCert = getFreshFooBankEmployeeCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshFooBankAdminKey = getFreshFooBankAdminKey();
|
||||||
|
PGPPublicKeyRing freshFooBankAdminCert = getFreshFooBankAdminCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshFooBankCustomerKey = getFreshFooBankCustomerKey();
|
||||||
|
PGPPublicKeyRing freshFooBankCustomerCert = getFreshFooBankCustomerCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshBarBankCaKey = getFreshBarBankCaKey();
|
||||||
|
PGPPublicKeyRing freshBarBankCaCert = getFreshBarBankCaCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshBarBankEmployeeKey = getFreshBarBankEmployeeKey();
|
||||||
|
PGPPublicKeyRing freshBarBankEmployeeCert = getFreshBarBankEmployeeCert();
|
||||||
|
|
||||||
|
PGPSecretKeyRing freshFakeFooBankEmployeeKey = getFreshFakeFooBankEmployeeKey();
|
||||||
|
PGPPublicKeyRing freshFakeFooBankEmployeeCert = getFreshFakeFooBankEmployeeCert();
|
||||||
|
|
||||||
|
final String fooBankRegex = "<[^>]+[@.]foobank\\.com>$";
|
||||||
|
final String barBankRegex = "<[^>]+[@.]barbank\\.com>$";
|
||||||
|
|
||||||
|
// Foo CA signs Foo Employee
|
||||||
|
PGPPublicKeyRing caCertifiedFooBankEmployeeCert = PGPainless.certify()
|
||||||
|
.userIdOnCertificate("Foo Bank Employee <employee@foobank.com>", freshFooBankEmployeeCert)
|
||||||
|
.withKey(freshFooBankCaKey, getFooBankCaProtector())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.addNotationData(false, "affiliation@foobank.com", "employee");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
// Foo CA signs Foo Admin
|
||||||
|
PGPPublicKeyRing caCertifiedFooBankAdminCert = PGPainless.certify()
|
||||||
|
.userIdOnCertificate("Foo Bank Admin <admin@foobank.com>", freshFooBankAdminCert)
|
||||||
|
.withKey(freshFooBankCaKey, getFooBankCaProtector())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.addNotationData(false, "affiliation@foobank.com", "administrator");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
// Foo Employee delegates trust to Foo CA
|
||||||
|
PGPPublicKeyRing employeeDelegatedCaCert = PGPainless.certify()
|
||||||
|
.certificate(freshFooBankCaCert, Trustworthiness.fullyTrusted().introducer())
|
||||||
|
.withKey(freshFooBankEmployeeKey, getFooBankEmployeeProtector())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.setRegularExpression(fooBankRegex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
// Foo Admin delegates trust to Foo CA
|
||||||
|
PGPPublicKeyRing adminDelegatedCaCert = PGPainless.certify()
|
||||||
|
.certificate(freshFooBankCaCert, Trustworthiness.fullyTrusted().introducer())
|
||||||
|
.withKey(freshFooBankAdminKey, getFooBankAdminProtector())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.setRegularExpression(fooBankRegex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
// Customer delegates trust to Foo CA
|
||||||
|
PGPPublicKeyRing customerDelegatedCaCert = PGPainless.certify()
|
||||||
|
.certificate(freshFooBankCaCert, Trustworthiness.fullyTrusted().introducer())
|
||||||
|
.withKey(freshFooBankCustomerKey, SecretKeyRingProtector.unprotectedKeys())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.setRegularExpression(fooBankRegex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
PGPPublicKeyRing mergedFooCa = PGPPublicKeyRing.join(employeeDelegatedCaCert, adminDelegatedCaCert);
|
||||||
|
mergedFooCa = PGPPublicKeyRing.join(mergedFooCa, customerDelegatedCaCert);
|
||||||
|
|
||||||
|
// Foo Admin delegates trust to Bar CA
|
||||||
|
PGPPublicKeyRing fooAdminDelegatedBarCa = PGPainless.certify()
|
||||||
|
.certificate(freshBarBankCaCert, Trustworthiness.fullyTrusted().introducer())
|
||||||
|
.withKey(freshFooBankAdminKey, getFooBankAdminProtector())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.setRegularExpression("<[^>]+[@.]barbank\\.com>$");
|
||||||
|
}
|
||||||
|
}).getCertifiedCertificate();
|
||||||
|
|
||||||
|
// Bar Employee delegates Bar CA
|
||||||
|
PGPPublicKeyRing barEmployeeDelegatesBarCa = PGPainless.certify()
|
||||||
|
.certificate(freshBarBankCaCert, Trustworthiness.fullyTrusted().introducer())
|
||||||
|
.withKey(freshBarBankEmployeeKey, SecretKeyRingProtector.unprotectedKeys())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.setRegularExpression(barBankRegex);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
PGPPublicKeyRing mergedBarCa = PGPPublicKeyRing.join(fooAdminDelegatedBarCa, barEmployeeDelegatesBarCa);
|
||||||
|
|
||||||
|
// Bar CA signs Bar Employee
|
||||||
|
PGPPublicKeyRing barCaCertifiedEmployeeCert = PGPainless.certify()
|
||||||
|
.userIdOnCertificate("Bar Bank Employee <employee@barbank.com>", freshBarBankEmployeeCert)
|
||||||
|
.withKey(freshBarBankCaKey, SecretKeyRingProtector.unprotectedKeys())
|
||||||
|
.buildWithSubpackets(new CertificationSubpackets.Callback() {
|
||||||
|
@Override
|
||||||
|
public void modifyHashedSubpackets(CertificationSubpackets hashedSubpackets) {
|
||||||
|
hashedSubpackets.addNotationData(false, "affiliation@barbank.com", "employee");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.getCertifiedCertificate();
|
||||||
|
|
||||||
|
System.out.println("Foo Employee");
|
||||||
|
System.out.println(PGPainless.asciiArmor(caCertifiedFooBankEmployeeCert));
|
||||||
|
|
||||||
|
System.out.println("Foo Admin");
|
||||||
|
System.out.println(PGPainless.asciiArmor(caCertifiedFooBankAdminCert));
|
||||||
|
|
||||||
|
System.out.println("Foo CA");
|
||||||
|
System.out.println(PGPainless.asciiArmor(mergedFooCa));
|
||||||
|
|
||||||
|
System.out.println("Bar CA");
|
||||||
|
System.out.println(PGPainless.asciiArmor(mergedBarCa));
|
||||||
|
|
||||||
|
System.out.println("Bar Employee");
|
||||||
|
System.out.println(PGPainless.asciiArmor(barCaCertifiedEmployeeCert));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStream getTestResourceInputStream(String resource) {
|
||||||
|
InputStream inputStream = WotTestVectors.class.getClassLoader().getResourceAsStream(resource);
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalArgumentException(String.format("Unknown resource %s", resource));
|
||||||
|
}
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
}
|
47
wot-dijkstra/src/test/resources/test_vectors/README.md
Normal file
47
wot-dijkstra/src/test/resources/test_vectors/README.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
# Test Vectors
|
||||||
|
|
||||||
|
## Freshly Generated Vectors
|
||||||
|
|
||||||
|
The `freshly_generated/` directory contains freshly generated test vectors.
|
||||||
|
Those are keys and certificates without any third-party signatures.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR;
|
||||||
|
a[Foo Bank CA <ca@foobank.com>];
|
||||||
|
b[Foo Bank Employee <employee@foobank.com>];
|
||||||
|
c[Foo Bank Admin <admin@foobank.com>];
|
||||||
|
|
||||||
|
d[Customer <customer@example.com>];
|
||||||
|
e[Bar Bank CA <ca@barbank.com>];
|
||||||
|
f[Bar Bank Employee <employee@barbank.com>];
|
||||||
|
g[Foo Bank Employee (Attacker) <employee@foobank.com>];
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cross Signed Vectors
|
||||||
|
The `cross_signed/` directory contains test vectors that model the following interconnectivity:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD;
|
||||||
|
a[Foo Bank CA <ca@foobank.com>];
|
||||||
|
b[Foo Bank Employee <employee@foobank.com>];
|
||||||
|
c[Foo Bank Admin <admin@foobank.com>];
|
||||||
|
|
||||||
|
d[Customer <customer@example.com>];
|
||||||
|
e[Bar Bank CA <ca@barbank.com>];
|
||||||
|
f[Bar Bank Employee <employee@barbank.com>];
|
||||||
|
g[Foo Bank Employee (Attacker) <employee@foobank.com>];
|
||||||
|
|
||||||
|
a -- generic certification --> b & c;
|
||||||
|
b & c & d == 1:120:"<[^>]+[@.]foobank\.com>$" ==> a;
|
||||||
|
e -- generic certification --> f;
|
||||||
|
c == 1:120:"<[^>]+[@.]barbank\.com>$" ==> e;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Useful Resources:
|
||||||
|
* https://mateam.net/html-escape-characters/
|
||||||
|
* https://docs.sequoia-pgp.org/sequoia_openpgp/regex/index.html#caveat-emptor
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: CEE5 FB5D C524 84A6 9B73 9FAD 7DA0 2993 D86B 0355
|
||||||
|
Comment: Bar Bank CA <ca@barbank.com>
|
||||||
|
|
||||||
|
mDMEYs1BgxYJKwYBBAHaRw8BAQdA3hOlkHAVyvTwePiifKnwLhkcJnswNidJ7dWo
|
||||||
|
UKEQlZWIlAQfFgoARgUCYs1MVwkQ9fHjtTaNbKcWIQSmiOyyabOBYdpNc4/18eO1
|
||||||
|
No1spxoGPFtePl0rW0AuXWJhcmJhbmtcLmNvbT4kAAOFAXgAAOfiAQCJIhMid48+
|
||||||
|
8FS9IO76ELTYMsy0q/kBd4z3Gs+OYqM3ZQEAjyqoEKT8OHNC3zPkneE4bhsB21CH
|
||||||
|
PMBe+pYcUE3tZAmIlAQfFgoARgUCYs1MVwkQitIzV+t4uwgWIQREeoKqA/fXpLHa
|
||||||
|
TXyK0jNX63i7CBoGPFtePl0rW0AuXWJhcmJhbmtcLmNvbT4kAAOFAXgAAHb5AP99
|
||||||
|
3BHUJhkpc6S0NiTsT1OKifmAuI9bRT++TIqEB6p7uwEA09k6Y59pjZhnISG4+KiK
|
||||||
|
Y+ZhGKx6bbyGIXirwlssMQK0HEJhciBCYW5rIENBIDxjYUBiYXJiYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYs1BgwkQfaApk9hrA1UWIQTO5ftdxSSEpptzn619oCmT2GsDVQKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAABltgEA4Ob86bhjLa6Xg4wnzYIGH21W
|
||||||
|
EUlc37BBaqwr4qvfsA4A/0BzOdTy3Wty5DkdMiA2yPOxIVuHbTD8pgqpne2yoegN
|
||||||
|
uDgEYs1BgxIKKwYBBAGXVQEFAQEHQDVHLNRE4Gtg9/BzwSUMW3psBD7OUm4Df0gg
|
||||||
|
ilvLZhMcAwEIB4h1BBgWCgAdBQJizUGDAp4BApsMBRYCAwEABAsJCAcFFQoJCAsA
|
||||||
|
CgkQfaApk9hrA1WrYAEAsZsEoUfAPIG6d9gtK7Zmm3zt+xiTELW08E/pwjmFTmEB
|
||||||
|
AODICUhsEelkdXrbIkL2oWAKoxlsbkyA6mNXBt5UXQcJuDMEYs1BgxYJKwYBBAHa
|
||||||
|
Rw8BAQdARHF/sgSTB38osF0+XA9N2htsMIrb322j3LQdrk0M77SI1QQYFgoAfQUC
|
||||||
|
Ys1BgwKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmLNQYMACgkQtEK9
|
||||||
|
w/vjcduqJwD+KW23+689GXtu4k3PW60GPsiue22lMGwZY7hsWvZB1hkBAPER8PMs
|
||||||
|
0MJAQzcs2u6bYPMDI921umqX8Yvsob1kzs0FAAoJEH2gKZPYawNVdKwBAKz5zfwE
|
||||||
|
KZ2dGPCsUJzAXfPxe0LmATcvS5g/LvAreD0KAQDfpfMFO2EqQu6wDt+e5MH3YCjG
|
||||||
|
saYwvjB1elj1zhblAg==
|
||||||
|
=O9uk
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,25 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 447A 82AA 03F7 D7A4 B1DA 4D7C 8AD2 3357 EB78 BB08
|
||||||
|
Comment: Bar Bank Employee <employee@barbank.com>
|
||||||
|
|
||||||
|
mDMEYs1CXRYJKwYBBAHaRw8BAQdAeMjyfqInb8aZppFsKHdndoeL3j08Z5CtagKz
|
||||||
|
KPb6YGO0KEJhciBCYW5rIEVtcGxveWVlIDxlbXBsb3llZUBiYXJiYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYs1CXQkQitIzV+t4uwgWIQREeoKqA/fXpLHaTXyK0jNX63i7CAKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAACgcgD7Bk2Hu+Lu3aA+IyzFyTQOw8zQ
|
||||||
|
RUeA/X8neEIezYDTC+MA/jGFyiKW7b+6W3zgdIgiHMeWhG3Wx2oOC1izW2+tP2cJ
|
||||||
|
iJ4EEBYKAFAFAmLNTFcJEH2gKZPYawNVFiEEzuX7XcUkhKabc5+tfaApk9hrA1Uo
|
||||||
|
FIAAAAAAFwAIYWZmaWxpYXRpb25AYmFyYmFuay5jb21lbXBsb3llZQAAG4ABAMF2
|
||||||
|
yTTckIjHNIyv7M8mcUx/zW++oJMxnhztT73cQeNxAQDVoyHqRgLpWR4lKw2b5IwE
|
||||||
|
gw9KT9zIA9jveWufwgIvD7g4BGLNQl0SCisGAQQBl1UBBQEBB0Bq216nP4pw9r1F
|
||||||
|
8OMcUWisYUvOePUeULPLYV+jX8UdBgMBCAeIdQQYFgoAHQUCYs1CXQKeAQKbDAUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLAAoJEIrSM1freLsIo5QA/A9zDz8XrjtbJIK60J3kmwvY
|
||||||
|
jynF9IkzyFTj4sNeHhJTAP92dTWvbogEwzPhBbofwzOT7PXg7laQ8v9eTqr50lWf
|
||||||
|
B7gzBGLNQl0WCSsGAQQB2kcPAQEHQEV9SpoogW2HrVIaU953W31ceDvDmBWMFBQQ
|
||||||
|
a3Qsz6IBiNUEGBYKAH0FAmLNQl0CngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkW
|
||||||
|
CgAGBQJizUJdAAoJENG3C+ldSVbaPsAA/2giZHcGT0nyAojPds1IfIE97dyAlVgj
|
||||||
|
fbTH3H4QNVsAAP9dpakDZya/q8M/wnZOyOBf+dHiUrvDbxiBo4tj2ANJBgAKCRCK
|
||||||
|
0jNX63i7CMPgAP4ofxoiit/7nqvndk50NkiM9Ab0yTcLnjY+b28YMDLacwEApoEl
|
||||||
|
I15NDk/uTXQRKtXrHKoORwSK3XRPSSGYgMOhkwQ=
|
||||||
|
=LiUn
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,25 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: A688 ECB2 69B3 8161 DA4D 738F F5F1 E3B5 368D 6CA7
|
||||||
|
Comment: Foo Bank Admin <admin@foobank.com>
|
||||||
|
|
||||||
|
mDMEYrcZeRYJKwYBBAHaRw8BAQdABkxvWXwHDD6B3hXYQehQkil3e3Gcg5mNbOdS
|
||||||
|
9DSeny20IkZvbyBCYW5rIEFkbWluIDxhZG1pbkBmb29iYW5rLmNvbT6IjwQTFgoA
|
||||||
|
QQUCYrcZeQkQ9fHjtTaNbKcWIQSmiOyyabOBYdpNc4/18eO1No1spwKeAQKbAQUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLApkBAABPGwEAv0TWDMkJV6QiIgm8V4b9uIEzMpQku4UM
|
||||||
|
FBHvMKXh0W8A/1pocJBG+K9srn8NJlPBul7duoNbkzzHANkytFVEBOgEiKMEEBYK
|
||||||
|
AFUFAmLNTFYJEKFJBrdXMI7wFiEEMUVo/QiegSvLRR4roUkGt1cwjvAtFIAAAAAA
|
||||||
|
FwANYWZmaWxpYXRpb25AZm9vYmFuay5jb21hZG1pbmlzdHJhdG9yAADddwEAkcJU
|
||||||
|
aQfRbAkUvOp1zPUddQq6+a5C1y33d5s2n9gLqucBALy/kkbN5moNxEtcqTD5K1uD
|
||||||
|
OFfEVEIOEAGE7ic1dWcMuDgEYrcZeRIKKwYBBAGXVQEFAQEHQDd1fqNPF27j+Z8B
|
||||||
|
PtbyoU6sp63UQfBhJrUKNFjpWNZrAwEIB4h1BBgWCgAdBQJitxl5Ap4BApsMBRYC
|
||||||
|
AwEABAsJCAcFFQoJCAsACgkQ9fHjtTaNbKdmNwEAzTQAJ/ML5puyGHR9zCbuAonD
|
||||||
|
B0lKoXlJeWX7YpsLSugA/3M4YgzpBfoRNbehCbc2hcd/hbW9gKQs2k2iCUYDoPIN
|
||||||
|
uDMEYrcZeRYJKwYBBAHaRw8BAQdAIF2e85PlS4PWquE3NLE59A1tr9KPxEznQ0Ej
|
||||||
|
G/DfefiI1QQYFgoAfQUCYrcZeQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYK
|
||||||
|
AAYFAmK3GXkACgkQUqp0e41/iO+PswD+I+dgdOrj/jflr3D0Th8cugj9zFzwFYn9
|
||||||
|
aaGmiee5wv8A/RvvJoiwHMTi3QPvR4zGdF5pibOccbWr/dggFjKXTmoFAAoJEPXx
|
||||||
|
47U2jWynVbEBANEjxzV8KnujGor79Mc1ag9wxyDgihXRowsoKEnSkyHQAQD6n0Pf
|
||||||
|
1q8fl7BxbreVeY+0HN2swKlO9TvO303a3X6/BQ==
|
||||||
|
=WtDJ
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,31 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3145 68FD 089E 812B CB45 1E2B A149 06B7 5730 8EF0
|
||||||
|
Comment: Foo Bank CA <ca@foobank.com>
|
||||||
|
|
||||||
|
mDMEYrcXbxYJKwYBBAHaRw8BAQdAPIIGHwbBzEIExd70jtw7uDvOymt0nU83uLqR
|
||||||
|
4Og+cxCIlAQfFgoARgUCYs1MVgkQIa3PO58zSf4WIQQ7JP05RzLWqc9uBx4hrc87
|
||||||
|
nzNJ/hoGPFtePl0rW0AuXWZvb2JhbmtcLmNvbT4kAAOFAXgAAD4CAPwIMuVG2f+b
|
||||||
|
UfDsrtbQx8UO8TUnoRVHhwW/ogsp9Mop6AD/SoMIK1aNxzha56NOgCmAHo3hvdVp
|
||||||
|
gflXu5SlMpDcBgyIlAQfFgoARgUCYs1MVwkQ9fHjtTaNbKcWIQSmiOyyabOBYdpN
|
||||||
|
c4/18eO1No1spxoGPFtePl0rW0AuXWZvb2JhbmtcLmNvbT4kAAOFAXgAADS+AQD5
|
||||||
|
L1q6IO6xnG7pz4iammO7yM5jseDKsnd06q1qXTOxRQEAsYz2dx0owhU+4qZwfEME
|
||||||
|
kLIewdsBcjJurlXYDZJSkAuIlAQfFgoARgUCYs1MVwkQ+LtlEBaP0r8WIQQsTMpM
|
||||||
|
iRd/0ZHuo+D4u2UQFo/SvxoGPFtePl0rW0AuXWZvb2JhbmtcLmNvbT4kAAOFAXgA
|
||||||
|
AKlYAQDO0czTk2j+CRpYLwH24UT0NZQGcImx/xW+XHUz40y/mgEAmvkBkS0yaDET
|
||||||
|
94Nq1FpCL0oaheEybrXPzVT5+67Q2QW0HEZvbyBCYW5rIENBIDxjYUBmb29iYW5r
|
||||||
|
LmNvbT6IjwQTFgoAQQUCYrcXbwkQoUkGt1cwjvAWIQQxRWj9CJ6BK8tFHiuhSQa3
|
||||||
|
VzCO8AKeAQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAAD+HwEAzElDjL9DRUnWd4yK
|
||||||
|
jNoB+yT6RAQ9kD6BgRs/vKyQtqcBANfIysKFneE0B4lExhh6hB2cGoMR/YMhJHSd
|
||||||
|
9zorxH4KuDgEYrcXbxIKKwYBBAGXVQEFAQEHQMmhBx59elwIbvvv3UOCLZn2VJDE
|
||||||
|
gkOGq1DOpYRNXe8FAwEIB4h1BBgWCgAdBQJitxdvAp4BApsMBRYCAwEABAsJCAcF
|
||||||
|
FQoJCAsACgkQoUkGt1cwjvDeBgEA9rsAaBuE5QWoZSH6FxHGpq5XY1rFpmvFKn7g
|
||||||
|
hZ33p6ABAJZJx0RQZGDaI5f46Pjph2U7pvLm18mXNd5cYPQtcFoFuDMEYrcXcBYJ
|
||||||
|
KwYBBAHaRw8BAQdAwdROT7LazWiJsEWF/bXjcAybl7TE3avv7GTVUT00MK2I1QQY
|
||||||
|
FgoAfQUCYrcXcAKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3F3AA
|
||||||
|
CgkQKvTwayMtR7nA+wEAzKlKeGvOSUtp5R07BTmOchkP0T3sZ0L4MvBBtpAuU5YA
|
||||||
|
/jNm1162I/ceEEtKgyKp0wC5pqYR0b+AWgB0tPaMfaoJAAoJEKFJBrdXMI7w608A
|
||||||
|
/0nV1NXH/U0pRzmNNeRJWAMlFXUdxhhYSlqrqYf2GQRlAP9NR9iMwpA0gFP+Uey3
|
||||||
|
bCNC8MxtZLKhPkz2Rz4pnnfaDA==
|
||||||
|
=y1eO
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,25 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3B24 FD39 4732 D6A9 CF6E 071E 21AD CF3B 9F33 49FE
|
||||||
|
Comment: Foo Bank Employee <employee@foobank.com>
|
||||||
|
|
||||||
|
mDMEYrcZeRYJKwYBBAHaRw8BAQdAl9j10kv/7NRAZe+yATf7kkXOoHwkxaKkHzM3
|
||||||
|
wMihWlu0KEZvbyBCYW5rIEVtcGxveWVlIDxlbXBsb3llZUBmb29iYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYrcZeQkQIa3PO58zSf4WIQQ7JP05RzLWqc9uBx4hrc87nzNJ/gKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAAA1aAEAthiiVUcYiKVyzfzbrZLkQlTW
|
||||||
|
NR6fu85fR5rPns2NUdwA/2vkrneDmkE04osRwUGLMh30iQzduQ3aFW0hEe2OmDUO
|
||||||
|
iJ4EEBYKAFAFAmLNTFYJEKFJBrdXMI7wFiEEMUVo/QiegSvLRR4roUkGt1cwjvAo
|
||||||
|
FIAAAAAAFwAIYWZmaWxpYXRpb25AZm9vYmFuay5jb21lbXBsb3llZQAAVjoBAOqF
|
||||||
|
r5tscY9sx4sxEjgDJ+v4+Jd4KxU8bNljzde4BG+AAP9Dj2IhrpNe8CJJlncV2TC1
|
||||||
|
55IXAr/DLYcKwzqEJrVxBLg4BGK3GXkSCisGAQQBl1UBBQEBB0ArMHy+cSuGxSdZ
|
||||||
|
ScGncoxzB9ZLioxTRlR5Mqd/M2rNGAMBCAeIdQQYFgoAHQUCYrcZeQKeAQKbDAUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLAAoJECGtzzufM0n+vDoA/A3p3LMYSUcvELY9Af3nC6/4
|
||||||
|
71r5B3MDnURShddOtcRyAP96J1i5ExKnC+Ltw36/QtyxfyHp9Pr9Fw6BX/zq4EFo
|
||||||
|
CrgzBGK3GXkWCSsGAQQB2kcPAQEHQPlVJ9tosjkDY81zIKll52Gh00rhhXY1jFEx
|
||||||
|
x248kkrjiNUEGBYKAH0FAmK3GXkCngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkW
|
||||||
|
CgAGBQJitxl5AAoJEJxjnlk3tCvcxesBAIf5xQYgRFfDeQlr63uglNCsvOXMa8BN
|
||||||
|
LzgObT2nn8LrAQC+sqoWycLRFdFqg29E4OjhZd3iRvFWDoIfs67d9ywBDgAKCRAh
|
||||||
|
rc87nzNJ/jWHAP4zs2k1MtV2eOcjUzdt8cfMsiHcD29uJsv6O628gqVdqgD/dvb5
|
||||||
|
LPKxFPnfhSGOip0q2USrbBZLgupBjsNuVVu2IgM=
|
||||||
|
=DqW1
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: CEE5 FB5D C524 84A6 9B73 9FAD 7DA0 2993 D86B 0355
|
||||||
|
Comment: Bar Bank CA <ca@barbank.com>
|
||||||
|
|
||||||
|
mDMEYs1BgxYJKwYBBAHaRw8BAQdA3hOlkHAVyvTwePiifKnwLhkcJnswNidJ7dWo
|
||||||
|
UKEQlZW0HEJhciBCYW5rIENBIDxjYUBiYXJiYW5rLmNvbT6IjwQTFgoAQQUCYs1B
|
||||||
|
gwkQfaApk9hrA1UWIQTO5ftdxSSEpptzn619oCmT2GsDVQKeAQKbAQUWAgMBAAQL
|
||||||
|
CQgHBRUKCQgLApkBAABltgEA4Ob86bhjLa6Xg4wnzYIGH21WEUlc37BBaqwr4qvf
|
||||||
|
sA4A/0BzOdTy3Wty5DkdMiA2yPOxIVuHbTD8pgqpne2yoegNuDgEYs1BgxIKKwYB
|
||||||
|
BAGXVQEFAQEHQDVHLNRE4Gtg9/BzwSUMW3psBD7OUm4Df0ggilvLZhMcAwEIB4h1
|
||||||
|
BBgWCgAdBQJizUGDAp4BApsMBRYCAwEABAsJCAcFFQoJCAsACgkQfaApk9hrA1Wr
|
||||||
|
YAEAsZsEoUfAPIG6d9gtK7Zmm3zt+xiTELW08E/pwjmFTmEBAODICUhsEelkdXrb
|
||||||
|
IkL2oWAKoxlsbkyA6mNXBt5UXQcJuDMEYs1BgxYJKwYBBAHaRw8BAQdARHF/sgST
|
||||||
|
B38osF0+XA9N2htsMIrb322j3LQdrk0M77SI1QQYFgoAfQUCYs1BgwKeAQKbAgUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmLNQYMACgkQtEK9w/vjcduqJwD+KW23
|
||||||
|
+689GXtu4k3PW60GPsiue22lMGwZY7hsWvZB1hkBAPER8PMs0MJAQzcs2u6bYPMD
|
||||||
|
I921umqX8Yvsob1kzs0FAAoJEH2gKZPYawNVdKwBAKz5zfwEKZ2dGPCsUJzAXfPx
|
||||||
|
e0LmATcvS5g/LvAreD0KAQDfpfMFO2EqQu6wDt+e5MH3YCjGsaYwvjB1elj1zhbl
|
||||||
|
Ag==
|
||||||
|
=Xlkn
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,24 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: CEE5 FB5D C524 84A6 9B73 9FAD 7DA0 2993 D86B 0355
|
||||||
|
Comment: Bar Bank CA <ca@barbank.com>
|
||||||
|
|
||||||
|
lFgEYs1BgxYJKwYBBAHaRw8BAQdA3hOlkHAVyvTwePiifKnwLhkcJnswNidJ7dWo
|
||||||
|
UKEQlZUAAQD94AUX6NT0z3kvWb1CXxgZacF3w/r2IWV0lSc6WZDcQRBTtBxCYXIg
|
||||||
|
QmFuayBDQSA8Y2FAYmFyYmFuay5jb20+iI8EExYKAEEFAmLNQYMJEH2gKZPYawNV
|
||||||
|
FiEEzuX7XcUkhKabc5+tfaApk9hrA1UCngECmwEFFgIDAQAECwkIBwUVCgkICwKZ
|
||||||
|
AQAAZbYBAODm/Om4Yy2ul4OMJ82CBh9tVhFJXN+wQWqsK+Kr37AOAP9AcznU8t1r
|
||||||
|
cuQ5HTIgNsjzsSFbh20w/KYKqZ3tsqHoDZxdBGLNQYMSCisGAQQBl1UBBQEBB0A1
|
||||||
|
RyzUROBrYPfwc8ElDFt6bAQ+zlJuA39IIIpby2YTHAMBCAcAAP9FU6uepd97vJ4y
|
||||||
|
VTcvtzPXG9jvpgNw50pDfV90z6VAwBEaiHUEGBYKAB0FAmLNQYMCngECmwwFFgID
|
||||||
|
AQAECwkIBwUVCgkICwAKCRB9oCmT2GsDVatgAQCxmwShR8A8gbp32C0rtmabfO37
|
||||||
|
GJMQtbTwT+nCOYVOYQEA4MgJSGwR6WR1etsiQvahYAqjGWxuTIDqY1cG3lRdBwmc
|
||||||
|
WARizUGDFgkrBgEEAdpHDwEBB0BEcX+yBJMHfyiwXT5cD03aG2wwitvfbaPctB2u
|
||||||
|
TQzvtAABAJJiLD7fXGdr/liZ//EOhJ4YicrcxXahud6q3OYA1QUJEYSI1QQYFgoA
|
||||||
|
fQUCYs1BgwKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmLNQYMACgkQ
|
||||||
|
tEK9w/vjcduqJwD+KW23+689GXtu4k3PW60GPsiue22lMGwZY7hsWvZB1hkBAPER
|
||||||
|
8PMs0MJAQzcs2u6bYPMDI921umqX8Yvsob1kzs0FAAoJEH2gKZPYawNVdKwBAKz5
|
||||||
|
zfwEKZ2dGPCsUJzAXfPxe0LmATcvS5g/LvAreD0KAQDfpfMFO2EqQu6wDt+e5MH3
|
||||||
|
YCjGsaYwvjB1elj1zhblAg==
|
||||||
|
=owuy
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 447A 82AA 03F7 D7A4 B1DA 4D7C 8AD2 3357 EB78 BB08
|
||||||
|
Comment: Bar Bank Employee <employee@barbank.com>
|
||||||
|
|
||||||
|
mDMEYs1CXRYJKwYBBAHaRw8BAQdAeMjyfqInb8aZppFsKHdndoeL3j08Z5CtagKz
|
||||||
|
KPb6YGO0KEJhciBCYW5rIEVtcGxveWVlIDxlbXBsb3llZUBiYXJiYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYs1CXQkQitIzV+t4uwgWIQREeoKqA/fXpLHaTXyK0jNX63i7CAKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAACgcgD7Bk2Hu+Lu3aA+IyzFyTQOw8zQ
|
||||||
|
RUeA/X8neEIezYDTC+MA/jGFyiKW7b+6W3zgdIgiHMeWhG3Wx2oOC1izW2+tP2cJ
|
||||||
|
uDgEYs1CXRIKKwYBBAGXVQEFAQEHQGrbXqc/inD2vUXw4xxRaKxhS8549R5Qs8th
|
||||||
|
X6NfxR0GAwEIB4h1BBgWCgAdBQJizUJdAp4BApsMBRYCAwEABAsJCAcFFQoJCAsA
|
||||||
|
CgkQitIzV+t4uwijlAD8D3MPPxeuO1skgrrQneSbC9iPKcX0iTPIVOPiw14eElMA
|
||||||
|
/3Z1Na9uiATDM+EFuh/DM5Ps9eDuVpDy/15OqvnSVZ8HuDMEYs1CXRYJKwYBBAHa
|
||||||
|
Rw8BAQdARX1KmiiBbYetUhpT3ndbfVx4O8OYFYwUFBBrdCzPogGI1QQYFgoAfQUC
|
||||||
|
Ys1CXQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmLNQl0ACgkQ0bcL
|
||||||
|
6V1JVto+wAD/aCJkdwZPSfICiM92zUh8gT3t3ICVWCN9tMfcfhA1WwAA/12lqQNn
|
||||||
|
Jr+rwz/Cdk7I4F/50eJSu8NvGIGji2PYA0kGAAoJEIrSM1freLsIw+AA/ih/GiKK
|
||||||
|
3/ueq+d2TnQ2SIz0BvTJNwueNj5vbxgwMtpzAQCmgSUjXk0OT+5NdBEq1escqg5H
|
||||||
|
BIrddE9JIZiAw6GTBA==
|
||||||
|
=F0kp
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,24 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 447A 82AA 03F7 D7A4 B1DA 4D7C 8AD2 3357 EB78 BB08
|
||||||
|
Comment: Bar Bank Employee <employee@barbank.com>
|
||||||
|
|
||||||
|
lFgEYs1CXRYJKwYBBAHaRw8BAQdAeMjyfqInb8aZppFsKHdndoeL3j08Z5CtagKz
|
||||||
|
KPb6YGMAAP0WnOME3m2zmC6ujA1r5s1RLCtIsrWnkX62ICDCJzIWLA8ftChCYXIg
|
||||||
|
QmFuayBFbXBsb3llZSA8ZW1wbG95ZWVAYmFyYmFuay5jb20+iI8EExYKAEEFAmLN
|
||||||
|
Ql0JEIrSM1freLsIFiEERHqCqgP316Sx2k18itIzV+t4uwgCngECmwEFFgIDAQAE
|
||||||
|
CwkIBwUVCgkICwKZAQAAoHIA+wZNh7vi7t2gPiMsxck0DsPM0EVHgP1/J3hCHs2A
|
||||||
|
0wvjAP4xhcoilu2/ult84HSIIhzHloRt1sdqDgtYs1tvrT9nCZxdBGLNQl0SCisG
|
||||||
|
AQQBl1UBBQEBB0Bq216nP4pw9r1F8OMcUWisYUvOePUeULPLYV+jX8UdBgMBCAcA
|
||||||
|
AP9AYnLs0zkVSsWMxZDMTCoW1fjrgjzOMGeZRtsvrcUA2BF2iHUEGBYKAB0FAmLN
|
||||||
|
Ql0CngECmwwFFgIDAQAECwkIBwUVCgkICwAKCRCK0jNX63i7CKOUAPwPcw8/F647
|
||||||
|
WySCutCd5JsL2I8pxfSJM8hU4+LDXh4SUwD/dnU1r26IBMMz4QW6H8Mzk+z14O5W
|
||||||
|
kPL/Xk6q+dJVnwecWARizUJdFgkrBgEEAdpHDwEBB0BFfUqaKIFth61SGlPed1t9
|
||||||
|
XHg7w5gVjBQUEGt0LM+iAQAA/3fH0f3QPCOEpByws3f4Ovqjc+IzwFmA6mmwlxN2
|
||||||
|
9wNpEs6I1QQYFgoAfQUCYs1CXQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYK
|
||||||
|
AAYFAmLNQl0ACgkQ0bcL6V1JVto+wAD/aCJkdwZPSfICiM92zUh8gT3t3ICVWCN9
|
||||||
|
tMfcfhA1WwAA/12lqQNnJr+rwz/Cdk7I4F/50eJSu8NvGIGji2PYA0kGAAoJEIrS
|
||||||
|
M1freLsIw+AA/ih/GiKK3/ueq+d2TnQ2SIz0BvTJNwueNj5vbxgwMtpzAQCmgSUj
|
||||||
|
Xk0OT+5NdBEq1escqg5HBIrddE9JIZiAw6GTBA==
|
||||||
|
=7A42
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: E5C1 A41B E6BF 8E3D 595B 7214 2284 3AF5 6677 E9B0
|
||||||
|
Comment: Foo Bank Employee (Attacker) <employee@foobank.com>
|
||||||
|
|
||||||
|
mDMEYs1CoBYJKwYBBAHaRw8BAQdAKjGuG4PPeUX1utitGGofxfcD5Sqf7c9CtyFA
|
||||||
|
qXA/gd60M0ZvbyBCYW5rIEVtcGxveWVlIChBdHRhY2tlcikgPGVtcGxveWVlQGZv
|
||||||
|
b2JhbmsuY29tPoiPBBMWCgBBBQJizUKgCRAihDr1ZnfpsBYhBOXBpBvmv449WVty
|
||||||
|
FCKEOvVmd+mwAp4BApsBBRYCAwEABAsJCAcFFQoJCAsCmQEAAAorAP9E0cnmX26P
|
||||||
|
zIcvmYXqCH4gfkH/18efgKAtLxFwz3yxuwD+KFj4xDxWy/KTmFRhJmFDBhJsNUiH
|
||||||
|
tNEbVpBV1GiVLQ24OARizUKgEgorBgEEAZdVAQUBAQdAU05+Xcun+77TCwhuwW/Y
|
||||||
|
zdKexCD+6u4EPUXyDKo0rjMDAQgHiHUEGBYKAB0FAmLNQqACngECmwwFFgIDAQAE
|
||||||
|
CwkIBwUVCgkICwAKCRAihDr1ZnfpsHH/AQDsxQe/sYVqwgtSFbOxw/hmGMEmMOwx
|
||||||
|
E5B+Pk7lLGcC3gEAuaFwRb4UgOeadQQ7eerxE0djYjL+wpqYLkYZrWI1dAy4MwRi
|
||||||
|
zUKgFgkrBgEEAdpHDwEBB0Dc1odFo5f84ciLYjkWoH0jAMlZxc/TLMS1yi5lrohX
|
||||||
|
M4jVBBgWCgB9BQJizUKgAp4BApsCBRYCAwEABAsJCAcFFQoJCAtfIAQZFgoABgUC
|
||||||
|
Ys1CoAAKCRDcHi36XF9/A/pLAQD7tDyLsbP+s6jV4ZloujljLdxIlhg+g/87ruhc
|
||||||
|
ISPRKQD/bTubvAzC8ixoYAWGPZOEut03b+zJ4g1l8SHXVCb+HwkACgkQIoQ69WZ3
|
||||||
|
6bAdwgEAhZb7c0u07FlgxXkEIPIt45DwZbML37hxaVjF08NlwssBAJInWO4Gcj8T
|
||||||
|
L0GLRaWEF+8dpPp+WtgklVkFel7f2XoK
|
||||||
|
=UN4g
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,24 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: E5C1 A41B E6BF 8E3D 595B 7214 2284 3AF5 6677 E9B0
|
||||||
|
Comment: Foo Bank Employee (Attacker) <employee@foobank.com>
|
||||||
|
|
||||||
|
lFgEYs1CoBYJKwYBBAHaRw8BAQdAKjGuG4PPeUX1utitGGofxfcD5Sqf7c9CtyFA
|
||||||
|
qXA/gd4AAP4vJXkVBVsASvS7pwIJXVuqKDb7yeCaR6Bjh9ihE1tZQw49tDNGb28g
|
||||||
|
QmFuayBFbXBsb3llZSAoQXR0YWNrZXIpIDxlbXBsb3llZUBmb29iYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYs1CoAkQIoQ69WZ36bAWIQTlwaQb5r+OPVlbchQihDr1ZnfpsAKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAAAKKwD/RNHJ5l9uj8yHL5mF6gh+IH5B
|
||||||
|
/9fHn4CgLS8RcM98sbsA/ihY+MQ8Vsvyk5hUYSZhQwYSbDVIh7TRG1aQVdRolS0N
|
||||||
|
nF0EYs1CoBIKKwYBBAGXVQEFAQEHQFNOfl3Lp/u+0wsIbsFv2M3SnsQg/uruBD1F
|
||||||
|
8gyqNK4zAwEIBwAA/2grdpHBu9eI82YNrx+/ljb69FIYK2ttBVmL5awfh9rgEWiI
|
||||||
|
dQQYFgoAHQUCYs1CoAKeAQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJECKEOvVmd+mw
|
||||||
|
cf8BAOzFB7+xhWrCC1IVs7HD+GYYwSYw7DETkH4+TuUsZwLeAQC5oXBFvhSA55p1
|
||||||
|
BDt56vETR2NiMv7CmpguRhmtYjV0DJxYBGLNQqAWCSsGAQQB2kcPAQEHQNzWh0Wj
|
||||||
|
l/zhyItiORagfSMAyVnFz9MsxLXKLmWuiFczAAEA+xMd+XrMwFJisctVMfZaaPDR
|
||||||
|
QZ7EAVeCZU2UAe0u1ssQ2ojVBBgWCgB9BQJizUKgAp4BApsCBRYCAwEABAsJCAcF
|
||||||
|
FQoJCAtfIAQZFgoABgUCYs1CoAAKCRDcHi36XF9/A/pLAQD7tDyLsbP+s6jV4Zlo
|
||||||
|
ujljLdxIlhg+g/87ruhcISPRKQD/bTubvAzC8ixoYAWGPZOEut03b+zJ4g1l8SHX
|
||||||
|
VCb+HwkACgkQIoQ69WZ36bAdwgEAhZb7c0u07FlgxXkEIPIt45DwZbML37hxaVjF
|
||||||
|
08NlwssBAJInWO4Gcj8TL0GLRaWEF+8dpPp+WtgklVkFel7f2XoK
|
||||||
|
=saRS
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: A688 ECB2 69B3 8161 DA4D 738F F5F1 E3B5 368D 6CA7
|
||||||
|
Comment: Foo Bank Admin <admin@foobank.com>
|
||||||
|
|
||||||
|
mDMEYrcZeRYJKwYBBAHaRw8BAQdABkxvWXwHDD6B3hXYQehQkil3e3Gcg5mNbOdS
|
||||||
|
9DSeny20IkZvbyBCYW5rIEFkbWluIDxhZG1pbkBmb29iYW5rLmNvbT6IjwQTFgoA
|
||||||
|
QQUCYrcZeQkQ9fHjtTaNbKcWIQSmiOyyabOBYdpNc4/18eO1No1spwKeAQKbAQUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLApkBAABPGwEAv0TWDMkJV6QiIgm8V4b9uIEzMpQku4UM
|
||||||
|
FBHvMKXh0W8A/1pocJBG+K9srn8NJlPBul7duoNbkzzHANkytFVEBOgEuDgEYrcZ
|
||||||
|
eRIKKwYBBAGXVQEFAQEHQDd1fqNPF27j+Z8BPtbyoU6sp63UQfBhJrUKNFjpWNZr
|
||||||
|
AwEIB4h1BBgWCgAdBQJitxl5Ap4BApsMBRYCAwEABAsJCAcFFQoJCAsACgkQ9fHj
|
||||||
|
tTaNbKdmNwEAzTQAJ/ML5puyGHR9zCbuAonDB0lKoXlJeWX7YpsLSugA/3M4Ygzp
|
||||||
|
BfoRNbehCbc2hcd/hbW9gKQs2k2iCUYDoPINuDMEYrcZeRYJKwYBBAHaRw8BAQdA
|
||||||
|
IF2e85PlS4PWquE3NLE59A1tr9KPxEznQ0EjG/DfefiI1QQYFgoAfQUCYrcZeQKe
|
||||||
|
AQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3GXkACgkQUqp0e41/iO+P
|
||||||
|
swD+I+dgdOrj/jflr3D0Th8cugj9zFzwFYn9aaGmiee5wv8A/RvvJoiwHMTi3QPv
|
||||||
|
R4zGdF5pibOccbWr/dggFjKXTmoFAAoJEPXx47U2jWynVbEBANEjxzV8KnujGor7
|
||||||
|
9Mc1ag9wxyDgihXRowsoKEnSkyHQAQD6n0Pf1q8fl7BxbreVeY+0HN2swKlO9TvO
|
||||||
|
303a3X6/BQ==
|
||||||
|
=CESR
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: A688 ECB2 69B3 8161 DA4D 738F F5F1 E3B5 368D 6CA7
|
||||||
|
Comment: Foo Bank Admin <admin@foobank.com>
|
||||||
|
|
||||||
|
lIYEYrcZeRYJKwYBBAHaRw8BAQdABkxvWXwHDD6B3hXYQehQkil3e3Gcg5mNbOdS
|
||||||
|
9DSeny3+CQMCmWVHhM7xa9pgkX1Z8T7FcGWpMD91IgrF+7Bh97UtTFw8a71ixXww
|
||||||
|
pH/86zqEE9mry/95KvxsiCSPYwKhS0j4S20mZfQriWvpM3gCZSbhMrQiRm9vIEJh
|
||||||
|
bmsgQWRtaW4gPGFkbWluQGZvb2JhbmsuY29tPoiPBBMWCgBBBQJitxl5CRD18eO1
|
||||||
|
No1spxYhBKaI7LJps4Fh2k1zj/Xx47U2jWynAp4BApsBBRYCAwEABAsJCAcFFQoJ
|
||||||
|
CAsCmQEAAE8bAQC/RNYMyQlXpCIiCbxXhv24gTMylCS7hQwUEe8wpeHRbwD/Wmhw
|
||||||
|
kEb4r2yufw0mU8G6Xt26g1uTPMcA2TK0VUQE6ASciwRitxl5EgorBgEEAZdVAQUB
|
||||||
|
AQdAN3V+o08XbuP5nwE+1vKhTqynrdRB8GEmtQo0WOlY1msDAQgH/gkDApllR4TO
|
||||||
|
8WvaYNfxPfMWsBQLze2hTDxhCds/kO7WSwJw0cN3IzGlCrv+KSId5n6Rfz4NtlWN
|
||||||
|
yBOIecPZbzK4H0RSIc7jqiNRMqznpclwNYGIdQQYFgoAHQUCYrcZeQKeAQKbDAUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLAAoJEPXx47U2jWynZjcBAM00ACfzC+abshh0fcwm7gKJ
|
||||||
|
wwdJSqF5SXll+2KbC0roAP9zOGIM6QX6ETW3oQm3NoXHf4W1vYCkLNpNoglGA6Dy
|
||||||
|
DZyGBGK3GXkWCSsGAQQB2kcPAQEHQCBdnvOT5UuD1qrhNzSxOfQNba/Sj8RM50NB
|
||||||
|
Ixvw33n4/gkDApllR4TO8WvaYFyjXSJ54rtghVxVYEUd4OFWaGmKO5+KMEgqCqv4
|
||||||
|
TWhfaqT+wV5hKJbx/IkgZFS9viFTK7BEEhaApslO/TuE6nFSoi7gVw+I1QQYFgoA
|
||||||
|
fQUCYrcZeQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3GXkACgkQ
|
||||||
|
Uqp0e41/iO+PswD+I+dgdOrj/jflr3D0Th8cugj9zFzwFYn9aaGmiee5wv8A/Rvv
|
||||||
|
JoiwHMTi3QPvR4zGdF5pibOccbWr/dggFjKXTmoFAAoJEPXx47U2jWynVbEBANEj
|
||||||
|
xzV8KnujGor79Mc1ag9wxyDgihXRowsoKEnSkyHQAQD6n0Pf1q8fl7BxbreVeY+0
|
||||||
|
HN2swKlO9TvO303a3X6/BQ==
|
||||||
|
=4xhi
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,23 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3145 68FD 089E 812B CB45 1E2B A149 06B7 5730 8EF0
|
||||||
|
Comment: Foo Bank CA <ca@foobank.com>
|
||||||
|
Comment: Freshly generated cert
|
||||||
|
|
||||||
|
mDMEYrcXbxYJKwYBBAHaRw8BAQdAPIIGHwbBzEIExd70jtw7uDvOymt0nU83uLqR
|
||||||
|
4Og+cxC0HEZvbyBCYW5rIENBIDxjYUBmb29iYW5rLmNvbT6IjwQTFgoAQQUCYrcX
|
||||||
|
bwkQoUkGt1cwjvAWIQQxRWj9CJ6BK8tFHiuhSQa3VzCO8AKeAQKbAQUWAgMBAAQL
|
||||||
|
CQgHBRUKCQgLApkBAAD+HwEAzElDjL9DRUnWd4yKjNoB+yT6RAQ9kD6BgRs/vKyQ
|
||||||
|
tqcBANfIysKFneE0B4lExhh6hB2cGoMR/YMhJHSd9zorxH4KuDgEYrcXbxIKKwYB
|
||||||
|
BAGXVQEFAQEHQMmhBx59elwIbvvv3UOCLZn2VJDEgkOGq1DOpYRNXe8FAwEIB4h1
|
||||||
|
BBgWCgAdBQJitxdvAp4BApsMBRYCAwEABAsJCAcFFQoJCAsACgkQoUkGt1cwjvDe
|
||||||
|
BgEA9rsAaBuE5QWoZSH6FxHGpq5XY1rFpmvFKn7ghZ33p6ABAJZJx0RQZGDaI5f4
|
||||||
|
6Pjph2U7pvLm18mXNd5cYPQtcFoFuDMEYrcXcBYJKwYBBAHaRw8BAQdAwdROT7La
|
||||||
|
zWiJsEWF/bXjcAybl7TE3avv7GTVUT00MK2I1QQYFgoAfQUCYrcXcAKeAQKbAgUW
|
||||||
|
AgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3F3AACgkQKvTwayMtR7nA+wEAzKlK
|
||||||
|
eGvOSUtp5R07BTmOchkP0T3sZ0L4MvBBtpAuU5YA/jNm1162I/ceEEtKgyKp0wC5
|
||||||
|
pqYR0b+AWgB0tPaMfaoJAAoJEKFJBrdXMI7w608A/0nV1NXH/U0pRzmNNeRJWAMl
|
||||||
|
FXUdxhhYSlqrqYf2GQRlAP9NR9iMwpA0gFP+Uey3bCNC8MxtZLKhPkz2Rz4pnnfa
|
||||||
|
DA==
|
||||||
|
=5bcR
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3145 68FD 089E 812B CB45 1E2B A149 06B7 5730 8EF0
|
||||||
|
Comment: Foo Bank CA <ca@foobank.com>
|
||||||
|
Comment: Freshly generated key
|
||||||
|
|
||||||
|
lIYEYrcXbxYJKwYBBAHaRw8BAQdAPIIGHwbBzEIExd70jtw7uDvOymt0nU83uLqR
|
||||||
|
4Og+cxD+CQMCgCIAcSyeuXJgGMgKUCcU6tDwfGXgIVy0wCoDsSX2qWTKkyOYf7fu
|
||||||
|
Kw0BmQ4bFhQtC9hpPDhCKuR0cLUV8f0TEU0/Vq4n5hNy2erDW60KFLQcRm9vIEJh
|
||||||
|
bmsgQ0EgPGNhQGZvb2JhbmsuY29tPoiPBBMWCgBBBQJitxdvCRChSQa3VzCO8BYh
|
||||||
|
BDFFaP0InoEry0UeK6FJBrdXMI7wAp4BApsBBRYCAwEABAsJCAcFFQoJCAsCmQEA
|
||||||
|
AP4fAQDMSUOMv0NFSdZ3jIqM2gH7JPpEBD2QPoGBGz+8rJC2pwEA18jKwoWd4TQH
|
||||||
|
iUTGGHqEHZwagxH9gyEkdJ33OivEfgqciwRitxdvEgorBgEEAZdVAQUBAQdAyaEH
|
||||||
|
Hn16XAhu++/dQ4ItmfZUkMSCQ4arUM6lhE1d7wUDAQgH/gkDAoAiAHEsnrlyYPCE
|
||||||
|
d+xi8TsvxtcWq7lO+wwMxg/et4nFijmCDwK5/1duRutt/UYj1PU1cicfJ9choM6l
|
||||||
|
5qui74PBr5yTkUvNhAOjWfH60heIdQQYFgoAHQUCYrcXbwKeAQKbDAUWAgMBAAQL
|
||||||
|
CQgHBRUKCQgLAAoJEKFJBrdXMI7w3gYBAPa7AGgbhOUFqGUh+hcRxqauV2NaxaZr
|
||||||
|
xSp+4IWd96egAQCWScdEUGRg2iOX+Oj46YdlO6by5tfJlzXeXGD0LXBaBZyGBGK3
|
||||||
|
F3AWCSsGAQQB2kcPAQEHQMHUTk+y2s1oibBFhf2143AMm5e0xN2r7+xk1VE9NDCt
|
||||||
|
/gkDAoAiAHEsnrlyYFpx33LyuL4N/uccem+lZPCwjSum+Turs6vZQNY3toahx0fm
|
||||||
|
i68BGm1Eu716NN/5AV3nXXa9jmf6PsesiEvfWWITo8A7/fuI1QQYFgoAfQUCYrcX
|
||||||
|
cAKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3F3AACgkQKvTwayMt
|
||||||
|
R7nA+wEAzKlKeGvOSUtp5R07BTmOchkP0T3sZ0L4MvBBtpAuU5YA/jNm1162I/ce
|
||||||
|
EEtKgyKp0wC5pqYR0b+AWgB0tPaMfaoJAAoJEKFJBrdXMI7w608A/0nV1NXH/U0p
|
||||||
|
RzmNNeRJWAMlFXUdxhhYSlqrqYf2GQRlAP9NR9iMwpA0gFP+Uey3bCNC8MxtZLKh
|
||||||
|
Pkz2Rz4pnnfaDA==
|
||||||
|
=roYK
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 2C4C CA4C 8917 7FD1 91EE A3E0 F8BB 6510 168F D2BF
|
||||||
|
Comment: Customer <customer@example.com>
|
||||||
|
|
||||||
|
mDMEYrcaYxYJKwYBBAHaRw8BAQdAIt6xhlPPq2wTnLO2CqMvoP2yk68NBSPJWkse
|
||||||
|
85lCWee0H0N1c3RvbWVyIDxjdXN0b21lckBleGFtcGxlLmNvbT6IjwQTFgoAQQUC
|
||||||
|
YrcaYwkQ+LtlEBaP0r8WIQQsTMpMiRd/0ZHuo+D4u2UQFo/SvwKeAQKbAQUWAgMB
|
||||||
|
AAQLCQgHBRUKCQgLApkBAAB3agEAmnfM6RToSpLfBFXOERCAz0v9FYfskTz7bsGM
|
||||||
|
CPSEgYcBAK85o67OTq5y8JhHHFfHvHeIIaE/IAzJLQHRNT3pvJ8KuDgEYrcaYxIK
|
||||||
|
KwYBBAGXVQEFAQEHQGZVHqBfmrVSMbIFQUSE9bnj9JU/W/JUFuPHbd5csPpdAwEI
|
||||||
|
B4h1BBgWCgAdBQJitxpjAp4BApsMBRYCAwEABAsJCAcFFQoJCAsACgkQ+LtlEBaP
|
||||||
|
0r/XhAD+LHlbWcUil8HmnWpBSwcv3wBP1vnt4zPOlm1pkfmgq/MA/3hb+I0kQNMR
|
||||||
|
7ux3bYORuLiHulapQtYQG5GGRfbvJqMPuDMEYrcaYxYJKwYBBAHaRw8BAQdAy3Jc
|
||||||
|
mVMbgm6VT88y2xNCFrePTBXaroz90pI9mWBjvMGI1QQYFgoAfQUCYrcaYwKeAQKb
|
||||||
|
AgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3GmMACgkQZTy2QngzKnRNbwEA
|
||||||
|
pyuSMaZgI+kOaiFiIxCGXoR/zhYKKMyoq5JlF1W+cwQBALwz2ixIlP3jzT7wJnDf
|
||||||
|
hcK7n/SMlXD4MIqR2CQkxRYHAAoJEPi7ZRAWj9K/Cb0A/24XLgqc5mj+MT0gyXRU
|
||||||
|
GBOpoTlpZ86bpb4LcLycRU+0AQDuAq/i1n6e/noMRsbOh0WYZbqAbOgiv9DVJcRQ
|
||||||
|
4kfpAg==
|
||||||
|
=r4Bk
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,24 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 2C4C CA4C 8917 7FD1 91EE A3E0 F8BB 6510 168F D2BF
|
||||||
|
Comment: Customer <customer@example.com>
|
||||||
|
|
||||||
|
lFgEYrcaYxYJKwYBBAHaRw8BAQdAIt6xhlPPq2wTnLO2CqMvoP2yk68NBSPJWkse
|
||||||
|
85lCWecAAP9xVDxOuRZ5pDo5cSKIJf50dMNp/I/xHkNDHPNcI+ManQ9HtB9DdXN0
|
||||||
|
b21lciA8Y3VzdG9tZXJAZXhhbXBsZS5jb20+iI8EExYKAEEFAmK3GmMJEPi7ZRAW
|
||||||
|
j9K/FiEELEzKTIkXf9GR7qPg+LtlEBaP0r8CngECmwEFFgIDAQAECwkIBwUVCgkI
|
||||||
|
CwKZAQAAd2oBAJp3zOkU6EqS3wRVzhEQgM9L/RWH7JE8+27BjAj0hIGHAQCvOaOu
|
||||||
|
zk6ucvCYRxxXx7x3iCGhPyAMyS0B0TU96byfCpxdBGK3GmMSCisGAQQBl1UBBQEB
|
||||||
|
B0BmVR6gX5q1UjGyBUFEhPW54/SVP1vyVBbjx23eXLD6XQMBCAcAAP9iOym80xxC
|
||||||
|
El9TTF/k7mfRBjNocGBMMUP5nnkPwdag2A+KiHUEGBYKAB0FAmK3GmMCngECmwwF
|
||||||
|
FgIDAQAECwkIBwUVCgkICwAKCRD4u2UQFo/Sv9eEAP4seVtZxSKXweadakFLBy/f
|
||||||
|
AE/W+e3jM86WbWmR+aCr8wD/eFv4jSRA0xHu7Hdtg5G4uIe6VqlC1hAbkYZF9u8m
|
||||||
|
ow+cWARitxpjFgkrBgEEAdpHDwEBB0DLclyZUxuCbpVPzzLbE0IWt49MFdqujP3S
|
||||||
|
kj2ZYGO8wQABAPY7EMCZEq/sSDkldwv/43GUe4KuDay7Q6jHugO+YkkqD3iI1QQY
|
||||||
|
FgoAfQUCYrcaYwKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3GmMA
|
||||||
|
CgkQZTy2QngzKnRNbwEApyuSMaZgI+kOaiFiIxCGXoR/zhYKKMyoq5JlF1W+cwQB
|
||||||
|
ALwz2ixIlP3jzT7wJnDfhcK7n/SMlXD4MIqR2CQkxRYHAAoJEPi7ZRAWj9K/Cb0A
|
||||||
|
/24XLgqc5mj+MT0gyXRUGBOpoTlpZ86bpb4LcLycRU+0AQDuAq/i1n6e/noMRsbO
|
||||||
|
h0WYZbqAbOgiv9DVJcRQ4kfpAg==
|
||||||
|
=th8Q
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3B24 FD39 4732 D6A9 CF6E 071E 21AD CF3B 9F33 49FE
|
||||||
|
Comment: Foo Bank Employee <employee@foobank.com>
|
||||||
|
|
||||||
|
mDMEYrcZeRYJKwYBBAHaRw8BAQdAl9j10kv/7NRAZe+yATf7kkXOoHwkxaKkHzM3
|
||||||
|
wMihWlu0KEZvbyBCYW5rIEVtcGxveWVlIDxlbXBsb3llZUBmb29iYW5rLmNvbT6I
|
||||||
|
jwQTFgoAQQUCYrcZeQkQIa3PO58zSf4WIQQ7JP05RzLWqc9uBx4hrc87nzNJ/gKe
|
||||||
|
AQKbAQUWAgMBAAQLCQgHBRUKCQgLApkBAAA1aAEAthiiVUcYiKVyzfzbrZLkQlTW
|
||||||
|
NR6fu85fR5rPns2NUdwA/2vkrneDmkE04osRwUGLMh30iQzduQ3aFW0hEe2OmDUO
|
||||||
|
uDgEYrcZeRIKKwYBBAGXVQEFAQEHQCswfL5xK4bFJ1lJwadyjHMH1kuKjFNGVHky
|
||||||
|
p38zas0YAwEIB4h1BBgWCgAdBQJitxl5Ap4BApsMBRYCAwEABAsJCAcFFQoJCAsA
|
||||||
|
CgkQIa3PO58zSf68OgD8DencsxhJRy8Qtj0B/ecLr/jvWvkHcwOdRFKF1061xHIA
|
||||||
|
/3onWLkTEqcL4u3Dfr9C3LF/Ien0+v0XDoFf/OrgQWgKuDMEYrcZeRYJKwYBBAHa
|
||||||
|
Rw8BAQdA+VUn22iyOQNjzXMgqWXnYaHTSuGFdjWMUTHHbjySSuOI1QQYFgoAfQUC
|
||||||
|
YrcZeQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3GXkACgkQnGOe
|
||||||
|
WTe0K9zF6wEAh/nFBiBEV8N5CWvre6CU0Ky85cxrwE0vOA5tPaefwusBAL6yqhbJ
|
||||||
|
wtEV0WqDb0Tg6OFl3eJG8VYOgh+zrt33LAEOAAoJECGtzzufM0n+NYcA/jOzaTUy
|
||||||
|
1XZ45yNTN23xx8yyIdwPb24my/o7rbyCpV2qAP929vks8rEU+d+FIY6KnSrZRKts
|
||||||
|
FkuC6kGOw25VW7YiAw==
|
||||||
|
=/hVO
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -0,0 +1,27 @@
|
||||||
|
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||||
|
Version: PGPainless
|
||||||
|
Comment: 3B24 FD39 4732 D6A9 CF6E 071E 21AD CF3B 9F33 49FE
|
||||||
|
Comment: Foo Bank Employee <employee@foobank.com>
|
||||||
|
|
||||||
|
lIYEYrcZeRYJKwYBBAHaRw8BAQdAl9j10kv/7NRAZe+yATf7kkXOoHwkxaKkHzM3
|
||||||
|
wMihWlv+CQMCMzeQucBpShVg5GroEDGhC62uvl+Rjki+P6aR5rCKbaoff1Y3DEGQ
|
||||||
|
LEz0InfGo4I2lLUhox1E+th6BHT+fwg7E/Qk+9j040TvEXAqHIJhXbQoRm9vIEJh
|
||||||
|
bmsgRW1wbG95ZWUgPGVtcGxveWVlQGZvb2JhbmsuY29tPoiPBBMWCgBBBQJitxl5
|
||||||
|
CRAhrc87nzNJ/hYhBDsk/TlHMtapz24HHiGtzzufM0n+Ap4BApsBBRYCAwEABAsJ
|
||||||
|
CAcFFQoJCAsCmQEAADVoAQC2GKJVRxiIpXLN/NutkuRCVNY1Hp+7zl9Hms+ezY1R
|
||||||
|
3AD/a+Sud4OaQTTiixHBQYsyHfSJDN25DdoVbSER7Y6YNQ6ciwRitxl5EgorBgEE
|
||||||
|
AZdVAQUBAQdAKzB8vnErhsUnWUnBp3KMcwfWS4qMU0ZUeTKnfzNqzRgDAQgH/gkD
|
||||||
|
AjM3kLnAaUoVYI0D8gPzG1t3dPpkNgc411bts2T9BgrZPkV7C3u338TXsFSHxTdo
|
||||||
|
vK7/l/PhikN0qKjKVG5PXnxHhu56RUYiF+XAhkjcI9qIdQQYFgoAHQUCYrcZeQKe
|
||||||
|
AQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJECGtzzufM0n+vDoA/A3p3LMYSUcvELY9
|
||||||
|
Af3nC6/471r5B3MDnURShddOtcRyAP96J1i5ExKnC+Ltw36/QtyxfyHp9Pr9Fw6B
|
||||||
|
X/zq4EFoCpyGBGK3GXkWCSsGAQQB2kcPAQEHQPlVJ9tosjkDY81zIKll52Gh00rh
|
||||||
|
hXY1jFExx248kkrj/gkDAjM3kLnAaUoVYFXrAVkSWsFeXVYLYtq0a49sc5q7Kz1K
|
||||||
|
KJmDBZKnvwgipPqf1eAkcZDSNanBZ2BO2K77Ix5FDFp67qc3XIZ6HUZqrP1siQmI
|
||||||
|
1QQYFgoAfQUCYrcZeQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmK3
|
||||||
|
GXkACgkQnGOeWTe0K9zF6wEAh/nFBiBEV8N5CWvre6CU0Ky85cxrwE0vOA5tPaef
|
||||||
|
wusBAL6yqhbJwtEV0WqDb0Tg6OFl3eJG8VYOgh+zrt33LAEOAAoJECGtzzufM0n+
|
||||||
|
NYcA/jOzaTUy1XZ45yNTN23xx8yyIdwPb24my/o7rbyCpV2qAP929vks8rEU+d+F
|
||||||
|
IY6KnSrZRKtsFkuC6kGOw25VW7YiAw==
|
||||||
|
=kvmL
|
||||||
|
-----END PGP PRIVATE KEY BLOCK-----
|
Loading…
Reference in a new issue