1
0
Fork 0
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:
Paul Schaub 2023-06-25 13:40:36 +02:00
parent 3a994625e9
commit ab0835d176
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
6 changed files with 134 additions and 67 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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"))
} }

View file

@ -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.
* *

View file

@ -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) {

View file

@ -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) {