Kotlin conversion: SignatureBuilder classes

This commit is contained in:
Paul Schaub 2023-11-13 16:21:08 +01:00
parent 3bb25a62a2
commit f07063d55f
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
23 changed files with 693 additions and 728 deletions

View File

@ -1,140 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import java.util.Set;
import javax.annotation.Nonnull;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator;
import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.key.util.OpenPgpKeyAttributeUtil;
import org.pgpainless.signature.subpackets.SignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper;
public abstract class AbstractSignatureBuilder<B extends AbstractSignatureBuilder<B>> {
protected final PGPPrivateKey privateSigningKey;
protected final PGPPublicKey publicSigningKey;
protected HashAlgorithm hashAlgorithm;
protected SignatureType signatureType;
protected SignatureSubpackets unhashedSubpackets;
protected SignatureSubpackets hashedSubpackets;
protected AbstractSignatureBuilder(SignatureType signatureType,
PGPSecretKey signingKey,
SecretKeyRingProtector protector,
HashAlgorithm hashAlgorithm,
SignatureSubpackets hashedSubpackets,
SignatureSubpackets unhashedSubpackets)
throws PGPException {
if (!isValidSignatureType(signatureType)) {
throw new IllegalArgumentException("Invalid signature type.");
}
this.signatureType = signatureType;
this.privateSigningKey = UnlockSecretKey.unlockSecretKey(signingKey, protector);
this.publicSigningKey = signingKey.getPublicKey();
this.hashAlgorithm = hashAlgorithm;
this.hashedSubpackets = hashedSubpackets;
this.unhashedSubpackets = unhashedSubpackets;
}
public AbstractSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
this(
signatureType,
signingKey,
protector,
negotiateHashAlgorithm(signingKey.getPublicKey()),
SignatureSubpackets.createHashedSubpackets(signingKey.getPublicKey()),
SignatureSubpackets.createEmptySubpackets()
);
}
public AbstractSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
throws PGPException {
this(
SignatureType.valueOf(archetypeSignature.getSignatureType()),
certificationKey,
protector,
negotiateHashAlgorithm(certificationKey.getPublicKey()),
SignatureSubpackets.refreshHashedSubpackets(certificationKey.getPublicKey(), archetypeSignature),
SignatureSubpackets.refreshUnhashedSubpackets(archetypeSignature)
);
}
/**
* Negotiate a {@link HashAlgorithm} to be used when creating the signature.
*
* @param publicKey signing public key
* @return hash algorithm
*/
protected static HashAlgorithm negotiateHashAlgorithm(PGPPublicKey publicKey) {
Set<HashAlgorithm> hashAlgorithmPreferences = OpenPgpKeyAttributeUtil.getOrGuessPreferredHashAlgorithms(publicKey);
return HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(PGPainless.getPolicy())
.negotiateHashAlgorithm(hashAlgorithmPreferences);
}
public B overrideHashAlgorithm(@Nonnull HashAlgorithm hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm;
return (B) this;
}
/**
* Set the builders {@link SignatureType}.
* Note that only those types who are valid for the concrete subclass of this {@link AbstractSignatureBuilder}
* are allowed. Invalid choices result in an {@link IllegalArgumentException} to be thrown.
*
* @param type signature type
* @return builder
*/
public B setSignatureType(SignatureType type) {
if (!isValidSignatureType(type)) {
throw new IllegalArgumentException("Invalid signature type: " + type);
}
this.signatureType = type;
return (B) this;
}
/**
* Build an instance of {@link PGPSignatureGenerator} initialized with the signing key
* and with hashed and unhashed subpackets.
*
* @return pgp signature generator
*
* @throws PGPException if the signature generator cannot be initialized
*/
protected PGPSignatureGenerator buildAndInitSignatureGenerator() throws PGPException {
PGPSignatureGenerator generator = new PGPSignatureGenerator(
ImplementationFactory.getInstance().getPGPContentSignerBuilder(
publicSigningKey.getAlgorithm(), hashAlgorithm.getAlgorithmId()
)
);
generator.setUnhashedSubpackets(SignatureSubpacketsHelper.toVector(unhashedSubpackets));
generator.setHashedSubpackets(SignatureSubpacketsHelper.toVector(hashedSubpackets));
generator.init(signatureType.getCode(), privateSigningKey);
return generator;
}
/**
* Return true if the given {@link SignatureType} is a valid choice for the concrete implementation
* of {@link AbstractSignatureBuilder}.
*
* @param type type
* @return return true if valid, false otherwise
*/
protected abstract boolean isValidSignatureType(SignatureType type);
}

View File

@ -1,57 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
public class DirectKeySelfSignatureBuilder extends AbstractSignatureBuilder<DirectKeySelfSignatureBuilder> {
public DirectKeySelfSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
throws PGPException {
super(certificationKey, protector, archetypeSignature);
}
public DirectKeySelfSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
super(SignatureType.DIRECT_KEY, signingKey, protector);
}
public SelfSignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public SelfSignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable SelfSignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignature build(PGPPublicKey key) throws PGPException {
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
if (key.getKeyID() != publicSigningKey.getKeyID()) {
return signatureGenerator.generateCertification(publicSigningKey, key);
} else {
return signatureGenerator.generateCertification(key);
}
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
return type == SignatureType.DIRECT_KEY;
}
}

View File

@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpackets;
public class PrimaryKeyBindingSignatureBuilder extends AbstractSignatureBuilder<PrimaryKeyBindingSignatureBuilder> {
public PrimaryKeyBindingSignatureBuilder(PGPSecretKey subkey, SecretKeyRingProtector subkeyProtector)
throws PGPException {
super(SignatureType.PRIMARYKEY_BINDING, subkey, subkeyProtector);
}
public PrimaryKeyBindingSignatureBuilder(PGPSecretKey secretSubKey,
SecretKeyRingProtector subkeyProtector,
HashAlgorithm hashAlgorithm)
throws PGPException {
super(SignatureType.PRIMARYKEY_BINDING, secretSubKey, subkeyProtector, hashAlgorithm,
SignatureSubpackets.createHashedSubpackets(secretSubKey.getPublicKey()),
SignatureSubpackets.createEmptySubpackets());
}
public SelfSignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public SelfSignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable SelfSignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
return type == SignatureType.PRIMARYKEY_BINDING;
}
public PGPSignature build(PGPPublicKey primaryKey) throws PGPException {
return buildAndInitSignatureGenerator()
.generateCertification(primaryKey, publicSigningKey);
}
}

View File

@ -1,71 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
public class RevocationSignatureBuilder extends AbstractSignatureBuilder<RevocationSignatureBuilder> {
public RevocationSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
super(signatureType, signingKey, protector);
getHashedSubpackets().setRevocable(false);
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
switch (type) {
case KEY_REVOCATION:
case SUBKEY_REVOCATION:
case CERTIFICATION_REVOCATION:
return true;
default:
return false;
}
}
public RevocationSignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public RevocationSignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable RevocationSignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignature build(PGPPublicKey revokeeSubkey) throws PGPException {
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
if (signatureType == SignatureType.KEY_REVOCATION) {
if (!revokeeSubkey.isMasterKey()) {
throw new IllegalArgumentException("Signature type is KEY_REVOCATION, but provided revokeeSubkey does not appear to be a primary key.");
}
return signatureGenerator.generateCertification(publicSigningKey);
} else {
return signatureGenerator.generateCertification(publicSigningKey, revokeeSubkey);
}
}
public PGPSignature build(String revokeeUserId) throws PGPException {
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
if (signatureType != SignatureType.CERTIFICATION_REVOCATION) {
throw new IllegalArgumentException("Signature type is != CERTIFICATION_REVOCATION.");
}
return signatureGenerator.generateCertification(revokeeUserId, publicSigningKey);
}
}

View File

@ -1,74 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
public class SelfSignatureBuilder extends AbstractSignatureBuilder<SelfSignatureBuilder> {
public SelfSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
this(SignatureType.GENERIC_CERTIFICATION, signingKey, protector);
}
public SelfSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
super(signatureType, signingKey, protector);
}
public SelfSignatureBuilder(
PGPSecretKey primaryKey,
SecretKeyRingProtector primaryKeyProtector,
PGPSignature oldCertification)
throws PGPException {
super(primaryKey, primaryKeyProtector, oldCertification);
}
public SelfSignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public SelfSignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable SelfSignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignature build(PGPPublicKey certifiedKey, String userId) throws PGPException {
return buildAndInitSignatureGenerator().generateCertification(userId, certifiedKey);
}
public PGPSignature build(PGPPublicKey certifiedKey, PGPUserAttributeSubpacketVector userAttribute)
throws PGPException {
return buildAndInitSignatureGenerator().generateCertification(userAttribute, certifiedKey);
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
switch (type) {
case GENERIC_CERTIFICATION:
case NO_CERTIFICATION:
case CASUAL_CERTIFICATION:
case POSITIVE_CERTIFICATION:
case DIRECT_KEY:
return true;
default:
return false;
}
}
}

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpackets;
public class SubkeyBindingSignatureBuilder extends AbstractSignatureBuilder<SubkeyBindingSignatureBuilder> {
public SubkeyBindingSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
super(SignatureType.SUBKEY_BINDING, signingKey, protector);
}
public SubkeyBindingSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector, HashAlgorithm hashAlgorithm)
throws PGPException {
super(SignatureType.SUBKEY_BINDING, signingKey, protector, hashAlgorithm,
SignatureSubpackets.createHashedSubpackets(signingKey.getPublicKey()),
SignatureSubpackets.createEmptySubpackets());
}
public SubkeyBindingSignatureBuilder(
PGPSecretKey signingKey,
SecretKeyRingProtector protector,
PGPSignature oldSubkeyBinding)
throws PGPException {
super(signingKey, protector, requireValidSignatureType(oldSubkeyBinding));
}
private static PGPSignature requireValidSignatureType(PGPSignature signature) {
if (signature.getSignatureType() == SignatureType.SUBKEY_BINDING.getCode()) {
return signature;
}
throw new IllegalArgumentException("Invalid signature type.");
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
return type == SignatureType.SUBKEY_BINDING;
}
public SelfSignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public SelfSignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable SelfSignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignature build(PGPPublicKey subkey) throws PGPException {
return buildAndInitSignatureGenerator()
.generateCertification(publicSigningKey, subkey);
}
}

View File

@ -1,119 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.exception.WrongPassphraseException;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.CertificationSubpackets;
/**
* Certification signature builder used to certify other users keys.
*/
public class ThirdPartyCertificationSignatureBuilder extends AbstractSignatureBuilder<ThirdPartyCertificationSignatureBuilder> {
/**
* Create a new certification signature builder.
* This constructor uses {@link SignatureType#GENERIC_CERTIFICATION} as signature type.
*
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @throws WrongPassphraseException in case of a wrong passphrase
*/
public ThirdPartyCertificationSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
this(SignatureType.GENERIC_CERTIFICATION, signingKey, protector);
}
/**
* Create a new certification signature builder.
*
* @param signatureType type of certification
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @throws WrongPassphraseException in case of a wrong passphrase
*/
public ThirdPartyCertificationSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
super(signatureType, signingKey, protector);
}
/**
* Create a new certification signature builder.
*
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @param archetypeSignature signature to use as a template for the new signature
* @throws WrongPassphraseException in case of a wrong passphrase
*/
public ThirdPartyCertificationSignatureBuilder(
PGPSecretKey signingKey,
SecretKeyRingProtector protector,
PGPSignature archetypeSignature)
throws PGPException {
super(signingKey, protector, archetypeSignature);
}
public CertificationSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public CertificationSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable CertificationSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
/**
* Create a certification signature for the given user-id and the primary key of the given key ring.
* @param certifiedKey key ring
* @param userId user-id to certify
* @return signature
*
* @throws PGPException if the signature generator cannot be initialized
*/
public PGPSignature build(PGPPublicKeyRing certifiedKey, String userId) throws PGPException {
return buildAndInitSignatureGenerator().generateCertification(userId, certifiedKey.getPublicKey());
}
/**
* Create a certification signature for the given user attribute and the primary key of the given key ring.
* @param certifiedKey key ring
* @param userAttribute user-attributes to certify
* @return signature
*
* @throws PGPException if the signature generator cannot be initialized
*/
public PGPSignature build(PGPPublicKeyRing certifiedKey, PGPUserAttributeSubpacketVector userAttribute)
throws PGPException {
return buildAndInitSignatureGenerator().generateCertification(userAttribute, certifiedKey.getPublicKey());
}
@Override
protected boolean isValidSignatureType(@Nonnull SignatureType type) {
switch (type) {
case GENERIC_CERTIFICATION:
case NO_CERTIFICATION:
case CASUAL_CERTIFICATION:
case POSITIVE_CERTIFICATION:
return true;
default:
return false;
}
}
}

View File

@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.CertificationSubpackets;
public class ThirdPartyDirectKeySignatureBuilder extends AbstractSignatureBuilder<ThirdPartyDirectKeySignatureBuilder> {
public ThirdPartyDirectKeySignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
throws PGPException {
super(certificationKey, protector, archetypeSignature);
}
public ThirdPartyDirectKeySignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
super(SignatureType.DIRECT_KEY, signingKey, protector);
}
public CertificationSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public CertificationSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable CertificationSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignature build(PGPPublicKey key) throws PGPException {
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
return signatureGenerator.generateCertification(key);
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
return type == SignatureType.DIRECT_KEY;
}
}

View File

@ -1,55 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.subpackets.SignatureSubpackets;
/**
* Signature builder without restrictions on subpacket contents.
*/
public class UniversalSignatureBuilder extends AbstractSignatureBuilder<UniversalSignatureBuilder> {
public UniversalSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws PGPException {
super(signatureType, signingKey, protector);
}
public UniversalSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
throws PGPException {
super(certificationKey, protector, archetypeSignature);
}
@Override
protected boolean isValidSignatureType(SignatureType type) {
return true;
}
public SignatureSubpackets getHashedSubpackets() {
return hashedSubpackets;
}
public SignatureSubpackets getUnhashedSubpackets() {
return unhashedSubpackets;
}
public void applyCallback(@Nullable SignatureSubpackets.Callback callback) {
if (callback != null) {
callback.modifyHashedSubpackets(getHashedSubpackets());
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
}
}
public PGPSignatureGenerator getSignatureGenerator() throws PGPException {
return buildAndInitSignatureGenerator();
}
}

View File

@ -1,8 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Classes related to OpenPGP signatures.
*/
package org.pgpainless.signature.builder;

View File

@ -1,8 +0,0 @@
// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Classes related to OpenPGP signatures.
*/
package org.pgpainless.signature;

View File

@ -157,7 +157,9 @@ enum class SignatureType(val code: Int) {
* @throws IllegalArgumentException in case of an unmatched signature type code
*/
@JvmStatic
@Deprecated("Deprecated in favor of requireFromCode", ReplaceWith("requireFromCode"))
@Deprecated(
"Deprecated in favor of requireFromCode",
ReplaceWith("SignatureType.requireFromCode(code)"))
fun valueOf(code: Int): SignatureType {
try {
return requireFromCode(code)

View File

@ -84,10 +84,7 @@ class SecretKeyRingEditor(
}
builder.applyCallback(callback)
secretKeyRing =
injectCertification(
secretKeyRing,
sanitizedUserId,
builder.build(primaryKey.publicKey, sanitizedUserId))
injectCertification(secretKeyRing, sanitizedUserId, builder.build(sanitizedUserId))
return this
}
@ -620,7 +617,7 @@ class SecretKeyRingEditor(
hashedSubpackets.setPrimaryUserId(null)
}
})
return builder.build(secretKeyRing.publicKey, userId)
return builder.build(userId)
}
@Throws(PGPException::class)
@ -648,7 +645,7 @@ class SecretKeyRingEditor(
}
})
}
.build(secretKeyRing.publicKey, primaryUserId)
.build(primaryUserId)
}
@Throws(PGPException::class)
@ -675,7 +672,7 @@ class SecretKeyRingEditor(
}
})
}
.build(secretKeyRing.publicKey)
.build()
}
private fun selectUserIds(predicate: Predicate<String>): List<String> =

View File

@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPrivateKey
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPSignatureGenerator
import org.pgpainless.PGPainless
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator
import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.key.protection.UnlockSecretKey
import org.pgpainless.key.util.OpenPgpKeyAttributeUtil
import org.pgpainless.signature.subpackets.SignatureSubpackets
import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper
abstract class AbstractSignatureBuilder<B : AbstractSignatureBuilder<B>>(
protected val privateSigningKey: PGPPrivateKey,
protected val publicSigningKey: PGPPublicKey,
protected var _hashAlgorithm: HashAlgorithm,
protected var _signatureType: SignatureType,
protected val _hashedSubpackets: SignatureSubpackets,
protected val _unhashedSubpackets: SignatureSubpackets
) {
protected abstract val signatureTypePredicate: Predicate<SignatureType>
init {
require(signatureTypePredicate.test(_signatureType)) { "Invalid signature type." }
}
@Throws(PGPException::class)
protected constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
hashAlgorithm: HashAlgorithm,
hashedSubpackets: SignatureSubpackets,
unhashedSubpackets: SignatureSubpackets
) : this(
UnlockSecretKey.unlockSecretKey(signingKey, protector),
signingKey.publicKey,
hashAlgorithm,
signatureType,
hashedSubpackets,
unhashedSubpackets)
@Throws(PGPException::class)
constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : this(
signatureType,
signingKey,
protector,
negotiateHashAlgorithm(signingKey.publicKey),
SignatureSubpackets.createHashedSubpackets(signingKey.publicKey),
SignatureSubpackets.createEmptySubpackets())
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
archetypeSignature: PGPSignature
) : this(
SignatureType.requireFromCode(archetypeSignature.signatureType),
signingKey,
protector,
negotiateHashAlgorithm(signingKey.publicKey),
SignatureSubpackets.refreshHashedSubpackets(signingKey.publicKey, archetypeSignature),
SignatureSubpackets.refreshUnhashedSubpackets(archetypeSignature))
val hashAlgorithm = _hashAlgorithm
fun overrideHashAlgorithm(hashAlgorithm: HashAlgorithm) =
apply { _hashAlgorithm = hashAlgorithm } as B
/**
* Set the builders [SignatureType]. Note that only those types who are valid for the concrete
* subclass of this [AbstractSignatureBuilder] are allowed. Invalid choices result in an
* [IllegalArgumentException] to be thrown.
*
* @param type signature type
* @return builder
*/
fun setSignatureType(type: SignatureType) =
apply {
require(signatureTypePredicate.test(type)) { "Invalid signature type: $type" }
_signatureType = type
}
as B
/**
* Build an instance of [PGPSignatureGenerator] initialized with the signing key and with hashed
* and unhashed subpackets.
*
* @return pgp signature generator
* @throws PGPException if the signature generator cannot be initialized
*/
@Throws(PGPException::class)
protected fun buildAndInitSignatureGenerator(): PGPSignatureGenerator =
PGPSignatureGenerator(
ImplementationFactory.getInstance()
.getPGPContentSignerBuilder(
publicSigningKey.algorithm, hashAlgorithm.algorithmId))
.apply {
setUnhashedSubpackets(SignatureSubpacketsHelper.toVector(_unhashedSubpackets))
setHashedSubpackets(SignatureSubpacketsHelper.toVector(_hashedSubpackets))
init(_signatureType.code, privateSigningKey)
}
companion object {
/**
* Negotiate a [HashAlgorithm] to be used when creating the signature.
*
* @param publicKey signing public key
* @return hash algorithm
*/
@JvmStatic
fun negotiateHashAlgorithm(publicKey: PGPPublicKey): HashAlgorithm =
HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(PGPainless.getPolicy())
.negotiateHashAlgorithm(
OpenPgpKeyAttributeUtil.getOrGuessPreferredHashAlgorithms(publicKey))
}
}

View File

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
/**
* [AbstractSignatureBuilder] devoted to direct-key self-signatures. Direct-key self-signatures are
* calculated by a primary-key over itself.
*/
class DirectKeySelfSignatureBuilder : AbstractSignatureBuilder<DirectKeySelfSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate { it == SignatureType.DIRECT_KEY }
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
archetypeSignature: PGPSignature
) : super(signingKey, protector, archetypeSignature)
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(SignatureType.DIRECT_KEY, signingKey, protector)
val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: SelfSignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(): PGPSignature =
buildAndInitSignatureGenerator().let { it.generateCertification(publicSigningKey) }
}

View File

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.signature.subpackets.SignatureSubpackets
/**
* [AbstractSignatureBuilder] subclass devoted to build primary-key binding-signatures. Those
* signatures (also called "back-signatures") are binding signatures issued by signing-capable
* subkeys.
*/
class PrimaryKeyBindingSignatureBuilder :
AbstractSignatureBuilder<PrimaryKeyBindingSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate<SignatureType> { it == SignatureType.PRIMARYKEY_BINDING }
@Throws(PGPException::class)
constructor(
signingSubkey: PGPSecretKey,
subkeyProtector: SecretKeyRingProtector
) : super(SignatureType.PRIMARYKEY_BINDING, signingSubkey, subkeyProtector)
@Throws(PGPException::class)
constructor(
signingSubkey: PGPSecretKey,
subkeyProtector: SecretKeyRingProtector,
hashAlgorithm: HashAlgorithm
) : super(
SignatureType.PRIMARYKEY_BINDING,
signingSubkey,
subkeyProtector,
hashAlgorithm,
SignatureSubpackets.createHashedSubpackets(signingSubkey.publicKey),
SignatureSubpackets.createEmptySubpackets())
val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: SelfSignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(primaryKey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(primaryKey, publicSigningKey)
}

View File

@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets
/** [AbstractSignatureBuilder] subclass devoted to revocation signatures. */
class RevocationSignatureBuilder : AbstractSignatureBuilder<RevocationSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() =
Predicate<SignatureType> {
it in
listOf(
SignatureType.KEY_REVOCATION,
SignatureType.SUBKEY_REVOCATION,
SignatureType.CERTIFICATION_REVOCATION)
}
@Throws(PGPException::class)
constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(signatureType, signingKey, protector) {
hashedSubpackets.setRevocable(false)
}
val hashedSubpackets: RevocationSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: RevocationSignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: RevocationSignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(revokeeKey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator().let {
if (_signatureType == SignatureType.KEY_REVOCATION) {
require(revokeeKey.isMasterKey) {
"Signature type is KEY_REVOCATION, but provided revokee does not appear to be a primary key."
}
it.generateCertification(publicSigningKey)
} else {
it.generateCertification(publicSigningKey, revokeeKey)
}
}
@Throws(PGPException::class)
fun build(revokeeUserId: CharSequence): PGPSignature =
buildAndInitSignatureGenerator()
.also {
require(_signatureType == SignatureType.CERTIFICATION_REVOCATION) {
"Signature type is != CERTIFICATION_REVOCATION."
}
}
.generateCertification(revokeeUserId.toString(), publicSigningKey)
}

View File

@ -0,0 +1,69 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
/**
* [AbstractSignatureBuilder] devoted to all types of self-certifications. Self-certifications are
* certifications calculated by a primary key over its own user-ids.
*/
class SelfSignatureBuilder : AbstractSignatureBuilder<SelfSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() =
Predicate<SignatureType> {
it in
listOf(
SignatureType.GENERIC_CERTIFICATION,
SignatureType.NO_CERTIFICATION,
SignatureType.CASUAL_CERTIFICATION,
SignatureType.POSITIVE_CERTIFICATION)
}
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(SignatureType.GENERIC_CERTIFICATION, signingKey, protector)
@Throws(PGPException::class)
constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(signatureType, signingKey, protector)
@Throws(PGPException::class)
constructor(
primaryKey: PGPSecretKey,
primaryKeyProtector: SecretKeyRingProtector,
oldCertification: PGPSignature
) : super(primaryKey, primaryKeyProtector, oldCertification)
val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: SelfSignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(userId: CharSequence): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(userId.toString(), publicSigningKey)
@Throws(PGPException::class)
fun build(userAttributes: PGPUserAttributeSubpacketVector): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(userAttributes, publicSigningKey)
}

View File

@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.signature.subpackets.SignatureSubpackets
/**
* [AbstractSignatureBuilder] devoted to generating subkey binding signatures. A subkey binding
* signature is calculated by a primary key over a subkey.
*/
class SubkeyBindingSignatureBuilder : AbstractSignatureBuilder<SubkeyBindingSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate<SignatureType> { it == SignatureType.SUBKEY_BINDING }
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(SignatureType.SUBKEY_BINDING, signingKey, protector)
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
hashAlgorithm: HashAlgorithm
) : super(
SignatureType.SUBKEY_BINDING,
signingKey,
protector,
hashAlgorithm,
SignatureSubpackets.createHashedSubpackets(signingKey.publicKey),
SignatureSubpackets.createEmptySubpackets())
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
oldSubkeyBinding: PGPSignature
) : super(
signingKey,
protector,
oldSubkeyBinding.also {
require(it.signatureType == SignatureType.SUBKEY_BINDING.code) {
"Invalid signature type."
}
})
val hashedSubpackets: SelfSignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SelfSignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: SelfSignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(subkey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(publicSigningKey, subkey)
}

View File

@ -0,0 +1,117 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.CertificationSubpackets
/**
* Certification signature builder used to certify other users keys. A third-party certification is
* calculated by the primary key of the issuer certificate, over a user-id on a third-party
* certificate.
*/
class ThirdPartyCertificationSignatureBuilder :
AbstractSignatureBuilder<ThirdPartyCertificationSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() =
Predicate<SignatureType> {
it in
listOf(
SignatureType.GENERIC_CERTIFICATION,
SignatureType.NO_CERTIFICATION,
SignatureType.CASUAL_CERTIFICATION,
SignatureType.POSITIVE_CERTIFICATION)
}
/**
* Create a new certification signature builder. This constructor uses
* [SignatureType.GENERIC_CERTIFICATION] as signature type.
*
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @throws WrongPassphraseException in case of a wrong passphrase
*/
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(SignatureType.GENERIC_CERTIFICATION, signingKey, protector)
/**
* Create a new certification signature builder.
*
* @param signatureType type of certification
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @throws WrongPassphraseException in case of a wrong passphrase
*/
@Throws(PGPException::class)
constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(signatureType, signingKey, protector)
/**
* Create a new certification signature builder.
*
* @param signingKey our own certification key
* @param protector protector to unlock the certification key
* @param archetypeSignature signature to use as a template for the new signature
* @throws WrongPassphraseException in case of a wrong passphrase
*/
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
archetypeSignature: PGPSignature
) : super(signingKey, protector, archetypeSignature)
val hashedSubpackets: CertificationSubpackets = _hashedSubpackets
val unhashedSubpackets: CertificationSubpackets = _unhashedSubpackets
fun applyCallback(callback: CertificationSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
/**
* Create a certification signature for the given user-id and the given third-party certificate.
*
* @param certificate third-party certificate
* @param userId user-id to certify
* @return signature
* @throws PGPException if the signature generator cannot be initialized
*/
@Throws(PGPException::class)
fun build(certificate: PGPPublicKeyRing, userId: CharSequence): PGPSignature =
buildAndInitSignatureGenerator()
.generateCertification(userId.toString(), certificate.publicKey)
/**
* Create a certification signature for the given user attribute and the given third-party
* certificate.
*
* @param certificate third-party certificate
* @param userAttribute user-attributes to certify
* @return signature
* @throws PGPException if the signature generator cannot be initialized
*/
@Throws(PGPException::class)
fun build(
certificate: PGPPublicKeyRing,
userAttribute: PGPUserAttributeSubpacketVector
): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(userAttribute, certificate.publicKey)
}

View File

@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.CertificationSubpackets
/**
* [AbstractSignatureBuilder] subclass devoted to generating direct-key signatures over primary keys
* of third-party certificates. Such signatures are also sometimes referred to as "delegations",
* i.e. in the context of the Web-of-Trust.
*/
class ThirdPartyDirectKeySignatureBuilder :
AbstractSignatureBuilder<ThirdPartyDirectKeySignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate<SignatureType> { it == SignatureType.DIRECT_KEY }
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(SignatureType.DIRECT_KEY, signingKey, protector)
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
archetypeSignature: PGPSignature
) : super(signingKey, protector, archetypeSignature)
val hashedSubpackets: CertificationSubpackets = _hashedSubpackets
val unhashedSubpackets: CertificationSubpackets = _unhashedSubpackets
fun applyCallback(callback: CertificationSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
@Throws(PGPException::class)
fun build(certificate: PGPPublicKeyRing): PGPSignature = build(certificate.publicKey)
@Throws(PGPException::class)
fun build(certifiedKey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator().generateCertification(certifiedKey)
}

View File

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder
import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.PGPSignatureGenerator
import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.signature.subpackets.SignatureSubpackets
/**
* Signature builder without restrictions on subpacket contents. Instead of providing a "build"
* method, this builder offers the user to decide on their own, how to generate the signature by
* exposing the [PGPSignatureGenerator] via [signatureGenerator].
*/
class UniversalSignatureBuilder : AbstractSignatureBuilder<UniversalSignatureBuilder> {
override val signatureTypePredicate: Predicate<SignatureType>
get() = Predicate<SignatureType> { true }
@Throws(PGPException::class)
constructor(
signatureType: SignatureType,
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector
) : super(signatureType, signingKey, protector)
@Throws(PGPException::class)
constructor(
signingKey: PGPSecretKey,
protector: SecretKeyRingProtector,
archetypeSignature: PGPSignature
) : super(signingKey, protector, archetypeSignature)
val hashedSubpackets: SignatureSubpackets = _hashedSubpackets
val unhashedSubpackets: SignatureSubpackets = _unhashedSubpackets
fun applyCallback(callback: SignatureSubpackets.Callback?) = apply {
callback?.let {
it.modifyHashedSubpackets(hashedSubpackets)
it.modifyUnhashedSubpackets(unhashedSubpackets)
}
}
val signatureGenerator: PGPSignatureGenerator
@Throws(PGPException::class) get() = buildAndInitSignatureGenerator()
}

View File

@ -8,8 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Date;
@ -33,7 +31,7 @@ import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
public class ThirdPartyDirectKeySignatureBuilderTest {
@Test
public void testDirectKeySignatureBuilding() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
public void testDirectKeySignatureBuilding() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
.modernKeyRing("Alice");
@ -55,7 +53,7 @@ public class ThirdPartyDirectKeySignatureBuilderTest {
}
});
PGPSignature directKeySig = dsb.build(secretKeys.getPublicKey());
PGPSignature directKeySig = dsb.build();
assertNotNull(directKeySig);
secretKeys = KeyRingUtils.injectCertification(secretKeys, secretKeys.getPublicKey(), directKeySig);