mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-26 04:47:59 +01:00
Introduce CertificationFactory.
This is done in an attempt to minimize the number of BC/PGPainless dependencies in wot-dijkstra
This commit is contained in:
parent
3a994625e9
commit
ab0835d176
6 changed files with 134 additions and 67 deletions
|
@ -0,0 +1,126 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.wot;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.RegularExpression;
|
||||||
|
import org.bouncycastle.bcpg.sig.TrustSignature;
|
||||||
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
|
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||||
|
import org.pgpainless.wot.dijkstra.sq.CertSynopsis;
|
||||||
|
import org.pgpainless.wot.dijkstra.sq.Certification;
|
||||||
|
import org.pgpainless.wot.dijkstra.sq.Depth;
|
||||||
|
import org.pgpainless.wot.dijkstra.sq.Optional;
|
||||||
|
import org.pgpainless.wot.dijkstra.sq.RegexSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class for creating {@link Certification} objects from {@link PGPSignature PGPSignatures}.
|
||||||
|
* The purpose of this class is to minimize the number of PGPainless / Bouncycastle class dependencies in wot-dijkstra.
|
||||||
|
*/
|
||||||
|
public class CertificationFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link Certification} object from a delegation signature.
|
||||||
|
*
|
||||||
|
* @param issuer signature issuer certificate
|
||||||
|
* @param target signature target certificate
|
||||||
|
* @param signature signature
|
||||||
|
* @return certification
|
||||||
|
*/
|
||||||
|
public static Certification fromDelegation(CertSynopsis issuer,
|
||||||
|
CertSynopsis target,
|
||||||
|
PGPSignature signature) {
|
||||||
|
return fromSignature(issuer, Optional.empty(), target, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link Certification} object from a certification signature.
|
||||||
|
*
|
||||||
|
* @param issuer signature issuer certificate
|
||||||
|
* @param targetUserId signature target user ID
|
||||||
|
* @param target signature target certificate
|
||||||
|
* @param signature signature
|
||||||
|
* @return certification
|
||||||
|
*/
|
||||||
|
public static Certification fromCertification(CertSynopsis issuer,
|
||||||
|
String targetUserId,
|
||||||
|
CertSynopsis target,
|
||||||
|
PGPSignature signature) {
|
||||||
|
return fromSignature(issuer, Optional.just(targetUserId), target, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link Certification} object from a signature.
|
||||||
|
*
|
||||||
|
* @param issuer signature issuer certificate
|
||||||
|
* @param targetUserId optional signature target user ID
|
||||||
|
* @param target signature target certificate
|
||||||
|
* @param signature signature
|
||||||
|
* @return certification
|
||||||
|
*/
|
||||||
|
public static Certification fromSignature(CertSynopsis issuer,
|
||||||
|
Optional<String> targetUserId,
|
||||||
|
CertSynopsis target,
|
||||||
|
PGPSignature signature) {
|
||||||
|
return new Certification(
|
||||||
|
issuer,
|
||||||
|
target,
|
||||||
|
targetUserId,
|
||||||
|
SignatureSubpacketsUtil.getSignatureCreationTime(signature).getTime(),
|
||||||
|
Optional.maybe(SignatureSubpacketsUtil.getSignatureExpirationTimeAsDate(signature)),
|
||||||
|
SignatureSubpacketsUtil.isExportable(signature),
|
||||||
|
getTrustAmountFrom(signature),
|
||||||
|
getTrustDepthFrom(signature),
|
||||||
|
regexSetFrom(signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the trust amount from the signature.
|
||||||
|
* If the signature has no {@link TrustSignature} subpacket, return a default value of 120.
|
||||||
|
*
|
||||||
|
* @param signature signature
|
||||||
|
* @return trust amount
|
||||||
|
*/
|
||||||
|
private static int getTrustAmountFrom(PGPSignature signature) {
|
||||||
|
TrustSignature packet = SignatureSubpacketsUtil.getTrustSignature(signature);
|
||||||
|
if (packet != null) {
|
||||||
|
return packet.getTrustAmount();
|
||||||
|
}
|
||||||
|
return 120; // default value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the trust depth from the signature.
|
||||||
|
* If the signature has no {@link TrustSignature} subpacket, return a default value of 0.
|
||||||
|
*
|
||||||
|
* @param signature signature
|
||||||
|
* @return trust depth
|
||||||
|
*/
|
||||||
|
private static Depth getTrustDepthFrom(PGPSignature signature) {
|
||||||
|
TrustSignature packet = SignatureSubpacketsUtil.getTrustSignature(signature);
|
||||||
|
if (packet != null) {
|
||||||
|
return Depth.auto(packet.getDepth());
|
||||||
|
}
|
||||||
|
return Depth.limited(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a {@link RegexSet} from the signature.
|
||||||
|
* If the signature has no {@link RegularExpression} subpacket, the result will equate to a wildcard.
|
||||||
|
*
|
||||||
|
* @param signature signature
|
||||||
|
* @return regex set
|
||||||
|
*/
|
||||||
|
private static RegexSet regexSetFrom(PGPSignature signature) {
|
||||||
|
List<RegularExpression> regexList = SignatureSubpacketsUtil.getRegularExpressions(signature);
|
||||||
|
List<String> stringList = new ArrayList<>();
|
||||||
|
for (RegularExpression regex : regexList) {
|
||||||
|
stringList.add(regex.getRegex());
|
||||||
|
}
|
||||||
|
return RegexSet.fromExpressionList(stringList);
|
||||||
|
}
|
||||||
|
}
|
|
@ -246,7 +246,7 @@ public class WebOfTrust implements CertificateAuthority {
|
||||||
boolean valid = SignatureVerifier.verifyDirectKeySignature(delegation, issuerSigningKey,
|
boolean valid = SignatureVerifier.verifyDirectKeySignature(delegation, issuerSigningKey,
|
||||||
targetPrimaryKey, policy, referenceTime.getTimestamp());
|
targetPrimaryKey, policy, referenceTime.getTimestamp());
|
||||||
if (valid) {
|
if (valid) {
|
||||||
indexEdge(new Certification(issuer, Optional.empty(), target, delegation));
|
indexEdge(CertificationFactory.fromDelegation(issuer, target, delegation));
|
||||||
}
|
}
|
||||||
} catch (SignatureValidationException e) {
|
} catch (SignatureValidationException e) {
|
||||||
LOGGER.warn("Cannot verify signature by " + issuerFingerprint + " on cert of " + OpenPgpFingerprint.of(targetPrimaryKey), e);
|
LOGGER.warn("Cannot verify signature by " + issuerFingerprint + " on cert of " + OpenPgpFingerprint.of(targetPrimaryKey), e);
|
||||||
|
@ -273,7 +273,7 @@ public class WebOfTrust implements CertificateAuthority {
|
||||||
boolean valid = SignatureVerifier.verifySignatureOverUserId(userId, certification,
|
boolean valid = SignatureVerifier.verifySignatureOverUserId(userId, certification,
|
||||||
issuerSigningKey, targetPrimaryKey, policy, referenceTime.getTimestamp());
|
issuerSigningKey, targetPrimaryKey, policy, referenceTime.getTimestamp());
|
||||||
if (valid) {
|
if (valid) {
|
||||||
indexEdge(new Certification(issuer, Optional.just(userId), target, certification));
|
indexEdge(CertificationFactory.fromCertification(issuer, userId, target, certification));
|
||||||
}
|
}
|
||||||
} catch (SignatureValidationException e) {
|
} catch (SignatureValidationException e) {
|
||||||
LOGGER.warn("Cannot verify signature for '" + userId + "' by " + issuerFingerprint + " on cert of " + target.getFingerprint(), e);
|
LOGGER.warn("Cannot verify signature for '" + userId + "' by " + issuerFingerprint + " on cert of " + target.getFingerprint(), e);
|
||||||
|
|
|
@ -34,6 +34,7 @@ dependencies {
|
||||||
// @Nullable, @Nonnull annotations
|
// @Nullable, @Nonnull annotations
|
||||||
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||||
|
|
||||||
|
// OpenPgpFingerprint, RevocationState
|
||||||
implementation(project(":pgpainless-core"))
|
implementation(project(":pgpainless-core"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,6 @@
|
||||||
package org.pgpainless.wot.dijkstra.sq;
|
package org.pgpainless.wot.dijkstra.sq;
|
||||||
|
|
||||||
import java.util.Date;
|
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 {
|
public class Certification {
|
||||||
|
|
||||||
|
@ -63,29 +56,6 @@ public class Certification {
|
||||||
this.regex = RegexSet.wildcard();
|
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.
|
* Get the issuer of the certification.
|
||||||
*
|
*
|
||||||
|
|
|
@ -9,8 +9,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,29 +40,6 @@ public final class CertificationSet {
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
private CertificationSet(CertSynopsis issuer,
|
||||||
CertSynopsis target,
|
CertSynopsis target,
|
||||||
Map<Optional<String>, List<Certification>> certifications) {
|
Map<Optional<String>, List<Certification>> certifications) {
|
||||||
|
|
|
@ -12,8 +12,6 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.sig.RegularExpression;
|
|
||||||
|
|
||||||
public final class RegexSet {
|
public final class RegexSet {
|
||||||
|
|
||||||
private final Set<String> regexStrings;
|
private final Set<String> regexStrings;
|
||||||
|
@ -22,20 +20,17 @@ public final class RegexSet {
|
||||||
this.regexStrings = regexStrings;
|
this.regexStrings = regexStrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegexSet fromList(@Nonnull List<RegularExpression> regexList) {
|
public static RegexSet fromExpressionList(@Nonnull List<String> regexList) {
|
||||||
Set<String> regexStringSet = new HashSet<>();
|
Set<String> regexStringSet = new HashSet<>(regexList);
|
||||||
for (RegularExpression regex : regexList) {
|
|
||||||
regexStringSet.add(regex.getRegex());
|
|
||||||
}
|
|
||||||
return new RegexSet(regexStringSet);
|
return new RegexSet(regexStringSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegexSet fromRegex(@Nonnull RegularExpression regex) {
|
public static RegexSet fromExpression(@Nonnull String regex) {
|
||||||
return fromList(Collections.singletonList(regex));
|
return fromExpressionList(Collections.singletonList(regex));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegexSet wildcard() {
|
public static RegexSet wildcard() {
|
||||||
return fromList(Collections.emptyList());
|
return fromExpressionList(Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(String string) {
|
public boolean matches(String string) {
|
||||||
|
|
Loading…
Reference in a new issue