1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 18:29:39 +02:00

Change type of KeyRingInfo.publicKey to OpenPGPPrimaryKey

This commit is contained in:
Paul Schaub 2025-02-05 10:31:28 +01:00
parent c593b5a590
commit 137bb51f2c
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
2 changed files with 38 additions and 42 deletions

View file

@ -43,8 +43,8 @@ class KeyRingInfo(
private val signatures: Signatures = Signatures(keys.pgpKeyRing, referenceDate, policy) private val signatures: Signatures = Signatures(keys.pgpKeyRing, referenceDate, policy)
/** Primary [PGPPublicKey]. */ /** Primary [OpenPGPCertificate.OpenPGPPrimaryKey]. */
val publicKey: PGPPublicKey = keys.primaryKey.pgpPublicKey val publicKey: OpenPGPCertificate.OpenPGPPrimaryKey = keys.primaryKey
/** Primary key ID. */ /** Primary key ID. */
val keyIdentifier: KeyIdentifier = publicKey.keyIdentifier val keyIdentifier: KeyIdentifier = publicKey.keyIdentifier
@ -55,10 +55,10 @@ class KeyRingInfo(
val keyId: Long = keyIdentifier.keyId val keyId: Long = keyIdentifier.keyId
/** Primary key fingerprint. */ /** Primary key fingerprint. */
val fingerprint: OpenPgpFingerprint = OpenPgpFingerprint.of(publicKey) val fingerprint: OpenPgpFingerprint = OpenPgpFingerprint.of(publicKey.pgpPublicKey)
/** All User-IDs (valid, expired, revoked). */ /** All User-IDs (valid, expired, revoked). */
val userIds: List<String> = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey) val userIds: List<String> = KeyRingUtils.getUserIdsIgnoringInvalidUTF8(publicKey.pgpPublicKey)
/** Primary User-ID. */ /** Primary User-ID. */
val primaryUserId = keys.getPrimaryUserId(referenceDate)?.userId val primaryUserId = keys.getPrimaryUserId(referenceDate)?.userId
@ -102,8 +102,7 @@ class KeyRingInfo(
} }
/** List of valid public subkeys. */ /** List of valid public subkeys. */
val validSubkeys: List<PGPPublicKey> = val validSubkeys: List<PGPPublicKey> = keys.getValidKeys(referenceDate).map { it.pgpPublicKey }
keys.publicKeys.values.filter { it.isBoundAt(referenceDate) }.map { it.pgpPublicKey }
/** List of valid user-IDs. */ /** List of valid user-IDs. */
val validUserIds: List<String> = keys.getValidUserIds(referenceDate).map { it.userId } val validUserIds: List<String> = keys.getValidUserIds(referenceDate).map { it.userId }
@ -136,7 +135,8 @@ class KeyRingInfo(
val revocationSelfSignature: PGPSignature? = signatures.primaryKeyRevocation val revocationSelfSignature: PGPSignature? = signatures.primaryKeyRevocation
/** Public-key encryption-algorithm of the primary key. */ /** 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. */ /** Creation date of the primary key. */
val creationDate: Date = publicKey.creationTime!! val creationDate: Date = publicKey.creationTime!!
@ -178,12 +178,16 @@ class KeyRingInfo(
val primaryKeyExpirationDate: Date? val primaryKeyExpirationDate: Date?
get() { get() {
val directKeyExpirationDate: Date? = val directKeyExpirationDate: Date? =
latestDirectKeySelfSignature?.let { getKeyExpirationTimeAsDate(it, publicKey) } latestDirectKeySelfSignature?.let {
getKeyExpirationTimeAsDate(it, publicKey.pgpPublicKey)
}
val possiblyExpiredPrimaryUserId = getPossiblyExpiredPrimaryUserId() val possiblyExpiredPrimaryUserId = getPossiblyExpiredPrimaryUserId()
val primaryUserIdCertification = val primaryUserIdCertification =
possiblyExpiredPrimaryUserId?.let { getLatestUserIdCertification(it) } possiblyExpiredPrimaryUserId?.let { getLatestUserIdCertification(it) }
val userIdExpirationDate: Date? = val userIdExpirationDate: Date? =
primaryUserIdCertification?.let { getKeyExpirationTimeAsDate(it, publicKey) } primaryUserIdCertification?.let {
getKeyExpirationTimeAsDate(it, publicKey.pgpPublicKey)
}
if (latestDirectKeySelfSignature == null && primaryUserIdCertification == null) { if (latestDirectKeySelfSignature == null && primaryUserIdCertification == null) {
throw NoSuchElementException( throw NoSuchElementException(
@ -257,7 +261,7 @@ class KeyRingInfo(
* @return expiration date * @return expiration date
*/ */
fun getSubkeyExpirationDate(keyId: Long): Date? { fun getSubkeyExpirationDate(keyId: Long): Date? {
if (publicKey.keyID == keyId) return primaryKeyExpirationDate if (publicKey.keyIdentifier.keyId == keyId) return primaryKeyExpirationDate
val subkey = val subkey =
getPublicKey(keyId) getPublicKey(keyId)
?: throw NoSuchElementException( ?: throw NoSuchElementException(
@ -328,7 +332,7 @@ class KeyRingInfo(
): List<PGPPublicKey> { ): List<PGPPublicKey> {
if (userId != null && !isUserIdValid(userId)) { if (userId != null && !isUserIdValid(userId)) {
throw UnboundUserIdException( throw UnboundUserIdException(
OpenPgpFingerprint.of(publicKey), OpenPgpFingerprint.of(publicKey.pgpPublicKey),
userId.toString(), userId.toString(),
getLatestUserIdCertification(userId), getLatestUserIdCertification(userId),
getUserIdRevocation(userId)) getUserIdRevocation(userId))
@ -469,7 +473,7 @@ class KeyRingInfo(
* @return list of key flags * @return list of key flags
*/ */
fun getKeyFlagsOf(keyId: Long): List<KeyFlag> = fun getKeyFlagsOf(keyId: Long): List<KeyFlag> =
if (keyId == publicKey.keyID) { if (keyId == publicKey.keyIdentifier.keyId) {
latestDirectKeySelfSignature?.let { sig -> latestDirectKeySelfSignature?.let { sig ->
SignatureSubpacketsUtil.parseKeyFlags(sig)?.let { flags -> SignatureSubpacketsUtil.parseKeyFlags(sig)?.let { flags ->
return flags return flags
@ -684,7 +688,7 @@ class KeyRingInfo(
return false return false
} }
if (sig.hashedSubPackets.isPrimaryUserID) { if (sig.hashedSubPackets.isPrimaryUserID) {
getKeyExpirationTimeAsDate(sig, publicKey)?.let { expirationDate -> getKeyExpirationTimeAsDate(sig, publicKey.pgpPublicKey)?.let { expirationDate ->
// key expired? // key expired?
if (expirationDate < referenceDate) return false if (expirationDate < referenceDate) return false
} }

View file

@ -7,12 +7,8 @@ package org.pgpainless.example;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; 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 java.util.Date;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.Test; 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 * 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 * such as {@link org.pgpainless.key.generation.KeyRingTemplates#modernKeyRing(CharSequence, String)} or
* {@link org.pgpainless.key.generation.KeyRingTemplates#simpleRsaKeyRing(CharSequence, RsaLength)}. * {@link org.pgpainless.key.generation.KeyRingTemplates#simpleRsaKeyRing(CharSequence, RsaLength)}.
* * <p>
* Those methods always take a user-id which is used as primary user-id, as well as a passphrase which is used to encrypt * 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. * the secret key.
* To generate unencrypted secret keys, just pass {@code null} as passphrase. * To generate unencrypted secret keys, just pass {@code null} as passphrase.
* * <p>
* Besides the archetype methods, it is possible to generate fully customized keys (see {@link #generateCustomOpenPGPKey()}). * Besides the archetype methods, it is possible to generate fully customized keys (see {@link #generateCustomOpenPGPKey()}).
*/ */
public class GenerateKeys { 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 * 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 * used solely for certification of subkeys, as well as an ed25519 EdDSA signing subkey, and an X25519 ECDH
* encryption subkey. * encryption subkey.
* * <p>
* This is the recommended way to generate OpenPGP keys with PGPainless. * This is the recommended way to generate OpenPGP keys with PGPainless.
*/ */
@Test @Test
public void generateModernEcKey() public void generateModernEcKey() {
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
// Define a primary user-id // Define a primary user-id
String userId = "gbaker@pgpainless.org"; String userId = "gbaker@pgpainless.org";
// Set a password to protect the secret key // Set a password to protect the secret key
@ -75,7 +70,7 @@ public class GenerateKeys {
assertEquals(3, keyInfo.getSecretKeys().size()); assertEquals(3, keyInfo.getSecretKeys().size());
assertEquals(userId, keyInfo.getPrimaryUserId()); assertEquals(userId, keyInfo.getPrimaryUserId());
assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(), assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(),
keyInfo.getPublicKey().getAlgorithm()); keyInfo.getAlgorithm().getAlgorithmId());
assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(), assertEquals(PublicKeyAlgorithm.EDDSA_LEGACY.getAlgorithmId(),
keyInfo.getSigningSubkeys().get(0).getAlgorithm()); keyInfo.getSigningSubkeys().get(0).getAlgorithm());
assertEquals(PublicKeyAlgorithm.ECDH.getAlgorithmId(), 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. * 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. * The RSA key is used for both signing and certifying, as well as encryption.
* * <p>
* This method is recommended if the application has to deal with legacy clients with poor algorithm support. * This method is recommended if the application has to deal with legacy clients with poor algorithm support.
*/ */
@Test @Test
public void generateSimpleRSAKey() public void generateSimpleRSAKey() {
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
// Define a primary user-id // Define a primary user-id
String userId = "mpage@pgpainless.org"; String userId = "mpage@pgpainless.org";
// Set a password to protect the secret key // Set a password to protect the secret key
@ -102,19 +96,18 @@ public class GenerateKeys {
KeyRingInfo keyInfo = new KeyRingInfo(secretKey); KeyRingInfo keyInfo = new KeyRingInfo(secretKey);
assertEquals(1, keyInfo.getSecretKeys().size()); assertEquals(1, keyInfo.getSecretKeys().size());
assertEquals(userId, keyInfo.getPrimaryUserId()); 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. * 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, * 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. * and a single ECDH encryption subkey.
* * <p>
* This method is recommended if small keys and high performance are desired. * This method is recommended if small keys and high performance are desired.
*/ */
@Test @Test
public void generateSimpleECKey() public void generateSimpleECKey() {
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
// Define a primary user-id // Define a primary user-id
String userId = "mhelms@pgpainless.org"; String userId = "mhelms@pgpainless.org";
// Set a password to protect the secret key // 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. * 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 * Among user-id and password, the user can add an arbitrary number of subkeys and specify their algorithms and
* algorithm preferences. * algorithm preferences.
* * <p>
* If the target key amalgamation (key ring) should consist of more than just a single (sub-)key, start by providing * 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)}. * 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)}. * Any additional subkeys can be then added using {@link org.pgpainless.key.generation.KeyRingBuilder#addSubkey(KeySpec)}.
* * <p>
* {@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}. * method and providing a {@link KeyType}.
* There are a bunch of factory methods for different {@link KeyType} implementations present in {@link KeyType} itself * 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 * (such as {@link KeyType#ECDH(EllipticCurve)}). {@link KeyFlag KeyFlags} determine
* the use of the key, like encryption, signing data or certifying subkeys. * the use of the key, like encryption, signing data or certifying subkeys.
* * <p>
* If you so desire, you can now specify your own algorithm preferences. * If you so desire, you can now specify your own algorithm preferences.
* For that, see {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredCompressionAlgorithms(CompressionAlgorithm...)}, * 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#overridePreferredHashAlgorithms(HashAlgorithm...)} or
* {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm...)}. * {@link org.pgpainless.key.generation.KeySpecBuilder#overridePreferredSymmetricKeyAlgorithms(SymmetricKeyAlgorithm...)}.
* * <p>
* Note, that if you set preferred algorithms, the preference lists are sorted from high priority to low priority. * Note, that if you set preferred algorithms, the preference lists are sorted from high priority to low priority.
* * <p>
* When setting the primary key spec ({@link org.pgpainless.key.generation.KeyRingBuilder#setPrimaryKey(KeySpecBuilder)}), * 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 * make sure that the primary key spec has the {@link KeyFlag} {@link KeyFlag#CERTIFY_OTHER} set, as this is a requirement
* for primary keys. * for primary keys.
* * <p>
* Furthermore, you have to set at least the primary user-id via * 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. * but you can also add additional user-ids.
* * <p>
* If you want the key to expire at a certain point in time, call * If you want the key to expire at a certain point in time, call
* {@link org.pgpainless.key.generation.KeyRingBuilder#setExpirationDate(Date)}. * {@link org.pgpainless.key.generation.KeyRingBuilder#setExpirationDate(Date)}.
* Lastly you can decide whether to set a passphrase to protect the secret key using * Lastly you can decide whether to set a passphrase to protect the secret key using
* {@link org.pgpainless.key.generation.KeyRingBuilder#setPassphrase(Passphrase)}. * {@link org.pgpainless.key.generation.KeyRingBuilder#setPassphrase(Passphrase)}.
*/ */
@Test @Test
public void generateCustomOpenPGPKey() public void generateCustomOpenPGPKey() {
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
// Instead of providing a string, we can assemble a user-id by using the user-id builder. // 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!) <mcarpenter@pgpainless.org>" // The example below corresponds to "Morgan Carpenter (Pride!) <mcarpenter@pgpainless.org>"
UserId userId = UserId.newBuilder() UserId userId = UserId.builder()
.withName("Morgan Carpenter") .withName("Morgan Carpenter")
.withEmail("mcarpenter@pgpainless.org") .withEmail("mcarpenter@pgpainless.org")
.withComment("Pride!") .withComment("Pride!")