mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Improve KeyRingInfos getPreferences implementations
This commit is contained in:
parent
35c6116643
commit
6eaa483650
8 changed files with 139 additions and 27 deletions
|
@ -0,0 +1,15 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.algorithm
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites.Combination
|
||||||
|
|
||||||
|
data class AEADCipherMode(val aeadAlgorithm: AEADAlgorithm, val ciphermode: SymmetricKeyAlgorithm) {
|
||||||
|
constructor(
|
||||||
|
combination: Combination
|
||||||
|
) : this(
|
||||||
|
AEADAlgorithm.requireFromId(combination.aeadAlgorithm),
|
||||||
|
SymmetricKeyAlgorithm.requireFromId(combination.symmetricAlgorithm))
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package org.pgpainless.bouncycastle.extensions
|
package org.pgpainless.bouncycastle.extensions
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPOnePassSignature
|
import org.bouncycastle.openpgp.PGPOnePassSignature
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package org.pgpainless.bouncycastle.extensions
|
package org.pgpainless.bouncycastle.extensions
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
|
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.bouncycastle.extensions
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites
|
||||||
|
import org.pgpainless.algorithm.AEADCipherMode
|
||||||
|
|
||||||
|
fun PreferredAEADCiphersuites?.toAEADCipherModes(): Set<AEADCipherMode> {
|
||||||
|
return this?.algorithms?.asSequence()?.map { AEADCipherMode(it) }?.toSet() ?: setOf()
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.bouncycastle.extensions
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.sig.PreferredAlgorithms
|
||||||
|
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||||
|
import org.pgpainless.algorithm.HashAlgorithm
|
||||||
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||||
|
|
||||||
|
fun PreferredAlgorithms?.toHashAlgorithms(): Set<HashAlgorithm> {
|
||||||
|
return this?.preferences?.asSequence()?.map { HashAlgorithm.requireFromId(it) }?.toSet()
|
||||||
|
?: setOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PreferredAlgorithms?.toSymmetricKeyAlgorithms(): Set<SymmetricKeyAlgorithm> {
|
||||||
|
return this?.preferences?.asSequence()?.map { SymmetricKeyAlgorithm.requireFromId(it) }?.toSet()
|
||||||
|
?: setOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PreferredAlgorithms?.toCompressionAlgorithms(): Set<CompressionAlgorithm> {
|
||||||
|
return this?.preferences?.asSequence()?.map { CompressionAlgorithm.requireFromId(it) }?.toSet()
|
||||||
|
?: setOf()
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
package org.pgpainless.key.info
|
package org.pgpainless.key.info
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature
|
import org.bouncycastle.openpgp.PGPSignature
|
||||||
|
import org.pgpainless.algorithm.AEADCipherMode
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||||
import org.pgpainless.algorithm.HashAlgorithm
|
import org.pgpainless.algorithm.HashAlgorithm
|
||||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||||
|
@ -40,6 +41,9 @@ abstract class KeyAccessor(protected val info: KeyRingInfo, protected val key: S
|
||||||
get() =
|
get() =
|
||||||
SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(signatureWithPreferences)
|
SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(signatureWithPreferences)
|
||||||
|
|
||||||
|
val preferredAEADCipherSuites: Set<AEADCipherMode>
|
||||||
|
get() = SignatureSubpacketsUtil.parsePreferredAEADCipherSuites(signatureWithPreferences)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address the key via a user-id (e.g. `Alice <alice@wonderland.lit>`). In this case we are
|
* Address the key via a user-id (e.g. `Alice <alice@wonderland.lit>`). In this case we are
|
||||||
* sourcing preferred algorithms from the user-id certification first.
|
* sourcing preferred algorithms from the user-id certification first.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.pgpainless.key.info
|
package org.pgpainless.key.info
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.NoSuchElementException
|
||||||
import openpgp.openPgpKeyId
|
import openpgp.openPgpKeyId
|
||||||
import org.bouncycastle.bcpg.KeyIdentifier
|
import org.bouncycastle.bcpg.KeyIdentifier
|
||||||
import org.bouncycastle.openpgp.*
|
import org.bouncycastle.openpgp.*
|
||||||
|
@ -249,6 +250,11 @@ class KeyRingInfo(
|
||||||
primaryUserId?.let { getPreferredCompressionAlgorithms(it) }
|
primaryUserId?.let { getPreferredCompressionAlgorithms(it) }
|
||||||
?: getPreferredCompressionAlgorithms(keyIdentifier)
|
?: getPreferredCompressionAlgorithms(keyIdentifier)
|
||||||
|
|
||||||
|
val preferredAEADCipherSuites: Set<AEADCipherMode>
|
||||||
|
get() =
|
||||||
|
primaryUserId?.let { getPreferredAEADCipherSuites(it) }
|
||||||
|
?: getPreferredAEADCipherSuites(keyIdentifier)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the expiration date of the subkey with the provided fingerprint.
|
* Return the expiration date of the subkey with the provided fingerprint.
|
||||||
*
|
*
|
||||||
|
@ -649,70 +655,103 @@ class KeyRingInfo(
|
||||||
|
|
||||||
/** [HashAlgorithm] preferences of the given user-ID. */
|
/** [HashAlgorithm] preferences of the given user-ID. */
|
||||||
fun getPreferredHashAlgorithms(userId: CharSequence): Set<HashAlgorithm> {
|
fun getPreferredHashAlgorithms(userId: CharSequence): Set<HashAlgorithm> {
|
||||||
return getKeyAccessor(userId, keyIdentifier).preferredHashAlgorithms
|
return keys
|
||||||
|
.getUserId(userId.toString())
|
||||||
|
?.getHashAlgorithmPreferences(referenceDate)
|
||||||
|
?.toHashAlgorithms()
|
||||||
|
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set<HashAlgorithm> {
|
fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set<HashAlgorithm> {
|
||||||
return getPreferredHashAlgorithms(keyIdentifier.keyId)
|
return keys
|
||||||
|
.getKey(keyIdentifier)
|
||||||
|
?.getHashAlgorithmPreferences(referenceDate)
|
||||||
|
?.toHashAlgorithms()
|
||||||
|
?: throw NoSuchElementException(
|
||||||
|
"No subkey with key-id $keyIdentifier found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [HashAlgorithm] preferences of the given key. */
|
/** [HashAlgorithm] preferences of the given key. */
|
||||||
|
@Deprecated("Pass KeyIdentifier instead.")
|
||||||
fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm> {
|
fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm> {
|
||||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
return getPreferredHashAlgorithms(KeyIdentifier(keyId))
|
||||||
.preferredHashAlgorithms
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [SymmetricKeyAlgorithm] preferences of the given user-ID. */
|
/** [SymmetricKeyAlgorithm] preferences of the given user-ID. */
|
||||||
fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set<SymmetricKeyAlgorithm> {
|
fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set<SymmetricKeyAlgorithm> {
|
||||||
return getKeyAccessor(userId, keyIdentifier).preferredSymmetricKeyAlgorithms
|
return keys
|
||||||
|
.getUserId(userId.toString())
|
||||||
|
?.getSymmetricCipherPreferences(referenceDate)
|
||||||
|
?.toSymmetricKeyAlgorithms()
|
||||||
|
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPreferredSymmetricKeyAlgorithms(
|
fun getPreferredSymmetricKeyAlgorithms(
|
||||||
keyIdentifier: KeyIdentifier
|
keyIdentifier: KeyIdentifier
|
||||||
): Set<SymmetricKeyAlgorithm> {
|
): Set<SymmetricKeyAlgorithm> {
|
||||||
return getPreferredSymmetricKeyAlgorithms(keyIdentifier.keyId)
|
return keys
|
||||||
|
.getKey(keyIdentifier)
|
||||||
|
?.getSymmetricCipherPreferences(referenceDate)
|
||||||
|
?.toSymmetricKeyAlgorithms()
|
||||||
|
?: throw NoSuchElementException(
|
||||||
|
"No subkey with key-id $keyIdentifier found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [SymmetricKeyAlgorithm] preferences of the given key. */
|
/** [SymmetricKeyAlgorithm] preferences of the given key. */
|
||||||
|
@Deprecated("Pass KeyIdentifier instead.")
|
||||||
fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm> {
|
fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm> {
|
||||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId))
|
||||||
.preferredSymmetricKeyAlgorithms
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [CompressionAlgorithm] preferences of the given user-ID. */
|
/** [CompressionAlgorithm] preferences of the given user-ID. */
|
||||||
fun getPreferredCompressionAlgorithms(userId: CharSequence): Set<CompressionAlgorithm> {
|
fun getPreferredCompressionAlgorithms(userId: CharSequence): Set<CompressionAlgorithm> {
|
||||||
return getKeyAccessor(userId, keyIdentifier).preferredCompressionAlgorithms
|
return keys
|
||||||
|
.getUserId(userId.toString())
|
||||||
|
?.getCompressionAlgorithmPreferences(referenceDate)
|
||||||
|
?.toCompressionAlgorithms()
|
||||||
|
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPreferredCompressionAlgorithms(keyIdentifier: KeyIdentifier): Set<CompressionAlgorithm> {
|
fun getPreferredCompressionAlgorithms(keyIdentifier: KeyIdentifier): Set<CompressionAlgorithm> {
|
||||||
return getPreferredCompressionAlgorithms(keyIdentifier.keyId)
|
return keys
|
||||||
|
.getKey(keyIdentifier)
|
||||||
|
?.getCompressionAlgorithmPreferences(referenceDate)
|
||||||
|
?.toCompressionAlgorithms()
|
||||||
|
?: throw NoSuchElementException(
|
||||||
|
"No subkey with key-id $keyIdentifier found on this key.")
|
||||||
}
|
}
|
||||||
|
|
||||||
/** [CompressionAlgorithm] preferences of the given key. */
|
/** [CompressionAlgorithm] preferences of the given key. */
|
||||||
fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm> {
|
fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm> {
|
||||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
return getPreferredCompressionAlgorithms(KeyIdentifier(keyId))
|
||||||
.preferredCompressionAlgorithms
|
}
|
||||||
|
|
||||||
|
fun getPreferredAEADCipherSuites(userId: CharSequence): Set<AEADCipherMode> {
|
||||||
|
return keys
|
||||||
|
.getUserId(userId.toString())
|
||||||
|
?.getAEADCipherSuitePreferences(referenceDate)
|
||||||
|
?.toAEADCipherModes()
|
||||||
|
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPreferredAEADCipherSuites(keyIdentifier: KeyIdentifier): Set<AEADCipherMode> {
|
||||||
|
return keys
|
||||||
|
.getKey(keyIdentifier)
|
||||||
|
?.getAEADCipherSuitePreferences(referenceDate)
|
||||||
|
?.toAEADCipherModes()
|
||||||
|
?: throw NoSuchElementException(
|
||||||
|
"No subkey with key-id $keyIdentifier found on this key.")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated("Pass KeyIdentifier instead.")
|
||||||
|
fun getPreferredAEADCipherSuites(keyId: Long): Set<AEADCipherMode> {
|
||||||
|
return getPreferredAEADCipherSuites(KeyIdentifier(keyId))
|
||||||
}
|
}
|
||||||
|
|
||||||
val isUsableForThirdPartyCertification: Boolean =
|
val isUsableForThirdPartyCertification: Boolean =
|
||||||
isKeyValidlyBound(keyIdentifier) &&
|
isKeyValidlyBound(keyIdentifier) &&
|
||||||
getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER)
|
getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER)
|
||||||
|
|
||||||
private fun getKeyAccessor(userId: CharSequence?, keyIdentifier: KeyIdentifier): KeyAccessor {
|
|
||||||
if (getPublicKey(keyIdentifier) == null) {
|
|
||||||
throw NoSuchElementException("No subkey with key-id $keyIdentifier found on this key.")
|
|
||||||
}
|
|
||||||
if (userId != null && !userIds.contains(userId)) {
|
|
||||||
throw NoSuchElementException("No user-id '$userId' found on this key.")
|
|
||||||
}
|
|
||||||
return if (userId != null) {
|
|
||||||
KeyAccessor.ViaUserId(
|
|
||||||
this, SubkeyIdentifier(keys.pgpKeyRing, keyIdentifier.keyId), userId)
|
|
||||||
} else {
|
|
||||||
KeyAccessor.ViaKeyId(this, SubkeyIdentifier(keys.pgpKeyRing, keyIdentifier.keyId))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
/** Evaluate the key for the given signature. */
|
/** Evaluate the key for the given signature. */
|
||||||
|
|
|
@ -269,6 +269,15 @@ class SignatureSubpacketsUtil {
|
||||||
?.toSet()
|
?.toSet()
|
||||||
?: setOf()
|
?: setOf()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun parsePreferredAEADCipherSuites(signature: PGPSignature): Set<AEADCipherMode> =
|
||||||
|
getPreferredAeadAlgorithms(signature)
|
||||||
|
?.algorithms
|
||||||
|
?.asSequence()
|
||||||
|
?.map { AEADCipherMode(it) }
|
||||||
|
?.toSet()
|
||||||
|
?: setOf()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getPreferredAeadAlgorithms(signature: PGPSignature): PreferredAEADCiphersuites? =
|
fun getPreferredAeadAlgorithms(signature: PGPSignature): PreferredAEADCiphersuites? =
|
||||||
hashed(signature, SignatureSubpacket.preferredAEADAlgorithms)
|
hashed(signature, SignatureSubpacket.preferredAEADAlgorithms)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue