summary refs log tree commit diff
path: root/Crypto/src/openpgp/PgpPublicKeyRing.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/openpgp/PgpPublicKeyRing.cs')
-rw-r--r--Crypto/src/openpgp/PgpPublicKeyRing.cs200
1 files changed, 200 insertions, 0 deletions
diff --git a/Crypto/src/openpgp/PgpPublicKeyRing.cs b/Crypto/src/openpgp/PgpPublicKeyRing.cs
new file mode 100644
index 000000000..ecb935e4b
--- /dev/null
+++ b/Crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Class to hold a single master public key and its subkeys.
+	/// <p>
+	/// Often PGP keyring files consist of multiple master keys, if you are trying to process
+	/// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
+	/// </p>
+	/// </remarks>
+	public class PgpPublicKeyRing
+		: PgpKeyRing
+    {
+        private readonly IList keys;
+
+		public PgpPublicKeyRing(
+            byte[] encoding)
+            : this(new MemoryStream(encoding, false))
+        {
+        }
+
+		internal PgpPublicKeyRing(
+            IList pubKeys)
+        {
+            this.keys = pubKeys;
+        }
+
+		public PgpPublicKeyRing(
+            Stream inputStream)
+        {
+			this.keys = Platform.CreateArrayList();
+
+            BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+			PacketTag initialTag = bcpgInput.NextPacketTag();
+            if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
+            {
+                throw new IOException("public key ring doesn't start with public key tag: "
+					+ "tag 0x" + ((int)initialTag).ToString("X"));
+            }
+
+			PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+			TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+
+            // direct signatures and revocations
+			IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+			IList ids, idTrusts, idSigs;
+			ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+			keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+
+
+			// Read subkeys
+			while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+            {
+				keys.Add(ReadSubkey(bcpgInput));
+            }
+        }
+
+		/// <summary>Return the first public key in the ring.</summary>
+        public PgpPublicKey GetPublicKey()
+        {
+            return (PgpPublicKey) keys[0];
+        }
+
+		/// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
+        public PgpPublicKey GetPublicKey(
+            long keyId)
+        {
+			foreach (PgpPublicKey k in keys)
+			{
+				if (keyId == k.KeyId)
+                {
+                    return k;
+                }
+            }
+
+			return null;
+        }
+
+		/// <summary>Allows enumeration of all the public keys.</summary>
+		/// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
+        public IEnumerable GetPublicKeys()
+        {
+            return new EnumerableProxy(keys);
+        }
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStr)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			foreach (PgpPublicKey k in keys)
+			{
+				k.Encode(outStr);
+            }
+        }
+
+		/// <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;
+        }
+
+		internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
+		{
+            PublicKeyPacket	pk = (PublicKeyPacket) bcpgInput.ReadPacket();
+			TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+
+			// PGP 8 actually leaves out the signature.
+			IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+			return new PgpPublicKey(pk, kTrust, sigList);
+		}
+    }
+}