package com.wesabe.grendel.openpgp; import java.security.SignatureException; import java.util.List; import java.util.Set; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import com.wesabe.grendel.util.IntegerEquivalents; /** * A signature on a {@link MasterKey} or {@link SubKey}. * * @author coda */ public class KeySignature { private final PGPSignature signature; private final PGPSignatureSubpacketVector subpackets; /** * Creates a new {@link KeySignature} given a {@link PGPSignature}. * * @param signature a {@link PGPSignature} instance */ public KeySignature(PGPSignature signature) { this.signature = signature; this.subpackets = signature.getHashedSubPackets(); } /** * Returns the type of signature {@code this} is. */ public SignatureType getSignatureType() { return IntegerEquivalents.fromInt(SignatureType.class, signature.getSignatureType()); } /** * Returns the {@link HashAlgorithm} used to make the signature. */ public HashAlgorithm getHashAlgorithm() { return IntegerEquivalents.fromInt(HashAlgorithm.class, signature.getHashAlgorithm()); } /** * Returns the timestamp at which the signature was made. */ public DateTime getCreatedAt() { return new DateTime(signature.getCreationTime(), DateTimeZone.UTC); } /** * Returns the {@link AsymmetricAlgorithm} used to make the signature. */ public AsymmetricAlgorithm getKeyAlgorithm() { return IntegerEquivalents.fromInt(AsymmetricAlgorithm.class, signature.getKeyAlgorithm()); } /** * Returns the key ID of the key that made the signature. */ public long getKeyID() { return signature.getKeyID(); } /** * Returns the {@link KeyFlag}s asserted by the signature. */ public Set<KeyFlag> getKeyFlags() { return IntegerEquivalents.fromBitmask(KeyFlag.class, subpackets.getKeyFlags()); } /** * Returns a list of the preferred {@link SymmetricAlgorithm}s of the key. */ public List<SymmetricAlgorithm> getPreferredSymmetricAlgorithms() { return IntegerEquivalents.fromIntArray(SymmetricAlgorithm.class, subpackets.getPreferredSymmetricAlgorithms()); } /** * Returns a list of the preferred {@link CompressionAlgorithm}s of the key. */ public List<CompressionAlgorithm> getPreferredCompressionAlgorithms() { return IntegerEquivalents.fromIntArray(CompressionAlgorithm.class, subpackets.getPreferredCompressionAlgorithms()); } /** * Returns a list of the preferred {@link HashAlgorithm}s of the key. */ public List<HashAlgorithm> getPreferredHashAlgorithms() { return IntegerEquivalents.fromIntArray(HashAlgorithm.class, subpackets.getPreferredHashAlgorithms()); } /** * Verify this signature for a self-signed {@link MasterKey}. * * @param key a self-signed master key * @return {@code true} if the signature is valid, {@code false} otherwise */ public boolean verifyCertification(MasterKey key) { try { signature.initVerify(key.getPublicKey(), "BC"); return signature.verifyCertification(key.getUserID(), key.getPublicKey()); } catch (PGPException e) { return false; } catch (SignatureException e) { return false; } catch (Exception e) { throw new RuntimeException(e); } } /** * Verify this signature for a {@link SubKey} signed by a {@link MasterKey}. * * @param key a subkey * @param masterKey the signing master key * @return {@code true} if the signature is valid, {@code false} otherwise */ public boolean verifyCertification(SubKey key, MasterKey masterKey) { try { signature.initVerify(masterKey.getPublicKey(), "BC"); return signature.verifyCertification(masterKey.getPublicKey(), key.getPublicKey()); } catch (Exception e) { return false; } } }