diff --git a/pgpainless-core/src/main/kotlin/org/bouncycastle/extensions/PGPKeyRingExtensions.kt b/pgpainless-core/src/main/kotlin/org/bouncycastle/extensions/PGPKeyRingExtensions.kt new file mode 100644 index 00000000..43669bd1 --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/bouncycastle/extensions/PGPKeyRingExtensions.kt @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.bouncycastle.extensions + +import org.bouncycastle.openpgp.PGPKeyRing +import org.pgpainless.key.SubkeyIdentifier + +/** + * Return true, if this [PGPKeyRing] contains the subkey identified by the [SubkeyIdentifier]. + */ +fun PGPKeyRing.matches(subkeyIdentifier: SubkeyIdentifier): Boolean = + this.publicKey.keyID == subkeyIdentifier.primaryKeyId && + this.getPublicKey(subkeyIdentifier.subkeyId) != null \ No newline at end of file diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt index 8719cef7..3eb49e5d 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/MessageMetadata.kt @@ -4,6 +4,7 @@ package org.pgpainless.decryption_verification +import org.bouncycastle.extensions.matches import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPLiteralData import org.pgpainless.algorithm.CompressionAlgorithm @@ -227,10 +228,9 @@ class MessageMetadata( */ @JvmOverloads fun isAuthenticatablySignedBy(userId: String, email: Boolean, certificateAuthority: CertificateAuthority, targetAmount: Int = 120): Boolean { - return verifiedSignatures.any { - certificateAuthority.authenticateBinding( - it.signingKey.fingerprint, userId, email, it.signature.creationTime, targetAmount - ).authenticated + return verifiedSignatures.any { certificateAuthority + .authenticateBinding(it.signingKey.fingerprint, userId, email, it.signature.creationTime, targetAmount) + .authenticated } } @@ -241,31 +241,23 @@ class MessageMetadata( * @param fingerprint fingerprint * @return true if message was signed by a cert identified by the given fingerprint */ - fun isVerifiedSignedBy(fingerprint: OpenPgpFingerprint) = verifiedSignatures.any { - it.signingKey.primaryKeyFingerprint == fingerprint || it.signingKey.subkeyFingerprint == fingerprint - } + fun isVerifiedSignedBy(fingerprint: OpenPgpFingerprint) = + verifiedSignatures.any { it.signingKey.matches(fingerprint) } - fun isVerifiedSignedBy(keys: PGPKeyRing) = containsSignatureBy(verifiedSignatures, keys) + fun isVerifiedSignedBy(keys: PGPKeyRing) = + verifiedSignatures.any { keys.matches(it.signingKey) } - fun isVerifiedDetachedSignedBy(fingerprint: OpenPgpFingerprint) = verifiedDetachedSignatures.any { - it.signingKey.primaryKeyFingerprint == fingerprint || it.signingKey.subkeyFingerprint == fingerprint - } + fun isVerifiedDetachedSignedBy(fingerprint: OpenPgpFingerprint) = + verifiedDetachedSignatures.any { it.signingKey.matches(fingerprint) } - fun isVerifiedDetachedSignedBy(keys: PGPKeyRing) = containsSignatureBy(verifiedDetachedSignatures, keys) + fun isVerifiedDetachedSignedBy(keys: PGPKeyRing) = + verifiedDetachedSignatures.any { keys.matches(it.signingKey) } - fun isVerifiedInlineSignedBy(fingerprint: OpenPgpFingerprint) = verifiedInlineSignatures.any { - it.signingKey.primaryKeyFingerprint == fingerprint || it.signingKey.subkeyFingerprint == fingerprint - } + fun isVerifiedInlineSignedBy(fingerprint: OpenPgpFingerprint) = + verifiedInlineSignatures.any { it.signingKey.matches(fingerprint) } - fun isVerifiedInlineSignedBy(keys: PGPKeyRing) = containsSignatureBy(verifiedInlineSignatures, keys) - - private fun containsSignatureBy(signatures: List, keys: PGPKeyRing) = - signatures.any { - // Match certificate by primary key id - keys.publicKey.keyID == it.signingKey.primaryKeyId && - // match signing subkey - keys.getPublicKey(it.signingKey.subkeyId) != null - } + fun isVerifiedInlineSignedBy(keys: PGPKeyRing) = + verifiedInlineSignatures.any { keys.matches(it.signingKey) } // ################################################################################################################ // ### Literal Data ### diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/EncryptionResult.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/EncryptionResult.kt index fd9febc7..0e9a40c9 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/EncryptionResult.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/EncryptionResult.kt @@ -4,6 +4,7 @@ package org.pgpainless.encryption_signing +import org.bouncycastle.extensions.matches import org.bouncycastle.openpgp.PGPLiteralData import org.bouncycastle.openpgp.PGPPublicKeyRing import org.bouncycastle.openpgp.PGPSignature @@ -39,10 +40,7 @@ data class EncryptionResult( * @param certificate certificate * @return true if encrypted for 1+ subkeys, false otherwise. */ - fun isEncryptedFor(certificate: PGPPublicKeyRing) = recipients.any { - certificate.publicKey.keyID == it.primaryKeyId && - certificate.getPublicKey(it.subkeyId) != null - } + fun isEncryptedFor(certificate: PGPPublicKeyRing) = recipients.any { certificate.matches(it) } companion object { /** diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt index ea36913c..58e7719c 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt @@ -31,6 +31,9 @@ class SubkeyIdentifier( val subkeyId = subkeyFingerprint.keyId val primaryKeyId = primaryKeyFingerprint.keyId + fun matches(fingerprint: OpenPgpFingerprint) = + primaryKeyFingerprint == fingerprint || subkeyFingerprint == fingerprint + override fun equals(other: Any?): Boolean { if (other == null) { return false