From 8f3049602ffd7da2a26d01b2277a733b02735f76 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 24 Mar 2025 12:40:43 +0100 Subject: [PATCH] Remove SignerUserId check, Policy setting only via constructor parameter --- .../main/kotlin/org/pgpainless/PGPainless.kt | 17 +- .../OpenPgpMessageInputStream.kt | 13 +- .../key/generation/KeyRingTemplates.kt | 9 +- .../kotlin/org/pgpainless/policy/Policy.kt | 6 +- .../ModifiedPublicKeysInvestigation.java | 8 +- .../WrongSignerUserIdTest.java | 174 ------------------ .../EncryptDecryptTest.java | 27 ++- .../org/pgpainless/example/ManagePolicy.java | 35 +--- ...GenerateKeyWithoutPrimaryKeyFlagsTest.java | 26 +-- .../key/generation/GenerateV6KeyTest.java | 21 +-- .../GeneratingWeakKeyThrowsTest.java | 21 +-- .../RefuseToAddWeakSubkeyTest.java | 8 +- .../org/pgpainless/policy/PolicyTest.java | 6 - .../signature/CertificateValidatorTest.java | 89 ++++----- .../main/kotlin/org/pgpainless/sop/SOPImpl.kt | 2 + .../sop/VerifyLegacySignatureTest.java | 11 +- 16 files changed, 125 insertions(+), 348 deletions(-) delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/decryption_verification/WrongSignerUserIdTest.java diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt index e15c285a..4a0084d2 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/PGPainless.kt @@ -17,7 +17,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator import org.bouncycastle.openpgp.api.OpenPGPKeyReader import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi -import org.bouncycastle.openpgp.api.bc.BcOpenPGPImplementation import org.pgpainless.algorithm.OpenPGPKeyVersion import org.pgpainless.bouncycastle.PolicyAdapter import org.pgpainless.bouncycastle.extensions.setAlgorithmSuite @@ -35,10 +34,14 @@ import org.pgpainless.util.ArmorUtils class PGPainless( val implementation: OpenPGPImplementation = OpenPGPImplementation.getInstance(), - var algorithmPolicy: Policy = Policy() + val algorithmPolicy: Policy = Policy() ) { - private var api: OpenPGPApi + constructor( + algorithmPolicy: Policy + ) : this(OpenPGPImplementation.getInstance(), algorithmPolicy) + + private val api: OpenPGPApi init { implementation.setPolicy( @@ -53,7 +56,11 @@ class PGPainless( ): KeyRingTemplates = KeyRingTemplates(version, creationTime, this) @JvmOverloads - fun buildKey( + fun buildKey(version: OpenPGPKeyVersion = OpenPGPKeyVersion.v4): KeyRingBuilder = + KeyRingBuilder(version, this) + + @JvmOverloads + fun _buildKey( version: OpenPGPKeyVersion = OpenPGPKeyVersion.v4, creationTime: Date = Date() ): OpenPGPKeyGenerator = @@ -108,8 +115,6 @@ class PGPainless( @Volatile private var instance: PGPainless? = null - @JvmStatic fun newInstance(): PGPainless = PGPainless(BcOpenPGPImplementation(), Policy()) - @JvmStatic fun getInstance(): PGPainless = instance ?: synchronized(this) { instance ?: PGPainless().also { instance = it } } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt index af5ffe97..8e8062af 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/OpenPgpMessageInputStream.kt @@ -26,6 +26,7 @@ import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData import org.bouncycastle.openpgp.PGPSessionKey import org.bouncycastle.openpgp.PGPSignature +import org.bouncycastle.openpgp.PGPSignatureException import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey @@ -870,6 +871,10 @@ class OpenPgpMessageInputStream( } catch (e: SignatureValidationException) { layer.addRejectedOnePassSignature( SignatureVerification.Failure(verification, e)) + } catch (e: PGPSignatureException) { + layer.addRejectedOnePassSignature( + SignatureVerification.Failure( + verification, SignatureValidationException(e.message, e))) } break } @@ -973,10 +978,12 @@ class OpenPgpMessageInputStream( SignatureValidator.signatureWasCreatedInBounds( options.getVerifyNotBefore(), options.getVerifyNotAfter()) .verify(detached.signature) - if (detached.verify() && detached.isValid(api.implementation.policy())) { - layer.addVerifiedDetachedSignature(verification) - } else { + if (!detached.verify()) { throw SignatureValidationException("Incorrect detached signature.") + } else if (!detached.isValid(api.implementation.policy())) { + throw SignatureValidationException("Detached signature is not valid.") + } else { + layer.addVerifiedDetachedSignature(verification) } } catch (e: MalformedOpenPGPSignatureException) { throw SignatureValidationException("Malformed detached signature.", e) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingTemplates.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingTemplates.kt index 54948878..122b8e31 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingTemplates.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingTemplates.kt @@ -7,7 +7,6 @@ package org.pgpainless.key.generation import java.util.* import org.bouncycastle.openpgp.api.OpenPGPKey import org.pgpainless.PGPainless -import org.pgpainless.PGPainless.Companion.buildKeyRing import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.OpenPGPKeyVersion import org.pgpainless.key.generation.KeySpec.Companion.getBuilder @@ -38,7 +37,7 @@ class KeyRingTemplates( length: RsaLength, passphrase: Passphrase = Passphrase.emptyPassphrase() ): OpenPGPKey = - buildKeyRing(version, api) + api.buildKey(version) .apply { setPrimaryKey( getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER) @@ -90,7 +89,7 @@ class KeyRingTemplates( length: RsaLength, passphrase: Passphrase = Passphrase.emptyPassphrase() ): OpenPGPKey = - buildKeyRing(version) + api.buildKey(version) .apply { setPrimaryKey( getBuilder( @@ -144,7 +143,7 @@ class KeyRingTemplates( val encryptionKeyType = if (version == OpenPGPKeyVersion.v6) KeyType.X25519() else KeyType.XDH_LEGACY(XDHLegacySpec._X25519) - return buildKeyRing(version) + return api.buildKey(version) .apply { setPrimaryKey( getBuilder(signingKeyType, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) @@ -197,7 +196,7 @@ class KeyRingTemplates( val encryptionKeyType = if (version == OpenPGPKeyVersion.v6) KeyType.X25519() else KeyType.XDH_LEGACY(XDHLegacySpec._X25519) - return buildKeyRing(version) + return api.buildKey(version) .apply { setPrimaryKey( getBuilder(signingKeyType, KeyFlag.CERTIFY_OTHER) 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 a2339bec..233600c7 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/policy/Policy.kt @@ -36,7 +36,6 @@ class Policy( NotationRegistry(), AlgorithmSuite.defaultAlgorithmSuite) - var signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED var enableKeyParameterValidation = false fun copy() = Builder(this) @@ -493,9 +492,6 @@ class Policy( keyProtectionSettings, notationRegistry, keyGenerationAlgorithmSuite) - .apply { - enableKeyParameterValidation = origin.enableKeyParameterValidation - signerUserIdValidationLevel = origin.signerUserIdValidationLevel - } + .apply { enableKeyParameterValidation = origin.enableKeyParameterValidation } } } diff --git a/pgpainless-core/src/test/java/investigations/ModifiedPublicKeysInvestigation.java b/pgpainless-core/src/test/java/investigations/ModifiedPublicKeysInvestigation.java index 46bfca6a..1d79658b 100644 --- a/pgpainless-core/src/test/java/investigations/ModifiedPublicKeysInvestigation.java +++ b/pgpainless-core/src/test/java/investigations/ModifiedPublicKeysInvestigation.java @@ -211,7 +211,7 @@ public class ModifiedPublicKeysInvestigation { @Test public void assertModifiedDSAKeyThrowsKeyIntegrityException() throws IOException { - PGPainless api = PGPainless.newInstance(); + PGPainless api = PGPainless.getInstance(); Policy policy = api.getAlgorithmPolicy(); policy.setEnableKeyParameterValidation(true); @@ -226,7 +226,7 @@ public class ModifiedPublicKeysInvestigation { @Test public void assertModifiedElGamalKeyThrowsKeyIntegrityException() throws IOException { - PGPainless api = PGPainless.newInstance(); + PGPainless api = PGPainless.getInstance(); Policy policy = api.getAlgorithmPolicy(); policy.setEnableKeyParameterValidation(true); @@ -239,7 +239,7 @@ public class ModifiedPublicKeysInvestigation { @Test public void assertInjectedKeyRingFailsToUnlockPrimaryKey() throws IOException { - PGPainless api = PGPainless.newInstance(); + PGPainless api = PGPainless.getInstance(); Policy policy = api.getAlgorithmPolicy(); policy.setEnableKeyParameterValidation(true); @@ -252,7 +252,7 @@ public class ModifiedPublicKeysInvestigation { @Test public void assertCannotUnlockElGamalPrimaryKeyDueToDummyS2K() throws IOException { - PGPainless api = PGPainless.newInstance(); + PGPainless api = PGPainless.getInstance(); SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("12345678")); OpenPGPKey elgamal = api.readKey().parseKey(ELGAMAL); diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/WrongSignerUserIdTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/WrongSignerUserIdTest.java deleted file mode 100644 index 61e06cf5..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/WrongSignerUserIdTest.java +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.decryption_verification; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.Iterator; - -import org.bouncycastle.bcpg.ArmoredOutputStream; -import org.bouncycastle.bcpg.BCPGOutputStream; -import org.bouncycastle.bcpg.CompressionAlgorithmTags; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle.openpgp.PGPCompressedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPLiteralDataGenerator; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureGenerator; -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; -import org.bouncycastle.util.io.Streams; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Test; -import org.pgpainless.PGPainless; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.key.protection.UnlockSecretKey; -import org.pgpainless.policy.Policy; -import org.pgpainless.util.Passphrase; - -public class WrongSignerUserIdTest { - - private static final String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - " Comment: Alice's OpenPGP Transferable Secret Key\n" + - " Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html\n" + - "\n" + - " lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U\n" + - " b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj\n" + - " ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ\n" + - " CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l\n" + - " nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf\n" + - " a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB\n" + - " BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA\n" + - " /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF\n" + - " u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM\n" + - " hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb\n" + - " Pnn+We1aTBhaGa86AQ==\n" + - " =n8OM\n" + - " -----END PGP PRIVATE KEY BLOCK-----"; - private static final String USER_ID = "Alice Lovelace "; - - @Test - public void verificationSucceedsWithDisabledCheck() throws PGPException, IOException { - executeTest(false, true); - } - - @Test - public void verificationFailsWithEnabledCheck() throws PGPException, IOException { - executeTest(true, false); - } - - @AfterAll - public static void resetDefault() { - PGPainless.getPolicy().setSignerUserIdValidationLevel(Policy.SignerUserIdValidationLevel.DISABLED); - } - - public void executeTest(boolean enableCheck, boolean expectSucessfulVerification) throws IOException, PGPException { - PGPainless.getPolicy().setSignerUserIdValidationLevel(enableCheck ? Policy.SignerUserIdValidationLevel.STRICT : Policy.SignerUserIdValidationLevel.DISABLED); - PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY); - assertEquals(USER_ID, secretKeys.getPublicKey().getUserIDs().next()); - - String messageWithWrongUserId = generateTestMessage(secretKeys); - verifyTestMessage(messageWithWrongUserId, secretKeys, expectSucessfulVerification); - } - - private void verifyTestMessage(String messageWithWrongUserId, PGPSecretKeyRing secretKeys, boolean expectSuccessfulVerification) throws IOException, PGPException { - PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys); - - DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify().onInputStream( - new ByteArrayInputStream(messageWithWrongUserId.getBytes(StandardCharsets.UTF_8))) - .withOptions(ConsumerOptions.get() - .addDecryptionKey(secretKeys) - .addVerificationCert(certificate)); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Streams.pipeAll(decryptionStream, out); - - decryptionStream.close(); - MessageMetadata metadata = decryptionStream.getMetadata(); - - if (expectSuccessfulVerification) { - assertTrue(metadata.isVerifiedSigned()); - } else { - assertFalse(metadata.isVerifiedSigned()); - } - - } - - private String generateTestMessage(PGPSecretKeyRing secretKeys) throws PGPException, IOException { - PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKeys); - - assertEquals(USER_ID, certificate.getPublicKey().getUserIDs().next()); - - Iterator keys = secretKeys.getSecretKeys(); - PGPSecretKey signingKey = keys.next(); - PGPSecretKey encryptionKey = keys.next(); - - PGPPrivateKey signingPrivKey = UnlockSecretKey.unlockSecretKey(signingKey, Passphrase.emptyPassphrase()); - - // ARMOR - ByteArrayOutputStream cipherText = new ByteArrayOutputStream(); - ArmoredOutputStream armorOut = new ArmoredOutputStream(cipherText); - - // ENCRYPTION - PGPDataEncryptorBuilder dataEncryptorBuilder = new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256); - dataEncryptorBuilder.setWithIntegrityPacket(true); - - PGPEncryptedDataGenerator encDataGenerator = new PGPEncryptedDataGenerator(dataEncryptorBuilder); - encDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encryptionKey.getPublicKey())); - OutputStream encStream = encDataGenerator.open(armorOut, new byte[4096]); - - // COMPRESSION - PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZLIB); - BCPGOutputStream bOut = new BCPGOutputStream(compressedDataGenerator.open(encStream)); - - // SIGNING - PGPSignatureGenerator sigGen = new PGPSignatureGenerator( - new BcPGPContentSignerBuilder(signingKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId())); - sigGen.init(PGPSignature.BINARY_DOCUMENT, signingPrivKey); - - PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator(); - subpacketGenerator.addSignerUserID(false, "Albert Lovelace "); - sigGen.setHashedSubpackets(subpacketGenerator.generate()); - - sigGen.generateOnePassVersion(false).encode(bOut); - - // LITERAL DATA - PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(); - OutputStream lOut = literalDataGenerator.open(bOut, PGPLiteralDataGenerator.BINARY, - PGPLiteralDataGenerator.CONSOLE, new Date(), new byte[4096]); - - // write msg - ByteArrayInputStream msgIn = new ByteArrayInputStream("Hello, World!\n".getBytes(StandardCharsets.UTF_8)); - int ch; - while ((ch = msgIn.read()) >= 0) { - lOut.write(ch); - sigGen.update((byte) ch); - } - - lOut.close(); - sigGen.generate().encode(bOut); - compressedDataGenerator.close(); - encStream.close(); - armorOut.close(); - - return cipherText.toString(); - } -} 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 5ec70502..6561368d 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 @@ -23,7 +23,6 @@ import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.util.io.Streams; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; import org.pgpainless.PGPainless; @@ -39,7 +38,6 @@ import org.pgpainless.key.generation.type.rsa.RsaLength; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.key.util.KeyRingUtils; -import org.pgpainless.policy.Policy; import org.pgpainless.util.ArmoredOutputStreamFactory; import org.pgpainless.util.TestAllImplementations; @@ -57,18 +55,14 @@ public class EncryptDecryptTest { "Unfold the imagined happiness that both\n" + "Receive in either by this dear encounter."; - @BeforeEach - public void setDefaultPolicy() { - PGPainless.getInstance().setAlgorithmPolicy(new Policy()); - } - @TestTemplate @ExtendWith(TestAllImplementations.class) public void freshKeysRsaToRsaTest() throws PGPException, IOException { - PGPSecretKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072) + PGPainless api = PGPainless.getInstance(); + PGPSecretKeyRing sender = api.generateKey().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072) .getPGPSecretKeyRing(); - PGPSecretKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._3072) + PGPSecretKeyRing recipient = api.generateKey().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._3072) .getPGPSecretKeyRing(); encryptDecryptForSecretKeyRings(sender, recipient); @@ -78,9 +72,10 @@ public class EncryptDecryptTest { @ExtendWith(TestAllImplementations.class) public void freshKeysEcToEcTest() throws IOException, PGPException { - PGPSecretKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("romeo@montague.lit") + PGPainless api = PGPainless.getInstance(); + PGPSecretKeyRing sender = api.generateKey().simpleEcKeyRing("romeo@montague.lit") .getPGPSecretKeyRing(); - PGPSecretKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("juliet@capulet.lit") + PGPSecretKeyRing recipient = api.generateKey().simpleEcKeyRing("juliet@capulet.lit") .getPGPSecretKeyRing(); encryptDecryptForSecretKeyRings(sender, recipient); @@ -90,9 +85,10 @@ public class EncryptDecryptTest { @ExtendWith(TestAllImplementations.class) public void freshKeysEcToRsaTest() throws PGPException, IOException { - PGPSecretKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("romeo@montague.lit") + PGPainless api = PGPainless.getInstance(); + PGPSecretKeyRing sender = api.generateKey().simpleEcKeyRing("romeo@montague.lit") .getPGPSecretKeyRing(); - PGPSecretKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._3072) + PGPSecretKeyRing recipient = api.generateKey().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._3072) .getPGPSecretKeyRing(); encryptDecryptForSecretKeyRings(sender, recipient); @@ -102,9 +98,10 @@ public class EncryptDecryptTest { @ExtendWith(TestAllImplementations.class) public void freshKeysRsaToEcTest() throws PGPException, IOException { - PGPSecretKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072) + PGPainless api = PGPainless.getInstance(); + PGPSecretKeyRing sender = api.generateKey().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072) .getPGPSecretKeyRing(); - PGPSecretKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("juliet@capulet.lit") + PGPSecretKeyRing recipient = api.generateKey().simpleEcKeyRing("juliet@capulet.lit") .getPGPSecretKeyRing(); encryptDecryptForSecretKeyRings(sender, recipient); 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 c0cbc505..7fc55f7b 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/ManagePolicy.java @@ -10,8 +10,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.HashMap; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; import org.pgpainless.algorithm.HashAlgorithm; @@ -36,16 +34,6 @@ import org.pgpainless.util.NotationRegistry; */ public class ManagePolicy { - /** - * Reset PGPainless' policy class to default values. - */ - @BeforeEach - @AfterEach - public void resetPolicy() { - // Policy for hash algorithms in non-revocation signatures - 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. @@ -62,8 +50,9 @@ public class ManagePolicy { */ @Test public void setCustomSignatureHashPolicy() { + PGPainless api = PGPainless.getInstance(); // Get PGPainless' policy - Policy oldPolicy = PGPainless.getInstance().getAlgorithmPolicy(); + Policy oldPolicy = api.getAlgorithmPolicy(); Policy.HashAlgorithmPolicy sigHashAlgoPolicy = oldPolicy.getDataSignatureHashAlgorithmPolicy(); assertTrue(sigHashAlgoPolicy.isAcceptable(HashAlgorithm.SHA512)); @@ -77,17 +66,12 @@ 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 - PGPainless.getInstance().setAlgorithmPolicy( - oldPolicy.copy().withDataSignatureHashAlgorithmPolicy(customPolicy).build() - ); + api = new PGPainless(oldPolicy.copy().withDataSignatureHashAlgorithmPolicy(customPolicy).build()); - sigHashAlgoPolicy = PGPainless.getInstance().getAlgorithmPolicy().getDataSignatureHashAlgorithmPolicy(); + sigHashAlgoPolicy = api.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); } /** @@ -100,7 +84,8 @@ public class ManagePolicy { */ @Test public void setCustomPublicKeyAlgorithmPolicy() { - Policy oldPolicy = PGPainless.getInstance().getAlgorithmPolicy(); + PGPainless api = PGPainless.getInstance(); + Policy oldPolicy = api.getAlgorithmPolicy(); Policy.PublicKeyAlgorithmPolicy pkAlgorithmPolicy = oldPolicy.getPublicKeyAlgorithmPolicy(); assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 4096)); assertTrue(pkAlgorithmPolicy.isAcceptable(PublicKeyAlgorithm.RSA_GENERAL, 2048)); @@ -115,17 +100,15 @@ public class ManagePolicy { put(PublicKeyAlgorithm.RSA_GENERAL, 3000); }} ); - PGPainless.getInstance().setAlgorithmPolicy(oldPolicy.copy().withPublicKeyAlgorithmPolicy(customPolicy).build()); - pkAlgorithmPolicy = PGPainless.getInstance().getAlgorithmPolicy().getPublicKeyAlgorithmPolicy(); + api = new PGPainless(oldPolicy.copy().withPublicKeyAlgorithmPolicy(customPolicy).build()); + + pkAlgorithmPolicy = api.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); } /** diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithoutPrimaryKeyFlagsTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithoutPrimaryKeyFlagsTest.java index d23e6f15..40bcac96 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithoutPrimaryKeyFlagsTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithoutPrimaryKeyFlagsTest.java @@ -15,8 +15,8 @@ import java.nio.charset.StandardCharsets; import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; @@ -42,15 +42,15 @@ public class GenerateKeyWithoutPrimaryKeyFlagsTest { @Test public void generateKeyWithoutCertifyKeyFlag_cannotCertifyThirdParties() throws PGPException, IOException { - PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing().setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519))) + PGPainless api = PGPainless.getInstance(); + OpenPGPKey key = api.buildKey().setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519))) .addSubkey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA)) .addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) .addUserId("Alice") - .build() - .getPGPSecretKeyRing(); - PGPPublicKeyRing cert = PGPainless.extractCertificate(secretKeys); + .build(); + OpenPGPCertificate cert = key.toCertificate(); - KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); + KeyRingInfo info = api.inspect(key); assertTrue(info.getValidUserIds().contains("Alice")); KeyIdentifier primaryKeyIdentifier = info.getKeyIdentifier(); @@ -59,18 +59,18 @@ public class GenerateKeyWithoutPrimaryKeyFlagsTest { assertFalse(info.isUsableForThirdPartyCertification()); // Key without CERTIFY_OTHER flag cannot be used to certify other keys - PGPPublicKeyRing thirdPartyCert = TestKeys.getCryptiePublicKeyRing(); + OpenPGPCertificate thirdPartyCert = TestKeys.getCryptieCertificate(); assertThrows(KeyException.UnacceptableThirdPartyCertificationKeyException.class, () -> - PGPainless.certify().certificate(thirdPartyCert) - .withKey(secretKeys, SecretKeyRingProtector.unprotectedKeys())); + api.generateCertification().certificate(thirdPartyCert) + .withKey(key, SecretKeyRingProtector.unprotectedKeys())); // Key without CERTIFY_OTHER flags is usable for encryption and signing ByteArrayOutputStream ciphertext = new ByteArrayOutputStream(); - EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() + EncryptionStream encryptionStream = api.generateMessage() .onOutputStream(ciphertext) .withOptions(ProducerOptions.signAndEncrypt( EncryptionOptions.get().addRecipient(cert), - SigningOptions.get().addInlineSignature(SecretKeyRingProtector.unprotectedKeys(), secretKeys, DocumentSignatureType.BINARY_DOCUMENT) + SigningOptions.get().addInlineSignature(SecretKeyRingProtector.unprotectedKeys(), key, DocumentSignatureType.BINARY_DOCUMENT) )); encryptionStream.write("Hello, World!\n".getBytes(StandardCharsets.UTF_8)); encryptionStream.close(); @@ -79,7 +79,7 @@ public class GenerateKeyWithoutPrimaryKeyFlagsTest { DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(new ByteArrayInputStream(ciphertext.toByteArray())) - .withOptions(ConsumerOptions.get().addDecryptionKey(secretKeys) + .withOptions(ConsumerOptions.get().addDecryptionKey(key) .addVerificationCert(cert)); ByteArrayOutputStream plaintext = new ByteArrayOutputStream(); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateV6KeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateV6KeyTest.java index 652afb33..58f4695e 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateV6KeyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateV6KeyTest.java @@ -18,7 +18,6 @@ import org.pgpainless.algorithm.OpenPGPKeyVersion; import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.key.generation.type.rsa.RsaLength; import org.pgpainless.key.protection.KeyRingProtectionSettings; -import org.pgpainless.policy.Policy; import java.io.IOException; @@ -31,7 +30,8 @@ public class GenerateV6KeyTest { @Test public void generateModernV6Key() { - OpenPGPKey key = PGPainless.generateKeyRing(OpenPGPKeyVersion.v6) + PGPainless api = PGPainless.getInstance(); + OpenPGPKey key = api.generateKey(OpenPGPKeyVersion.v6) .modernKeyRing("Alice "); assertEquals(3, key.getKeys().size()); @@ -54,7 +54,7 @@ public class GenerateV6KeyTest { @Test public void buildMinimalEd25519V6Key() throws PGPException { - OpenPGPKey key = PGPainless.getInstance().buildKey(OpenPGPKeyVersion.v6) + OpenPGPKey key = PGPainless.getInstance()._buildKey(OpenPGPKeyVersion.v6) .withPrimaryKey(PGPKeyPairGenerator::generateEd25519KeyPair, new SignatureParameters.Callback() { @Override public SignatureParameters apply(SignatureParameters parameters) { @@ -87,7 +87,7 @@ public class GenerateV6KeyTest { @Test public void buildCompositeCurve25519V6Key() throws PGPException, IOException { - OpenPGPKey key = PGPainless.getInstance().buildKey(OpenPGPKeyVersion.v6) + OpenPGPKey key = PGPainless.getInstance()._buildKey(OpenPGPKeyVersion.v6) .withPrimaryKey(PGPKeyPairGenerator::generateEd25519KeyPair) .addSigningSubkey(PGPKeyPairGenerator::generateEd25519KeyPair) .addEncryptionSubkey(PGPKeyPairGenerator::generateX25519KeyPair) @@ -138,20 +138,19 @@ public class GenerateV6KeyTest { @Test public void generateAEADProtectedModernKey() throws IOException, PGPException { - Policy oldPolicy = PGPainless.getInstance().getAlgorithmPolicy(); + PGPainless api = PGPainless.getInstance(); // Change Policy to use AEAD for secret key protection - PGPainless.getInstance().setAlgorithmPolicy( - oldPolicy.copy().withKeyProtectionSettings(KeyRingProtectionSettings.aead()).build() - ); + api = new PGPainless(api.getAlgorithmPolicy().copy() + .withKeyProtectionSettings(KeyRingProtectionSettings.aead()).build()); - OpenPGPKey key = PGPainless.getInstance() + OpenPGPKey key = api .generateKey(OpenPGPKeyVersion.v6) .modernKeyRing("Alice ", "p455w0rd"); String armored = key.toAsciiArmoredString(); - OpenPGPKey parsed = PGPainless.getInstance().readKey().parseKey(armored); + OpenPGPKey parsed = api.readKey().parseKey(armored); OpenPGPKey.OpenPGPSecretKey primaryKey = key.getPrimarySecretKey(); assertEquals(SecretKeyPacket.USAGE_AEAD, primaryKey.getPGPSecretKey().getS2KUsage()); @@ -160,7 +159,5 @@ public class GenerateV6KeyTest { assertNotNull(privateKey); assertEquals(armored, parsed.toAsciiArmoredString()); - - PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); } } 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 49db0243..d75a751c 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 @@ -21,20 +21,15 @@ public class GeneratingWeakKeyThrowsTest { @Test public void refuseToGenerateWeakPrimaryKeyTest() { - // ensure we have default public key algorithm policy set - PGPainless.getInstance().setAlgorithmPolicy(new Policy()); assertThrows(IllegalArgumentException.class, () -> - PGPainless.buildKeyRing() + PGPainless.getInstance().buildKey() .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA))); } @Test public void refuseToAddWeakSubkeyDuringGenerationTest() { - // ensure we have default public key algorithm policy set - PGPainless.getInstance().setAlgorithmPolicy(new Policy()); - - KeyRingBuilder kb = PGPainless.buildKeyRing() + KeyRingBuilder kb = PGPainless.getInstance().buildKey() .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._4096), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)); @@ -46,23 +41,19 @@ public class GeneratingWeakKeyThrowsTest { @Test public void allowToAddWeakKeysWithWeakPolicy() { // set a weak algorithm policy + PGPainless api = PGPainless.getInstance(); Map bitStrengths = new HashMap<>(); bitStrengths.put(PublicKeyAlgorithm.RSA_GENERAL, 512); - Policy oldPolicy = PGPainless.getPolicy(); - PGPainless.getInstance().setAlgorithmPolicy(oldPolicy.copy() - .withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(bitStrengths)) - .build()); + Policy oldPolicy = api.getAlgorithmPolicy(); + api = new PGPainless(oldPolicy.copy().withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(bitStrengths)).build()); - PGPainless.buildKeyRing() + api.buildKey() .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._4096), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) .addSubkey(KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS)) .addUserId("Henry") .build(); - - // reset public key algorithm policy - PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/modification/RefuseToAddWeakSubkeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/modification/RefuseToAddWeakSubkeyTest.java index c1019679..cffdd063 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/modification/RefuseToAddWeakSubkeyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/modification/RefuseToAddWeakSubkeyTest.java @@ -34,7 +34,7 @@ public class RefuseToAddWeakSubkeyTest { Policy adjusted = oldPolicy.copy().withPublicKeyAlgorithmPolicy( Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy() ).build(); - api.setAlgorithmPolicy(adjusted); + api = new PGPainless(adjusted); OpenPGPKey secretKeys = api.generateKey() .modernKeyRing("Alice"); @@ -43,7 +43,6 @@ public class RefuseToAddWeakSubkeyTest { assertThrows(IllegalArgumentException.class, () -> editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())); - api.setAlgorithmPolicy(oldPolicy); } @Test @@ -75,7 +74,7 @@ public class RefuseToAddWeakSubkeyTest { minimalBitStrengths.put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000); // ยง7.2.2 minimalBitStrengths.put(PublicKeyAlgorithm.ECDH, 250); - api.setAlgorithmPolicy(oldPolicy.copy() + api = new PGPainless(oldPolicy.copy() .withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(minimalBitStrengths)) .build()); @@ -88,8 +87,5 @@ public class RefuseToAddWeakSubkeyTest { .done(); assertEquals(2, api.inspect(secretKeys).getEncryptionSubkeys(EncryptionPurpose.ANY).size()); - - // reset default policy - api.setAlgorithmPolicy(oldPolicy); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/policy/PolicyTest.java b/pgpainless-core/src/test/java/org/pgpainless/policy/PolicyTest.java index 27288218..440b8165 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/policy/PolicyTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/policy/PolicyTest.java @@ -6,7 +6,6 @@ package org.pgpainless.policy; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; @@ -205,9 +204,4 @@ public class PolicyTest { public void testUnknownPublicKeyAlgorithmIsNotAcceptable() { assertFalse(policy.getPublicKeyAlgorithmPolicy().isAcceptable(-1, 4096)); } - - @Test - public void setNullSignerUserIdValidationLevelThrows() { - assertThrows(NullPointerException.class, () -> policy.setSignerUserIdValidationLevel(null)); - } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/signature/CertificateValidatorTest.java b/pgpainless-core/src/test/java/org/pgpainless/signature/CertificateValidatorTest.java index ff22d4d3..1ab69990 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/signature/CertificateValidatorTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/signature/CertificateValidatorTest.java @@ -12,7 +12,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; -import java.util.Date; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; @@ -27,7 +26,6 @@ import org.pgpainless.decryption_verification.ConsumerOptions; import org.pgpainless.decryption_verification.DecryptionStream; import org.pgpainless.decryption_verification.MessageMetadata; import org.pgpainless.exception.SignatureValidationException; -import org.pgpainless.policy.Policy; import org.pgpainless.util.TestAllImplementations; public class CertificateValidatorTest { @@ -166,21 +164,19 @@ public class CertificateValidatorTest { PGPSignature primaryKeyRevoked = SignatureUtils.readSignatures(sigPrimaryKeyRevoked).get(0); PGPSignature primaryKeyRevalidated = SignatureUtils.readSignatures(sigPrimaryKeyRevalidated).get(0); - Policy policy = PGPainless.getPolicy(); - Date validationDate = new Date(); String data = "Hello, World"; assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, validationDate), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key"); assertThrows(SignatureValidationException.class, () -> verify( - unboundSubkey, getSignedData(data), publicKeys, policy, validationDate), + unboundSubkey, getSignedData(data), publicKeys), "Primary key hard revoked"); assertThrows(SignatureValidationException.class, () -> verify( - primaryKeyRevoked, getSignedData(data), publicKeys, policy, validationDate), + primaryKeyRevoked, getSignedData(data), publicKeys), "Primary key hard revoked"); assertThrows(SignatureValidationException.class, () -> verify( - primaryKeyRevalidated, getSignedData(data), publicKeys, policy, validationDate), + primaryKeyRevalidated, getSignedData(data), publicKeys), "Primary key hard revoked"); } @@ -317,21 +313,19 @@ public class CertificateValidatorTest { PGPSignature revokedSubkey = SignatureUtils.readSignatures(sigSubkeyRevoked).get(0); PGPSignature revalidatedSubkey = SignatureUtils.readSignatures(sigSubkeyRevalidated).get(0); - Policy policy = PGPainless.getPolicy(); - Date validationDate = new Date(); String data = "Hello, World"; assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, validationDate), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key"); assertThrows(SignatureValidationException.class, () -> verify( - unboundSubkey, getSignedData(data), publicKeys, policy, validationDate), + unboundSubkey, getSignedData(data), publicKeys), "Signing key unbound + hard revocation"); assertThrows(SignatureValidationException.class, () -> verify( - revokedSubkey, getSignedData(data), publicKeys, policy, validationDate), + revokedSubkey, getSignedData(data), publicKeys), "Primary key is hard revoked"); assertThrows(SignatureValidationException.class, () -> verify( - revalidatedSubkey, getSignedData(data), publicKeys, policy, validationDate), + revalidatedSubkey, getSignedData(data), publicKeys), "Primary key is hard revoked"); } @@ -469,21 +463,19 @@ public class CertificateValidatorTest { PGPSignature afterHardRevocation = SignatureUtils.readSignatures(sigAfterHardRevocation).get(0); PGPSignature afterRevalidation = SignatureUtils.readSignatures(sigAfterRevalidation).get(0); - Policy policy = PGPainless.getPolicy(); - Date validationDate = new Date(); String data = "Hello World :)"; assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, validationDate), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key"); assertThrows(SignatureValidationException.class, () -> verify( - unboundKey, getSignedData(data), publicKeys, policy, validationDate), + unboundKey, getSignedData(data), publicKeys), "Signing key unbound + hard revocation"); assertThrows(SignatureValidationException.class, () -> verify( - afterHardRevocation, getSignedData(data), publicKeys, policy, validationDate), + afterHardRevocation, getSignedData(data), publicKeys), "Hard revocation invalidates key at all times"); assertThrows(SignatureValidationException.class, () -> verify( - afterRevalidation, getSignedData(data), publicKeys, policy, validationDate), + afterRevalidation, getSignedData(data), publicKeys), "Hard revocation invalidates key at all times"); } @@ -620,27 +612,26 @@ public class CertificateValidatorTest { PGPSignature keyIsValid = SignatureUtils.readSignatures(sigKeyIsValid).get(0); PGPSignature keyIsRevoked = SignatureUtils.readSignatures(sigKeyIsRevoked).get(0); PGPSignature keyIsRevalidated = SignatureUtils.readSignatures(sigKeyIsRevalidated).get(0); - Policy policy = PGPainless.getPolicy(); String data = "Hello, World"; // Sig not valid, as it predates the signing key creation time assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, predatesPrimaryKey.getCreationTime()), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key creation date"); // Sig valid assertDoesNotThrow(() -> verify( - keyIsValid, getSignedData(data), publicKeys, policy, keyIsValid.getCreationTime()), + keyIsValid, getSignedData(data), publicKeys), "Signature is valid"); // Sig not valid, as the signing key is revoked assertThrows(SignatureValidationException.class, () -> verify( - keyIsRevoked, getSignedData(data), publicKeys, policy, keyIsRevoked.getCreationTime()), + keyIsRevoked, getSignedData(data), publicKeys), "Signing key is revoked at this point"); // Sig valid, as the signing key is revalidated assertDoesNotThrow(() -> verify( - keyIsRevalidated, getSignedData(data), publicKeys, policy, keyIsRevalidated.getCreationTime()), + keyIsRevalidated, getSignedData(data), publicKeys), "Signature is valid, as signing key is revalidated"); } @@ -778,22 +769,20 @@ public class CertificateValidatorTest { PGPSignature keyRevoked = SignatureUtils.readSignatures(sigKeyRevoked).get(0); PGPSignature valid = SignatureUtils.readSignatures(sigKeyValid).get(0); - Policy policy = PGPainless.getPolicy(); String data = "Hello, World"; - Date validationDate = new Date(); assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, validationDate), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key creation date"); assertThrows(SignatureValidationException.class, () -> verify( - keyNotBound, getSignedData(data), publicKeys, policy, validationDate), + keyNotBound, getSignedData(data), publicKeys), "Signing key is not bound at this point"); assertThrows(SignatureValidationException.class, () -> verify( - keyRevoked, getSignedData(data), publicKeys, policy, validationDate), + keyRevoked, getSignedData(data), publicKeys), "Signing key is revoked at this point"); assertDoesNotThrow(() -> verify( - valid, getSignedData(data), publicKeys, policy, validationDate), + valid, getSignedData(data), publicKeys), "Signing key is revalidated"); } @@ -931,22 +920,20 @@ public class CertificateValidatorTest { PGPSignature revoked = SignatureUtils.readSignatures(sigRevoked).get(0); PGPSignature revalidated = SignatureUtils.readSignatures(sigReLegitimized).get(0); - Policy policy = PGPainless.getPolicy(); - Date validationDate = new Date(); String data = "Hello, World"; assertThrows(SignatureValidationException.class, () -> verify( - predatesPrimaryKey, getSignedData(data), publicKeys, policy, validationDate), + predatesPrimaryKey, getSignedData(data), publicKeys), "Signature predates primary key creation date"); assertDoesNotThrow(() -> verify( - valid, getSignedData(data), publicKeys, policy, validationDate), + valid, getSignedData(data), publicKeys), "Signature is valid"); assertThrows(SignatureValidationException.class, () -> verify( - revoked, getSignedData(data), publicKeys, policy, validationDate), + revoked, getSignedData(data), publicKeys), "Primary key is revoked"); assertDoesNotThrow(() -> verify( - revalidated, getSignedData(data), publicKeys, policy, validationDate), + revalidated, getSignedData(data), publicKeys), "Primary key is re-legitimized"); } @@ -1271,52 +1258,50 @@ public class CertificateValidatorTest { PGPSignature sigCT2_T3 = SignatureUtils.readSignatures(keyCSigT2_T3).get(0); PGPSignature sigCT3_now = SignatureUtils.readSignatures(keyCSigT3_now).get(0); - Policy policy = PGPainless.getPolicy(); - Date validationDate = new Date(); String data = "Hello World :)"; assertThrows(SignatureValidationException.class, () -> verify( - sigAT0, getSignedData(data), keysA, policy, validationDate), + sigAT0, getSignedData(data), keysA), "Signature predates key creation time"); assertDoesNotThrow(() -> verify( - sigAT1_T2, getSignedData(data), keysA, policy, validationDate), + sigAT1_T2, getSignedData(data), keysA), "Key valid"); assertThrows(SignatureValidationException.class, () -> verify( - sigAT2_T3, getSignedData(data), keysA, policy, validationDate), + sigAT2_T3, getSignedData(data), keysA), "Key is not valid, as subkey binding expired"); assertDoesNotThrow(() -> verify( - sigAT3_now, getSignedData(data), keysA, policy, validationDate), + sigAT3_now, getSignedData(data), keysA), "Key is valid again"); assertThrows(SignatureValidationException.class, () -> verify( - sigBT0, getSignedData(data), keysB, policy, validationDate), + sigBT0, getSignedData(data), keysB), "Signature predates key creation time"); assertDoesNotThrow(() -> verify( - sigBT1_T2, getSignedData(data), keysB, policy, validationDate), + sigBT1_T2, getSignedData(data), keysB), "Key is valid"); assertThrows(SignatureValidationException.class, () -> verify( - sigBT2_T3, getSignedData(data), keysB, policy, validationDate), + sigBT2_T3, getSignedData(data), keysB), "Primary key is not signing-capable"); assertDoesNotThrow(() -> verify( - sigBT3_now, getSignedData(data), keysB, policy, validationDate), + sigBT3_now, getSignedData(data), keysB), "Key is valid again"); assertThrows(SignatureValidationException.class, () -> verify( - sigCT0, getSignedData(data), keysC, policy, validationDate), + sigCT0, getSignedData(data), keysC), "Signature predates key creation time"); assertDoesNotThrow(() -> verify( - sigCT1_T2, getSignedData(data), keysC, policy, validationDate), + sigCT1_T2, getSignedData(data), keysC), "Key is valid"); assertThrows(SignatureValidationException.class, () -> verify( - sigCT2_T3, getSignedData(data), keysC, policy, validationDate), + sigCT2_T3, getSignedData(data), keysC), "Key is revoked"); assertDoesNotThrow(() -> verify( - sigCT3_now, getSignedData(data), keysC, policy, validationDate), + sigCT3_now, getSignedData(data), keysC), "Key is valid again"); } - private void verify(PGPSignature signature, InputStream dataIn, PGPPublicKeyRing cert, Policy policy, Date validationDate) throws PGPException, IOException { + private void verify(PGPSignature signature, InputStream dataIn, PGPPublicKeyRing cert) throws PGPException, IOException { PGPainless api = PGPainless.getInstance(); OpenPGPCertificate certificate = api.toCertificate(cert); diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt index 6af80060..2c393901 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/SOPImpl.kt @@ -28,6 +28,8 @@ class SOPImpl( private val sopv: SOPV = SOPVImpl(api) ) : SOP { + constructor(api: PGPainless) : this(api, SOPVImpl(api)) + override fun armor(): Armor = ArmorImpl(api) override fun changeKeyPassword(): ChangeKeyPassword = ChangeKeyPasswordImpl(api) diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java index 721c338d..a6096915 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java @@ -123,7 +123,8 @@ public class VerifyLegacySignatureTest { "=TtKx\n" + "-----END PGP MESSAGE-----"; - SOPImpl sop = new SOPImpl(); + PGPainless api = PGPainless.getInstance(); + SOPImpl sop = new SOPImpl(api); byte[] cert = sop.extractCert().key(KEY.getBytes(StandardCharsets.UTF_8)) .getBytes(); ByteArrayAndResult> result = sop.inlineVerify() @@ -134,12 +135,13 @@ public class VerifyLegacySignatureTest { assertFalse(result.getResult().isEmpty()); // Adjust data signature hash policy to accept new SHA-1 sigs - Policy policy = PGPainless.getPolicy(); + Policy policy = api.getAlgorithmPolicy(); Policy adjusted = policy.copy() .withDataSignatureHashAlgorithmPolicy( Policy.HashAlgorithmPolicy.static2022RevocationSignatureHashAlgorithmPolicy() ).build(); - PGPainless.getInstance().setAlgorithmPolicy(adjusted); + api = new PGPainless(adjusted); + sop = new SOPImpl(api); // Sig generated in 2024 using SHA1 String newSig = "-----BEGIN PGP MESSAGE-----\n" + @@ -164,8 +166,5 @@ public class VerifyLegacySignatureTest { .toByteArrayAndResult(); assertFalse(result.getResult().isEmpty()); - - // Reset old policy - PGPainless.getInstance().setAlgorithmPolicy(policy); } }