From 04ada881884d21bd69f763bc543fdefe397583af Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 8 Nov 2021 21:25:02 +0100 Subject: [PATCH] Fix errors --- .../org/pgpainless/algorithm/KeyFlag.java | 9 ++ .../key/generation/KeyRingBuilder.java | 14 ++-- .../pgpainless/key/generation/KeySpec.java | 22 +++-- .../key/generation/KeySpecBuilder.java | 27 +----- .../secretkeyring/SecretKeyRingEditor.java | 83 +++++++++++++++++++ .../SecretKeyRingEditorInterface.java | 20 +++++ .../org/pgpainless/key/util/KeyRingUtils.java | 27 ++++++ .../SignatureSubpacketGeneratorWrapper.java | 1 - .../subpackets/SignatureSubpacketsUtil.java | 56 +++++++++++++ .../org/pgpainless/util/CollectionUtils.java | 9 ++ .../org/pgpainless/example/GenerateKeys.java | 3 +- ...ignatureSubpacketGeneratorWrapperTest.java | 4 +- 12 files changed, 232 insertions(+), 43 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java index 69843a93..92205fd9 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java @@ -109,4 +109,13 @@ public enum KeyFlag { public static boolean hasKeyFlag(int mask, KeyFlag flag) { return (mask & flag.getFlag()) == flag.getFlag(); } + + public static boolean containsAny(int mask, KeyFlag... flags) { + for (KeyFlag flag : flags) { + if (hasKeyFlag(mask, flag)) { + return true; + } + } + return false; + } } 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 762757e0..85b95b92 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 @@ -44,6 +44,7 @@ import org.pgpainless.key.generation.type.KeyType; 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.util.Passphrase; public class KeyRingBuilder implements KeyRingBuilderInterface { @@ -110,7 +111,9 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { } private boolean hasCertifyOthersFlag(KeySpec keySpec) { - return SignatureSubpacketGeneratorUtil.hasKeyFlag(KeyFlag.CERTIFY_OTHER, keySpec.getSubpacketGenerator()); + return SignatureSubpacketGeneratorUtil.hasKeyFlag(KeyFlag.CERTIFY_OTHER, + keySpec.getSubpacketGenerator() == null ? null : + keySpec.getSubpacketGenerator().getGenerator()); } private boolean keyIsCertificationCapable(KeySpec keySpec) { @@ -135,13 +138,12 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { PGPKeyPair certKey = generateKeyPair(primaryKeySpec); PGPContentSignerBuilder signer = buildContentSigner(certKey); signatureGenerator = new PGPSignatureGenerator(signer); - PGPSignatureSubpacketGenerator hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); - hashedSubPacketGenerator.setPrimaryUserID(false, true); + SignatureSubpacketGeneratorWrapper hashedSubPacketGenerator = primaryKeySpec.getSubpacketGenerator(); + hashedSubPacketGenerator.setPrimaryUserId(); if (expirationDate != null) { - SignatureSubpacketGeneratorUtil.setKeyExpirationDateInSubpacketGenerator( - expirationDate, new Date(), hashedSubPacketGenerator); + hashedSubPacketGenerator.setKeyExpirationTime(certKey.getPublicKey(), expirationDate); } - PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.generate(); + PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.getGenerator().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 364384ae..bff89af4 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 @@ -5,21 +5,30 @@ package org.pgpainless.key.generation; import javax.annotation.Nonnull; -import javax.annotation.Nullable; 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; public class KeySpec { private final KeyType keyType; - private final PGPSignatureSubpacketGenerator subpacketGenerator; + private final SignatureSubpacketGeneratorWrapper subpacketGenerator; private final boolean inheritedSubPackets; KeySpec(@Nonnull KeyType type, - @Nullable PGPSignatureSubpacketGenerator subpacketGenerator, + @Nonnull PGPSignatureSubpacketGenerator subpacketGenerator, + boolean inheritedSubPackets) { + this( + type, + SignatureSubpacketGeneratorWrapper.createSubpacketsFrom(subpacketGenerator.generate()), + inheritedSubPackets); + } + + KeySpec(@Nonnull KeyType type, + @Nonnull SignatureSubpacketGeneratorWrapper subpacketGenerator, boolean inheritedSubPackets) { this.keyType = type; this.subpacketGenerator = subpacketGenerator; @@ -31,12 +40,13 @@ public class KeySpec { return keyType; } - @Nullable + @Nonnull public PGPSignatureSubpacketVector getSubpackets() { - return subpacketGenerator != null ? subpacketGenerator.generate() : null; + return subpacketGenerator.getGenerator().generate(); } - PGPSignatureSubpacketGenerator getSubpacketGenerator() { + @Nonnull + SignatureSubpacketGeneratorWrapper getSubpacketGenerator() { return subpacketGenerator; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java index 80756b74..3a99bb94 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java @@ -19,6 +19,7 @@ import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.key.generation.type.KeyType; +import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.util.CollectionUtils; public class KeySpecBuilder implements KeySpecBuilderInterface { @@ -39,7 +40,7 @@ public class KeySpecBuilder implements KeySpecBuilderInterface { throw new IllegalArgumentException("List of additional flags MUST NOT be null."); } flags = CollectionUtils.concat(flag, flags); - assureKeyCanCarryFlags(type, flags); + SignatureSubpacketsUtil.assureKeyCanCarryFlags(type, flags); this.type = type; this.keyFlags = flags; } @@ -100,28 +101,4 @@ public class KeySpecBuilder implements KeySpecBuilderInterface { } return ids; } - - private static void assureKeyCanCarryFlags(KeyType type, KeyFlag... flags) { - final int mask = KeyFlag.toBitmask(flags); - - if (!type.canCertify() && KeyFlag.hasKeyFlag(mask, KeyFlag.CERTIFY_OTHER)) { - throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag CERTIFY_OTHER."); - } - - if (!type.canSign() && KeyFlag.hasKeyFlag(mask, KeyFlag.SIGN_DATA)) { - throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag SIGN_DATA."); - } - - if (!type.canEncryptCommunication() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_COMMS)) { - throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_COMMS."); - } - - if (!type.canEncryptStorage() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_STORAGE)) { - throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_STORAGE."); - } - - if (!type.canAuthenticate() && KeyFlag.hasKeyFlag(mask, KeyFlag.AUTHENTICATION)) { - throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag AUTHENTIACTION."); - } - } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index 06718a6a..299721f7 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -4,6 +4,9 @@ package org.pgpainless.key.modification.secretkeyring; +import static org.pgpainless.util.CollectionUtils.concat; + +import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -35,6 +38,8 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; 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; @@ -52,9 +57,13 @@ import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvi import org.pgpainless.key.util.KeyRingUtils; import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.signature.SignatureUtils; +import org.pgpainless.signature.builder.PrimaryKeyBindingSignatureBuilder; import org.pgpainless.signature.builder.SelfSignatureBuilder; +import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; +import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; +import org.pgpainless.util.CollectionUtils; import org.pgpainless.util.Passphrase; public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @@ -134,6 +143,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { } @Override + @Deprecated public SecretKeyRingEditorInterface addSubKey(PGPSecretKey secretSubKey, PGPSignatureSubpacketVector hashedSubpackets, PGPSignatureSubpacketVector unhashedSubpackets, @@ -163,6 +173,79 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { return this; } + @Override + public SecretKeyRingEditorInterface addSubKey(PGPSecretKey subkey, + @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, + @Nullable SelfSignatureSubpackets.Callback backSignatureCallback, + SecretKeyRingProtector subkeyProtector, + SecretKeyRingProtector primaryKeyProtector, + KeyFlag keyFlag, + KeyFlag... additionalKeyFlags) throws PGPException, IOException { + KeyFlag[] flags = concat(keyFlag, additionalKeyFlags); + SignatureSubpacketsUtil.assureKeyCanCarryFlags(PublicKeyAlgorithm.fromId(subkey.getPublicKey().getAlgorithm())); + + boolean isSigningKey = CollectionUtils.contains(flags, KeyFlag.SIGN_DATA) || + CollectionUtils.contains(flags, KeyFlag.CERTIFY_OTHER); + if (!isSigningKey) { + return addSubKey(subkey.getPublicKey(), + bindingSignatureCallback, + primaryKeyProtector, + keyFlag, + additionalKeyFlags); + } + + PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); + SubkeyBindingSignatureBuilder bindingSigBuilder = new SubkeyBindingSignatureBuilder(primaryKey, primaryKeyProtector); + bindingSigBuilder.applyCallback(bindingSignatureCallback); + bindingSigBuilder.getHashedSubpackets().setKeyFlags(flags); + + PrimaryKeyBindingSignatureBuilder backSigBuilder = new PrimaryKeyBindingSignatureBuilder(subkey, subkeyProtector); + backSigBuilder.applyCallback(backSignatureCallback); + PGPSignature backSig = backSigBuilder.build(primaryKey.getPublicKey()); + + bindingSigBuilder.getHashedSubpackets().addEmbeddedSignature(backSig); + PGPSignature bindingSig = bindingSigBuilder.build(subkey.getPublicKey()); + subkey = KeyRingUtils.secretKeyPlusSignature(subkey, bindingSig); + secretKeyRing = KeyRingUtils.secretKeysPlusSecretKey(secretKeyRing, subkey); + + return this; + } + + @Override + public SecretKeyRingEditorInterface addSubKey(PGPPublicKey subkey, + SelfSignatureSubpackets.Callback bindingSignatureCallback, + SecretKeyRingProtector primaryKeyProtector, + KeyFlag keyFlag, + KeyFlag... additionalKeyFlags) throws PGPException { + KeyFlag[] flags = concat(keyFlag, additionalKeyFlags); + boolean isSigningKey = CollectionUtils.contains(flags, KeyFlag.SIGN_DATA) || + CollectionUtils.contains(flags, KeyFlag.CERTIFY_OTHER); + if (isSigningKey) { + throw new IllegalArgumentException("Cannot bind a signing capable subkey without access to the secret subkey.\n" + + "Please use addSubKey(PGPSecretKey secretSubKey, [...]) instead."); + } + + PGPSignature bindingSignature = createSubkeyBindingSignature(subkey, bindingSignatureCallback, primaryKeyProtector, flags); + subkey = PGPPublicKey.addCertification(subkey, bindingSignature); + + secretKeyRing = KeyRingUtils.secretKeysPlusPublicKey(secretKeyRing, subkey); + + return this; + } + + private PGPSignature createSubkeyBindingSignature(PGPPublicKey subkey, + SelfSignatureSubpackets.Callback bindingSignatureCallback, + SecretKeyRingProtector primaryKeyProtector, + KeyFlag... keyFlags) throws PGPException { + PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); + SubkeyBindingSignatureBuilder builder = new SubkeyBindingSignatureBuilder(primaryKey, primaryKeyProtector); + builder.applyCallback(bindingSignatureCallback); + builder.getHashedSubpackets().setKeyFlags(keyFlags); + + PGPSignature signature = builder.build(subkey); + return signature; + } + private PGPSecretKey generateSubKey(@Nonnull KeySpec keySpec, @Nonnull Passphrase subKeyPassphrase) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java index b45f7523..a1699eaa 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java @@ -4,6 +4,7 @@ package org.pgpainless.key.modification.secretkeyring; +import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.util.Date; @@ -11,16 +12,19 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.generation.KeySpec; import org.pgpainless.key.protection.KeyRingProtectionSettings; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.UserId; +import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.util.Passphrase; public interface SecretKeyRingEditorInterface { @@ -59,11 +63,27 @@ public interface SecretKeyRingEditorInterface { SecretKeyRingProtector secretKeyRingProtector) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException; + @Deprecated SecretKeyRingEditorInterface addSubKey(PGPSecretKey subKey, PGPSignatureSubpacketVector hashedSubpackets, PGPSignatureSubpacketVector unhashedSubpackets, SecretKeyRingProtector subKeyProtector, SecretKeyRingProtector keyRingProtector) throws PGPException; + + SecretKeyRingEditorInterface addSubKey(PGPSecretKey subkey, + @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, + @Nullable SelfSignatureSubpackets.Callback backSignatureCallback, + SecretKeyRingProtector subkeyProtector, + SecretKeyRingProtector primaryKeyProtector, + KeyFlag keyFlag, + KeyFlag... additionalKeyFlags) throws PGPException, IOException; + + SecretKeyRingEditorInterface addSubKey(PGPPublicKey subkey, + SelfSignatureSubpackets.Callback bindingSignatureCallback, + SecretKeyRingProtector primaryKeyProtector, + KeyFlag keyFlag, + KeyFlag... additionalKeyFlags) throws PGPException; + /** * Revoke the key ring. * The revocation will be a hard revocation, rendering the whole key invalid for any past or future signatures. diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/util/KeyRingUtils.java b/pgpainless-core/src/main/java/org/pgpainless/key/util/KeyRingUtils.java index 5ae789d4..99c4c894 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/util/KeyRingUtils.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/util/KeyRingUtils.java @@ -21,8 +21,10 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; +import org.bouncycastle.openpgp.PGPSignature; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnlockSecretKey; +import org.pgpainless.util.CollectionUtils; public final class KeyRingUtils { @@ -200,4 +202,29 @@ public final class KeyRingUtils { publicKeys = PGPPublicKeyRing.insertPublicKey(publicKeys, publicKey); return publicKeys; } + + public static PGPSecretKeyRing secretKeysPlusPublicKey(PGPSecretKeyRing secretKeys, PGPPublicKey subkey) { + PGPPublicKeyRing publicKeys = publicKeyRingFrom(secretKeys); + PGPPublicKeyRing newPublicKeys = publicKeysPlusPublicKey(publicKeys, subkey); + PGPSecretKeyRing newSecretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, newPublicKeys); + return newSecretKeys; + } + + public static PGPPublicKeyRing publicKeysPlusPublicKey(PGPPublicKeyRing publicKeys, PGPPublicKey subkey) { + List publicKeyList = CollectionUtils.iteratorToList(publicKeys.getPublicKeys()); + publicKeyList.add(subkey); + PGPPublicKeyRing newPublicKeys = new PGPPublicKeyRing(publicKeyList); + return newPublicKeys; + } + + public static PGPSecretKeyRing secretKeysPlusSecretKey(PGPSecretKeyRing secretKeys, PGPSecretKey subkey) { + return PGPSecretKeyRing.insertSecretKey(secretKeys, subkey); + } + + public static PGPSecretKey secretKeyPlusSignature(PGPSecretKey secretKey, PGPSignature signature) { + PGPPublicKey publicKey = secretKey.getPublicKey(); + publicKey = PGPPublicKey.addCertification(publicKey, signature); + PGPSecretKey newSecretKey = PGPSecretKey.replacePublicKey(secretKey, publicKey); + return newSecretKey; + } } 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 index e2e9c584..c4016709 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapper.java @@ -95,7 +95,6 @@ public class SignatureSubpacketGeneratorWrapper public static SignatureSubpacketGeneratorWrapper createSubpacketsFrom(PGPSignatureSubpacketVector base) { SignatureSubpacketGeneratorWrapper wrapper = new SignatureSubpacketGeneratorWrapper(); wrapper.extractSubpacketsFromVector(base); - wrapper.setSignatureCreationTime(new Date()); return wrapper; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java index 4792a362..751c9f73 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/subpackets/SignatureSubpacketsUtil.java @@ -41,10 +41,12 @@ 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.SignatureSubpacket; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint; +import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.signature.SignatureUtils; /** @@ -560,4 +562,58 @@ public final class SignatureSubpacketsUtil { } return (P) allPackets[allPackets.length - 1]; // return last } + + /** + * Make sure that the given key type can carry the given key flags. + * + * @param type key type + * @param flags key flags + */ + public static void assureKeyCanCarryFlags(KeyType type, KeyFlag... flags) { + final int mask = KeyFlag.toBitmask(flags); + + if (!type.canCertify() && KeyFlag.hasKeyFlag(mask, KeyFlag.CERTIFY_OTHER)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag CERTIFY_OTHER."); + } + + if (!type.canSign() && KeyFlag.hasKeyFlag(mask, KeyFlag.SIGN_DATA)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag SIGN_DATA."); + } + + if (!type.canEncryptCommunication() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_COMMS)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_COMMS."); + } + + if (!type.canEncryptStorage() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_STORAGE)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag ENCRYPT_STORAGE."); + } + + if (!type.canAuthenticate() && KeyFlag.hasKeyFlag(mask, KeyFlag.AUTHENTICATION)) { + throw new IllegalArgumentException("KeyType " + type.getName() + " cannot carry key flag AUTHENTIACTION."); + } + } + + public static void assureKeyCanCarryFlags(PublicKeyAlgorithm algorithm, KeyFlag... flags) { + final int mask = KeyFlag.toBitmask(flags); + + if (!algorithm.isSigningCapable() && KeyFlag.hasKeyFlag(mask, KeyFlag.CERTIFY_OTHER)) { + throw new IllegalArgumentException("Algorithm " + algorithm + " cannot be used with key flag CERTIFY_OTHER."); + } + + if (!algorithm.isSigningCapable() && KeyFlag.hasKeyFlag(mask, KeyFlag.SIGN_DATA)) { + throw new IllegalArgumentException("Algorithm " + algorithm + " cannot be used with key flag SIGN_DATA."); + } + + if (!algorithm.isEncryptionCapable() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_COMMS)) { + throw new IllegalArgumentException("Algorithm " + algorithm + " cannot be used with key flag ENCRYPT_COMMS."); + } + + if (!algorithm.isEncryptionCapable() && KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_STORAGE)) { + throw new IllegalArgumentException("Algorithm " + algorithm + " cannot be used with key flag ENCRYPT_STORAGE."); + } + + if (!algorithm.isSigningCapable() && KeyFlag.hasKeyFlag(mask, KeyFlag.AUTHENTICATION)) { + throw new IllegalArgumentException("Algorithm " + algorithm + " cannot be used with key flag AUTHENTIACTION."); + } + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/CollectionUtils.java b/pgpainless-core/src/main/java/org/pgpainless/util/CollectionUtils.java index dcae3240..91b48ba2 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/util/CollectionUtils.java +++ b/pgpainless-core/src/main/java/org/pgpainless/util/CollectionUtils.java @@ -30,4 +30,13 @@ public final class CollectionUtils { System.arraycopy(ts, 0, concat, 1, ts.length); return concat; } + + public static boolean contains(T[] ts, T t) { + for (T i : ts) { + if (i.equals(t)) { + return true; + } + } + return false; + } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java index 6dcd6812..4046ede6 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java @@ -97,7 +97,7 @@ public class GenerateKeys { * @throws NoSuchAlgorithmException */ @Test - public void generateSimpleRSAKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + public void generateSimpleRSAKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { // Define a primary user-id String userId = "mpage@pgpainless.org"; // Set a password to protect the secret key @@ -106,7 +106,6 @@ public class GenerateKeys { PGPSecretKeyRing secretKey = PGPainless.generateKeyRing() .simpleRsaKeyRing(userId, RsaLength._4096, password); - KeyRingInfo keyInfo = new KeyRingInfo(secretKey); assertEquals(1, keyInfo.getSecretKeys().size()); assertEquals(userId, keyInfo.getPrimaryUserId()); diff --git a/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java b/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java index e2498e19..a07f792e 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/signature/subpackets/SignatureSubpacketGeneratorWrapperTest.java @@ -39,7 +39,6 @@ import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.junit.JUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -493,8 +492,7 @@ public class SignatureSubpacketGeneratorWrapperTest { // Verify these are not extracted assertEquals(0, vector.getIssuerKeyID()); assertNull(vector.getIssuerFingerprint()); - // BC overrides the date with current time - JUtils.assertDateNotEquals(sigCreationDate, vector.getSignatureCreationTime()); + assertNull(vector.getSignatureCreationTime()); // Verify these are extracted assertEquals(256000, vector.getSignatureExpirationTime());