From 1379942c07421ae3e3ff3a721198a76fcdd0cb8c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 24 Feb 2025 12:33:04 +0100 Subject: [PATCH] Migrate from MissingPublicKeyCallback to OpenPGPCertifcateProvider --- .../ConsumerOptions.kt | 12 ++++---- .../MissingPublicKeyCallback.kt | 28 ------------------- .../OpenPgpMessageInputStream.kt | 6 ++-- ...erifyWithMissingPublicKeyCallbackTest.java | 11 ++++---- 4 files changed, 15 insertions(+), 42 deletions(-) delete mode 100644 pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt index 9e85d71d..55c781ae 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/ConsumerOptions.kt @@ -12,6 +12,7 @@ import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.api.OpenPGPCertificate import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.bouncycastle.openpgp.api.OpenPGPKey +import org.bouncycastle.openpgp.api.OpenPGPKeyMaterialProvider.OpenPGPCertificateProvider import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory import org.pgpainless.PGPainless @@ -34,7 +35,7 @@ class ConsumerOptions { private val certificates = CertificateSource() private val detachedSignatures = mutableSetOf() - private var missingCertificateCallback: MissingPublicKeyCallback? = null + private var missingCertificateCallback: OpenPGPCertificateProvider? = null private var sessionKey: SessionKey? = null private val customDecryptorFactories = @@ -164,9 +165,10 @@ class ConsumerOptions { * @param callback callback * @return options */ - fun setMissingCertificateCallback(callback: MissingPublicKeyCallback): ConsumerOptions = apply { - this.missingCertificateCallback = callback - } + fun setMissingCertificateCallback(callback: OpenPGPCertificateProvider): ConsumerOptions = + apply { + this.missingCertificateCallback = callback + } /** * Attempt decryption using a session key. @@ -283,7 +285,7 @@ class ConsumerOptions { * * @return missing public key callback */ - fun getMissingCertificateCallback(): MissingPublicKeyCallback? = missingCertificateCallback + fun getMissingCertificateCallback(): OpenPGPCertificateProvider? = missingCertificateCallback /** * Return the [SecretKeyRingProtector] for the given [PGPSecretKeyRing]. diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt deleted file mode 100644 index 9da5eb06..00000000 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MissingPublicKeyCallback.kt +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.decryption_verification - -import org.bouncycastle.bcpg.KeyIdentifier -import org.bouncycastle.openpgp.api.OpenPGPCertificate - -fun interface MissingPublicKeyCallback { - - /** - * This method gets called if we encounter a signature made by a key which was not provided for - * signature verification. If you cannot provide the requested key, it is safe to return null - * here. PGPainless will then continue verification with the next signature. - * - * Note: The key-id might belong to a subkey, so be aware that when looking up the - * [OpenPGPCertificate], you may not only search for the key-id on the key rings primary key! - * - * It would be super cool to provide the OpenPgp fingerprint here, but unfortunately - * one-pass-signatures only contain the key id. - * - * @param keyIdentifier ID of the missing signing (sub)key - * @return keyring containing the key or null - * @see RFC - */ - fun onMissingPublicKeyEncountered(keyIdentifier: KeyIdentifier): OpenPGPCertificate? -} 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 422fc25a..680344ca 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 @@ -912,7 +912,7 @@ class OpenPgpMessageInputStream( if (options.getMissingCertificateCallback() != null) { return options .getMissingCertificateCallback()!! - .onMissingPublicKeyEncountered(signature.keyIdentifiers.first()) + .provide(signature.keyIdentifiers.first()) } return null // TODO: Missing cert for sig } @@ -924,9 +924,7 @@ class OpenPgpMessageInputStream( } if (options.getMissingCertificateCallback() != null) { - return options - .getMissingCertificateCallback()!! - .onMissingPublicKeyEncountered(signature.keyIdentifier) + return options.getMissingCertificateCallback()!!.provide(signature.keyIdentifier) } return null // TODO: Missing cert for sig } diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java index 3bc2c5f0..c8112cfa 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/VerifyWithMissingPublicKeyCallbackTest.java @@ -18,6 +18,7 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyMaterialProvider; import org.bouncycastle.util.io.Streams; import org.junit.jupiter.api.Test; import org.pgpainless.PGPainless; @@ -32,9 +33,9 @@ import org.pgpainless.key.protection.SecretKeyRingProtector; import javax.annotation.Nonnull; /** - * Test functionality of the {@link MissingPublicKeyCallback} which is called when during signature verification, - * a signature is encountered which was made by a key that was not provided in - * {@link ConsumerOptions#addVerificationCert(PGPPublicKeyRing)}. + * Test functionality of the {@link org.bouncycastle.openpgp.api.OpenPGPKeyMaterialProvider.OpenPGPCertificateProvider} + * which is called when during signature verification, a signature is encountered which was made by a key that was + * not provided in {@link ConsumerOptions#addVerificationCert(PGPPublicKeyRing)}. */ public class VerifyWithMissingPublicKeyCallbackTest { @@ -63,9 +64,9 @@ public class VerifyWithMissingPublicKeyCallbackTest { .onInputStream(new ByteArrayInputStream(signOut.toByteArray())) .withOptions(new ConsumerOptions() .addVerificationCert(unrelatedKeys) - .setMissingCertificateCallback(new MissingPublicKeyCallback() { + .setMissingCertificateCallback(new OpenPGPKeyMaterialProvider.OpenPGPCertificateProvider() { @Override - public OpenPGPCertificate onMissingPublicKeyEncountered(@Nonnull KeyIdentifier keyIdentifier) { + public OpenPGPCertificate provide(@Nonnull KeyIdentifier keyIdentifier) { assertEquals(signingKey.getKeyIdentifier(), keyIdentifier, "Signing key-ID mismatch."); return signingPubKeys; }