From f2f7305fec49172cd0d2515fb00cecc1712dbb84 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Sat, 13 Feb 2021 12:22:28 +0100 Subject: [PATCH] Allow for setting of expiration date during key generation --- .../pgpainless/key/generation/KeyRingBuilder.java | 15 +++++++++++++++ .../key/generation/KeyRingBuilderInterface.java | 9 +++++++++ .../GenerateKeyWithAdditionalUserIdTest.java | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java index 463483a1..7822fc45 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java @@ -66,6 +66,7 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { private String userId; private final Set additionalUserIds = new LinkedHashSet<>(); private Passphrase passphrase; + private Date expirationDate = null; /** * Creates a simple, unencrypted RSA KeyPair of length {@code length} with user-id {@code userId}. @@ -288,6 +289,16 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { class WithAdditionalUserIdOrPassphraseImpl implements WithAdditionalUserIdOrPassphrase { + @Override + public WithAdditionalUserIdOrPassphrase setExpirationDate(@Nonnull Date expirationDate) { + Date now = new Date(); + if (now.after(expirationDate)) { + throw new IllegalArgumentException("Expiration date must be in the future."); + } + KeyRingBuilder.this.expirationDate = expirationDate; + return this; + } + @Override public WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull String userId) { String trimmed = userId.trim(); @@ -341,6 +352,10 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { signatureGenerator = new PGPSignatureGenerator(signer); PGPSignatureSubpacketGenerator hashedSubPacketGenerator = certKeySpec.getSubpacketGenerator(); hashedSubPacketGenerator.setPrimaryUserID(false, true); + if (expirationDate != null) { + SignatureSubpacketGeneratorUtil.setExpirationDateInSubpacketGenerator( + expirationDate, new Date(), hashedSubPacketGenerator); + } PGPSignatureSubpacketVector hashedSubPackets = hashedSubPacketGenerator.generate(); // Generator which the user can get the key pair from diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java index f4f2ff29..effdfcf1 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java @@ -17,6 +17,7 @@ package org.pgpainless.key.generation; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.util.Date; import javax.annotation.Nonnull; import org.bouncycastle.openpgp.PGPException; @@ -60,6 +61,14 @@ public interface KeyRingBuilderInterface { return withAdditionalUserId(userId.toString()); } + /** + * Set an expiration date for the key. + * + * @param expirationDate date on which the key will expire. + * @return builder + */ + WithAdditionalUserIdOrPassphrase setExpirationDate(@Nonnull Date expirationDate); + WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull String userId); WithAdditionalUserIdOrPassphrase withAdditionalUserId(@Nonnull byte[] userId); diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java index 0ced3b71..67937f74 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/generation/GenerateKeyWithAdditionalUserIdTest.java @@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; +import java.util.Date; import java.util.Iterator; import org.bouncycastle.bcpg.ArmoredOutputStream; @@ -39,6 +40,8 @@ public class GenerateKeyWithAdditionalUserIdTest { @Test public void test() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { + Date now = new Date(); + Date expiration = new Date(now.getTime() + 1000 * 5); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() .withPrimaryKey(KeySpec.getBuilder(KeyType.RSA(RsaLength._3072)) .withKeyFlags(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS) @@ -47,10 +50,13 @@ public class GenerateKeyWithAdditionalUserIdTest { .withAdditionalUserId("additional@user.id") .withAdditionalUserId("additional2@user.id") .withAdditionalUserId("\ttrimThis@user.id ") + .setExpirationDate(expiration) .withoutPassphrase() .build(); PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys); + assertEquals(expiration.getTime(), PGPainless.inspectKeyRing(publicKeys).getExpirationDate().getTime(), 2); + Iterator userIds = publicKeys.getPublicKey().getUserIDs(); assertEquals("primary@user.id", userIds.next()); assertEquals("additional@user.id", userIds.next());