mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-23 03:17:58 +01:00
Kotlin conversion: CertifyCertificate
This commit is contained in:
parent
39c5d12096
commit
de73b3b00b
3 changed files with 228 additions and 306 deletions
|
@ -1,298 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.key.certification;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.CertificationType;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.algorithm.Trustworthiness;
|
||||
import org.pgpainless.exception.KeyException;
|
||||
import org.pgpainless.key.OpenPgpFingerprint;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
import org.pgpainless.signature.builder.ThirdPartyDirectKeySignatureBuilder;
|
||||
import org.pgpainless.signature.builder.ThirdPartyCertificationSignatureBuilder;
|
||||
import org.pgpainless.signature.subpackets.CertificationSubpackets;
|
||||
import org.pgpainless.util.DateUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* API for creating certifications and delegations (Signatures) on keys.
|
||||
* This API can be used to sign another persons OpenPGP key.
|
||||
*
|
||||
* A certification over a user-id is thereby used to attest, that the user believes that the user-id really belongs
|
||||
* to the owner of the certificate.
|
||||
* A delegation over a key can be used to delegate trust by marking the certificate as a trusted introducer.
|
||||
*/
|
||||
public class CertifyCertificate {
|
||||
|
||||
/**
|
||||
* Create a certification over a User-Id.
|
||||
* By default, this method will use {@link CertificationType#GENERIC} to create the signature.
|
||||
* If you need to create another type of certification, use
|
||||
* {@link #userIdOnCertificate(String, PGPPublicKeyRing, CertificationType)} instead.
|
||||
*
|
||||
* @param userId user-id to certify
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
public CertificationOnUserId userIdOnCertificate(@Nonnull String userId,
|
||||
@Nonnull PGPPublicKeyRing certificate) {
|
||||
return userIdOnCertificate(userId, certificate, CertificationType.GENERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certification of the given {@link CertificationType} over a User-Id.
|
||||
*
|
||||
* @param userid user-id to certify
|
||||
* @param certificate certificate
|
||||
* @param certificationType type of signature
|
||||
* @return API
|
||||
*/
|
||||
public CertificationOnUserId userIdOnCertificate(@Nonnull String userid,
|
||||
@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull CertificationType certificationType) {
|
||||
return new CertificationOnUserId(userid, certificate, certificationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer
|
||||
* (see {@link #certificate(PGPPublicKeyRing, Trustworthiness)}).
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
public DelegationOnCertificate certificate(@Nonnull PGPPublicKeyRing certificate) {
|
||||
return certificate(certificate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) containing a {@link org.bouncycastle.bcpg.sig.TrustSignature} packet
|
||||
* over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer.
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @param trustworthiness trustworthiness of the certificate
|
||||
* @return API
|
||||
*/
|
||||
public DelegationOnCertificate certificate(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nullable Trustworthiness trustworthiness) {
|
||||
return new DelegationOnCertificate(certificate, trustworthiness);
|
||||
}
|
||||
|
||||
public static class CertificationOnUserId {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final String userId;
|
||||
private final CertificationType certificationType;
|
||||
|
||||
CertificationOnUserId(@Nonnull String userId,
|
||||
@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull CertificationType certificationType) {
|
||||
this.userId = userId;
|
||||
this.certificate = certificate;
|
||||
this.certificationType = certificationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the certification using the given key.
|
||||
*
|
||||
* @param certificationKey key used to create the certification
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationOnUserIdWithSubpackets withKey(@Nonnull PGPSecretKeyRing certificationKey,
|
||||
@Nonnull SecretKeyRingProtector protector)
|
||||
throws PGPException {
|
||||
PGPSecretKey secretKey = getCertifyingSecretKey(certificationKey);
|
||||
|
||||
ThirdPartyCertificationSignatureBuilder sigBuilder = new ThirdPartyCertificationSignatureBuilder(
|
||||
certificationType.asSignatureType(), secretKey, protector);
|
||||
|
||||
return new CertificationOnUserIdWithSubpackets(certificate, userId, sigBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CertificationOnUserIdWithSubpackets {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final String userId;
|
||||
private final ThirdPartyCertificationSignatureBuilder sigBuilder;
|
||||
|
||||
CertificationOnUserIdWithSubpackets(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull String userId,
|
||||
@Nonnull ThirdPartyCertificationSignatureBuilder sigBuilder) {
|
||||
this.certificate = certificate;
|
||||
this.userId = userId;
|
||||
this.sigBuilder = sigBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the certification.
|
||||
*
|
||||
* @param subpacketCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult buildWithSubpackets(@Nonnull CertificationSubpackets.Callback subpacketCallback)
|
||||
throws PGPException {
|
||||
sigBuilder.applyCallback(subpacketCallback);
|
||||
return build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the certification signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult build() throws PGPException {
|
||||
PGPSignature signature = sigBuilder.build(certificate, userId);
|
||||
PGPPublicKeyRing certifiedCertificate = KeyRingUtils.injectCertification(certificate, userId, signature);
|
||||
return new CertificationResult(certifiedCertificate, signature);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DelegationOnCertificate {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final Trustworthiness trustworthiness;
|
||||
|
||||
DelegationOnCertificate(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nullable Trustworthiness trustworthiness) {
|
||||
this.certificate = certificate;
|
||||
this.trustworthiness = trustworthiness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the delegation using the given certification key.
|
||||
*
|
||||
* @param certificationKey key to create the certification with
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public DelegationOnCertificateWithSubpackets withKey(@Nonnull PGPSecretKeyRing certificationKey,
|
||||
@Nonnull SecretKeyRingProtector protector)
|
||||
throws PGPException {
|
||||
PGPSecretKey secretKey = getCertifyingSecretKey(certificationKey);
|
||||
|
||||
ThirdPartyDirectKeySignatureBuilder sigBuilder = new ThirdPartyDirectKeySignatureBuilder(secretKey, protector);
|
||||
if (trustworthiness != null) {
|
||||
sigBuilder.getHashedSubpackets().setTrust(true, trustworthiness.getDepth(), trustworthiness.getAmount());
|
||||
}
|
||||
return new DelegationOnCertificateWithSubpackets(certificate, sigBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DelegationOnCertificateWithSubpackets {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final ThirdPartyDirectKeySignatureBuilder sigBuilder;
|
||||
|
||||
DelegationOnCertificateWithSubpackets(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull ThirdPartyDirectKeySignatureBuilder sigBuilder) {
|
||||
this.certificate = certificate;
|
||||
this.sigBuilder = sigBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the delegation signature.
|
||||
*
|
||||
* @param subpacketsCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult buildWithSubpackets(@Nonnull CertificationSubpackets.Callback subpacketsCallback)
|
||||
throws PGPException {
|
||||
sigBuilder.applyCallback(subpacketsCallback);
|
||||
return build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the delegation signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult build() throws PGPException {
|
||||
PGPPublicKey delegatedKey = certificate.getPublicKey();
|
||||
PGPSignature delegation = sigBuilder.build(delegatedKey);
|
||||
PGPPublicKeyRing delegatedCertificate = KeyRingUtils.injectCertification(certificate, delegatedKey, delegation);
|
||||
return new CertificationResult(delegatedCertificate, delegation);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CertificationResult {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final PGPSignature certification;
|
||||
|
||||
CertificationResult(@Nonnull PGPPublicKeyRing certificate, @Nonnull PGPSignature certification) {
|
||||
this.certificate = certificate;
|
||||
this.certification = certification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the signature.
|
||||
*
|
||||
* @return signature
|
||||
*/
|
||||
@Nonnull
|
||||
public PGPSignature getCertification() {
|
||||
return certification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the certificate, which now contains the signature.
|
||||
*
|
||||
* @return certificate + signature
|
||||
*/
|
||||
@Nonnull
|
||||
public PGPPublicKeyRing getCertifiedCertificate() {
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
|
||||
private static PGPSecretKey getCertifyingSecretKey(PGPSecretKeyRing certificationKey) {
|
||||
Date now = DateUtil.now();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(certificationKey, now);
|
||||
|
||||
// We only support certification-capable primary keys
|
||||
OpenPgpFingerprint fingerprint = info.getFingerprint();
|
||||
PGPPublicKey certificationPubKey = info.getPublicKey(fingerprint);
|
||||
assert (certificationPubKey != null);
|
||||
if (!info.isKeyValidlyBound(certificationPubKey.getKeyID())) {
|
||||
throw new KeyException.RevokedKeyException(fingerprint);
|
||||
}
|
||||
|
||||
if (!info.isUsableForThirdPartyCertification()) {
|
||||
throw new KeyException.UnacceptableThirdPartyCertificationKeyException(fingerprint);
|
||||
}
|
||||
|
||||
Date expirationDate = info.getExpirationDateForUse(KeyFlag.CERTIFY_OTHER);
|
||||
if (expirationDate != null && expirationDate.before(now)) {
|
||||
throw new KeyException.ExpiredKeyException(fingerprint, expirationDate);
|
||||
}
|
||||
|
||||
PGPSecretKey secretKey = certificationKey.getSecretKey(certificationPubKey.getKeyID());
|
||||
if (secretKey == null) {
|
||||
throw new KeyException.MissingSecretKeyException(fingerprint, certificationPubKey.getKeyID());
|
||||
}
|
||||
return secretKey;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* API for key certifications.
|
||||
*/
|
||||
package org.pgpainless.key.certification;
|
|
@ -0,0 +1,228 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.key.certification
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSecretKey
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.CertificationType
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.algorithm.Trustworthiness
|
||||
import org.pgpainless.exception.KeyException
|
||||
import org.pgpainless.exception.KeyException.ExpiredKeyException
|
||||
import org.pgpainless.exception.KeyException.MissingSecretKeyException
|
||||
import org.pgpainless.exception.KeyException.RevokedKeyException
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector
|
||||
import org.pgpainless.key.util.KeyRingUtils
|
||||
import org.pgpainless.signature.builder.ThirdPartyCertificationSignatureBuilder
|
||||
import org.pgpainless.signature.builder.ThirdPartyDirectKeySignatureBuilder
|
||||
import org.pgpainless.signature.subpackets.CertificationSubpackets
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* API for creating certifications and delegations (Signatures) on keys.
|
||||
* This API can be used to sign another persons OpenPGP key.
|
||||
*
|
||||
* A certification over a user-id is thereby used to attest, that the user believes that the user-id really belongs
|
||||
* to the owner of the certificate.
|
||||
* A delegation over a key can be used to delegate trust by marking the certificate as a trusted introducer.
|
||||
*/
|
||||
class CertifyCertificate {
|
||||
|
||||
/**
|
||||
* Create a certification over a User-Id.
|
||||
* By default, this method will use [CertificationType.GENERIC] to create the signature.
|
||||
*
|
||||
* @param userId user-id to certify
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
fun userIdOnCertificate(userId: String, certificate: PGPPublicKeyRing): CertificationOnUserId =
|
||||
userIdOnCertificate(userId, certificate, CertificationType.GENERIC)
|
||||
|
||||
/**
|
||||
* Create a certification of the given [CertificationType] over a User-Id.
|
||||
*
|
||||
* @param userid user-id to certify
|
||||
* @param certificate certificate
|
||||
* @param certificationType type of signature
|
||||
* @return API
|
||||
*/
|
||||
fun userIdOnCertificate(userId: String, certificate: PGPPublicKeyRing, certificationType: CertificationType) =
|
||||
CertificationOnUserId(userId, certificate, certificationType)
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer
|
||||
* (see [certificate] method with [Trustworthiness] argument).
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
fun certificate(certificate: PGPPublicKeyRing): DelegationOnCertificate =
|
||||
certificate(certificate, null)
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) containing a [org.bouncycastle.bcpg.sig.TrustSignature] packet
|
||||
* over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer.
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @param trustworthiness trustworthiness of the certificate
|
||||
* @return API
|
||||
*/
|
||||
fun certificate(certificate: PGPPublicKeyRing, trustworthiness: Trustworthiness?) =
|
||||
DelegationOnCertificate(certificate, trustworthiness)
|
||||
|
||||
class CertificationOnUserId(
|
||||
val userId: String,
|
||||
val certificate: PGPPublicKeyRing,
|
||||
val certificationType: CertificationType) {
|
||||
|
||||
/**
|
||||
* Create the certification using the given key.
|
||||
*
|
||||
* @param certificationKey key used to create the certification
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun withKey(certificationKey: PGPSecretKeyRing,
|
||||
protector: SecretKeyRingProtector): CertificationOnUserIdWithSubpackets {
|
||||
|
||||
val secretKey = getCertifyingSecretKey(certificationKey)
|
||||
val sigBuilder = ThirdPartyCertificationSignatureBuilder(
|
||||
certificationType.asSignatureType(), secretKey, protector)
|
||||
|
||||
return CertificationOnUserIdWithSubpackets(certificate, userId, sigBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
class CertificationOnUserIdWithSubpackets(
|
||||
val certificate: PGPPublicKeyRing,
|
||||
val userId: String,
|
||||
val sigBuilder: ThirdPartyCertificationSignatureBuilder
|
||||
) {
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the certification.
|
||||
*
|
||||
* @param subpacketCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun buildWithSubpackets(subpacketCallback: CertificationSubpackets.Callback): CertificationResult {
|
||||
sigBuilder.applyCallback(subpacketCallback)
|
||||
return build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the certification signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun build(): CertificationResult {
|
||||
val signature = sigBuilder.build(certificate, userId)
|
||||
val certifiedCertificate = KeyRingUtils.injectCertification(certificate, userId, signature)
|
||||
return CertificationResult(certifiedCertificate, signature)
|
||||
}
|
||||
}
|
||||
|
||||
class DelegationOnCertificate(
|
||||
val certificate: PGPPublicKeyRing,
|
||||
val trustworthiness: Trustworthiness?) {
|
||||
|
||||
/**
|
||||
* Build the delegation using the given certification key.
|
||||
*
|
||||
* @param certificationKey key to create the certification with
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun withKey(certificationKey: PGPSecretKeyRing,
|
||||
protector: SecretKeyRingProtector): DelegationOnCertificateWithSubpackets {
|
||||
val secretKey = getCertifyingSecretKey(certificationKey)
|
||||
val sigBuilder = ThirdPartyDirectKeySignatureBuilder(secretKey, protector)
|
||||
if (trustworthiness != null) {
|
||||
sigBuilder.hashedSubpackets.setTrust(true, trustworthiness.depth, trustworthiness.amount)
|
||||
}
|
||||
return DelegationOnCertificateWithSubpackets(certificate, sigBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
class DelegationOnCertificateWithSubpackets(
|
||||
val certificate: PGPPublicKeyRing,
|
||||
val sigBuilder: ThirdPartyDirectKeySignatureBuilder) {
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the delegation signature.
|
||||
*
|
||||
* @param subpacketsCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun buildWithSubpackets(subpacketsCallback: CertificationSubpackets.Callback): CertificationResult {
|
||||
sigBuilder.applyCallback(subpacketsCallback)
|
||||
return build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the delegation signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
fun build(): CertificationResult {
|
||||
val delegatedKey = certificate.publicKey
|
||||
val delegation = sigBuilder.build(delegatedKey)
|
||||
val delegatedCertificate = KeyRingUtils.injectCertification(certificate, delegatedKey, delegation)
|
||||
return CertificationResult(delegatedCertificate, delegation)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a certification operation.
|
||||
*
|
||||
* @param certifiedCertificate certificate which now contains the newly created signature
|
||||
* @param certification the newly created signature
|
||||
*/
|
||||
data class CertificationResult(
|
||||
val certifiedCertificate: PGPPublicKeyRing,
|
||||
val certification: PGPSignature)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun getCertifyingSecretKey(certificationKey: PGPSecretKeyRing): PGPSecretKey {
|
||||
val now = Date()
|
||||
val info = PGPainless.inspectKeyRing(certificationKey, now)
|
||||
|
||||
val fingerprint = info.fingerprint
|
||||
val certificationPubKey = info.getPublicKey(fingerprint)
|
||||
requireNotNull(certificationPubKey) {
|
||||
"Primary key cannot be null."
|
||||
}
|
||||
if (!info.isKeyValidlyBound(certificationPubKey.keyID)) {
|
||||
throw RevokedKeyException(fingerprint)
|
||||
}
|
||||
|
||||
if (!info.isUsableForThirdPartyCertification) {
|
||||
throw KeyException.UnacceptableThirdPartyCertificationKeyException(fingerprint)
|
||||
}
|
||||
|
||||
val expirationDate = info.getExpirationDateForUse(KeyFlag.CERTIFY_OTHER)
|
||||
if (expirationDate != null && expirationDate < now) {
|
||||
throw ExpiredKeyException(fingerprint, expirationDate)
|
||||
}
|
||||
|
||||
return certificationKey.getSecretKey(certificationPubKey.keyID)
|
||||
?: throw MissingSecretKeyException(fingerprint, certificationPubKey.keyID)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue