Source for gnu.javax.crypto.keyring.EnvelopeEntry

   1: /* EnvelopeEntry.java -- 
   2:    Copyright (C) 2003, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.javax.crypto.keyring;
  40: 
  41: import gnu.java.security.Configuration;
  42: 
  43: import java.io.ByteArrayOutputStream;
  44: import java.io.DataInputStream;
  45: import java.io.DataOutputStream;
  46: import java.io.IOException;
  47: import java.util.ArrayList;
  48: import java.util.Iterator;
  49: import java.util.LinkedList;
  50: import java.util.List;
  51: import java.util.StringTokenizer;
  52: import java.util.logging.Logger;
  53: 
  54: /**
  55:  * An envelope entry is a generic container for some number of primitive and
  56:  * other envelope entries.
  57:  */
  58: public abstract class EnvelopeEntry
  59:     extends Entry
  60: {
  61:   private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName());
  62:   /** The envelope that contains this one (if any). */
  63:   protected EnvelopeEntry containingEnvelope;
  64:   /** The contained entries. */
  65:   protected List entries;
  66: 
  67:   public EnvelopeEntry(int type, Properties properties)
  68:   {
  69:     super(type, properties);
  70:     entries = new LinkedList();
  71:     if (this.properties.get("alias-list") != null)
  72:       this.properties.remove("alias-list");
  73:   }
  74: 
  75:   protected EnvelopeEntry(int type)
  76:   {
  77:     super(type);
  78:     entries = new LinkedList();
  79:   }
  80: 
  81:   /**
  82:    * Adds an entry to this envelope.
  83:    * 
  84:    * @param entry The entry to add.
  85:    */
  86:   public void add(Entry entry)
  87:   {
  88:     if (Configuration.DEBUG)
  89:       log.entering(this.getClass().getName(), "add", entry);
  90:     if (! containsEntry(entry))
  91:       {
  92:         if (entry instanceof EnvelopeEntry)
  93:           ((EnvelopeEntry) entry).setContainingEnvelope(this);
  94:         entries.add(entry);
  95:         if (Configuration.DEBUG)
  96:           log.fine("Payload is " + (payload == null ? "" : "not ") + "null");
  97:         makeAliasList();
  98:       }
  99:     if (Configuration.DEBUG)
 100:       log.exiting(this.getClass().getName(), "add");
 101:   }
 102: 
 103:   /**
 104:    * Tests if this envelope contains a primitive entry with the given alias.
 105:    * 
 106:    * @param alias The alias to test.
 107:    * @return True if this envelope (or one of the contained envelopes) contains
 108:    *         a primitive entry with the given alias.
 109:    */
 110:   public boolean containsAlias(String alias)
 111:   {
 112:     if (Configuration.DEBUG)
 113:       log.entering(this.getClass().getName(), "containsAlias", alias);
 114:     String aliases = getAliasList();
 115:     if (Configuration.DEBUG)
 116:       log.fine("aliases = [" + aliases + "]");
 117:     boolean result = false;
 118:     if (aliases != null)
 119:       {
 120:         StringTokenizer tok = new StringTokenizer(aliases, ";");
 121:         while (tok.hasMoreTokens())
 122:           if (tok.nextToken().equals(alias))
 123:             {
 124:               result = true;
 125:               break;
 126:             }
 127:       }
 128:     if (Configuration.DEBUG)
 129:       log.exiting(this.getClass().getName(), "containsAlias",
 130:                   Boolean.valueOf(result));
 131:     return result;
 132:   }
 133: 
 134:   /**
 135:    * Tests if this envelope contains the given entry.
 136:    * 
 137:    * @param entry The entry to test.
 138:    * @return True if this envelope contains the given entry.
 139:    */
 140:   public boolean containsEntry(Entry entry)
 141:   {
 142:     if (entry instanceof EnvelopeEntry)
 143:       return entries.contains(entry);
 144:     if (entry instanceof PrimitiveEntry)
 145:       for (Iterator it = entries.iterator(); it.hasNext();)
 146:         {
 147:           Entry e = (Entry) it.next();
 148:           if (e.equals(entry))
 149:             return true;
 150:           if ((e instanceof EnvelopeEntry)
 151:               && ((EnvelopeEntry) e).containsEntry(entry))
 152:             return true;
 153:         }
 154:     return false;
 155:   }
 156: 
 157:   /**
 158:    * Returns a copy of all entries this envelope contains.
 159:    * 
 160:    * @return All contained entries.
 161:    */
 162:   public List getEntries()
 163:   {
 164:     return new ArrayList(entries);
 165:   }
 166: 
 167:   /**
 168:    * Gets all primitive entries that have the given alias. If there are any
 169:    * masked entries that contain the given alias, they will be returned as well.
 170:    * 
 171:    * @param alias The alias of the entries to get.
 172:    * @return A list of all primitive entries that have the given alias.
 173:    */
 174:   public List get(String alias)
 175:   {
 176:     if (Configuration.DEBUG)
 177:       log.entering(this.getClass().getName(), "get", alias);
 178:     List result = new LinkedList();
 179:     for (Iterator it = entries.iterator(); it.hasNext();)
 180:       {
 181:         Entry e = (Entry) it.next();
 182:         if (e instanceof EnvelopeEntry)
 183:           {
 184:             EnvelopeEntry ee = (EnvelopeEntry) e;
 185:             if (! ee.containsAlias(alias))
 186:               continue;
 187:             if (ee instanceof MaskableEnvelopeEntry)
 188:               {
 189:                 MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee;
 190:                 if (mee.isMasked())
 191:                   {
 192:                     if (Configuration.DEBUG)
 193:                       log.fine("Processing masked entry: " + mee);
 194:                     result.add(mee);
 195:                     continue;
 196:                   }
 197:               }
 198:             if (Configuration.DEBUG)
 199:               log.fine("Processing unmasked entry: " + ee);
 200:             result.addAll(ee.get(alias));
 201:           }
 202:         else if (e instanceof PrimitiveEntry)
 203:           {
 204:             PrimitiveEntry pe = (PrimitiveEntry) e;
 205:             if (pe.getAlias().equals(alias))
 206:               result.add(e);
 207:           }
 208:       }
 209:     if (Configuration.DEBUG)
 210:       log.exiting(this.getClass().getName(), "get", result);
 211:     return result;
 212:   }
 213: 
 214:   /**
 215:    * Returns the list of all aliases contained by this envelope, separated by a
 216:    * semicolon (';').
 217:    * 
 218:    * @return The list of aliases.
 219:    */
 220:   public String getAliasList()
 221:   {
 222:     String list = properties.get("alias-list");
 223:     if (list == null)
 224:       return "";
 225:     else
 226:       return list;
 227:   }
 228: 
 229:   /**
 230:    * Removes the specified entry.
 231:    * 
 232:    * @param entry The entry.
 233:    * @return True if an entry was removed.
 234:    */
 235:   public boolean remove(Entry entry)
 236:   {
 237:     if (Configuration.DEBUG)
 238:       log.entering(this.getClass().getName(), "remove", entry);
 239:     boolean ret = false;
 240:     for (Iterator it = entries.iterator(); it.hasNext();)
 241:       {
 242:         Entry e = (Entry) it.next();
 243:         if (e instanceof EnvelopeEntry)
 244:           {
 245:             if (e == entry)
 246:               {
 247:                 it.remove();
 248:                 ret = true;
 249:                 break;
 250:               }
 251:             if (((EnvelopeEntry) e).remove(entry))
 252:               {
 253:                 ret = true;
 254:                 break;
 255:               }
 256:           }
 257:         else if (e instanceof PrimitiveEntry)
 258:           {
 259:             if (((PrimitiveEntry) e).equals(entry))
 260:               {
 261:                 it.remove();
 262:                 ret = true;
 263:                 break;
 264:               }
 265:           }
 266:       }
 267:     if (ret)
 268:       {
 269:         if (Configuration.DEBUG)
 270:           log.fine("State before: " + this);
 271:         payload = null;
 272:         makeAliasList();
 273:         if (Configuration.DEBUG)
 274:           log.fine("State after: " + this);
 275:       }
 276:     if (Configuration.DEBUG)
 277:       log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret));
 278:     return ret;
 279:   }
 280: 
 281:   /**
 282:    * Removes all primitive entries that have the specified alias.
 283:    * 
 284:    * @param alias The alias of the entries to remove.
 285:    * @return <code>true</code> if <code>alias</code> was present and was
 286:    *         successfully trmoved. Returns <code>false</code> if
 287:    *         <code>alias</code> was not present in the list of aliases in this
 288:    *         envelope.
 289:    */
 290:   public boolean remove(String alias)
 291:   {
 292:     if (Configuration.DEBUG)
 293:       log.entering(this.getClass().getName(), "remove", alias);
 294:     boolean result = false;
 295:     for (Iterator it = entries.iterator(); it.hasNext();)
 296:       {
 297:         Entry e = (Entry) it.next();
 298:         if (e instanceof EnvelopeEntry)
 299:           {
 300:             EnvelopeEntry ee = (EnvelopeEntry) e;
 301:             result = ee.remove(alias) || result;
 302:           }
 303:         else if (e instanceof PrimitiveEntry)
 304:           {
 305:             PrimitiveEntry pe = (PrimitiveEntry) e;
 306:             if (pe.getAlias().equals(alias))
 307:               {
 308:                 it.remove();
 309:                 result = true;
 310:               }
 311:           }
 312:       }
 313:     if (result)
 314:       {
 315:         if (Configuration.DEBUG)
 316:           log.fine("State before: " + this);
 317:         payload = null;
 318:         makeAliasList();
 319:         if (Configuration.DEBUG)
 320:           log.fine("State after: " + this);
 321:       }
 322:     if (Configuration.DEBUG)
 323:       log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result));
 324:     return result;
 325:   }
 326: 
 327:   public String toString()
 328:   {
 329:     return new StringBuilder("Envelope{")
 330:         .append(super.toString())
 331:         .append(", entries=").append(entries)
 332:         .append("}")
 333:         .toString();
 334:   }
 335: 
 336:   // Protected methods.
 337:   // ------------------------------------------------------------------------
 338: 
 339:   protected void encodePayload() throws IOException
 340:   {
 341:     ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
 342:     DataOutputStream out = new DataOutputStream(bout);
 343:     for (Iterator it = entries.iterator(); it.hasNext();)
 344:       ((Entry) it.next()).encode(out);
 345:   }
 346: 
 347:   protected void setContainingEnvelope(EnvelopeEntry e)
 348:   {
 349:     if (containingEnvelope != null)
 350:       throw new IllegalArgumentException("envelopes may not be shared");
 351:     containingEnvelope = e;
 352:   }
 353: 
 354:   protected void decodeEnvelope(DataInputStream in) throws IOException
 355:   {
 356:     this.entries.clear();
 357:     while (true)
 358:       {
 359:         int type = in.read();
 360:         switch (type)
 361:           {
 362:           case EncryptedEntry.TYPE:
 363:             add(EncryptedEntry.decode(in));
 364:             break;
 365:           case PasswordEncryptedEntry.TYPE:
 366:             add(PasswordEncryptedEntry.decode(in));
 367:             break;
 368:           case PasswordAuthenticatedEntry.TYPE:
 369:             add(PasswordAuthenticatedEntry.decode(in));
 370:             break;
 371:           case AuthenticatedEntry.TYPE:
 372:             add(AuthenticatedEntry.decode(in));
 373:             break;
 374:           case CompressedEntry.TYPE:
 375:             add(CompressedEntry.decode(in));
 376:             break;
 377:           case CertificateEntry.TYPE:
 378:             add(CertificateEntry.decode(in));
 379:             break;
 380:           case PublicKeyEntry.TYPE:
 381:             add(PublicKeyEntry.decode(in));
 382:             break;
 383:           case PrivateKeyEntry.TYPE:
 384:             add(PrivateKeyEntry.decode(in));
 385:             break;
 386:           case CertPathEntry.TYPE:
 387:             add(CertPathEntry.decode(in));
 388:             break;
 389:           case BinaryDataEntry.TYPE:
 390:             add(BinaryDataEntry.decode(in));
 391:             break;
 392:           case -1:
 393:             return;
 394:           default:
 395:             throw new MalformedKeyringException("unknown type " + type);
 396:           }
 397:       }
 398:   }
 399: 
 400:   private void makeAliasList()
 401:   {
 402:     if (Configuration.DEBUG)
 403:       log.entering(this.getClass().getName(), "makeAliasList");
 404:     if (! entries.isEmpty())
 405:       {
 406:         StringBuilder buf = new StringBuilder();
 407:         String aliasOrList;
 408:         for (Iterator it = entries.iterator(); it.hasNext();)
 409:           {
 410:             Entry entry = (Entry) it.next();
 411:             aliasOrList = null;
 412:             if (entry instanceof EnvelopeEntry)
 413:               aliasOrList = ((EnvelopeEntry) entry).getAliasList();
 414:             else if (entry instanceof PrimitiveEntry)
 415:               aliasOrList = ((PrimitiveEntry) entry).getAlias();
 416:             else if (Configuration.DEBUG)
 417:               log.fine("Entry with no Alias. Ignored: " + entry);
 418:             if (aliasOrList != null)
 419:               {
 420:                 aliasOrList = aliasOrList.trim();
 421:                 if (aliasOrList.trim().length() > 0)
 422:                   {
 423:                     buf.append(aliasOrList);
 424:                     if (it.hasNext())
 425:                       buf.append(';');
 426:                   }
 427:               }
 428:           }
 429:         String aliasList = buf.toString();
 430:         properties.put("alias-list", aliasList);
 431:         if (Configuration.DEBUG)
 432:           log.fine("alias-list=[" + aliasList + "]");
 433:         if (containingEnvelope != null)
 434:           containingEnvelope.makeAliasList();
 435:       }
 436:     if (Configuration.DEBUG)
 437:       log.exiting(this.getClass().getName(), "makeAliasList");
 438:   }
 439: }