From 264eb1c8a6ed0a3e07cd0cea3c5faceb884fd89c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 20 Mar 2025 19:25:29 +0100 Subject: [PATCH] Delete SignaturePicker class --- .../signature/consumer/SignaturePicker.kt | 383 ------------------ .../SignatureSubpacketsUtilTest.java | 24 -- 2 files changed, 407 deletions(-) delete mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignaturePicker.kt diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignaturePicker.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignaturePicker.kt deleted file mode 100644 index 5952003e..00000000 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignaturePicker.kt +++ /dev/null @@ -1,383 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.signature.consumer - -import java.util.Date -import org.bouncycastle.openpgp.PGPKeyRing -import org.bouncycastle.openpgp.PGPPublicKey -import org.bouncycastle.openpgp.PGPSignature -import org.pgpainless.algorithm.SignatureType -import org.pgpainless.bouncycastle.extensions.getPublicKeyFor -import org.pgpainless.bouncycastle.extensions.isExpired -import org.pgpainless.bouncycastle.extensions.wasIssuedBy -import org.pgpainless.exception.SignatureValidationException -import org.pgpainless.policy.Policy - -/** - * Pick signatures from keys. - * - * The format of a V4 OpenPGP key is: - * - * Primary-Key [Revocation Self Signature] [Direct Key Signature...] User ID [Signature ...] [User - * ID [Signature ...] ...] [User Attribute [Signature ...] ...] [[Subkey - * [Binding-Signature-Revocation] Primary-Key-Binding-Signature] ...] - */ -class SignaturePicker { - - companion object { - - /** - * Pick the at validation date most recent valid key revocation signature. If there are hard - * revocation signatures, the latest hard revocation sig is picked, even if it was created - * after validationDate or if it is already expired. - * - * @param keyRing key ring - * @param policy policy - * @param referenceTime date of signature validation - * @return most recent, valid key revocation signature - */ - @JvmStatic - fun pickCurrentRevocationSelfSignature( - keyRing: PGPKeyRing, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - return getSortedSignaturesOfType(primaryKey, SignatureType.KEY_REVOCATION).lastOrNull { - return@lastOrNull try { - SignatureVerifier.verifyKeyRevocationSignature( - it, primaryKey, policy, referenceTime) - true // valid - } catch (e: SignatureValidationException) { - false // not valid - } - } - } - - /** - * Pick the at validationDate most recent, valid direct key signature. This method might - * return null, if there is no direct key self-signature which is valid at validationDate. - * - * @param keyRing key ring - * @param policy policy - * @param referenceTime validation date - * @return direct-key self-signature - */ - @JvmStatic - fun pickCurrentDirectKeySelfSignature( - keyRing: PGPKeyRing, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - return pickCurrentDirectKeySignature(primaryKey, primaryKey, policy, referenceTime) - } - - @JvmStatic - fun pickCurrentDirectKeySignature( - signingKey: PGPPublicKey, - signedKey: PGPPublicKey, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - return getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY).lastOrNull { - return@lastOrNull try { - SignatureVerifier.verifyDirectKeySignature( - it, signingKey, signedKey, policy, referenceTime) - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate latest direct key signature. This method might return an - * expired signature. If there are more than one direct-key signature, and some of those are - * not expired, the latest non-expired yet already effective direct-key signature will be - * returned. - * - * @param keyRing key ring - * @param policy policy - * @param referenceTime validation date - * @return latest direct key signature - */ - @JvmStatic - fun pickLatestDirectKeySignature( - keyRing: PGPKeyRing, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - return pickLatestDirectKeySignature( - keyRing.publicKey, keyRing.publicKey, policy, referenceTime) - } - - /** - * Pick the at validationDate latest direct key signature made by signingKey on signedKey. - * This method might return an expired signature. If a non-expired direct-key signature - * exists, the latest non-expired yet already effective direct-key signature will be - * returned. - * - * @param signingKey signing key (key that made the sig) - * @param signedKey signed key (key that carries the sig) - * @param policy policy - * @param referenceTime date of validation - * @return latest direct key sig - */ - @JvmStatic - fun pickLatestDirectKeySignature( - signingKey: PGPPublicKey, - signedKey: PGPPublicKey, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - var latest: PGPSignature? = null - return getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY).lastOrNull { - try { - SignatureValidator.signatureIsOfType(SignatureType.DIRECT_KEY).verify(it) - SignatureValidator.signatureStructureIsAcceptable(signingKey, policy).verify(it) - SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it) - if (latest != null && !latest!!.isExpired(referenceTime)) { - SignatureValidator.signatureIsNotYetExpired(referenceTime).verify(it) - } - SignatureValidator.correctSignatureOverKey(signingKey, signedKey).verify(it) - latest = it - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate most recent, valid user-id revocation signature. If there are - * hard revocation signatures, the latest hard revocation sig is picked, even if it was - * created after validationDate or if it is already expired. - * - * @param keyRing key ring - * @param userId user-Id that gets revoked - * @param policy policy - * @param referenceTime validation date - * @return revocation signature - */ - @JvmStatic - fun pickCurrentUserIdRevocationSignature( - keyRing: PGPKeyRing, - userId: CharSequence, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - return getSortedSignaturesOfType(primaryKey, SignatureType.CERTIFICATION_REVOCATION) - .lastOrNull { - keyRing.getPublicKeyFor(it) - ?: return@lastOrNull false // signature made by external key. skip. - return@lastOrNull try { - SignatureVerifier.verifyUserIdRevocation( - userId.toString(), it, primaryKey, policy, referenceTime) - true - } catch (e: SignatureValidationException) { - false // signature not valid - } - } - } - - /** - * Pick the at validationDate latest, valid certification self-signature for the given - * user-id. This method might return null, if there is no certification self signature for - * that user-id which is valid at validationDate. - * - * @param keyRing keyring - * @param userId userid - * @param policy policy - * @param referenceTime validation date - * @return user-id certification - */ - @JvmStatic - fun pickCurrentUserIdCertificationSignature( - keyRing: PGPKeyRing, - userId: CharSequence, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - return primaryKey - .getSignaturesForID(userId.toString()) - .asSequence() - .sortedWith(SignatureCreationDateComparator()) - .lastOrNull { - return@lastOrNull it.wasIssuedBy(primaryKey) && - try { - SignatureVerifier.verifyUserIdCertification( - userId.toString(), it, primaryKey, policy, referenceTime) - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate latest certification self-signature for the given user-id. - * This method might return an expired signature. If a non-expired user-id certification - * signature exists, the latest non-expired yet already effective user-id certification - * signature for the given user-id will be returned. - * - * @param keyRing keyring - * @param userId userid - * @param policy policy - * @param referenceTime validation date - * @return user-id certification - */ - @JvmStatic - fun pickLatestUserIdCertificationSignature( - keyRing: PGPKeyRing, - userId: CharSequence, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - return primaryKey - .getSignaturesForID(userId.toString()) - .asSequence() - .sortedWith(SignatureCreationDateComparator()) - .lastOrNull { - return@lastOrNull try { - SignatureValidator.wasPossiblyMadeByKey(primaryKey).verify(it) - SignatureValidator.signatureIsCertification().verify(it) - SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy) - .verify(it) - SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it) - SignatureValidator.correctSignatureOverUserId( - userId.toString(), primaryKey, primaryKey) - .verify(it) - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate most recent, valid subkey revocation signature. If there are - * hard revocation signatures, the latest hard revocation sig is picked, even if it was - * created after validationDate or if it is already expired. - * - * @param keyRing keyring - * @param subkey subkey - * @param policy policy - * @param referenceTime validation date - * @return subkey revocation signature - */ - @JvmStatic - fun pickCurrentSubkeyBindingRevocationSignature( - keyRing: PGPKeyRing, - subkey: PGPPublicKey, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - require(primaryKey.keyID != subkey.keyID) { - "Primary key cannot have subkey binding revocations." - } - return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_REVOCATION).lastOrNull { - return@lastOrNull try { - SignatureVerifier.verifySubkeyBindingRevocation( - it, primaryKey, subkey, policy, referenceTime) - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate latest, valid subkey binding signature for the given subkey. - * This method might return null, if there is no subkey binding signature which is valid at - * validationDate. - * - * @param keyRing key ring - * @param subkey subkey - * @param policy policy - * @param referenceTime date of validation - * @return most recent valid subkey binding signature - */ - @JvmStatic - fun pickCurrentSubkeyBindingSignature( - keyRing: PGPKeyRing, - subkey: PGPPublicKey, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - require(primaryKey.keyID != subkey.keyID) { - "Primary key cannot have subkey binding signatures." - } - return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING).lastOrNull { - return@lastOrNull try { - SignatureVerifier.verifySubkeyBindingSignature( - it, primaryKey, subkey, policy, referenceTime) - true - } catch (e: SignatureValidationException) { - false - } - } - } - - /** - * Pick the at validationDate latest subkey binding signature for the given subkey. This - * method might return an expired signature. If a non-expired subkey binding signature - * exists, the latest non-expired yet already effective subkey binding signature for the - * given subkey will be returned. - * - * @param keyRing key ring - * @param subkey subkey - * @param policy policy - * @param referenceTime validationDate - * @return subkey binding signature - */ - @JvmStatic - fun pickLatestSubkeyBindingSignature( - keyRing: PGPKeyRing, - subkey: PGPPublicKey, - policy: Policy, - referenceTime: Date - ): PGPSignature? { - val primaryKey = keyRing.publicKey - require(primaryKey.keyID != subkey.keyID) { - "Primary key cannot have subkey binding signatures." - } - var latest: PGPSignature? = null - return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING).lastOrNull { - return@lastOrNull try { - SignatureValidator.signatureIsOfType(SignatureType.SUBKEY_BINDING).verify(it) - SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy).verify(it) - SignatureValidator.signatureDoesNotPredateSignee(subkey).verify(it) - SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it) - // if the currently latest signature is not yet expired, check if the next - // candidate is not yet expired - if (latest != null && !latest!!.isExpired(referenceTime)) { - SignatureValidator.signatureIsNotYetExpired(referenceTime).verify(it) - } - SignatureValidator.correctSubkeyBindingSignature(primaryKey, subkey).verify(it) - latest = it - true - } catch (e: SignatureValidationException) { - false - } - } - } - - @JvmStatic - private fun getSortedSignaturesOfType( - key: PGPPublicKey, - type: SignatureType - ): List = - key.getSignaturesOfType(type.code) - .asSequence() - .sortedWith(SignatureCreationDateComparator()) - .toList() - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureSubpacketsUtilTest.java b/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureSubpacketsUtilTest.java index a377ed82..475aa8c6 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureSubpacketsUtilTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/signature/SignatureSubpacketsUtilTest.java @@ -9,13 +9,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; -import java.time.temporal.ChronoUnit; import java.util.Arrays; -import java.util.Date; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; @@ -32,11 +29,9 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPImplementation; import org.bouncycastle.openpgp.api.OpenPGPKey; import org.junit.jupiter.api.Test; -import org.pgpainless.PGPainless; import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.Feature; import org.pgpainless.algorithm.HashAlgorithm; @@ -44,29 +39,10 @@ import org.pgpainless.algorithm.SignatureType; import org.pgpainless.key.TestKeys; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnlockSecretKey; -import org.pgpainless.signature.consumer.SignaturePicker; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; public class SignatureSubpacketsUtilTest { - @Test - public void testGetKeyExpirationTimeAsDate() { - PGPainless api = PGPainless.getInstance(); - OpenPGPKey secretKeys = api.generateKey() - .modernKeyRing("Expire"); - Date expiration = Date.from(new Date().toInstant().plus(365, ChronoUnit.DAYS)); - secretKeys = api.modify(secretKeys) - .setExpirationDate(expiration, SecretKeyRingProtector.unprotectedKeys()) - .done(); - - PGPSignature expirationSig = SignaturePicker.pickCurrentUserIdCertificationSignature( - secretKeys.getPGPSecretKeyRing(), "Expire", api.getAlgorithmPolicy(), new Date()); - OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = api.inspect(secretKeys).getSigningSubkeys().get(0); - - assertThrows(IllegalArgumentException.class, () -> - SignatureSubpacketsUtil.getKeyExpirationTimeAsDate(expirationSig, notTheRightKey.getPGPPublicKey())); - } - @Test public void testGetRevocable() throws PGPException, IOException { OpenPGPKey secretKeys = TestKeys.getEmilKey();