Rename KeyGenerator and add MalformedKeyGenerationTest

This commit is contained in:
Paul Schaub 2024-01-27 18:45:55 +01:00
parent 6df4211985
commit 44a3096467
Signed by: vanitasvitae
GPG Key ID: 62BEE9264BF17311
3 changed files with 75 additions and 22 deletions

View File

@ -24,31 +24,51 @@ import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
* @param referenceTime reference time for key generation
* @param preferences set of preferred algorithms and enabled features
*/
open class OpenPgpKeyBuilder(
protected val policy: Policy,
protected val referenceTime: Date = Date(),
protected val preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
open class GenerateOpenPgpKey(
private val policy: Policy,
private val referenceTime: Date = Date(),
private val preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
) {
abstract class OpenPgpKeyBuilder(
protected val policy: Policy,
protected val referenceTime: Date,
protected val preferences: AlgorithmSuite
) {
/**
* Make sure, that the chosen [KeyType] is allowed.
*/
open fun sanitizePublicKeyAlgorithms(keyType: KeyType, policy: Policy) {
verifyAlgorithmComplianceWithPolicy(keyType, policy)
}
/**
* Make sure, that the chosen [KeyType] complies to the given [Policy] by comparing it to the
* [Policy.PublicKeyAlgorithmPolicy].
*
* @throws IllegalArgumentException if [keyType] fails to be accepted by [policy]
*/
private fun verifyAlgorithmComplianceWithPolicy(keyType: KeyType, policy: Policy) {
val algorithm = keyType.algorithm
val bitStrength = keyType.bitStrength
require(policy.publicKeyAlgorithmPolicy.isAcceptable(algorithm, bitStrength)) {
"Public key algorithm policy violation: $algorithm with bit strength $bitStrength is not acceptable."
}
}
}
/**
* Build an OpenPGP v4 key. The result will be a key compliant to RFC4880, RFC6637.
*
* @param keyType type of the primary key
* @param flags key flags for the primary key. Defaults to [KeyFlag.CERTIFY_OTHER].
* @return [V4OpenPgpKeyBuilder] which can be further modified, e.g. add subkeys, user-ids etc.
* @return [V4GenerateOpenPgpKey] which can be further modified, e.g. add subkeys, user-ids etc.
*/
fun buildV4Key(
keyType: KeyType,
flags: List<KeyFlag>? = listOf(KeyFlag.CERTIFY_OTHER)
): V4OpenPgpKeyBuilder = V4OpenPgpKeyBuilder(keyType, flags, policy, referenceTime, preferences)
internal fun verifyAlgorithmComplianceWithPolicy(keyType: KeyType, policy: Policy) {
val algorithm = keyType.algorithm
val bitStrength = keyType.bitStrength
require(policy.publicKeyAlgorithmPolicy.isAcceptable(algorithm, bitStrength)) {
"Public key algorithm policy violation: $algorithm with bit strength $bitStrength is not acceptable."
}
}
): V4GenerateOpenPgpKey = V4GenerateOpenPgpKey(keyType, flags, policy, referenceTime, preferences)
/**
* Builder for version 4 OpenPGP keys.
@ -59,7 +79,7 @@ open class OpenPgpKeyBuilder(
* @param referenceTime reference time for key generation
* @param preferences set of algorithm preferences and enabled features for the key
*/
class V4OpenPgpKeyBuilder
class V4GenerateOpenPgpKey
internal constructor(
primaryKeyType: KeyType,
primaryFlags: List<KeyFlag>?,
@ -69,7 +89,7 @@ open class OpenPgpKeyBuilder(
) : OpenPgpKeyBuilder(policy, referenceTime, preferences) {
init {
verifyAlgorithmComplianceWithPolicy(primaryKeyType, policy)
sanitizePublicKeyAlgorithms(primaryKeyType, policy)
}
private val primaryKey =
@ -152,7 +172,7 @@ open class OpenPgpKeyBuilder(
subkeyBuilder: BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder,
subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop()
) = apply {
verifyAlgorithmComplianceWithPolicy(subkeyBuilder.type, policy)
sanitizePublicKeyAlgorithms(subkeyBuilder.type, policy)
subkeys.add(subkeyBuilder.bindingSignature(subpacketsCallback = subpacketsCallback))
}

View File

@ -15,13 +15,13 @@ import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.policy.Policy
import org.pgpainless.util.DateUtil
class OpenPgpKeyBuilderTest {
class GenerateOpenPgpKeyTest {
@Test
fun test() {
val date = DateUtil.parseUTCDate("2020-04-01 10:00:00 UTC")
val key =
OpenPgpKeyBuilder(Policy.getInstance(), date)
GenerateOpenPgpKey(Policy.getInstance(), date)
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER))
.addUserId("Alice")
.addUserAttribute(
@ -37,7 +37,7 @@ class OpenPgpKeyBuilderTest {
@Test
fun minimal() {
val key =
OpenPgpKeyBuilder(Policy.getInstance())
GenerateOpenPgpKey(Policy.getInstance())
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER))
.build()
println(PGPainless.asciiArmor(key))
@ -46,7 +46,7 @@ class OpenPgpKeyBuilderTest {
@Test
fun minimalWithUserId() {
val key =
OpenPgpKeyBuilder(Policy.getInstance())
GenerateOpenPgpKey(Policy.getInstance())
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER))
.addUserId("Alice <alice@pgpainless.org>")
.build()
@ -60,7 +60,7 @@ class OpenPgpKeyBuilderTest {
Policy(
publicKeyAlgorithmPolicy =
Policy.PublicKeyAlgorithmPolicy(mapOf(PublicKeyAlgorithm.RSA_GENERAL to 4096)))
val builder = OpenPgpKeyBuilder(policy)
val builder = GenerateOpenPgpKey(policy)
assertThrows<IllegalArgumentException> {
builder.buildV4Key(KeyType.RSA(RsaLength._3072)) // too weak

View File

@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.key.generation
import org.bouncycastle.bcpg.sig.PrimaryUserID
import org.junit.jupiter.api.Test
import org.pgpainless.PGPainless
import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
import org.pgpainless.policy.Policy
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
class MalformedKeyGenerationTest {
@Test
fun malformedPrimaryUserIdSubpacket() {
val userId = "Alice <alice@pgpainless.org>"
val key = GenerateOpenPgpKey(Policy.getInstance())
.buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519))
.addUserId(userId,
SelfSignatureSubpackets.applyHashed {
setPrimaryUserId(PrimaryUserID(false, false, byteArrayOf(0x02)))
})
.build()
println(PGPainless.asciiArmor(key))
PGPainless.readKeyRing().secretKeyRing(key.encoded)!!
// TODO: Check interpretation of faulty PrimaryUserID packet
}
}