/lib/bouncycastle/openpgp/PgpPublicKeyRingBundle.cs
C# | 280 lines | 190 code | 44 blank | 46 comment | 15 complexity | f6bd20818b6726ce9ed58186cac3c595 MD5 | raw file
1using System;
2using System.Collections;
3using System.Globalization;
4using System.IO;
5
6using Org.BouncyCastle.Utilities;
7using Org.BouncyCastle.Utilities.Collections;
8
9namespace Org.BouncyCastle.Bcpg.OpenPgp
10{
11 /// <remarks>
12 /// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
13 /// If you want to read an entire public key file in one hit this is the class for you.
14 /// </remarks>
15 public class PgpPublicKeyRingBundle
16 {
17 private readonly IDictionary pubRings;
18 private readonly IList order;
19
20 private PgpPublicKeyRingBundle(
21 IDictionary pubRings,
22 IList order)
23 {
24 this.pubRings = pubRings;
25 this.order = order;
26 }
27
28 public PgpPublicKeyRingBundle(
29 byte[] encoding)
30 : this(new MemoryStream(encoding, false))
31 {
32 }
33
34 /// <summary>Build a PgpPublicKeyRingBundle from the passed in input stream.</summary>
35 /// <param name="inputStream">Input stream containing data.</param>
36 /// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
37 /// <exception cref="PgpException">If an object is encountered which isn't a PgpPublicKeyRing.</exception>
38 public PgpPublicKeyRingBundle(
39 Stream inputStream)
40 : this(new PgpObjectFactory(inputStream).AllPgpObjects())
41 {
42 }
43
44 public PgpPublicKeyRingBundle(
45 IEnumerable e)
46 {
47 this.pubRings = Platform.CreateHashtable();
48 this.order = Platform.CreateArrayList();
49
50 foreach (object obj in e)
51 {
52 PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing;
53
54 if (pgpPub == null)
55 {
56 throw new PgpException(obj.GetType().FullName + " found where PgpPublicKeyRing expected");
57 }
58
59 long key = pgpPub.GetPublicKey().KeyId;
60 pubRings.Add(key, pgpPub);
61 order.Add(key);
62 }
63 }
64
65 [Obsolete("Use 'Count' property instead")]
66 public int Size
67 {
68 get { return order.Count; }
69 }
70
71 /// <summary>Return the number of key rings in this collection.</summary>
72 public int Count
73 {
74 get { return order.Count; }
75 }
76
77 /// <summary>Allow enumeration of the public key rings making up this collection.</summary>
78 public IEnumerable GetKeyRings()
79 {
80 return new EnumerableProxy(pubRings.Values);
81 }
82
83 /// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
84 /// <param name="userId">The user ID to be matched.</param>
85 /// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
86 public IEnumerable GetKeyRings(
87 string userId)
88 {
89 return GetKeyRings(userId, false, false);
90 }
91
92 /// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
93 /// <param name="userId">The user ID to be matched.</param>
94 /// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
95 /// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
96 public IEnumerable GetKeyRings(
97 string userId,
98 bool matchPartial)
99 {
100 return GetKeyRings(userId, matchPartial, false);
101 }
102
103 /// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
104 /// <param name="userId">The user ID to be matched.</param>
105 /// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
106 /// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
107 /// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
108 public IEnumerable GetKeyRings(
109 string userId,
110 bool matchPartial,
111 bool ignoreCase)
112 {
113 IList rings = Platform.CreateArrayList();
114
115 if (ignoreCase)
116 {
117 userId = userId.ToLower(CultureInfo.InvariantCulture);
118 }
119
120 foreach (PgpPublicKeyRing pubRing in GetKeyRings())
121 {
122 foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds())
123 {
124 string next = nextUserID;
125 if (ignoreCase)
126 {
127 next = next.ToLower(CultureInfo.InvariantCulture);
128 }
129
130 if (matchPartial)
131 {
132 if (next.IndexOf(userId) > -1)
133 {
134 rings.Add(pubRing);
135 }
136 }
137 else
138 {
139 if (next.Equals(userId))
140 {
141 rings.Add(pubRing);
142 }
143 }
144 }
145 }
146
147 return new EnumerableProxy(rings);
148 }
149
150 /// <summary>Return the PGP public key associated with the given key id.</summary>
151 /// <param name="keyId">The ID of the public key to return.</param>
152 public PgpPublicKey GetPublicKey(
153 long keyId)
154 {
155 foreach (PgpPublicKeyRing pubRing in GetKeyRings())
156 {
157 PgpPublicKey pub = pubRing.GetPublicKey(keyId);
158
159 if (pub != null)
160 {
161 return pub;
162 }
163 }
164
165 return null;
166 }
167
168 /// <summary>Return the public key ring which contains the key referred to by keyId</summary>
169 /// <param name="keyId">key ID to match against</param>
170 public PgpPublicKeyRing GetPublicKeyRing(
171 long keyId)
172 {
173 if (pubRings.Contains(keyId))
174 {
175 return (PgpPublicKeyRing)pubRings[keyId];
176 }
177
178 foreach (PgpPublicKeyRing pubRing in GetKeyRings())
179 {
180 PgpPublicKey pub = pubRing.GetPublicKey(keyId);
181
182 if (pub != null)
183 {
184 return pubRing;
185 }
186 }
187
188 return null;
189 }
190
191 /// <summary>
192 /// Return true if a key matching the passed in key ID is present, false otherwise.
193 /// </summary>
194 /// <param name="keyID">key ID to look for.</param>
195 public bool Contains(
196 long keyID)
197 {
198 return GetPublicKey(keyID) != null;
199 }
200
201 public byte[] GetEncoded()
202 {
203 MemoryStream bOut = new MemoryStream();
204
205 Encode(bOut);
206
207 return bOut.ToArray();
208 }
209
210 public void Encode(
211 Stream outStr)
212 {
213 BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
214
215 foreach (long key in order)
216 {
217 PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key];
218
219 sec.Encode(bcpgOut);
220 }
221 }
222
223 /// <summary>
224 /// Return a new bundle containing the contents of the passed in bundle and
225 /// the passed in public key ring.
226 /// </summary>
227 /// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be added to.</param>
228 /// <param name="publicKeyRing">The key ring to be added.</param>
229 /// <returns>A new <c>PgpPublicKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
230 /// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
231 public static PgpPublicKeyRingBundle AddPublicKeyRing(
232 PgpPublicKeyRingBundle bundle,
233 PgpPublicKeyRing publicKeyRing)
234 {
235 long key = publicKeyRing.GetPublicKey().KeyId;
236
237 if (bundle.pubRings.Contains(key))
238 {
239 throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
240 }
241
242 IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
243 IList newOrder = Platform.CreateArrayList(bundle.order);
244
245 newPubRings[key] = publicKeyRing;
246
247 newOrder.Add(key);
248
249 return new PgpPublicKeyRingBundle(newPubRings, newOrder);
250 }
251
252 /// <summary>
253 /// Return a new bundle containing the contents of the passed in bundle with
254 /// the passed in public key ring removed.
255 /// </summary>
256 /// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be removed from.</param>
257 /// <param name="publicKeyRing">The key ring to be removed.</param>
258 /// <returns>A new <c>PgpPublicKeyRingBundle</c> not containing the passed in key ring.</returns>
259 /// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
260 public static PgpPublicKeyRingBundle RemovePublicKeyRing(
261 PgpPublicKeyRingBundle bundle,
262 PgpPublicKeyRing publicKeyRing)
263 {
264 long key = publicKeyRing.GetPublicKey().KeyId;
265
266 if (!bundle.pubRings.Contains(key))
267 {
268 throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
269 }
270
271 IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
272 IList newOrder = Platform.CreateArrayList(bundle.order);
273
274 newPubRings.Remove(key);
275 newOrder.Remove(key);
276
277 return new PgpPublicKeyRingBundle(newPubRings, newOrder);
278 }
279 }
280}