diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthenticity.java b/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthenticity.java new file mode 100644 index 00000000..ac059646 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthenticity.java @@ -0,0 +1,139 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.authentication; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; + +import org.bouncycastle.openpgp.PGPPublicKeyRing; + +public class CertificateAuthenticity { + + private final String userId; + private final PGPPublicKeyRing certificate; + private final Map certificationChains = new HashMap<>(); + private final int targetAmount; + + public CertificateAuthenticity(@Nonnull PGPPublicKeyRing certificate, + @Nonnull String userId, + @Nonnull Map certificationChains, + int targetAmount) { + this.userId = userId; + this.certificate = certificate; + this.certificationChains.putAll(certificationChains); + this.targetAmount = targetAmount; + } + + @Nonnull + public String getUserId() { + return userId; + } + + @Nonnull + public PGPPublicKeyRing getCertificate() { + return certificate; + } + + public int getTotalTrustAmount() { + int total = 0; + for (int v : certificationChains.values()) { + total += v; + } + return total; + } + + /** + * Return the degree of authentication of the binding in percent. + * 100% means full authentication. + * Values smaller than 100% mean partial authentication. + * + * @return authenticity in percent + */ + public int getAuthenticityPercentage() { + return targetAmount * 100 / getTotalTrustAmount(); + } + + /** + * Return true, if the binding is authenticated to a sufficient degree. + * + * @return true if total gathered evidence outweighs the target trust amount. + */ + public boolean isAuthenticated() { + return targetAmount <= getTotalTrustAmount(); + } + + /** + * Return a map of {@link CertificationChain CertificationChains} and their respective effective trust amount. + * The effective trust amount of a path might be smaller than its actual trust amount, for example if nodes of a + * path are used multiple times. + * + * @return map of certification chains and their effective trust amounts + */ + @Nonnull + public Map getCertificationChains() { + return Collections.unmodifiableMap(certificationChains); + } + + public static class CertificationChain { + private final int trustAmount; + private final List chainLinks = new ArrayList<>(); + + /** + * A chain of certifications. + * + * @param trustAmount actual trust amount of the chain + * @param chainLinks links of the chain, starting at the trust-root, ending at the target. + */ + public CertificationChain(int trustAmount, @Nonnull List chainLinks) { + this.trustAmount = trustAmount; + this.chainLinks.addAll(chainLinks); + } + + /** + * Actual trust amount of the certification chain. + * @return trust amount + */ + public int getTrustAmount() { + return trustAmount; + } + + /** + * Return all links in the chain, starting at the trust-root and ending at the target. + * @return chain links + */ + @Nonnull + public List getChainLinks() { + return Collections.unmodifiableList(chainLinks); + } + } + + /** + * A chain link contains a node in the trust chain. + */ + public static class ChainLink { + private final PGPPublicKeyRing certificate; + + /** + * Create a chain link. + * @param certificate node in the trust chain + */ + public ChainLink(@Nonnull PGPPublicKeyRing certificate) { + this.certificate = certificate; + } + + /** + * Return the certificate that belongs to the node. + * @return certificate + */ + @Nonnull + public PGPPublicKeyRing getCertificate() { + return certificate; + } + } +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthority.java b/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthority.java new file mode 100644 index 00000000..7f48c9c6 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/authentication/CertificateAuthority.java @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.authentication; + +import org.pgpainless.key.OpenPgpFingerprint; + +import javax.annotation.Nonnull; +import java.util.Date; + +public interface CertificateAuthority { + + /** + * Determine the authenticity of the binding between the given fingerprint and the userId. + * In other words, determine, how much evidence can be gathered, that the certificate with the given + * fingerprint really belongs to the user with the given userId. + * + * @param fingerprint fingerprint of the certificate + * @param userId userId + * @param email if true, the userId will be treated as an email address and all user-IDs containing + * the email address will be matched. + * @param referenceTime reference time at which the binding shall be evaluated + * @param targetAmount target trust amount (120 = fully authenticated, 240 = doubly authenticated, + * 60 = partially authenticated...) + * @return information about the authenticity of the binding + */ + CertificateAuthenticity authenticate(@Nonnull OpenPgpFingerprint fingerprint, + @Nonnull String userId, + boolean email, + @Nonnull Date referenceTime, + int targetAmount); +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java new file mode 100644 index 00000000..495ab1f7 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/authentication/package-info.java @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * Classes and interfaces related to certificate authenticity. + */ +package org.pgpainless.authentication;