General class to handle a PGP public key object.
상속: IPgpPublicKey
예제 #1
0
		/// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary>
		/// <param name="pub">The public key.</param>
		/// <param name="priv">The private key.</param>
        public PgpKeyPair(
            PgpPublicKey	pub,
            PgpPrivateKey	priv)
        {
            this.pub = pub;
            this.priv = priv;
        }
예제 #2
0
 internal PgpSecretKey(
     SecretKeyPacket	secret,
     PgpPublicKey	pub)
 {
     this.secret = secret;
     this.pub = pub;
 }
예제 #3
0
        /// <summary>
        /// Returns a new key ring with the public key passed in either added or
        /// replacing an existing one.
        /// </summary>
        /// <param name="pubRing">The public key ring to be modified.</param>
        /// <param name="pubKey">The public key to be inserted.</param>
        /// <returns>A new <c>PgpPublicKeyRing</c></returns>
        public static PgpPublicKeyRing InsertPublicKey(
            PgpPublicKeyRing	pubRing,
            PgpPublicKey		pubKey)
        {
            ArrayList keys = new ArrayList(pubRing.keys);
            bool found = false;

            for (int i = 0; i != keys.Count; i++)
            {
                PgpPublicKey key = (PgpPublicKey) keys[i];

                if (key.KeyId == pubKey.KeyId)
                {
                    found = true;
                    keys[i] = pubKey;
                }
            }

            if (!found)
            {
                keys.Add(pubKey);
            }

            return new PgpPublicKeyRing(keys);
        }
예제 #4
0
		internal OpenPgpDigitalCertificate (PgpPublicKey pubkey)
		{
			var data = pubkey.GetFingerprint ();
			var builder = new StringBuilder ();

			for (int i = 0; i < data.Length; i++)
				builder.Append (data[i].ToString ("X"));

//			var trust = pubkey.GetTrustData ();
//			if (trust != null) {
//				TrustLevel = (TrustLevel) (trust[0] & 15);
//			} else {
//				TrustLevel = TrustLevel.None;
//			}

			Fingerprint = builder.ToString ();
			PublicKey = pubkey;

			foreach (string userId in pubkey.GetUserIds ()) {
				data = Encoding.UTF8.GetBytes (userId);
				MailboxAddress mailbox;
				int index = 0;

				if (!MailboxAddress.TryParse (ParserOptions.Default, data, ref index, data.Length, false, out mailbox))
					continue;

				Email = mailbox.Address;
				Name = mailbox.Name;
				break;
			}
		}
예제 #5
0
		public PgpKeyPair(
            PublicKeyAlgorithmTag	algorithm,
            AsymmetricKeyParameter	pubKey,
            AsymmetricKeyParameter	privKey,
            DateTime				time)
        {
            this.pub = new PgpPublicKey(algorithm, pubKey, time);
			this.priv = new PgpPrivateKey(privKey, pub.KeyId);
        }
예제 #6
0
		internal PgpSecretKey(
			PgpPrivateKey				privKey,
			PgpPublicKey				pubKey,
			SymmetricKeyAlgorithmTag	encAlgorithm,
			char[]						passPhrase,
			bool						useSha1,
			SecureRandom				rand)
			: this(privKey, pubKey, encAlgorithm, passPhrase, useSha1, rand, false)
		{
		}
        private void Load(PgpPublicKey key)
        {
            this.KeyId = key.KeyId.ToString("X");
            if (this.KeyId != null && this.KeyId.Length >= 15)
            {
                this.KeyIdShort = this.KeyId.Substring(this.KeyId.Length - 8);
            }
            this.Algorithm = key.Algorithm.ToString();
            this.BitStrength = key.BitStrength;
            this.IsMasterKey = key.IsMasterKey;
            this.IsEncryptionKey = key.IsEncryptionKey;
            this.Version = key.Version;
            this.CreatedOnUtc = key.CreationTime.ToUniversalTime();

            var validForSeconds = key.GetValidSeconds();
            if(validForSeconds > 0)
            {
                this.Expires = this.CreatedOnUtc.Value.AddSeconds(validForSeconds);
            }

            //this.ValidDays = key.ValidDays;
            //if (this.ValidDays.HasValue)
            //{
            //    this.Expires = this.CreatedOnUtc.Value.AddDays(this.ValidDays.Value);
            //}
            //else
            //{
            //    this.Expires = null;
            //}

            try
            {
                var userIds = key.GetUserIds();
                if (userIds != null)
                {
                    var enumerator = userIds.GetEnumerator();
                    if (enumerator.MoveNext())
                    {
                        var userIdentity = enumerator.Current as string;
                        if (userIdentity != null && userIdentity.Contains("<") && userIdentity.Contains(">"))
                        {
                            var name = userIdentity.Substring(0, userIdentity.IndexOf("<") - 1).Trim();
                            this.IdentityName = name;
                            var email = userIdentity.Substring(userIdentity.IndexOf("<") + 1);
                            email = email.Substring(0, email.IndexOf(">")).Trim();
                            this.IdentityEmail = email;
                        }
                    }
                }
            }
            catch { }

        }
예제 #8
0
		public bool IsSigningAlg(PgpPublicKey key)
		{
			var alg = key.Algorithm;
			switch (alg)
			{
				case PublicKeyAlgorithmTag.Dsa:
				case PublicKeyAlgorithmTag.RsaSign:
				case PublicKeyAlgorithmTag.ECDsa:
					return true;
			}

			return true;
		}
    public static Stream PgpEncrypt(this Stream toEncrypt, PgpPublicKey encryptionKey, bool armor = true, bool verify = false)
    {
        var outStream = new MemoryStream();

        var encryptor = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, verify, new SecureRandom());
        var literalizer = new PgpLiteralDataGenerator();
        var compressor = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);

        encryptor.AddMethod(encryptionKey);

        //it would be nice if these streams were read/write, and supported seeking.  Since they are not,
        //we need to shunt the data to a read/write stream so that we can control the flow of data as we go.

        using (var stream = new MemoryStream()) // this is the read/write stream
        using (var armoredStream = armor ? new ArmoredOutputStream(stream) : stream as Stream)
        using (var compressedStream = compressor.Open(armoredStream))
        {
            //data is encrypted first, then compressed, but because of the one-way nature of these streams,
            //other "interim" streams are required.  The raw data is encapsulated in a "Literal" PGP object.
            var rawData = toEncrypt.ReadFully();
            var buffer = new byte[1024];

            using (var literalOut = new MemoryStream())
            using (var literalStream = literalizer.Open(literalOut, PgpLiteralData.Binary, "STREAM", DateTime.UtcNow, buffer))
            {
                literalStream.Write(rawData, 0, rawData.Length);
                literalStream.Close();
                var literalData = literalOut.ReadFully();

                //The literal data object is then encrypted, which flows into the compressing stream and
                //(optionally) into the ASCII armoring stream.
                using (var encryptedStream = encryptor.Open(compressedStream, literalData.Length))
                {
                    encryptedStream.Write(literalData, 0, literalData.Length);
                    encryptedStream.Close();
                    compressedStream.Close();
                    armoredStream.Close();

                    //the stream processes are now complete, and our read/write stream is now populated with
                    //encrypted data.  Convert the stream to a byte array and write to the out stream.
                    stream.Position = 0;
                    var data = stream.ReadFully();
                    outStream.Write(data, 0, data.Length);
                }
            }
        }

        outStream.Position = 0;

        return outStream;
    }
예제 #10
0
        public PgpSecretKey(
			int							certificationLevel,
			PgpKeyPair					keyPair,
			string						id,
			SymmetricKeyAlgorithmTag	encAlgorithm,
			char[]						passPhrase,
			bool						useSHA1,
			PgpSignatureSubpacketVector	hashedPackets,
			PgpSignatureSubpacketVector	unhashedPackets,
			SecureRandom				rand)
            : this(keyPair, encAlgorithm, passPhrase, useSHA1, rand)
        {
            try
            {
                this.trust = null;
                this.ids = new ArrayList();
                ids.Add(id);

                this.idTrusts = new ArrayList();
                idTrusts.Add(null);

                this.idSigs = new ArrayList();

                PgpSignatureGenerator sGen = new PgpSignatureGenerator(
                    keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);

                //
                // Generate the certification
                //
                sGen.InitSign(certificationLevel, keyPair.PrivateKey);

                sGen.SetHashedSubpackets(hashedPackets);
                sGen.SetUnhashedSubpackets(unhashedPackets);

                PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
                this.pub = PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);

                ArrayList sigList = new ArrayList();
                sigList.Add(certification);
                idSigs.Add(sigList);
            }
            catch (PgpException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new PgpException("Exception encrypting key", e);
            }
        }
예제 #11
0
		public bool IsEncryptionAlg(PgpPublicKey key)
		{
			var alg = key.Algorithm;
			switch (alg)
			{
				case PublicKeyAlgorithmTag.DiffieHellman:
				case PublicKeyAlgorithmTag.EC:
				case PublicKeyAlgorithmTag.ElGamalEncrypt:
				case PublicKeyAlgorithmTag.RsaEncrypt:
					return true;
			}

			return false;
		}
        private static void EncryptFile(Stream outputStream, string fileName, PgpPublicKey encKey, bool armor, bool withIntegrityCheck)
        {
            if (armor)
                outputStream = new ArmoredOutputStream(outputStream);

            try
            {
                MemoryStream bOut = new MemoryStream();
                PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(
                CompressionAlgorithmTag.Zip);
                PgpUtilities.WriteFileToLiteralData(
                comData.Open(bOut),
                PgpLiteralData.Binary,
                new FileInfo(fileName));
                comData.Close();
                PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(
                SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
                cPk.AddMethod(encKey);
                byte[] bytes = bOut.ToArray();
                Stream cOut = cPk.Open(outputStream, bytes.Length);
                cOut.Write(bytes, 0, bytes.Length);
                cOut.Close();
                if (armor)
                    outputStream.Close();
            }

            catch (PgpException e)
            {

                Console.Error.WriteLine(e);
                Exception underlyingException = e.InnerException;
                if (underlyingException != null)
                {

                    Console.Error.WriteLine(underlyingException.Message);
                    Console.Error.WriteLine(underlyingException.StackTrace);

                }
            }
        }
		/// <summary>Initialise the signature object for verification.</summary>
        public void InitVerify(
            PgpPublicKey pubKey)
        {
			lastb = 0;

			try
			{
				sig = SignerUtilities.GetSigner(
					PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
			}
			catch (Exception e)
			{
				throw new PgpException("can't set up signature object.",  e);
			}

			try
            {
                sig.Init(false, pubKey.GetKey());
            }
			catch (InvalidKeyException e)
            {
                throw new PgpException("invalid key.", e);
            }
        }
예제 #14
0
		/// <summary>
		/// Verify the signature as certifying the passed in public key as associated
		/// with the passed in ID.
		/// </summary>
		/// <param name="id">ID the key was stored under.</param>
		/// <param name="key">The key to be verified.</param>
		/// <returns>True, if the signature matches, false otherwise.</returns>
        public bool VerifyCertification(
            string			id,
            PgpPublicKey	key)
        {
			UpdateWithPublicKey(key);

			//
            // hash in the id
            //
            UpdateWithIdData(0xb4, Strings.ToUtf8ByteArray(id));

			Update(sigPck.GetSignatureTrailer());

			return sig.VerifySignature(GetSignature());
        }
예제 #15
0
		private void UpdateWithPublicKey(
			PgpPublicKey key)
		{
			byte[] keyBytes = GetEncodedPublicKey(key);

			this.Update(
				(byte) 0x99,
				(byte)(keyBytes.Length >> 8),
				(byte)(keyBytes.Length));
			this.Update(keyBytes);
		}
예제 #16
0
		/// <summary>
		/// Verify the signature as certifying the passed in public key as associated
		/// with the passed in user attributes.
		/// </summary>
		/// <param name="userAttributes">User attributes the key was stored under.</param>
		/// <param name="key">The key to be verified.</param>
		/// <returns>True, if the signature matches, false otherwise.</returns>
		public bool VerifyCertification(
			PgpUserAttributeSubpacketVector	userAttributes,
			PgpPublicKey					key)
		{
			UpdateWithPublicKey(key);

			//
			// hash in the userAttributes
			//
			try
			{
				MemoryStream bOut = new MemoryStream();
				foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
				{
					packet.Encode(bOut);
				}
				UpdateWithIdData(0xd1, bOut.ToArray());
			}
			catch (IOException e)
			{
				throw new PgpException("cannot encode subpacket array", e);
			}

			this.Update(sigPck.GetSignatureTrailer());

			return sig.VerifySignature(this.GetSignature());
		}
        private static PgpPublicKey RemoveCert(IPgpPublicKey key, object id, PgpSignature certification)
        {
            var returnKey = new PgpPublicKey(key);
            var found = false;

            for (var i = 0; i < returnKey._ids.Count; i++)
            {
                if (!id.Equals(returnKey._ids[i]))
                    continue;

                var certs = returnKey.IdSigs[i];
                found = certs.Contains(certification);
                if (found)
                {
                    certs.Remove(certification);
                }
            }

            return found ? returnKey : null;
        }
예제 #18
0
		public void InitVerify(
            PgpPublicKey pubKey)
        {
			lastb = 0;
            if (sig == null)
            {
                GetSig();
            }
            try
            {
                sig.Init(false, pubKey.GetKey());
            }
            catch (InvalidKeyException e)
            {
                throw new PgpException("invalid key.", e);
            }
        }
        private static PgpPublicKey AddCert(IPgpPublicKey key, object id, IPgpSignature certification)
        {
            var returnKey = new PgpPublicKey(key);
            IList<IPgpSignature> sigList = null;

            for (var i = 0; i != returnKey.Ids.Count; i++)
            {
                if (id.Equals(returnKey.Ids[i]))
                {
                    sigList = returnKey.IdSigs[i];
                }
            }

            if (sigList != null)
            {
                sigList.Add(certification);
            }
            else
            {
                sigList = Platform.CreateArrayList<IPgpSignature>();
                sigList.Add(certification);
                returnKey.Ids.Add(id);
                returnKey.IdTrusts.Add(null);
                returnKey.IdSigs.Add(sigList);
            }

            return returnKey;
        }
        private static IPgpPublicKey RemoveCert(IPgpPublicKey key, object id)
        {
            var returnKey = new PgpPublicKey(key);
            var found = false;

            for (var i = 0; i < returnKey._ids.Count; i++)
            {
                if (!id.Equals(returnKey._ids[i]))
                    continue;

                found = true;
                returnKey.Ids.RemoveAt(i);
                returnKey.IdTrusts.RemoveAt(i);
                returnKey.IdSigs.RemoveAt(i);
            }

            return found ? returnKey : null;
        }
        /// <summary>Add a revocation or some other key certification to a key.</summary>
        /// <param name="key">The key the revocation is to be added to.</param>
        /// <param name="certification">The key signature to be added.</param>
        /// <returns>The new changed public key object.</returns>
        public static PgpPublicKey AddCertification(IPgpPublicKey key, PgpSignature certification)
        {
            if (key.IsMasterKey)
            {
                if (certification.SignatureType == PgpSignature.SubkeyRevocation)
                {
                    throw new ArgumentException("signature type incorrect for master key revocation.");
                }
            }
            else
            {
                if (certification.SignatureType == PgpSignature.KeyRevocation)
                {
                    throw new ArgumentException("signature type incorrect for sub-key revocation.");
                }
            }

            var returnKey = new PgpPublicKey(key);
            if (returnKey.SubSigs != null)
            {
                returnKey.SubSigs.Add(certification);
            }
            else
            {
                returnKey.KeySigs.Add(certification);
            }

            return returnKey;
        }
        /// <summary>Remove a certification from the key.</summary>
        /// <param name="key">The key the certifications are to be removed from.</param>
        /// <param name="certification">The certfication to be removed.</param>
        /// <returns>The modified key, null if the certification was not found.</returns>
        public static PgpPublicKey RemoveCertification(PgpPublicKey key, PgpSignature certification)
        {
            var returnKey = new PgpPublicKey(key);
            var sigs = returnKey.SubSigs ?? returnKey.KeySigs;

            //			bool found = sigs.Remove(certification);
            var pos = sigs.IndexOf(certification);
            var found = pos >= 0;

            if (found)
            {
                sigs.RemoveAt(pos);
            }
            else
            {
                foreach (string id in key.GetUserIds())
                {
                    foreach (var sig in key.GetSignaturesForId(id))
                    {
                        // TODO Is this the right type of equality test?
                        if (certification != sig)
                            continue;

                        found = true;
                        returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
                    }
                }

                if (!found)
                {
                    foreach (IPgpUserAttributeSubpacketVector id in key.GetUserAttributes())
                    {
                        foreach (var sig in key.GetSignaturesForUserAttribute(id))
                        {
                            // TODO Is this the right type of equality test?
                            if (certification != sig) continue;
                            // found = true;
                            returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
                        }
                    }
                }
            }

            return returnKey;
        }
        /// <summary>
        /// Returns a new key ring with the public key passed in either added or
        /// replacing an existing one.
        /// </summary>
        /// <param name="pubRing">The public key ring to be modified.</param>
        /// <param name="pubKey">The public key to be inserted.</param>
        /// <returns>A new <c>PgpPublicKeyRing</c></returns>
        public static PgpPublicKeyRing InsertPublicKey(
            PgpPublicKeyRing	pubRing,
            PgpPublicKey		pubKey)
        {
            IList keys = Platform.CreateArrayList(pubRing.keys);
            bool found = false;
            bool masterFound = false;

            for (int i = 0; i != keys.Count; i++)
            {
                PgpPublicKey key = (PgpPublicKey) keys[i];

                if (key.KeyId == pubKey.KeyId)
                {
                    found = true;
                    keys[i] = pubKey;
                }
                if (key.IsMasterKey)
                {
                    masterFound = true;
                }
            }

            if (!found)
            {
                if (pubKey.IsMasterKey)
                {
                    if (masterFound)
                        throw new ArgumentException("cannot add a master key to a ring that already has one");

                    keys.Insert(0, pubKey);
                }
                else
                {
                    keys.Add(pubKey);
                }
            }

            return new PgpPublicKeyRing(keys);
        }
        /// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
        /// <param name="pubRing">The public key ring to be modified.</param>
        /// <param name="pubKey">The public key to be removed.</param>
        /// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
        public static PgpPublicKeyRing RemovePublicKey(
            PgpPublicKeyRing	pubRing,
            PgpPublicKey		pubKey)
        {
            IList keys = Platform.CreateArrayList(pubRing.keys);
            bool found = false;

            for (int i = 0; i < keys.Count; i++)
            {
                PgpPublicKey key = (PgpPublicKey) keys[i];

                if (key.KeyId == pubKey.KeyId)
                {
                    found = true;
                    keys.RemoveAt(i);
                }
            }

            return found ? new PgpPublicKeyRing(keys) : null;
        }
예제 #25
0
		/// <summary>Remove a certification from the key.</summary>
		/// <param name="key">The key the certifications are to be removed from.</param>
		/// <param name="certification">The certfication to be removed.</param>
		/// <returns>The modified key, null if the certification was not found.</returns>
		public static PgpPublicKey RemoveCertification(
			PgpPublicKey	key,
			PgpSignature	certification)
		{
			PgpPublicKey returnKey = new PgpPublicKey(key);
			IList sigs = returnKey.subSigs != null
				?	returnKey.subSigs
				:	returnKey.keySigs;

//			bool found = sigs.Remove(certification);
			int pos = sigs.IndexOf(certification);
			bool found = pos >= 0;

			if (found)
			{
				sigs.RemoveAt(pos);
			}
			else
			{
				foreach (String id in key.GetUserIds())
				{
					foreach (object sig in key.GetSignaturesForId(id))
					{
						// TODO Is this the right type of equality test?
						if (certification == sig)
						{
							found = true;
							returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
						}
					}
				}

				if (!found)
				{
					foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes())
					{
						foreach (object sig in key.GetSignaturesForUserAttribute(id))
						{
							// TODO Is this the right type of equality test?
							if (certification == sig)
							{
								found = true;
								returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
							}
						}
					}
				}
			}

			return returnKey;
		}
예제 #26
0
 /// <summary>Remove any certifications associated with a given ID on a key.</summary>
 /// <param name="key">The key the certifications are to be removed from.</param>
 /// <param name="id">The ID that is to be removed.</param>
 /// <returns>The re-certified key, or null if the ID was not found on the key.</returns>
 public static PgpPublicKey RemoveCertification(
     PgpPublicKey key,
     string id)
 {
     return(RemoveCert(key, id));
 }
예제 #27
0
		private byte[] GetEncodedPublicKey(
			PgpPublicKey pubKey) 
		{
			try
			{
				return pubKey.publicPk.GetEncodedContents();
			}
			catch (IOException e)
			{
				throw new PgpException("exception preparing key.", e);
			}
		}
예제 #28
0
		/// <summary>Verify a certification for the passed in key against the passed in master key.</summary>
		/// <param name="masterKey">The key we are verifying against.</param>
		/// <param name="pubKey">The key we are verifying.</param>
		/// <returns>True, if the certification is valid, false otherwise.</returns>
        public bool VerifyCertification(
            PgpPublicKey	masterKey,
            PgpPublicKey	pubKey)
        {
			UpdateWithPublicKey(masterKey);
			UpdateWithPublicKey(pubKey);

			Update(sigPck.GetSignatureTrailer());

			return sig.VerifySignature(GetSignature());
        }
예제 #29
0
 internal PgpSecretKey(SecretKeyPacket secret, PgpPublicKey pub)
 {
     this.secret = secret;
     this.pub    = pub;
 }
예제 #30
0
		/// <summary>Verify a key certification, such as revocation, for the passed in key.</summary>
		/// <param name="pubKey">The key we are checking.</param>
		/// <returns>True, if the certification is valid, false otherwise.</returns>
        public bool VerifyCertification(
            PgpPublicKey pubKey)
        {
            if (SignatureType != KeyRevocation
                && SignatureType != SubkeyRevocation)
            {
                throw new InvalidOperationException("signature is not a key signature");
            }

			UpdateWithPublicKey(pubKey);

            Update(sigPck.GetSignatureTrailer());

			return sig.VerifySignature(GetSignature());
        }
예제 #31
0
		private static PgpPublicKey RemoveCert(
			PgpPublicKey	key,
			object			id,
			PgpSignature	certification)
		{
			PgpPublicKey returnKey = new PgpPublicKey(key);
            bool found = false;

			for (int i = 0; i < returnKey.ids.Count; i++)
            {
                if (id.Equals(returnKey.ids[i]))
                {
                    IList certs = (IList) returnKey.idSigs[i];
                    found = certs.Contains(certification);

					if (found)
					{
						certs.Remove(certification);
					}
                }
            }

			return found ? returnKey : null;
        }
		internal OpenPgpDigitalSignature (PgpPublicKey pubkey, PgpSignature signature)
		{
			SignerCertificate = pubkey != null ? new OpenPgpDigitalCertificate (pubkey) : null;
			Signature = signature;
		}
예제 #33
0
 /// <summary>
 /// Remove any certifications associated with a user attribute subpacket on a key.
 /// </summary>
 /// <param name="key">The key the certifications are to be removed from.</param>
 /// <param name="userAttributes">The attributes to be removed.</param>
 /// <returns>
 /// The re-certified key, or null if the user attribute subpacket was not found on the key.
 /// </returns>
 public static PgpPublicKey RemoveCertification(
     PgpPublicKey key,
     PgpUserAttributeSubpacketVector userAttributes)
 {
     return(RemoveCert(key, userAttributes));
 }