001: package org.bouncycastle.openpgp;
002:
003: import org.bouncycastle.bcpg.BCPGOutputStream;
004:
005: import java.io.ByteArrayInputStream;
006: import java.io.ByteArrayOutputStream;
007: import java.io.IOException;
008: import java.io.InputStream;
009: import java.io.OutputStream;
010: import java.util.ArrayList;
011: import java.util.Collection;
012: import java.util.HashMap;
013: import java.util.Iterator;
014: import java.util.List;
015: import java.util.Map;
016:
017: /**
018: * Often a PGP key ring file is made up of a succession of master/sub-key key rings.
019: * If you want to read an entire public key file in one hit this is the class for you.
020: */
021: public class PGPPublicKeyRingCollection {
022: private Map pubRings = new HashMap();
023: private List order = new ArrayList();
024:
025: private PGPPublicKeyRingCollection(Map pubRings, List order) {
026: this .pubRings = pubRings;
027: this .order = order;
028: }
029:
030: public PGPPublicKeyRingCollection(byte[] encoding)
031: throws IOException, PGPException {
032: this (new ByteArrayInputStream(encoding));
033: }
034:
035: /**
036: * Build a PGPPublicKeyRingCollection from the passed in input stream.
037: *
038: * @param in input stream containing data
039: * @throws IOException if a problem parsinh the base stream occurs
040: * @throws PGPException if an object is encountered which isn't a PGPPublicKeyRing
041: */
042: public PGPPublicKeyRingCollection(InputStream in)
043: throws IOException, PGPException {
044: PGPObjectFactory pgpFact = new PGPObjectFactory(in);
045: Object obj;
046:
047: while ((obj = pgpFact.nextObject()) != null) {
048: if (!(obj instanceof PGPPublicKeyRing)) {
049: throw new PGPException(obj.getClass().getName()
050: + " found where PGPPublicKeyRing expected");
051: }
052:
053: PGPPublicKeyRing pgpPub = (PGPPublicKeyRing) obj;
054: Long key = new Long(pgpPub.getPublicKey().getKeyID());
055:
056: pubRings.put(key, pgpPub);
057: order.add(key);
058: }
059: }
060:
061: public PGPPublicKeyRingCollection(Collection collection)
062: throws IOException, PGPException {
063: Iterator it = collection.iterator();
064:
065: while (it.hasNext()) {
066: PGPPublicKeyRing pgpPub = (PGPPublicKeyRing) it.next();
067:
068: Long key = new Long(pgpPub.getPublicKey().getKeyID());
069:
070: pubRings.put(key, pgpPub);
071: order.add(key);
072: }
073: }
074:
075: /**
076: * Return the number of rings in this collection.
077: *
078: * @return size of the collection
079: */
080: public int size() {
081: return order.size();
082: }
083:
084: /**
085: * return the public key rings making up this collection.
086: */
087: public Iterator getKeyRings() {
088: return pubRings.values().iterator();
089: }
090:
091: /**
092: * Return an iterator of the key rings associated with the passed in userID.
093: * <p>
094: *
095: * @param userID the user ID to be matched.
096: * @param matchPartial if true userID need only be a substring of an actual ID string to match.
097: * @return an iterator (possibly empty) of key rings which matched.
098: * @throws PGPException
099: */
100: public Iterator getKeyRings(String userID, boolean matchPartial)
101: throws PGPException {
102: Iterator it = this .getKeyRings();
103: List rings = new ArrayList();
104:
105: while (it.hasNext()) {
106: PGPPublicKeyRing pubRing = (PGPPublicKeyRing) it.next();
107: Iterator uIt = pubRing.getPublicKey().getUserIDs();
108:
109: while (uIt.hasNext()) {
110: if (matchPartial) {
111: if (((String) uIt.next()).indexOf(userID) > -1) {
112: rings.add(pubRing);
113: }
114: } else {
115: if (uIt.next().equals(userID)) {
116: rings.add(pubRing);
117: }
118: }
119: }
120: }
121:
122: return rings.iterator();
123: }
124:
125: /**
126: * Return an iterator of the key rings associated with the passed in userID.
127: *
128: * @param userID the user ID to be matched.
129: * @return an iterator (possibly empty) of key rings which matched.
130: * @throws PGPException
131: */
132: public Iterator getKeyRings(String userID) throws PGPException {
133: return getKeyRings(userID, false);
134: }
135:
136: /**
137: * Return the PGP public key associated with the given key id.
138: *
139: * @param keyID
140: * @return the PGP public key
141: * @throws PGPException
142: */
143: public PGPPublicKey getPublicKey(long keyID) throws PGPException {
144: Iterator it = this .getKeyRings();
145:
146: while (it.hasNext()) {
147: PGPPublicKeyRing pubRing = (PGPPublicKeyRing) it.next();
148: PGPPublicKey pub = pubRing.getPublicKey(keyID);
149:
150: if (pub != null) {
151: return pub;
152: }
153: }
154:
155: return null;
156: }
157:
158: /**
159: * Return the public key ring which contains the key referred to by keyID.
160: *
161: * @param keyID
162: * @return the public key ring
163: * @throws PGPException
164: */
165: public PGPPublicKeyRing getPublicKeyRing(long keyID)
166: throws PGPException {
167: Long id = new Long(keyID);
168:
169: if (pubRings.containsKey(id)) {
170: return (PGPPublicKeyRing) pubRings.get(id);
171: }
172:
173: Iterator it = this .getKeyRings();
174:
175: while (it.hasNext()) {
176: PGPPublicKeyRing pubRing = (PGPPublicKeyRing) it.next();
177: PGPPublicKey pub = pubRing.getPublicKey(keyID);
178:
179: if (pub != null) {
180: return pubRing;
181: }
182: }
183:
184: return null;
185: }
186:
187: public byte[] getEncoded() throws IOException {
188: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
189:
190: this .encode(bOut);
191:
192: return bOut.toByteArray();
193: }
194:
195: public void encode(OutputStream outStream) throws IOException {
196: BCPGOutputStream out;
197:
198: if (outStream instanceof BCPGOutputStream) {
199: out = (BCPGOutputStream) outStream;
200: } else {
201: out = new BCPGOutputStream(outStream);
202: }
203:
204: Iterator it = order.iterator();
205: while (it.hasNext()) {
206: PGPPublicKeyRing sr = (PGPPublicKeyRing) pubRings.get(it
207: .next());
208:
209: sr.encode(out);
210: }
211: }
212:
213: /**
214: * Return a new collection object containing the contents of the passed in collection and
215: * the passed in public key ring.
216: *
217: * @param ringCollection the collection the ring to be added to.
218: * @param publicKeyRing the key ring to be added.
219: * @return a new collection merging the current one with the passed in ring.
220: * @exception IllegalArgumentException if the keyID for the passed in ring is already present.
221: */
222: public static PGPPublicKeyRingCollection addPublicKeyRing(
223: PGPPublicKeyRingCollection ringCollection,
224: PGPPublicKeyRing publicKeyRing) {
225: Long key = new Long(publicKeyRing.getPublicKey().getKeyID());
226:
227: if (ringCollection.pubRings.containsKey(key)) {
228: throw new IllegalArgumentException(
229: "Collection already contains a key with a keyID for the passed in ring.");
230: }
231:
232: Map newPubRings = new HashMap(ringCollection.pubRings);
233: List newOrder = new ArrayList(ringCollection.order);
234:
235: newPubRings.put(key, publicKeyRing);
236: newOrder.add(key);
237:
238: return new PGPPublicKeyRingCollection(newPubRings, newOrder);
239: }
240:
241: /**
242: * Return a new collection object containing the contents of this collection with
243: * the passed in public key ring removed.
244: *
245: * @param ringCollection the collection the ring to be removed from.
246: * @param publicKeyRing the key ring to be removed.
247: * @return a new collection not containing the passed in ring.
248: * @exception IllegalArgumentException if the keyID for the passed in ring not present.
249: */
250: public static PGPPublicKeyRingCollection removePublicKeyRing(
251: PGPPublicKeyRingCollection ringCollection,
252: PGPPublicKeyRing publicKeyRing) {
253: Long key = new Long(publicKeyRing.getPublicKey().getKeyID());
254:
255: if (!ringCollection.pubRings.containsKey(key)) {
256: throw new IllegalArgumentException(
257: "Collection does not contain a key with a keyID for the passed in ring.");
258: }
259:
260: Map newPubRings = new HashMap(ringCollection.pubRings);
261: List newOrder = new ArrayList(ringCollection.order);
262:
263: newPubRings.remove(key);
264:
265: for (int i = 0; i < newOrder.size(); i++) {
266: Long r = (Long) newOrder.get(i);
267:
268: if (r.longValue() == key.longValue()) {
269: newOrder.remove(i);
270: break;
271: }
272: }
273:
274: return new PGPPublicKeyRingCollection(newPubRings, newOrder);
275: }
276: }
|