From 6df42119852c101e4df62dd4960be223ce40a849 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 27 Jan 2024 17:23:29 +0100 Subject: [PATCH] Validate PublicKeyAlgorithmPolicy when generating keys --- .../key/generation/OpenPgpKeyBuilder.kt | 13 +++++++++++ .../key/generation/OpenPgpKeyBuilderTest.kt | 22 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt index 012aea80..16408c2c 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilder.kt @@ -42,6 +42,14 @@ open class OpenPgpKeyBuilder( flags: List? = 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." + } + } + /** * Builder for version 4 OpenPGP keys. * @@ -60,6 +68,10 @@ open class OpenPgpKeyBuilder( preferences: AlgorithmSuite ) : OpenPgpKeyBuilder(policy, referenceTime, preferences) { + init { + verifyAlgorithmComplianceWithPolicy(primaryKeyType, policy) + } + private val primaryKey = BaseOpenPgpKeyBuilder.BaseV4PrimaryKeyBuilder(primaryKeyType, referenceTime, policy) private val subkeys = mutableListOf() @@ -140,6 +152,7 @@ open class OpenPgpKeyBuilder( subkeyBuilder: BaseOpenPgpKeyBuilder.BaseV4SubkeyBuilder, subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() ) = apply { + verifyAlgorithmComplianceWithPolicy(subkeyBuilder.type, policy) subkeys.add(subkeyBuilder.bindingSignature(subpacketsCallback = subpacketsCallback)) } diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt index 5c5c3338..9cbad1d5 100644 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/OpenPgpKeyBuilderTest.kt @@ -3,10 +3,13 @@ package org.pgpainless.key.generation import org.bouncycastle.bcpg.attr.ImageAttribute import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.pgpainless.PGPainless import org.pgpainless.algorithm.KeyFlag +import org.pgpainless.algorithm.PublicKeyAlgorithm import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.eddsa.EdDSACurve +import org.pgpainless.key.generation.type.rsa.RsaLength import org.pgpainless.key.generation.type.xdh.XDHSpec import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.policy.Policy @@ -49,4 +52,23 @@ class OpenPgpKeyBuilderTest { .build() println(PGPainless.asciiArmor(key)) } + + @Test + fun testKeyGenerationWithUnacceptablePKAlgorithmFails() { + // Policy only allows RSA 4096 algorithms + val policy = + Policy( + publicKeyAlgorithmPolicy = + Policy.PublicKeyAlgorithmPolicy(mapOf(PublicKeyAlgorithm.RSA_GENERAL to 4096))) + val builder = OpenPgpKeyBuilder(policy) + + assertThrows { + builder.buildV4Key(KeyType.RSA(RsaLength._3072)) // too weak + } + + val v4Builder = builder.buildV4Key(KeyType.RSA(RsaLength._4096)) // ok + assertThrows { + v4Builder.addSigningSubkey(KeyType.RSA(RsaLength._2048)) // too weak + } + } }