diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyAccessor.java b/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyAccessor.java deleted file mode 100644 index 8ab8a9c4..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/info/KeyAccessor.java +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-FileCopyrightText: 2021 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package org.pgpainless.key.info; - -import java.util.Set; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPSignature; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.key.SubkeyIdentifier; -import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; - -public abstract class KeyAccessor { - - protected final KeyRingInfo info; - protected final SubkeyIdentifier key; - - KeyAccessor(@Nonnull KeyRingInfo info, @Nonnull SubkeyIdentifier key) { - this.info = info; - this.key = key; - } - - /** - * Depending on the way we address the key (key-id or user-id), return the respective {@link PGPSignature} - * which contains the algorithm preferences we are going to use. - *

- * If we address a key via its user-id, we want to rely on the algorithm preferences in the user-id certification, - * while we would instead rely on those in the direct-key signature if we'd address the key by key-id. - * - * @return signature - */ - @Nonnull - public abstract PGPSignature getSignatureWithPreferences(); - - /** - * Return preferred symmetric key encryption algorithms. - * - * @return preferred symmetric algorithms - */ - @Nonnull - public Set getPreferredSymmetricKeyAlgorithms() { - return SignatureSubpacketsUtil.parsePreferredSymmetricKeyAlgorithms(getSignatureWithPreferences()); - } - - /** - * Return preferred hash algorithms. - * - * @return preferred hash algorithms - */ - @Nonnull - public Set getPreferredHashAlgorithms() { - return SignatureSubpacketsUtil.parsePreferredHashAlgorithms(getSignatureWithPreferences()); - } - - /** - * Return preferred compression algorithms. - * - * @return preferred compression algorithms - */ - @Nonnull - public Set getPreferredCompressionAlgorithms() { - return SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(getSignatureWithPreferences()); - } - - /** - * Address the key via a user-id (e.g. "Alice <alice@wonderland.lit>"). - * In this case we are sourcing preferred algorithms from the user-id certification first. - */ - public static class ViaUserId extends KeyAccessor { - - private final String userId; - - /** - * Access a key via user-id. - * - * @param info info about a key at a given date - * @param key id of the subkey - * @param userId user-id - */ - public ViaUserId(@Nonnull KeyRingInfo info, - @Nonnull SubkeyIdentifier key, - @Nonnull String userId) { - super(info, key); - this.userId = userId; - } - - @Override - @Nonnull - public PGPSignature getSignatureWithPreferences() { - PGPSignature signature = info.getLatestUserIdCertification(userId); - if (signature != null) { - return signature; - } - throw new IllegalStateException("No valid user-id certification signature found for '" + userId + "'."); - } - } - - /** - * Address the key via key-id. - * In this case we are sourcing preferred algorithms from the keys direct-key signature first. - */ - public static class ViaKeyId extends KeyAccessor { - - /** - * Address the key via key-id. - * @param info info about the key at a given date - * @param key key-id - */ - public ViaKeyId(@Nonnull KeyRingInfo info, - @Nonnull SubkeyIdentifier key) { - super(info, key); - } - - @Override - @Nonnull - public PGPSignature getSignatureWithPreferences() { - String primaryUserId = info.getPrimaryUserId(); - // If the key is located by Key ID, the algorithm of the primary User ID of the key provides the - // preferred symmetric algorithm. - PGPSignature signature = null; - if (primaryUserId != null) { - signature = info.getLatestUserIdCertification(primaryUserId); - } - - if (signature == null) { - signature = info.getLatestDirectKeySelfSignature(); - } - - if (signature == null) { - throw new IllegalStateException("No valid signature found."); - } - return signature; - } - } - - public static class SubKey extends KeyAccessor { - - public SubKey(@Nonnull KeyRingInfo info, - @Nonnull SubkeyIdentifier key) { - super(info, key); - } - - @Override - @Nonnull - public PGPSignature getSignatureWithPreferences() { - PGPSignature signature; - if (key.getPrimaryKeyId() == key.getSubkeyId()) { - signature = info.getLatestDirectKeySelfSignature(); - if (signature == null && info.getPrimaryUserId() != null) { - signature = info.getLatestUserIdCertification(info.getPrimaryUserId()); - } - } else { - signature = info.getCurrentSubkeyBindingSignature(key.getSubkeyId()); - } - - if (signature == null) { - throw new IllegalStateException("No valid signature found."); - } - return signature; - } - } -} diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt index 58e7719c..cda7eccd 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/SubkeyIdentifier.kt @@ -31,6 +31,8 @@ class SubkeyIdentifier( val subkeyId = subkeyFingerprint.keyId val primaryKeyId = primaryKeyFingerprint.keyId + val isPrimaryKey = keyId == subkeyId + fun matches(fingerprint: OpenPgpFingerprint) = primaryKeyFingerprint == fingerprint || subkeyFingerprint == fingerprint diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt new file mode 100644 index 00000000..f49a6ca4 --- /dev/null +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package org.pgpainless.key.info + +import org.bouncycastle.openpgp.PGPSignature +import org.pgpainless.algorithm.CompressionAlgorithm +import org.pgpainless.algorithm.HashAlgorithm +import org.pgpainless.algorithm.SymmetricKeyAlgorithm +import org.pgpainless.key.SubkeyIdentifier +import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil + +abstract class KeyAccessor( + protected val info: KeyRingInfo, + protected val key: SubkeyIdentifier +) { + + /** + * Depending on the way we address the key (key-id or user-id), return the respective [PGPSignature] + * which contains the algorithm preferences we are going to use. + *

+ * If we address a key via its user-id, we want to rely on the algorithm preferences in the user-id certification, + * while we would instead rely on those in the direct-key signature if we'd address the key by key-id. + * + * @return signature + */ + abstract val signatureWithPreferences: PGPSignature + + /** + * Preferred symmetric key encryption algorithms. + */ + val preferredSymmetricKeyAlgorithms: Set + get() = SignatureSubpacketsUtil.parsePreferredSymmetricKeyAlgorithms(signatureWithPreferences) + + /** + * Preferred hash algorithms. + */ + val preferredHashAlgorithms: Set + get() = SignatureSubpacketsUtil.parsePreferredHashAlgorithms(signatureWithPreferences) + + /** + * Preferred compression algorithms. + */ + val preferredCompressionAlgorithms: Set + get() = SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(signatureWithPreferences) + + /** + * Address the key via a user-id (e.g. `Alice `). + * In this case we are sourcing preferred algorithms from the user-id certification first. + */ + class ViaUserId(info: KeyRingInfo, key: SubkeyIdentifier, private val userId: CharSequence): KeyAccessor(info, key) { + override val signatureWithPreferences: PGPSignature + get() = checkNotNull(info.getLatestUserIdCertification(userId.toString())) { + "No valid user-id certification signature found for '$userId'." + } + } + + /** + * Address the key via key-id. + * In this case we are sourcing preferred algorithms from the keys direct-key signature first. + */ + class ViaKeyId(info: KeyRingInfo, key: SubkeyIdentifier) : KeyAccessor(info, key) { + override val signatureWithPreferences: PGPSignature + get() { + // If the key is located by Key ID, the algorithm of the primary User ID of the key provides the + // preferred symmetric algorithm. + info.primaryUserId?.let { + userId -> info.getLatestUserIdCertification(userId).let { if (it != null) return it } + } + + return checkNotNull(info.latestDirectKeySelfSignature) { "No valid signature found." } + } + } + + class SubKey(info: KeyRingInfo, key: SubkeyIdentifier): KeyAccessor(info, key) { + override val signatureWithPreferences: PGPSignature + get() = checkNotNull( + if (key.isPrimaryKey) { + info.latestDirectKeySelfSignature ?: + info.primaryUserId?.let { info.getLatestUserIdCertification(it) } + } else { + info.getCurrentSubkeyBindingSignature(key.subkeyId) + } + ) { "No valid signature found." } + + } +} \ No newline at end of file