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
1379942c07
commit
3030f2af2b
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.pgpainless.algorithm.AEADCipherMode
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||
|
@ -40,6 +41,9 @@ abstract class KeyAccessor(protected val info: KeyRingInfo, protected val key: S
|
|||
get() =
|
||||
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
|
||||
* sourcing preferred algorithms from the user-id certification first.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.pgpainless.key.info
|
||||
|
||||
import java.util.*
|
||||
import kotlin.NoSuchElementException
|
||||
import openpgp.openPgpKeyId
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.openpgp.*
|
||||
|
@ -249,6 +250,11 @@ class KeyRingInfo(
|
|||
primaryUserId?.let { getPreferredCompressionAlgorithms(it) }
|
||||
?: getPreferredCompressionAlgorithms(keyIdentifier)
|
||||
|
||||
val preferredAEADCipherSuites: Set<AEADCipherMode>
|
||||
get() =
|
||||
primaryUserId?.let { getPreferredAEADCipherSuites(it) }
|
||||
?: getPreferredAEADCipherSuites(keyIdentifier)
|
||||
|
||||
/**
|
||||
* Return the expiration date of the subkey with the provided fingerprint.
|
||||
*
|
||||
|
@ -649,70 +655,103 @@ class KeyRingInfo(
|
|||
|
||||
/** [HashAlgorithm] preferences of the given user-ID. */
|
||||
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> {
|
||||
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. */
|
||||
@Deprecated("Pass KeyIdentifier instead.")
|
||||
fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm> {
|
||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
||||
.preferredHashAlgorithms
|
||||
return getPreferredHashAlgorithms(KeyIdentifier(keyId))
|
||||
}
|
||||
|
||||
/** [SymmetricKeyAlgorithm] preferences of the given user-ID. */
|
||||
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(
|
||||
keyIdentifier: KeyIdentifier
|
||||
): 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. */
|
||||
@Deprecated("Pass KeyIdentifier instead.")
|
||||
fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm> {
|
||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
||||
.preferredSymmetricKeyAlgorithms
|
||||
return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId))
|
||||
}
|
||||
|
||||
/** [CompressionAlgorithm] preferences of the given user-ID. */
|
||||
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> {
|
||||
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. */
|
||||
fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm> {
|
||||
return KeyAccessor.SubKey(this, SubkeyIdentifier(keys.pgpKeyRing, keyId))
|
||||
.preferredCompressionAlgorithms
|
||||
return getPreferredCompressionAlgorithms(KeyIdentifier(keyId))
|
||||
}
|
||||
|
||||
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 =
|
||||
isKeyValidlyBound(keyIdentifier) &&
|
||||
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 {
|
||||
|
||||
/** Evaluate the key for the given signature. */
|
||||
|
|
|
@ -269,6 +269,15 @@ class SignatureSubpacketsUtil {
|
|||
?.toSet()
|
||||
?: setOf()
|
||||
|
||||
@JvmStatic
|
||||
fun parsePreferredAEADCipherSuites(signature: PGPSignature): Set<AEADCipherMode> =
|
||||
getPreferredAeadAlgorithms(signature)
|
||||
?.algorithms
|
||||
?.asSequence()
|
||||
?.map { AEADCipherMode(it) }
|
||||
?.toSet()
|
||||
?: setOf()
|
||||
|
||||
@JvmStatic
|
||||
fun getPreferredAeadAlgorithms(signature: PGPSignature): PreferredAEADCiphersuites? =
|
||||
hashed(signature, SignatureSubpacket.preferredAEADAlgorithms)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue