From a23f2c4401a218ffaef18c3cbdaed13f5305f004 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 28 May 2021 22:21:03 +0200 Subject: [PATCH] Delete SelectSignatureFromKey class --- .../signature/SelectSignatureFromKey.java | 594 ------------------ .../pgpainless/signature/SignatureUtils.java | 1 - .../signature/SelectSignatureFromKeyTest.java | 174 ----- 3 files changed, 769 deletions(-) delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/signature/SelectSignatureFromKey.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/util/selection/signature/SelectSignatureFromKeyTest.java diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/SelectSignatureFromKey.java b/pgpainless-core/src/main/java/org/pgpainless/signature/SelectSignatureFromKey.java deleted file mode 100644 index e8a3a207..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/SelectSignatureFromKey.java +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright 2021 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.signature; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyRing; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureList; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.algorithm.SignatureType; -import org.pgpainless.implementation.ImplementationFactory; -import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; - -/** - * Utility class to select signatures from keys based on certain criteria. - * This abstract class provides a method {@link #accept(PGPSignature, PGPPublicKey, PGPKeyRing)} which shall only - * return true if the provided signature is acceptable regarding the implementations selection criteria. - * - * The idea is to create an implementation of the class for each criterion, so that those criteria can be - * composed to create complex validity checks. - */ -public abstract class SelectSignatureFromKey { - - private static final Logger LOGGER = Logger.getLogger(SelectSignatureFromKey.class.getName()); - - public abstract boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing); - - public List select(List signatures, PGPPublicKey key, PGPKeyRing keyRing) { - List selected = new ArrayList<>(); - for (PGPSignature signature : signatures) { - if (accept(signature, key, keyRing)) { - selected.add(signature); - } - } - return selected; - } - - /** - * Criterion that checks if the signature is valid at the validation date. - * A signature is not valid if it was created after the validation date, or if it is expired at the validation date. - * - * creationTime ≤ validationDate < expirationDate. - * - * @param validationDate validation date - * @return criterion implementation - */ - public static SelectSignatureFromKey isValidAt(Date validationDate) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - Date expirationDate = SignatureUtils.getSignatureExpirationDate(signature); - return !signature.getCreationTime().after(validationDate) && (expirationDate == null || expirationDate.after(validationDate)); - } - }; - } - - /** - * Criterion that checks if the provided signature is a valid subkey binding signature. - * - * A signature is only a valid subkey binding signature if it is of type {@link SignatureType#SUBKEY_BINDING}, - * if it was created by the primary key, and - if the subkey is capable of signing - it contains a valid - * primary key binding signature. - * - * @param primaryKey primary key - * @param subkey subkey - * @return criterion to validate binding signatures - */ - public static SelectSignatureFromKey isValidSubkeyBindingSignature(PGPPublicKey primaryKey, PGPPublicKey subkey) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - - if (!isOfType(SignatureType.SUBKEY_BINDING).accept(signature, key, keyRing)) { - return false; - } - - if (signature.getKeyID() != primaryKey.getKeyID()) { - return false; - } - - if (!isSigNotExpired().accept(signature, subkey, keyRing)) { - LOGGER.log(Level.INFO, "Subkey binding signature expired."); - return false; - } - - // Check signature correctness - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), primaryKey); - boolean subkeyBindingSigValid = signature.verifyCertification(primaryKey, subkey); - if (!subkeyBindingSigValid) { - return false; - } - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Verification of subkey binding signature failed.", e); - return false; - } - - List flags = KeyFlag.fromBitmask(signature.getHashedSubPackets().getKeyFlags()); - boolean isSigningKey = flags.contains(KeyFlag.SIGN_DATA) || flags.contains(KeyFlag.CERTIFY_OTHER); - - if (isSigningKey && !hasValidPrimaryKeyBindingSignatureSubpacket(subkey, primaryKey) - .accept(signature, subkey, keyRing)) { - LOGGER.log(Level.INFO, "Subkey binding signature on signing key does not carry valid primary key binding signature."); - return false; - } - return true; - } - }; - } - - /** - * Criterion that checks if a primary key binding signature is valid. - * - * @param subkey subkey - * @param primaryKey primary key - * @return criterion to validate primary key binding signatures - */ - public static SelectSignatureFromKey isValidPrimaryKeyBindingSignature(PGPPublicKey subkey, PGPPublicKey primaryKey) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - - if (!isVersion4Signature().accept(signature, key, keyRing)) { - return false; - } - - if (!isOfType(SignatureType.PRIMARYKEY_BINDING).accept(signature, key, keyRing)) { - return false; - } - - if (signature.getKeyID() != subkey.getKeyID()) { - return false; - } - - if (!isSigNotExpired().accept(signature, primaryKey, keyRing)) { - LOGGER.log(Level.INFO, "Primary key binding signature expired."); - return false; - } - - // Check signature correctness - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), subkey); - return signature.verifyCertification(primaryKey, subkey); - } catch (PGPException e) { - return false; - } - } - }; - } - - /** - * Criterion that checks if a signature has an embedded valid primary key binding signature. - * @param subkey subkey - * @param primaryKey primary key - * @return criterion - */ - public static SelectSignatureFromKey hasValidPrimaryKeyBindingSignatureSubpacket(PGPPublicKey subkey, PGPPublicKey primaryKey) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - try { - PGPSignatureList embeddedSignatures = SignatureSubpacketsUtil.getEmbeddedSignature(signature); - if (embeddedSignatures != null) { - for (PGPSignature embeddedSignature : embeddedSignatures) { - if (isValidPrimaryKeyBindingSignature(subkey, primaryKey).accept(embeddedSignature, subkey, keyRing)) { - return true; - } - } - } - } catch (PGPException e) { - LOGGER.log(Level.WARNING, "Cannot parse embedded signatures:", e); - } - return false; - } - }; - } - - /** - * Criterion that checks if a signature is a valid v4 direct-key signature. - * Note: This method does not check expiration. - * - * @param signer signing key - * @param signee signed key - * @return criterion - */ - public static SelectSignatureFromKey isValidDirectKeySignature(PGPPublicKey signer, PGPPublicKey signee) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - if (!isVersion4Signature().accept(signature, key, keyRing)) { - return false; - } - - if (!isOfType(SignatureType.DIRECT_KEY).accept(signature, key, keyRing)) { - return false; - } - - // Check signature correctness - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), signer); - return signature.verifyCertification(signee); - } catch (PGPException e) { - return false; - } - } - }; - } - - /** - * Criterion that checks if a signature is a valid key revocation signature. - * - * @param key primary key - * @return criterion - */ - public static SelectSignatureFromKey isValidKeyRevocationSignature(PGPPublicKey key) { - return and( - isVersion4Signature(), - isOfType(SignatureType.KEY_REVOCATION), - isCreatedBy(key), - isWellFormed(), - doesNotPredateKeyCreationDate(key), - isVerifyingSignatureOnKey(key, key) - ); - } - - /** - * Criterion that only accepts valid subkey revocation signatures. - * - * @return criterion - */ - public static SelectSignatureFromKey isValidSubkeyRevocationSignature() { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return isValidSubkeyRevocationSignature(key, keyRing.getPublicKey()) - .accept(signature, key, keyRing); - } - }; - } - - /** - * Criterion that only accepts valid subkey revocation signatures. - * - * @param subkey subkey - * @param primaryKey primary key - * @return criterion - */ - public static SelectSignatureFromKey isValidSubkeyRevocationSignature(PGPPublicKey subkey, PGPPublicKey primaryKey) { - return SelectSignatureFromKey.and( - isVersion4Signature(), - isOfType(SignatureType.SUBKEY_REVOCATION), - isCreatedBy(primaryKey), - isVerifyingSignatureOnKeys(primaryKey, subkey, primaryKey) - ); - } - - /** - * Criterion that only accepts signatures which are valid user-id revocations. - * - * @param revoker signing key - * @param userId user id - * @return criterion - */ - public static SelectSignatureFromKey isValidCertificationRevocationSignature(PGPPublicKey revoker, String userId) { - return and( - isVersion4Signature(), - isCreatedBy(revoker), - isOfType(SignatureType.CERTIFICATION_REVOCATION), - isValidSignatureOnUserId(userId, revoker) - ); - } - - /** - * Criterion that only accepts signatures which are valid signatures over a user-id. - * This method only checks signature correctness, not expiry etc. - * - * @param userId user-id - * @param signingKey signing key - * @return criterion - */ - public static SelectSignatureFromKey isValidSignatureOnUserId(String userId, PGPPublicKey signingKey) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), signingKey); - return signature.verifyCertification(userId, key); - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Verification of signature on userID " + userId + " failed.", e); - return false; - } - } - }; - } - - /** - * Criterion that only accepts signatures which are valid signatures over a key. - * This method only checks signature correctness, not expiry etc. - * - * @param target signed key - * @param signer signing key - * @return criterion - */ - public static SelectSignatureFromKey isVerifyingSignatureOnKey(PGPPublicKey target, PGPPublicKey signer) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), signer); - boolean valid = signature.verifyCertification(target); - return valid; - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Signature verification failed.", e); - return false; - } - } - }; - } - - /** - * Criterion that only accepts signatures which are correct binding signatures. - * This method only checks signature correctness, not expiry etc. - * - * @param primaryKey primary key - * @param subkey subkey - * @param signingKey signing key (either primary, or subkey) - * @return criterion - */ - public static SelectSignatureFromKey isVerifyingSignatureOnKeys(PGPPublicKey primaryKey, PGPPublicKey subkey, PGPPublicKey signingKey) { - if (signingKey.getKeyID() != primaryKey.getKeyID() && signingKey.getKeyID() != subkey.getKeyID()) { - throw new IllegalArgumentException("Signing key MUST be either the primary or subkey."); - } - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - try { - signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), signingKey); - return signature.verifyCertification(primaryKey, subkey); - } catch (PGPException e) { - LOGGER.log(Level.INFO, "Verification of " + SignatureType.valueOf(signature.getSignatureType()) + " signature failed.", e); - return false; - } - } - }; - } - - /** - * Criterion that only accepts certification signatures. - * - * Those are signature of the following types: - * - {@link SignatureType#NO_CERTIFICATION}, - * - {@link SignatureType#CASUAL_CERTIFICATION}, - * - {@link SignatureType#GENERIC_CERTIFICATION}, - * - {@link SignatureType#POSITIVE_CERTIFICATION}. - * - * @return criterion - */ - public static SelectSignatureFromKey isCertification() { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return signature.isCertification(); - } - }; - } - - /** - * Criterion that only accepts "well formed" signatures. - * A signature is "well formed", iff it has a creation time subpacket and if it does not predate - * its creating keys creation time. - * - * @return criterion - */ - public static SelectSignatureFromKey isWellFormed() { - return and( - hasCreationTimeSubpacket(), - doesNotPredateKeyCreationDate() - ); - } - - /** - * Criterion that only accepts v4 signatures. - * - * @return criterion - */ - public static SelectSignatureFromKey isVersion4Signature() { - return isVersion(4); - } - - /** - * Criterion that only accepts signatures which carry a creation time subpacket. - * According to the RFC, all signatures are required to have such a subpacket. - * - * @return criterion - */ - public static SelectSignatureFromKey hasCreationTimeSubpacket() { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return signature.getHashedSubPackets().getSignatureCreationTime() != null; - } - }; - } - - /** - * Criterion that only accepts signatures that were created by the provided key. - * - * @param publicKey public key of the creation key pair - * @return criterion - */ - public static SelectSignatureFromKey isCreatedBy(PGPPublicKey publicKey) { - return isCreatedBy(publicKey.getKeyID()); - } - - /** - * Criterion that only accepts signatures which were created by the public key with the provided key id. - * - * @param keyId key id - * @return criterion - */ - public static SelectSignatureFromKey isCreatedBy(long keyId) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return signature.getKeyID() == keyId; - } - }; - } - - /** - * Criterion that only accepts signatures which are not expired RIGHT NOW. - * - * @return criterion - */ - public static SelectSignatureFromKey isSigNotExpired() { - return isSigNotExpired(new Date()); - } - - /** - * Criterion that only accepts signatures which are not expired at comparisonDate. - * - * @param comparisonDate comparison date - * @return criterion - */ - public static SelectSignatureFromKey isSigNotExpired(Date comparisonDate) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return !SignatureUtils.isSignatureExpired(signature, comparisonDate); - } - }; - } - - /** - * Criterion that only accepts signatures which do not predate their signing key's creation date. - * - * @return criterion - */ - public static SelectSignatureFromKey doesNotPredateKeyCreationDate() { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - PGPPublicKey creator = keyRing.getPublicKey(signature.getKeyID()); - if (creator == null) { - return false; - } - return doesNotPredateKeyCreationDate(creator).accept(signature, key, keyRing); - } - }; - } - - /** - * Criterion that only accepts signatures which do not predate the creation date of the provided key. - * - * @param creator key - * @return criterion - */ - public static SelectSignatureFromKey doesNotPredateKeyCreationDate(PGPPublicKey creator) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return !signature.getCreationTime().before(creator.getCreationTime()); - } - }; - } - - /** - * Criterion that only accepts signatures of the provided signature version. - * - * @param version signature version - * @return criterion - */ - public static SelectSignatureFromKey isVersion(int version) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return signature.getVersion() == version; - } - }; - } - - /** - * Criterion that only accepts signatures that are of the provided {@link SignatureType}. - * - * @param signatureType signature type that shall be accepted - * @return criterion - */ - public static SelectSignatureFromKey isOfType(SignatureType signatureType) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return signature.getSignatureType() == signatureType.getCode(); - } - }; - } - - /** - * Compose different {@link SelectSignatureFromKey} by combining them with a logic AND. - * A signature will only be accepted, iff it satisfies every selector from selectors. - * - * @param selectors one or more selectors - * @return combined selector using AND operator - */ - public static SelectSignatureFromKey and(SelectSignatureFromKey... selectors) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - for (SelectSignatureFromKey selector : selectors) { - if (!selector.accept(signature, key, keyRing)) { - return false; - } - } - return true; - } - }; - } - - /** - * Compose different {@link SelectSignatureFromKey} by combining them with a logic OR. - * A signature will only be accepted, iff it satisfies at least one selector from selectors. - * - * @param selectors one or more selectors - * @return combined selector using OR operator - */ - public static SelectSignatureFromKey or(SelectSignatureFromKey... selectors) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - boolean accept = false; - for (SelectSignatureFromKey selector : selectors) { - accept |= selector.accept(signature, key, keyRing); - } - return accept; - } - }; - } - - /** - * Negate the result of a {@link SelectSignatureFromKey} implementations {@link #accept(PGPSignature, PGPPublicKey, PGPKeyRing)}. - * The resulting {@link SelectSignatureFromKey} will only accept signatures that are rejected by the provided selector - * and reject those that are accepted by it. - * - * @param selector selector whose logic operation will be negated - * @return negated selector - */ - public static SelectSignatureFromKey not(SelectSignatureFromKey selector) { - return new SelectSignatureFromKey() { - @Override - public boolean accept(PGPSignature signature, PGPPublicKey key, PGPKeyRing keyRing) { - return !selector.accept(signature, key, keyRing); - } - }; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/signature/SignatureUtils.java b/pgpainless-core/src/main/java/org/pgpainless/signature/SignatureUtils.java index 019727b1..60a93acc 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/signature/SignatureUtils.java +++ b/pgpainless-core/src/main/java/org/pgpainless/signature/SignatureUtils.java @@ -147,7 +147,6 @@ public class SignatureUtils { /** * Return true, iff a signature is valid. * - * TODO: There is code duplication here ({@link SelectSignatureFromKey}, {@link SignatureChainValidator}, {@link SignatureValidator}). * @param signature signature to validate * @param issuer signing key * @param target signed key diff --git a/pgpainless-core/src/test/java/org/pgpainless/util/selection/signature/SelectSignatureFromKeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/util/selection/signature/SelectSignatureFromKeyTest.java deleted file mode 100644 index 2ece0158..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/util/selection/signature/SelectSignatureFromKeyTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2021 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.util.selection.signature; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.util.Iterator; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.junit.jupiter.api.Test; -import org.pgpainless.PGPainless; -import org.pgpainless.signature.SelectSignatureFromKey; - -public class SelectSignatureFromKeyTest { - - @Test - public void validKeyTest() throws IOException { - String key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "\n" + - "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\n" + - "Db7pzk2vugYKrebvskFQaq0S8TwhHQ4n9GVrUnenFf2OAWYfRYmYbENUv+fQm22+\n" + - "EOxHWSVwB3NWl8albQxs/aPCi3nuPdtdTMU2fHLGDAZ9MGQesb/0tSJLWaqQRvqT\n" + - "k3llI1OqxGbYLaNXSz6nJDLsKK9v+6lFzxA5C8OOxGikHE7b9RJ6SGVNijItXtHo\n" + - "rVuAKayDfMKO+0jc25I+agMbfg6p4Ik5D+1LFzZtsSc6Ib6AKu+FLit6Ik74/nrr\n" + - "/ORSAoTpxnIyJlBu4DS3AUwRd/O7rke8FNVg6EpzaPazrqfY1eZ2YelEE4EO3xXm\n" + - "wcOLSPVwsLNoC3DdRRLtw5EItZy2z0QiARF+NsUYQQM5RCrQizxuzD5+nXg1AcaE\n" + - "ixnbju8StB8jT1m4ccJKHsObgi/cIPPsWm5+BUhV9RDLsMWnaVZ8f3tRAHy2TAld\n" + - "FiEE0aZuGiOxgsmYD3iM+/zIKgFeczAAAAv/DACScy69f/qohzub6e06b3sgmL1K\n" + - "foCMmFRAiEsDHUHunAb/KWBqkbJ8W6wP0COwh4tbmjUzwexMQyI4m58SLRYULcJ7\n" + - "kj3axMV0+JJyFoqUpCT06GpqQQIhZY7Y+AHz9FdVNEDjjUwb3mODx8zVyEg57T9C\n" + - "TfuLrrJDYpycfNJtxYy9qSMPHBiVGqlzqnyETOa312QquZuY6ucfTL8i8kXk5qtL\n" + - "jVHTnKogzrbTCWuKR8fzsxfZ9afdYXI3SMMsip4Ixx2mLM5tN9IeDI/DQnWetwB2\n" + - "Z0PEs7UcYcrn6UWs1X4P7jOmtLH+0d96I9ljd9SSmJ9dTr2cV62J/qtK+75hCBk8\n" + - "Lz+MNWzyAU3sVqGRhsBaLOqvb7K9p3bm6brEmGpBLeKrxuxjBER+7knqkTxSsb+S\n" + - "msO3lGrEnNEQIlcvoxLIGQiv9b0sblGM9lr40C0D84PEvajhuFAUTItoPfCIVVaT\n" + - "7Ry8/ZA6t0uQh9/B0hYblb07mJ92hCacoTx+APM=\n" + - "=yeYe\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - - PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(key); - Iterator keyIt = publicKeys.getPublicKeys(); - PGPPublicKey primaryKey = publicKeys.getPublicKey(); - while (keyIt.hasNext()) { - PGPPublicKey publicKey = keyIt.next(); - if (publicKey == primaryKey) { - continue; - } - - boolean validBinding = false; - Iterator signatures = publicKey.getSignatures(); - while (signatures.hasNext()) { - PGPSignature signature = signatures.next(); - if (SelectSignatureFromKey.isValidSubkeyBindingSignature(primaryKey, publicKey).accept(signature, publicKey, publicKeys)) { - validBinding = true; - } - } - assertTrue(validBinding); - } - } - - @Test - public void missingBackSigTest() throws IOException { - String key = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "\n" + - "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\n" + - "=uSRw\n" + - "-----END PGP PUBLIC KEY BLOCK-----\n"; - PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(key); - Iterator keyIt = publicKeys.getPublicKeys(); - PGPPublicKey primaryKey = publicKeys.getPublicKey(); - while (keyIt.hasNext()) { - PGPPublicKey publicKey = keyIt.next(); - if (publicKey == primaryKey) { - continue; - } - - Iterator signatures = publicKey.getSignatures(); - while (signatures.hasNext()) { - PGPSignature signature = signatures.next(); - if (SelectSignatureFromKey.isValidSubkeyBindingSignature(primaryKey, publicKey).accept(signature, publicKey, publicKeys)) { - fail("Implementation MUST NOT accept this subkey as bound valid since the backsig is missing."); - } - } - } - } -}