001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.key; 006 007import java.util.NoSuchElementException; 008import javax.annotation.Nonnull; 009 010import org.bouncycastle.openpgp.PGPKeyRing; 011import org.bouncycastle.openpgp.PGPPublicKey; 012 013/** 014 * Tuple class used to identify a subkey by fingerprints of the primary key of the subkeys key ring, 015 * as well as the subkeys fingerprint. 016 */ 017public class SubkeyIdentifier { 018 019 private final OpenPgpFingerprint primaryKeyFingerprint; 020 private final OpenPgpFingerprint subkeyFingerprint; 021 022 /** 023 * Create a {@link SubkeyIdentifier} from a {@link PGPKeyRing}. 024 * The identifier will point to the primary key of the provided ring. 025 * 026 * @param keyRing key ring 027 */ 028 public SubkeyIdentifier(PGPKeyRing keyRing) { 029 this(keyRing, keyRing.getPublicKey().getKeyID()); 030 } 031 032 /** 033 * Create a {@link SubkeyIdentifier} from a {@link PGPKeyRing} and the subkeys key id. 034 * {@link #getPrimaryKeyFingerprint()} will return the {@link OpenPgpFingerprint} of the keyrings primary key, 035 * while {@link #getSubkeyFingerprint()} will return the subkeys fingerprint. 036 * 037 * @param keyRing keyring the subkey belongs to 038 * @param keyId keyid of the subkey 039 */ 040 public SubkeyIdentifier(@Nonnull PGPKeyRing keyRing, long keyId) { 041 PGPPublicKey subkey = keyRing.getPublicKey(keyId); 042 if (subkey == null) { 043 throw new NoSuchElementException("Key ring does not contain subkey with id " + Long.toHexString(keyId)); 044 } 045 this.primaryKeyFingerprint = OpenPgpFingerprint.of(keyRing); 046 this.subkeyFingerprint = OpenPgpFingerprint.of(subkey); 047 } 048 049 public SubkeyIdentifier(@Nonnull PGPKeyRing keyRing, @Nonnull OpenPgpFingerprint subkeyFingerprint) { 050 this(OpenPgpFingerprint.of(keyRing), subkeyFingerprint); 051 } 052 053 /** 054 * Create a {@link SubkeyIdentifier} that identifies the primary key with the given fingerprint. 055 * This means, both {@link #getPrimaryKeyFingerprint()} and {@link #getSubkeyFingerprint()} return the same. 056 * 057 * @param primaryKeyFingerprint fingerprint of the identified key 058 */ 059 public SubkeyIdentifier(@Nonnull OpenPgpFingerprint primaryKeyFingerprint) { 060 this(primaryKeyFingerprint, primaryKeyFingerprint); 061 } 062 063 /** 064 * Create a {@link SubkeyIdentifier} which points to the subkey with the given subkeyFingerprint, 065 * which has a primary key with the given primaryKeyFingerprint. 066 * 067 * @param primaryKeyFingerprint fingerprint of the primary key 068 * @param subkeyFingerprint fingerprint of the subkey 069 */ 070 public SubkeyIdentifier(@Nonnull OpenPgpFingerprint primaryKeyFingerprint, @Nonnull OpenPgpFingerprint subkeyFingerprint) { 071 this.primaryKeyFingerprint = primaryKeyFingerprint; 072 this.subkeyFingerprint = subkeyFingerprint; 073 } 074 075 public @Nonnull OpenPgpFingerprint getFingerprint() { 076 return getSubkeyFingerprint(); 077 } 078 079 public long getKeyId() { 080 return getSubkeyId(); 081 } 082 083 /** 084 * Return the {@link OpenPgpFingerprint} of the primary key of the identified key. 085 * This might be the same as {@link #getSubkeyFingerprint()} if the identified subkey is the primary key. 086 * 087 * @return primary key fingerprint 088 */ 089 public @Nonnull OpenPgpFingerprint getPrimaryKeyFingerprint() { 090 return primaryKeyFingerprint; 091 } 092 093 /** 094 * Return the key id of the primary key of the identified key. 095 * This might be the same as {@link #getSubkeyId()} if the identified subkey is the primary key. 096 * 097 * @return primary key id 098 */ 099 public long getPrimaryKeyId() { 100 return getPrimaryKeyFingerprint().getKeyId(); 101 } 102 103 /** 104 * Return the {@link OpenPgpFingerprint} of the identified subkey. 105 * 106 * @return subkey fingerprint 107 */ 108 public @Nonnull OpenPgpFingerprint getSubkeyFingerprint() { 109 return subkeyFingerprint; 110 } 111 112 /** 113 * Return the key id of the identified subkey. 114 * 115 * @return subkey id 116 */ 117 public long getSubkeyId() { 118 return getSubkeyFingerprint().getKeyId(); 119 } 120 121 @Override 122 public int hashCode() { 123 return primaryKeyFingerprint.hashCode() * 31 + subkeyFingerprint.hashCode(); 124 } 125 126 @Override 127 public boolean equals(Object obj) { 128 if (obj == null) { 129 return false; 130 } 131 if (this == obj) { 132 return true; 133 } 134 if (!(obj instanceof SubkeyIdentifier)) { 135 return false; 136 } 137 SubkeyIdentifier other = (SubkeyIdentifier) obj; 138 return getPrimaryKeyFingerprint().equals(other.getPrimaryKeyFingerprint()) 139 && getSubkeyFingerprint().equals(other.getSubkeyFingerprint()); 140 } 141 142 @Override 143 public String toString() { 144 return getSubkeyFingerprint() + " " + getPrimaryKeyFingerprint(); 145 } 146}