1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 18:29:39 +02:00

Improve KeyExceptions

This commit is contained in:
Paul Schaub 2025-02-17 13:01:46 +01:00
parent 3e8dd78e74
commit c0b6ea8f96
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 99 additions and 48 deletions

View file

@ -4,7 +4,9 @@
package org.pgpainless.exception; package org.pgpainless.exception;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.pgpainless.algorithm.PublicKeyAlgorithm; import org.pgpainless.algorithm.PublicKeyAlgorithm;
import org.pgpainless.key.OpenPgpFingerprint; import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.util.DateUtil; import org.pgpainless.util.DateUtil;
@ -33,6 +35,10 @@ public abstract class KeyException extends RuntimeException {
public static class ExpiredKeyException extends KeyException { public static class ExpiredKeyException extends KeyException {
public ExpiredKeyException(@Nonnull OpenPGPCertificate cert, @Nonnull Date expirationDate) {
this(OpenPgpFingerprint.of(cert), expirationDate);
}
public ExpiredKeyException(@Nonnull OpenPgpFingerprint fingerprint, @Nonnull Date expirationDate) { public ExpiredKeyException(@Nonnull OpenPgpFingerprint fingerprint, @Nonnull Date expirationDate) {
super("Key " + fingerprint + " is expired. Expiration date: " + DateUtil.formatUTCDate(expirationDate), fingerprint); super("Key " + fingerprint + " is expired. Expiration date: " + DateUtil.formatUTCDate(expirationDate), fingerprint);
} }
@ -43,10 +49,29 @@ public abstract class KeyException extends RuntimeException {
public RevokedKeyException(@Nonnull OpenPgpFingerprint fingerprint) { public RevokedKeyException(@Nonnull OpenPgpFingerprint fingerprint) {
super("Key " + fingerprint + " appears to be revoked.", fingerprint); super("Key " + fingerprint + " appears to be revoked.", fingerprint);
} }
public RevokedKeyException(@Nonnull OpenPGPCertificate.OpenPGPComponentKey key) {
super("Subkey " + key.getKeyIdentifier() + " appears to be revoked.",
OpenPgpFingerprint.of(key));
}
public RevokedKeyException(@Nonnull OpenPGPCertificate cert) {
super("Key or certificate " + cert.getKeyIdentifier() + " appears to be revoked.",
OpenPgpFingerprint.of(cert));
}
} }
public static class UnacceptableEncryptionKeyException extends KeyException { public static class UnacceptableEncryptionKeyException extends KeyException {
public UnacceptableEncryptionKeyException(@Nonnull OpenPGPCertificate cert) {
this(OpenPgpFingerprint.of(cert));
}
public UnacceptableEncryptionKeyException(@Nonnull OpenPGPCertificate.OpenPGPComponentKey subkey) {
super("Subkey " + subkey.getKeyIdentifier() + " is not an acceptable encryption key.",
OpenPgpFingerprint.of(subkey));
}
public UnacceptableEncryptionKeyException(@Nonnull OpenPgpFingerprint fingerprint) { public UnacceptableEncryptionKeyException(@Nonnull OpenPgpFingerprint fingerprint) {
super("Key " + fingerprint + " has no acceptable encryption key.", fingerprint); super("Key " + fingerprint + " has no acceptable encryption key.", fingerprint);
} }
@ -58,6 +83,14 @@ public abstract class KeyException extends RuntimeException {
public static class UnacceptableSigningKeyException extends KeyException { public static class UnacceptableSigningKeyException extends KeyException {
public UnacceptableSigningKeyException(OpenPGPCertificate certificate) {
this(OpenPgpFingerprint.of(certificate));
}
public UnacceptableSigningKeyException(OpenPGPCertificate.OpenPGPComponentKey subkey) {
this(OpenPgpFingerprint.of(subkey));
}
public UnacceptableSigningKeyException(@Nonnull OpenPgpFingerprint fingerprint) { public UnacceptableSigningKeyException(@Nonnull OpenPgpFingerprint fingerprint) {
super("Key " + fingerprint + " has no acceptable signing key.", fingerprint); super("Key " + fingerprint + " has no acceptable signing key.", fingerprint);
} }
@ -76,6 +109,10 @@ public abstract class KeyException extends RuntimeException {
public static class UnacceptableSelfSignatureException extends KeyException { public static class UnacceptableSelfSignatureException extends KeyException {
public UnacceptableSelfSignatureException(@Nonnull OpenPGPCertificate cert) {
this(OpenPgpFingerprint.of(cert));
}
public UnacceptableSelfSignatureException(@Nonnull OpenPgpFingerprint fingerprint) { public UnacceptableSelfSignatureException(@Nonnull OpenPgpFingerprint fingerprint) {
super("Key " + fingerprint + " does not have a valid/acceptable signature to derive an expiration date from.", fingerprint); super("Key " + fingerprint + " does not have a valid/acceptable signature to derive an expiration date from.", fingerprint);
} }
@ -83,29 +120,50 @@ public abstract class KeyException extends RuntimeException {
public static class MissingSecretKeyException extends KeyException { public static class MissingSecretKeyException extends KeyException {
private final long missingSecretKeyId; private final KeyIdentifier missingSecretKeyIdentifier;
public MissingSecretKeyException(@Nonnull OpenPgpFingerprint fingerprint, long keyId) { public MissingSecretKeyException(@Nonnull OpenPGPCertificate.OpenPGPComponentKey publicKey) {
super("Key " + fingerprint + " does not contain a secret key for public key " + Long.toHexString(keyId), fingerprint); this(OpenPgpFingerprint.of(publicKey.getCertificate()), publicKey.getKeyIdentifier());
this.missingSecretKeyId = keyId;
} }
public long getMissingSecretKeyId() { public MissingSecretKeyException(@Nonnull OpenPgpFingerprint fingerprint, KeyIdentifier keyIdentifier) {
return missingSecretKeyId; super("Key " + fingerprint + " does not contain a secret key for public key " + keyIdentifier, fingerprint);
this.missingSecretKeyIdentifier = keyIdentifier;
}
@Deprecated
public MissingSecretKeyException(@Nonnull OpenPgpFingerprint fingerprint, long keyId) {
this(fingerprint, new KeyIdentifier(keyId));
}
public KeyIdentifier getMissingSecretKeyIdentifier() {
return missingSecretKeyIdentifier;
} }
} }
public static class PublicKeyAlgorithmPolicyException extends KeyException { public static class PublicKeyAlgorithmPolicyException extends KeyException {
private final long violatingSubkeyId; private final KeyIdentifier violatingSubkeyId;
public PublicKeyAlgorithmPolicyException(@Nonnull OpenPgpFingerprint fingerprint, long keyId, @Nonnull PublicKeyAlgorithm algorithm, int bitSize) { public PublicKeyAlgorithmPolicyException(@Nonnull OpenPGPCertificate.OpenPGPComponentKey subkey,
super("Subkey " + Long.toHexString(keyId) + " of key " + fingerprint + " is violating the Public Key Algorithm Policy:\n" + @Nonnull PublicKeyAlgorithm algorithm,
algorithm + " of size " + bitSize + " is not acceptable.", fingerprint); int bitSize) {
this.violatingSubkeyId = keyId; super("Subkey " + subkey.getKeyIdentifier() + " of key " + subkey.getCertificate().getKeyIdentifier() +
" is violating the Public Key Algorithm Policy:\n" +
algorithm + " of size " + bitSize + " is not acceptable.", OpenPgpFingerprint.of(subkey));
this.violatingSubkeyId = subkey.getKeyIdentifier();
} }
public long getViolatingSubkeyId() { public PublicKeyAlgorithmPolicyException(@Nonnull OpenPgpFingerprint fingerprint,
long keyId,
@Nonnull PublicKeyAlgorithm algorithm,
int bitSize) {
super("Subkey " + Long.toHexString(keyId) + " of key " + fingerprint + " is violating the Public Key Algorithm Policy:\n" +
algorithm + " of size " + bitSize + " is not acceptable.", fingerprint);
this.violatingSubkeyId = new KeyIdentifier(keyId);
}
public KeyIdentifier getViolatingSubkeyId() {
return violatingSubkeyId; return violatingSubkeyId;
} }
} }

View file

@ -17,7 +17,6 @@ import org.pgpainless.bouncycastle.extensions.toOpenPGPCertificate
import org.pgpainless.encryption_signing.EncryptionOptions.EncryptionKeySelector import org.pgpainless.encryption_signing.EncryptionOptions.EncryptionKeySelector
import org.pgpainless.exception.KeyException.* import org.pgpainless.exception.KeyException.*
import org.pgpainless.implementation.ImplementationFactory import org.pgpainless.implementation.ImplementationFactory
import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.SubkeyIdentifier import org.pgpainless.key.SubkeyIdentifier
import org.pgpainless.key.info.KeyAccessor import org.pgpainless.key.info.KeyAccessor
import org.pgpainless.key.info.KeyRingInfo import org.pgpainless.key.info.KeyRingInfo
@ -197,7 +196,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose) {
encryptionKeySelector.selectEncryptionSubkeys( encryptionKeySelector.selectEncryptionSubkeys(
info.getEncryptionSubkeys(userId, purpose)) info.getEncryptionSubkeys(userId, purpose))
if (subkeys.isEmpty()) { if (subkeys.isEmpty()) {
throw UnacceptableEncryptionKeyException(OpenPgpFingerprint.of(cert)) throw UnacceptableEncryptionKeyException(cert)
} }
for (subkey in subkeys) { for (subkey in subkeys) {
@ -295,13 +294,11 @@ class EncryptionOptions(private val purpose: EncryptionPurpose) {
try { try {
info.primaryKeyExpirationDate info.primaryKeyExpirationDate
} catch (e: NoSuchElementException) { } catch (e: NoSuchElementException) {
throw UnacceptableSelfSignatureException( throw UnacceptableSelfSignatureException(cert)
OpenPgpFingerprint.of(cert))
} }
if (primaryKeyExpiration != null && primaryKeyExpiration < evaluationDate) { if (primaryKeyExpiration != null && primaryKeyExpiration < evaluationDate) {
throw ExpiredKeyException( throw ExpiredKeyException(cert, primaryKeyExpiration)
OpenPgpFingerprint.of(cert), primaryKeyExpiration)
} }
var encryptionSubkeys = selector.selectEncryptionSubkeys(info.getEncryptionSubkeys(purpose)) var encryptionSubkeys = selector.selectEncryptionSubkeys(info.getEncryptionSubkeys(purpose))
@ -318,7 +315,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose) {
} }
if (encryptionSubkeys.isEmpty()) { if (encryptionSubkeys.isEmpty()) {
throw UnacceptableEncryptionKeyException(OpenPgpFingerprint.of(cert)) throw UnacceptableEncryptionKeyException(cert)
} }
for (subkey in encryptionSubkeys) { for (subkey in encryptionSubkeys) {

View file

@ -157,14 +157,13 @@ class SigningOptions {
val signingPubKeys = keyRingInfo.signingSubkeys val signingPubKeys = keyRingInfo.signingSubkeys
if (signingPubKeys.isEmpty()) { if (signingPubKeys.isEmpty()) {
throw UnacceptableSigningKeyException(of(signingKey)) throw UnacceptableSigningKeyException(signingKey)
} }
for (signingPubKey in signingPubKeys) { for (signingPubKey in signingPubKeys) {
val signingSecKey: OpenPGPSecretKey = val signingSecKey: OpenPGPSecretKey =
signingKey.getSecretKey(signingPubKey) signingKey.getSecretKey(signingPubKey)
?: throw MissingSecretKeyException( ?: throw MissingSecretKeyException(signingPubKey)
of(signingKey), signingPubKey.keyIdentifier.keyId)
val signingPrivKey: OpenPGPPrivateKey = val signingPrivKey: OpenPGPPrivateKey =
unlockSecretKey(signingSecKey, signingKeyProtector) unlockSecretKey(signingSecKey, signingKeyProtector)
val hashAlgorithms = val hashAlgorithms =
@ -220,12 +219,11 @@ class SigningOptions {
val keyRingInfo = inspectKeyRing(openPGPKey, evaluationDate) val keyRingInfo = inspectKeyRing(openPGPKey, evaluationDate)
val signingPubKeys = keyRingInfo.signingSubkeys val signingPubKeys = keyRingInfo.signingSubkeys
if (signingPubKeys.isEmpty()) { if (signingPubKeys.isEmpty()) {
throw UnacceptableSigningKeyException(of(openPGPKey)) throw UnacceptableSigningKeyException(openPGPKey)
} }
if (!signingPubKeys.any { it.keyIdentifier.matches(signingKey.keyIdentifier) }) { if (!signingPubKeys.any { it.keyIdentifier.matches(signingKey.keyIdentifier) }) {
throw MissingSecretKeyException( throw MissingSecretKeyException(signingKey)
of(openPGPKey), signingKey.keyIdentifier.keyId)
} }
val signingPrivKey = unlockSecretKey(signingKey, signingKeyProtector) val signingPrivKey = unlockSecretKey(signingKey, signingKeyProtector)
@ -258,13 +256,16 @@ class SigningOptions {
keyId: Long, keyId: Long,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT, signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null subpacketsCallback: Callback? = null
) = ): SigningOptions {
addInlineSignature( val key = signingKey.toOpenPGPKey()
val subkeyIdentifier = KeyIdentifier(keyId)
return addInlineSignature(
signingKeyProtector, signingKeyProtector,
signingKey.toOpenPGPKey().getSecretKey(KeyIdentifier(keyId)) key.getSecretKey(subkeyIdentifier)
?: throw MissingSecretKeyException(of(signingKey), keyId), ?: throw MissingSecretKeyException(of(signingKey), subkeyIdentifier),
signatureType, signatureType,
subpacketsCallback) subpacketsCallback)
}
/** /**
* Add detached signatures with all key rings from the provided secret key ring collection. * Add detached signatures with all key rings from the provided secret key ring collection.
@ -332,14 +333,13 @@ class SigningOptions {
val signingPubKeys = keyRingInfo.signingSubkeys val signingPubKeys = keyRingInfo.signingSubkeys
if (signingPubKeys.isEmpty()) { if (signingPubKeys.isEmpty()) {
throw UnacceptableSigningKeyException(of(signingKey)) throw UnacceptableSigningKeyException(signingKey)
} }
for (signingPubKey in signingPubKeys) { for (signingPubKey in signingPubKeys) {
val signingSecKey: OpenPGPSecretKey = val signingSecKey: OpenPGPSecretKey =
signingKey.getSecretKey(signingPubKey.keyIdentifier) signingKey.getSecretKey(signingPubKey.keyIdentifier)
?: throw MissingSecretKeyException( ?: throw MissingSecretKeyException(signingPubKey)
of(signingKey), signingPubKey.keyIdentifier.keyId)
addDetachedSignature( addDetachedSignature(
signingKeyProtector, signingSecKey, userId, signatureType, subpacketCallback) signingKeyProtector, signingSecKey, userId, signatureType, subpacketCallback)
} }
@ -421,14 +421,17 @@ class SigningOptions {
keyId: Long, keyId: Long,
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT, signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null subpacketsCallback: Callback? = null
) = ): SigningOptions {
addDetachedSignature( val key = signingKey.toOpenPGPKey()
val signingKeyIdentifier = KeyIdentifier(keyId)
return addDetachedSignature(
signingKeyProtector, signingKeyProtector,
signingKey.toOpenPGPKey().getSecretKey(KeyIdentifier(keyId)) key.getSecretKey(signingKeyIdentifier)
?: throw MissingSecretKeyException(of(signingKey), keyId), ?: throw MissingSecretKeyException(of(key), signingKeyIdentifier),
null, null,
signatureType, signatureType,
subpacketsCallback) subpacketsCallback)
}
private fun addSigningMethod( private fun addSigningMethod(
signingKey: OpenPGPPrivateKey, signingKey: OpenPGPPrivateKey,
@ -443,10 +446,7 @@ class SigningOptions {
if (!getPolicy().publicKeyAlgorithmPolicy.isAcceptable(publicKeyAlgorithm, bitStrength)) { if (!getPolicy().publicKeyAlgorithmPolicy.isAcceptable(publicKeyAlgorithm, bitStrength)) {
throw UnacceptableSigningKeyException( throw UnacceptableSigningKeyException(
PublicKeyAlgorithmPolicyException( PublicKeyAlgorithmPolicyException(
of(signingKey), signingKey.secretKey, publicKeyAlgorithm, bitStrength))
signingSecretKey.keyID,
publicKeyAlgorithm,
bitStrength))
} }
val generator: PGPSignatureGenerator = val generator: PGPSignatureGenerator =

View file

@ -132,17 +132,13 @@ abstract class OpenPgpFingerprint : CharSequence, Comparable<OpenPgpFingerprint>
*/ */
@JvmStatic fun of(keys: PGPKeyRing): OpenPgpFingerprint = of(keys.publicKey) @JvmStatic fun of(keys: PGPKeyRing): OpenPgpFingerprint = of(keys.publicKey)
/** /** Return the [OpenPgpFingerprint] of the primary key of the given [OpenPGPCertificate]. */
* Return the [OpenPgpFingerprint] of the primary key of the given [OpenPGPCertificate].
*/
@JvmStatic fun of(cert: OpenPGPCertificate): OpenPgpFingerprint = of(cert.pgpPublicKeyRing) @JvmStatic fun of(cert: OpenPGPCertificate): OpenPgpFingerprint = of(cert.pgpPublicKeyRing)
/** /** Return the [OpenPgpFingerprint] of the given [OpenPGPComponentKey]. */
* Return the [OpenPgpFingerprint] of the given [OpenPGPComponentKey]. @JvmStatic fun of(key: OpenPGPComponentKey): OpenPgpFingerprint = of(key.pgpPublicKey)
*/
@JvmStatic fun of (key: OpenPGPComponentKey): OpenPgpFingerprint = of(key.pgpPublicKey)
@JvmStatic fun of (key: OpenPGPPrivateKey): OpenPgpFingerprint = of(key.secretKey) @JvmStatic fun of(key: OpenPGPPrivateKey): OpenPgpFingerprint = of(key.secretKey)
/** /**
* Try to parse an [OpenPgpFingerprint] from the given fingerprint string. If the trimmed * Try to parse an [OpenPgpFingerprint] from the given fingerprint string. If the trimmed