diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt index 98ff0603..c5768e99 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt @@ -34,7 +34,7 @@ import org.pgpainless.util.ArmorUtils class PGPainless( val implementation: OpenPGPImplementation = OpenPGPImplementation.getInstance(), - val algorithmPolicy: Policy = Policy.getInstance() + var algorithmPolicy: Policy = Policy.getInstance() ) { private var api: OpenPGPApi @@ -230,7 +230,11 @@ class PGPainless( * * @return policy */ - @JvmStatic fun getPolicy() = getInstance().algorithmPolicy + @Deprecated( + "Use PGPainless.getInstance().getAlgorithmPolicy() instead.", + replaceWith = ReplaceWith("getInstance().algorithmPolicy")) + @JvmStatic + fun getPolicy() = getInstance().algorithmPolicy /** * Create different kinds of signatures on other keys. diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt index 61978792..eb875e21 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt @@ -11,15 +11,16 @@ import org.pgpainless.util.DateUtil import org.pgpainless.util.NotationRegistry class Policy( - var certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, - var revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, - var dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, - var symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, - var symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, - var compressionAlgorithmPolicy: CompressionAlgorithmPolicy, - var publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy, - var keyProtectionSettings: KeyRingProtectionSettings, - var notationRegistry: NotationRegistry + val certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, + val revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, + val dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy, + val symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, + val symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy, + val compressionAlgorithmPolicy: CompressionAlgorithmPolicy, + val publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy, + val keyProtectionSettings: KeyRingProtectionSettings, + val notationRegistry: NotationRegistry, + val keyGenerationAlgorithmSuite: AlgorithmSuite ) { constructor() : @@ -32,12 +33,14 @@ class Policy( CompressionAlgorithmPolicy.anyCompressionAlgorithmPolicy(), PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy(), KeyRingProtectionSettings.secureDefaultSettings(), - NotationRegistry()) + NotationRegistry(), + AlgorithmSuite.defaultAlgorithmSuite) - var keyGenerationAlgorithmSuite = AlgorithmSuite.defaultAlgorithmSuite var signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED var enableKeyParameterValidation = false + fun copy() = Builder(this) + fun isEnableKeyParameterValidation() = enableKeyParameterValidation /** @@ -415,4 +418,92 @@ class Policy( fun getInstance() = INSTANCE ?: synchronized(this) { INSTANCE ?: Policy().also { INSTANCE = it } } } + + class Builder(private val origin: Policy) { + private var certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy = + origin.certificationSignatureHashAlgorithmPolicy + private var revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy = + origin.revocationSignatureHashAlgorithmPolicy + private var dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy = + origin.dataSignatureHashAlgorithmPolicy + private var symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy = + origin.symmetricKeyEncryptionAlgorithmPolicy + private var symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy = + origin.symmetricKeyDecryptionAlgorithmPolicy + private var compressionAlgorithmPolicy: CompressionAlgorithmPolicy = + origin.compressionAlgorithmPolicy + private var publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy = + origin.publicKeyAlgorithmPolicy + private var keyProtectionSettings: KeyRingProtectionSettings = origin.keyProtectionSettings + private var notationRegistry: NotationRegistry = origin.notationRegistry + private var keyGenerationAlgorithmSuite: AlgorithmSuite = origin.keyGenerationAlgorithmSuite + + fun withCertificationSignatureHashAlgorithmPolicy( + certificationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy + ) = apply { + this.certificationSignatureHashAlgorithmPolicy = + certificationSignatureHashAlgorithmPolicy + } + + fun withRevocationSignatureHashAlgorithmPolicy( + revocationSignatureHashAlgorithmPolicy: HashAlgorithmPolicy + ) = apply { + this.revocationSignatureHashAlgorithmPolicy = revocationSignatureHashAlgorithmPolicy + } + + fun withDataSignatureHashAlgorithmPolicy( + dataSignatureHashAlgorithmPolicy: HashAlgorithmPolicy + ) = apply { this.dataSignatureHashAlgorithmPolicy = dataSignatureHashAlgorithmPolicy } + + fun withSymmetricKeyEncryptionAlgorithmPolicy( + symmetricKeyEncryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy + ) = apply { + this.symmetricKeyEncryptionAlgorithmPolicy = symmetricKeyEncryptionAlgorithmPolicy + } + + fun withSymmetricKeyDecryptionAlgorithmPolicy( + symmetricKeyDecryptionAlgorithmPolicy: SymmetricKeyAlgorithmPolicy + ) = apply { + this.symmetricKeyDecryptionAlgorithmPolicy = symmetricKeyDecryptionAlgorithmPolicy + } + + fun withCompressionAlgorithmPolicy(compressionAlgorithmPolicy: CompressionAlgorithmPolicy) = + apply { + this.compressionAlgorithmPolicy = compressionAlgorithmPolicy + } + + fun withPublicKeyAlgorithmPolicy(publicKeyAlgorithmPolicy: PublicKeyAlgorithmPolicy) = + apply { + this.publicKeyAlgorithmPolicy = publicKeyAlgorithmPolicy + } + + fun withKeyProtectionSettings(keyProtectionSettings: KeyRingProtectionSettings) = apply { + this.keyProtectionSettings = keyProtectionSettings + } + + fun withNotationRegistry(notationRegistry: NotationRegistry) = apply { + this.notationRegistry = notationRegistry + } + + fun withKeyGenerationAlgorithmSuite(keyGenerationAlgorithmSuite: AlgorithmSuite) = apply { + this.keyGenerationAlgorithmSuite = keyGenerationAlgorithmSuite + } + + fun build() = + Policy( + certificationSignatureHashAlgorithmPolicy, + revocationSignatureHashAlgorithmPolicy, + dataSignatureHashAlgorithmPolicy, + symmetricKeyEncryptionAlgorithmPolicy, + symmetricKeyDecryptionAlgorithmPolicy, + compressionAlgorithmPolicy, + publicKeyAlgorithmPolicy, + keyProtectionSettings, + notationRegistry, + keyGenerationAlgorithmSuite) + .apply { + enableKeyParameterValidation = origin.enableKeyParameterValidation + signerUserIdValidationLevel = origin.signerUserIdValidationLevel + } + } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java index 71e5085e..6352984a 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/EncryptDecryptTest.java @@ -59,10 +59,7 @@ public class EncryptDecryptTest { @BeforeEach public void setDefaultPolicy() { - PGPainless.getPolicy().setSymmetricKeyEncryptionAlgorithmPolicy( - Policy.SymmetricKeyAlgorithmPolicy.symmetricKeyEncryptionPolicy2022()); - PGPainless.getPolicy().setSymmetricKeyDecryptionAlgorithmPolicy( - Policy.SymmetricKeyAlgorithmPolicy.symmetricKeyDecryptionPolicy2022()); + PGPainless.getInstance().setAlgorithmPolicy(new Policy()); } @TestTemplate diff --git a/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java b/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java index 3b29e35d..c0cbc505 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java @@ -25,13 +25,13 @@ import org.pgpainless.util.NotationRegistry; * can be rejected. * Note, that PGPainless distinguishes between hash algorithms used in revocation and non-revocation signatures, * and has different policies for those. - * + *
* Furthermore, PGPainless has policies for symmetric encryption algorithms (both for encrypting and decrypting), * for public key algorithms and key lengths, as well as compression algorithms. - * + *
* The following examples show how these policies can be modified. - * - * PGPainless' policy is being accessed by calling {@link PGPainless#getPolicy()}. + *
+ * PGPainless' policy is being accessed by calling {@link PGPainless#getAlgorithmPolicy()}. * Custom sub-policies can be set by calling the setter methods of {@link Policy}. */ public class ManagePolicy { @@ -43,50 +43,29 @@ public class ManagePolicy { @AfterEach public void resetPolicy() { // Policy for hash algorithms in non-revocation signatures - PGPainless.getPolicy().setCertificationSignatureHashAlgorithmPolicy( - Policy.HashAlgorithmPolicy.static2022SignatureHashAlgorithmPolicy()); - // Policy for hash algorithms in data signatures - PGPainless.getPolicy().setDataSignatureHashAlgorithmPolicy( - Policy.HashAlgorithmPolicy.static2022SignatureHashAlgorithmPolicy()); - // Policy for hash algorithms in revocation signatures - PGPainless.getPolicy().setRevocationSignatureHashAlgorithmPolicy( - Policy.HashAlgorithmPolicy.static2022RevocationSignatureHashAlgorithmPolicy()); - // Policy for public key algorithms and bit lengths - PGPainless.getPolicy().setPublicKeyAlgorithmPolicy( - Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy()); - // Policy for acceptable symmetric encryption algorithms when decrypting messages - PGPainless.getPolicy().setSymmetricKeyDecryptionAlgorithmPolicy( - Policy.SymmetricKeyAlgorithmPolicy.symmetricKeyDecryptionPolicy2022()); - // Policy for acceptable symmetric encryption algorithms when encrypting messages - PGPainless.getPolicy().setSymmetricKeyEncryptionAlgorithmPolicy( - Policy.SymmetricKeyAlgorithmPolicy.symmetricKeyEncryptionPolicy2022()); - // Policy for acceptable compression algorithms - PGPainless.getPolicy().setCompressionAlgorithmPolicy( - Policy.CompressionAlgorithmPolicy.anyCompressionAlgorithmPolicy()); - // Known notations - PGPainless.getPolicy().getNotationRegistry().clear(); + PGPainless.getInstance().setAlgorithmPolicy(new Policy()); } /** * {@link HashAlgorithm Hash Algorithms} may get outdated with time. {@link HashAlgorithm#SHA1} is a prominent * example for an algorithm that is nowadays considered unsafe to use and which shall be avoided. - * + *
* PGPainless comes with a {@link Policy} class that defines which algorithms are trustworthy and acceptable. * It also allows the user to specify a custom policy tailored to their needs. - * + *
* Per default, PGPainless will reject non-revocation signatures that use SHA-1 as hash algorithm. * To inspect PGPainless' default signature hash algorithm policy, see * {@link Policy.HashAlgorithmPolicy#static2022SignatureHashAlgorithmPolicy()}. - * + *
* Since it may be a valid use-case to accept signatures made using SHA-1 as part of a less strict policy, * this example demonstrates how to set a custom signature hash algorithm policy. */ @Test public void setCustomSignatureHashPolicy() { - // Get PGPainless' policy singleton - Policy policy = PGPainless.getPolicy(); + // Get PGPainless' policy + Policy oldPolicy = PGPainless.getInstance().getAlgorithmPolicy(); - Policy.HashAlgorithmPolicy sigHashAlgoPolicy = policy.getDataSignatureHashAlgorithmPolicy(); + Policy.HashAlgorithmPolicy sigHashAlgoPolicy = oldPolicy.getDataSignatureHashAlgorithmPolicy(); assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA512)); // Per default, non-revocation signatures using SHA-1 are rejected assertFalse(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA1)); @@ -98,12 +77,17 @@ public class ManagePolicy { // List of acceptable hash algorithms Arrays.asList(HashAlgorithm.SHA512, HashAlgorithm.SHA384, HashAlgorithm.SHA256, HashAlgorithm.SHA224, HashAlgorithm.SHA1)); // Set the hash algo policy as policy for non-revocation signatures - policy.setDataSignatureHashAlgorithmPolicy(customPolicy); + PGPainless.getInstance().setAlgorithmPolicy( + oldPolicy.copy().withDataSignatureHashAlgorithmPolicy(customPolicy).build() + ); - sigHashAlgoPolicy = policy.getDataSignatureHashAlgorithmPolicy(); + sigHashAlgoPolicy = PGPainless.getInstance().getAlgorithmPolicy().getDataSignatureHashAlgorithmPolicy(); assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA512)); // SHA-1 is now acceptable as well assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA1)); + + // reset old policy + PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); } /** @@ -111,13 +95,13 @@ public class ManagePolicy { * Per default, PGPainless will reject signatures made by keys of unacceptable algorithm or length. * See {@link Policy.PublicKeyAlgorithmPolicy#bsi2021PublicKeyAlgorithmPolicy()} * to inspect PGPainless' defaults. - * + *
* This example demonstrates how to set a custom public key algorithm policy. */ @Test public void setCustomPublicKeyAlgorithmPolicy() { - Policy policy = PGPainless.getPolicy(); - Policy.PublicKeyAlgorithmPolicy pkAlgorithmPolicy = policy.getPublicKeyAlgorithmPolicy(); + Policy oldPolicy = PGPainless.getInstance().getAlgorithmPolicy(); + Policy.PublicKeyAlgorithmPolicy pkAlgorithmPolicy = oldPolicy.getPublicKeyAlgorithmPolicy(); assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 4096)); assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 2048)); assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 1024)); @@ -131,27 +115,30 @@ public class ManagePolicy { put(PublicKeyAlgorithm.RSA_GENERAL, 3000); }} ); - policy.setPublicKeyAlgorithmPolicy(customPolicy); + PGPainless.getInstance().setAlgorithmPolicy(oldPolicy.copy().withPublicKeyAlgorithmPolicy(customPolicy).build()); - pkAlgorithmPolicy = policy.getPublicKeyAlgorithmPolicy(); + pkAlgorithmPolicy = PGPainless.getInstance().getAlgorithmPolicy().getPublicKeyAlgorithmPolicy(); assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 4096)); // RSA 2048 is no longer acceptable assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 2048)); // ECDSA is no longer acceptable, since it is no longer included in the policy at all assertFalse(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.ECDSA, 256)); + + // Reset policy + PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); } /** * OpenPGP requires implementations to reject signatures which contain critical notation data subpackets * which are not known to the implementation. - * + *
* PGPainless allows the user to define which notations should be considered known notations.
* The following example demonstrates how to mark the notation value 'unknown@pgpainless.org' as known,
* such that signatures containing a critical notation with that name are no longer being invalidated because of it.
*/
@Test
public void manageKnownNotations() {
- Policy policy = PGPainless.getPolicy();
+ Policy policy = PGPainless.getInstance().getAlgorithmPolicy();
NotationRegistry notationRegistry = policy.getNotationRegistry();
assertFalse(notationRegistry.isKnownNotation("unknown@pgpainless.org"));
diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GeneratingWeakKeyThrowsTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GeneratingWeakKeyThrowsTest.java
index 65dea167..49db0243 100644
--- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GeneratingWeakKeyThrowsTest.java
+++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GeneratingWeakKeyThrowsTest.java
@@ -22,9 +22,7 @@ public class GeneratingWeakKeyThrowsTest {
@Test
public void refuseToGenerateWeakPrimaryKeyTest() {
// ensure we have default public key algorithm policy set
- PGPainless.getPolicy().setPublicKeyAlgorithmPolicy(
- Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy());
-
+ PGPainless.getInstance().setAlgorithmPolicy(new Policy());
assertThrows(IllegalArgumentException.class, () ->
PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._1024),
@@ -34,8 +32,7 @@ public class GeneratingWeakKeyThrowsTest {
@Test
public void refuseToAddWeakSubkeyDuringGenerationTest() {
// ensure we have default public key algorithm policy set
- PGPainless.getPolicy().setPublicKeyAlgorithmPolicy(
- Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy());
+ PGPainless.getInstance().setAlgorithmPolicy(new Policy());
KeyRingBuilder kb = PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._4096),
@@ -52,8 +49,10 @@ public class GeneratingWeakKeyThrowsTest {
Map