1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-24 11:57: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 2de7c0aa36
commit c213760e6c
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
7 changed files with 155 additions and 67 deletions

View file

@ -531,6 +531,11 @@ public final class SignatureSubpacketsUtil {
return hashed(signature, SignatureSubpacket.exportableCertification);
}
public static boolean isExportable(PGPSignature signature) {
Exportable exportable = getExportableCertification(signature);
return exportable == null || exportable.isExportable();
}
/**
* Return the trust signature packet from the signatures hashed area.
*
@ -541,6 +546,22 @@ public final class SignatureSubpacketsUtil {
return hashed(signature, SignatureSubpacket.trustSignature);
}
public static int getTrustDepthOr(PGPSignature signature, int defaultDepth) {
TrustSignature packet = getTrustSignature(signature);
if (packet != null) {
return packet.getDepth();
}
return defaultDepth;
}
public static int getTrustAmountOr(PGPSignature signature, int defaultAmount) {
TrustSignature packet = getTrustSignature(signature);
if (packet != null) {
return packet.getTrustAmount();
}
return defaultAmount;
}
/**
* Return all regular expression subpackets from the hashed area of the given signature.
*

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,
targetPrimaryKey, policy, referenceTime.getTimestamp());
if (valid) {
indexEdge(new Certification(issuer, Optional.empty(), target, delegation));
indexEdge(CertificationFactory.fromDelegation(issuer, target, delegation));
}
} catch (SignatureValidationException 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,
issuerSigningKey, targetPrimaryKey, policy, referenceTime.getTimestamp());
if (valid) {
indexEdge(new Certification(issuer, Optional.just(userId), target, certification));
indexEdge(CertificationFactory.fromCertification(issuer, userId, target, certification));
}
} catch (SignatureValidationException 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
implementation "com.google.code.findbugs:jsr305:3.0.2"
// OpenPgpFingerprint, RevocationState
implementation(project(":pgpainless-core"))
}

View file

@ -5,13 +5,6 @@
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 {
@ -63,29 +56,6 @@ public class Certification {
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.
*

View file

@ -9,8 +9,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bouncycastle.openpgp.PGPSignature;
import javax.annotation.Nonnull;
/**
@ -42,29 +40,6 @@ public final class CertificationSet {
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,
CertSynopsis target,
Map<Optional<String>, List<Certification>> certifications) {

View file

@ -12,8 +12,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.bouncycastle.bcpg.sig.RegularExpression;
public final class RegexSet {
private final Set<String> regexStrings;
@ -22,20 +20,17 @@ public final class RegexSet {
this.regexStrings = regexStrings;
}
public static RegexSet fromList(@Nonnull List<RegularExpression> regexList) {
Set<String> regexStringSet = new HashSet<>();
for (RegularExpression regex : regexList) {
regexStringSet.add(regex.getRegex());
}
public static RegexSet fromExpressionList(@Nonnull List<String> regexList) {
Set<String> regexStringSet = new HashSet<>(regexList);
return new RegexSet(regexStringSet);
}
public static RegexSet fromRegex(@Nonnull RegularExpression regex) {
return fromList(Collections.singletonList(regex));
public static RegexSet fromExpression(@Nonnull String regex) {
return fromExpressionList(Collections.singletonList(regex));
}
public static RegexSet wildcard() {
return fromList(Collections.emptyList());
return fromExpressionList(Collections.emptyList());
}
public boolean matches(String string) {