1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-06-26 05:24:49 +02:00
pgpainless/pgpainless-core/src/main/java/org/pgpainless/signature/builder/AbstractSignatureBuilder.java

122 lines
5.4 KiB
Java
Raw Normal View History

2021-10-20 21:27:59 +02:00
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.signature.builder;
import java.util.Set;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
2021-10-22 15:42:08 +02:00
import org.bouncycastle.openpgp.PGPSignature;
2021-10-20 21:27:59 +02:00
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.exception.WrongPassphraseException;
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.SignatureSubpacketGeneratorWrapper;
public abstract class AbstractSignatureBuilder<B extends AbstractSignatureBuilder<B>> {
protected final PGPPrivateKey privateSigningKey;
protected final PGPPublicKey publicSigningKey;
protected HashAlgorithm hashAlgorithm;
protected SignatureType signatureType;
protected SignatureSubpacketGeneratorWrapper unhashedSubpackets;
protected SignatureSubpacketGeneratorWrapper hashedSubpackets;
public AbstractSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector)
throws WrongPassphraseException {
if (!isValidSignatureType(signatureType)) {
throw new IllegalArgumentException("Invalid signature type.");
}
this.signatureType = signatureType;
this.privateSigningKey = UnlockSecretKey.unlockSecretKey(signingKey, protector);
this.publicSigningKey = signingKey.getPublicKey();
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
unhashedSubpackets = SignatureSubpacketGeneratorWrapper.createEmptySubpackets();
// Prepopulate hashed subpackets with default values (key-id etc.)
hashedSubpackets = SignatureSubpacketGeneratorWrapper.createHashedSubpackets(publicSigningKey);
2021-10-20 21:27:59 +02:00
}
public AbstractSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
throws WrongPassphraseException {
2021-10-22 15:42:08 +02:00
SignatureType type = SignatureType.valueOf(archetypeSignature.getSignatureType());
if (!isValidSignatureType(type)) {
throw new IllegalArgumentException("Invalid signature type.");
}
this.signatureType = SignatureType.valueOf(archetypeSignature.getSignatureType());
this.privateSigningKey = UnlockSecretKey.unlockSecretKey(certificationKey, protector);
this.publicSigningKey = certificationKey.getPublicKey();
this.hashAlgorithm = negotiateHashAlgorithm(publicSigningKey);
unhashedSubpackets = SignatureSubpacketGeneratorWrapper.refreshUnhashedSubpackets(archetypeSignature);
hashedSubpackets = SignatureSubpacketGeneratorWrapper.refreshHashedSubpackets(publicSigningKey, archetypeSignature);
2021-10-22 15:42:08 +02:00
}
/**
* Negotiate a {@link HashAlgorithm} to be used when creating the signature.
*
* @param publicKey signing public key
* @return hash algorithm
*/
2021-10-20 21:27:59 +02:00
protected HashAlgorithm negotiateHashAlgorithm(PGPPublicKey publicKey) {
Set<HashAlgorithm> hashAlgorithmPreferences = OpenPgpKeyAttributeUtil.getOrGuessPreferredHashAlgorithms(publicKey);
return HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(PGPainless.getPolicy())
.negotiateHashAlgorithm(hashAlgorithmPreferences);
}
/**
* 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
*/
2021-10-20 21:27:59 +02:00
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
*/
2021-10-20 21:27:59 +02:00
protected PGPSignatureGenerator buildAndInitSignatureGenerator() throws PGPException {
PGPSignatureGenerator generator = new PGPSignatureGenerator(
ImplementationFactory.getInstance().getPGPContentSignerBuilder(
publicSigningKey.getAlgorithm(), hashAlgorithm.getAlgorithmId()
)
);
generator.setUnhashedSubpackets(unhashedSubpackets.getGenerator().generate());
generator.setHashedSubpackets(hashedSubpackets.getGenerator().generate());
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
*/
2021-10-20 21:27:59 +02:00
protected abstract boolean isValidSignatureType(SignatureType type);
}