mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-30 08:12:06 +01:00
SecretKeyRingEditor: UserIDs only reside on primary keys
This commit is contained in:
parent
57c11a63e5
commit
77800f26e8
5 changed files with 101 additions and 266 deletions
|
@ -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;
|
publicKey = addUserIdToPubKey(userId, privateKey, publicKey);
|
||||||
PGPPublicKey publicKey = secretKey.getPublicKey();
|
primaryKey = PGPSecretKey.replacePublicKey(primaryKey, publicKey);
|
||||||
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(secretKey, secretKeyRingProtector);
|
|
||||||
publicKey = addUserIdToPubKey(userId, privateKey, publicKey);
|
|
||||||
secretKey = PGPSecretKey.replacePublicKey(secretKey, 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();
|
||||||
|
List<String> 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()) {
|
while (publicKeyIterator.hasNext()) {
|
||||||
PGPPublicKey publicKey = publicKeyIterator.next();
|
publicKeys.add(publicKeyIterator.next());
|
||||||
if (publicKey.getKeyID() == keyId) {
|
|
||||||
foundKey = true;
|
|
||||||
List<String> 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -302,72 +270,35 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretKeyRingEditorInterface revokeUserIdOnAllSubkeys(String userId,
|
public SecretKeyRingEditorInterface revokeUserId(String userId,
|
||||||
SecretKeyRingProtector secretKeyRingProtector,
|
SecretKeyRingProtector secretKeyRingProtector,
|
||||||
RevocationAttributes revocationAttributes)
|
RevocationAttributes revocationAttributes)
|
||||||
throws PGPException {
|
throws PGPException {
|
||||||
Iterator<PGPPublicKey> iterator = secretKeyRing.getPublicKeys();
|
Iterator<String> userIds = secretKeyRing.getPublicKey().getUserIDs();
|
||||||
while (iterator.hasNext()) {
|
boolean found = false;
|
||||||
PGPPublicKey publicKey = iterator.next();
|
while (userIds.hasNext()) {
|
||||||
try {
|
if (userId.equals(userIds.next())) {
|
||||||
revokeUserId(userId, new OpenPgpV4Fingerprint(publicKey), secretKeyRingProtector, revocationAttributes);
|
found = true;
|
||||||
} catch (IllegalArgumentException | NoSuchElementException e) {
|
break;
|
||||||
// skip
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
if (!found) {
|
||||||
}
|
throw new NoSuchElementException("No user-id '" + userId + "' found on the key.");
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
}
|
||||||
|
return doRevokeUserId(userId, secretKeyRingProtector, revocationAttributes);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
SecretKeyRingProtector secretKeyRingProtector,
|
|
||||||
RevocationAttributes revocationAttributes)
|
RevocationAttributes revocationAttributes)
|
||||||
throws PGPException;
|
throws PGPException;
|
||||||
|
|
||||||
/**
|
PGPSignature createRevocationCertificate(long subkeyId,
|
||||||
* 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;
|
||||||
|
|
||||||
|
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.
|
* Change the passphrase of the whole key ring.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.")));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
Loading…
Reference in a new issue