Rework return types and improve method visibility

This commit is contained in:
Paul Schaub 2024-02-22 00:54:58 +01:00
parent 9215987f24
commit 94dfd6633e
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
2 changed files with 227 additions and 233 deletions

View File

@ -35,7 +35,6 @@ class KeyRingTemplates {
if (userId != null) { if (userId != null) {
addUserId(userId) addUserId(userId)
} }
keyPair
} }
.addSigningSubkey(KeyType.RSA(length)) .addSigningSubkey(KeyType.RSA(length))
.addEncryptionSubkey(KeyType.RSA(length)) .addEncryptionSubkey(KeyType.RSA(length))
@ -87,7 +86,6 @@ class KeyRingTemplates {
if (userId != null) { if (userId != null) {
addUserId(userId) addUserId(userId)
} }
keyPair
} }
.build(passphrase) .build(passphrase)
@ -131,7 +129,6 @@ class KeyRingTemplates {
if (userId != null) { if (userId != null) {
addUserId(userId) addUserId(userId)
} }
keyPair
} }
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.build(passphrase) .build(passphrase)
@ -172,7 +169,6 @@ class KeyRingTemplates {
if (userId != null) { if (userId != null) {
addUserId(userId) addUserId(userId)
} }
keyPair
} }
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))

View File

@ -21,6 +21,8 @@ import org.pgpainless.algorithm.CertificationType
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.generation.DefinePrimaryKey.ApplyToPrimaryKey
import org.pgpainless.key.generation.DefineSubkeys.ApplyToSubkey
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.eddsa.EdDSACurve import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.key.generation.type.rsa.RsaLength import org.pgpainless.key.generation.type.rsa.RsaLength
@ -34,6 +36,10 @@ import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
typealias PrimaryKeyBlock = (ApplyToPrimaryKey.() -> Unit)
typealias SubkeyBlock = (ApplyToSubkey.() -> Unit)
/** /**
* API for generating OpenPGP keys. The API allows to generate keys of different OpenPGP protocol * API for generating OpenPGP keys. The API allows to generate keys of different OpenPGP protocol
* versions (currently only v4). The API is divided into an opinionated and unopinionated * versions (currently only v4). The API is divided into an opinionated and unopinionated
@ -135,14 +141,14 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* *
* @return altered [PGPKeyPair] * @return altered [PGPKeyPair]
*/ */
protected abstract fun applyToPrimaryKey( protected abstract fun invokeOnPrimaryKey(
primaryKey: PGPKeyPair, primaryKey: PGPKeyPair,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? block: PrimaryKeyBlock?
): PGPKeyPair ): PGPKeyPair
/** /**
* Define the primary key for the OpenPGP key. The [applyToPrimaryKey] function block can be * Define the primary key for the OpenPGP key. The [block] function block can be used to add
* used to add UserIDs and preferences to the key. Example: * UserIDs and preferences to the key. Example:
* ``` * ```
* setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { * setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
* addDirectKeySignature(...) * addDirectKeySignature(...)
@ -154,7 +160,7 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* @param type primary key type * @param type primary key type
* @param keyFlags list of key flags that denote the primary keys capabilities * @param keyFlags list of key flags that denote the primary keys capabilities
* @param creationTime creation time of the primary key * @param creationTime creation time of the primary key
* @param applyToPrimaryKey function block to apply to the primary key * @param block function block to apply to the primary key
* @return subkey builder * @return subkey builder
*/ */
@JvmOverloads @JvmOverloads
@ -162,17 +168,17 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
type: KeyType, type: KeyType,
keyFlags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER), keyFlags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER),
creationTime: Date = this.creationTime, creationTime: Date = this.creationTime,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? = null block: PrimaryKeyBlock? = null
): O = doSetPrimaryKey(type, keyFlags, creationTime, applyToPrimaryKey) ): O = doSetPrimaryKey(type, keyFlags, creationTime, block)
fun setPrimaryKey(type: KeyType, applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?): O = fun setPrimaryKey(type: KeyType, block: PrimaryKeyBlock?): O =
setPrimaryKey(type, listOf(KeyFlag.CERTIFY_OTHER), this.creationTime, applyToPrimaryKey) setPrimaryKey(type, listOf(KeyFlag.CERTIFY_OTHER), this.creationTime, block)
protected abstract fun doSetPrimaryKey( protected abstract fun doSetPrimaryKey(
type: KeyType, type: KeyType,
keyFlags: List<KeyFlag>?, keyFlags: List<KeyFlag>?,
creationTime: Date, creationTime: Date,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? block: PrimaryKeyBlock?
): O ): O
/** /**
@ -201,7 +207,10 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* @param builder builder instance that generated the primary key * @param builder builder instance that generated the primary key
*/ */
abstract class ApplyToPrimaryKey abstract class ApplyToPrimaryKey
internal constructor(var keyPair: PGPKeyPair, val builder: DefinePrimaryKey<*>) { protected constructor(
protected var keyPair: PGPKeyPair,
protected val builder: DefinePrimaryKey<*>
) {
/** /**
* Add a UserID to the primary key. * Add a UserID to the primary key.
@ -213,8 +222,8 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* [CertificationType.POSITIVE] * [CertificationType.POSITIVE]
* @param hashAlgorithm hash algorithm to be used during signature calculation * @param hashAlgorithm hash algorithm to be used during signature calculation
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified key pair
*/ */
@JvmOverloads
fun addUserId( fun addUserId(
userId: CharSequence, userId: CharSequence,
subpacketsCallback: SelfSignatureSubpackets.Callback = builder.preferencesSubpackets(), subpacketsCallback: SelfSignatureSubpackets.Callback = builder.preferencesSubpackets(),
@ -222,12 +231,12 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
hashAlgorithm: HashAlgorithm = hashAlgorithm: HashAlgorithm =
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
bindingTime: Date = builder.creationTime bindingTime: Date = builder.creationTime
): PGPKeyPair { ) {
builder.sanitizeHashAlgorithm(hashAlgorithm) builder.sanitizeHashAlgorithm(hashAlgorithm)
builder.sanitizeBindingTime(bindingTime, keyPair) builder.sanitizeBindingTime(bindingTime, keyPair)
val callback = builder.userIdSubpackets(keyPair).then(subpacketsCallback) val callback = builder.userIdSubpackets(keyPair).then(subpacketsCallback)
return doAddUserId(userId, callback, certificationType, hashAlgorithm, bindingTime) doAddUserId(userId, callback, certificationType, hashAlgorithm, bindingTime)
} }
/** /**
@ -238,7 +247,6 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* @param certificationType signature type of the binding signature (certification level) * @param certificationType signature type of the binding signature (certification level)
* @param hashAlgorithm hash algorithm to be used to calculate the signature * @param hashAlgorithm hash algorithm to be used to calculate the signature
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified primary key
*/ */
protected abstract fun doAddUserId( protected abstract fun doAddUserId(
userId: CharSequence, userId: CharSequence,
@ -246,7 +254,7 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
certificationType: CertificationType, certificationType: CertificationType,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair )
/** /**
* Add a UserAttribute to the primary key. * Add a UserAttribute to the primary key.
@ -259,8 +267,8 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* [CertificationType.POSITIVE] * [CertificationType.POSITIVE]
* @param hashAlgorithm hash algorithm to be used during signature calculation * @param hashAlgorithm hash algorithm to be used during signature calculation
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified key pair
*/ */
@JvmOverloads
fun addUserAttribute( fun addUserAttribute(
userAttribute: PGPUserAttributeSubpacketVector, userAttribute: PGPUserAttributeSubpacketVector,
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(), subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
@ -268,12 +276,12 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
hashAlgorithm: HashAlgorithm = hashAlgorithm: HashAlgorithm =
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
bindingTime: Date = builder.creationTime bindingTime: Date = builder.creationTime
): PGPKeyPair { ) {
builder.sanitizeHashAlgorithm(hashAlgorithm) builder.sanitizeHashAlgorithm(hashAlgorithm)
builder.sanitizeBindingTime(bindingTime, keyPair) builder.sanitizeBindingTime(bindingTime, keyPair)
val callback = builder.userAttributeSubpackets(keyPair).then(subpacketsCallback) val callback = builder.userAttributeSubpackets(keyPair).then(subpacketsCallback)
return doAddUserAttribute( doAddUserAttribute(
userAttribute, callback, certificationType, hashAlgorithm, bindingTime) userAttribute, callback, certificationType, hashAlgorithm, bindingTime)
} }
@ -285,7 +293,6 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* @param certificationType signature type (certification level) * @param certificationType signature type (certification level)
* @param hashAlgorithm hash algorithm to calculate the binding signature with * @param hashAlgorithm hash algorithm to calculate the binding signature with
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified primary key
*/ */
protected abstract fun doAddUserAttribute( protected abstract fun doAddUserAttribute(
userAttribute: PGPUserAttributeSubpacketVector, userAttribute: PGPUserAttributeSubpacketVector,
@ -293,7 +300,7 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
certificationType: CertificationType, certificationType: CertificationType,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair )
/** /**
* Add a JPEG image as UserAttribute to the primary key. This may for example be a profile * Add a JPEG image as UserAttribute to the primary key. This may for example be a profile
@ -305,8 +312,8 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* [CertificationType.POSITIVE] * [CertificationType.POSITIVE]
* @param hashAlgorithm hash algorithm to be used during signature calculation * @param hashAlgorithm hash algorithm to be used during signature calculation
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified key pair
*/ */
@JvmOverloads
fun addImageAttribute( fun addImageAttribute(
jpegInputStream: InputStream, jpegInputStream: InputStream,
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(), subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
@ -314,7 +321,7 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
hashAlgorithm: HashAlgorithm = hashAlgorithm: HashAlgorithm =
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
bindingTime: Date = builder.creationTime bindingTime: Date = builder.creationTime
): PGPKeyPair = ) =
addUserAttribute( addUserAttribute(
PGPUserAttributeSubpacketVectorGenerator() PGPUserAttributeSubpacketVectorGenerator()
.apply { .apply {
@ -335,20 +342,20 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* subpackets. * subpackets.
* @param hashAlgorithm hash algorithm to calculate the signature with * @param hashAlgorithm hash algorithm to calculate the signature with
* @param bindingTime signature creation time * @param bindingTime signature creation time
* @return modified primary key
*/ */
@JvmOverloads
fun addDirectKeySignature( fun addDirectKeySignature(
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(), subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
hashAlgorithm: HashAlgorithm = hashAlgorithm: HashAlgorithm =
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
bindingTime: Date = builder.creationTime bindingTime: Date = builder.creationTime
): PGPKeyPair { ) {
builder.sanitizeHashAlgorithm(hashAlgorithm) builder.sanitizeHashAlgorithm(hashAlgorithm)
builder.sanitizeBindingTime(bindingTime, keyPair) builder.sanitizeBindingTime(bindingTime, keyPair)
skipDefaultSignature() skipDefaultSignature()
val callback = builder.directKeySignatureSubpackets().then(subpacketsCallback) val callback = builder.directKeySignatureSubpackets().then(subpacketsCallback)
return doAddDirectKeySignature(callback, hashAlgorithm, bindingTime) doAddDirectKeySignature(callback, hashAlgorithm, bindingTime)
} }
/** /**
@ -357,51 +364,18 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
* @param subpacketsCallback callback to modify the direct-key signatures subpackets with * @param subpacketsCallback callback to modify the direct-key signatures subpackets with
* @param hashAlgorithm hash algorithm to calculate the signature with * @param hashAlgorithm hash algorithm to calculate the signature with
* @param bindingTime creation time for the direct-key signature * @param bindingTime creation time for the direct-key signature
* @return modified primary key
*/ */
protected abstract fun doAddDirectKeySignature( protected abstract fun doAddDirectKeySignature(
subpacketsCallback: SelfSignatureSubpackets.Callback, subpacketsCallback: SelfSignatureSubpackets.Callback,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair )
/** Do not add the default direct-key signature automatically. */ /** Do not add the default direct-key signature automatically. */
fun skipDefaultSignature(): PGPKeyPair { fun skipDefaultSignature(): PGPKeyPair {
builder.skipDefaultDirectKeySignature = true builder.skipDefaultDirectKeySignature = true
return keyPair return keyPair
} }
/**
* Schedule the execution of another [ApplyToPrimaryKey] function instance right after this
* one has been executed.
*
* @param other second instance
* @return modified key pair after this and [other] have been executed
*/
abstract fun then(other: (ApplyToPrimaryKey.() -> PGPKeyPair)?): PGPKeyPair
}
}
/** Implementation of [DefinePrimaryKey] build for version 4 OpenPGP keys. */
abstract class DefinePrimaryKeyV4<O : DefineSubkeys<O>>(
policy: Policy,
creationTime: Date,
preferences: AlgorithmSuite
) : DefinePrimaryKey<O>(policy, creationTime, preferences) {
override fun generatePrimaryKey(type: KeyType, creationTime: Date): PGPKeyPair {
return OpenPgpKeyPairGenerator.V4().generatePrimaryKey(type, creationTime)
}
override fun applyToPrimaryKey(
primaryKey: PGPKeyPair,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)?
): PGPKeyPair {
return if (applyToPrimaryKey == null) {
primaryKey
} else {
ApplyToPrimaryKeyV4(primaryKey, this).applyToPrimaryKey()
}
} }
} }
@ -427,34 +401,32 @@ internal constructor(
* *
* @param type subkey type * @param type subkey type
* @param creationTime creation time of the subkey * @param creationTime creation time of the subkey
* @param applyToSubkey function to apply to the subkey. Used to add binding signatures. * @param block function to apply to the subkey. Used to add binding signatures.
* @return this * @return this
*/ */
@JvmOverloads @JvmOverloads
fun addSubkey( fun addSubkey(
type: KeyType, type: KeyType,
creationTime: Date = this.creationTime, creationTime: Date = this.creationTime,
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? = null block: SubkeyBlock? = null
): B = ): B =
apply { apply {
sanitizeSubkeyCreationTime(creationTime, primaryKey) sanitizeSubkeyCreationTime(creationTime, primaryKey)
val subkey = generateSubkey(type, creationTime) var subkey = generateSubkey(type, creationTime)
subkeys.add(applyToSubkey(subkey, applyToSubkey)) subkey = invokeOnSubkey(subkey, block)
subkeys.add(subkey)
} }
as B as B
/** /**
* Apply the given [applyToSubkey] function block to the given [subkey]. * Apply the given [block] function block to the given [subkey].
* *
* @param subkey subkey * @param subkey subkey
* @param applyToSubkey function block * @param block function block
* @return modified subkey * @return modified subkey
*/ */
protected abstract fun applyToSubkey( protected abstract fun invokeOnSubkey(subkey: PGPKeyPair, block: SubkeyBlock?): PGPKeyPair
subkey: PGPKeyPair,
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)?
): PGPKeyPair
/** /**
* Generate an OpenPGP subkey. * Generate an OpenPGP subkey.
@ -527,9 +499,9 @@ internal constructor(
*/ */
abstract class ApplyToSubkey abstract class ApplyToSubkey
internal constructor( internal constructor(
val primaryKey: PGPKeyPair, protected val primaryKey: PGPKeyPair,
var subkey: PGPKeyPair, protected var subkey: PGPKeyPair,
val builder: DefineSubkeys<*> protected val builder: DefineSubkeys<*>
) { ) {
/** /**
@ -540,84 +512,151 @@ internal constructor(
* @param bindingTime creation time of the binding signature * @param bindingTime creation time of the binding signature
* @return modified subkey pair * @return modified subkey pair
*/ */
@JvmOverloads
fun addBindingSignature( fun addBindingSignature(
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(), subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop(),
hashAlgorithm: HashAlgorithm = hashAlgorithm: HashAlgorithm =
builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm, builder.policy.certificationSignatureHashAlgorithmPolicy.defaultHashAlgorithm,
bindingTime: Date = subkey.publicKey.creationTime bindingTime: Date = subkey.publicKey.creationTime
): PGPKeyPair { ) {
builder.sanitizeHashAlgorithm(hashAlgorithm) builder.sanitizeHashAlgorithm(hashAlgorithm)
builder.sanitizeBindingTime(bindingTime, subkey) builder.sanitizeBindingTime(bindingTime, subkey)
return doAddBindingSignature(subpacketsCallback, hashAlgorithm, bindingTime) doAddBindingSignature(subpacketsCallback, hashAlgorithm, bindingTime)
} }
abstract fun doAddBindingSignature( abstract fun doAddBindingSignature(
subpacketsCallback: SelfSignatureSubpackets.Callback, subpacketsCallback: SelfSignatureSubpackets.Callback,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair )
} }
} }
/** /**
* Implementation of [DefineSubkeys] tailored to version 4 OpenPGP keys. * Implementation of the [ApplyToSubkey] function tailored to OpenPGP v4 keys.
* *
* @param primaryKey primary key * @param primaryKey primary key pair
* @param policy policy * @param subkey subkey pair
* @param creationTime creation time of the OpenPGP key * @param builder builder instance that generated the subkey
* @param subkeys list of already added subkeys
*/ */
abstract class DefineSubkeysV4<O : DefineSubkeys<O>>( class ApplyToSubkeyV4
primaryKey: PGPKeyPair, internal constructor(primaryKey: PGPKeyPair, subkey: PGPKeyPair, builder: DefineSubkeys<*>) :
policy: Policy, ApplyToSubkey(primaryKey, subkey, builder) {
creationTime: Date,
subkeys: List<PGPKeyPair>
) : DefineSubkeys<O>(primaryKey, policy, creationTime, subkeys.toMutableList()) {
override fun generateSubkey(type: KeyType, creationTime: Date): PGPKeyPair { override fun doAddBindingSignature(
return OpenPgpKeyPairGenerator.V4().generateSubkey(type, creationTime) subpacketsCallback: SelfSignatureSubpackets.Callback,
hashAlgorithm: HashAlgorithm,
bindingTime: Date
) {
val sigBuilder = SubkeyBindingSignatureBuilder(primaryKey, hashAlgorithm)
sigBuilder.applyCallback(
// sets key flags
subpacketsCallback
.then(setCreationTime(bindingTime))
// adds back sig if key flags contain sign or certify
.then(addBackSignatureIfNecessary(hashAlgorithm)))
val sig = sigBuilder.build(subkey)
subkey = subkey.plusCertification(sig)
} }
override fun applyToSubkey( /**
subkey: PGPKeyPair, * Return a [SelfSignatureSubpackets.Callback] that sets the signature creation time to the
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? * given [bindingTime].
): PGPKeyPair { *
return if (applyToSubkey == null) { * @param bindingTime signature creation time
subkey * @return callback
} else { */
ApplyToSubkeyV4(primaryKey, subkey, this).applyToSubkey() private fun setCreationTime(bindingTime: Date): SelfSignatureSubpackets.Callback {
return SelfSignatureSubpackets.applyHashed { setSignatureCreationTime(bindingTime) }
}
/**
* Return a [SelfSignatureSubpackets.Callback] that adds a PrimaryKeyBinding Signature
* (back-signature) if the subkey is signing capable.
*
* @param hashAlgorithm hash algorithm to calculate the back-sig with
* @return callback
*/
private fun addBackSignatureIfNecessary(
hashAlgorithm: HashAlgorithm
): SelfSignatureSubpackets.Callback {
return SelfSignatureSubpackets.applyHashed {
if (isSigningCapable(getKeyFlags())) {
addEmbeddedSignature(
PrimaryKeyBindingSignatureBuilder(subkey, hashAlgorithm).build(primaryKey))
}
} }
} }
override fun build(protector: SecretKeyRingProtector): PGPSecretKeyRing { /**
return PGPSecretKeyRing( * Return `true` if the given [flags] list contains either [KeyFlag.SIGN_DATA] or
buildList { * [KeyFlag.CERTIFY_OTHER].
// Primary Key *
add( * @return true if contains SIGN_DATA or CERTIFY_OTHER
PGPSecretKey( */
primaryKey.privateKey, private fun isSigningCapable(flags: List<KeyFlag>?): Boolean =
primaryKey.publicKey, flags.orEmpty().contains(KeyFlag.SIGN_DATA) ||
ImplementationFactory.getInstance().v4FingerprintCalculator, flags.orEmpty().contains(KeyFlag.CERTIFY_OTHER)
true,
protector.getEncryptor(primaryKey.keyID)))
// Subkeys /**
subkeys.forEach { * Implementation of [DefineSubkeys] tailored to version 4 OpenPGP keys.
*
* @param primaryKey primary key
* @param policy policy
* @param creationTime creation time of the OpenPGP key
* @param subkeys list of already added subkeys
*/
abstract class DefineSubkeysV4<O : DefineSubkeys<O>>(
primaryKey: PGPKeyPair,
policy: Policy,
creationTime: Date,
subkeys: List<PGPKeyPair>
) : DefineSubkeys<O>(primaryKey, policy, creationTime, subkeys.toMutableList()) {
override fun generateSubkey(type: KeyType, creationTime: Date): PGPKeyPair {
return OpenPgpKeyPairGenerator.V4().generateSubkey(type, creationTime)
}
override fun invokeOnSubkey(subkey: PGPKeyPair, block: SubkeyBlock?): PGPKeyPair {
return with(ApplyToSubkeyV4(primaryKey, subkey, this)) {
if (block != null) {
block()
}
this.subkey
}
}
override fun build(protector: SecretKeyRingProtector): PGPSecretKeyRing {
return PGPSecretKeyRing(
buildList {
// Primary Key
add( add(
PGPSecretKey( PGPSecretKey(
it.privateKey, primaryKey.privateKey,
it.publicKey, primaryKey.publicKey,
ImplementationFactory.getInstance().v4FingerprintCalculator, ImplementationFactory.getInstance().v4FingerprintCalculator,
false, true,
protector.getEncryptor(it.keyID))) protector.getEncryptor(primaryKey.keyID)))
}
}) // Subkeys
subkeys.forEach {
add(
PGPSecretKey(
it.privateKey,
it.publicKey,
ImplementationFactory.getInstance().v4FingerprintCalculator,
false,
protector.getEncryptor(it.keyID)))
}
})
}
} }
} }
/** /**
* Implementation of an opinionated [DefinePrimaryKeyV4] builder. * Implementation of an opinionated [ApplyToPrimaryKeyV4.DefinePrimaryKeyV4] builder.
* *
* @param policy policy for algorithm compliance and fallbacks * @param policy policy for algorithm compliance and fallbacks
* @param creationTime creation time of the primary key * @param creationTime creation time of the primary key
@ -625,7 +664,8 @@ abstract class DefineSubkeysV4<O : DefineSubkeys<O>>(
*/ */
class OpinionatedDefinePrimaryKeyV4 class OpinionatedDefinePrimaryKeyV4
internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) : internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) :
DefinePrimaryKeyV4<OpinionatedDefineSubkeysV4>(policy, creationTime, preferences) { ApplyToPrimaryKeyV4.DefinePrimaryKeyV4<OpinionatedDefineSubkeysV4>(
policy, creationTime, preferences) {
/** /**
* Return an unopinionated implementation of this builder. * Return an unopinionated implementation of this builder.
@ -681,7 +721,7 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
type: KeyType, type: KeyType,
keyFlags: List<KeyFlag>?, keyFlags: List<KeyFlag>?,
creationTime: Date, creationTime: Date,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? block: PrimaryKeyBlock?
): OpinionatedDefineSubkeysV4 { ): OpinionatedDefineSubkeysV4 {
// Check algorithm is signing capable // Check algorithm is signing capable
require(type.algorithm.isSigningCapable()) { "Primary Key MUST be capable of signing." } require(type.algorithm.isSigningCapable()) { "Primary Key MUST be capable of signing." }
@ -695,15 +735,17 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
// Remember flags for DK and UID signatures // Remember flags for DK and UID signatures
this.keyFlags = keyFlags this.keyFlags = keyFlags
var primaryKey = generatePrimaryKey(type, creationTime)
// Add user-provided signatures // Add user-provided signatures
var key = applyToPrimaryKey(generatePrimaryKey(type, creationTime), applyToPrimaryKey) primaryKey = invokeOnPrimaryKey(primaryKey, block)
// If no DK sig has been added by user, add default DK sig // If no DK sig has been added by user, add default DK sig
if (!skipDefaultDirectKeySignature) { if (!skipDefaultDirectKeySignature) {
key = applyToPrimaryKey(key) { addDirectKeySignature(preferencesSubpackets()) } primaryKey =
invokeOnPrimaryKey(primaryKey) { addDirectKeySignature(preferencesSubpackets()) }
} }
return OpinionatedDefineSubkeysV4(key, policy, creationTime) return OpinionatedDefineSubkeysV4(primaryKey, policy, creationTime)
} }
override fun sanitizeHashAlgorithm(algorithm: HashAlgorithm) { override fun sanitizeHashAlgorithm(algorithm: HashAlgorithm) {
@ -723,7 +765,7 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
} }
/** /**
* Implementation of an unopinionated [DefinePrimaryKeyV4] builder. * Implementation of an unopinionated [ApplyToPrimaryKeyV4.DefinePrimaryKeyV4] builder.
* *
* @param policy policy * @param policy policy
* @param creationTime creation time of the primary key * @param creationTime creation time of the primary key
@ -731,7 +773,8 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
*/ */
class UnopinionatedDefinePrimaryKeyV4 class UnopinionatedDefinePrimaryKeyV4
internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) : internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmSuite) :
DefinePrimaryKeyV4<UnopinionatedDefineSubkeysV4>(policy, creationTime, preferences) { ApplyToPrimaryKeyV4.DefinePrimaryKeyV4<UnopinionatedDefineSubkeysV4>(
policy, creationTime, preferences) {
/** /**
* Constructor for an unopinionated variant of the passed in [OpinionatedDefinePrimaryKeyV4]. * Constructor for an unopinionated variant of the passed in [OpinionatedDefinePrimaryKeyV4].
@ -757,22 +800,20 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
type: KeyType, type: KeyType,
keyFlags: List<KeyFlag>?, keyFlags: List<KeyFlag>?,
creationTime: Date, creationTime: Date,
applyToPrimaryKey: (ApplyToPrimaryKey.() -> PGPKeyPair)? block: PrimaryKeyBlock?
): UnopinionatedDefineSubkeysV4 { ): UnopinionatedDefineSubkeysV4 {
// Remember flags for DK and UID signatures
// this.keyFlags = keyFlags
// Add user-provided signatures // Add user-provided signatures
val key = applyToPrimaryKey(generatePrimaryKey(type, creationTime), applyToPrimaryKey) var primaryKey = generatePrimaryKey(type, creationTime)
primaryKey = invokeOnPrimaryKey(primaryKey, block)
// return builder for adding subkeys // return builder for adding subkeys
return UnopinionatedDefineSubkeysV4(key, policy, creationTime) return UnopinionatedDefineSubkeysV4(primaryKey, policy, creationTime)
} }
} }
/** /**
* Implementation of an opinionated [DefineSubkeysV4] builder. * Implementation of an opinionated [ApplyToSubkeyV4.DefineSubkeysV4] builder.
* *
* @param primaryKey version 4 OpenPGP primary key * @param primaryKey version 4 OpenPGP primary key
* @param policy policy * @param policy policy
@ -780,7 +821,8 @@ internal constructor(policy: Policy, creationTime: Date, preferences: AlgorithmS
*/ */
class OpinionatedDefineSubkeysV4 class OpinionatedDefineSubkeysV4
internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date) : internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date) :
DefineSubkeysV4<OpinionatedDefineSubkeysV4>(primaryKey, policy, creationTime, listOf()) { ApplyToSubkeyV4.DefineSubkeysV4<OpinionatedDefineSubkeysV4>(
primaryKey, policy, creationTime, listOf()) {
/** /**
* Return an unopinionated implementation of this builder. * Return an unopinionated implementation of this builder.
@ -794,34 +836,54 @@ internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date)
* *
* @param type signing key type * @param type signing key type
* @param creationTime creation time of the signing subkey * @param creationTime creation time of the signing subkey
* @param applyToSubkey function block to add binding signatures to the subkey * @param block function block to add binding signatures to the subkey
*/ */
@JvmOverloads
fun addSigningSubkey( fun addSigningSubkey(
type: KeyType, type: KeyType,
creationTime: Date = this.creationTime, creationTime: Date = this.creationTime,
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? = { block: SubkeyBlock? = {
addBindingSignature( addBindingSignature(
SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) }) SelfSignatureSubpackets.applyHashed { setKeyFlags(KeyFlag.SIGN_DATA) })
} }
) = addSubkey(type, creationTime, applyToSubkey) ) = addSubkey(type, creationTime, block)
/**
* Add a subkey for signing messages to the OpenPGP key.
*
* @param type signing key type
* @param block function block to add binding signatures to the subkey
*/
fun addSigningSubkey(type: KeyType, block: SubkeyBlock?) =
addSigningSubkey(type, this.creationTime, block)
/** /**
* Add a subkey for message encryption to the OpenPGP key. * Add a subkey for message encryption to the OpenPGP key.
* *
* @param type encryption key type * @param type encryption key type
* @param creationTime creation time of the encryption key * @param creationTime creation time of the encryption key
* @param applyToSubkey function block to add binding signatures to the subkey * @param block function block to add binding signatures to the subkey
*/ */
@JvmOverloads
fun addEncryptionSubkey( fun addEncryptionSubkey(
type: KeyType, type: KeyType,
creationTime: Date = this.creationTime, creationTime: Date = this.creationTime,
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)? = { block: SubkeyBlock? = {
addBindingSignature( addBindingSignature(
SelfSignatureSubpackets.applyHashed { SelfSignatureSubpackets.applyHashed {
setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE) setKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
}) })
} }
) = addSubkey(type, creationTime, applyToSubkey) ) = addSubkey(type, creationTime, block)
/**
* Add a subkey for message encryption to the OpenPGP key.
*
* @param type encryption key type
* @param block function block to add binding signatures to the subkey
*/
fun addEncryptionSubkey(type: KeyType, block: SubkeyBlock?) =
addEncryptionSubkey(type, this.creationTime, block)
override fun sanitizeHashAlgorithm(algorithm: HashAlgorithm) { override fun sanitizeHashAlgorithm(algorithm: HashAlgorithm) {
require(policy.certificationSignatureHashAlgorithmPolicy.isAcceptable(algorithm)) { require(policy.certificationSignatureHashAlgorithmPolicy.isAcceptable(algorithm)) {
@ -848,7 +910,7 @@ internal constructor(primaryKey: PGPKeyPair, policy: Policy, creationTime: Date)
} }
/** /**
* Unopinionated implementation of [DefineSubkeysV4]. * Unopinionated implementation of [ApplyToSubkeyV4.DefineSubkeysV4].
* *
* @param primaryKey primary key of the OpenPGP key * @param primaryKey primary key of the OpenPGP key
* @param policy policy * @param policy policy
@ -861,7 +923,9 @@ internal constructor(
policy: Policy, policy: Policy,
creationTime: Date, creationTime: Date,
subkeys: List<PGPKeyPair> = mutableListOf() subkeys: List<PGPKeyPair> = mutableListOf()
) : DefineSubkeysV4<UnopinionatedDefineSubkeysV4>(primaryKey, policy, creationTime, subkeys) { ) :
ApplyToSubkeyV4.DefineSubkeysV4<UnopinionatedDefineSubkeysV4>(
primaryKey, policy, creationTime, subkeys) {
/** /**
* Constructor to build an unopinionated variant of the given [OpinionatedDefineSubkeysV4]. * Constructor to build an unopinionated variant of the given [OpinionatedDefineSubkeysV4].
@ -873,25 +937,14 @@ internal constructor(
) : this( ) : this(
opinionated.primaryKey, opinionated.policy, opinionated.creationTime, opinionated.subkeys) opinionated.primaryKey, opinionated.policy, opinionated.creationTime, opinionated.subkeys)
override fun applyToSubkey(
subkey: PGPKeyPair,
applyToSubkey: (ApplyToSubkey.() -> PGPKeyPair)?
): PGPKeyPair {
return if (applyToSubkey == null) {
subkey
} else {
ApplyToSubkeyV4(primaryKey, subkey, this).applyToSubkey()
}
}
override fun generateSubkey(type: KeyType, creationTime: Date): PGPKeyPair { override fun generateSubkey(type: KeyType, creationTime: Date): PGPKeyPair {
return OpenPgpKeyPairGenerator.V4().generateSubkey(type, creationTime) return OpenPgpKeyPairGenerator.V4().generateSubkey(type, creationTime)
} }
} }
/** Implementation of [ApplyToPrimaryKey] tailored to version 4 OpenPGP keys. */ /** Implementation of [DefinePrimaryKey.ApplyToPrimaryKey] tailored to version 4 OpenPGP keys. */
class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: DefinePrimaryKey<*>) : class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: DefinePrimaryKey<*>) :
DefinePrimaryKey.ApplyToPrimaryKey(keyPair, builder) { ApplyToPrimaryKey(keyPair, builder) {
override fun doAddUserId( override fun doAddUserId(
userId: CharSequence, userId: CharSequence,
@ -899,7 +952,7 @@ class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: Def
certificationType: CertificationType, certificationType: CertificationType,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair { ) {
val builder = val builder =
SelfSignatureBuilder( SelfSignatureBuilder(
keyPair.privateKey, keyPair.privateKey,
@ -910,7 +963,6 @@ class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: Def
val sig = builder.build(userId) val sig = builder.build(userId)
keyPair = keyPair.plusCertification(userId, sig) keyPair = keyPair.plusCertification(userId, sig)
return keyPair
} }
override fun doAddUserAttribute( override fun doAddUserAttribute(
@ -919,7 +971,7 @@ class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: Def
certificationType: CertificationType, certificationType: CertificationType,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair { ) {
val builder = val builder =
SelfSignatureBuilder( SelfSignatureBuilder(
keyPair.privateKey, keyPair.privateKey,
@ -930,21 +982,19 @@ class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: Def
val sig = builder.build(userAttribute) val sig = builder.build(userAttribute)
keyPair = keyPair.plusCertification(userAttribute, sig) keyPair = keyPair.plusCertification(userAttribute, sig)
return keyPair
} }
override fun doAddDirectKeySignature( override fun doAddDirectKeySignature(
subpacketsCallback: SelfSignatureSubpackets.Callback, subpacketsCallback: SelfSignatureSubpackets.Callback,
hashAlgorithm: HashAlgorithm, hashAlgorithm: HashAlgorithm,
bindingTime: Date bindingTime: Date
): PGPKeyPair { ) {
val builder = val builder =
DirectKeySelfSignatureBuilder(keyPair.privateKey, keyPair.publicKey, hashAlgorithm) DirectKeySelfSignatureBuilder(keyPair.privateKey, keyPair.publicKey, hashAlgorithm)
builder.applyCallback(subpacketsCallback.then(setCreationTime(bindingTime))) builder.applyCallback(subpacketsCallback.then(setCreationTime(bindingTime)))
val sig = builder.build() val sig = builder.build()
keyPair = keyPair.plusCertification(sig) keyPair = keyPair.plusCertification(sig)
return keyPair
} }
/** /**
@ -958,81 +1008,29 @@ class ApplyToPrimaryKeyV4 internal constructor(keyPair: PGPKeyPair, builder: Def
return SelfSignatureSubpackets.applyHashed { setSignatureCreationTime(bindingTime) } return SelfSignatureSubpackets.applyHashed { setSignatureCreationTime(bindingTime) }
} }
override fun then(other: (DefinePrimaryKey.ApplyToPrimaryKey.() -> PGPKeyPair)?): PGPKeyPair { /** Implementation of [DefinePrimaryKey] build for version 4 OpenPGP keys. */
if (other != null) { abstract class DefinePrimaryKeyV4<O : DefineSubkeys<O>>(
keyPair = ApplyToPrimaryKeyV4(keyPair, builder).other() policy: Policy,
creationTime: Date,
preferences: AlgorithmSuite
) : DefinePrimaryKey<O>(policy, creationTime, preferences) {
override fun generatePrimaryKey(type: KeyType, creationTime: Date): PGPKeyPair {
return OpenPgpKeyPairGenerator.V4().generatePrimaryKey(type, creationTime)
} }
return keyPair
}
}
/** override fun invokeOnPrimaryKey(
* Implementation of the [ApplyToSubkey] function tailored to OpenPGP v4 keys. primaryKey: PGPKeyPair,
* block: PrimaryKeyBlock?
* @param primaryKey primary key pair ): PGPKeyPair {
* @param subkey subkey pair return with(ApplyToPrimaryKeyV4(primaryKey, this)) {
* @param builder builder instance that generated the subkey if (block != null) {
*/ block()
class ApplyToSubkeyV4 }
internal constructor(primaryKey: PGPKeyPair, subkey: PGPKeyPair, builder: DefineSubkeys<*>) : this.keyPair
DefineSubkeys.ApplyToSubkey(primaryKey, subkey, builder) {
override fun doAddBindingSignature(
subpacketsCallback: SelfSignatureSubpackets.Callback,
hashAlgorithm: HashAlgorithm,
bindingTime: Date
): PGPKeyPair {
val sigBuilder = SubkeyBindingSignatureBuilder(primaryKey, hashAlgorithm)
sigBuilder.applyCallback(
// sets key flags
subpacketsCallback
.then(setCreationTime(bindingTime))
// adds back sig if key flags contain sign or certify
.then(addBackSignatureIfNecessary(hashAlgorithm)))
val sig = sigBuilder.build(subkey)
subkey = subkey.plusCertification(sig)
return subkey
}
/**
* Return a [SelfSignatureSubpackets.Callback] that sets the signature creation time to the
* given [bindingTime].
*
* @param bindingTime signature creation time
* @return callback
*/
private fun setCreationTime(bindingTime: Date): SelfSignatureSubpackets.Callback {
return SelfSignatureSubpackets.applyHashed { setSignatureCreationTime(bindingTime) }
}
/**
* Return a [SelfSignatureSubpackets.Callback] that adds a PrimaryKeyBinding Signature
* (back-signature) if the subkey is signing capable.
*
* @param hashAlgorithm hash algorithm to calculate the back-sig with
* @return callback
*/
private fun addBackSignatureIfNecessary(
hashAlgorithm: HashAlgorithm
): SelfSignatureSubpackets.Callback {
return SelfSignatureSubpackets.applyHashed {
if (isSigningCapable(getKeyFlags())) {
addEmbeddedSignature(
PrimaryKeyBindingSignatureBuilder(subkey, hashAlgorithm).build(primaryKey))
} }
} }
} }
/**
* Return `true` if the given [flags] list contains either [KeyFlag.SIGN_DATA] or
* [KeyFlag.CERTIFY_OTHER].
*
* @return true if contains SIGN_DATA or CERTIFY_OTHER
*/
private fun isSigningCapable(flags: List<KeyFlag>?): Boolean =
flags.orEmpty().contains(KeyFlag.SIGN_DATA) ||
flags.orEmpty().contains(KeyFlag.CERTIFY_OTHER)
} }
/** Templates for OpenPGP key generation. */ /** Templates for OpenPGP key generation. */