// 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(KeyRingInfo info, 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 */ public abstract @Nonnull PGPSignature getSignatureWithPreferences(); /** * Return preferred symmetric key encryption algorithms. * * @return preferred symmetric algorithms */ public Set getPreferredSymmetricKeyAlgorithms() { return SignatureSubpacketsUtil.parsePreferredSymmetricKeyAlgorithms(getSignatureWithPreferences()); } /** * Return preferred hash algorithms. * * @return preferred hash algorithms */ public Set getPreferredHashAlgorithms() { return SignatureSubpacketsUtil.parsePreferredHashAlgorithms(getSignatureWithPreferences()); } /** * Return preferred compression algorithms. * * @return preferred compression algorithms */ 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(KeyRingInfo info, SubkeyIdentifier key, String userId) { super(info, key); this.userId = userId; } @Override public @Nonnull 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(KeyRingInfo info, SubkeyIdentifier key) { super(info, key); } @Override public @Nonnull PGPSignature getSignatureWithPreferences() { PGPSignature signature; if (key.getPrimaryKeyId() != key.getSubkeyId()) { signature = info.getCurrentSubkeyBindingSignature(key.getSubkeyId()); } else { signature = info.getLatestDirectKeySelfSignature(); } if (signature != null) { return signature; } signature = info.getLatestUserIdCertification(info.getPrimaryUserId()); if (signature == null) { throw new IllegalStateException("No valid signature found."); } return signature; } } }