From 137bb51f2cf61837e12aa47b13afb3f51702de38 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 5 Feb 2025 10:31:28 +0100 Subject: [PATCH] Change type of KeyRingInfo.publicKey to OpenPGPPrimaryKey --- .../org/pgpainless/key/info/KeyRingInfo.kt | 30 ++++++----- .../org/pgpainless/example/GenerateKeys.java | 50 ++++++++----------- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt index 007756a6..9271f550 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt @@ -43,8 +43,8 @@ class KeyRingInfo( private val signatures: Signatures = Signatures(keys.pgpKeyRing, referenceDate, policy) - /** Primary [PGPPublicKey]. */ - val publicKey: PGPPublicKey = keys.primaryKey.pgpPublicKey + /** Primary [OpenPGPCertificate.OpenPGPPrimaryKey]. */ + val publicKey: OpenPGPCertificate.OpenPGPPrimaryKey = keys.primaryKey /** Primary key ID. */ val keyIdentifier: KeyIdentifier = publicKey.keyIdentifier @@ -55,10 +55,10 @@ class KeyRingInfo( val keyId: Long = keyIdentifier.keyId /** Primary key fingerprint. */ - val fingerprint: OpenPgpFingerprint = OpenPgpFingerprint.of(publicKey) + val fingerprint: OpenPgpFingerprint = OpenPgpFingerprint.of(publicKey.pgpPublicKey) /** All User-IDs (valid, expired, revoked). */ - val userIds: List = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey) + val userIds: List = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey.pgpPublicKey) /** Primary User-ID. */ val primaryUserId = keys.getPrimaryUserId(referenceDate)?.userId @@ -102,8 +102,7 @@ class KeyRingInfo( } /** List of valid public subkeys. */ - val validSubkeys: List = - keys.publicKeys.values.filter { it.isBoundAt(referenceDate) }.map { it.pgpPublicKey } + val validSubkeys: List = keys.getValidKeys(referenceDate).map { it.pgpPublicKey } /** List of valid user-IDs. */ val validUserIds: List = keys.getValidUserIds(referenceDate).map { it.userId } @@ -136,7 +135,8 @@ class KeyRingInfo( val revocationSelfSignature: PGPSignature? = signatures.primaryKeyRevocation /** Public-key encryption-algorithm of the primary key. */ - val algorithm: PublicKeyAlgorithm = PublicKeyAlgorithm.requireFromId(publicKey.algorithm) + val algorithm: PublicKeyAlgorithm = + PublicKeyAlgorithm.requireFromId(publicKey.pgpPublicKey.algorithm) /** Creation date of the primary key. */ val creationDate: Date = publicKey.creationTime!! @@ -178,12 +178,16 @@ class KeyRingInfo( val primaryKeyExpirationDate: Date? get() { val directKeyExpirationDate: Date? = - latestDirectKeySelfSignature?.let { getKeyExpirationTimeAsDate(it, publicKey) } + latestDirectKeySelfSignature?.let { + getKeyExpirationTimeAsDate(it, publicKey.pgpPublicKey) + } val possiblyExpiredPrimaryUserId = getPossiblyExpiredPrimaryUserId() val primaryUserIdCertification = possiblyExpiredPrimaryUserId?.let { getLatestUserIdCertification(it) } val userIdExpirationDate: Date? = - primaryUserIdCertification?.let { getKeyExpirationTimeAsDate(it, publicKey) } + primaryUserIdCertification?.let { + getKeyExpirationTimeAsDate(it, publicKey.pgpPublicKey) + } if (latestDirectKeySelfSignature == null && primaryUserIdCertification == null) { throw NoSuchElementException( @@ -257,7 +261,7 @@ class KeyRingInfo( * @return expiration date */ fun getSubkeyExpirationDate(keyId: Long): Date? { - if (publicKey.keyID == keyId) return primaryKeyExpirationDate + if (publicKey.keyIdentifier.keyId == keyId) return primaryKeyExpirationDate val subkey = getPublicKey(keyId) ?: throw NoSuchElementException( @@ -328,7 +332,7 @@ class KeyRingInfo( ): List { if (userId != null && !isUserIdValid(userId)) { throw UnboundUserIdException( - OpenPgpFingerprint.of(publicKey), + OpenPgpFingerprint.of(publicKey.pgpPublicKey), userId.toString(), getLatestUserIdCertification(userId), getUserIdRevocation(userId)) @@ -469,7 +473,7 @@ class KeyRingInfo( * @return list of key flags */ fun getKeyFlagsOf(keyId: Long): List = - if (keyId == publicKey.keyID) { + if (keyId == publicKey.keyIdentifier.keyId) { latestDirectKeySelfSignature?.let { sig -> SignatureSubpacketsUtil.parseKeyFlags(sig)?.let { flags -> return flags @@ -684,7 +688,7 @@ class KeyRingInfo( return false } if (sig.hashedSubPackets.isPrimaryUserID) { - getKeyExpirationTimeAsDate(sig, publicKey)?.let { expirationDate -> + getKeyExpirationTimeAsDate(sig, publicKey.pgpPublicKey)?.let { expirationDate -> // key expired? if (expirationDate < referenceDate) return false } diff --git a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java index d6bcb0b1..3ee24a60 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java +++ b/pgpainless-core/src/test/java/org/pgpainless/example/GenerateKeys.java @@ -7,12 +7,8 @@ package org.pgpainless.example; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; import java.util.Date; -import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.junit.jupiter.api.Test; @@ -39,11 +35,11 @@ import org.pgpainless.util.Passphrase; * The result ({@link org.pgpainless.key.generation.KeyRingBuilder}) provides some factory methods for key archetypes * such as {@link org.pgpainless.key.generation.KeyRingTemplates#modernKeyRing(CharSequence, String)} or * {@link org.pgpainless.key.generation.KeyRingTemplates#simpleRsaKeyRing(CharSequence, RsaLength)}. - * + *

* Those methods always take a user-id which is used as primary user-id, as well as a passphrase which is used to encrypt * the secret key. * To generate unencrypted secret keys, just pass {@code null} as passphrase. - * + *

* Besides the archetype methods, it is possible to generate fully customized keys (see {@link #generateCustomOpenPGPKey()}). */ public class GenerateKeys { @@ -52,12 +48,11 @@ public class GenerateKeys { * This example demonstrates how to generate a modern OpenPGP key which consists of an ed25519 EdDSA primary key * used solely for certification of subkeys, as well as an ed25519 EdDSA signing subkey, and an X25519 ECDH * encryption subkey. - * + *

* This is the recommended way to generate OpenPGP keys with PGPainless. */ @Test - public void generateModernEcKey() - throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { + public void generateModernEcKey() { // Define a primary user-id String userId = "gbaker@pgpainless.org"; // Set a password to protect the secret key @@ -75,7 +70,7 @@ public class GenerateKeys { assertEquals(3, keyInfo.getSecretKeys().size()); assertEquals(userId, keyInfo.getPrimaryUserId()); assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(), - keyInfo.getPublicKey().getAlgorithm()); + keyInfo.getAlgorithm().getAlgorithmId()); assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(), keyInfo.getSigningSubkeys().get(0).getAlgorithm()); assertEquals(PublicKeyAlgorithm.ECDH.getAlgorithmId(), @@ -85,12 +80,11 @@ public class GenerateKeys { /** * This example demonstrates how to generate a simple OpenPGP key consisting of a 4096-bit RSA key. * The RSA key is used for both signing and certifying, as well as encryption. - * + *

* This method is recommended if the application has to deal with legacy clients with poor algorithm support. */ @Test - public void generateSimpleRSAKey() - throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + public void generateSimpleRSAKey() { // Define a primary user-id String userId = "mpage@pgpainless.org"; // Set a password to protect the secret key @@ -102,19 +96,18 @@ public class GenerateKeys { KeyRingInfo keyInfo = new KeyRingInfo(secretKey); assertEquals(1, keyInfo.getSecretKeys().size()); assertEquals(userId, keyInfo.getPrimaryUserId()); - assertEquals(PublicKeyAlgorithm.RSA_GENERAL.getAlgorithmId(), keyInfo.getPublicKey().getAlgorithm()); + assertEquals(PublicKeyAlgorithm.RSA_GENERAL.getAlgorithmId(), keyInfo.getAlgorithm().getAlgorithmId()); } /** * This example demonstrates how to generate a simple OpenPGP key based on elliptic curves. * The key consists of an ECDSA primary key that is used both for certification of subkeys, and signing of data, * and a single ECDH encryption subkey. - * + *

* This method is recommended if small keys and high performance are desired. */ @Test - public void generateSimpleECKey() - throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + public void generateSimpleECKey() { // Define a primary user-id String userId = "mhelms@pgpainless.org"; // Set a password to protect the secret key @@ -133,43 +126,42 @@ public class GenerateKeys { * This example demonstrates how to generate a custom OpenPGP secret key. * Among user-id and password, the user can add an arbitrary number of subkeys and specify their algorithms and * algorithm preferences. - * + *

* If the target key amalgamation (key ring) should consist of more than just a single (sub-)key, start by providing * the primary key specification using {@link org.pgpainless.key.generation.KeyRingBuilder#setPrimaryKey(KeySpec)}. * Any additional subkeys can be then added using {@link org.pgpainless.key.generation.KeyRingBuilder#addSubkey(KeySpec)}. - * - * {@link KeySpec} objects can best be obtained by using the {@link KeySpec#getBuilder(KeyType, KeyFlag, KeyFlag...)} + *

+ * {@link KeySpec} objects can best be obtained by using the {@link KeySpec#getBuilder(KeyType, KeyFlag...)} * method and providing a {@link KeyType}. * There are a bunch of factory methods for different {@link KeyType} implementations present in {@link KeyType} itself * (such as {@link KeyType#ECDH(EllipticCurve)}). {@link KeyFlag KeyFlags} determine * the use of the key, like encryption, signing data or certifying subkeys. - * + *

* If you so desire, you can now specify your own algorithm preferences. * For that, see {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredCompressionAlgorithms(CompressionAlgorithm...)}, * {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredHashAlgorithms(HashAlgorithm...)} or * {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm...)}. - * + *

* Note, that if you set preferred algorithms, the preference lists are sorted from high priority to low priority. - * + *

* When setting the primary key spec ({@link org.pgpainless.key.generation.KeyRingBuilder#setPrimaryKey(KeySpecBuilder)}), * make sure that the primary key spec has the {@link KeyFlag} {@link KeyFlag#CERTIFY_OTHER} set, as this is a requirement * for primary keys. - * + *

* Furthermore, you have to set at least the primary user-id via - * {@link org.pgpainless.key.generation.KeyRingBuilder#addUserId(String)}, + * {@link org.pgpainless.key.generation.KeyRingBuilder#addUserId(CharSequence)}, * but you can also add additional user-ids. - * + *

* If you want the key to expire at a certain point in time, call * {@link org.pgpainless.key.generation.KeyRingBuilder#setExpirationDate(Date)}. * Lastly you can decide whether to set a passphrase to protect the secret key using * {@link org.pgpainless.key.generation.KeyRingBuilder#setPassphrase(Passphrase)}. */ @Test - public void generateCustomOpenPGPKey() - throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { + public void generateCustomOpenPGPKey() { // Instead of providing a string, we can assemble a user-id by using the user-id builder. // The example below corresponds to "Morgan Carpenter (Pride!) " - UserId userId = UserId.newBuilder() + UserId userId = UserId.builder() .withName("Morgan Carpenter") .withEmail("mcarpenter@pgpainless.org") .withComment("Pride!")