From f08981b78cf17f3a15f1296c08ed27cf5b57e41c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 3 Feb 2024 13:16:37 +0100 Subject: [PATCH] Add methods to control direct-key sigs and add unfinished test for primaryUserId test --- .../key/generation/GenerateOpenPgpKey.kt | 15 +++++++- .../generation/MalformedKeyGenerationTest.kt | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt index 401f03e7..3c339dae 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt @@ -103,6 +103,7 @@ open class GenerateOpenPgpKey( private val primaryKey = OpenPgpComponentKeyBuilder.V4PrimaryKeyBuilder(primaryKeyType, referenceTime, policy) private val subkeys = mutableListOf() + private var addDirectKeySignature = true private val preferencesCallback = SelfSignatureSubpackets.applyHashed { @@ -113,6 +114,16 @@ open class GenerateOpenPgpKey( primaryFlags?.let { setKeyFlags(*it.toTypedArray()) } } + fun directKeySignature( + subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() + ) = apply { + addDirectKeySignature = false + primaryKey.directKeySignature( + subpacketsCallback = preferencesCallback.then(subpacketsCallback)) + } + + fun noDirectKeySignature() = apply { addDirectKeySignature = false } + /** * Add a user-id to the key. The subpackets of the binding signature are prepopulated, * setting algorithm preferences and features. However, the subpackets can still be modified @@ -259,7 +270,9 @@ open class GenerateOpenPgpKey( ): PGPSecretKeyRing { // add a direct key sig with preferences - primaryKey.directKeySignature(subpacketsCallback = preferencesCallback) + if (addDirectKeySignature) { + primaryKey.directKeySignature(subpacketsCallback = preferencesCallback) + } return PGPSecretKeyRing( mutableListOf( diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt index 64efb704..dcfbc85d 100644 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/MalformedKeyGenerationTest.kt @@ -7,10 +7,14 @@ package org.pgpainless.key.generation import org.bouncycastle.bcpg.sig.Exportable import org.bouncycastle.bcpg.sig.PrimaryUserID import org.bouncycastle.bcpg.sig.Revocable +import org.bouncycastle.extensions.toAsciiArmor import org.junit.jupiter.api.Test import org.pgpainless.PGPainless +import org.pgpainless.algorithm.HashAlgorithm +import org.pgpainless.algorithm.KeyFlag import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.eddsa.EdDSACurve +import org.pgpainless.key.generation.type.xdh.XDHSpec import org.pgpainless.policy.Policy import org.pgpainless.signature.subpackets.SelfSignatureSubpackets @@ -70,4 +74,38 @@ class MalformedKeyGenerationTest { PGPainless.readKeyRing().secretKeyRing(key.encoded)!! // TODO: Check interpretation of faulty packet } + + @Test + fun primaryUserIdOnDirectKeySig() { + val policy = Policy.getInstance() + val key = + GenerateOpenPgpKey(policy) + .buildV4Key( + KeyType.EDDSA(EdDSACurve._Ed25519), + listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) + .directKeySignature( + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId() + setPreferredHashAlgorithms(HashAlgorithm.SHA224) + }) + .addUserId( + "Alice ", + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId(null) + setPreferredHashAlgorithms(HashAlgorithm.SHA256) + }) + .addUserId( + "Bob ", + SelfSignatureSubpackets.applyHashed { + setPrimaryUserId() + setPreferredHashAlgorithms(HashAlgorithm.SHA384) + }) + .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) + .build() + println(key.toAsciiArmor()) + + // TODO: Test, which hash algo is used when we encrypt+sign a message for this key. + // Correct would be SHA384, since this is the primary user-id. + // PrimaryUserID packets on the DK sig shall be ignored. + } }