001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.key.info; 006 007import java.util.Set; 008 009import javax.annotation.Nonnull; 010 011import org.bouncycastle.openpgp.PGPSignature; 012import org.pgpainless.algorithm.CompressionAlgorithm; 013import org.pgpainless.algorithm.HashAlgorithm; 014import org.pgpainless.algorithm.SymmetricKeyAlgorithm; 015import org.pgpainless.key.SubkeyIdentifier; 016import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; 017 018public abstract class KeyAccessor { 019 020 protected final KeyRingInfo info; 021 protected final SubkeyIdentifier key; 022 023 KeyAccessor(KeyRingInfo info, SubkeyIdentifier key) { 024 this.info = info; 025 this.key = key; 026 } 027 028 /** 029 * Depending on the way we address the key (key-id or user-id), return the respective {@link PGPSignature} 030 * which contains the algorithm preferences we are going to use. 031 * 032 * If we address a key via its user-id, we want to rely on the algorithm preferences in the user-id certification, 033 * while we would instead rely on those in the direct-key signature if we'd address the key by key-id. 034 * 035 * @return signature 036 */ 037 public abstract @Nonnull PGPSignature getSignatureWithPreferences(); 038 039 /** 040 * Return preferred symmetric key encryption algorithms. 041 * 042 * @return preferred symmetric algorithms 043 */ 044 public Set<SymmetricKeyAlgorithm> getPreferredSymmetricKeyAlgorithms() { 045 return SignatureSubpacketsUtil.parsePreferredSymmetricKeyAlgorithms(getSignatureWithPreferences()); 046 } 047 048 /** 049 * Return preferred hash algorithms. 050 * 051 * @return preferred hash algorithms 052 */ 053 public Set<HashAlgorithm> getPreferredHashAlgorithms() { 054 return SignatureSubpacketsUtil.parsePreferredHashAlgorithms(getSignatureWithPreferences()); 055 } 056 057 /** 058 * Return preferred compression algorithms. 059 * 060 * @return preferred compression algorithms 061 */ 062 public Set<CompressionAlgorithm> getPreferredCompressionAlgorithms() { 063 return SignatureSubpacketsUtil.parsePreferredCompressionAlgorithms(getSignatureWithPreferences()); 064 } 065 066 /** 067 * Address the key via a user-id (e.g. "Alice <alice@wonderland.lit>"). 068 * In this case we are sourcing preferred algorithms from the user-id certification first. 069 */ 070 public static class ViaUserId extends KeyAccessor { 071 072 private final String userId; 073 074 /** 075 * Access a key via user-id. 076 * 077 * @param info info about a key at a given date 078 * @param key id of the subkey 079 * @param userId user-id 080 */ 081 public ViaUserId(KeyRingInfo info, SubkeyIdentifier key, String userId) { 082 super(info, key); 083 this.userId = userId; 084 } 085 086 @Override 087 public @Nonnull PGPSignature getSignatureWithPreferences() { 088 PGPSignature signature = info.getLatestUserIdCertification(userId); 089 if (signature != null) { 090 return signature; 091 } 092 throw new IllegalStateException("No valid user-id certification signature found for '" + userId + "'."); 093 } 094 } 095 096 /** 097 * Address the key via key-id. 098 * In this case we are sourcing preferred algorithms from the keys direct-key signature first. 099 */ 100 public static class ViaKeyId extends KeyAccessor { 101 102 /** 103 * Address the key via key-id. 104 * @param info info about the key at a given date 105 * @param key key-id 106 */ 107 public ViaKeyId(KeyRingInfo info, SubkeyIdentifier key) { 108 super(info, key); 109 } 110 111 @Override 112 public @Nonnull PGPSignature getSignatureWithPreferences() { 113 PGPSignature signature; 114 if (key.getPrimaryKeyId() != key.getSubkeyId()) { 115 signature = info.getCurrentSubkeyBindingSignature(key.getSubkeyId()); 116 } else { 117 signature = info.getLatestDirectKeySelfSignature(); 118 } 119 120 if (signature != null) { 121 return signature; 122 } 123 124 signature = info.getLatestUserIdCertification(info.getPrimaryUserId()); 125 if (signature == null) { 126 throw new IllegalStateException("No valid signature found."); 127 } 128 return signature; 129 } 130 } 131}