1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 18:29:39 +02:00

WIP: Migrate SecretKeyRingEditor

This commit is contained in:
Paul Schaub 2025-03-10 14:14:41 +01:00
parent 3abc2a4e39
commit 18cdf6bbc7
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
6 changed files with 99 additions and 96 deletions

View file

@ -21,7 +21,7 @@ interface HashAlgorithmNegotiator {
* @param orderedPrefs hash algorithm preferences * @param orderedPrefs hash algorithm preferences
* @return picked algorithms * @return picked algorithms
*/ */
fun negotiateHashAlgorithm(orderedPrefs: Set<HashAlgorithm>): HashAlgorithm fun negotiateHashAlgorithm(orderedPrefs: Set<HashAlgorithm>?): HashAlgorithm
companion object { companion object {
@ -62,9 +62,9 @@ interface HashAlgorithmNegotiator {
): HashAlgorithmNegotiator { ): HashAlgorithmNegotiator {
return object : HashAlgorithmNegotiator { return object : HashAlgorithmNegotiator {
override fun negotiateHashAlgorithm( override fun negotiateHashAlgorithm(
orderedPrefs: Set<HashAlgorithm> orderedPrefs: Set<HashAlgorithm>?
): HashAlgorithm { ): HashAlgorithm {
return orderedPrefs.firstOrNull { hashAlgorithmPolicy.isAcceptable(it) } return orderedPrefs?.firstOrNull { hashAlgorithmPolicy.isAcceptable(it) }
?: hashAlgorithmPolicy.defaultHashAlgorithm() ?: hashAlgorithmPolicy.defaultHashAlgorithm()
} }
} }

View file

@ -482,7 +482,7 @@ class SigningOptions {
* @return selected hash algorithm * @return selected hash algorithm
*/ */
private fun negotiateHashAlgorithm( private fun negotiateHashAlgorithm(
preferences: Set<HashAlgorithm>, preferences: Set<HashAlgorithm>?,
policy: Policy policy: Policy
): HashAlgorithm { ): HashAlgorithm {
return _hashAlgorithmOverride return _hashAlgorithmOverride

View file

@ -240,7 +240,7 @@ class KeyRingInfo(
getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER) getKeyFlagsOf(keyIdentifier).contains(KeyFlag.CERTIFY_OTHER)
/** [HashAlgorithm] preferences of the primary user-ID or if absent, of the primary key. */ /** [HashAlgorithm] preferences of the primary user-ID or if absent, of the primary key. */
val preferredHashAlgorithms: Set<HashAlgorithm> val preferredHashAlgorithms: Set<HashAlgorithm>?
get() = get() =
primaryUserId?.let { getPreferredHashAlgorithms(it) } primaryUserId?.let { getPreferredHashAlgorithms(it) }
?: getPreferredHashAlgorithms(keyIdentifier) ?: getPreferredHashAlgorithms(keyIdentifier)
@ -248,19 +248,19 @@ class KeyRingInfo(
/** /**
* [SymmetricKeyAlgorithm] preferences of the primary user-ID or if absent of the primary key. * [SymmetricKeyAlgorithm] preferences of the primary user-ID or if absent of the primary key.
*/ */
val preferredSymmetricKeyAlgorithms: Set<SymmetricKeyAlgorithm> val preferredSymmetricKeyAlgorithms: Set<SymmetricKeyAlgorithm>?
get() = get() =
primaryUserId?.let { getPreferredSymmetricKeyAlgorithms(it) } primaryUserId?.let { getPreferredSymmetricKeyAlgorithms(it) }
?: getPreferredSymmetricKeyAlgorithms(keyIdentifier) ?: getPreferredSymmetricKeyAlgorithms(keyIdentifier)
/** [CompressionAlgorithm] preferences of the primary user-ID or if absent, the primary key. */ /** [CompressionAlgorithm] preferences of the primary user-ID or if absent, the primary key. */
val preferredCompressionAlgorithms: Set<CompressionAlgorithm> val preferredCompressionAlgorithms: Set<CompressionAlgorithm>?
get() = get() =
primaryUserId?.let { getPreferredCompressionAlgorithms(it) } primaryUserId?.let { getPreferredCompressionAlgorithms(it) }
?: getPreferredCompressionAlgorithms(keyIdentifier) ?: getPreferredCompressionAlgorithms(keyIdentifier)
/** [AEADCipherMode] preferences of the primary user-id, or if absent, the primary key. */ /** [AEADCipherMode] preferences of the primary user-id, or if absent, the primary key. */
val preferredAEADCipherSuites: Set<AEADCipherMode> val preferredAEADCipherSuites: Set<AEADCipherMode>?
get() = get() =
primaryUserId?.let { getPreferredAEADCipherSuites(it) } primaryUserId?.let { getPreferredAEADCipherSuites(it) }
?: getPreferredAEADCipherSuites(keyIdentifier) ?: getPreferredAEADCipherSuites(keyIdentifier)
@ -738,12 +738,11 @@ class KeyRingInfo(
* @param userId user-id * @param userId user-id
* @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order) * @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order)
*/ */
fun getPreferredHashAlgorithms(userId: CharSequence): Set<HashAlgorithm> { fun getPreferredHashAlgorithms(userId: CharSequence): Set<HashAlgorithm>? {
return keys return (keys.getUserId(userId.toString())
.getUserId(userId.toString()) ?: throw NoSuchElementException("No user-id '$userId' found on this key."))
?.getHashAlgorithmPreferences(referenceDate) .getHashAlgorithmPreferences(referenceDate)
?.toHashAlgorithms() ?.toHashAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
} }
/** /**
@ -752,18 +751,17 @@ class KeyRingInfo(
* @param keyIdentifier identifier of a [OpenPGPComponentKey] * @param keyIdentifier identifier of a [OpenPGPComponentKey]
* @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order) * @return ordered set of preferred [HashAlgorithms][HashAlgorithm] (descending order)
*/ */
fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set<HashAlgorithm> { fun getPreferredHashAlgorithms(keyIdentifier: KeyIdentifier): Set<HashAlgorithm>? {
return keys return (keys.getKey(keyIdentifier)
.getKey(keyIdentifier) ?: throw NoSuchElementException(
?.getHashAlgorithmPreferences(referenceDate) "No subkey with key-id $keyIdentifier found on this key."))
.getHashAlgorithmPreferences(referenceDate)
?.toHashAlgorithms() ?.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.") @Deprecated("Pass KeyIdentifier instead.")
fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm> { fun getPreferredHashAlgorithms(keyId: Long): Set<HashAlgorithm>? {
return getPreferredHashAlgorithms(KeyIdentifier(keyId)) return getPreferredHashAlgorithms(KeyIdentifier(keyId))
} }
@ -774,12 +772,11 @@ class KeyRingInfo(
* @return ordered set of preferred [SymmetricKeyAlgorithms][SymmetricKeyAlgorithm] (descending * @return ordered set of preferred [SymmetricKeyAlgorithms][SymmetricKeyAlgorithm] (descending
* order) * order)
*/ */
fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set<SymmetricKeyAlgorithm> { fun getPreferredSymmetricKeyAlgorithms(userId: CharSequence): Set<SymmetricKeyAlgorithm>? {
return keys return (keys.getUserId(userId.toString())
.getUserId(userId.toString()) ?: throw NoSuchElementException("No user-id '$userId' found on this key."))
?.getSymmetricCipherPreferences(referenceDate) .getSymmetricCipherPreferences(referenceDate)
?.toSymmetricKeyAlgorithms() ?.toSymmetricKeyAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
} }
/** /**
@ -792,18 +789,17 @@ class KeyRingInfo(
*/ */
fun getPreferredSymmetricKeyAlgorithms( fun getPreferredSymmetricKeyAlgorithms(
keyIdentifier: KeyIdentifier keyIdentifier: KeyIdentifier
): Set<SymmetricKeyAlgorithm> { ): Set<SymmetricKeyAlgorithm>? {
return keys return (keys.getKey(keyIdentifier)
.getKey(keyIdentifier) ?: throw NoSuchElementException(
?.getSymmetricCipherPreferences(referenceDate) "No subkey with key-id $keyIdentifier found on this key."))
.getSymmetricCipherPreferences(referenceDate)
?.toSymmetricKeyAlgorithms() ?.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.") @Deprecated("Pass KeyIdentifier instead.")
fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm> { fun getPreferredSymmetricKeyAlgorithms(keyId: Long): Set<SymmetricKeyAlgorithm>? {
return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId)) return getPreferredSymmetricKeyAlgorithms(KeyIdentifier(keyId))
} }
@ -814,12 +810,11 @@ class KeyRingInfo(
* @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending * @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending
* order) * order)
*/ */
fun getPreferredCompressionAlgorithms(userId: CharSequence): Set<CompressionAlgorithm> { fun getPreferredCompressionAlgorithms(userId: CharSequence): Set<CompressionAlgorithm>? {
return keys return (keys.getUserId(userId.toString())
.getUserId(userId.toString()) ?: throw NoSuchElementException("No user-id '$userId' found on this key."))
?.getCompressionAlgorithmPreferences(referenceDate) .getCompressionAlgorithmPreferences(referenceDate)
?.toCompressionAlgorithms() ?.toCompressionAlgorithms()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
} }
/** /**
@ -830,18 +825,19 @@ class KeyRingInfo(
* @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending * @return ordered set of preferred [CompressionAlgorithms][CompressionAlgorithm] (descending
* order) * order)
*/ */
fun getPreferredCompressionAlgorithms(keyIdentifier: KeyIdentifier): Set<CompressionAlgorithm> { fun getPreferredCompressionAlgorithms(
return keys keyIdentifier: KeyIdentifier
.getKey(keyIdentifier) ): Set<CompressionAlgorithm>? {
?.getCompressionAlgorithmPreferences(referenceDate) return (keys.getKey(keyIdentifier)
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key."))
.getCompressionAlgorithmPreferences(referenceDate)
?.toCompressionAlgorithms() ?.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. */
@Deprecated("Pass in a KeyIdentifier instead.") @Deprecated("Pass in a KeyIdentifier instead.")
fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm> { fun getPreferredCompressionAlgorithms(keyId: Long): Set<CompressionAlgorithm>? {
return getPreferredCompressionAlgorithms(KeyIdentifier(keyId)) return getPreferredCompressionAlgorithms(KeyIdentifier(keyId))
} }
@ -852,12 +848,11 @@ class KeyRingInfo(
* @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including * @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including
* implicitly supported AEAD modes) * implicitly supported AEAD modes)
*/ */
fun getPreferredAEADCipherSuites(userId: CharSequence): Set<AEADCipherMode> { fun getPreferredAEADCipherSuites(userId: CharSequence): Set<AEADCipherMode>? {
return keys return (keys.getUserId(userId.toString())
.getUserId(userId.toString()) ?: throw NoSuchElementException("No user-id '$userId' found on this key."))
?.getAEADCipherSuitePreferences(referenceDate) .getAEADCipherSuitePreferences(referenceDate)
?.toAEADCipherModes() ?.toAEADCipherModes()
?: throw NoSuchElementException("No user-id '$userId' found on this key.")
} }
/** /**
@ -868,17 +863,16 @@ class KeyRingInfo(
* @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including * @return ordered set of [AEADCipherModes][AEADCipherMode] (descending order, including
* implicitly supported AEAD modes) * implicitly supported AEAD modes)
*/ */
fun getPreferredAEADCipherSuites(keyIdentifier: KeyIdentifier): Set<AEADCipherMode> { fun getPreferredAEADCipherSuites(keyIdentifier: KeyIdentifier): Set<AEADCipherMode>? {
return keys return (keys.getKey(keyIdentifier)
.getKey(keyIdentifier) ?: throw NoSuchElementException(
?.getAEADCipherSuitePreferences(referenceDate) "No subkey with key-id $keyIdentifier found on this key."))
.getAEADCipherSuitePreferences(referenceDate)
?.toAEADCipherModes() ?.toAEADCipherModes()
?: throw NoSuchElementException(
"No subkey with key-id $keyIdentifier found on this key.")
} }
@Deprecated("Pass KeyIdentifier instead.") @Deprecated("Pass KeyIdentifier instead.")
fun getPreferredAEADCipherSuites(keyId: Long): Set<AEADCipherMode> { fun getPreferredAEADCipherSuites(keyId: Long): Set<AEADCipherMode>? {
return getPreferredAEADCipherSuites(KeyIdentifier(keyId)) return getPreferredAEADCipherSuites(KeyIdentifier(keyId))
} }

View file

@ -17,11 +17,12 @@ import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPSubkey
import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
import org.bouncycastle.openpgp.api.OpenPGPKeyEditor
import org.bouncycastle.openpgp.api.OpenPGPSignature import org.bouncycastle.openpgp.api.OpenPGPSignature
import org.bouncycastle.openpgp.api.SignatureParameters
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.PGPainless.Companion.inspectKeyRing import org.pgpainless.PGPainless.Companion.inspectKeyRing
import org.pgpainless.algorithm.AlgorithmSuite import org.pgpainless.algorithm.AlgorithmSuite
import org.pgpainless.algorithm.Feature
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.algorithm.OpenPGPKeyVersion import org.pgpainless.algorithm.OpenPGPKeyVersion
import org.pgpainless.algorithm.SignatureType import org.pgpainless.algorithm.SignatureType
@ -59,48 +60,54 @@ class SecretKeyRingEditor(var key: OpenPGPKey, override val referenceTime: Date
callback: SelfSignatureSubpackets.Callback?, callback: SelfSignatureSubpackets.Callback?,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
val sanitizedUserId = sanitizeUserId(userId).toString() key = PGPainless.getInstance().toKey(secretKeyRing)
val primaryKey = secretKeyRing.secretKey val info = inspectKeyRing(key, referenceTime)
val info = inspectKeyRing(secretKeyRing, referenceTime)
require(!info.isHardRevoked(userId)) { require(!info.isHardRevoked(userId)) {
"User-ID $userId is hard revoked and cannot be re-certified." "User-ID $userId is hard revoked and cannot be re-certified."
} }
val ( val hashAlgorithmPreferences =
hashAlgorithmPreferences, info.preferredHashAlgorithms ?: AlgorithmSuite.defaultHashAlgorithms
symmetricKeyAlgorithmPreferences, val symmetricAlgorithmPreferences =
compressionAlgorithmPreferences) = info.preferredSymmetricKeyAlgorithms ?: AlgorithmSuite.defaultSymmetricKeyAlgorithms
try { val compressionAlgorithmPreferences =
Triple( info.preferredCompressionAlgorithms ?: AlgorithmSuite.defaultCompressionAlgorithms
info.preferredHashAlgorithms, val aeadAlgorithmPreferences =
info.preferredSymmetricKeyAlgorithms, info.preferredAEADCipherSuites ?: AlgorithmSuite.defaultAEADAlgorithmSuites
info.preferredCompressionAlgorithms)
} catch (e: IllegalStateException) { // missing user-id sig
val algorithmSuite = AlgorithmSuite.defaultAlgorithmSuite
Triple(
algorithmSuite.hashAlgorithms,
algorithmSuite.symmetricKeyAlgorithms,
algorithmSuite.compressionAlgorithms)
}
val builder = key =
SelfSignatureBuilder(key.primarySecretKey, protector).apply { OpenPGPKeyEditor(key, protector)
hashedSubpackets.setSignatureCreationTime(referenceTime) .addUserId(
setSignatureType(SignatureType.POSITIVE_CERTIFICATION) sanitizeUserId(userId).toString(),
} object : SignatureParameters.Callback {
builder.hashedSubpackets.apply { override fun apply(parameters: SignatureParameters): SignatureParameters {
setKeyFlags(info.getKeyFlagsOf(primaryKey.keyID)) return parameters
hashAlgorithmPreferences .setSignatureCreationTime(referenceTime)
hashAlgorithmPreferences?.let { setPreferredHashAlgorithms(it) } .setHashedSubpacketsFunction { subpacketGenerator ->
symmetricKeyAlgorithmPreferences?.let { setPreferredSymmetricKeyAlgorithms(it) } val subpackets = SignatureSubpackets(subpacketGenerator)
compressionAlgorithmPreferences?.let { setPreferredCompressionAlgorithms(it) } subpackets.setAppropriateIssuerInfo(secretKeyRing.publicKey)
setFeatures(Feature.MODIFICATION_DETECTION)
} subpackets.setKeyFlags(info.getKeyFlagsOf(key.keyIdentifier))
builder.applyCallback(callback) subpackets.setPreferredHashAlgorithms(hashAlgorithmPreferences)
secretKeyRing = subpackets.setPreferredSymmetricKeyAlgorithms(
injectCertification(secretKeyRing, sanitizedUserId, builder.build(sanitizedUserId)) symmetricAlgorithmPreferences)
key = PGPainless.getInstance().toKey(secretKeyRing) subpackets.setPreferredCompressionAlgorithms(
compressionAlgorithmPreferences)
subpackets.setPreferredAEADCiphersuites(
aeadAlgorithmPreferences)
callback?.modifyHashedSubpackets(subpackets)
subpacketGenerator
}
.setUnhashedSubpacketsFunction { subpacketGenerator ->
callback?.modifyUnhashedSubpackets(
SignatureSubpackets(subpacketGenerator))
subpacketGenerator
}
}
})
.done()
secretKeyRing = key.pgpSecretKeyRing
return this return this
} }

View file

@ -113,7 +113,9 @@ interface SelfSignatureSubpackets : BaseSignatureSubpackets {
fun setPreferredHashAlgorithms(algorithms: PreferredAlgorithms?): SelfSignatureSubpackets fun setPreferredHashAlgorithms(algorithms: PreferredAlgorithms?): SelfSignatureSubpackets
fun setPreferredAEADCiphersuites(aeadAlgorithms: Set<AEADCipherMode>): SelfSignatureSubpackets fun setPreferredAEADCiphersuites(
aeadAlgorithms: Collection<AEADCipherMode>
): SelfSignatureSubpackets
fun setPreferredAEADCiphersuites( fun setPreferredAEADCiphersuites(
algorithms: PreferredAEADCiphersuites.Builder? algorithms: PreferredAEADCiphersuites.Builder?

View file

@ -314,7 +314,7 @@ class SignatureSubpackets(
} }
override fun setPreferredAEADCiphersuites( override fun setPreferredAEADCiphersuites(
aeadAlgorithms: Set<AEADCipherMode> aeadAlgorithms: Collection<AEADCipherMode>
): SignatureSubpackets = ): SignatureSubpackets =
setPreferredAEADCiphersuites( setPreferredAEADCiphersuites(
PreferredAEADCiphersuites.builder(false).apply { PreferredAEADCiphersuites.builder(false).apply {