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 b45baeb3..3e1cadca 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 @@ -39,11 +39,13 @@ import org.bouncycastle.openpgp.operator.PGPDigestCalculator; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.KeyFlag; +import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.protection.UnlockSecretKey; +import org.pgpainless.policy.Policy; import org.pgpainless.provider.ProviderFactory; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SignatureSubpackets; @@ -62,6 +64,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { @Override public KeyRingBuilder setPrimaryKey(@Nonnull KeySpec keySpec) { + verifyKeySpecCompliesToPolicy(keySpec, PGPainless.getPolicy()); verifyMasterKeyCanCertify(keySpec); this.primaryKeySpec = keySpec; return this; @@ -69,6 +72,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { @Override public KeyRingBuilder addSubkey(@Nonnull KeySpec keySpec) { + verifyKeySpecCompliesToPolicy(keySpec, PGPainless.getPolicy()); this.subkeySpecs.add(keySpec); return this; } @@ -107,6 +111,16 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { return this; } + private void verifyKeySpecCompliesToPolicy(KeySpec keySpec, Policy policy) { + PublicKeyAlgorithm publicKeyAlgorithm = keySpec.getKeyType().getAlgorithm(); + int bitStrength = keySpec.getKeyType().getBitStrength(); + + if (!policy.getPublicKeyAlgorithmPolicy().isAcceptable(publicKeyAlgorithm, bitStrength)) { + throw new IllegalArgumentException("Public key algorithm policy violation: " + + publicKeyAlgorithm + " with bit strength " + bitStrength + " is not acceptable."); + } + } + private void verifyMasterKeyCanCertify(KeySpec spec) { if (!hasCertifyOthersFlag(spec)) { throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER"); 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 6bffde16..bd5a5063 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 @@ -27,7 +27,7 @@ public class KeySpec { } @Nonnull - KeyType getKeyType() { + public KeyType getKeyType() { return keyType; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java index 584ec1e7..b62fa190 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java @@ -33,6 +33,12 @@ public interface KeyType { */ PublicKeyAlgorithm getAlgorithm(); + /** + * Return the strength of the key in bits. + * @return + */ + int getBitStrength(); + /** * Return an implementation of {@link AlgorithmParameterSpec} that can be used to generate the key. * diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java index 851d2d32..2372896e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/EllipticCurve.java @@ -15,22 +15,28 @@ import org.pgpainless.key.generation.type.xdh.XDHSpec; * {@link XDHSpec} and {@link org.pgpainless.key.generation.type.eddsa.EdDSACurve}. */ public enum EllipticCurve { - _P256("prime256v1"), // prime256v1 is equivalent to P-256, see https://tools.ietf.org/search/rfc4492#page-32 - _P384("secp384r1"), // secp384r1 is equivalent to P-384, see https://tools.ietf.org/search/rfc4492#page-32 - _P521("secp521r1"), // secp521r1 is equivalent to P-521, see https://tools.ietf.org/search/rfc4492#page-32 - _SECP256K1("secp256k1"), - _BRAINPOOLP256R1("brainpoolP256r1"), - _BRAINPOOLP384R1("brainpoolP384r1"), - _BRAINPOOLP512R1("brainpoolP512r1") + _P256("prime256v1", 256), // prime256v1 is equivalent to P-256, see https://tools.ietf.org/search/rfc4492#page-32 + _P384("secp384r1", 384), // secp384r1 is equivalent to P-384, see https://tools.ietf.org/search/rfc4492#page-32 + _P521("secp521r1", 521), // secp521r1 is equivalent to P-521, see https://tools.ietf.org/search/rfc4492#page-32 + _SECP256K1("secp256k1", 256), + _BRAINPOOLP256R1("brainpoolP256r1", 256), + _BRAINPOOLP384R1("brainpoolP384r1", 384), + _BRAINPOOLP512R1("brainpoolP512r1", 512) ; private final String name; + private final int bitStrength; - EllipticCurve(@Nonnull String name) { + EllipticCurve(@Nonnull String name, int bitStrength) { this.name = name; + this.bitStrength = bitStrength; } public String getName() { return name; } + + public int getBitStrength() { + return bitStrength; + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java index 53f0d1b7..bb7e3f3c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdh/ECDH.java @@ -34,6 +34,11 @@ public final class ECDH implements KeyType { return PublicKeyAlgorithm.ECDH; } + @Override + public int getBitStrength() { + return curve.getBitStrength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new ECNamedCurveGenParameterSpec(curve.getName()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java index 93c6398b..87301655 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ecc/ecdsa/ECDSA.java @@ -35,6 +35,11 @@ public final class ECDSA implements KeyType { return PublicKeyAlgorithm.ECDSA; } + @Override + public int getBitStrength() { + return curve.getBitStrength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new ECNamedCurveGenParameterSpec(curve.getName()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java index 67532d6c..ae46b44f 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSA.java @@ -35,6 +35,11 @@ public final class EdDSA implements KeyType { return PublicKeyAlgorithm.EDDSA; } + @Override + public int getBitStrength() { + return curve.getBitStrength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new ECNamedCurveGenParameterSpec(curve.getName()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSACurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSACurve.java index cc1c1831..4d5aed1c 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSACurve.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/eddsa/EdDSACurve.java @@ -7,16 +7,22 @@ package org.pgpainless.key.generation.type.eddsa; import javax.annotation.Nonnull; public enum EdDSACurve { - _Ed25519("ed25519"), + _Ed25519("ed25519", 256), ; final String name; + final int bitStrength; - EdDSACurve(@Nonnull String curveName) { + EdDSACurve(@Nonnull String curveName, int bitStrength) { this.name = curveName; + this.bitStrength = bitStrength; } public String getName() { return name; } + + public int getBitStrength() { + return bitStrength; + } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal.java index ac7a239b..4deb0559 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/elgamal/ElGamal.java @@ -36,6 +36,11 @@ public final class ElGamal implements KeyType { return PublicKeyAlgorithm.ELGAMAL_ENCRYPT; } + @Override + public int getBitStrength() { + return length.getLength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new ElGamalParameterSpec(length.getP(), length.getG()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java index 231c95a2..3cf717b2 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/rsa/RSA.java @@ -36,6 +36,11 @@ public class RSA implements KeyType { return PublicKeyAlgorithm.RSA_GENERAL; } + @Override + public int getBitStrength() { + return length.getLength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new RSAKeyGenParameterSpec(length.getLength(), RSAKeyGenParameterSpec.F4); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java index db8d7d1e..4e589677 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDH.java @@ -32,6 +32,11 @@ public final class XDH implements KeyType { return PublicKeyAlgorithm.ECDH; } + @Override + public int getBitStrength() { + return spec.getBitStrength(); + } + @Override public AlgorithmParameterSpec getAlgorithmSpec() { return new ECNamedCurveGenParameterSpec(spec.getName()); diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDHSpec.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDHSpec.java index e33fecd4..ccbd2038 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDHSpec.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/xdh/XDHSpec.java @@ -7,15 +7,17 @@ package org.pgpainless.key.generation.type.xdh; import javax.annotation.Nonnull; public enum XDHSpec { - _X25519("X25519", "curve25519"), + _X25519("X25519", "curve25519", 256), ; final String name; final String curveName; + final int bitStrength; - XDHSpec(@Nonnull String name, @Nonnull String curveName) { + XDHSpec(@Nonnull String name, @Nonnull String curveName, int bitStrength) { this.name = name; this.curveName = curveName; + this.bitStrength = bitStrength; } public String getName() { @@ -25,4 +27,8 @@ public enum XDHSpec { public String getCurveName() { return curveName; } + + public int getBitStrength() { + return bitStrength; + } } 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 0f2b0eee..db657a31 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 @@ -70,6 +70,7 @@ import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; import org.pgpainless.signature.subpackets.SignatureSubpackets; import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; +import org.pgpainless.util.BCUtil; import org.pgpainless.util.CollectionUtils; import org.pgpainless.util.Passphrase; import org.pgpainless.util.selection.userid.SelectUserId; @@ -169,7 +170,6 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Nonnull Passphrase subKeyPassphrase, @Nonnull SecretKeyRingProtector secretKeyRingProtector) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { - PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec); SecretKeyRingProtector subKeyProtector = PasswordBasedSecretKeyRingProtector @@ -216,11 +216,19 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Nonnull SecretKeyRingProtector primaryKeyProtector, @Nonnull KeyFlag keyFlag, KeyFlag... additionalKeyFlags) - throws PGPException, IOException { + throws PGPException, IOException, NoSuchAlgorithmException { KeyFlag[] flags = concat(keyFlag, additionalKeyFlags); PublicKeyAlgorithm subkeyAlgorithm = PublicKeyAlgorithm.fromId(subkey.getPublicKey().getAlgorithm()); SignatureSubpacketsUtil.assureKeyCanCarryFlags(subkeyAlgorithm); + // check key against public key algorithm policy + PublicKeyAlgorithm publicKeyAlgorithm = PublicKeyAlgorithm.fromId(subkey.getPublicKey().getAlgorithm()); + int bitStrength = BCUtil.getBitStrength(subkey.getPublicKey()); + if (!PGPainless.getPolicy().getPublicKeyAlgorithmPolicy().isAcceptable(publicKeyAlgorithm, bitStrength)) { + throw new IllegalArgumentException("Public key algorithm policy violation: " + + publicKeyAlgorithm + " with bit strength " + bitStrength + " is not acceptable."); + } + PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing); PublicKeyAlgorithm signingKeyAlgorithm = PublicKeyAlgorithm.fromId(primaryKey.getPublicKey().getAlgorithm()); 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 87c53acd..66fa58b5 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 @@ -119,7 +119,7 @@ public interface SecretKeyRingEditorInterface { @Nonnull SecretKeyRingProtector primaryKeyProtector, @Nonnull KeyFlag keyFlag, KeyFlag... additionalKeyFlags) - throws PGPException, IOException; + throws PGPException, IOException, NoSuchAlgorithmException; /** * Revoke the key ring.