mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-10 02:39:39 +02:00
Delete SignaturePicker class
This commit is contained in:
parent
dc1da5ff49
commit
264eb1c8a6
2 changed files with 0 additions and 407 deletions
|
@ -1,383 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package org.pgpainless.signature.consumer
|
|
||||||
|
|
||||||
import java.util.Date
|
|
||||||
import org.bouncycastle.openpgp.PGPKeyRing
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey
|
|
||||||
import org.bouncycastle.openpgp.PGPSignature
|
|
||||||
import org.pgpainless.algorithm.SignatureType
|
|
||||||
import org.pgpainless.bouncycastle.extensions.getPublicKeyFor
|
|
||||||
import org.pgpainless.bouncycastle.extensions.isExpired
|
|
||||||
import org.pgpainless.bouncycastle.extensions.wasIssuedBy
|
|
||||||
import org.pgpainless.exception.SignatureValidationException
|
|
||||||
import org.pgpainless.policy.Policy
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick signatures from keys.
|
|
||||||
*
|
|
||||||
* The format of a V4 OpenPGP key is:
|
|
||||||
*
|
|
||||||
* Primary-Key [Revocation Self Signature] [Direct Key Signature...] User ID [Signature ...] [User
|
|
||||||
* ID [Signature ...] ...] [User Attribute [Signature ...] ...] [[Subkey
|
|
||||||
* [Binding-Signature-Revocation] Primary-Key-Binding-Signature] ...]
|
|
||||||
*/
|
|
||||||
class SignaturePicker {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validation date most recent valid key revocation signature. If there are hard
|
|
||||||
* revocation signatures, the latest hard revocation sig is picked, even if it was created
|
|
||||||
* after validationDate or if it is already expired.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime date of signature validation
|
|
||||||
* @return most recent, valid key revocation signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentRevocationSelfSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
return getSortedSignaturesOfType(primaryKey, SignatureType.KEY_REVOCATION).lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureVerifier.verifyKeyRevocationSignature(
|
|
||||||
it, primaryKey, policy, referenceTime)
|
|
||||||
true // valid
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false // not valid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate most recent, valid direct key signature. This method might
|
|
||||||
* return null, if there is no direct key self-signature which is valid at validationDate.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return direct-key self-signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentDirectKeySelfSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
return pickCurrentDirectKeySignature(primaryKey, primaryKey, policy, referenceTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentDirectKeySignature(
|
|
||||||
signingKey: PGPPublicKey,
|
|
||||||
signedKey: PGPPublicKey,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
return getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY).lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureVerifier.verifyDirectKeySignature(
|
|
||||||
it, signingKey, signedKey, policy, referenceTime)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest direct key signature. This method might return an
|
|
||||||
* expired signature. If there are more than one direct-key signature, and some of those are
|
|
||||||
* not expired, the latest non-expired yet already effective direct-key signature will be
|
|
||||||
* returned.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return latest direct key signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickLatestDirectKeySignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
return pickLatestDirectKeySignature(
|
|
||||||
keyRing.publicKey, keyRing.publicKey, policy, referenceTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest direct key signature made by signingKey on signedKey.
|
|
||||||
* This method might return an expired signature. If a non-expired direct-key signature
|
|
||||||
* exists, the latest non-expired yet already effective direct-key signature will be
|
|
||||||
* returned.
|
|
||||||
*
|
|
||||||
* @param signingKey signing key (key that made the sig)
|
|
||||||
* @param signedKey signed key (key that carries the sig)
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime date of validation
|
|
||||||
* @return latest direct key sig
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickLatestDirectKeySignature(
|
|
||||||
signingKey: PGPPublicKey,
|
|
||||||
signedKey: PGPPublicKey,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
var latest: PGPSignature? = null
|
|
||||||
return getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY).lastOrNull {
|
|
||||||
try {
|
|
||||||
SignatureValidator.signatureIsOfType(SignatureType.DIRECT_KEY).verify(it)
|
|
||||||
SignatureValidator.signatureStructureIsAcceptable(signingKey, policy).verify(it)
|
|
||||||
SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it)
|
|
||||||
if (latest != null && !latest!!.isExpired(referenceTime)) {
|
|
||||||
SignatureValidator.signatureIsNotYetExpired(referenceTime).verify(it)
|
|
||||||
}
|
|
||||||
SignatureValidator.correctSignatureOverKey(signingKey, signedKey).verify(it)
|
|
||||||
latest = it
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate most recent, valid user-id revocation signature. If there are
|
|
||||||
* hard revocation signatures, the latest hard revocation sig is picked, even if it was
|
|
||||||
* created after validationDate or if it is already expired.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param userId user-Id that gets revoked
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return revocation signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentUserIdRevocationSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
userId: CharSequence,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
return getSortedSignaturesOfType(primaryKey, SignatureType.CERTIFICATION_REVOCATION)
|
|
||||||
.lastOrNull {
|
|
||||||
keyRing.getPublicKeyFor(it)
|
|
||||||
?: return@lastOrNull false // signature made by external key. skip.
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureVerifier.verifyUserIdRevocation(
|
|
||||||
userId.toString(), it, primaryKey, policy, referenceTime)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false // signature not valid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest, valid certification self-signature for the given
|
|
||||||
* user-id. This method might return null, if there is no certification self signature for
|
|
||||||
* that user-id which is valid at validationDate.
|
|
||||||
*
|
|
||||||
* @param keyRing keyring
|
|
||||||
* @param userId userid
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return user-id certification
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentUserIdCertificationSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
userId: CharSequence,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
return primaryKey
|
|
||||||
.getSignaturesForID(userId.toString())
|
|
||||||
.asSequence()
|
|
||||||
.sortedWith(SignatureCreationDateComparator())
|
|
||||||
.lastOrNull {
|
|
||||||
return@lastOrNull it.wasIssuedBy(primaryKey) &&
|
|
||||||
try {
|
|
||||||
SignatureVerifier.verifyUserIdCertification(
|
|
||||||
userId.toString(), it, primaryKey, policy, referenceTime)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest certification self-signature for the given user-id.
|
|
||||||
* This method might return an expired signature. If a non-expired user-id certification
|
|
||||||
* signature exists, the latest non-expired yet already effective user-id certification
|
|
||||||
* signature for the given user-id will be returned.
|
|
||||||
*
|
|
||||||
* @param keyRing keyring
|
|
||||||
* @param userId userid
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return user-id certification
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickLatestUserIdCertificationSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
userId: CharSequence,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
return primaryKey
|
|
||||||
.getSignaturesForID(userId.toString())
|
|
||||||
.asSequence()
|
|
||||||
.sortedWith(SignatureCreationDateComparator())
|
|
||||||
.lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureValidator.wasPossiblyMadeByKey(primaryKey).verify(it)
|
|
||||||
SignatureValidator.signatureIsCertification().verify(it)
|
|
||||||
SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy)
|
|
||||||
.verify(it)
|
|
||||||
SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it)
|
|
||||||
SignatureValidator.correctSignatureOverUserId(
|
|
||||||
userId.toString(), primaryKey, primaryKey)
|
|
||||||
.verify(it)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate most recent, valid subkey revocation signature. If there are
|
|
||||||
* hard revocation signatures, the latest hard revocation sig is picked, even if it was
|
|
||||||
* created after validationDate or if it is already expired.
|
|
||||||
*
|
|
||||||
* @param keyRing keyring
|
|
||||||
* @param subkey subkey
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validation date
|
|
||||||
* @return subkey revocation signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentSubkeyBindingRevocationSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
subkey: PGPPublicKey,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
require(primaryKey.keyID != subkey.keyID) {
|
|
||||||
"Primary key cannot have subkey binding revocations."
|
|
||||||
}
|
|
||||||
return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_REVOCATION).lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureVerifier.verifySubkeyBindingRevocation(
|
|
||||||
it, primaryKey, subkey, policy, referenceTime)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest, valid subkey binding signature for the given subkey.
|
|
||||||
* This method might return null, if there is no subkey binding signature which is valid at
|
|
||||||
* validationDate.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param subkey subkey
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime date of validation
|
|
||||||
* @return most recent valid subkey binding signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickCurrentSubkeyBindingSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
subkey: PGPPublicKey,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
require(primaryKey.keyID != subkey.keyID) {
|
|
||||||
"Primary key cannot have subkey binding signatures."
|
|
||||||
}
|
|
||||||
return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING).lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureVerifier.verifySubkeyBindingSignature(
|
|
||||||
it, primaryKey, subkey, policy, referenceTime)
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pick the at validationDate latest subkey binding signature for the given subkey. This
|
|
||||||
* method might return an expired signature. If a non-expired subkey binding signature
|
|
||||||
* exists, the latest non-expired yet already effective subkey binding signature for the
|
|
||||||
* given subkey will be returned.
|
|
||||||
*
|
|
||||||
* @param keyRing key ring
|
|
||||||
* @param subkey subkey
|
|
||||||
* @param policy policy
|
|
||||||
* @param referenceTime validationDate
|
|
||||||
* @return subkey binding signature
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun pickLatestSubkeyBindingSignature(
|
|
||||||
keyRing: PGPKeyRing,
|
|
||||||
subkey: PGPPublicKey,
|
|
||||||
policy: Policy,
|
|
||||||
referenceTime: Date
|
|
||||||
): PGPSignature? {
|
|
||||||
val primaryKey = keyRing.publicKey
|
|
||||||
require(primaryKey.keyID != subkey.keyID) {
|
|
||||||
"Primary key cannot have subkey binding signatures."
|
|
||||||
}
|
|
||||||
var latest: PGPSignature? = null
|
|
||||||
return getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING).lastOrNull {
|
|
||||||
return@lastOrNull try {
|
|
||||||
SignatureValidator.signatureIsOfType(SignatureType.SUBKEY_BINDING).verify(it)
|
|
||||||
SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy).verify(it)
|
|
||||||
SignatureValidator.signatureDoesNotPredateSignee(subkey).verify(it)
|
|
||||||
SignatureValidator.signatureIsAlreadyEffective(referenceTime).verify(it)
|
|
||||||
// if the currently latest signature is not yet expired, check if the next
|
|
||||||
// candidate is not yet expired
|
|
||||||
if (latest != null && !latest!!.isExpired(referenceTime)) {
|
|
||||||
SignatureValidator.signatureIsNotYetExpired(referenceTime).verify(it)
|
|
||||||
}
|
|
||||||
SignatureValidator.correctSubkeyBindingSignature(primaryKey, subkey).verify(it)
|
|
||||||
latest = it
|
|
||||||
true
|
|
||||||
} catch (e: SignatureValidationException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
private fun getSortedSignaturesOfType(
|
|
||||||
key: PGPPublicKey,
|
|
||||||
type: SignatureType
|
|
||||||
): List<PGPSignature> =
|
|
||||||
key.getSignaturesOfType(type.code)
|
|
||||||
.asSequence()
|
|
||||||
.sortedWith(SignatureCreationDateComparator())
|
|
||||||
.toList()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,13 +9,10 @@ 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.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -32,11 +29,9 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation;
|
import org.bouncycastle.openpgp.api.OpenPGPImplementation;
|
||||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.pgpainless.PGPainless;
|
|
||||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import org.pgpainless.algorithm.Feature;
|
import org.pgpainless.algorithm.Feature;
|
||||||
import org.pgpainless.algorithm.HashAlgorithm;
|
import org.pgpainless.algorithm.HashAlgorithm;
|
||||||
|
@ -44,29 +39,10 @@ import org.pgpainless.algorithm.SignatureType;
|
||||||
import org.pgpainless.key.TestKeys;
|
import org.pgpainless.key.TestKeys;
|
||||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import org.pgpainless.key.protection.UnlockSecretKey;
|
import org.pgpainless.key.protection.UnlockSecretKey;
|
||||||
import org.pgpainless.signature.consumer.SignaturePicker;
|
|
||||||
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||||
|
|
||||||
public class SignatureSubpacketsUtilTest {
|
public class SignatureSubpacketsUtilTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetKeyExpirationTimeAsDate() {
|
|
||||||
PGPainless api = PGPainless.getInstance();
|
|
||||||
OpenPGPKey secretKeys = api.generateKey()
|
|
||||||
.modernKeyRing("Expire");
|
|
||||||
Date expiration = Date.from(new Date().toInstant().plus(365, ChronoUnit.DAYS));
|
|
||||||
secretKeys = api.modify(secretKeys)
|
|
||||||
.setExpirationDate(expiration, SecretKeyRingProtector.unprotectedKeys())
|
|
||||||
.done();
|
|
||||||
|
|
||||||
PGPSignature expirationSig = SignaturePicker.pickCurrentUserIdCertificationSignature(
|
|
||||||
secretKeys.getPGPSecretKeyRing(), "Expire", api.getAlgorithmPolicy(), new Date());
|
|
||||||
OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = api.inspect(secretKeys).getSigningSubkeys().get(0);
|
|
||||||
|
|
||||||
assertThrows(IllegalArgumentException.class, () ->
|
|
||||||
SignatureSubpacketsUtil.getKeyExpirationTimeAsDate(expirationSig, notTheRightKey.getPGPPublicKey()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetRevocable() throws PGPException, IOException {
|
public void testGetRevocable() throws PGPException, IOException {
|
||||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue