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

SecretKeyRingEditor: UserIDs only reside on primary keys

This commit is contained in:
Paul Schaub 2021-05-28 23:14:20 +02:00
parent 57c11a63e5
commit 77800f26e8
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
5 changed files with 101 additions and 266 deletions

View file

@ -45,7 +45,6 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator; import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SignatureType; import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
@ -53,9 +52,8 @@ import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.generation.KeyRingBuilder; import org.pgpainless.key.generation.KeyRingBuilder;
import org.pgpainless.key.generation.KeySpec; 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.CachingSecretKeyRingProtector;
import org.pgpainless.key.protection.KeyRingProtectionSettings;
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.UnlockSecretKey; 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.KeyRingUtils;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.SignatureUtils; import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.util.Passphrase;
import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketGeneratorUtil;
import org.pgpainless.util.Passphrase;
import org.pgpainless.util.selection.userid.SelectUserId; import org.pgpainless.util.selection.userid.SelectUserId;
public class SecretKeyRingEditor implements SecretKeyRingEditorInterface { public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@ -86,31 +84,22 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface addUserId(String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException { 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); userId = sanitizeUserId(userId);
List<PGPSecretKey> secretKeyList = new ArrayList<>(); List<PGPSecretKey> secretKeyList = new ArrayList<>();
Iterator<PGPSecretKey> secretKeyIterator = secretKeyRing.getSecretKeys(); Iterator<PGPSecretKey> secretKeyIterator = secretKeyRing.getSecretKeys();
boolean found = false; // add user-id certificate to primary key
while (!found && secretKeyIterator.hasNext()) { PGPSecretKey primaryKey = secretKeyIterator.next();
PGPSecretKey secretKey = secretKeyIterator.next(); PGPPublicKey publicKey = primaryKey.getPublicKey();
if (secretKey.getKeyID() == keyId) { PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, secretKeyRingProtector);
found = true;
PGPPublicKey publicKey = secretKey.getPublicKey();
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, secretKeyRingProtector);
publicKey = addUserIdToPubKey(userId, privateKey, publicKey); publicKey = addUserIdToPubKey(userId, privateKey, publicKey);
secretKey = PGPSecretKey.replacePublicKey(secretKey, publicKey); primaryKey = PGPSecretKey.replacePublicKey(primaryKey, publicKey);
}
secretKeyList.add(secretKey);
}
if (!found) { secretKeyList.add(primaryKey);
throw new NoSuchElementException("Cannot find secret key with id " + Long.toHexString(keyId));
while (secretKeyIterator.hasNext()) {
secretKeyList.add(secretKeyIterator.next());
} }
secretKeyRing = new PGPSecretKeyRing(secretKeyList); secretKeyRing = new PGPSecretKeyRing(secretKeyList);
@ -143,53 +132,32 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
@Override @Override
public SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector protector) { public SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector protector) {
PGPPublicKey publicKey = secretKeyRing.getPublicKey(); return deleteUserIds(SelectUserId.exactMatch(userId), protector);
return deleteUserId(publicKey.getKeyID(), userId, protector);
} }
@Override @Override
public SecretKeyRingEditorInterface deleteUserIds(SelectUserId selectionStrategy, SecretKeyRingProtector secretKeyRingProtector) { 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<PGPPublicKey> publicKeys = new ArrayList<>(); List<PGPPublicKey> publicKeys = new ArrayList<>();
Iterator<PGPPublicKey> publicKeyIterator = secretKeyRing.getPublicKeys(); Iterator<PGPPublicKey> publicKeyIterator = secretKeyRing.getPublicKeys();
boolean foundKey = false; PGPPublicKey primaryKey = publicKeyIterator.next();
while (publicKeyIterator.hasNext()) { List<String> matchingUserIds = selectionStrategy.selectUserIds(iteratorToList(primaryKey.getUserIDs()));
PGPPublicKey publicKey = publicKeyIterator.next();
if (publicKey.getKeyID() == keyId) {
foundKey = true;
List<String> matchingUserIds = selectionStrategy.selectUserIds(iteratorToList(publicKey.getUserIDs()));
if (matchingUserIds.isEmpty()) { if (matchingUserIds.isEmpty()) {
throw new NoSuchElementException("Key " + Long.toHexString(keyId) + " does not have a matching user-id attribute."); throw new NoSuchElementException("Key does not have a matching user-id attribute.");
} }
for (String userId : matchingUserIds) { for (String userId : matchingUserIds) {
publicKey = PGPPublicKey.removeCertification(publicKey, userId); primaryKey = PGPPublicKey.removeCertification(primaryKey, userId);
} }
publicKeys.add(primaryKey);
while (publicKeyIterator.hasNext()) {
publicKeys.add(publicKeyIterator.next());
} }
publicKeys.add(publicKey);
}
if (!foundKey) {
throw new NoSuchElementException("Cannot find public key with id " + Long.toHexString(keyId));
}
PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(publicKeys); PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(publicKeys);
secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing); secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing);
return this; return this;
} }
private static boolean hasUserId(String userId, PGPPublicKey publicKey) {
boolean hasUserId = false;
Iterator<String> userIdIterator = publicKey.getUserIDs();
while (userIdIterator.hasNext()) {
hasUserId = userId.equals(userIdIterator.next());
if (hasUserId) break;
}
return hasUserId;
}
@Override @Override
public SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec, public SecretKeyRingEditorInterface addSubKey(@Nonnull KeySpec keySpec,
@Nonnull Passphrase subKeyPassphrase, @Nonnull Passphrase subKeyPassphrase,
@ -301,73 +269,36 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return this; return this;
} }
@Override
public SecretKeyRingEditorInterface revokeUserIdOnAllSubkeys(String userId,
SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes)
throws PGPException {
Iterator<PGPPublicKey> iterator = secretKeyRing.getPublicKeys();
while (iterator.hasNext()) {
PGPPublicKey publicKey = iterator.next();
try {
revokeUserId(userId, new OpenPgpV4Fingerprint(publicKey), secretKeyRingProtector, revocationAttributes);
} catch (IllegalArgumentException | NoSuchElementException e) {
// skip
}
}
return this;
}
@Override @Override
public SecretKeyRingEditorInterface revokeUserId(String userId, public SecretKeyRingEditorInterface revokeUserId(String userId,
OpenPgpV4Fingerprint subkeyFingerprint,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
PGPPublicKey publicKey = secretKeyRing.getPublicKey(subkeyFingerprint.getKeyId()); Iterator<String> userIds = secretKeyRing.getPublicKey().getUserIDs();
if (publicKey == null) { boolean found = false;
throw new IllegalArgumentException("Key ring does not carry a public key with fingerprint " + subkeyFingerprint); while (userIds.hasNext()) {
if (userId.equals(userIds.next())) {
found = true;
break;
} }
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeyRing);
if (!info.getUserIds().contains(userId)) {
throw new NoSuchElementException("Key " + subkeyFingerprint + " does not carry userID '" + userId + '\'');
} }
if (!found) {
return doRevokeUserId(userId, subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes); throw new NoSuchElementException("No user-id '" + userId + "' found on the key.");
} }
return doRevokeUserId(userId, 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);
} }
private SecretKeyRingEditorInterface doRevokeUserId(String userId, private SecretKeyRingEditorInterface doRevokeUserId(String userId,
long subKeyId,
SecretKeyRingProtector protector, SecretKeyRingProtector protector,
RevocationAttributes revocationAttributes) throws PGPException { RevocationAttributes revocationAttributes) throws PGPException {
PGPPublicKey publicKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subKeyId); PGPSecretKey primarySecretKey = secretKeyRing.getSecretKey();
PGPSecretKey primaryKey = secretKeyRing.getSecretKey(); PGPPublicKey primaryPublicKey = primarySecretKey.getPublicKey();
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primaryKey, protector); PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(primarySecretKey, protector);
PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator subpacketGenerator = new PGPSignatureSubpacketGenerator();
subpacketGenerator.setSignatureCreationTime(false, new Date()); subpacketGenerator.setSignatureCreationTime(false, new Date());
subpacketGenerator.setRevocable(false, false); subpacketGenerator.setRevocable(false, false);
subpacketGenerator.setIssuerFingerprint(false, primaryKey); subpacketGenerator.setIssuerFingerprint(false, primarySecretKey);
if (revocationAttributes != null) { if (revocationAttributes != null) {
RevocationAttributes.Reason reason = revocationAttributes.getReason(); RevocationAttributes.Reason reason = revocationAttributes.getReason();
if (reason != RevocationAttributes.Reason.NO_REASON if (reason != RevocationAttributes.Reason.NO_REASON
@ -377,15 +308,15 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
subpacketGenerator.setRevocationReason(false, revocationAttributes.getReason().code(), revocationAttributes.getDescription()); subpacketGenerator.setRevocationReason(false, revocationAttributes.getReason().code(), revocationAttributes.getDescription());
} }
PGPSignatureGenerator signatureGenerator = SignatureUtils.getSignatureGeneratorFor(primaryKey); PGPSignatureGenerator signatureGenerator = SignatureUtils.getSignatureGeneratorFor(primarySecretKey);
signatureGenerator.setHashedSubpackets(subpacketGenerator.generate()); signatureGenerator.setHashedSubpackets(subpacketGenerator.generate());
signatureGenerator.init(SignatureType.CERTIFICATION_REVOCATION.getCode(), privateKey); signatureGenerator.init(SignatureType.CERTIFICATION_REVOCATION.getCode(), privateKey);
PGPSignature revocationSignature = signatureGenerator.generateCertification(userId, publicKey); PGPSignature revocationSignature = signatureGenerator.generateCertification(userId, primaryPublicKey);
publicKey = PGPPublicKey.addCertification(publicKey, userId, revocationSignature); primaryPublicKey = PGPPublicKey.addCertification(primaryPublicKey, userId, revocationSignature);
PGPPublicKeyRing publicKeyRing = KeyRingUtils.publicKeyRingFrom(secretKeyRing); PGPPublicKeyRing publicKeyRing = KeyRingUtils.publicKeyRingFrom(secretKeyRing);
publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, publicKey); publicKeyRing = PGPPublicKeyRing.insertPublicKey(publicKeyRing, primaryPublicKey);
secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing); secretKeyRing = PGPSecretKeyRing.replacePublicKeys(secretKeyRing, publicKeyRing);
return this; return this;
@ -503,32 +434,18 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
return oldSignature; return oldSignature;
} }
@Override @Override
public PGPSignature createRevocationCertificate(OpenPgpV4Fingerprint fingerprint, public PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector,
SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException { throws PGPException {
PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(fingerprint.getKeyId()); PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey();
if (revokeeSubKey == null) {
throw new NoSuchElementException("No subkey with fingerprint " + fingerprint + " found.");
}
PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes); PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes);
return revocationCertificate; return revocationCertificate;
} }
@Override @Override
public PGPSignature createRevocationCertificate(long subKeyId, public PGPSignature createRevocationCertificate(long subkeyId, SecretKeyRingProtector secretKeyRingProtector, RevocationAttributes revocationAttributes) throws PGPException {
SecretKeyRingProtector secretKeyRingProtector, PGPPublicKey revokeeSubKey = KeyRingUtils.requirePublicKeyFrom(secretKeyRing, subkeyId);
RevocationAttributes revocationAttributes)
throws PGPException {
PGPPublicKey revokeeSubKey = secretKeyRing.getPublicKey(subKeyId);
if (revokeeSubKey == null) {
throw new NoSuchElementException("No subkey with id " + Long.toHexString(subKeyId) + " found.");
}
PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes); PGPSignature revocationCertificate = generateRevocation(secretKeyRingProtector, revokeeSubKey, revocationAttributes);
return revocationCertificate; return revocationCertificate;
} }

View file

@ -36,12 +36,19 @@ import org.pgpainless.util.selection.userid.SelectUserId;
public interface SecretKeyRingEditorInterface { 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 { default SecretKeyRingEditorInterface addUserId(UserId userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException {
return addUserId(userId.toString(), secretKeyRingProtector); 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 userId user-id
* @param secretKeyRingProtector protector to unlock the secret key * @param secretKeyRingProtector protector to unlock the secret key
@ -49,22 +56,8 @@ public interface SecretKeyRingEditorInterface {
*/ */
SecretKeyRingEditorInterface addUserId(String userId, SecretKeyRingProtector secretKeyRingProtector) throws PGPException; 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 userId exact user-id to be removed
* @param secretKeyRingProtector protector to unlock the secret key * @param secretKeyRingProtector protector to unlock the secret key
@ -72,22 +65,26 @@ public interface SecretKeyRingEditorInterface {
*/ */
SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector secretKeyRingProtector); SecretKeyRingEditorInterface deleteUserId(String userId, SecretKeyRingProtector secretKeyRingProtector);
default SecretKeyRingEditorInterface deleteUserId(OpenPgpV4Fingerprint fingerprint, String userId, SecretKeyRingProtector secretKeyRingProtector) { /**
return deleteUserId(fingerprint.getKeyId(), userId, secretKeyRingProtector); * Remove a user-id from the key ring.
} *
* @param userId exact user-id to be removed
default SecretKeyRingEditorInterface deleteUserId(long keyId, String userId, SecretKeyRingProtector secretKeyRingProtector) { * @param secretKeyRingProtector protector to unlock the secret key
return deleteUserIds(keyId, SelectUserId.exactMatch(userId), secretKeyRingProtector); * @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); 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. * Add a subkey to the key ring.
* The subkey will be generated from the provided {@link KeySpec}. * The subkey will be generated from the provided {@link KeySpec}.
@ -129,6 +126,7 @@ public interface SecretKeyRingEditorInterface {
/** /**
* Revoke the key ring. * 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 * @param secretKeyRingProtector protector of the primary key
* @return the builder * @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 secretKeyRingProtector protector of the primary key
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
@ -209,88 +208,30 @@ public interface SecretKeyRingEditorInterface {
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException; 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 userId userId to revoke
* @param secretKeyRingProtector protector to unlock the primary key * @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 * @return the builder
*/ */
default SecretKeyRingEditorInterface revokeUserId(String userId, default SecretKeyRingEditorInterface revokeUserId(String userId,
OpenPgpV4Fingerprint subkeyFingerprint,
SecretKeyRingProtector secretKeyRingProtector) SecretKeyRingProtector secretKeyRingProtector)
throws PGPException { 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 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 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 revokeUserId(String userId, 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, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException; 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. * If the key is supposed to never expire, then an expiration date of null is expected.
* *
* @param expiration new expiration date or null * @param expiration new expiration date or null
* @param secretKeyRingProtector * @param secretKeyRingProtector to unlock the secret key
* @return * @return the builder
* @throws PGPException
*/ */
SecretKeyRingEditorInterface setExpirationDate(Date expiration, SecretKeyRingEditorInterface setExpirationDate(Date expiration,
SecretKeyRingProtector secretKeyRingProtector) SecretKeyRingProtector secretKeyRingProtector)
@ -324,28 +264,25 @@ public interface SecretKeyRingEditorInterface {
/** /**
* 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 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 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(OpenPgpV4Fingerprint fingerprint, PGPSignature createRevocationCertificate(SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes)
throws PGPException;
PGPSignature createRevocationCertificate(long subkeyId,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException;
/** default PGPSignature createRevocationCertificate(OpenPgpV4Fingerprint subkeyFingerprint,
* 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,
SecretKeyRingProtector secretKeyRingProtector, SecretKeyRingProtector secretKeyRingProtector,
RevocationAttributes revocationAttributes) RevocationAttributes revocationAttributes)
throws PGPException; throws PGPException {
return createRevocationCertificate(subkeyFingerprint.getKeyId(), secretKeyRingProtector, revocationAttributes);
}
/** /**
* Change the passphrase of the whole key ring. * Change the passphrase of the whole key ring.

View file

@ -136,7 +136,7 @@ public class SigningTest {
.modernKeyRing("alice", "password123"); .modernKeyRing("alice", "password123");
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword("password123"), secretKeys); SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(Passphrase.fromPassword("password123"), secretKeys);
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.revokeUserIdOnAllSubkeys("alice", protector) .revokeUserId("alice", protector)
.done(); .done();
final PGPSecretKeyRing fSecretKeys = secretKeys; final PGPSecretKeyRing fSecretKeys = secretKeys;

View file

@ -64,7 +64,7 @@ public class UserIdRevocationTest {
// make a copy with revoked subkey // make a copy with revoked subkey
PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys) PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys)
.revokeUserIdOnAllSubkeys("secondary@key.id", new UnprotectedKeysProtector()) .revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(revoked); 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 assertTrue(info.isUserIdValid("secondary@key.id")); // key on original secret key ring is still valid
revoked = PGPainless.modifyKeyRing(secretKeys) revoked = PGPainless.modifyKeyRing(secretKeys)
.revokeUserId("secondary@key.id", secretKeys.getSecretKey().getKeyID(), new UnprotectedKeysProtector()) .revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
.done(); .done();
info = PGPainless.inspectKeyRing(revoked); info = PGPainless.inspectKeyRing(revoked);
userIds = info.getUserIds(); userIds = info.getUserIds();
@ -103,7 +103,7 @@ public class UserIdRevocationTest {
.build(); .build();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = PGPainless.modifyKeyRing(secretKeys)
.revokeUserIdOnAllSubkeys("secondary@key.id", new UnprotectedKeysProtector(), .revokeUserId("secondary@key.id", new UnprotectedKeysProtector(),
RevocationAttributes.createCertificateRevocation() RevocationAttributes.createCertificateRevocation()
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID) .withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
.withDescription("I lost my mail password")) .withDescription("I lost my mail password"))
@ -123,10 +123,8 @@ public class UserIdRevocationTest {
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
.revokeUserId("cryptie@encrypted.key", 1L, protector)); .revokeSubKey(1L, protector));
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys)
.revokeUserId("cryptie@encrypted.key", TestKeys.EMIL_FINGERPRINT, protector));
} }
@Test @Test
@ -136,9 +134,7 @@ public class UserIdRevocationTest {
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
.revokeUserId("invalid@user.id", TestKeys.CRYPTIE_FINGERPRINT, protector)); .revokeUserId("invalid@user.id", protector));
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
.revokeUserId("invalid@user.id", TestKeys.CRYPTIE_KEY_ID, protector));
} }
@Test @Test
@ -148,7 +144,7 @@ public class UserIdRevocationTest {
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) 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) RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED)
.withDescription("This is not a valid certification revocation reason."))); .withDescription("This is not a valid certification revocation reason.")));
} }

View file

@ -69,14 +69,6 @@ public class AddUserIdTest {
assertFalse(userIds.hasNext()); 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 @Test
public void deleteUserId_noSuchElementExceptionForMissingUserId() throws IOException, PGPException { public void deleteUserId_noSuchElementExceptionForMissingUserId() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
@ -84,13 +76,6 @@ public class AddUserIdTest {
.deleteUserId("invalid@user.id", new UnprotectedKeysProtector())); .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 @Test
public void deleteExistingAndAddNewUserIdToExistingKeyRing() throws PGPException, IOException { public void deleteExistingAndAddNewUserIdToExistingKeyRing() throws PGPException, IOException {
final String ARMORED_PRIVATE_KEY = final String ARMORED_PRIVATE_KEY =