From bc6513b6c73cab73472926d4dd3202bbef2976b3 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 26 Feb 2025 14:59:39 +0100 Subject: [PATCH] Complete migration of KeyRingInfo to KeyIdentifier, javadoc --- .../org/pgpainless/key/info/KeyRingInfo.kt | 242 +++++++++++++----- 1 file changed, 185 insertions(+), 57 deletions(-) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt index 80e3f6c9..f7d873d0 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt @@ -6,7 +6,6 @@ package org.pgpainless.key.info import java.util.* import kotlin.NoSuchElementException -import openpgp.openPgpKeyId import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.api.OpenPGPCertificate @@ -232,6 +231,14 @@ class KeyRingInfo( val isUsableForSigning: Boolean = isSigningCapable && signingSubkeys.any { isSecretKeyAvailable(it.keyIdentifier) } + /** + * True, if the [OpenPGPCertificate] can be used to certify other + * [OpenPGPCertificates][OpenPGPCertificate]. + */ + val isUsableForThirdPartyCertification: Boolean = + isKeyValidlyBound(keyIdentifier) && + getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER) + /** [HashAlgorithm] preferences of the primary user-ID or if absent, of the primary key. */ val preferredHashAlgorithms: Set get() = @@ -252,6 +259,7 @@ class KeyRingInfo( primaryUserId?.let { getPreferredCompressionAlgorithms(it) } ?: getPreferredCompressionAlgorithms(keyIdentifier) + /** [AEADCipherMode] preferences of the primary user-id, or if absent, the primary key. */ val preferredAEADCipherSuites: Set get() = primaryUserId?.let { getPreferredAEADCipherSuites(it) } @@ -264,11 +272,24 @@ class KeyRingInfo( * @return expiration date or null */ fun getSubkeyExpirationDate(fingerprint: OpenPgpFingerprint): Date? { - return getSubkeyExpirationDate(fingerprint.keyId) + return getSubkeyExpirationDate(fingerprint.keyIdentifier) } + /** + * Return the expiration date of the [OpenPGPComponentKey] with the provided [keyIdentifier]. + * + * @param keyIdentifier subkey KeyIdentifier + * @return expiration date + */ fun getSubkeyExpirationDate(keyIdentifier: KeyIdentifier): Date? { - return getSubkeyExpirationDate(keyIdentifier.keyId) + if (primaryKey.keyIdentifier.matches(keyIdentifier)) return primaryKeyExpirationDate + val subkey = + getPublicKey(keyIdentifier) + ?: throw NoSuchElementException("No subkey with key-ID ${keyIdentifier} found.") + val bindingSig = + getCurrentSubkeyBindingSignature(keyIdentifier) + ?: throw AssertionError("Subkey has no valid binding signature.") + return bindingSig.getKeyExpirationDate(subkey.creationTime) } /** @@ -277,16 +298,9 @@ class KeyRingInfo( * @param keyId subkey keyId * @return expiration date */ + @Deprecated("Pass in a KeyIdentifer instead.") fun getSubkeyExpirationDate(keyId: Long): Date? { - if (primaryKey.keyIdentifier.keyId == keyId) return primaryKeyExpirationDate - val subkey = - getPublicKey(keyId) - ?: throw NoSuchElementException( - "No subkey with key-ID ${keyId.openPgpKeyId()} found.") - val bindingSig = - getCurrentSubkeyBindingSignature(keyId) - ?: throw AssertionError("Subkey has no valid binding signature.") - return bindingSig.getKeyExpirationDate(subkey.creationTime) + return getSubkeyExpirationDate(KeyIdentifier(keyId)) } /** @@ -465,32 +479,51 @@ class KeyRingInfo( keys.getUserId(userId.toString())?.getRevocation(referenceDate)?.signature /** - * Return the current binding signature for the subkey with the given key-ID. + * Return the current binding signature for the subkey with the given [keyIdentifier]. * + * @param keyIdentifier subkey identifier * @return current subkey binding signature */ + fun getCurrentSubkeyBindingSignature(keyIdentifier: KeyIdentifier): PGPSignature? = + keys.getKey(keyIdentifier)?.getCertification(referenceDate)?.signature + + /** + * Return the current binding signature for the subkey with the given key-ID. + * + * @param keyId key-ID + * @return current subkey binding signature + */ + @Deprecated("Pass in a KeyIdentifier instead.") fun getCurrentSubkeyBindingSignature(keyId: Long): PGPSignature? = - keys.getKey(KeyIdentifier(keyId))?.getCertification(referenceDate)?.signature + getCurrentSubkeyBindingSignature(KeyIdentifier(keyId)) + + /** + * Return the current revocation signature for the subkey with the given [keyIdentifier]. + * + * @param keyIdentifier subkey identifier + * @return current subkey revocation signature + */ + fun getSubkeyRevocationSignature(keyIdentifier: KeyIdentifier): PGPSignature? = + keys.getKey(keyIdentifier)?.getRevocation(referenceDate)?.signature /** * Return the current revocation signature for the subkey with the given key-ID. * * @return current subkey revocation signature */ + @Deprecated("Pass in a KeyIdentifier instead.") fun getSubkeyRevocationSignature(keyId: Long): PGPSignature? = - keys.getKey(KeyIdentifier(keyId))?.getRevocation(referenceDate)?.signature - - fun getKeyFlagsOf(keyIdentifier: KeyIdentifier): List = - getKeyFlagsOf(keyIdentifier.keyId) + getSubkeyRevocationSignature(KeyIdentifier(keyId)) /** - * Return a list of [KeyFlags][KeyFlag] that apply to the subkey with the provided key id. + * Return a list of [KeyFlags][KeyFlag] that apply to the subkey with the provided + * [keyIdentifier]. * - * @param keyId key-id + * @param keyIdentifier keyIdentifier * @return list of key flags */ - fun getKeyFlagsOf(keyId: Long): List = - if (keyId == primaryKey.keyIdentifier.keyId) { + fun getKeyFlagsOf(keyIdentifier: KeyIdentifier): List = + if (primaryKey.keyIdentifier.matches(keyIdentifier)) { latestDirectKeySelfSignature?.let { sig -> SignatureSubpacketsUtil.parseKeyFlags(sig)?.let { flags -> return flags @@ -505,7 +538,7 @@ class KeyRingInfo( } listOf() } else { - getCurrentSubkeyBindingSignature(keyId)?.let { + getCurrentSubkeyBindingSignature(keyIdentifier)?.let { SignatureSubpacketsUtil.parseKeyFlags(it)?.let { flags -> return flags } @@ -513,6 +546,15 @@ class KeyRingInfo( listOf() } + /** + * Return a list of [KeyFlags][KeyFlag] that apply to the subkey with the provided key id. + * + * @param keyId key-id + * @return list of key flags + */ + @Deprecated("Pass in a KeyIdentifier instead.") + fun getKeyFlagsOf(keyId: Long): List = getKeyFlagsOf(KeyIdentifier(keyId)) + /** * Return a list of [KeyFlags][KeyFlag] that apply to the given user-id. * @@ -530,13 +572,35 @@ class KeyRingInfo( "While user-id '$userId' was reported as valid, there appears to be no certification for it.") } + /** + * Return the [OpenPGPComponentKey] with the given [keyIdentifier] from this + * [OpenPGPCertificate] or [OpenPGPKey]. + * + * @param keyIdentifier keyIdentifier + * @return public component key or null + */ + fun getPublicKey(keyIdentifier: KeyIdentifier): OpenPGPComponentKey? = + keys.getKey(keyIdentifier) + /** * Return the public key with the given key id from the provided key ring. * * @param keyId key id * @return public key or null */ - fun getPublicKey(keyId: Long): OpenPGPComponentKey? = keys.getKey(KeyIdentifier(keyId)) + @Deprecated("Pass in a KeyIdentifier instead.") + fun getPublicKey(keyId: Long): OpenPGPComponentKey? = getPublicKey(KeyIdentifier(keyId)) + + /** + * Return the [OpenPGPSecretKey] component with the given [keyIdentifier]. + * + * @param keyIdentifier keyIdentifier + * @return secret key or null + */ + fun getSecretKey(keyIdentifier: KeyIdentifier): OpenPGPSecretKey? = + if (keys.isSecretKey) { + (keys as OpenPGPKey).getSecretKey(keyIdentifier) + } else null /** * Return the secret key with the given key id. @@ -544,20 +608,12 @@ class KeyRingInfo( * @param keyId key id * @return secret key or null */ + @Deprecated("Pass in a KeyIdentifier instead.") fun getSecretKey(keyId: Long): OpenPGPSecretKey? = getSecretKey(KeyIdentifier(keyId)) - fun getSecretKey(keyIdentifier: KeyIdentifier): OpenPGPSecretKey? = - if (keys.isSecretKey) { - (keys as OpenPGPKey).getSecretKey(keyIdentifier) - } else null - - fun isSecretKeyAvailable(keyId: Long): Boolean { - return isSecretKeyAvailable(KeyIdentifier(keyId)) - } - /** - * Return true, if the secret-key with the given key-ID is available (i.e. not moved to a - * smart-card). + * Return true, if the secret-key with the given [keyIdentifier] is available (i.e. part of the + * certificate AND not moved to a smart-card). * * @return availability of the secret key */ @@ -569,6 +625,11 @@ class KeyRingInfo( ?: false // Missing secret key } + @Deprecated("Pass in a KeyIdentifier instead.") + fun isSecretKeyAvailable(keyId: Long): Boolean { + return isSecretKeyAvailable(KeyIdentifier(keyId)) + } + /** * Return the public key with the given fingerprint. * @@ -576,7 +637,7 @@ class KeyRingInfo( * @return public key or null */ fun getPublicKey(fingerprint: OpenPgpFingerprint): OpenPGPComponentKey? = - keys.getKey(KeyIdentifier(fingerprint.bytes)) + keys.getKey(fingerprint.keyIdentifier) /** * Return the secret key with the given fingerprint. @@ -585,11 +646,7 @@ class KeyRingInfo( * @return secret key or null */ fun getSecretKey(fingerprint: OpenPgpFingerprint): OpenPGPSecretKey? = - getSecretKey(KeyIdentifier(fingerprint.bytes)) - - fun getPublicKey(keyIdentifier: KeyIdentifier): OpenPGPComponentKey? { - return keys.getKey(keyIdentifier) - } + getSecretKey(fingerprint.keyIdentifier) /** * Return the public key matching the given [SubkeyIdentifier]. @@ -599,7 +656,7 @@ class KeyRingInfo( * key of the key. */ fun getPublicKey(identifier: SubkeyIdentifier): OpenPGPComponentKey? { - require(primaryKey.keyIdentifier.equals(identifier.keyIdentifier)) { + require(primaryKey.keyIdentifier.matches(identifier.keyIdentifier)) { "Mismatching primary key ID." } return getPublicKey(identifier.componentKeyIdentifier) @@ -612,11 +669,22 @@ class KeyRingInfo( * @throws IllegalArgumentException if the identifier's primary key does not match the primary * key of the key. */ - fun getSecretKey(identifier: SubkeyIdentifier): OpenPGPComponentKey? = - getSecretKey(identifier.componentKeyIdentifier) + fun getSecretKey(identifier: SubkeyIdentifier): OpenPGPComponentKey? { + require(primaryKey.keyIdentifier.matches(identifier.keyIdentifier)) { + "Mismatching primary key ID." + } + return getSecretKey(identifier.componentKeyIdentifier) + } + /** + * Return true if the [OpenPGPComponentKey] with the given [keyIdentifier] is bound to the + * [OpenPGPCertificate] properly. + * + * @param keyIdentifier identifier of the component key + * @return true if key is bound validly + */ fun isKeyValidlyBound(keyIdentifier: KeyIdentifier): Boolean { - return isKeyValidlyBound(keyIdentifier.keyId) + return keys.getKey(keyIdentifier)?.isBoundAt(referenceDate) ?: false } /** @@ -625,9 +693,8 @@ class KeyRingInfo( * @param keyId key id * @return true if key is bound validly */ - fun isKeyValidlyBound(keyId: Long): Boolean { - return keys.getKey(KeyIdentifier(keyId))?.isBoundAt(referenceDate) ?: false - } + @Deprecated("Pass in a KeyIdentifier instead.") + fun isKeyValidlyBound(keyId: Long): Boolean = isKeyValidlyBound(KeyIdentifier(keyId)) /** * Return the current primary user-id of the key ring. @@ -643,7 +710,12 @@ class KeyRingInfo( return keys.primaryKey.getExplicitOrImplicitPrimaryUserId(referenceDate)?.userId } - /** Return true, if the primary user-ID, as well as the given user-ID are valid and bound. */ + /** + * Return true, if the primary user-ID, as well as the given user-ID are valid and bound. + * + * @param userId user-id + * @return true if the primary user-ID and the given user-ID are valid. + */ fun isUserIdValid(userId: CharSequence): Boolean { var valid = isUserIdBound(userId) if (primaryUserId != null) valid = valid && isUserIdBound(primaryUserId) @@ -651,11 +723,21 @@ class KeyRingInfo( return valid } - /** Return true, if the given user-ID is validly bound. */ + /** + * Return true, if the given user-ID is validly bound. + * + * @param userId user-id + * @return true if the user-id is validly bound to the [OpenPGPCertificate] + */ fun isUserIdBound(userId: CharSequence): Boolean = keys.getUserId(userId.toString())?.isBoundAt(referenceDate) ?: false - /** [HashAlgorithm] preferences of the given user-ID. */ + /** + * Return the [HashAlgorithm] preferences of the given [userId]. + * + * @param userId user-id + * @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order) + */ fun getPreferredHashAlgorithms(userId: CharSequence): Set { return keys .getUserId(userId.toString()) @@ -664,6 +746,12 @@ class KeyRingInfo( ?: throw NoSuchElementException("No user-id '$userId' found on this key.") } + /** + * Return the [HashAlgorithm] preferences of the component key with the given [KeyIdentifier]. + * + * @param keyIdentifier identifier of a [OpenPGPComponentKey] + * @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order) + */ fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set { return keys .getKey(keyIdentifier) @@ -679,7 +767,13 @@ class KeyRingInfo( return getPreferredHashAlgorithms(KeyIdentifier(keyId)) } - /** [SymmetricKeyAlgorithm] preferences of the given user-ID. */ + /** + * Return the [SymmetricKeyAlgorithm] preferences of the given [userId]. + * + * @param userId user-id + * @return ordered set of preferred [SymmetricKeyAlgorithms][SymmetricKeyAlgorithm] (descending + * order) + */ fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set { return keys .getUserId(userId.toString()) @@ -688,6 +782,14 @@ class KeyRingInfo( ?: throw NoSuchElementException("No user-id '$userId' found on this key.") } + /** + * Return the [SymmetricKeyAlgorithm] preferences of the [OpenPGPComponentKey] with the given + * [keyIdentifier]. + * + * @param keyIdentifier identifier of the [OpenPGPComponentKey] + * @return ordered set of preferred [SymmetricKeyAlgorithms][SymmetricKeyAlgorithm] (descending + * order) + */ fun getPreferredSymmetricKeyAlgorithms( keyIdentifier: KeyIdentifier ): Set { @@ -705,7 +807,13 @@ class KeyRingInfo( return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId)) } - /** [CompressionAlgorithm] preferences of the given user-ID. */ + /** + * Return the [CompressionAlgorithm] preferences of the given [userId]. + * + * @param userId user-id + * @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending + * order) + */ fun getPreferredCompressionAlgorithms(userId: CharSequence): Set { return keys .getUserId(userId.toString()) @@ -714,6 +822,14 @@ class KeyRingInfo( ?: throw NoSuchElementException("No user-id '$userId' found on this key.") } + /** + * Return the [CompressionAlgorithm] preferences of the [OpenPGPComponentKey] with the given + * [keyIdentifier]. + * + * @param keyIdentifier identifier of the [OpenPGPComponentKey] + * @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending + * order) + */ fun getPreferredCompressionAlgorithms(keyIdentifier: KeyIdentifier): Set { return keys .getKey(keyIdentifier) @@ -724,10 +840,18 @@ class KeyRingInfo( } /** [CompressionAlgorithm] preferences of the given key. */ + @Deprecated("Pass in a KeyIdentifier instead.") fun getPreferredCompressionAlgorithms(keyId: Long): Set { return getPreferredCompressionAlgorithms(KeyIdentifier(keyId)) } + /** + * Return the [AEADCipherMode] preferences of the given [userId]. + * + * @param userId user-ID + * @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including + * implicitly supported AEAD modes) + */ fun getPreferredAEADCipherSuites(userId: CharSequence): Set { return keys .getUserId(userId.toString()) @@ -736,6 +860,14 @@ class KeyRingInfo( ?: throw NoSuchElementException("No user-id '$userId' found on this key.") } + /** + * Return the [AEADCipherMode] preferences of the [OpenPGPComponentKey] with the given + * [keyIdentifier]. + * + * @param keyIdentifier component key identifier + * @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including + * implicitly supported AEAD modes) + */ fun getPreferredAEADCipherSuites(keyIdentifier: KeyIdentifier): Set { return keys .getKey(keyIdentifier) @@ -750,10 +882,6 @@ class KeyRingInfo( return getPreferredAEADCipherSuites(KeyIdentifier(keyId)) } - val isUsableForThirdPartyCertification: Boolean = - isKeyValidlyBound(keyIdentifier) && - getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER) - companion object { /** Evaluate the key for the given signature. */