From 77800f26e8847fb8017f0a5bb97f28a4aac64b34 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Fri, 28 May 2021 23:14:20 +0200 Subject: [PATCH] SecretKeyRingEditor: UserIDs only reside on primary keys --- .../secretkeyring/SecretKeyRingEditor.java | 181 +++++------------- .../SecretKeyRingEditorInterface.java | 151 +++++---------- .../encryption_signing/SigningTest.java | 2 +- .../key/info/UserIdRevocationTest.java | 18 +- .../key/modification/AddUserIdTest.java | 15 -- 5 files changed, 101 insertions(+), 266 deletions(-) diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java index 0adb208a..61beacee 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.java @@ -45,7 +45,6 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.pgpainless.PGPainless; import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SymmetricKeyAlgorithm; @@ -53,9 +52,8 @@ import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.generation.KeyRingBuilder; import org.pgpainless.key.generation.KeySpec; -import org.pgpainless.key.info.KeyRingInfo; -import org.pgpainless.key.protection.KeyRingProtectionSettings; import org.pgpainless.key.protection.CachingSecretKeyRingProtector; +import org.pgpainless.key.protection.KeyRingProtectionSettings; import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.UnlockSecretKey; @@ -64,8 +62,8 @@ import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvi import org.pgpainless.key.util.KeyRingUtils; import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.signature.SignatureUtils; -import org.pgpainless.util.Passphrase; import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; +import org.pgpainless.util.Passphrase; import org.pgpainless.util.selection.userid.SelectUserId; public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @@ -86,31 +84,22 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Override public SecretKeyRingEditorInterface addUserId(String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { - return addUserId(secretKeyRing.getPublicKey().getKeyID(), userId, secretKeyRingProtector); - } - - @Override - public SecretKeyRingEditorInterface addUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { userId = sanitizeUserId(userId); List secretKeyList = new ArrayList<>(); Iterator secretKeyIterator = secretKeyRing.getSecretKeys(); - boolean found = false; - while (!found && secretKeyIterator.hasNext()) { - PGPSecretKey secretKey = secretKeyIterator.next(); - if (secretKey.getKeyID() == keyId) { - found = true; - PGPPublicKey publicKey = secretKey.getPublicKey(); - PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, secretKeyRingProtector); - publicKey = addUserIdToPubKey(userId, privateKey, publicKey); - secretKey = PGPSecretKey.replacePublicKey(secretKey, publicKey); - } - secretKeyList.add(secretKey); - } + // add user-id certificate to primary key + PGPSecretKey primaryKey = secretKeyIterator.next(); + PGPPublicKey publicKey = primaryKey.getPublicKey(); + PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, secretKeyRingProtector); + publicKey = addUserIdToPubKey(userId, privateKey, publicKey); + primaryKey = PGPSecretKey.replacePublicKey(primaryKey, publicKey); - if (!found) { - throw new NoSuchElementException("Cannot find secret key with id " + Long.toHexString(keyId)); + secretKeyList.add(primaryKey); + + while (secretKeyIterator.hasNext()) { + secretKeyList.add(secretKeyIterator.next()); } secretKeyRing = new PGPSecretKeyRing(secretKeyList); @@ -143,53 +132,32 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { @Override public SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector protector) { - PGPPublicKey publicKey = secretKeyRing.getPublicKey(); - return deleteUserId(publicKey.getKeyID(), userId, protector); + return deleteUserIds(SelectUserId.exactMatch(userId), protector); } @Override public SecretKeyRingEditorInterface deleteUserIds(SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector) { - PGPPublicKey publicKey = secretKeyRing.getPublicKey(); - return deleteUserIds(publicKey.getKeyID(), selectionStrategy, secretKeyRingProtector); - } - - @Override - public SecretKeyRingEditorInterface deleteUserIds(long keyId, SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector) { List publicKeys = new ArrayList<>(); Iterator publicKeyIterator = secretKeyRing.getPublicKeys(); - boolean foundKey = false; + PGPPublicKey primaryKey = publicKeyIterator.next(); + List matchingUserIds = selectionStrategy.selectUserIds(iteratorToList(primaryKey.getUserIDs())); + if (matchingUserIds.isEmpty()) { + throw new NoSuchElementException("Key does not have a matching user-id attribute."); + } + for (String userId : matchingUserIds) { + primaryKey = PGPPublicKey.removeCertification(primaryKey, userId); + } + publicKeys.add(primaryKey); + while (publicKeyIterator.hasNext()) { - PGPPublicKey publicKey = publicKeyIterator.next(); - if (publicKey.getKeyID() == keyId) { - foundKey = true; - List matchingUserIds = selectionStrategy.selectUserIds(iteratorToList(publicKey.getUserIDs())); - if (matchingUserIds.isEmpty()) { - throw new NoSuchElementException("Key " + Long.toHexString(keyId) + " does not have a matching user-id attribute."); - } - for (String userId : matchingUserIds) { - publicKey = PGPPublicKey.removeCertification(publicKey, userId); - } - } - publicKeys.add(publicKey); - } - if (!foundKey) { - throw new NoSuchElementException("Cannot find public key with id " + Long.toHexString(keyId)); + publicKeys.add(publicKeyIterator.next()); } + PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(publicKeys); secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing); return this; } - private static boolean hasUserId(String userId, PGPPublicKey publicKey) { - boolean hasUserId = false; - Iterator userIdIterator = publicKey.getUserIDs(); - while (userIdIterator.hasNext()) { - hasUserId = userId.equals(userIdIterator.next()); - if (hasUserId) break; - } - return hasUserId; - } - @Override public SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, @Nonnull Passphrase subKeyPassphrase, @@ -302,72 +270,35 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { } @Override - public SecretKeyRingEditorInterface revokeUserIdOnAllSubkeys(String userId, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) + public SecretKeyRingEditorInterface revokeUserId(String userId, + SecretKeyRingProtector secretKeyRingProtector, + RevocationAttributes revocationAttributes) throws PGPException { - Iterator iterator = secretKeyRing.getPublicKeys(); - while (iterator.hasNext()) { - PGPPublicKey publicKey = iterator.next(); - try { - revokeUserId(userId, new OpenPgpV4Fingerprint(publicKey), secretKeyRingProtector, revocationAttributes); - } catch (IllegalArgumentException | NoSuchElementException e) { - // skip + Iterator userIds = secretKeyRing.getPublicKey().getUserIDs(); + boolean found = false; + while (userIds.hasNext()) { + if (userId.equals(userIds.next())) { + found = true; + break; } } - return this; - } - - @Override - public SecretKeyRingEditorInterface revokeUserId(String userId, - OpenPgpV4Fingerprint subkeyFingerprint, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) - throws PGPException { - PGPPublicKey publicKey = secretKeyRing.getPublicKey(subkeyFingerprint.getKeyId()); - if (publicKey == null) { - throw new IllegalArgumentException("Key ring does not carry a public key with fingerprint " + subkeyFingerprint); + if (!found) { + throw new NoSuchElementException("No user-id '" + userId + "' found on the key."); } - - KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing); - if (!info.getUserIds().contains(userId)) { - throw new NoSuchElementException("Key " + subkeyFingerprint + " does not carry userID '" + userId + '\''); - } - - return doRevokeUserId(userId, subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes); - } - - @Override - public SecretKeyRingEditorInterface revokeUserId(String userId, - long subkeyId, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) - throws PGPException { - PGPPublicKey publicKey = secretKeyRing.getPublicKey(subkeyId); - if (publicKey == null) { - throw new IllegalArgumentException("Key ring does not carry a public key with ID " + Long.toHexString(subkeyId)); - } - - KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing); - if (!info.getUserIds().contains(userId)) { - throw new NoSuchElementException("Key " + Long.toHexString(subkeyId) + " does not carry userID '" + userId + '\''); - } - - return doRevokeUserId(userId, subkeyId, secretKeyRingProtector, revocationAttributes); + return doRevokeUserId(userId, secretKeyRingProtector, revocationAttributes); } private SecretKeyRingEditorInterface doRevokeUserId(String userId, - long subKeyId, SecretKeyRingProtector protector, RevocationAttributes revocationAttributes) throws PGPException { - PGPPublicKey publicKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subKeyId); - PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); - PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, protector); + PGPSecretKey primarySecretKey = secretKeyRing.getSecretKey(); + PGPPublicKey primaryPublicKey = primarySecretKey.getPublicKey(); + PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primarySecretKey, protector); PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator(); subpacketGenerator.setSignatureCreationTime(false, new Date()); subpacketGenerator.setRevocable(false, false); - subpacketGenerator.setIssuerFingerprint(false, primaryKey); + subpacketGenerator.setIssuerFingerprint(false, primarySecretKey); if (revocationAttributes != null) { RevocationAttributes.Reason reason = revocationAttributes.getReason(); if (reason != RevocationAttributes.Reason.NO_REASON @@ -377,15 +308,15 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { subpacketGenerator.setRevocationReason(false, revocationAttributes.getReason().code(), revocationAttributes.getDescription()); } - PGPSignatureGenerator signatureGenerator = SignatureUtils.getSignatureGeneratorFor(primaryKey); + PGPSignatureGenerator signatureGenerator = SignatureUtils.getSignatureGeneratorFor(primarySecretKey); signatureGenerator.setHashedSubpackets(subpacketGenerator.generate()); signatureGenerator.init(SignatureType.CERTIFICATION_REVOCATION.getCode(), privateKey); - PGPSignature revocationSignature = signatureGenerator.generateCertification(userId, publicKey); - publicKey = PGPPublicKey.addCertification(publicKey, userId, revocationSignature); + PGPSignature revocationSignature = signatureGenerator.generateCertification(userId, primaryPublicKey); + primaryPublicKey = PGPPublicKey.addCertification(primaryPublicKey, userId, revocationSignature); PGPPublicKeyRing publicKeyRing = KeyRingUtils.publicKeyRingFrom(secretKeyRing); - publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, publicKey); + publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, primaryPublicKey); secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing); return this; @@ -503,32 +434,18 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { return oldSignature; } - - @Override - public PGPSignature createRevocationCertificate(OpenPgpV4Fingerprint fingerprint, - SecretKeyRingProtector secretKeyRingProtector, + public PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) throws PGPException { - PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(fingerprint.getKeyId()); - if (revokeeSubKey == null) { - throw new NoSuchElementException("No subkey with fingerprint " + fingerprint + " found."); - } - + PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(); PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes); return revocationCertificate; } @Override - public PGPSignature createRevocationCertificate(long subKeyId, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) - throws PGPException { - PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(subKeyId); - if (revokeeSubKey == null) { - throw new NoSuchElementException("No subkey with id " + Long.toHexString(subKeyId) + " found."); - } - + public PGPSignature createRevocationCertificate(long subkeyId, SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) throws PGPException { + PGPPublicKey revokeeSubKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId); PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes); return revocationCertificate; } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java index fde7908f..b5ce6723 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditorInterface.java @@ -36,12 +36,19 @@ import org.pgpainless.util.selection.userid.SelectUserId; public interface SecretKeyRingEditorInterface { + /** + * Add a user-id to the key ring. + * + * @param userId user-id + * @param secretKeyRingProtector protector to unlock the secret key + * @return the builder + */ default SecretKeyRingEditorInterface addUserId(UserId userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { return addUserId(userId.toString(), secretKeyRingProtector); } /** - * Add a user-id to the primary key of the key ring. + * Add a user-id to the key ring. * * @param userId user-id * @param secretKeyRingProtector protector to unlock the secret key @@ -49,22 +56,8 @@ public interface SecretKeyRingEditorInterface { */ SecretKeyRingEditorInterface addUserId(String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException; - default SecretKeyRingEditorInterface addUserId(OpenPgpV4Fingerprint fingerprint, UserId userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { - return addUserId(fingerprint, userId.toString(), secretKeyRingProtector); - } - - default SecretKeyRingEditorInterface addUserId(OpenPgpV4Fingerprint fingerprint, String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { - return addUserId(fingerprint.getKeyId(), userId, secretKeyRingProtector); - } - - default SecretKeyRingEditorInterface addUserId(long keyId, UserId userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { - return addUserId(keyId, userId.toString(), secretKeyRingProtector); - } - - SecretKeyRingEditorInterface addUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException; - /** - * Remove a user-id from the primary key of the key ring. + * Remove a user-id from the key ring. * * @param userId exact user-id to be removed * @param secretKeyRingProtector protector to unlock the secret key @@ -72,22 +65,26 @@ public interface SecretKeyRingEditorInterface { */ SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector secretKeyRingProtector); - default SecretKeyRingEditorInterface deleteUserId(OpenPgpV4Fingerprint fingerprint, String userId, SecretKeyRingProtector secretKeyRingProtector) { - return deleteUserId(fingerprint.getKeyId(), userId, secretKeyRingProtector); - } - - default SecretKeyRingEditorInterface deleteUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) { - return deleteUserIds(keyId, SelectUserId.exactMatch(userId), secretKeyRingProtector); + /** + * Remove a user-id from the key ring. + * + * @param userId exact user-id to be removed + * @param secretKeyRingProtector protector to unlock the secret key + * @return the builder + */ + default SecretKeyRingEditorInterface deleteUserId(UserId userId, SecretKeyRingProtector secretKeyRingProtector) { + return deleteUserId(userId.toString(), secretKeyRingProtector); } + /** + * Delete all user-ids from the key, which match the provided {@link SelectUserId} strategy. + * + * @param selectionStrategy strategy to select user-ids + * @param secretKeyRingProtector protector to unlock the secret key + * @return the builder + */ SecretKeyRingEditorInterface deleteUserIds(SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector); - default SecretKeyRingEditorInterface deleteUserIds(OpenPgpV4Fingerprint fingerprint, SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector) { - return deleteUserIds(fingerprint.getKeyId(), selectionStrategy, secretKeyRingProtector); - } - - SecretKeyRingEditorInterface deleteUserIds(long keyId, SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector); - /** * Add a subkey to the key ring. * The subkey will be generated from the provided {@link KeySpec}. @@ -129,6 +126,7 @@ public interface SecretKeyRingEditorInterface { /** * Revoke the key ring. + * The revocation will be a hard revocation, rendering the whole key invalid for any past or future signatures. * * @param secretKeyRingProtector protector of the primary key * @return the builder @@ -139,7 +137,8 @@ public interface SecretKeyRingEditorInterface { } /** - * Revoke the key ring. + * Revoke the key ring using the provided revocation attributes. + * The attributes define, whether or not the revocation was a hard revocation or not. * * @param secretKeyRingProtector protector of the primary key * @param revocationAttributes reason for the revocation @@ -209,88 +208,30 @@ public interface SecretKeyRingEditorInterface { RevocationAttributes revocationAttributes) throws PGPException; - /** - * Revoke the given userID on any key in the key ring that is currently carrying the userID. - * - * @param userId userId to revoke - * @param secretKeyRingProtector protector to unlock the primary key - * @return the builder - */ - default SecretKeyRingEditorInterface revokeUserIdOnAllSubkeys(String userId, - SecretKeyRingProtector secretKeyRingProtector) - throws PGPException { - return revokeUserIdOnAllSubkeys(userId, secretKeyRingProtector, null); - } /** - * Revoke the given userID on any key in the key ring that is currently carrying the userID. + * Revoke the given userID. + * The revocation will be a hard revocation, rendering the user-id invalid for any past or future signatures. * * @param userId userId to revoke * @param secretKeyRingProtector protector to unlock the primary key - * @param revocationAttributes reason for the revocation - * @return the builder - */ - SecretKeyRingEditorInterface revokeUserIdOnAllSubkeys(String userId, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) - throws PGPException; - - /** - * Revoke the given userID on the key that belongs to the given fingerprint. - * - * @param userId userId to revoke - * @param subkeyFingerprint fingerprint of the key on which the userID should be revoked - * @param secretKeyRingProtector protector to unlock the primary key * @return the builder */ default SecretKeyRingEditorInterface revokeUserId(String userId, - OpenPgpV4Fingerprint subkeyFingerprint, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { - return revokeUserId(userId, subkeyFingerprint, secretKeyRingProtector, null); + return revokeUserId(userId, secretKeyRingProtector, null); } /** - * Revoke the given userID on the key that belongs to the given fingerprint. + * Revoke the given userID using the provided revocation attributes. * * @param userId userId to revoke - * @param subkeyFingerprint fingerprint of the key on which the userID should be revoked * @param secretKeyRingProtector protector to unlock the primary key * @param revocationAttributes reason for the revocation * @return the builder */ SecretKeyRingEditorInterface revokeUserId(String userId, - OpenPgpV4Fingerprint subkeyFingerprint, - SecretKeyRingProtector secretKeyRingProtector, - RevocationAttributes revocationAttributes) - throws PGPException; - - /** - * Revoke the given userID on the key that belongs to the given key ID. - * - * @param userId userId to revoke - * @param subKeyId ID of the subkey on which we the userID should be revoked - * @param secretKeyRingProtector protector to unlock the primary key - * @return the builder - */ - default SecretKeyRingEditorInterface revokeUserId(String userId, - long subKeyId, - SecretKeyRingProtector secretKeyRingProtector) - throws PGPException { - return revokeUserId(userId, subKeyId, secretKeyRingProtector, null); - } - - /** - * Revoke the given userID on the key that belongs to the given key ID. - * - * @param userId userId to revoke - * @param subkeyId ID of the subkey on which we the userID should be revoked - * @param secretKeyRingProtector protector to unlock the primary key - * @param revocationAttributes reason for the revocation - * @return the builder - */ - SecretKeyRingEditorInterface revokeUserId(String userId, - long subkeyId, SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) throws PGPException; @@ -300,9 +241,8 @@ public interface SecretKeyRingEditorInterface { * If the key is supposed to never expire, then an expiration date of null is expected. * * @param expiration new expiration date or null - * @param secretKeyRingProtector - * @return - * @throws PGPException + * @param secretKeyRingProtector to unlock the secret key + * @return the builder */ SecretKeyRingEditorInterface setExpirationDate(Date expiration, SecretKeyRingProtector secretKeyRingProtector) @@ -324,28 +264,25 @@ public interface SecretKeyRingEditorInterface { /** * Create a detached revocation certificate, which can be used to revoke the specified key. * - * @param fingerprint fingerprint of the key to be revoked. Can be primary or sub key. * @param secretKeyRingProtector protector to unlock the primary key. * @param revocationAttributes reason for the revocation * @return revocation certificate */ - PGPSignature createRevocationCertificate(OpenPgpV4Fingerprint fingerprint, - SecretKeyRingProtector secretKeyRingProtector, + PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) throws PGPException; - /** - * Create a detached revocation certificate, which can be used to revoke the specified key. - * - * @param subKeyId id of the key to be revoked. Can be primary or sub key. - * @param secretKeyRingProtector protector to unlock the primary key. - * @param revocationAttributes reason for the revocation - * @return revocation certificate - */ - PGPSignature createRevocationCertificate(long subKeyId, + PGPSignature createRevocationCertificate(long subkeyId, SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) - throws PGPException; + throws PGPException; + + default PGPSignature createRevocationCertificate(OpenPgpV4Fingerprint subkeyFingerprint, + SecretKeyRingProtector secretKeyRingProtector, + RevocationAttributes revocationAttributes) + throws PGPException { + return createRevocationCertificate(subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes); + } /** * Change the passphrase of the whole key ring. diff --git a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/SigningTest.java b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/SigningTest.java index 0e4f54c0..49223c71 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/SigningTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/encryption_signing/SigningTest.java @@ -136,7 +136,7 @@ public class SigningTest { .modernKeyRing("alice", "password123"); SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword("password123"), secretKeys); secretKeys = PGPainless.modifyKeyRing(secretKeys) - .revokeUserIdOnAllSubkeys("alice", protector) + .revokeUserId("alice", protector) .done(); final PGPSecretKeyRing fSecretKeys = secretKeys; diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java index 763f6813..f00e7cca 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/info/UserIdRevocationTest.java @@ -64,7 +64,7 @@ public class UserIdRevocationTest { // make a copy with revoked subkey PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys) - .revokeUserIdOnAllSubkeys("secondary@key.id", new UnprotectedKeysProtector()) + .revokeUserId("secondary@key.id", new UnprotectedKeysProtector()) .done(); KeyRingInfo info = PGPainless.inspectKeyRing(revoked); @@ -78,7 +78,7 @@ public class UserIdRevocationTest { assertTrue(info.isUserIdValid("secondary@key.id")); // key on original secret key ring is still valid revoked = PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("secondary@key.id", secretKeys.getSecretKey().getKeyID(), new UnprotectedKeysProtector()) + .revokeUserId("secondary@key.id", new UnprotectedKeysProtector()) .done(); info = PGPainless.inspectKeyRing(revoked); userIds = info.getUserIds(); @@ -103,7 +103,7 @@ public class UserIdRevocationTest { .build(); secretKeys = PGPainless.modifyKeyRing(secretKeys) - .revokeUserIdOnAllSubkeys("secondary@key.id", new UnprotectedKeysProtector(), + .revokeUserId("secondary@key.id", new UnprotectedKeysProtector(), RevocationAttributes.createCertificateRevocation() .withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID) .withDescription("I lost my mail password")) @@ -123,10 +123,8 @@ public class UserIdRevocationTest { SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); - assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("cryptie@encrypted.key", 1L, protector)); - assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("cryptie@encrypted.key", TestKeys.EMIL_FINGERPRINT, protector)); + assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) + .revokeSubKey(1L, protector)); } @Test @@ -136,9 +134,7 @@ public class UserIdRevocationTest { .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("invalid@user.id", TestKeys.CRYPTIE_FINGERPRINT, protector)); - assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("invalid@user.id", TestKeys.CRYPTIE_KEY_ID, protector)); + .revokeUserId("invalid@user.id", protector)); } @Test @@ -148,7 +144,7 @@ public class UserIdRevocationTest { .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .revokeUserId("cryptie@encrypted.key", secretKeys.getSecretKey().getKeyID(), protector, + .revokeUserId("cryptie@encrypted.key", protector, RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED) .withDescription("This is not a valid certification revocation reason."))); } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/modification/AddUserIdTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/modification/AddUserIdTest.java index 8c94be98..3872efbb 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/key/modification/AddUserIdTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/key/modification/AddUserIdTest.java @@ -69,14 +69,6 @@ public class AddUserIdTest { assertFalse(userIds.hasNext()); } - - @Test - public void addUserId_NoSuchElementExceptionForMissingKey() throws IOException, PGPException { - PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); - assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .addUserId(0L, TestKeys.CRYPTIE_UID, new UnprotectedKeysProtector())); - } - @Test public void deleteUserId_noSuchElementExceptionForMissingUserId() throws IOException, PGPException { PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); @@ -84,13 +76,6 @@ public class AddUserIdTest { .deleteUserId("invalid@user.id", new UnprotectedKeysProtector())); } - @Test - public void deleteUserId_noSuchElementExceptionForMissingKey() throws IOException, PGPException { - PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); - assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) - .deleteUserId(0L, TestKeys.CRYPTIE_UID, new UnprotectedKeysProtector())); - } - @Test public void deleteExistingAndAddNewUserIdToExistingKeyRing() throws PGPException, IOException { final String ARMORED_PRIVATE_KEY =