1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-26 22:32:07 +01:00

SecretKeyRingEditor: Restructure arguments of modification methods

This commit is contained in:
Paul Schaub 2021-11-27 14:50:04 +01:00
parent 5e85e975cd
commit 151d3c7b96
6 changed files with 383 additions and 147 deletions

View file

@ -254,8 +254,8 @@ public class KeyRingInfo {
/** /**
* Return the primary user-id of the key ring. * Return the primary user-id of the key ring.
* *
* Note: If no user-id is marked as primary key using a {@link PrimaryUserID} packet, this method returns the * Note: If no user-id is marked as primary key using a {@link PrimaryUserID} packet,
* first valid user-id, otherwise null. * this method returns the first valid user-id, otherwise null.
* *
* @return primary user-id or null * @return primary user-id or null
*/ */
@ -278,7 +278,7 @@ public class KeyRingInfo {
PrimaryUserID subpacket = SignatureSubpacketsUtil.getPrimaryUserId(signature); PrimaryUserID subpacket = SignatureSubpacketsUtil.getPrimaryUserId(signature);
if (subpacket != null && subpacket.isPrimaryUserID()) { if (subpacket != null && subpacket.isPrimaryUserID()) {
// if there are multiple primary userIDs, return most recently signed // if there are multiple primary userIDs, return most recently signed
if (modificationDate == null || modificationDate.before(signature.getCreationTime())) { if (modificationDate == null || !signature.getCreationTime().before(modificationDate)) {
primaryUserId = userId; primaryUserId = userId;
modificationDate = signature.getCreationTime(); modificationDate = signature.getCreationTime();
} }

View file

@ -87,18 +87,19 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface addUserId( public SecretKeyRingEditorInterface addUserId(
String userId, @Nonnull CharSequence userId,
SecretKeyRingProtector secretKeyRingProtector) @Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return addUserId(userId, null, secretKeyRingProtector); return addUserId(userId, null, secretKeyRingProtector);
} }
@Override @Override
public SecretKeyRingEditorInterface addUserId( public SecretKeyRingEditorInterface addUserId(
String userId, @Nonnull CharSequence userId,
@Nullable SelfSignatureSubpackets.Callback signatureSubpacketCallback, @Nullable SelfSignatureSubpackets.Callback signatureSubpacketCallback,
SecretKeyRingProtector protector) throws PGPException { @Nonnull SecretKeyRingProtector protector)
userId = sanitizeUserId(userId); throws PGPException {
String sanitizeUserId = sanitizeUserId(userId);
// user-id certifications live on the primary key // user-id certifications live on the primary key
PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); PGPSecretKey primaryKey = secretKeyRing.getSecretKey();
@ -134,25 +135,39 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
builder.applyCallback(signatureSubpacketCallback); builder.applyCallback(signatureSubpacketCallback);
PGPSignature signature = builder.build(primaryKey.getPublicKey(), userId); PGPSignature signature = builder.build(primaryKey.getPublicKey(), sanitizeUserId);
secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, userId, signature); secretKeyRing = KeyRingUtils.injectCertification(secretKeyRing, sanitizeUserId, signature);
return this; return this;
} }
@Override
public SecretKeyRingEditorInterface addPrimaryUserId(
@Nonnull CharSequence userId, @Nonnull SecretKeyRingProtector protector)
throws PGPException {
return addUserId(
userId,
new SelfSignatureSubpackets.Callback() {
@Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
hashedSubpackets.setPrimaryUserId();
}
},
protector);
}
// TODO: Move to utility class? // TODO: Move to utility class?
private String sanitizeUserId(String userId) { private String sanitizeUserId(@Nonnull CharSequence userId) {
userId = userId.trim();
// TODO: Further research how to sanitize user IDs. // TODO: Further research how to sanitize user IDs.
// eg. what about newlines? // eg. what about newlines?
return userId; return userId.toString().trim();
} }
@Override @Override
public SecretKeyRingEditorInterface addSubKey( public SecretKeyRingEditorInterface addSubKey(
@Nonnull KeySpec keySpec, @Nonnull KeySpec keySpec,
@Nonnull Passphrase subKeyPassphrase, @Nonnull Passphrase subKeyPassphrase,
SecretKeyRingProtector secretKeyRingProtector) @Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException { throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException {
PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec); PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec);
@ -179,7 +194,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Nonnull KeySpec keySpec, @Nonnull KeySpec keySpec,
@Nullable Passphrase subkeyPassphrase, @Nullable Passphrase subkeyPassphrase,
@Nullable SelfSignatureSubpackets.Callback subpacketsCallback, @Nullable SelfSignatureSubpackets.Callback subpacketsCallback,
SecretKeyRingProtector secretKeyRingProtector) @Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException { throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec); PGPKeyPair keyPair = KeyRingBuilder.generateKeyPair(keySpec);
@ -195,11 +210,11 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface addSubKey( public SecretKeyRingEditorInterface addSubKey(
PGPKeyPair subkey, @Nonnull PGPKeyPair subkey,
@Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback,
SecretKeyRingProtector subkeyProtector, @Nonnull SecretKeyRingProtector subkeyProtector,
SecretKeyRingProtector primaryKeyProtector, @Nonnull SecretKeyRingProtector primaryKeyProtector,
KeyFlag keyFlag, @Nonnull KeyFlag keyFlag,
KeyFlag... additionalKeyFlags) KeyFlag... additionalKeyFlags)
throws PGPException, IOException { throws PGPException, IOException {
KeyFlag[] flags = concat(keyFlag, additionalKeyFlags); KeyFlag[] flags = concat(keyFlag, additionalKeyFlags);
@ -251,7 +266,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
@Override @Override
public SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector, public SecretKeyRingEditorInterface revoke(@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
RevocationSignatureSubpackets.Callback callback = callbackFromRevocationAttributes(revocationAttributes); RevocationSignatureSubpackets.Callback callback = callbackFromRevocationAttributes(revocationAttributes);
@ -259,7 +274,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
@Override @Override
public SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector, public SecretKeyRingEditorInterface revoke(@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException { throws PGPException {
return revokeSubKey(secretKeyRing.getSecretKey().getKeyID(), secretKeyRingProtector, subpacketsCallback); return revokeSubKey(secretKeyRing.getSecretKey().getKeyID(), secretKeyRingProtector, subpacketsCallback);
@ -276,7 +291,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface revokeSubKey(long keyID, public SecretKeyRingEditorInterface revokeSubKey(long keyID,
SecretKeyRingProtector secretKeyRingProtector, @Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException { throws PGPException {
// retrieve subkey to be revoked // retrieve subkey to be revoked
@ -290,8 +305,8 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
@Override @Override
public PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector, public PGPSignature createRevocationCertificate(@Nonnull SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(); PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey();
PGPSignature revocationCertificate = generateRevocation( PGPSignature revocationCertificate = generateRevocation(
@ -302,8 +317,8 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public PGPSignature createRevocationCertificate( public PGPSignature createRevocationCertificate(
long subkeyId, long subkeyId,
SecretKeyRingProtector secretKeyRingProtector, @Nonnull SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
PGPPublicKey revokeeSubkey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId); PGPPublicKey revokeeSubkey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId);
RevocationSignatureSubpackets.Callback callback = callbackFromRevocationAttributes(revocationAttributes); RevocationSignatureSubpackets.Callback callback = callbackFromRevocationAttributes(revocationAttributes);
@ -313,15 +328,15 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public PGPSignature createRevocationCertificate( public PGPSignature createRevocationCertificate(
long subkeyId, long subkeyId,
SecretKeyRingProtector secretKeyRingProtector, @Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback)
throws PGPException { throws PGPException {
PGPPublicKey revokeeSubkey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId); PGPPublicKey revokeeSubkey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId);
return generateRevocation(secretKeyRingProtector, revokeeSubkey, certificateSubpacketsCallback); return generateRevocation(secretKeyRingProtector, revokeeSubkey, certificateSubpacketsCallback);
} }
private PGPSignature generateRevocation(SecretKeyRingProtector protector, private PGPSignature generateRevocation(@Nonnull SecretKeyRingProtector protector,
PGPPublicKey revokeeSubKey, @Nonnull PGPPublicKey revokeeSubKey,
@Nullable RevocationSignatureSubpackets.Callback callback) @Nullable RevocationSignatureSubpackets.Callback callback)
throws PGPException { throws PGPException {
PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); PGPSecretKey primaryKey = secretKeyRing.getSecretKey();
@ -336,7 +351,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
private static RevocationSignatureSubpackets.Callback callbackFromRevocationAttributes( private static RevocationSignatureSubpackets.Callback callbackFromRevocationAttributes(
RevocationAttributes attributes) { @Nullable RevocationAttributes attributes) {
return new RevocationSignatureSubpackets.Callback() { return new RevocationSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) {
@ -348,8 +363,9 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
@Override @Override
public SecretKeyRingEditorInterface revokeUserId(String userId, public SecretKeyRingEditorInterface revokeUserId(
SecretKeyRingProtector secretKeyRingProtector, @Nonnull CharSequence userId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
if (revocationAttributes != null) { if (revocationAttributes != null) {
@ -374,26 +390,41 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface revokeUserId( public SecretKeyRingEditorInterface revokeUserId(
String userId, @Nonnull CharSequence userId,
SecretKeyRingProtector secretKeyRingProtector, @Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketCallback)
throws PGPException { throws PGPException {
Iterator<String> userIds = secretKeyRing.getPublicKey().getUserIDs(); String sanitized = sanitizeUserId(userId);
boolean found = false; return revokeUserIds(
while (userIds.hasNext()) { SelectUserId.exactMatch(sanitized),
if (userId.equals(userIds.next())) { secretKeyRingProtector,
found = true; subpacketCallback);
break;
}
}
if (!found) {
throw new NoSuchElementException("No user-id '" + userId + "' found on the key.");
}
return doRevokeUserId(userId, secretKeyRingProtector, subpacketCallback);
} }
@Override @Override
public SecretKeyRingEditorInterface revokeUserIds(SelectUserId userIdSelector, SecretKeyRingProtector secretKeyRingProtector, @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) throws PGPException { public SecretKeyRingEditorInterface revokeUserIds(
@Nonnull SelectUserId userIdSelector,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes)
throws PGPException {
return revokeUserIds(
userIdSelector,
secretKeyRingProtector,
new RevocationSignatureSubpackets.Callback() {
@Override
public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) {
hashedSubpackets.setRevocationReason(revocationAttributes);
}
});
}
@Override
public SecretKeyRingEditorInterface revokeUserIds(
@Nonnull SelectUserId userIdSelector,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException {
List<String> selected = userIdSelector.selectUserIds(secretKeyRing); List<String> selected = userIdSelector.selectUserIds(secretKeyRing);
if (selected.isEmpty()) { if (selected.isEmpty()) {
throw new NoSuchElementException("No matching user-ids found on the key."); throw new NoSuchElementException("No matching user-ids found on the key.");
@ -406,8 +437,9 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return this; return this;
} }
private SecretKeyRingEditorInterface doRevokeUserId(String userId, private SecretKeyRingEditorInterface doRevokeUserId(
SecretKeyRingProtector protector, @Nonnull String userId,
@Nonnull SecretKeyRingProtector protector,
@Nullable RevocationSignatureSubpackets.Callback callback) @Nullable RevocationSignatureSubpackets.Callback callback)
throws PGPException { throws PGPException {
PGPSecretKey primarySecretKey = secretKeyRing.getSecretKey(); PGPSecretKey primarySecretKey = secretKeyRing.getSecretKey();
@ -424,16 +456,18 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
} }
@Override @Override
public SecretKeyRingEditorInterface setExpirationDate(Date expiration, public SecretKeyRingEditorInterface setExpirationDate(
SecretKeyRingProtector secretKeyRingProtector) @Nullable Date expiration,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return setExpirationDate(OpenPgpFingerprint.of(secretKeyRing), expiration, secretKeyRingProtector); return setExpirationDate(OpenPgpFingerprint.of(secretKeyRing), expiration, secretKeyRingProtector);
} }
@Override @Override
public SecretKeyRingEditorInterface setExpirationDate(OpenPgpFingerprint fingerprint, public SecretKeyRingEditorInterface setExpirationDate(
Date expiration, @Nonnull OpenPgpFingerprint fingerprint,
SecretKeyRingProtector secretKeyRingProtector) @Nullable Date expiration,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
List<PGPSecretKey> secretKeyList = new ArrayList<>(); List<PGPSecretKey> secretKeyList = new ArrayList<>();

View file

@ -21,7 +21,6 @@ import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.protection.KeyRingProtectionSettings; import org.pgpainless.key.protection.KeyRingProtectionSettings;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.key.util.UserId;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets; import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets; import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -36,23 +35,39 @@ public interface SecretKeyRingEditorInterface {
* @param secretKeyRingProtector protector to unlock the secret key * @param secretKeyRingProtector protector to unlock the secret key
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface addUserId(UserId userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { SecretKeyRingEditorInterface addUserId(
return addUserId(userId.toString(), secretKeyRingProtector); @Nonnull CharSequence userId,
} @Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException;
/** /**
* Add a user-id to the key ring. * Add a user-id to the key ring.
* *
* @param userId user-id * @param userId user-id
* @param secretKeyRingProtector protector to unlock the secret key * @param signatureSubpacketCallback callback that can be used to modify signature subpackets of the
* certification signature.
* @param protector protector to unlock the primary secret key
* @return the builder
* @throws PGPException
*/
SecretKeyRingEditorInterface addUserId(
@Nonnull CharSequence userId,
@Nullable SelfSignatureSubpackets.Callback signatureSubpacketCallback,
@Nonnull SecretKeyRingProtector protector)
throws PGPException;
/**
* Add a user-id to the key ring and mark it as primary.
* If the user-id is already present, a new certification signature will be created.
*
* @param userId user id
* @param protector protector to unlock the secret key
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface addUserId(String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException; SecretKeyRingEditorInterface addPrimaryUserId(
@Nonnull CharSequence userId,
SecretKeyRingEditorInterface addUserId( @Nonnull SecretKeyRingProtector protector)
String userId, throws PGPException;
@Nullable SelfSignatureSubpackets.Callback signatureSubpacketCallback,
SecretKeyRingProtector protector) throws PGPException;
/** /**
* Add a subkey to the key ring. * Add a subkey to the key ring.
@ -63,22 +78,48 @@ public interface SecretKeyRingEditorInterface {
* @param secretKeyRingProtector protector to unlock the secret key of the key ring * @param secretKeyRingProtector protector to unlock the secret key of the key ring
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, SecretKeyRingEditorInterface addSubKey(
@Nullable Passphrase subKeyPassphrase, @Nonnull KeySpec keySpec,
SecretKeyRingProtector secretKeyRingProtector) @Nonnull Passphrase subKeyPassphrase,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException; throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException;
SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, /**
@Nullable Passphrase subkeyPassphrase, * Add a subkey to the key ring.
* The subkey will be generated from the provided {@link KeySpec}.
*
* @param keySpec key spec of the subkey
* @param subkeyPassphrase passphrase to encrypt the subkey
* @param subpacketsCallback callback to modify the subpackets of the subkey binding signature
* @param secretKeyRingProtector protector to unlock the primary key
* @return builder
*/
SecretKeyRingEditorInterface addSubKey(
@Nonnull KeySpec keySpec,
@Nonnull Passphrase subkeyPassphrase,
@Nullable SelfSignatureSubpackets.Callback subpacketsCallback, @Nullable SelfSignatureSubpackets.Callback subpacketsCallback,
SecretKeyRingProtector secretKeyRingProtector) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException; @Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException;
SecretKeyRingEditorInterface addSubKey(PGPKeyPair subkey, /**
* Add a subkey to the key ring.
*
* @param subkey subkey key pair
* @param bindingSignatureCallback callback to modify the subpackets of the subkey binding signature
* @param subkeyProtector protector to unlock and encrypt the subkey
* @param primaryKeyProtector protector to unlock the primary key
* @param keyFlag first key flag for the subkey
* @param additionalKeyFlags optional additional key flags
* @return builder
*/
SecretKeyRingEditorInterface addSubKey(
@Nonnull PGPKeyPair subkey,
@Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback, @Nullable SelfSignatureSubpackets.Callback bindingSignatureCallback,
SecretKeyRingProtector subkeyProtector, @Nonnull SecretKeyRingProtector subkeyProtector,
SecretKeyRingProtector primaryKeyProtector, @Nonnull SecretKeyRingProtector primaryKeyProtector,
KeyFlag keyFlag, @Nonnull KeyFlag keyFlag,
KeyFlag... additionalKeyFlags) throws PGPException, IOException; KeyFlag... additionalKeyFlags)
throws PGPException, IOException;
/** /**
* Revoke the key ring. * Revoke the key ring.
@ -87,24 +128,36 @@ public interface SecretKeyRingEditorInterface {
* @param secretKeyRingProtector protector of the primary key * @param secretKeyRingProtector protector of the primary key
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector) default SecretKeyRingEditorInterface revoke(
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return revoke(secretKeyRingProtector, (RevocationAttributes) null); return revoke(secretKeyRingProtector, (RevocationAttributes) null);
} }
/** /**
* Revoke the key ring using the provided revocation attributes. * Revoke the key ring using the provided revocation attributes.
* The attributes define, whether or not the revocation was a hard revocation or not. * The attributes define, whether the revocation was a hard revocation or not.
* *
* @param secretKeyRingProtector protector of the primary key * @param secretKeyRingProtector protector of the primary key
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingEditorInterface revoke(
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
SecretKeyRingEditorInterface revoke(SecretKeyRingProtector secretKeyRingProtector, /**
* Revoke the key ring.
* You can use the {@link RevocationSignatureSubpackets.Callback} to modify the revocation signatures
* subpackets, eg. in order to define whether this is a hard or soft revocation.
*
* @param secretKeyRingProtector protector to unlock the primary secret key
* @param subpacketsCallback callback to modify the revocations subpackets
* @return builder
*/
SecretKeyRingEditorInterface revoke(
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) throws PGPException; @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) throws PGPException;
/** /**
@ -112,12 +165,18 @@ public interface SecretKeyRingEditorInterface {
* The subkey with the provided fingerprint will be revoked. * The subkey with the provided fingerprint will be revoked.
* If no suitable subkey is found, a {@link java.util.NoSuchElementException} will be thrown. * If no suitable subkey is found, a {@link java.util.NoSuchElementException} will be thrown.
* *
* Note: This method will hard-revoke the provided subkey, meaning it cannot be re-certified at a later point.
* If you instead want to temporarily "deactivate" the subkey, provide a soft revocation reason,
* eg. by calling {@link #revokeSubKey(OpenPgpFingerprint, SecretKeyRingProtector, RevocationAttributes)}
* and provide a suitable {@link RevocationAttributes} object.
*
* @param fingerprint fingerprint of the subkey to be revoked * @param fingerprint fingerprint of the subkey to be revoked
* @param secretKeyRingProtector protector to unlock the secret key ring * @param secretKeyRingProtector protector to unlock the secret key ring
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface revokeSubKey(OpenPgpFingerprint fingerprint, default SecretKeyRingEditorInterface revokeSubKey(
SecretKeyRingProtector secretKeyRingProtector) @Nonnull OpenPgpFingerprint fingerprint,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return revokeSubKey(fingerprint, secretKeyRingProtector, null); return revokeSubKey(fingerprint, secretKeyRingProtector, null);
} }
@ -132,7 +191,8 @@ public interface SecretKeyRingEditorInterface {
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface revokeSubKey(OpenPgpFingerprint fingerprint, default SecretKeyRingEditorInterface revokeSubKey(
OpenPgpFingerprint fingerprint,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
@ -144,14 +204,15 @@ public interface SecretKeyRingEditorInterface {
/** /**
* Revoke the subkey binding signature of a subkey. * Revoke the subkey binding signature of a subkey.
* The subkey with the provided key-id will be revoked. * The subkey with the provided key-id will be revoked.
* If no suitable subkey is found, q {@link java.util.NoSuchElementException} will be thrown. * If no suitable subkey is found, a {@link java.util.NoSuchElementException} will be thrown.
* *
* @param subKeyId id of the subkey * @param subKeyId id of the subkey
* @param secretKeyRingProtector protector to unlock the primary key * @param secretKeyRingProtector protector to unlock the primary key
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface revokeSubKey(long subKeyId, SecretKeyRingEditorInterface revokeSubKey(
long subKeyId,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
@ -161,31 +222,59 @@ public interface SecretKeyRingEditorInterface {
* The subkey with the provided key-id will be revoked. * The subkey with the provided key-id will be revoked.
* If no suitable subkey is found, q {@link java.util.NoSuchElementException} will be thrown. * If no suitable subkey is found, q {@link java.util.NoSuchElementException} will be thrown.
* *
* Note: This method will hard-revoke the subkey, meaning it cannot be re-bound at a later point.
* If you intend to re-bind the subkey in order to make it usable again at a later point in time,
* consider using {@link #revokeSubKey(long, SecretKeyRingProtector, RevocationAttributes)}
* and provide a soft revocation reason.
*
* @param subKeyId id of the subkey * @param subKeyId id of the subkey
* @param secretKeyRingProtector protector to unlock the secret key ring * @param secretKeyRingProtector protector to unlock the secret key ring
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface revokeSubKey(long subKeyId, default SecretKeyRingEditorInterface revokeSubKey(
SecretKeyRingProtector secretKeyRingProtector) long subKeyId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return revokeSubKey(subKeyId, secretKeyRingProtector, (RevocationSignatureSubpackets.Callback) null);
return revokeSubKey(
subKeyId,
secretKeyRingProtector,
(RevocationSignatureSubpackets.Callback) null);
} }
SecretKeyRingEditorInterface revokeSubKey(long keyID, /**
SecretKeyRingProtector secretKeyRingProtector, * Revoke the subkey binding signature of a subkey.
* The subkey with the provided key-id will be revoked.
* If no suitable subkey is found, q {@link java.util.NoSuchElementException} will be thrown.
*
* The provided subpackets callback is used to modify the revocation signatures subpackets.
*
* @param keyID id of the subkey
* @param secretKeyRingProtector protector to unlock the secret key ring
* @param subpacketsCallback callback which can be used to modify the subpackets of the revocation
* signature
* @return the builder
*/
SecretKeyRingEditorInterface revokeSubKey(
long keyID,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException; throws PGPException;
/** /**
* Revoke the given userID. * Revoke the given userID.
* The revocation will be a hard revocation, rendering the user-id invalid for any past or future signatures. * The revocation will be a hard revocation, rendering the user-id invalid for any past or future signatures.
* If you intend to re-certify the user-id at a later point in time, consider using
* {@link #revokeUserId(CharSequence, SecretKeyRingProtector, RevocationAttributes)} instead and provide
* a soft revocation reason.
* *
* @param userId userId to revoke * @param userId userId to revoke
* @param secretKeyRingProtector protector to unlock the primary key * @param secretKeyRingProtector protector to unlock the primary key
* @return the builder * @return the builder
*/ */
default SecretKeyRingEditorInterface revokeUserId(String userId, default SecretKeyRingEditorInterface revokeUserId(
SecretKeyRingProtector secretKeyRingProtector) @Nonnull CharSequence userId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { throws PGPException {
return revokeUserId(userId, secretKeyRingProtector, (RevocationAttributes) null); return revokeUserId(userId, secretKeyRingProtector, (RevocationAttributes) null);
} }
@ -198,18 +287,69 @@ public interface SecretKeyRingEditorInterface {
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface revokeUserId(String userId, SecretKeyRingEditorInterface revokeUserId(
SecretKeyRingProtector secretKeyRingProtector, @Nonnull CharSequence userId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
SecretKeyRingEditorInterface revokeUserId(String userId, /**
SecretKeyRingProtector secretKeyRingProtector, * Revoke the provided user-id.
* Note: If you don't provide a {@link RevocationSignatureSubpackets.Callback} which
* sets a revocation reason ({@link RevocationAttributes}), the revocation might be considered hard.
* So if you intend to re-certify the user-id at a later point to make it valid again,
* make sure to set a soft revocation reason in the signatures hashed area using the subpacket callback.
*
* @param userId userid to be revoked
* @param secretKeyRingProtector protector to unlock the primary secret key
* @param subpacketCallback callback to modify the revocations subpackets
* @return builder
*/
SecretKeyRingEditorInterface revokeUserId(
@Nonnull CharSequence userId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketCallback)
throws PGPException; throws PGPException;
SecretKeyRingEditorInterface revokeUserIds(SelectUserId userIdSelector, /**
SecretKeyRingProtector secretKeyRingProtector, * Revoke all user-ids that match the provided {@link SelectUserId} filter.
* The provided {@link RevocationAttributes} will be set as reason for revocation in each
* revocation signature.
*
* Note: If you intend to re-certify these user-ids at a later point, make sure to choose
* a soft revocation reason. See {@link RevocationAttributes.Reason} for more information.
*
* @param userIdSelector user-id selector
* @param secretKeyRingProtector protector to unlock the primary secret key
* @param revocationAttributes revocation attributes
* @return builder
* @throws PGPException
*/
SecretKeyRingEditorInterface revokeUserIds(
@Nonnull SelectUserId userIdSelector,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes)
throws PGPException;
/**
* Revoke all user-ids that match the provided {@link SelectUserId} filter.
* The provided {@link RevocationSignatureSubpackets.Callback} will be used to modify the
* revocation signatures subpackets.
*
* Note: If you intend to re-certify these user-ids at a later point, make sure to set
* a soft revocation reason in the revocation signatures hashed subpacket area using the callback.
*
* See {@link RevocationAttributes.Reason} for more information.
*
* @param userIdSelector user-id selector
* @param secretKeyRingProtector protector to unlock the primary secret key
* @param subpacketsCallback callback to modify the revocations subpackets
* @return builder
* @throws PGPException
*/
SecretKeyRingEditorInterface revokeUserIds(
@Nonnull SelectUserId userIdSelector,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback subpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback subpacketsCallback)
throws PGPException; throws PGPException;
@ -221,8 +361,9 @@ public interface SecretKeyRingEditorInterface {
* @param secretKeyRingProtector to unlock the secret key * @param secretKeyRingProtector to unlock the secret key
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface setExpirationDate(Date expiration, SecretKeyRingEditorInterface setExpirationDate(
SecretKeyRingProtector secretKeyRingProtector) @Nullable Date expiration,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException; throws PGPException;
/** /**
@ -233,37 +374,70 @@ public interface SecretKeyRingEditorInterface {
* @param secretKeyRingProtector protector to unlock the priary key * @param secretKeyRingProtector protector to unlock the priary key
* @return the builder * @return the builder
*/ */
SecretKeyRingEditorInterface setExpirationDate(OpenPgpFingerprint fingerprint, SecretKeyRingEditorInterface setExpirationDate(
Date expiration, @Nonnull OpenPgpFingerprint fingerprint,
SecretKeyRingProtector secretKeyRingProtector) @Nullable Date expiration,
@Nonnull SecretKeyRingProtector secretKeyRingProtector)
throws PGPException; throws PGPException;
/** /**
* Create a detached revocation certificate, which can be used to revoke the specified key. * Create a detached revocation certificate, which can be used to revoke the whole key.
* *
* @param secretKeyRingProtector protector to unlock the primary key. * @param secretKeyRingProtector protector to unlock the primary key.
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return revocation certificate * @return revocation certificate
*/ */
PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector, PGPSignature createRevocationCertificate(
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
PGPSignature createRevocationCertificate(long subkeyId, /**
SecretKeyRingProtector secretKeyRingProtector, * Create a detached revocation certificate, which can be used to revoke the specified subkey.
*
* @param subkeyId id of the subkey to be revoked
* @param secretKeyRingProtector protector to unlock the primary key.
* @param revocationAttributes reason for the revocation
* @return revocation certificate
*/
PGPSignature createRevocationCertificate(
long subkeyId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
PGPSignature createRevocationCertificate(long subkeyId, /**
SecretKeyRingProtector secretKeyRingProtector, * Create a detached revocation certificate, which can be used to revoke the specified subkey.
*
* @param subkeyId id of the subkey to be revoked
* @param secretKeyRingProtector protector to unlock the primary key.
* @param certificateSubpacketsCallback callback to modify the subpackets of the revocation certificate.
* @return revocation certificate
*/
PGPSignature createRevocationCertificate(
long subkeyId,
@Nonnull SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback) @Nullable RevocationSignatureSubpackets.Callback certificateSubpacketsCallback)
throws PGPException; throws PGPException;
default PGPSignature createRevocationCertificate(OpenPgpFingerprint subkeyFingerprint, /**
* Create a detached revocation certificate, which can be used to revoke the specified subkey.
*
* @param subkeyFingerprint fingerprint of the subkey to be revoked
* @param secretKeyRingProtector protector to unlock the primary key.
* @param revocationAttributes reason for the revocation
* @return revocation certificate
*/
default PGPSignature createRevocationCertificate(
OpenPgpFingerprint subkeyFingerprint,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
@Nullable RevocationAttributes revocationAttributes) @Nullable RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
return createRevocationCertificate(subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes);
return createRevocationCertificate(
subkeyFingerprint.getKeyId(),
secretKeyRingProtector,
revocationAttributes);
} }
/** /**
@ -272,7 +446,8 @@ public interface SecretKeyRingEditorInterface {
* @param oldPassphrase old passphrase or null, if the key was unprotected * @param oldPassphrase old passphrase or null, if the key was unprotected
* @return next builder step * @return next builder step
*/ */
default WithKeyRingEncryptionSettings changePassphraseFromOldPassphrase(@Nullable Passphrase oldPassphrase) { default WithKeyRingEncryptionSettings changePassphraseFromOldPassphrase(
@Nullable Passphrase oldPassphrase) {
return changePassphraseFromOldPassphrase(oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings()); return changePassphraseFromOldPassphrase(oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings());
} }
@ -283,7 +458,8 @@ public interface SecretKeyRingEditorInterface {
* @param oldProtectionSettings custom settings for the old passphrase * @param oldProtectionSettings custom settings for the old passphrase
* @return next builder step * @return next builder step
*/ */
WithKeyRingEncryptionSettings changePassphraseFromOldPassphrase(@Nullable Passphrase oldPassphrase, WithKeyRingEncryptionSettings changePassphraseFromOldPassphrase(
@Nullable Passphrase oldPassphrase,
@Nonnull KeyRingProtectionSettings oldProtectionSettings); @Nonnull KeyRingProtectionSettings oldProtectionSettings);
/** /**
@ -296,12 +472,14 @@ public interface SecretKeyRingEditorInterface {
* @param oldPassphrase old passphrase * @param oldPassphrase old passphrase
* @return next builder step * @return next builder step
*/ */
default WithKeyRingEncryptionSettings changeSubKeyPassphraseFromOldPassphrase(@Nonnull Long keyId, default WithKeyRingEncryptionSettings changeSubKeyPassphraseFromOldPassphrase(
@Nonnull Long keyId,
@Nullable Passphrase oldPassphrase) { @Nullable Passphrase oldPassphrase) {
return changeSubKeyPassphraseFromOldPassphrase(keyId, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings()); return changeSubKeyPassphraseFromOldPassphrase(keyId, oldPassphrase, KeyRingProtectionSettings.secureDefaultSettings());
} }
WithKeyRingEncryptionSettings changeSubKeyPassphraseFromOldPassphrase(@Nonnull Long keyId, WithKeyRingEncryptionSettings changeSubKeyPassphraseFromOldPassphrase(
@Nonnull Long keyId,
@Nullable Passphrase oldPassphrase, @Nullable Passphrase oldPassphrase,
@Nonnull KeyRingProtectionSettings oldProtectionSettings); @Nonnull KeyRingProtectionSettings oldProtectionSettings);
@ -333,7 +511,8 @@ public interface SecretKeyRingEditorInterface {
* @param passphrase passphrase * @param passphrase passphrase
* @return editor builder * @return editor builder
*/ */
SecretKeyRingEditorInterface toNewPassphrase(Passphrase passphrase) throws PGPException; SecretKeyRingEditorInterface toNewPassphrase(Passphrase passphrase)
throws PGPException;
/** /**
* Leave the key unprotected. * Leave the key unprotected.

View file

@ -39,7 +39,7 @@ public class KeyGenerationSubpacketsTest {
@Test @Test
public void verifyDefaultSubpacketsForUserIdSignatures() public void verifyDefaultSubpacketsForUserIdSignatures()
throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, InterruptedException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice", null); PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice", null);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
@ -87,6 +87,9 @@ public class KeyGenerationSubpacketsTest {
assertEquals("Bob", info.getPrimaryUserId()); assertEquals("Bob", info.getPrimaryUserId());
// wait one sec so that it is clear that the new certification for alice is the most recent one
Thread.sleep(1000);
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.addUserId("Alice", new SelfSignatureSubpackets.Callback() { .addUserId("Alice", new SelfSignatureSubpackets.Callback() {
@Override @Override

View file

@ -6,6 +6,7 @@ package org.pgpainless.key.modification;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException; import java.io.IOException;
@ -16,6 +17,7 @@ import java.util.NoSuchElementException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -25,6 +27,7 @@ import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector; import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.key.protection.UnprotectedKeysProtector;
import org.pgpainless.key.util.UserId;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
public class AddUserIdTest { public class AddUserIdTest {
@ -109,4 +112,19 @@ public class AddUserIdTest {
assertEquals("cheshirecat@wonderland.lit", userIds.next()); assertEquals("cheshirecat@wonderland.lit", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
} }
@Test
public void addNewPrimaryUserIdTest() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
.modernKeyRing("Alice", null);
UserId bob = UserId.newBuilder().withName("Bob").noEmail().noComment().build();
assertNotEquals("Bob", PGPainless.inspectKeyRing(secretKeys).getPrimaryUserId());
secretKeys = PGPainless.modifyKeyRing(secretKeys)
.addPrimaryUserId(bob, SecretKeyRingProtector.unprotectedKeys())
.done();
assertEquals("Bob", PGPainless.inspectKeyRing(secretKeys).getPrimaryUserId());
}
} }

View file

@ -10,6 +10,8 @@ import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
import org.pgpainless.util.selection.userid.SelectUserId; import org.pgpainless.util.selection.userid.SelectUserId;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
@ -39,7 +41,7 @@ public class RevokeUserIdsTest {
assertTrue(info.isUserIdValid("Alice <alice@example.org>")); assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.revokeUserIds(SelectUserId.containsEmailAddress("alice@example.org"), protector, null) .revokeUserIds(SelectUserId.containsEmailAddress("alice@example.org"), protector, (RevocationSignatureSubpackets.Callback) null)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = PGPainless.inspectKeyRing(secretKeys);
@ -57,6 +59,6 @@ public class RevokeUserIdsTest {
PGPainless.modifyKeyRing(secretKeys).revokeUserIds( PGPainless.modifyKeyRing(secretKeys).revokeUserIds(
SelectUserId.containsEmailAddress("alice@example.org"), SelectUserId.containsEmailAddress("alice@example.org"),
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
null)); (RevocationAttributes) null));
} }
} }