mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-27 13:28:00 +01:00
WIP: Work on SignatureBuilders
This commit is contained in:
parent
daefab60f6
commit
f0bc19b0da
10 changed files with 1447 additions and 0 deletions
|
@ -0,0 +1,76 @@
|
|||
// 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;
|
||||
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 = new SignatureSubpacketGeneratorWrapper();
|
||||
hashedSubpackets = new SignatureSubpacketGeneratorWrapper(publicSigningKey);
|
||||
}
|
||||
|
||||
protected HashAlgorithm negotiateHashAlgorithm(PGPPublicKey publicKey) {
|
||||
Set<HashAlgorithm> hashAlgorithmPreferences = OpenPgpKeyAttributeUtil.getOrGuessPreferredHashAlgorithms(publicKey);
|
||||
return HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(PGPainless.getPolicy())
|
||||
.negotiateHashAlgorithm(hashAlgorithmPreferences);
|
||||
}
|
||||
|
||||
public B setSignatureType(SignatureType type) {
|
||||
if (!isValidSignatureType(type)) {
|
||||
throw new IllegalArgumentException("Invalid signature type: " + type);
|
||||
}
|
||||
this.signatureType = type;
|
||||
return (B) this;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
protected abstract boolean isValidSignatureType(SignatureType type);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package org.pgpainless.signature.builder;
|
||||
|
||||
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.exception.WrongPassphraseException;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
|
||||
public class CertificationSignatureBuilder extends AbstractSignatureBuilder<CertificationSignatureBuilder> {
|
||||
|
||||
public CertificationSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector) throws WrongPassphraseException {
|
||||
super(SignatureType.GENERIC_CERTIFICATION, certificationKey, protector);
|
||||
}
|
||||
|
||||
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 (signatureType) {
|
||||
case GENERIC_CERTIFICATION:
|
||||
case NO_CERTIFICATION:
|
||||
case CASUAL_CERTIFICATION:
|
||||
case POSITIVE_CERTIFICATION:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.builder;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.exception.WrongPassphraseException;
|
||||
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 WrongPassphraseException {
|
||||
super(signatureType, signingKey, protector);
|
||||
}
|
||||
|
||||
@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 PGPSignature build()
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.builder;
|
||||
|
||||
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.exception.WrongPassphraseException;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
|
||||
|
||||
public class SubkeyBindingSignatureBuilder extends AbstractSignatureBuilder<SubkeyBindingSignatureBuilder> {
|
||||
|
||||
public SubkeyBindingSignatureBuilder(SignatureType signatureType, PGPSecretKey signingKey, SecretKeyRingProtector protector) throws WrongPassphraseException {
|
||||
super(signatureType, signingKey, protector);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidSignatureType(SignatureType type) {
|
||||
return type == SignatureType.SUBKEY_BINDING;
|
||||
}
|
||||
|
||||
public SelfSignatureSubpackets getHashedSubpackets() {
|
||||
return hashedSubpackets;
|
||||
}
|
||||
|
||||
public SelfSignatureSubpackets getUnhashedSubpackets() {
|
||||
return unhashedSubpackets;
|
||||
}
|
||||
|
||||
public PGPSignature build(PGPPublicKey subkey) throws PGPException {
|
||||
return buildAndInitSignatureGenerator()
|
||||
.generateCertification(publicSigningKey, subkey);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.bcpg.sig.EmbeddedSignature;
|
||||
import org.bouncycastle.bcpg.sig.Exportable;
|
||||
import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint;
|
||||
import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
||||
import org.bouncycastle.bcpg.sig.IssuerKeyID;
|
||||
import org.bouncycastle.bcpg.sig.NotationData;
|
||||
import org.bouncycastle.bcpg.sig.Revocable;
|
||||
import org.bouncycastle.bcpg.sig.SignatureCreationTime;
|
||||
import org.bouncycastle.bcpg.sig.SignatureExpirationTime;
|
||||
import org.bouncycastle.bcpg.sig.SignatureTarget;
|
||||
import org.bouncycastle.bcpg.sig.SignerUserID;
|
||||
import org.bouncycastle.bcpg.sig.TrustSignature;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm;
|
||||
|
||||
public interface BaseSignatureSubpackets {
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerFingerprintAndKeyId(PGPPublicKey key);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerKeyId(long keyId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerKeyId(boolean isCritical, long keyId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerKeyId(@Nullable IssuerKeyID issuerKeyID);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerFingerprint(@Nonnull PGPPublicKey key);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerFingerprint(boolean isCritical, @Nonnull PGPPublicKey key);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setIssuerFingerprint(@Nullable IssuerFingerprint fingerprint);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureCreationTime(@Nonnull Date creationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureCreationTime(boolean isCritical, @Nonnull Date creationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureCreationTime(@Nullable SignatureCreationTime signatureCreationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(@Nonnull Date creationTime, @Nonnull Date expirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(boolean isCritical, @Nonnull Date creationTime, @Nonnull Date expirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(boolean isCritical, long seconds);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(@Nullable SignatureExpirationTime expirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignerUserId(@Nonnull String userId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignerUserId(boolean isCritical, @Nonnull String userId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignerUserId(@Nullable SignerUserID signerUserId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addNotationData(boolean isCritical, @Nonnull String notationName, @Nonnull String notationValue);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addNotationData(@Nonnull NotationData notationData);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper clearNotationData();
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(@Nonnull PGPPublicKey recipient);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(boolean isCritical, @Nonnull PGPPublicKey recipient);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(IntendedRecipientFingerprint intendedRecipientFingerprint);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper clearIntendedRecipientFingerprints();
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setExportable(boolean isCritical, boolean isExportable);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setExportable(@Nullable Exportable exportable);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocable(boolean isCritical, boolean isRevocable);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocable(@Nullable Revocable revocable);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureTarget(@Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureTarget(boolean isCritical, @Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setSignatureTarget(@Nullable SignatureTarget signatureTarget);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setTrust(int depth, int amount);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setTrust(boolean isCritical, int depth, int amount);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setTrust(@Nullable TrustSignature trust);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addEmbeddedSignature(@Nonnull PGPSignature signature) throws IOException;
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addEmbeddedSignature(boolean isCritical, @Nonnull PGPSignature signature) throws IOException;
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addEmbeddedSignature(@Nonnull EmbeddedSignature embeddedSignature);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper clearEmbeddedSignatures();
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.bcpg.sig.RevocationReason;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
|
||||
public interface RevocationSignatureSubpackets extends BaseSignatureSubpackets {
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocationReason(RevocationAttributes revocationAttributes);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocationReason(boolean isCritical, RevocationAttributes revocationAttributes);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocationReason(boolean isCritical, RevocationAttributes.Reason reason, @Nonnull String description);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setRevocationReason(@Nullable RevocationReason reason);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
public interface SelfSignatureSubpacketCallback {
|
||||
|
||||
void modifyHashedSubpackets(SelfSignatureSubpackets subpackets);
|
||||
|
||||
void modifyUnhashedSubpackets(SelfSignatureSubpackets subpackets);
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.bcpg.sig.Features;
|
||||
import org.bouncycastle.bcpg.sig.KeyExpirationTime;
|
||||
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
|
||||
import org.bouncycastle.bcpg.sig.PrimaryUserID;
|
||||
import org.bouncycastle.bcpg.sig.RevocationKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
import org.pgpainless.algorithm.Feature;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
|
||||
public interface SelfSignatureSubpackets extends BaseSignatureSubpackets {
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyFlags(KeyFlag... keyFlags);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyFlags(boolean isCritical, KeyFlag... keyFlags);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyFlags(@Nullable KeyFlags keyFlags);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPrimaryUserId();
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPrimaryUserId(boolean isCritical);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPrimaryUserId(@Nullable PrimaryUserID primaryUserId);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyExpirationTime(boolean isCritical, long secondsFromCreationToExpiration);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nullable KeyExpirationTime keyExpirationTime);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(Set<CompressionAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(boolean isCritical, Set<CompressionAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(@Nullable PreferredAlgorithms algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm... algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(Set<SymmetricKeyAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(boolean isCritical, Set<SymmetricKeyAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(@Nullable PreferredAlgorithms algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(HashAlgorithm... algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(Set<HashAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(boolean isCritical, Set<HashAlgorithm> algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(@Nullable PreferredAlgorithms algorithms);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addRevocationKey(@Nonnull PGPPublicKey revocationKey);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addRevocationKey(boolean isCritical, @Nonnull PGPPublicKey revocationKey);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addRevocationKey(boolean isCritical, boolean isSensitive, @Nonnull PGPPublicKey revocationKey);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper addRevocationKey(@Nonnull RevocationKey revocationKey);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper clearRevocationKeys();
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setFeatures(Feature... features);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setFeatures(boolean isCritical, Feature... features);
|
||||
|
||||
SignatureSubpacketGeneratorWrapper setFeatures(@Nullable Features features);
|
||||
}
|
|
@ -0,0 +1,583 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.bcpg.SignatureSubpacket;
|
||||
import org.bouncycastle.bcpg.SignatureSubpacketTags;
|
||||
import org.bouncycastle.bcpg.sig.EmbeddedSignature;
|
||||
import org.bouncycastle.bcpg.sig.Exportable;
|
||||
import org.bouncycastle.bcpg.sig.Features;
|
||||
import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint;
|
||||
import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
||||
import org.bouncycastle.bcpg.sig.IssuerKeyID;
|
||||
import org.bouncycastle.bcpg.sig.KeyExpirationTime;
|
||||
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||
import org.bouncycastle.bcpg.sig.NotationData;
|
||||
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
|
||||
import org.bouncycastle.bcpg.sig.PrimaryUserID;
|
||||
import org.bouncycastle.bcpg.sig.Revocable;
|
||||
import org.bouncycastle.bcpg.sig.RevocationKey;
|
||||
import org.bouncycastle.bcpg.sig.RevocationReason;
|
||||
import org.bouncycastle.bcpg.sig.SignatureCreationTime;
|
||||
import org.bouncycastle.bcpg.sig.SignatureExpirationTime;
|
||||
import org.bouncycastle.bcpg.sig.SignatureTarget;
|
||||
import org.bouncycastle.bcpg.sig.SignerUserID;
|
||||
import org.bouncycastle.bcpg.sig.TrustSignature;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
import org.pgpainless.algorithm.Feature;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm;
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
|
||||
public class SignatureSubpacketGeneratorWrapper
|
||||
implements BaseSignatureSubpackets, SelfSignatureSubpackets, RevocationSignatureSubpackets {
|
||||
|
||||
private SignatureCreationTime signatureCreationTime;
|
||||
private SignatureExpirationTime signatureExpirationTime;
|
||||
private IssuerKeyID issuerKeyID;
|
||||
private IssuerFingerprint issuerFingerprint;
|
||||
private final List<NotationData> notationDataList = new ArrayList<>();
|
||||
private final List<IntendedRecipientFingerprint> intendedRecipientFingerprintList = new ArrayList<>();
|
||||
private final List<RevocationKey> revocationKeyList = new ArrayList<>();
|
||||
private Exportable exportable;
|
||||
private SignatureTarget signatureTarget;
|
||||
private Features features;
|
||||
private KeyFlags keyFlags;
|
||||
private TrustSignature trust;
|
||||
private PreferredAlgorithms preferredCompressionAlgorithms;
|
||||
private PreferredAlgorithms preferredSymmetricKeyAlgorithms;
|
||||
private PreferredAlgorithms preferredHashAlgorithms;
|
||||
private final List<EmbeddedSignature> embeddedSignatureList = new ArrayList<>();
|
||||
private SignerUserID signerUserId;
|
||||
private KeyExpirationTime keyExpirationTime;
|
||||
private PrimaryUserID primaryUserId;
|
||||
private Revocable revocable;
|
||||
private RevocationReason revocationReason;
|
||||
|
||||
public SignatureSubpacketGeneratorWrapper() {
|
||||
setSignatureCreationTime(new Date());
|
||||
}
|
||||
|
||||
public SignatureSubpacketGeneratorWrapper(PGPPublicKey issuer) {
|
||||
this();
|
||||
setIssuerFingerprintAndKeyId(issuer);
|
||||
}
|
||||
|
||||
public PGPSignatureSubpacketGenerator getGenerator() {
|
||||
PGPSignatureSubpacketGenerator generator = new PGPSignatureSubpacketGenerator();
|
||||
|
||||
addSubpacket(generator, issuerKeyID);
|
||||
addSubpacket(generator, issuerFingerprint);
|
||||
addSubpacket(generator, signatureCreationTime);
|
||||
addSubpacket(generator, signatureExpirationTime);
|
||||
addSubpacket(generator, exportable);
|
||||
for (NotationData notationData : notationDataList) {
|
||||
addSubpacket(generator, notationData);
|
||||
}
|
||||
for (IntendedRecipientFingerprint intendedRecipientFingerprint : intendedRecipientFingerprintList) {
|
||||
addSubpacket(generator, intendedRecipientFingerprint);
|
||||
}
|
||||
for (RevocationKey revocationKey : revocationKeyList) {
|
||||
addSubpacket(generator, revocationKey);
|
||||
}
|
||||
addSubpacket(generator, signatureTarget);
|
||||
addSubpacket(generator, features);
|
||||
addSubpacket(generator, keyFlags);
|
||||
addSubpacket(generator, trust);
|
||||
addSubpacket(generator, preferredCompressionAlgorithms);
|
||||
addSubpacket(generator, preferredSymmetricKeyAlgorithms);
|
||||
addSubpacket(generator, preferredHashAlgorithms);
|
||||
for (EmbeddedSignature embeddedSignature : embeddedSignatureList) {
|
||||
addSubpacket(generator, embeddedSignature);
|
||||
}
|
||||
addSubpacket(generator, signerUserId);
|
||||
addSubpacket(generator, keyExpirationTime);
|
||||
addSubpacket(generator, primaryUserId);
|
||||
addSubpacket(generator, revocable);
|
||||
addSubpacket(generator, revocationReason);
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerFingerprintAndKeyId(PGPPublicKey key) {
|
||||
setIssuerKeyId(key.getKeyID());
|
||||
setIssuerFingerprint(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerKeyId(long keyId) {
|
||||
return setIssuerKeyId(true, keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerKeyId(boolean isCritical, long keyId) {
|
||||
return setIssuerKeyId(new IssuerKeyID(isCritical, keyId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerKeyId(@Nullable IssuerKeyID issuerKeyID) {
|
||||
this.issuerKeyID = issuerKeyID;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerFingerprint(@Nonnull PGPPublicKey key) {
|
||||
return setIssuerFingerprint(true, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerFingerprint(boolean isCritical, @Nonnull PGPPublicKey key) {
|
||||
return setIssuerFingerprint(new IssuerFingerprint(isCritical, key.getVersion(), key.getFingerprint()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setIssuerFingerprint(@Nullable IssuerFingerprint fingerprint) {
|
||||
this.issuerFingerprint = fingerprint;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyFlags(KeyFlag... keyFlags) {
|
||||
return setKeyFlags(true, keyFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyFlags(boolean isCritical, KeyFlag... keyFlags) {
|
||||
int bitmask = KeyFlag.toBitmask(keyFlags);
|
||||
return setKeyFlags(new KeyFlags(isCritical, bitmask));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyFlags(@Nullable KeyFlags keyFlags) {
|
||||
this.keyFlags = keyFlags;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureCreationTime(@Nonnull Date creationTime) {
|
||||
return setSignatureCreationTime(true, creationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureCreationTime(boolean isCritical, @Nonnull Date creationTime) {
|
||||
return setSignatureCreationTime(new SignatureCreationTime(isCritical, creationTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureCreationTime(@Nullable SignatureCreationTime signatureCreationTime) {
|
||||
this.signatureCreationTime = signatureCreationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(@Nonnull Date creationTime, @Nonnull Date expirationTime) {
|
||||
return setSignatureExpirationTime(true, creationTime, expirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(boolean isCritical, @Nonnull Date creationTime, @Nonnull Date expirationTime) {
|
||||
return setSignatureExpirationTime(isCritical, (expirationTime.getTime() / 1000) - (creationTime.getTime() / 1000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(boolean isCritical, long seconds) {
|
||||
if (seconds < 0) {
|
||||
throw new IllegalArgumentException("Expiration time cannot be negative.");
|
||||
}
|
||||
return setSignatureExpirationTime(new SignatureExpirationTime(isCritical, seconds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureExpirationTime(@Nullable SignatureExpirationTime expirationTime) {
|
||||
this.signatureExpirationTime = expirationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignerUserId(@Nonnull String userId) {
|
||||
return setSignerUserId(false, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignerUserId(boolean isCritical, @Nonnull String userId) {
|
||||
return setSignerUserId(new SignerUserID(isCritical, userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignerUserId(@Nullable SignerUserID signerUserId) {
|
||||
this.signerUserId = signerUserId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPrimaryUserId() {
|
||||
return setPrimaryUserId(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPrimaryUserId(boolean isCritical) {
|
||||
return setPrimaryUserId(new PrimaryUserID(isCritical, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPrimaryUserId(@Nullable PrimaryUserID primaryUserId) {
|
||||
this.primaryUserId = primaryUserId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime) {
|
||||
return setKeyExpirationTime(key.getCreationTime(), keyExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) {
|
||||
return setKeyExpirationTime(true, keyCreationTime, keyExpirationTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) {
|
||||
return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyExpirationTime(boolean isCritical, long secondsFromCreationToExpiration) {
|
||||
if (secondsFromCreationToExpiration < 0) {
|
||||
throw new IllegalArgumentException("Seconds from key creation to expiration cannot be less than 0.");
|
||||
}
|
||||
return setKeyExpirationTime(new KeyExpirationTime(isCritical, secondsFromCreationToExpiration));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setKeyExpirationTime(@Nullable KeyExpirationTime keyExpirationTime) {
|
||||
this.keyExpirationTime = keyExpirationTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms) {
|
||||
return setPreferredCompressionAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(Set<CompressionAlgorithm> algorithms) {
|
||||
return setPreferredCompressionAlgorithms(true, algorithms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(boolean isCritical, Set<CompressionAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
Iterator<CompressionAlgorithm> iterator = algorithms.iterator();
|
||||
for (int i = 0; i < algorithms.size(); i++) {
|
||||
ids[i] = iterator.next().getAlgorithmId();
|
||||
}
|
||||
return setPreferredCompressionAlgorithms(new PreferredAlgorithms(
|
||||
SignatureSubpacketTags.PREFERRED_COMP_ALGS, isCritical, ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(@Nullable PreferredAlgorithms algorithms) {
|
||||
if (algorithms == null) {
|
||||
this.preferredCompressionAlgorithms = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (algorithms.getType() != SignatureSubpacketTags.PREFERRED_COMP_ALGS) {
|
||||
throw new IllegalArgumentException("Invalid preferred compression algorithms type.");
|
||||
}
|
||||
this.preferredCompressionAlgorithms = algorithms;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm... algorithms) {
|
||||
return setPreferredSymmetricKeyAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(Set<SymmetricKeyAlgorithm> algorithms) {
|
||||
return setPreferredSymmetricKeyAlgorithms(true, algorithms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(boolean isCritical, Set<SymmetricKeyAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
Iterator<SymmetricKeyAlgorithm> iterator = algorithms.iterator();
|
||||
for (int i = 0; i < algorithms.size(); i++) {
|
||||
ids[i] = iterator.next().getAlgorithmId();
|
||||
}
|
||||
return setPreferredSymmetricKeyAlgorithms(new PreferredAlgorithms(
|
||||
SignatureSubpacketTags.PREFERRED_SYM_ALGS, isCritical, ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(@Nullable PreferredAlgorithms algorithms) {
|
||||
if (algorithms == null) {
|
||||
this.preferredSymmetricKeyAlgorithms = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (algorithms.getType() != SignatureSubpacketTags.PREFERRED_SYM_ALGS) {
|
||||
throw new IllegalArgumentException("Invalid preferred symmetric key algorithms type.");
|
||||
}
|
||||
this.preferredSymmetricKeyAlgorithms = algorithms;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(HashAlgorithm... algorithms) {
|
||||
return setPreferredHashAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(Set<HashAlgorithm> algorithms) {
|
||||
return setPreferredHashAlgorithms(true, algorithms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(boolean isCritical, Set<HashAlgorithm> algorithms) {
|
||||
int[] ids = new int[algorithms.size()];
|
||||
Iterator<HashAlgorithm> iterator = algorithms.iterator();
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
ids[i] = iterator.next().getAlgorithmId();
|
||||
}
|
||||
return setPreferredHashAlgorithms(new PreferredAlgorithms(
|
||||
SignatureSubpacketTags.PREFERRED_HASH_ALGS, isCritical, ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(@Nullable PreferredAlgorithms algorithms) {
|
||||
if (algorithms == null) {
|
||||
preferredHashAlgorithms = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
if (algorithms.getType() != SignatureSubpacketTags.PREFERRED_HASH_ALGS) {
|
||||
throw new IllegalArgumentException("Invalid preferred hash algorithms type.");
|
||||
}
|
||||
this.preferredHashAlgorithms = algorithms;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addNotationData(boolean isCritical, @Nonnull String notationName, @Nonnull String notationValue) {
|
||||
return addNotationData(new NotationData(isCritical, true, notationName, notationValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addNotationData(@Nonnull NotationData notationData) {
|
||||
notationDataList.add(notationData);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper clearNotationData() {
|
||||
notationDataList.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(@Nonnull PGPPublicKey recipient) {
|
||||
return addIntendedRecipientFingerprint(false, recipient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(boolean isCritical, @Nonnull PGPPublicKey recipient) {
|
||||
return addIntendedRecipientFingerprint(new IntendedRecipientFingerprint(isCritical, recipient.getVersion(), recipient.getFingerprint()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addIntendedRecipientFingerprint(IntendedRecipientFingerprint intendedRecipientFingerprint) {
|
||||
this.intendedRecipientFingerprintList.add(intendedRecipientFingerprint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper clearIntendedRecipientFingerprints() {
|
||||
intendedRecipientFingerprintList.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setExportable(boolean isCritical, boolean isExportable) {
|
||||
return setExportable(new Exportable(isCritical, isExportable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setExportable(@Nullable Exportable exportable) {
|
||||
this.exportable = exportable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocable(boolean isCritical, boolean isRevocable) {
|
||||
return setRevocable(new Revocable(isCritical, isRevocable));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocable(@Nullable Revocable revocable) {
|
||||
this.revocable = revocable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addRevocationKey(@Nonnull PGPPublicKey revocationKey) {
|
||||
return addRevocationKey(true, revocationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addRevocationKey(boolean isCritical, @Nonnull PGPPublicKey revocationKey) {
|
||||
return addRevocationKey(isCritical, false, revocationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addRevocationKey(boolean isCritical, boolean isSensitive, @Nonnull PGPPublicKey revocationKey) {
|
||||
byte clazz = (byte) 0x80;
|
||||
clazz |= (isSensitive ? 0x40 : 0x00);
|
||||
return addRevocationKey(new RevocationKey(isCritical, clazz, revocationKey.getAlgorithm(), revocationKey.getFingerprint()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addRevocationKey(@Nonnull RevocationKey revocationKey) {
|
||||
this.revocationKeyList.add(revocationKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper clearRevocationKeys() {
|
||||
revocationKeyList.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocationReason(RevocationAttributes revocationAttributes) {
|
||||
return setRevocationReason(true, revocationAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocationReason(boolean isCritical, RevocationAttributes revocationAttributes) {
|
||||
return setRevocationReason(isCritical, revocationAttributes.getReason(), revocationAttributes.getDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocationReason(boolean isCritical, RevocationAttributes.Reason reason, @Nonnull String description) {
|
||||
return setRevocationReason(new RevocationReason(isCritical, reason.code(), description));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setRevocationReason(@Nullable RevocationReason reason) {
|
||||
this.revocationReason = reason;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureTarget(@Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData) {
|
||||
return setSignatureTarget(true, keyAlgorithm, hashAlgorithm, hashData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureTarget(boolean isCritical, @Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData) {
|
||||
return setSignatureTarget(new SignatureTarget(isCritical, keyAlgorithm.getAlgorithmId(), hashAlgorithm.getAlgorithmId(), hashData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setSignatureTarget(@Nullable SignatureTarget signatureTarget) {
|
||||
this.signatureTarget = signatureTarget;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setFeatures(Feature... features) {
|
||||
return setFeatures(true, features);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setFeatures(boolean isCritical, Feature... features) {
|
||||
byte bitmask = Feature.toBitmask(features);
|
||||
return setFeatures(new Features(isCritical, bitmask));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setFeatures(@Nullable Features features) {
|
||||
this.features = features;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setTrust(int depth, int amount) {
|
||||
return setTrust(true, depth, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setTrust(boolean isCritical, int depth, int amount) {
|
||||
return setTrust(new TrustSignature(isCritical, depth, amount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper setTrust(@Nullable TrustSignature trust) {
|
||||
this.trust = trust;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addEmbeddedSignature(@Nonnull PGPSignature signature) throws IOException {
|
||||
return addEmbeddedSignature(true, signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addEmbeddedSignature(boolean isCritical, @Nonnull PGPSignature signature) throws IOException {
|
||||
byte[] sig = signature.getEncoded();
|
||||
byte[] data;
|
||||
|
||||
if (sig.length - 1 > 256)
|
||||
{
|
||||
data = new byte[sig.length - 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new byte[sig.length - 2];
|
||||
}
|
||||
|
||||
System.arraycopy(sig, sig.length - data.length, data, 0, data.length);
|
||||
|
||||
return addEmbeddedSignature(new EmbeddedSignature(isCritical, false, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper addEmbeddedSignature(@Nonnull EmbeddedSignature embeddedSignature) {
|
||||
this.embeddedSignatureList.add(embeddedSignature);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureSubpacketGeneratorWrapper clearEmbeddedSignatures() {
|
||||
this.embeddedSignatureList.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void addSubpacket(PGPSignatureSubpacketGenerator generator, SignatureSubpacket subpacket) {
|
||||
if (subpacket != null) {
|
||||
generator.addCustomSubpacket(subpacket);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,441 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.subpackets;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bouncycastle.bcpg.SignatureSubpacket;
|
||||
import org.bouncycastle.bcpg.SignatureSubpacketTags;
|
||||
import org.bouncycastle.bcpg.sig.Exportable;
|
||||
import org.bouncycastle.bcpg.sig.Features;
|
||||
import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
||||
import org.bouncycastle.bcpg.sig.NotationData;
|
||||
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
|
||||
import org.bouncycastle.bcpg.sig.Revocable;
|
||||
import org.bouncycastle.bcpg.sig.RevocationKey;
|
||||
import org.bouncycastle.bcpg.sig.RevocationReason;
|
||||
import org.bouncycastle.bcpg.sig.SignatureTarget;
|
||||
import org.bouncycastle.bcpg.sig.TrustSignature;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
import org.pgpainless.algorithm.Feature;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
import org.pgpainless.implementation.ImplementationFactory;
|
||||
import org.pgpainless.key.TestKeys;
|
||||
import org.pgpainless.key.protection.UnlockSecretKey;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
|
||||
public class SignatureSubpacketGeneratorWrapperTest {
|
||||
|
||||
private static PGPPublicKeyRing keys;
|
||||
private static PGPPublicKey key;
|
||||
|
||||
private SignatureSubpacketGeneratorWrapper wrapper;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
keys = TestKeys.getEmilPublicKeyRing();
|
||||
key = keys.getPublicKey();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void createWrapper() {
|
||||
wrapper = new SignatureSubpacketGeneratorWrapper(key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialStateTest() {
|
||||
Date now = new Date();
|
||||
wrapper = new SignatureSubpacketGeneratorWrapper();
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initialStateFromKeyTest() throws PGPException {
|
||||
Date now = new Date();
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(key.getKeyID(), vector.getIssuerKeyID());
|
||||
assertEquals(key.getVersion(), vector.getIssuerFingerprint().getKeyVersion());
|
||||
assertArrayEquals(key.getFingerprint(), vector.getIssuerFingerprint().getFingerprint());
|
||||
assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 2000);
|
||||
|
||||
assertEquals(0, vector.getKeyFlags());
|
||||
assertEquals(0, vector.getSignatureExpirationTime());
|
||||
assertNull(vector.getSignerUserID());
|
||||
assertFalse(vector.isPrimaryUserID());
|
||||
assertEquals(0, vector.getKeyExpirationTime());
|
||||
assertNull(vector.getPreferredCompressionAlgorithms());
|
||||
assertNull(vector.getPreferredSymmetricAlgorithms());
|
||||
assertNull(vector.getPreferredHashAlgorithms());
|
||||
assertEquals(0, vector.getNotationDataOccurrences().length);
|
||||
assertNull(vector.getIntendedRecipientFingerprint());
|
||||
assertNull(vector.getSubpacket(SignatureSubpacketTags.EXPORTABLE));
|
||||
assertNull(vector.getSubpacket(SignatureSubpacketTags.REVOCATION_KEY));
|
||||
assertNull(vector.getSubpacket(SignatureSubpacketTags.REVOCATION_REASON));
|
||||
assertNull(vector.getSignatureTarget());
|
||||
assertNull(vector.getFeatures());
|
||||
assertNull(vector.getSubpacket(SignatureSubpacketTags.TRUST_SIG));
|
||||
assertTrue(vector.getEmbeddedSignatures().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullKeyId() {
|
||||
wrapper.setIssuerKeyId(null);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(0, vector.getIssuerKeyID());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNullFingerprint() {
|
||||
wrapper.setIssuerFingerprint((IssuerFingerprint) null);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertNull(vector.getIssuerFingerprint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNotationData() {
|
||||
wrapper.addNotationData(true, "critical@notation.data", "isCritical");
|
||||
wrapper.addNotationData(false, "noncrit@notation.data", "notCritical");
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
NotationData[] notationData = vector.getNotationDataOccurrences();
|
||||
assertEquals(2, notationData.length);
|
||||
NotationData first = notationData[0];
|
||||
assertTrue(first.isCritical());
|
||||
assertTrue(first.isHumanReadable());
|
||||
assertEquals("critical@notation.data", first.getNotationName());
|
||||
assertEquals("isCritical", first.getNotationValue());
|
||||
|
||||
NotationData second = notationData[1];
|
||||
assertFalse(second.isCritical());
|
||||
assertTrue(second.isHumanReadable());
|
||||
assertEquals("noncrit@notation.data", second.getNotationName());
|
||||
assertEquals("notCritical", second.getNotationValue());
|
||||
|
||||
wrapper.clearNotationData();
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getNotationDataOccurrences().length);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntendedRecipientFingerprints() {
|
||||
wrapper.addIntendedRecipientFingerprint(key);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(1, vector.getSubpackets(SignatureSubpacketTags.INTENDED_RECIPIENT_FINGERPRINT).length);
|
||||
assertArrayEquals(key.getFingerprint(), vector.getIntendedRecipientFingerprint().getFingerprint());
|
||||
assertEquals(key.getVersion(), vector.getIntendedRecipientFingerprint().getKeyVersion());
|
||||
|
||||
wrapper.clearIntendedRecipientFingerprints();
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getSubpackets(SignatureSubpacketTags.INTENDED_RECIPIENT_FINGERPRINT).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRevocationKeys() {
|
||||
Iterator<PGPPublicKey> keyIterator = keys.getPublicKeys();
|
||||
PGPPublicKey first = keyIterator.next();
|
||||
wrapper.addRevocationKey(first);
|
||||
assertTrue(keyIterator.hasNext());
|
||||
PGPPublicKey second = keyIterator.next();
|
||||
wrapper.addRevocationKey(false, true, second);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
SignatureSubpacket[] revKeys = vector.getSubpackets(SignatureSubpacketTags.REVOCATION_KEY);
|
||||
assertEquals(2, revKeys.length);
|
||||
RevocationKey r1 = (RevocationKey) revKeys[0];
|
||||
RevocationKey r2 = (RevocationKey) revKeys[1];
|
||||
|
||||
assertTrue(r1.isCritical());
|
||||
assertArrayEquals(first.getFingerprint(), r1.getFingerprint());
|
||||
assertEquals(first.getAlgorithm(), r1.getAlgorithm());
|
||||
assertEquals((byte) 0x80, r1.getSignatureClass());
|
||||
|
||||
assertFalse(r2.isCritical());
|
||||
assertArrayEquals(second.getFingerprint(), r2.getFingerprint());
|
||||
assertEquals(second.getAlgorithm(), r2.getAlgorithm());
|
||||
assertEquals((byte) (0x80 | 0x40), r2.getSignatureClass());
|
||||
|
||||
wrapper.clearRevocationKeys();
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getSubpackets(SignatureSubpacketTags.REVOCATION_KEY).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKeyFlags() {
|
||||
wrapper.setKeyFlags(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA); // duplicates are removed
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(KeyFlag.toBitmask(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER), vector.getKeyFlags());
|
||||
assertTrue(vector.getSubpacket(SignatureSubpacketTags.KEY_FLAGS).isCritical());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignatureExpirationTime() {
|
||||
Date now = new Date();
|
||||
long secondsInAWeek = 60 * 60 * 24 * 7;
|
||||
Date inAWeek = new Date(now.getTime() + 1000 * secondsInAWeek);
|
||||
wrapper.setSignatureExpirationTime(now, inAWeek);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(secondsInAWeek, vector.getSignatureExpirationTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignatureExpirationTimeCannotBeNegative() {
|
||||
Date now = new Date();
|
||||
long secondsInAWeek = 60 * 60 * 24 * 7;
|
||||
Date oneWeekEarlier = new Date(now.getTime() - 1000 * secondsInAWeek);
|
||||
assertThrows(IllegalArgumentException.class, () -> wrapper.setSignatureExpirationTime(now, oneWeekEarlier));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSignerUserId() {
|
||||
String userId = "Alice <alice@pgpainless.org>";
|
||||
wrapper.setSignerUserId(userId);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(userId, vector.getSignerUserID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetPrimaryUserId() {
|
||||
assertFalse(wrapper.getGenerator().generate().isPrimaryUserID());
|
||||
|
||||
wrapper.setPrimaryUserId();
|
||||
assertTrue(wrapper.getGenerator().generate().isPrimaryUserID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKeyExpiration() {
|
||||
Date now = new Date();
|
||||
long secondsSinceKeyCreation = (now.getTime() - key.getCreationTime().getTime()) / 1000;
|
||||
wrapper.setKeyExpirationTime(key, now);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(secondsSinceKeyCreation, vector.getKeyExpirationTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetKeyExpirationCannotBeNegative() {
|
||||
Date beforeKeyCreation = new Date(key.getCreationTime().getTime() - 10000);
|
||||
assertThrows(IllegalArgumentException.class, () -> wrapper.setKeyExpirationTime(key, beforeKeyCreation));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetPreferredCompressionAlgorithms() {
|
||||
wrapper.setPreferredCompressionAlgorithms(CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZIP, CompressionAlgorithm.BZIP2); // duplicates get removed
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
int[] ids = vector.getPreferredCompressionAlgorithms();
|
||||
assertEquals(2, ids.length);
|
||||
assertEquals(CompressionAlgorithm.BZIP2.getAlgorithmId(), ids[0]);
|
||||
assertEquals(CompressionAlgorithm.ZIP.getAlgorithmId(), ids[1]);
|
||||
|
||||
wrapper.setPreferredCompressionAlgorithms(); // empty
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getPreferredCompressionAlgorithms().length);
|
||||
|
||||
wrapper.setPreferredCompressionAlgorithms((PreferredAlgorithms) null);
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertNull(vector.getPreferredCompressionAlgorithms());
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredCompressionAlgorithms(
|
||||
new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_SYM_ALGS, true, new int[0])));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetPreferredSymmetricKeyAlgorithms() {
|
||||
wrapper.setPreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128, SymmetricKeyAlgorithm.AES_128); // duplicates get removed
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
int[] ids = vector.getPreferredSymmetricAlgorithms();
|
||||
assertEquals(2, ids.length);
|
||||
assertEquals(SymmetricKeyAlgorithm.AES_192.getAlgorithmId(), ids[0]);
|
||||
assertEquals(SymmetricKeyAlgorithm.AES_128.getAlgorithmId(), ids[1]);
|
||||
|
||||
wrapper.setPreferredSymmetricKeyAlgorithms(); // empty
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getPreferredSymmetricAlgorithms().length);
|
||||
|
||||
wrapper.setPreferredSymmetricKeyAlgorithms((PreferredAlgorithms) null);
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertNull(vector.getPreferredCompressionAlgorithms());
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredSymmetricKeyAlgorithms(
|
||||
new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_HASH_ALGS, true, new int[0])));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetPreferredHashAlgorithms() {
|
||||
wrapper.setPreferredHashAlgorithms(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA512); // duplicates get removed
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
int[] ids = vector.getPreferredHashAlgorithms();
|
||||
assertEquals(2, ids.length);
|
||||
assertEquals(HashAlgorithm.SHA512.getAlgorithmId(), ids[0]);
|
||||
assertEquals(HashAlgorithm.SHA384.getAlgorithmId(), ids[1]);
|
||||
|
||||
wrapper.setPreferredHashAlgorithms(); // empty
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getPreferredHashAlgorithms().length);
|
||||
|
||||
wrapper.setPreferredHashAlgorithms((PreferredAlgorithms) null);
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertNull(vector.getPreferredHashAlgorithms());
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredHashAlgorithms(
|
||||
new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_COMP_ALGS, true, new int[0])));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetExportable() {
|
||||
wrapper.setExportable(true, false);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
Exportable exportable = (Exportable) vector.getSubpacket(SignatureSubpacketTags.EXPORTABLE);
|
||||
assertTrue(exportable.isCritical());
|
||||
assertFalse(exportable.isExportable());
|
||||
|
||||
wrapper.setExportable(false, true);
|
||||
vector = wrapper.getGenerator().generate();
|
||||
|
||||
exportable = (Exportable) vector.getSubpacket(SignatureSubpacketTags.EXPORTABLE);
|
||||
assertFalse(exportable.isCritical());
|
||||
assertTrue(exportable.isExportable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRevocable() {
|
||||
wrapper.setRevocable(true, true);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
Revocable revocable = (Revocable) vector.getSubpacket(SignatureSubpacketTags.REVOCABLE);
|
||||
assertTrue(revocable.isCritical());
|
||||
assertTrue(revocable.isRevocable());
|
||||
|
||||
wrapper.setRevocable(false, false);
|
||||
vector = wrapper.getGenerator().generate();
|
||||
|
||||
revocable = (Revocable) vector.getSubpacket(SignatureSubpacketTags.REVOCABLE);
|
||||
assertFalse(revocable.isCritical());
|
||||
assertFalse(revocable.isRevocable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetRevocationReason() {
|
||||
wrapper.setRevocationReason(RevocationAttributes.createKeyRevocation()
|
||||
.withReason(RevocationAttributes.Reason.KEY_RETIRED).withDescription("The key is too weak."));
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
assertEquals(1, vector.getSubpackets(SignatureSubpacketTags.REVOCATION_REASON).length);
|
||||
RevocationReason reason = (RevocationReason) vector.getSubpacket(SignatureSubpacketTags.REVOCATION_REASON);
|
||||
assertEquals(RevocationAttributes.Reason.KEY_RETIRED.code(), reason.getRevocationReason());
|
||||
assertEquals("The key is too weak.", reason.getRevocationDescription());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSignatureTarget() {
|
||||
byte[] hash = new byte[20];
|
||||
new Random().nextBytes(hash);
|
||||
wrapper.setSignatureTarget(PublicKeyAlgorithm.fromId(key.getAlgorithm()), HashAlgorithm.SHA512, hash);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
SignatureTarget target = vector.getSignatureTarget();
|
||||
assertNotNull(target);
|
||||
assertEquals(key.getAlgorithm(), target.getPublicKeyAlgorithm());
|
||||
assertEquals(HashAlgorithm.SHA512.getAlgorithmId(), target.getHashAlgorithm());
|
||||
assertArrayEquals(hash, target.getHashData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFeatures() {
|
||||
wrapper.setFeatures(Feature.MODIFICATION_DETECTION, Feature.AEAD_ENCRYPTED_DATA);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
Features features = vector.getFeatures();
|
||||
assertTrue(features.supportsModificationDetection());
|
||||
assertTrue(features.supportsFeature(Features.FEATURE_AEAD_ENCRYPTED_DATA));
|
||||
assertFalse(features.supportsFeature(Features.FEATURE_VERSION_5_PUBLIC_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTrust() {
|
||||
wrapper.setTrust(10, 5);
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
|
||||
TrustSignature trustSignature = (TrustSignature) vector.getSubpacket(SignatureSubpacketTags.TRUST_SIG);
|
||||
assertNotNull(trustSignature);
|
||||
assertEquals(10, trustSignature.getDepth());
|
||||
assertEquals(5, trustSignature.getTrustAmount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddEmbeddedSignature() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
Iterator<PGPSecretKey> secretKeyIterator = secretKeys.iterator();
|
||||
PGPSecretKey primaryKey = secretKeyIterator.next();
|
||||
PGPSignatureGenerator generator = new PGPSignatureGenerator(
|
||||
ImplementationFactory.getInstance().getPGPContentSignerBuilder(primaryKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId())
|
||||
);
|
||||
|
||||
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, (Passphrase) null);
|
||||
generator.init(SignatureType.DIRECT_KEY.getCode(), privateKey);
|
||||
PGPSignature sig1 = generator.generateCertification(primaryKey.getPublicKey());
|
||||
|
||||
generator.init(SignatureType.DIRECT_KEY.getCode(), privateKey);
|
||||
PGPSignature sig2 = generator.generateCertification(secretKeyIterator.next().getPublicKey());
|
||||
|
||||
wrapper.addEmbeddedSignature(sig1);
|
||||
|
||||
PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate();
|
||||
assertEquals(1, vector.getEmbeddedSignatures().size());
|
||||
assertArrayEquals(sig1.getSignature(), vector.getEmbeddedSignatures().get(0).getSignature());
|
||||
|
||||
wrapper.addEmbeddedSignature(sig2);
|
||||
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(2, vector.getEmbeddedSignatures().size());
|
||||
assertArrayEquals(sig2.getSignature(), vector.getEmbeddedSignatures().get(1).getSignature());
|
||||
|
||||
wrapper.clearEmbeddedSignatures();
|
||||
vector = wrapper.getGenerator().generate();
|
||||
assertEquals(0, vector.getEmbeddedSignatures().size());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue