From 3d5a005ec7c1f9b7cc63c25d89f0efb6589e4813 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Tue, 9 Nov 2021 12:21:57 +0100 Subject: [PATCH] Make SignatureSubpackets more procedural --- .../key/generation/KeyRingBuilder.java | 16 +- .../pgpainless/key/generation/KeySpec.java | 13 +- .../builder/AbstractSignatureBuilder.java | 19 +- .../builder/UniversalSignatureBuilder.java | 6 +- .../subpackets/BaseSignatureSubpackets.java | 2 +- .../SignatureSubpacketGeneratorWrapper.java | 719 ------------------ .../subpackets/SignatureSubpackets.java | 660 ++++++++++++++++ .../subpackets/SignatureSubpacketsHelper.java | 180 +++++ ...Test.java => SignatureSubpacketsTest.java} | 93 ++- 9 files changed, 916 insertions(+), 792 deletions(-) delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java create mode 100644 pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java rename pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/{SignatureSubpacketGeneratorWrapperTest.java => SignatureSubpacketsTest.java} (86%) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java index 205b7b4e..e62a9d15 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Set; import javax.annotation.Nonnull; +import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPKeyRingGenerator; @@ -44,8 +45,8 @@ import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.provider.ProviderFactory; -import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; -import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorWrapper; +import org.pgpainless.signature.subpackets.SignatureSubpackets; +import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper; import org.pgpainless.util.Passphrase; public class KeyRingBuilder implements KeyRingBuilderInterface { @@ -112,9 +113,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { } private boolean hasCertifyOthersFlag(KeySpec keySpec) { - return SignatureSubpacketGeneratorUtil.hasKeyFlag(KeyFlag.CERTIFY_OTHER, - keySpec.getSubpacketGenerator() == null ? null : - keySpec.getSubpacketGenerator().getGenerator()); + KeyFlags keyFlags = keySpec.getSubpacketGenerator().getKeyFlagsSubpacket(); + return keyFlags != null && KeyFlag.hasKeyFlag(keyFlags.getFlags(), KeyFlag.CERTIFY_OTHER); } private boolean keyIsCertificationCapable(KeySpec keySpec) { @@ -137,12 +137,14 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { PGPKeyPair certKey = generateKeyPair(primaryKeySpec); PGPContentSignerBuilder signer = buildContentSigner(certKey); signatureGenerator = new PGPSignatureGenerator(signer); - SignatureSubpacketGeneratorWrapper hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); + SignatureSubpackets hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); hashedSubPacketGenerator.setPrimaryUserId(); if (expirationDate != null) { hashedSubPacketGenerator.setKeyExpirationTime(certKey.getPublicKey(), expirationDate); } - PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.getGenerator().generate(); + PGPSignatureSubpacketGenerator generator = new PGPSignatureSubpacketGenerator(); + SignatureSubpacketsHelper.applyTo(hashedSubPacketGenerator, generator); + PGPSignatureSubpacketVector hashedSubPackets = generator.generate(); // Generator which the user can get the key pair from PGPKeyRingGenerator ringGenerator = buildRingGenerator(certKey, signer, hashedSubPackets); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java index bff89af4..2249c854 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java @@ -10,12 +10,13 @@ import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.key.generation.type.KeyType; -import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorWrapper; +import org.pgpainless.signature.subpackets.SignatureSubpackets; +import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper; public class KeySpec { private final KeyType keyType; - private final SignatureSubpacketGeneratorWrapper subpacketGenerator; + private final SignatureSubpackets subpacketGenerator; private final boolean inheritedSubPackets; KeySpec(@Nonnull KeyType type, @@ -23,12 +24,12 @@ public class KeySpec { boolean inheritedSubPackets) { this( type, - SignatureSubpacketGeneratorWrapper.createSubpacketsFrom(subpacketGenerator.generate()), + SignatureSubpackets.createSubpacketsFrom(subpacketGenerator.generate()), inheritedSubPackets); } KeySpec(@Nonnull KeyType type, - @Nonnull SignatureSubpacketGeneratorWrapper subpacketGenerator, + @Nonnull SignatureSubpackets subpacketGenerator, boolean inheritedSubPackets) { this.keyType = type; this.subpacketGenerator = subpacketGenerator; @@ -42,11 +43,11 @@ public class KeySpec { @Nonnull public PGPSignatureSubpacketVector getSubpackets() { - return subpacketGenerator.getGenerator().generate(); + return SignatureSubpacketsHelper.toVector(subpacketGenerator); } @Nonnull - SignatureSubpacketGeneratorWrapper getSubpacketGenerator() { + SignatureSubpackets getSubpacketGenerator() { return subpacketGenerator; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/builder/AbstractSignatureBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/signature/builder/AbstractSignatureBuilder.java index 219e7d22..d919d49b 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/builder/AbstractSignatureBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/builder/AbstractSignatureBuilder.java @@ -21,7 +21,8 @@ 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; +import org.pgpainless.signature.subpackets.SignatureSubpackets; +import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper; public abstract class AbstractSignatureBuilder> { protected final PGPPrivateKey privateSigningKey; @@ -30,8 +31,8 @@ public abstract class AbstractSignatureBuilder { + interface Callback extends SignatureSubpacketCallback { } diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java deleted file mode 100644 index c4016709..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java +++ /dev/null @@ -1,719 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// 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.bouncycastle.openpgp.PGPSignatureSubpacketVector; -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, CertificationSubpackets, RevocationSignatureSubpackets { - - private SignatureCreationTime signatureCreationTime; - private SignatureExpirationTime signatureExpirationTime; - private IssuerKeyID issuerKeyID; - private IssuerFingerprint issuerFingerprint; - private final List notationDataList = new ArrayList<>(); - private final List intendedRecipientFingerprintList = new ArrayList<>(); - private final List 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 embeddedSignatureList = new ArrayList<>(); - private SignerUserID signerUserId; - private KeyExpirationTime keyExpirationTime; - private PrimaryUserID primaryUserId; - private Revocable revocable; - private RevocationReason revocationReason; - private final List unsupportedSubpackets = new ArrayList<>(); - - public SignatureSubpacketGeneratorWrapper() { - - } - - public static SignatureSubpacketGeneratorWrapper refreshHashedSubpackets(PGPPublicKey issuer, PGPSignature oldSignature) { - return createHashedSubpacketsFrom(issuer, oldSignature.getHashedSubPackets()); - } - - public static SignatureSubpacketGeneratorWrapper refreshUnhashedSubpackets(PGPSignature oldSignature) { - return createSubpacketsFrom(oldSignature.getUnhashedSubPackets()); - } - - public static SignatureSubpacketGeneratorWrapper createHashedSubpacketsFrom(PGPPublicKey issuer, PGPSignatureSubpacketVector base) { - SignatureSubpacketGeneratorWrapper wrapper = createSubpacketsFrom(base); - wrapper.setIssuerFingerprintAndKeyId(issuer); - return wrapper; - } - - public static SignatureSubpacketGeneratorWrapper createSubpacketsFrom(PGPSignatureSubpacketVector base) { - SignatureSubpacketGeneratorWrapper wrapper = new SignatureSubpacketGeneratorWrapper(); - wrapper.extractSubpacketsFromVector(base); - return wrapper; - } - - public static SignatureSubpacketGeneratorWrapper createEmptySubpackets() { - return new SignatureSubpacketGeneratorWrapper(); - } - - public static SignatureSubpacketGeneratorWrapper createHashedSubpackets() { - SignatureSubpacketGeneratorWrapper wrapper = new SignatureSubpacketGeneratorWrapper(); - wrapper.setSignatureCreationTime(new Date()); - return wrapper; - } - - public static SignatureSubpacketGeneratorWrapper createHashedSubpackets(PGPPublicKey issuer) { - SignatureSubpacketGeneratorWrapper wrapper = createHashedSubpackets(); - wrapper.setIssuerFingerprintAndKeyId(issuer); - return wrapper; - } - - private void extractSubpacketsFromVector(PGPSignatureSubpacketVector base) { - for (SignatureSubpacket subpacket : base.toArray()) { - org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType()); - switch (type) { - case signatureCreationTime: - case issuerKeyId: - case issuerFingerprint: - // ignore, we override this anyways - break; - case signatureExpirationTime: - SignatureExpirationTime sigExpTime = (SignatureExpirationTime) subpacket; - setSignatureExpirationTime(sigExpTime.isCritical(), sigExpTime.getTime()); - break; - case exportableCertification: - Exportable exp = (Exportable) subpacket; - setExportable(exp.isCritical(), exp.isExportable()); - break; - case trustSignature: - TrustSignature trustSignature = (TrustSignature) subpacket; - setTrust(trustSignature.isCritical(), trustSignature.getDepth(), trustSignature.getTrustAmount()); - break; - case revocable: - Revocable rev = (Revocable) subpacket; - setRevocable(rev.isCritical(), rev.isRevocable()); - break; - case keyExpirationTime: - KeyExpirationTime keyExpTime = (KeyExpirationTime) subpacket; - setKeyExpirationTime(keyExpTime.isCritical(), keyExpTime.getTime()); - break; - case preferredSymmetricAlgorithms: - setPreferredSymmetricKeyAlgorithms((PreferredAlgorithms) subpacket); - break; - case revocationKey: - RevocationKey revocationKey = (RevocationKey) subpacket; - addRevocationKey(revocationKey); - break; - case notationData: - NotationData notationData = (NotationData) subpacket; - addNotationData(notationData.isCritical(), notationData.getNotationName(), notationData.getNotationValue()); - break; - case preferredHashAlgorithms: - setPreferredHashAlgorithms((PreferredAlgorithms) subpacket); - break; - case preferredCompressionAlgorithms: - setPreferredCompressionAlgorithms((PreferredAlgorithms) subpacket); - break; - case primaryUserId: - PrimaryUserID primaryUserID = (PrimaryUserID) subpacket; - setPrimaryUserId(primaryUserID); - break; - case keyFlags: - KeyFlags flags = (KeyFlags) subpacket; - setKeyFlags(flags.isCritical(), KeyFlag.fromBitmask(flags.getFlags()).toArray(new KeyFlag[0])); - break; - case signerUserId: - SignerUserID signerUserID = (SignerUserID) subpacket; - setSignerUserId(signerUserID.isCritical(), signerUserID.getID()); - break; - case revocationReason: - RevocationReason reason = (RevocationReason) subpacket; - setRevocationReason(reason.isCritical(), - RevocationAttributes.Reason.fromCode(reason.getRevocationReason()), - reason.getRevocationDescription()); - break; - case features: - Features f = (Features) subpacket; - setFeatures(f.isCritical(), Feature.fromBitmask(f.getData()[0]).toArray(new Feature[0])); - break; - case signatureTarget: - SignatureTarget target = (SignatureTarget) subpacket; - setSignatureTarget(target.isCritical(), - PublicKeyAlgorithm.fromId(target.getPublicKeyAlgorithm()), - HashAlgorithm.fromId(target.getHashAlgorithm()), - target.getHashData()); - break; - case embeddedSignature: - EmbeddedSignature embeddedSignature = (EmbeddedSignature) subpacket; - addEmbeddedSignature(embeddedSignature); - break; - case intendedRecipientFingerprint: - IntendedRecipientFingerprint intendedRecipientFingerprint = (IntendedRecipientFingerprint) subpacket; - addIntendedRecipientFingerprint(intendedRecipientFingerprint); - break; - - case regularExpression: - case keyServerPreferences: - case preferredKeyServers: - case policyUrl: - case placeholder: - case preferredAEADAlgorithms: - case attestedCertification: - unsupportedSubpackets.add(subpacket); - break; - } - } - } - - 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); - for (SignatureSubpacket subpacket : unsupportedSubpackets) { - addSubpacket(generator, subpacket); - } - - 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 algorithms) { - return setPreferredCompressionAlgorithms(true, algorithms); - } - - @Override - public SignatureSubpacketGeneratorWrapper setPreferredCompressionAlgorithms(boolean isCritical, Set algorithms) { - int[] ids = new int[algorithms.size()]; - Iterator 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 algorithms) { - return setPreferredSymmetricKeyAlgorithms(true, algorithms); - } - - @Override - public SignatureSubpacketGeneratorWrapper setPreferredSymmetricKeyAlgorithms(boolean isCritical, Set algorithms) { - int[] ids = new int[algorithms.size()]; - Iterator 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 algorithms) { - return setPreferredHashAlgorithms(true, algorithms); - } - - @Override - public SignatureSubpacketGeneratorWrapper setPreferredHashAlgorithms(boolean isCritical, Set algorithms) { - int[] ids = new int[algorithms.size()]; - Iterator 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(isCritical, true, notationName, notationValue); - } - - @Override - public SignatureSubpacketGeneratorWrapper addNotationData(boolean isCritical, boolean isHumanReadable, @Nonnull String notationName, @Nonnull String notationValue) { - return addNotationData(new NotationData(isCritical, isHumanReadable, 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); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java new file mode 100644 index 00000000..a7a5b71d --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpackets.java @@ -0,0 +1,660 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// 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.PGPSignatureSubpacketVector; +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 SignatureSubpackets + implements BaseSignatureSubpackets, SelfSignatureSubpackets, CertificationSubpackets, RevocationSignatureSubpackets { + + private SignatureCreationTime signatureCreationTime; + private SignatureExpirationTime signatureExpirationTime; + private IssuerKeyID issuerKeyID; + private IssuerFingerprint issuerFingerprint; + private final List notationDataList = new ArrayList<>(); + private final List intendedRecipientFingerprintList = new ArrayList<>(); + private final List 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 embeddedSignatureList = new ArrayList<>(); + private SignerUserID signerUserId; + private KeyExpirationTime keyExpirationTime; + private PrimaryUserID primaryUserId; + private Revocable revocable; + private RevocationReason revocationReason; + private final List residualSubpackets = new ArrayList<>(); + + public SignatureSubpackets() { + + } + + public static SignatureSubpackets refreshHashedSubpackets(PGPPublicKey issuer, PGPSignature oldSignature) { + return createHashedSubpacketsFrom(issuer, oldSignature.getHashedSubPackets()); + } + + public static SignatureSubpackets refreshUnhashedSubpackets(PGPSignature oldSignature) { + return createSubpacketsFrom(oldSignature.getUnhashedSubPackets()); + } + + public static SignatureSubpackets createHashedSubpacketsFrom(PGPPublicKey issuer, PGPSignatureSubpacketVector base) { + SignatureSubpackets wrapper = createSubpacketsFrom(base); + wrapper.setIssuerFingerprintAndKeyId(issuer); + return wrapper; + } + + public static SignatureSubpackets createSubpacketsFrom(PGPSignatureSubpacketVector base) { + SignatureSubpackets wrapper = new SignatureSubpackets(); + SignatureSubpacketsHelper.applyFrom(base, wrapper); + return wrapper; + } + + public static SignatureSubpackets createHashedSubpackets(PGPPublicKey issuer) { + SignatureSubpackets wrapper = new SignatureSubpackets(); + wrapper.setIssuerFingerprintAndKeyId(issuer); + return wrapper; + } + + @Override + public SignatureSubpackets setIssuerFingerprintAndKeyId(PGPPublicKey key) { + setIssuerKeyId(key.getKeyID()); + setIssuerFingerprint(key); + return this; + } + + @Override + public SignatureSubpackets setIssuerKeyId(long keyId) { + return setIssuerKeyId(true, keyId); + } + + @Override + public SignatureSubpackets setIssuerKeyId(boolean isCritical, long keyId) { + return setIssuerKeyId(new IssuerKeyID(isCritical, keyId)); + } + + @Override + public SignatureSubpackets setIssuerKeyId(@Nullable IssuerKeyID issuerKeyID) { + this.issuerKeyID = issuerKeyID; + return this; + } + + public IssuerKeyID getIssuerKeyIdSubpacket() { + return issuerKeyID; + } + + @Override + public SignatureSubpackets setIssuerFingerprint(@Nonnull PGPPublicKey key) { + return setIssuerFingerprint(true, key); + } + + @Override + public SignatureSubpackets setIssuerFingerprint(boolean isCritical, @Nonnull PGPPublicKey key) { + return setIssuerFingerprint(new IssuerFingerprint(isCritical, key.getVersion(), key.getFingerprint())); + } + + @Override + public SignatureSubpackets setIssuerFingerprint(@Nullable IssuerFingerprint fingerprint) { + this.issuerFingerprint = fingerprint; + return this; + } + + public IssuerFingerprint getIssuerFingerprintSubpacket() { + return issuerFingerprint; + } + + @Override + public SignatureSubpackets setKeyFlags(KeyFlag... keyFlags) { + return setKeyFlags(true, keyFlags); + } + + @Override + public SignatureSubpackets setKeyFlags(boolean isCritical, KeyFlag... keyFlags) { + int bitmask = KeyFlag.toBitmask(keyFlags); + return setKeyFlags(new KeyFlags(isCritical, bitmask)); + } + + @Override + public SignatureSubpackets setKeyFlags(@Nullable KeyFlags keyFlags) { + this.keyFlags = keyFlags; + return this; + } + + public KeyFlags getKeyFlagsSubpacket() { + return keyFlags; + } + + @Override + public SignatureSubpackets setSignatureCreationTime(@Nonnull Date creationTime) { + return setSignatureCreationTime(true, creationTime); + } + + @Override + public SignatureSubpackets setSignatureCreationTime(boolean isCritical, @Nonnull Date creationTime) { + return setSignatureCreationTime(new SignatureCreationTime(isCritical, creationTime)); + } + + @Override + public SignatureSubpackets setSignatureCreationTime(@Nullable SignatureCreationTime signatureCreationTime) { + this.signatureCreationTime = signatureCreationTime; + return this; + } + + public SignatureCreationTime getSignatureCreationTimeSubpacket() { + return signatureCreationTime; + } + + @Override + public SignatureSubpackets setSignatureExpirationTime(@Nonnull Date creationTime, @Nonnull Date expirationTime) { + return setSignatureExpirationTime(true, creationTime, expirationTime); + } + + @Override + public SignatureSubpackets setSignatureExpirationTime(boolean isCritical, @Nonnull Date creationTime, @Nonnull Date expirationTime) { + return setSignatureExpirationTime(isCritical, (expirationTime.getTime() / 1000) - (creationTime.getTime() / 1000)); + } + + @Override + public SignatureSubpackets setSignatureExpirationTime(boolean isCritical, long seconds) { + if (seconds < 0) { + throw new IllegalArgumentException("Expiration time cannot be negative."); + } + return setSignatureExpirationTime(new SignatureExpirationTime(isCritical, seconds)); + } + + @Override + public SignatureSubpackets setSignatureExpirationTime(@Nullable SignatureExpirationTime expirationTime) { + this.signatureExpirationTime = expirationTime; + return this; + } + + public SignatureExpirationTime getSignatureExpirationTimeSubpacket() { + return signatureExpirationTime; + } + + @Override + public SignatureSubpackets setSignerUserId(@Nonnull String userId) { + return setSignerUserId(false, userId); + } + + @Override + public SignatureSubpackets setSignerUserId(boolean isCritical, @Nonnull String userId) { + return setSignerUserId(new SignerUserID(isCritical, userId)); + } + + @Override + public SignatureSubpackets setSignerUserId(@Nullable SignerUserID signerUserId) { + this.signerUserId = signerUserId; + return this; + } + + public SignerUserID getSignerUserIdSubpacket() { + return signerUserId; + } + + @Override + public SignatureSubpackets setPrimaryUserId() { + return setPrimaryUserId(true); + } + + @Override + public SignatureSubpackets setPrimaryUserId(boolean isCritical) { + return setPrimaryUserId(new PrimaryUserID(isCritical, true)); + } + + @Override + public SignatureSubpackets setPrimaryUserId(@Nullable PrimaryUserID primaryUserId) { + this.primaryUserId = primaryUserId; + return this; + } + + public PrimaryUserID getPrimaryUserIdSubpacket() { + return primaryUserId; + } + + @Override + public SignatureSubpackets setKeyExpirationTime(@Nonnull PGPPublicKey key, @Nonnull Date keyExpirationTime) { + return setKeyExpirationTime(key.getCreationTime(), keyExpirationTime); + } + + @Override + public SignatureSubpackets setKeyExpirationTime(@Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) { + return setKeyExpirationTime(true, keyCreationTime, keyExpirationTime); + } + + @Override + public SignatureSubpackets setKeyExpirationTime(boolean isCritical, @Nonnull Date keyCreationTime, @Nonnull Date keyExpirationTime) { + return setKeyExpirationTime(isCritical, (keyExpirationTime.getTime() / 1000) - (keyCreationTime.getTime() / 1000)); + } + + @Override + public SignatureSubpackets 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 SignatureSubpackets setKeyExpirationTime(@Nullable KeyExpirationTime keyExpirationTime) { + this.keyExpirationTime = keyExpirationTime; + return this; + } + + public KeyExpirationTime getKeyExpirationTimeSubpacket() { + return keyExpirationTime; + } + + @Override + public SignatureSubpackets setPreferredCompressionAlgorithms(CompressionAlgorithm... algorithms) { + return setPreferredCompressionAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms))); + } + + @Override + public SignatureSubpackets setPreferredCompressionAlgorithms(Set algorithms) { + return setPreferredCompressionAlgorithms(true, algorithms); + } + + @Override + public SignatureSubpackets setPreferredCompressionAlgorithms(boolean isCritical, Set algorithms) { + int[] ids = new int[algorithms.size()]; + Iterator 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 SignatureSubpackets 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; + } + + public PreferredAlgorithms getPreferredCompressionAlgorithmsSubpacket() { + return preferredCompressionAlgorithms; + } + + @Override + public SignatureSubpackets setPreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm... algorithms) { + return setPreferredSymmetricKeyAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms))); + } + + @Override + public SignatureSubpackets setPreferredSymmetricKeyAlgorithms(Set algorithms) { + return setPreferredSymmetricKeyAlgorithms(true, algorithms); + } + + @Override + public SignatureSubpackets setPreferredSymmetricKeyAlgorithms(boolean isCritical, Set algorithms) { + int[] ids = new int[algorithms.size()]; + Iterator 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 SignatureSubpackets 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; + } + + public PreferredAlgorithms getPreferredSymmetricKeyAlgorithmsSubpacket() { + return preferredSymmetricKeyAlgorithms; + } + + @Override + public SignatureSubpackets setPreferredHashAlgorithms(HashAlgorithm... algorithms) { + return setPreferredHashAlgorithms(new LinkedHashSet<>(Arrays.asList(algorithms))); + } + + @Override + public SignatureSubpackets setPreferredHashAlgorithms(Set algorithms) { + return setPreferredHashAlgorithms(true, algorithms); + } + + @Override + public SignatureSubpackets setPreferredHashAlgorithms(boolean isCritical, Set algorithms) { + int[] ids = new int[algorithms.size()]; + Iterator 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 SignatureSubpackets 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; + } + + public PreferredAlgorithms getPreferredHashAlgorithmsSubpacket() { + return preferredHashAlgorithms; + } + + @Override + public SignatureSubpackets addNotationData(boolean isCritical, @Nonnull String notationName, @Nonnull String notationValue) { + return addNotationData(isCritical, true, notationName, notationValue); + } + + @Override + public SignatureSubpackets addNotationData(boolean isCritical, boolean isHumanReadable, @Nonnull String notationName, @Nonnull String notationValue) { + return addNotationData(new NotationData(isCritical, isHumanReadable, notationName, notationValue)); + } + + @Override + public SignatureSubpackets addNotationData(@Nonnull NotationData notationData) { + notationDataList.add(notationData); + return this; + } + + @Override + public SignatureSubpackets clearNotationData() { + notationDataList.clear(); + return this; + } + + public List getNotationDataSubpackets() { + return new ArrayList<>(notationDataList); + } + + @Override + public SignatureSubpackets addIntendedRecipientFingerprint(@Nonnull PGPPublicKey recipient) { + return addIntendedRecipientFingerprint(false, recipient); + } + + @Override + public SignatureSubpackets addIntendedRecipientFingerprint(boolean isCritical, @Nonnull PGPPublicKey recipient) { + return addIntendedRecipientFingerprint(new IntendedRecipientFingerprint(isCritical, recipient.getVersion(), recipient.getFingerprint())); + } + + @Override + public SignatureSubpackets addIntendedRecipientFingerprint(IntendedRecipientFingerprint intendedRecipientFingerprint) { + this.intendedRecipientFingerprintList.add(intendedRecipientFingerprint); + return this; + } + + @Override + public SignatureSubpackets clearIntendedRecipientFingerprints() { + intendedRecipientFingerprintList.clear(); + return this; + } + + public List getIntendedRecipientFingerprintSubpackets() { + return new ArrayList<>(intendedRecipientFingerprintList); + } + + @Override + public SignatureSubpackets setExportable(boolean isCritical, boolean isExportable) { + return setExportable(new Exportable(isCritical, isExportable)); + } + + @Override + public SignatureSubpackets setExportable(@Nullable Exportable exportable) { + this.exportable = exportable; + return this; + } + + public Exportable getExportableSubpacket() { + return exportable; + } + + @Override + public SignatureSubpackets setRevocable(boolean isCritical, boolean isRevocable) { + return setRevocable(new Revocable(isCritical, isRevocable)); + } + + @Override + public SignatureSubpackets setRevocable(@Nullable Revocable revocable) { + this.revocable = revocable; + return this; + } + + public Revocable getRevocableSubpacket() { + return revocable; + } + + @Override + public SignatureSubpackets addRevocationKey(@Nonnull PGPPublicKey revocationKey) { + return addRevocationKey(true, revocationKey); + } + + @Override + public SignatureSubpackets addRevocationKey(boolean isCritical, @Nonnull PGPPublicKey revocationKey) { + return addRevocationKey(isCritical, false, revocationKey); + } + + @Override + public SignatureSubpackets 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 SignatureSubpackets addRevocationKey(@Nonnull RevocationKey revocationKey) { + this.revocationKeyList.add(revocationKey); + return this; + } + + @Override + public SignatureSubpackets clearRevocationKeys() { + revocationKeyList.clear(); + return this; + } + + public List getRevocationKeySubpackets() { + return new ArrayList<>(revocationKeyList); + } + + @Override + public SignatureSubpackets setRevocationReason(RevocationAttributes revocationAttributes) { + return setRevocationReason(true, revocationAttributes); + } + + @Override + public SignatureSubpackets setRevocationReason(boolean isCritical, RevocationAttributes revocationAttributes) { + return setRevocationReason(isCritical, revocationAttributes.getReason(), revocationAttributes.getDescription()); + } + + @Override + public SignatureSubpackets setRevocationReason(boolean isCritical, RevocationAttributes.Reason reason, @Nonnull String description) { + return setRevocationReason(new RevocationReason(isCritical, reason.code(), description)); + } + + @Override + public SignatureSubpackets setRevocationReason(@Nullable RevocationReason reason) { + this.revocationReason = reason; + return this; + } + + public RevocationReason getRevocationReasonSubpacket() { + return revocationReason; + } + + @Override + public SignatureSubpackets setSignatureTarget(@Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData) { + return setSignatureTarget(true, keyAlgorithm, hashAlgorithm, hashData); + } + + @Override + public SignatureSubpackets setSignatureTarget(boolean isCritical, @Nonnull PublicKeyAlgorithm keyAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, @Nonnull byte[] hashData) { + return setSignatureTarget(new SignatureTarget(isCritical, keyAlgorithm.getAlgorithmId(), hashAlgorithm.getAlgorithmId(), hashData)); + } + + @Override + public SignatureSubpackets setSignatureTarget(@Nullable SignatureTarget signatureTarget) { + this.signatureTarget = signatureTarget; + return this; + } + + public SignatureTarget getSignatureTargetSubpacket() { + return signatureTarget; + } + + @Override + public SignatureSubpackets setFeatures(Feature... features) { + return setFeatures(true, features); + } + + @Override + public SignatureSubpackets setFeatures(boolean isCritical, Feature... features) { + byte bitmask = Feature.toBitmask(features); + return setFeatures(new Features(isCritical, bitmask)); + } + + @Override + public SignatureSubpackets setFeatures(@Nullable Features features) { + this.features = features; + return this; + } + + public Features getFeaturesSubpacket() { + return features; + } + + @Override + public SignatureSubpackets setTrust(int depth, int amount) { + return setTrust(true, depth, amount); + } + + @Override + public SignatureSubpackets setTrust(boolean isCritical, int depth, int amount) { + return setTrust(new TrustSignature(isCritical, depth, amount)); + } + + @Override + public SignatureSubpackets setTrust(@Nullable TrustSignature trust) { + this.trust = trust; + return this; + } + + public TrustSignature getTrustSubpacket() { + return trust; + } + + @Override + public SignatureSubpackets addEmbeddedSignature(@Nonnull PGPSignature signature) throws IOException { + return addEmbeddedSignature(true, signature); + } + + @Override + public SignatureSubpackets 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 SignatureSubpackets addEmbeddedSignature(@Nonnull EmbeddedSignature embeddedSignature) { + this.embeddedSignatureList.add(embeddedSignature); + return this; + } + + @Override + public SignatureSubpackets clearEmbeddedSignatures() { + this.embeddedSignatureList.clear(); + return this; + } + + public List getEmbeddedSignatureSubpackets() { + return new ArrayList<>(embeddedSignatureList); + } + + public SignatureSubpackets addResidualSubpacket(SignatureSubpacket subpacket) { + this.residualSubpackets.add(subpacket); + return this; + } + + public List getResidualSubpackets() { + return new ArrayList<>(residualSubpackets); + } + +} diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java new file mode 100644 index 00000000..34b717e9 --- /dev/null +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsHelper.java @@ -0,0 +1,180 @@ +// SPDX-FileCopyrightText: 2021 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.signature.subpackets; + +import org.bouncycastle.bcpg.SignatureSubpacket; +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.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.SignatureExpirationTime; +import org.bouncycastle.bcpg.sig.SignatureTarget; +import org.bouncycastle.bcpg.sig.SignerUserID; +import org.bouncycastle.bcpg.sig.TrustSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.pgpainless.algorithm.Feature; +import org.pgpainless.algorithm.HashAlgorithm; +import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.algorithm.PublicKeyAlgorithm; +import org.pgpainless.key.util.RevocationAttributes; + +public class SignatureSubpacketsHelper { + + public static SignatureSubpackets applyFrom(PGPSignatureSubpacketVector vector, SignatureSubpackets subpackets) { + for (SignatureSubpacket subpacket : vector.toArray()) { + org.pgpainless.algorithm.SignatureSubpacket type = org.pgpainless.algorithm.SignatureSubpacket.fromCode(subpacket.getType()); + switch (type) { + case signatureCreationTime: + case issuerKeyId: + case issuerFingerprint: + // ignore, we override this anyways + break; + case signatureExpirationTime: + SignatureExpirationTime sigExpTime = (SignatureExpirationTime) subpacket; + subpackets.setSignatureExpirationTime(sigExpTime.isCritical(), sigExpTime.getTime()); + break; + case exportableCertification: + Exportable exp = (Exportable) subpacket; + subpackets.setExportable(exp.isCritical(), exp.isExportable()); + break; + case trustSignature: + TrustSignature trustSignature = (TrustSignature) subpacket; + subpackets.setTrust(trustSignature.isCritical(), trustSignature.getDepth(), trustSignature.getTrustAmount()); + break; + case revocable: + Revocable rev = (Revocable) subpacket; + subpackets.setRevocable(rev.isCritical(), rev.isRevocable()); + break; + case keyExpirationTime: + KeyExpirationTime keyExpTime = (KeyExpirationTime) subpacket; + subpackets.setKeyExpirationTime(keyExpTime.isCritical(), keyExpTime.getTime()); + break; + case preferredSymmetricAlgorithms: + subpackets.setPreferredSymmetricKeyAlgorithms((PreferredAlgorithms) subpacket); + break; + case revocationKey: + RevocationKey revocationKey = (RevocationKey) subpacket; + subpackets.addRevocationKey(revocationKey); + break; + case notationData: + NotationData notationData = (NotationData) subpacket; + subpackets.addNotationData(notationData.isCritical(), notationData.getNotationName(), notationData.getNotationValue()); + break; + case preferredHashAlgorithms: + subpackets.setPreferredHashAlgorithms((PreferredAlgorithms) subpacket); + break; + case preferredCompressionAlgorithms: + subpackets.setPreferredCompressionAlgorithms((PreferredAlgorithms) subpacket); + break; + case primaryUserId: + PrimaryUserID primaryUserID = (PrimaryUserID) subpacket; + subpackets.setPrimaryUserId(primaryUserID); + break; + case keyFlags: + KeyFlags flags = (KeyFlags) subpacket; + subpackets.setKeyFlags(flags.isCritical(), KeyFlag.fromBitmask(flags.getFlags()).toArray(new KeyFlag[0])); + break; + case signerUserId: + SignerUserID signerUserID = (SignerUserID) subpacket; + subpackets.setSignerUserId(signerUserID.isCritical(), signerUserID.getID()); + break; + case revocationReason: + RevocationReason reason = (RevocationReason) subpacket; + subpackets.setRevocationReason(reason.isCritical(), + RevocationAttributes.Reason.fromCode(reason.getRevocationReason()), + reason.getRevocationDescription()); + break; + case features: + Features f = (Features) subpacket; + subpackets.setFeatures(f.isCritical(), Feature.fromBitmask(f.getData()[0]).toArray(new Feature[0])); + break; + case signatureTarget: + SignatureTarget target = (SignatureTarget) subpacket; + subpackets.setSignatureTarget(target.isCritical(), + PublicKeyAlgorithm.fromId(target.getPublicKeyAlgorithm()), + HashAlgorithm.fromId(target.getHashAlgorithm()), + target.getHashData()); + break; + case embeddedSignature: + EmbeddedSignature embeddedSignature = (EmbeddedSignature) subpacket; + subpackets.addEmbeddedSignature(embeddedSignature); + break; + case intendedRecipientFingerprint: + IntendedRecipientFingerprint intendedRecipientFingerprint = (IntendedRecipientFingerprint) subpacket; + subpackets.addIntendedRecipientFingerprint(intendedRecipientFingerprint); + break; + + case regularExpression: + case keyServerPreferences: + case preferredKeyServers: + case policyUrl: + case placeholder: + case preferredAEADAlgorithms: + case attestedCertification: + subpackets.addResidualSubpacket(subpacket); + break; + } + } + return subpackets; + } + + public static PGPSignatureSubpacketGenerator applyTo(SignatureSubpackets subpackets, PGPSignatureSubpacketGenerator generator) { + addSubpacket(generator, subpackets.getIssuerKeyIdSubpacket()); + addSubpacket(generator, subpackets.getIssuerFingerprintSubpacket()); + addSubpacket(generator, subpackets.getSignatureCreationTimeSubpacket()); + addSubpacket(generator, subpackets.getSignatureExpirationTimeSubpacket()); + addSubpacket(generator, subpackets.getExportableSubpacket()); + for (NotationData notationData : subpackets.getNotationDataSubpackets()) { + addSubpacket(generator, notationData); + } + for (IntendedRecipientFingerprint intendedRecipientFingerprint : subpackets.getIntendedRecipientFingerprintSubpackets()) { + addSubpacket(generator, intendedRecipientFingerprint); + } + for (RevocationKey revocationKey : subpackets.getRevocationKeySubpackets()) { + addSubpacket(generator, revocationKey); + } + addSubpacket(generator, subpackets.getSignatureTargetSubpacket()); + addSubpacket(generator, subpackets.getFeaturesSubpacket()); + addSubpacket(generator, subpackets.getKeyFlagsSubpacket()); + addSubpacket(generator, subpackets.getTrustSubpacket()); + addSubpacket(generator, subpackets.getPreferredCompressionAlgorithmsSubpacket()); + addSubpacket(generator, subpackets.getPreferredSymmetricKeyAlgorithmsSubpacket()); + addSubpacket(generator, subpackets.getPreferredHashAlgorithmsSubpacket()); + for (EmbeddedSignature embeddedSignature : subpackets.getEmbeddedSignatureSubpackets()) { + addSubpacket(generator, embeddedSignature); + } + addSubpacket(generator, subpackets.getSignerUserIdSubpacket()); + addSubpacket(generator, subpackets.getKeyExpirationTimeSubpacket()); + addSubpacket(generator, subpackets.getPrimaryUserIdSubpacket()); + addSubpacket(generator, subpackets.getRevocableSubpacket()); + addSubpacket(generator, subpackets.getRevocationReasonSubpacket()); + for (SignatureSubpacket subpacket : subpackets.getResidualSubpackets()) { + addSubpacket(generator, subpacket); + } + + return generator; + } + + private static void addSubpacket(PGPSignatureSubpacketGenerator generator, SignatureSubpacket subpacket) { + if (subpacket != null) { + generator.addCustomSubpacket(subpacket); + } + } + + public static PGPSignatureSubpacketVector toVector(SignatureSubpackets subpackets) { + PGPSignatureSubpacketGenerator generator = new PGPSignatureSubpacketGenerator(); + applyTo(subpackets, generator); + return generator.generate(); + } +} diff --git a/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java b/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketsTest.java similarity index 86% rename from pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java rename to pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketsTest.java index a07f792e..988bc776 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketsTest.java @@ -57,12 +57,12 @@ import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.util.DateUtil; import org.pgpainless.util.Passphrase; -public class SignatureSubpacketGeneratorWrapperTest { +public class SignatureSubpacketsTest { private static PGPPublicKeyRing keys; private static PGPPublicKey key; - private SignatureSubpacketGeneratorWrapper wrapper; + private SignatureSubpackets wrapper; @BeforeAll public static void setup() throws IOException { @@ -72,27 +72,24 @@ public class SignatureSubpacketGeneratorWrapperTest { @BeforeEach public void createWrapper() { - wrapper = SignatureSubpacketGeneratorWrapper.createHashedSubpackets(key); + wrapper = SignatureSubpackets.createHashedSubpackets(key); } @Test public void initialStateTest() { - Date now = new Date(); - wrapper = SignatureSubpacketGeneratorWrapper.createHashedSubpackets(); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); - - assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 1000); + wrapper = new SignatureSubpackets(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); + assertNull(vector.getSignatureCreationTime()); } @Test public void initialStateFromKeyTest() throws PGPException { - Date now = new Date(); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(key.getKeyID(), vector.getIssuerKeyID()); assertEquals(key.getVersion(), vector.getIssuerFingerprint().getKeyVersion()); assertArrayEquals(key.getFingerprint(), vector.getIssuerFingerprint().getFingerprint()); - assertEquals(now.getTime(), vector.getSignatureCreationTime().getTime(), 2000); + assertNull(vector.getSignatureCreationTime()); assertEquals(0, vector.getKeyFlags()); assertEquals(0, vector.getSignatureExpirationTime()); @@ -116,7 +113,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testNullKeyId() { wrapper.setIssuerKeyId(null); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getIssuerKeyID()); } @@ -125,7 +122,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testNullFingerprint() { wrapper.setIssuerFingerprint((IssuerFingerprint) null); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertNull(vector.getIssuerFingerprint()); } @@ -134,7 +131,7 @@ public class SignatureSubpacketGeneratorWrapperTest { public void testAddNotationData() { wrapper.addNotationData(true, "critical@notation.data", "isCritical"); wrapper.addNotationData(false, "noncrit@notation.data", "notCritical"); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); NotationData[] notationData = vector.getNotationDataOccurrences(); assertEquals(2, notationData.length); @@ -151,7 +148,7 @@ public class SignatureSubpacketGeneratorWrapperTest { assertEquals("notCritical", second.getNotationValue()); wrapper.clearNotationData(); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getNotationDataOccurrences().length); } @@ -159,14 +156,14 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testIntendedRecipientFingerprints() { wrapper.addIntendedRecipientFingerprint(key); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); 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(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getSubpackets(SignatureSubpacketTags.INTENDED_RECIPIENT_FINGERPRINT).length); } @@ -178,7 +175,7 @@ public class SignatureSubpacketGeneratorWrapperTest { assertTrue(keyIterator.hasNext()); PGPPublicKey second = keyIterator.next(); wrapper.addRevocationKey(false, true, second); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); SignatureSubpacket[] revKeys = vector.getSubpackets(SignatureSubpacketTags.REVOCATION_KEY); assertEquals(2, revKeys.length); @@ -196,14 +193,14 @@ public class SignatureSubpacketGeneratorWrapperTest { assertEquals((byte) (0x80 | 0x40), r2.getSignatureClass()); wrapper.clearRevocationKeys(); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); 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(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(KeyFlag.toBitmask(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER), vector.getKeyFlags()); assertTrue(vector.getSubpacket(SignatureSubpacketTags.KEY_FLAGS).isCritical()); @@ -215,7 +212,7 @@ public class SignatureSubpacketGeneratorWrapperTest { long secondsInAWeek = 60 * 60 * 24 * 7; Date inAWeek = new Date(now.getTime() + 1000 * secondsInAWeek); wrapper.setSignatureExpirationTime(now, inAWeek); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(secondsInAWeek, vector.getSignatureExpirationTime()); } @@ -232,17 +229,19 @@ public class SignatureSubpacketGeneratorWrapperTest { public void testSignerUserId() { String userId = "Alice "; wrapper.setSignerUserId(userId); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(userId, vector.getSignerUserID()); } @Test public void testSetPrimaryUserId() { - assertFalse(wrapper.getGenerator().generate().isPrimaryUserID()); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); + assertFalse(vector.isPrimaryUserID()); wrapper.setPrimaryUserId(); - assertTrue(wrapper.getGenerator().generate().isPrimaryUserID()); + vector = SignatureSubpacketsHelper.toVector(wrapper); + assertTrue(vector.isPrimaryUserID()); } @Test @@ -250,7 +249,7 @@ public class SignatureSubpacketGeneratorWrapperTest { Date now = new Date(); long secondsSinceKeyCreation = (now.getTime() - key.getCreationTime().getTime()) / 1000; wrapper.setKeyExpirationTime(key, now); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(secondsSinceKeyCreation, vector.getKeyExpirationTime()); } @@ -264,7 +263,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetPreferredCompressionAlgorithms() { wrapper.setPreferredCompressionAlgorithms(CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZIP, CompressionAlgorithm.BZIP2); // duplicates get removed - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); int[] ids = vector.getPreferredCompressionAlgorithms(); assertEquals(2, ids.length); @@ -272,11 +271,11 @@ public class SignatureSubpacketGeneratorWrapperTest { assertEquals(CompressionAlgorithm.ZIP.getAlgorithmId(), ids[1]); wrapper.setPreferredCompressionAlgorithms(); // empty - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getPreferredCompressionAlgorithms().length); wrapper.setPreferredCompressionAlgorithms((PreferredAlgorithms) null); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertNull(vector.getPreferredCompressionAlgorithms()); assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredCompressionAlgorithms( @@ -286,7 +285,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetPreferredSymmetricKeyAlgorithms() { wrapper.setPreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128, SymmetricKeyAlgorithm.AES_128); // duplicates get removed - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); int[] ids = vector.getPreferredSymmetricAlgorithms(); assertEquals(2, ids.length); @@ -294,11 +293,11 @@ public class SignatureSubpacketGeneratorWrapperTest { assertEquals(SymmetricKeyAlgorithm.AES_128.getAlgorithmId(), ids[1]); wrapper.setPreferredSymmetricKeyAlgorithms(); // empty - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getPreferredSymmetricAlgorithms().length); wrapper.setPreferredSymmetricKeyAlgorithms((PreferredAlgorithms) null); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertNull(vector.getPreferredCompressionAlgorithms()); assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredSymmetricKeyAlgorithms( @@ -308,7 +307,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetPreferredHashAlgorithms() { wrapper.setPreferredHashAlgorithms(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA512); // duplicates get removed - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); int[] ids = vector.getPreferredHashAlgorithms(); assertEquals(2, ids.length); @@ -316,11 +315,11 @@ public class SignatureSubpacketGeneratorWrapperTest { assertEquals(HashAlgorithm.SHA384.getAlgorithmId(), ids[1]); wrapper.setPreferredHashAlgorithms(); // empty - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getPreferredHashAlgorithms().length); wrapper.setPreferredHashAlgorithms((PreferredAlgorithms) null); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertNull(vector.getPreferredHashAlgorithms()); assertThrows(IllegalArgumentException.class, () -> wrapper.setPreferredHashAlgorithms( @@ -330,14 +329,14 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetExportable() { wrapper.setExportable(true, false); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); Exportable exportable = (Exportable) vector.getSubpacket(SignatureSubpacketTags.EXPORTABLE); assertTrue(exportable.isCritical()); assertFalse(exportable.isExportable()); wrapper.setExportable(false, true); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); exportable = (Exportable) vector.getSubpacket(SignatureSubpacketTags.EXPORTABLE); assertFalse(exportable.isCritical()); @@ -347,14 +346,14 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetRevocable() { wrapper.setRevocable(true, true); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); Revocable revocable = (Revocable) vector.getSubpacket(SignatureSubpacketTags.REVOCABLE); assertTrue(revocable.isCritical()); assertTrue(revocable.isRevocable()); wrapper.setRevocable(false, false); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); revocable = (Revocable) vector.getSubpacket(SignatureSubpacketTags.REVOCABLE); assertFalse(revocable.isCritical()); @@ -365,7 +364,7 @@ public class SignatureSubpacketGeneratorWrapperTest { public void testSetRevocationReason() { wrapper.setRevocationReason(RevocationAttributes.createKeyRevocation() .withReason(RevocationAttributes.Reason.KEY_RETIRED).withDescription("The key is too weak.")); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(1, vector.getSubpackets(SignatureSubpacketTags.REVOCATION_REASON).length); RevocationReason reason = (RevocationReason) vector.getSubpacket(SignatureSubpacketTags.REVOCATION_REASON); @@ -378,7 +377,7 @@ public class SignatureSubpacketGeneratorWrapperTest { byte[] hash = new byte[20]; new Random().nextBytes(hash); wrapper.setSignatureTarget(PublicKeyAlgorithm.fromId(key.getAlgorithm()), HashAlgorithm.SHA512, hash); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); SignatureTarget target = vector.getSignatureTarget(); assertNotNull(target); @@ -390,7 +389,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetFeatures() { wrapper.setFeatures(Feature.MODIFICATION_DETECTION, Feature.AEAD_ENCRYPTED_DATA); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); Features features = vector.getFeatures(); assertTrue(features.supportsModificationDetection()); @@ -401,7 +400,7 @@ public class SignatureSubpacketGeneratorWrapperTest { @Test public void testSetTrust() { wrapper.setTrust(10, 5); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); TrustSignature trustSignature = (TrustSignature) vector.getSubpacket(SignatureSubpacketTags.TRUST_SIG); assertNotNull(trustSignature); @@ -427,18 +426,18 @@ public class SignatureSubpacketGeneratorWrapperTest { wrapper.addEmbeddedSignature(sig1); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(1, vector.getEmbeddedSignatures().size()); assertArrayEquals(sig1.getSignature(), vector.getEmbeddedSignatures().get(0).getSignature()); wrapper.addEmbeddedSignature(sig2); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(2, vector.getEmbeddedSignatures().size()); assertArrayEquals(sig2.getSignature(), vector.getEmbeddedSignatures().get(1).getSignature()); wrapper.clearEmbeddedSignatures(); - vector = wrapper.getGenerator().generate(); + vector = SignatureSubpacketsHelper.toVector(wrapper); assertEquals(0, vector.getEmbeddedSignatures().size()); } @@ -486,8 +485,8 @@ public class SignatureSubpacketGeneratorWrapperTest { subpackets.addCustomSubpacket(aead); - SignatureSubpacketGeneratorWrapper wrapper = SignatureSubpacketGeneratorWrapper.createSubpacketsFrom(subpackets.generate()); - PGPSignatureSubpacketVector vector = wrapper.getGenerator().generate(); + SignatureSubpackets wrapper = SignatureSubpackets.createSubpacketsFrom(subpackets.generate()); + PGPSignatureSubpacketVector vector = SignatureSubpacketsHelper.toVector(wrapper); // Verify these are not extracted assertEquals(0, vector.getIssuerKeyID());