Expand the experiment
This commit is contained in:
parent
6f3d2cb9ef
commit
68b9496381
|
@ -0,0 +1,11 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package openpgp
|
||||
|
||||
/**
|
||||
* Filter `null` values from a [Map<K, V?>], turning it into a [Map<K, V>].
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <K, V> Map<K, V?>.filterNotNullValues(): Map<K, V> = filterValues { it != null } as Map<K, V>
|
|
@ -12,6 +12,13 @@ import org.bouncycastle.openpgp.PGPSignature
|
|||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.key.OpenPgpFingerprint
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
import java.util.*
|
||||
import kotlin.NoSuchElementException
|
||||
import kotlin.math.max
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
val PGPKeyRing.primaryPublicKey: PGPPublicKey
|
||||
get() = requireNotNull(publicKey).also { require(it.isMasterKey) }
|
||||
|
||||
/**
|
||||
* Return true, if this [PGPKeyRing] contains the subkey identified by the [SubkeyIdentifier].
|
||||
|
@ -72,9 +79,44 @@ fun PGPKeyRing.getPublicKeyFor(onePassSignature: PGPOnePassSignature): PGPPublic
|
|||
* Return the [OpenPgpFingerprint] of this OpenPGP key.
|
||||
*/
|
||||
val PGPKeyRing.openPgpFingerprint: OpenPgpFingerprint
|
||||
get() = OpenPgpFingerprint.of(this)
|
||||
get() = OpenPgpFingerprint.of(primaryPublicKey)
|
||||
|
||||
/**
|
||||
* Return this OpenPGP key as an ASCII armored String.
|
||||
*/
|
||||
fun PGPKeyRing.toAsciiArmor(): String = PGPainless.asciiArmor(this)
|
||||
fun PGPKeyRing.toAsciiArmor(): String = PGPainless.asciiArmor(this)
|
||||
|
||||
val PGPKeyRing.goodDirectKeySignatures: List<PGPSignature> by LazyPGPKeyRing {
|
||||
it.primaryPublicKey.goodDirectKeySignatures
|
||||
}
|
||||
|
||||
val PGPKeyRing.goodDirectKeySignature: PGPSignature? by LazyPGPKeyRing {
|
||||
it.primaryPublicKey.goodDirectKeySignature
|
||||
}
|
||||
|
||||
val PGPKeyRing.expirationDate: Date? by LazyPGPKeyRing {
|
||||
val dkExp = it.goodDirectKeySignature?.getKeyExpirationDate(it.primaryPublicKey.creationTime)
|
||||
val puExp = it.primaryPublicKey.goodUserIds[it.primaryPublicKey.primaryUserId]
|
||||
?.getKeyExpirationDate(it.primaryPublicKey.creationTime)
|
||||
|
||||
dkExp ?: return@LazyPGPKeyRing puExp // direct-key exp null ? -> userId exp
|
||||
puExp ?: return@LazyPGPKeyRing dkExp // userId exp null ? -> direct-key exp
|
||||
|
||||
return@LazyPGPKeyRing if (dkExp < puExp) dkExp else puExp // max direct-key exp, userId exp
|
||||
}
|
||||
|
||||
|
||||
internal class LazyPGPKeyRing<T>(val function: (PGPKeyRing) -> T) {
|
||||
private var value: Result<T>? = null
|
||||
|
||||
operator fun getValue(keys: PGPKeyRing, property: KProperty<*>): T {
|
||||
if (value == null) {
|
||||
value = try {
|
||||
Result.success(function(keys))
|
||||
} catch (e : Throwable) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
return value!!.getOrThrow()
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.bouncycastle.extensions
|
||||
|
||||
import openpgp.filterNotNullValues
|
||||
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers
|
||||
import org.bouncycastle.bcpg.ECDHPublicBCPGKey
|
||||
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey
|
||||
|
@ -12,11 +13,8 @@ import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil
|
|||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm
|
||||
import org.pgpainless.algorithm.SignatureType
|
||||
import org.pgpainless.decryption_verification.SignatureVerification
|
||||
import org.pgpainless.exception.SignatureValidationException
|
||||
import org.pgpainless.key.OpenPgpFingerprint
|
||||
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
||||
import org.pgpainless.signature.consumer.SignatureVerifier
|
||||
|
@ -55,9 +53,9 @@ val PGPPublicKey.publicKeyAlgorithm: PublicKeyAlgorithm
|
|||
/**
|
||||
* Return the [OpenPgpFingerprint] of this key.
|
||||
*/
|
||||
val PGPPublicKey.openPgpFingerprint: OpenPgpFingerprint by Lazy { OpenPgpFingerprint.of(it) }
|
||||
val PGPPublicKey.openPgpFingerprint: OpenPgpFingerprint by LazyPGPPublicKey { OpenPgpFingerprint.of(it) }
|
||||
|
||||
val PGPPublicKey.goodDirectKeySignatures: List<PGPSignature> by Lazy { key ->
|
||||
val PGPPublicKey.goodDirectKeySignatures: List<PGPSignature> by LazyPGPPublicKey { key ->
|
||||
key.getSignaturesOfType(SignatureType.DIRECT_KEY.code)
|
||||
.asSequence()
|
||||
.filter { it.keyID == key.keyID }
|
||||
|
@ -69,13 +67,13 @@ val PGPPublicKey.goodDirectKeySignatures: List<PGPSignature> by Lazy { key ->
|
|||
.toList()
|
||||
}
|
||||
|
||||
val PGPPublicKey.goodDirectKeySignature: PGPSignature? by Lazy {
|
||||
val PGPPublicKey.goodDirectKeySignature: PGPSignature? by LazyPGPPublicKey {
|
||||
it.goodDirectKeySignatures
|
||||
.sortedBy { sig -> sig.creationTime }
|
||||
.lastOrNull()
|
||||
}
|
||||
|
||||
val PGPPublicKey.goodKeyRevocations: List<PGPSignature> by Lazy { key ->
|
||||
val PGPPublicKey.goodKeyRevocations: List<PGPSignature> by LazyPGPPublicKey { key ->
|
||||
key.getSignaturesOfType(SignatureType.KEY_REVOCATION.code)
|
||||
.asSequence()
|
||||
.filter { it.keyID == key.keyID }
|
||||
|
@ -87,13 +85,34 @@ val PGPPublicKey.goodKeyRevocations: List<PGPSignature> by Lazy { key ->
|
|||
.toList()
|
||||
}
|
||||
|
||||
val PGPPublicKey.goodKeyRevocation: PGPSignature? by Lazy {
|
||||
val PGPPublicKey.goodKeyRevocation: PGPSignature? by LazyPGPPublicKey {
|
||||
it.goodKeyRevocations
|
||||
.sortedBy { sig -> sig.creationTime }
|
||||
.lastOrNull()
|
||||
}
|
||||
|
||||
internal class Lazy<T>(val function: (PGPPublicKey) -> T) {
|
||||
val PGPPublicKey.goodUserIds: Map<String, PGPSignature> by LazyPGPPublicKey { it.getGoodUserIds(Date()) }
|
||||
|
||||
fun PGPPublicKey.getGoodUserIds(referenceTime: Date): Map<String, PGPSignature> {
|
||||
return userIDs.asSequence().associateWith { userId ->
|
||||
getSignaturesForID(userId).asSequence()
|
||||
.filter { it.wasIssuedBy(this) }
|
||||
.filter { it.isCertification }
|
||||
.filter { it.isEffective(referenceTime)}
|
||||
.sortedBy { it.creationTime }
|
||||
.lastOrNull()
|
||||
}.filterNotNullValues()
|
||||
}
|
||||
|
||||
val PGPPublicKey.primaryUserId: String? by LazyPGPPublicKey { it.getPrimaryUserId(Date()) }
|
||||
|
||||
fun PGPPublicKey.getPrimaryUserId(referenceTime: Date): String? =
|
||||
getGoodUserIds(referenceTime).entries
|
||||
.sortedBy { it.value.creationTime }
|
||||
.lastOrNull { it.value.hashedSubPackets.isPrimaryUserID }?.key // latest primary User ID
|
||||
?: getGoodUserIds(referenceTime).keys.firstOrNull() // else first User ID
|
||||
|
||||
internal class LazyPGPPublicKey<T>(val function: (PGPPublicKey) -> T) {
|
||||
private var value: Result<T>? = null
|
||||
|
||||
operator fun getValue(pgpPublicKey: PGPPublicKey, property: KProperty<*>): T {
|
||||
|
|
|
@ -36,6 +36,9 @@ val PGPSignature.signatureExpirationDate: Date?
|
|||
fun PGPSignature.isExpired(referenceTime: Date = Date()) =
|
||||
signatureExpirationDate?.let { referenceTime >= it } ?: false
|
||||
|
||||
fun PGPSignature.isEffective(referenceTime: Date = Date()) =
|
||||
!isExpired(referenceTime) && creationTime < referenceTime
|
||||
|
||||
/**
|
||||
* Return the key-ID of the issuer, determined by examining the IssuerKeyId and IssuerFingerprint
|
||||
* subpackets of the signature.
|
||||
|
|
Loading…
Reference in New Issue