All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bouncycastle.openpgp.PGPPublicKey Maven / Gradle / Ivy

Go to download

The Bouncy Castle Java APIs for the OpenPGP Protocol. The APIs are designed primarily to be used in conjunction with the BC FIPS provider. The APIs may also be used with other providers although if being used in a FIPS context it is the responsibility of the user to ensure that any other providers used are FIPS certified and used appropriately.

There is a newer version: 2.0.9
Show newest version
package org.bouncycastle.openpgp;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.DSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.PublicSubkeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.bcpg.TrustPacket;
import org.bouncycastle.bcpg.UserAttributePacket;
import org.bouncycastle.bcpg.UserDataPacket;
import org.bouncycastle.bcpg.UserIDPacket;
import org.bouncycastle.crypto.asymmetric.ECDomainParametersIndex;
import org.bouncycastle.crypto.asymmetric.NamedECDomainParameters;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;

/**
 * general class to handle a PGP public key object.
 */
public class PGPPublicKey
    implements PublicKeyAlgorithmTags
{
    private static final int[] MASTER_KEY_CERTIFICATION_TYPES = new int[]{PGPSignature.POSITIVE_CERTIFICATION, PGPSignature.CASUAL_CERTIFICATION, PGPSignature.NO_CERTIFICATION, PGPSignature.DEFAULT_CERTIFICATION, PGPSignature.DIRECT_KEY};

    PublicKeyPacket publicPk;
    TrustPacket trustPk;
    List keySigs = new ArrayList();
    List ids = new ArrayList();
    List idTrusts = new ArrayList();
    List> idSigs = new ArrayList>();

    List subSigs = null;

    private long keyID;
    private byte[] fingerprint;
    private int keyStrength;

    private void init(KeyFingerPrintCalculator fingerPrintCalculator)
        throws PGPException
    {
        BCPGKey key = publicPk.getKey();

        this.fingerprint = fingerPrintCalculator.calculateFingerprint(publicPk);

        if (publicPk.getVersion() <= PublicKeyPacket.VERSION_3)
        {
            RSAPublicBCPGKey rK = (RSAPublicBCPGKey)key;

            this.keyID = rK.getModulus().longValue();
            this.keyStrength = rK.getModulus().bitLength();
        }
        else if (publicPk.getVersion() == PublicKeyPacket.VERSION_4)
        {
            this.keyID = Pack.bigEndianToLong(fingerprint, fingerprint.length - 8);
        }
        else if (publicPk.getVersion() == PublicKeyPacket.VERSION_6)
        {
            this.keyID = Pack.bigEndianToLong(fingerprint, 0);
        }

        // key strength
        if (publicPk.getVersion() >= PublicKeyPacket.VERSION_4)
        {
            if (key instanceof RSAPublicBCPGKey)
            {
                this.keyStrength = ((RSAPublicBCPGKey)key).getModulus().bitLength();
            }
            else if (key instanceof DSAPublicBCPGKey)
            {
                this.keyStrength = ((DSAPublicBCPGKey)key).getP().bitLength();
            }
            else if (key instanceof ElGamalPublicBCPGKey)
            {
                this.keyStrength = ((ElGamalPublicBCPGKey)key).getP().bitLength();
            }
            else if (key instanceof ECPublicBCPGKey)
            {
                ASN1ObjectIdentifier curveOID = ((ECPublicBCPGKey)key).getCurveOID();
                if (curveOID.equals(GNUObjectIdentifiers.Ed25519)
                    || curveOID.equals(CryptlibObjectIdentifiers.curvey25519))
                {
                    this.keyStrength = 256;
                }
                else
                {
                    NamedECDomainParameters ecParameters = ECDomainParametersIndex.lookupDomainParameters(curveOID);

                    if (ecParameters != null)
                    {
                        this.keyStrength = ecParameters.getCurve().getFieldSize();
                    }
                    else
                    {
                        this.keyStrength = -1; // unknown
                    }
                }
            }
        }
    }

    /**
     * Create a PGP public key from a packet descriptor using the passed in fingerPrintCalculator to do calculate
     * the fingerprint and keyID.
     *
     * @param publicKeyPacket       packet describing the public key.
     * @param fingerPrintCalculator calculator providing the digest support ot create the key fingerprint.
     * @throws PGPException if the packet is faulty, or the required calculations fail.
     */
    public PGPPublicKey(PublicKeyPacket publicKeyPacket, KeyFingerPrintCalculator fingerPrintCalculator)
        throws PGPException
    {
        this.publicPk = publicKeyPacket;
        this.ids = new ArrayList();
        this.idSigs = new ArrayList>();

        init(fingerPrintCalculator);
    }

    /*
     * Constructor for a sub-key.
     */
    PGPPublicKey(
        PublicKeyPacket publicPk,
        TrustPacket trustPk,
        List sigs,
        KeyFingerPrintCalculator fingerPrintCalculator)
        throws PGPException
    {
        this.publicPk = publicPk;
        this.trustPk = trustPk;
        this.subSigs = sigs;

        init(fingerPrintCalculator);
    }

    PGPPublicKey(
        PGPPublicKey key,
        TrustPacket trust,
        List subSigs)
    {
        this.publicPk = key.publicPk;
        this.trustPk = trust;
        this.subSigs = subSigs;

        this.fingerprint = key.fingerprint;
        this.keyID = key.keyID;
        this.keyStrength = key.keyStrength;
    }

    /**
     * Copy constructor.
     *
     * @param pubKey the public key to copy.
     */
    PGPPublicKey(
        PGPPublicKey pubKey)
    {
        this.publicPk = pubKey.publicPk;

        this.keySigs = new ArrayList(pubKey.keySigs);
        this.ids = new ArrayList(pubKey.ids);
        this.idTrusts = new ArrayList(pubKey.idTrusts);
        this.idSigs = new ArrayList>(pubKey.idSigs.size());
        for (int i = 0; i != pubKey.idSigs.size(); i++)
        {
            this.idSigs.add(new ArrayList((List)pubKey.idSigs.get(i)));
        }

        if (pubKey.subSigs != null)
        {
            this.subSigs = new ArrayList(pubKey.subSigs.size());
            this.subSigs.addAll(pubKey.subSigs);
        }

        this.fingerprint = pubKey.fingerprint;
        this.keyID = pubKey.keyID;
        this.keyStrength = pubKey.keyStrength;
    }

    PGPPublicKey(
        PublicKeyPacket publicPk,
        TrustPacket trustPk,
        List keySigs,
        List ids,
        List idTrusts,
        List> idSigs,
        KeyFingerPrintCalculator fingerPrintCalculator)
        throws PGPException
    {
        this.publicPk = publicPk;
        this.trustPk = trustPk;
        this.keySigs = keySigs;
        this.ids = ids;
        this.idTrusts = idTrusts;
        this.idSigs = idSigs;

        init(fingerPrintCalculator);
    }

    PGPPublicKey(
        PGPPublicKey original,
        TrustPacket trustPk,
        List keySigs,
        List ids,
        List idTrusts,
        List> idSigs)
        throws PGPException
    {
        this.publicPk = original.publicPk;
        this.fingerprint = original.fingerprint;
        this.keyStrength = original.keyStrength;
        this.keyID = original.keyID;

        this.trustPk = trustPk;
        this.keySigs = keySigs;
        this.ids = ids;
        this.idTrusts = idTrusts;
        this.idSigs = idSigs;
    }

    /**
     * @return the version of this key.
     */
    public int getVersion()
    {
        return publicPk.getVersion();
    }

    /**
     * @return creation time of key.
     */
    public Date getCreationTime()
    {
        return publicPk.getTime();
    }

    /**
     * @return number of valid days from creation time - zero means no
     * expiry.
     * @deprecated use getValidSeconds(): greater than version 3 keys may be valid for less than a day.
     */
    public int getValidDays()
    {
        if (publicPk.getVersion() > PublicKeyPacket.VERSION_3)
        {
            long delta = this.getValidSeconds() % (24 * 60 * 60);
            int days = (int)(this.getValidSeconds() / (24 * 60 * 60));

            if (delta > 0 && days == 0)
            {
                return 1;
            }
            else
            {
                return days;
            }
        }
        else
        {
            return publicPk.getValidDays();
        }
    }

    /**
     * Return the trust data associated with the public key, if present.
     *
     * @return a byte array with trust data, null otherwise.
     */
    public byte[] getTrustData()
    {
        if (trustPk == null)
        {
            return null;
        }

        return Arrays.clone(trustPk.getLevelAndTrustAmount());
    }

    /**
     * @return number of valid seconds from creation time - zero means no
     * expiry.
     */
    public long getValidSeconds()
    {
        if (publicPk.getVersion() > PublicKeyPacket.VERSION_3)
        {
            if (this.isMasterKey())
            {
                for (int i = 0; i != MASTER_KEY_CERTIFICATION_TYPES.length; i++)
                {
                    long seconds = getExpirationTimeFromSig(true, MASTER_KEY_CERTIFICATION_TYPES[i]);

                    if (seconds >= 0)
                    {
                        return seconds;
                    }
                }
            }
            else
            {
                long seconds = getExpirationTimeFromSig(false, PGPSignature.SUBKEY_BINDING);

                if (seconds >= 0)
                {
                    return seconds;
                }

                seconds = getExpirationTimeFromSig(false, PGPSignature.DIRECT_KEY);
                if (seconds >= 0)
                {
                    return seconds;
                }
            }

            return 0;
        }
        else
        {
            return (long)publicPk.getValidDays() * 24 * 60 * 60;
        }
    }

    private long getExpirationTimeFromSig(
        boolean selfSigned,
        int signatureType)
    {
        Iterator signatures = this.getSignaturesOfType(signatureType);
        long expiryTime = -1;
        long lastDate = -1;

        while (signatures.hasNext())
        {
            PGPSignature sig = (PGPSignature)signatures.next();

            if (!selfSigned || sig.getKeyID() == this.getKeyID())
            {
                PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
                if (hashed == null)
                {
                    continue;
                }

                if (!hashed.hasSubpacket(SignatureSubpacketTags.KEY_EXPIRE_TIME))
                {
                    continue;
                }

                long current = hashed.getKeyExpirationTime();

                if (sig.getKeyID() == this.getKeyID())
                {
                    if (sig.getCreationTime().getTime() > lastDate)
                    {
                        lastDate = sig.getCreationTime().getTime();
                        expiryTime = current;
                    }
                }
                else
                {
                    if (current == 0 || current > expiryTime)
                    {
                        expiryTime = current;
                    }
                }
            }
        }

        return expiryTime;
    }

    /**
     * Return the keyID associated with the public key.
     *
     * @return long
     */
    public long getKeyID()
    {
        return keyID;
    }

    /**
     * Return the fingerprint of the public key.
     *
     * @return key fingerprint.
     */
    public byte[] getFingerprint()
    {
        return Arrays.clone(fingerprint);
    }

    public boolean hasFingerprint(byte[] fingerprint)
    {
        return Arrays.areEqual(this.fingerprint, fingerprint);
    }

    /**
     * Return true if this key has an algorithm type that makes it suitable to use for encryption.
     * 

* Note: with version 4 keys KeyFlags subpackets should also be considered when present for * determining the preferred use of the key. * * @return true if the key algorithm is suitable for encryption. */ public boolean isEncryptionKey() { int algorithm = publicPk.getAlgorithm(); return ((algorithm == RSA_GENERAL) || (algorithm == RSA_ENCRYPT) || (algorithm == ELGAMAL_ENCRYPT) || (algorithm == ELGAMAL_GENERAL) || (algorithm == DIFFIE_HELLMAN) || (algorithm == ECDH) || (algorithm == X448) || (algorithm == X25519)); } /** * Return true if this could be a master key. * * @return true if a master key. */ public boolean isMasterKey() { // this might seem a bit excessive, but we're also trying to flag something can't be a master key. return !(publicPk instanceof PublicSubkeyPacket) && !(this.isEncryptionKey() && publicPk.getAlgorithm() != PublicKeyAlgorithmTags.RSA_GENERAL); } /** * Return the algorithm code associated with the public key. * * @return int */ public int getAlgorithm() { return publicPk.getAlgorithm(); } /** * Return the strength of the key in bits. * * @return bit strength of key. */ public int getBitStrength() { return keyStrength; } /** * Return any userIDs associated with the key. * * @return an iterator of Strings. */ public Iterator getUserIDs() { List temp = new ArrayList(); for (int i = 0; i != ids.size(); i++) { if (ids.get(i) instanceof UserIDPacket) { temp.add(((UserIDPacket)ids.get(i)).getID()); } } return temp.iterator(); } /** * Return any userIDs associated with the key in raw byte form. No attempt is made * to convert the IDs into Strings. * * @return an iterator of byte[]. */ public Iterator getRawUserIDs() { List temp = new ArrayList(); for (int i = 0; i != ids.size(); i++) { if (ids.get(i) instanceof UserIDPacket) { temp.add(((UserIDPacket)ids.get(i)).getRawID()); } } return temp.iterator(); } /** * Return any user attribute vectors associated with the key. * * @return an iterator of PGPUserAttributeSubpacketVector objects. */ public Iterator getUserAttributes() { List temp = new ArrayList(); for (int i = 0; i != ids.size(); i++) { if (ids.get(i) instanceof PGPUserAttributeSubpacketVector) { temp.add((PGPUserAttributeSubpacketVector)ids.get(i)); } } return temp.iterator(); } /** * Return any signatures associated with the passed in id. * * @param id the id to be matched. * @return an iterator of PGPSignature objects. */ public Iterator getSignaturesForID( String id) { return getSignaturesForID(new UserIDPacket(id)); } /** * Return any signatures associated with the passed in id. * * @param rawID the id to be matched in raw byte form. * @return an iterator of PGPSignature objects. */ public Iterator getSignaturesForID( byte[] rawID) { return getSignaturesForID(new UserIDPacket(rawID)); } /** * Return any signatures associated with the passed in key identifier keyID. * * @param keyID the key id to be matched. * @return an iterator of PGPSignature objects issued by the key with keyID. */ public Iterator getSignaturesForKeyID( long keyID) { List sigs = new ArrayList(); for (Iterator it = getSignatures(); it.hasNext(); ) { PGPSignature sig = (PGPSignature)it.next(); if (sig.getKeyID() == keyID) { sigs.add(sig); } } return sigs.iterator(); } private Iterator getSignaturesForID( UserIDPacket id) { List signatures = new ArrayList(); boolean userIdFound = false; for (int i = 0; i != ids.size(); i++) { if (id.equals(ids.get(i))) { userIdFound = true; signatures.addAll((List)idSigs.get(i)); } } return userIdFound ? signatures.iterator() : null; } /** * Return an iterator of signatures associated with the passed in user attributes. * * @param userAttributes the vector of user attributes to be matched. * @return an iterator of PGPSignature objects. */ public Iterator getSignaturesForUserAttribute( PGPUserAttributeSubpacketVector userAttributes) { List signatures = new ArrayList(); boolean attributeFound = false; for (int i = 0; i != ids.size(); i++) { if (userAttributes.equals(ids.get(i))) { attributeFound = true; signatures.addAll((List)idSigs.get(i)); } } return attributeFound ? signatures.iterator() : null; } /** * Return signatures of the passed in type that are on this key. * * @param signatureType the type of the signature to be returned. * @return an iterator (possibly empty) of signatures of the given type. */ public Iterator getSignaturesOfType( int signatureType) { List l = new ArrayList(); Iterator it = this.getSignatures(); while (it.hasNext()) { PGPSignature sig = (PGPSignature)it.next(); if (sig.getSignatureType() == signatureType) { l.add(sig); } } return l.iterator(); } /** * Return all signatures/certifications associated with this key. * * @return an iterator (possibly empty) with all signatures/certifications. */ public Iterator getSignatures() { if (subSigs == null) { List sigs = new ArrayList(keySigs); for (int i = 0; i != idSigs.size(); i++) { sigs.addAll((List)idSigs.get(i)); } return sigs.iterator(); } else { return subSigs.iterator(); } } /** * Return all signatures/certifications directly associated with this key (ie, not to a user id). * * @return an iterator (possibly empty) with all signatures/certifications. */ public Iterator getKeySignatures() { if (subSigs == null) { List sigs = new ArrayList(keySigs); return sigs.iterator(); } else { return subSigs.iterator(); } } public PublicKeyPacket getPublicKeyPacket() { return publicPk; } public byte[] getEncoded() throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); this.encode(bOut, false); return bOut.toByteArray(); } /** * Return an encoding of the key, with trust packets stripped out if forTransfer is true. * * @param forTransfer if the purpose of encoding is to send key to other users. * @return a encoded byte array representing the key. * @throws IOException in case of encoding error. */ public byte[] getEncoded(boolean forTransfer) throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); this.encode(bOut, forTransfer); return bOut.toByteArray(); } public void encode( OutputStream outStream) throws IOException { encode(outStream, false); } /** * Encode the key to outStream, with trust packets stripped out if forTransfer is true. * * @param outStream stream to write the key encoding to. * @param forTransfer if the purpose of encoding is to send key to other users. * @throws IOException in case of encoding error. */ public void encode(OutputStream outStream, boolean forTransfer) throws IOException { BCPGOutputStream out = BCPGOutputStream.wrap(outStream); out.writePacket(publicPk); if (!forTransfer && trustPk != null) { out.writePacket(trustPk); } if (subSigs == null) // not a sub-key { Util.encodePGPSignatures(out, keySigs, false); for (int i = 0; i != ids.size(); i++) { if (ids.get(i) instanceof UserIDPacket) { UserIDPacket id = (UserIDPacket)ids.get(i); out.writePacket(id); } else { PGPUserAttributeSubpacketVector v = (PGPUserAttributeSubpacketVector)ids.get(i); out.writePacket(new UserAttributePacket(v.toSubpacketArray())); } if (!forTransfer && idTrusts.get(i) != null) { out.writePacket((TrustPacket)idTrusts.get(i)); } List sigs = (List)idSigs.get(i); Util.encodePGPSignatures(out, sigs, forTransfer); } } else { Util.encodePGPSignatures(out, subSigs, forTransfer); } } /** * Check whether this (sub)key has a revocation signature on it. * * @return boolean indicating whether this (sub)key has been revoked. * @deprecated this method is poorly named, use hasRevocation(). */ public boolean isRevoked() { return hasRevocation(); } /** * Check whether this (sub)key has a revocation signature on it. * * @return boolean indicating whether this (sub)key has had a (possibly invalid) revocation attached.. */ public boolean hasRevocation() { int ns = 0; boolean revoked = false; if (this.isMasterKey()) // Master key { while (!revoked && (ns < keySigs.size())) { if (((PGPSignature)keySigs.get(ns++)).getSignatureType() == PGPSignature.KEY_REVOCATION) { revoked = true; } } } else // Sub-key { while (!revoked && (ns < subSigs.size())) { if (((PGPSignature)subSigs.get(ns++)).getSignatureType() == PGPSignature.SUBKEY_REVOCATION) { revoked = true; } } } return revoked; } /** * Add a certification for an id to the given public key. * * @param key the key the certification is to be added to. * @param rawID the raw bytes making up the user id.. * @param certification the new certification. * @return the re-certified key. */ public static PGPPublicKey addCertification( PGPPublicKey key, byte[] rawID, PGPSignature certification) { return addCert(key, new UserIDPacket(rawID), certification); } /** * Add a certification for an id to the given public key. * * @param key the key the certification is to be added to. * @param id the id the certification is associated with. * @param certification the new certification. * @return the re-certified key. */ public static PGPPublicKey addCertification( PGPPublicKey key, String id, PGPSignature certification) { return addCert(key, new UserIDPacket(id), certification); } /** * Add a certification for the given UserAttributeSubpackets to the given public key. * * @param key the key the certification is to be added to. * @param userAttributes the attributes the certification is associated with. * @param certification the new certification. * @return the re-certified key. */ public static PGPPublicKey addCertification( PGPPublicKey key, PGPUserAttributeSubpacketVector userAttributes, PGPSignature certification) { return addCert(key, userAttributes, certification); } private static PGPPublicKey addCert( PGPPublicKey key, UserDataPacket id, PGPSignature certification) { PGPPublicKey returnKey = new PGPPublicKey(key); List sigList = null; for (int i = 0; i != returnKey.ids.size(); i++) { if (id.equals(returnKey.ids.get(i))) { sigList = (List)returnKey.idSigs.get(i); } } if (sigList != null) { sigList.add(certification); } else { sigList = new ArrayList(); sigList.add(certification); returnKey.ids.add(id); returnKey.idTrusts.add(null); returnKey.idSigs.add(sigList); } return returnKey; } /** * Remove any certifications associated with a given user attribute subpacket * on a key. * * @param key the key the certifications are to be removed from. * @param userAttributes the attributes to be removed. * @return the re-certified key, null if the user attribute subpacket was not found on the key. */ public static PGPPublicKey removeCertification( PGPPublicKey key, PGPUserAttributeSubpacketVector userAttributes) { return removeCert(key, userAttributes); } /** * Remove any certifications associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param id the id that is to be removed. * @return the re-certified key, null if the id was not found on the key. */ public static PGPPublicKey removeCertification( PGPPublicKey key, String id) { return removeCert(key, new UserIDPacket(id)); } /** * Remove any certifications associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param rawID the id that is to be removed in raw byte form. * @return the re-certified key, null if the id was not found on the key. */ public static PGPPublicKey removeCertification( PGPPublicKey key, byte[] rawID) { return removeCert(key, new UserIDPacket(rawID)); } private static PGPPublicKey removeCert( PGPPublicKey key, UserDataPacket id) { PGPPublicKey returnKey = new PGPPublicKey(key); boolean found = false; for (int i = returnKey.ids.size() - 1; i >= 0; i--) { if (id.equals(returnKey.ids.get(i))) { found = true; returnKey.ids.remove(i); returnKey.idTrusts.remove(i); returnKey.idSigs.remove(i); } } return found ? returnKey : null; } /** * Remove a certification associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param id the id that the certification is to be removed from (in its raw byte form) * @param certification the certification to be removed. * @return the re-certified key, null if the certification was not found. */ public static PGPPublicKey removeCertification( PGPPublicKey key, byte[] id, PGPSignature certification) { return removeCert(key, new UserIDPacket(id), certification); } /** * Remove a certification associated with a given id on a key. * * @param key the key the certifications are to be removed from. * @param id the id that the certification is to be removed from. * @param certification the certification to be removed. * @return the re-certified key, null if the certification was not found. */ public static PGPPublicKey removeCertification( PGPPublicKey key, String id, PGPSignature certification) { return removeCert(key, new UserIDPacket(id), certification); } /** * Remove a certification associated with a given user attributes on a key. * * @param key the key the certifications are to be removed from. * @param userAttributes the user attributes that the certification is to be removed from. * @param certification the certification to be removed. * @return the re-certified key, null if the certification was not found. */ public static PGPPublicKey removeCertification( PGPPublicKey key, PGPUserAttributeSubpacketVector userAttributes, PGPSignature certification) { return removeCert(key, userAttributes, certification); } private static PGPPublicKey removeCert( PGPPublicKey key, UserDataPacket id, PGPSignature certification) { PGPPublicKey returnKey = new PGPPublicKey(key); boolean found = false; for (int i = 0; i < returnKey.ids.size(); i++) { if (id.equals(returnKey.ids.get(i))) { found |= ((List)returnKey.idSigs.get(i)).remove(certification); } } return found ? returnKey : null; } /** * Add a revocation or some other key certification to a key. * * @param key the key the revocation is to be added to. * @param certification the key signature to be added. * @return the new changed public key object. */ public static PGPPublicKey addCertification( PGPPublicKey key, PGPSignature certification) { if (key.isMasterKey()) { if (certification.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) { throw new IllegalArgumentException("signature type incorrect for master key revocation."); } } else { if (certification.getSignatureType() == PGPSignature.KEY_REVOCATION) { throw new IllegalArgumentException("signature type incorrect for sub-key revocation."); } } PGPPublicKey returnKey = new PGPPublicKey(key); List sigs = returnKey.subSigs != null ? returnKey.subSigs : returnKey.keySigs; sigs.add(certification); return returnKey; } /** * Remove a certification from the key. * * @param key the key the certifications are to be removed from. * @param certification the certification to be removed. * @return the modified key, null if the certification was not found. */ public static PGPPublicKey removeCertification( PGPPublicKey key, PGPSignature certification) { PGPPublicKey returnKey = new PGPPublicKey(key); List sigs = returnKey.subSigs != null ? returnKey.subSigs : returnKey.keySigs; boolean found = sigs.remove(certification); for (Iterator> it = returnKey.idSigs.iterator(); it.hasNext(); ) { List idSigs = (List)it.next(); found |= idSigs.remove(certification); } return found ? returnKey : null; } /** * Merge this the given local public key with another, potentially fresher copy. * The resulting {@link PGPPublicKey} contains the sum of both keys user-ids and signatures. *

* If joinTrustPackets is set to true and the copy carries a trust packet, * the joined key will copy the trust-packet from the copy. * Otherwise, it will carry the trust packet of the local key. * * @param key local public key * @param copy copy of the public key (e.g. from a key server) * @param joinTrustPackets if true, trust packets from the copy are copied over into the resulting key * @param allowSubkeySigsOnNonSubkey if true, subkey signatures on the copy will be present in the merged key, even if key was not a subkey before. * @return joined key * @throws PGPException */ public static PGPPublicKey join( PGPPublicKey key, PGPPublicKey copy, boolean joinTrustPackets, boolean allowSubkeySigsOnNonSubkey) throws PGPException { if (key.getKeyID() != copy.getKeyID()) { throw new IllegalArgumentException("Key-ID mismatch."); } TrustPacket trustPk = key.trustPk; List keySigs = new ArrayList(key.keySigs); List ids = new ArrayList(key.ids); List idTrusts = new ArrayList(key.idTrusts); List> idSigs = new ArrayList>(key.idSigs); List subSigs = key.subSigs == null ? null : new ArrayList(key.subSigs); if (joinTrustPackets) { if (copy.trustPk != null) { trustPk = copy.trustPk; } } // key signatures joinPgpSignatureList(copy.keySigs, keySigs, true, true); // user-ids and id sigs for (int idIdx = 0; idIdx < copy.ids.size(); idIdx++) { UserDataPacket copyId = (UserDataPacket)copy.ids.get(idIdx); List copyIdSigs = new ArrayList((List)copy.idSigs.get(idIdx)); TrustPacket copyTrust = (TrustPacket)copy.idTrusts.get(idIdx); int existingIdIndex = -1; for (int i = 0; i < ids.size(); i++) { UserDataPacket existingId = (UserDataPacket)ids.get(i); if (existingId.equals(copyId)) { existingIdIndex = i; break; } } // new user-id if (existingIdIndex == -1) { ids.add(copyId); idSigs.add(copyIdSigs); idTrusts.add(joinTrustPackets ? copyTrust : null); continue; } // existing user-id if (joinTrustPackets && copyTrust != null) { TrustPacket existingTrust = (TrustPacket)idTrusts.get(existingIdIndex); if (existingTrust == null || Arrays.areEqual(copyTrust.getLevelAndTrustAmount(), existingTrust.getLevelAndTrustAmount())) { idTrusts.set(existingIdIndex, copyTrust); } } List existingIdSigs = (List)idSigs.get(existingIdIndex); joinPgpSignatureList(copyIdSigs, existingIdSigs, false, true); } // subSigs if (copy.subSigs != null) { if (subSigs == null && allowSubkeySigsOnNonSubkey) { subSigs = new ArrayList(copy.subSigs); } else { joinPgpSignatureList(copy.subSigs, subSigs, false, subSigs != null); } } PGPPublicKey merged = new PGPPublicKey(key, trustPk, keySigs, ids, idTrusts, idSigs); merged.subSigs = subSigs; return merged; } private static void joinPgpSignatureList(List source, List rlt, boolean needBreak, boolean isNotNull) throws PGPException { for (Iterator it = source.iterator(); it.hasNext(); ) { PGPSignature copySubSig = (PGPSignature)it.next(); boolean found = false; for (int i = 0; isNotNull && i < rlt.size(); i++) { PGPSignature existingSubSig = (PGPSignature)rlt.get(i); if (PGPSignature.isSignatureEncodingEqual(existingSubSig, copySubSig)) { found = true; // join existing sig with copy to apply modifications in unhashed subpackets existingSubSig = PGPSignature.join(existingSubSig, copySubSig); rlt.set(i, existingSubSig); break; } } if (found && needBreak) { break; } else if (!found && isNotNull) { rlt.add(copySubSig); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy