EnvelopeEntry.java 13.3 KB
Newer Older
1
/* EnvelopeEntry.java --
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
   Copyright (C) 2003, 2006 Free Software Foundation, Inc.

This file is a part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.  */


package gnu.javax.crypto.keyring;

41 42
import gnu.java.security.Configuration;

43 44 45 46 47 48 49 50 51
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
52
import java.util.logging.Logger;
53 54

/**
55 56
 * An envelope entry is a generic container for some number of primitive and
 * other envelope entries.
57
 */
58 59
public abstract class EnvelopeEntry
    extends Entry
60
{
61
  private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName());
62 63 64 65 66 67 68 69 70 71
  /** The envelope that contains this one (if any). */
  protected EnvelopeEntry containingEnvelope;
  /** The contained entries. */
  protected List entries;

  public EnvelopeEntry(int type, Properties properties)
  {
    super(type, properties);
    entries = new LinkedList();
    if (this.properties.get("alias-list") != null)
72
      this.properties.remove("alias-list");
73 74 75 76 77 78 79 80 81 82
  }

  protected EnvelopeEntry(int type)
  {
    super(type);
    entries = new LinkedList();
  }

  /**
   * Adds an entry to this envelope.
83
   *
84 85 86 87
   * @param entry The entry to add.
   */
  public void add(Entry entry)
  {
88 89 90
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "add", entry);
    if (! containsEntry(entry))
91 92
      {
        if (entry instanceof EnvelopeEntry)
93
          ((EnvelopeEntry) entry).setContainingEnvelope(this);
94
        entries.add(entry);
95 96
        if (Configuration.DEBUG)
          log.fine("Payload is " + (payload == null ? "" : "not ") + "null");
97 98
        makeAliasList();
      }
99 100
    if (Configuration.DEBUG)
      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 108
   * @return True if this envelope (or one of the contained envelopes) contains
   *         a primitive entry with the given alias.
109 110 111
   */
  public boolean containsAlias(String alias)
  {
112 113
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "containsAlias", alias);
114
    String aliases = getAliasList();
115 116 117 118
    if (Configuration.DEBUG)
      log.fine("aliases = [" + aliases + "]");
    boolean result = false;
    if (aliases != null)
119
      {
120 121 122 123 124 125 126
        StringTokenizer tok = new StringTokenizer(aliases, ";");
        while (tok.hasMoreTokens())
          if (tok.nextToken().equals(alias))
            {
              result = true;
              break;
            }
127
      }
128 129 130 131
    if (Configuration.DEBUG)
      log.exiting(this.getClass().getName(), "containsAlias",
                  Boolean.valueOf(result));
    return result;
132 133 134 135
  }

  /**
   * Tests if this envelope contains the given entry.
136
   *
137 138 139 140 141 142
   * @param entry The entry to test.
   * @return True if this envelope contains the given entry.
   */
  public boolean containsEntry(Entry entry)
  {
    if (entry instanceof EnvelopeEntry)
143 144 145 146 147 148 149 150 151 152 153
      return entries.contains(entry);
    if (entry instanceof PrimitiveEntry)
      for (Iterator it = entries.iterator(); it.hasNext();)
        {
          Entry e = (Entry) it.next();
          if (e.equals(entry))
            return true;
          if ((e instanceof EnvelopeEntry)
              && ((EnvelopeEntry) e).containsEntry(entry))
            return true;
        }
154 155 156 157 158
    return false;
  }

  /**
   * Returns a copy of all entries this envelope contains.
159
   *
160 161 162 163 164 165 166 167
   * @return All contained entries.
   */
  public List getEntries()
  {
    return new ArrayList(entries);
  }

  /**
168 169
   * Gets all primitive entries that have the given alias. If there are any
   * masked entries that contain the given alias, they will be returned as well.
170
   *
171 172 173 174 175
   * @param alias The alias of the entries to get.
   * @return A list of all primitive entries that have the given alias.
   */
  public List get(String alias)
  {
176 177
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "get", alias);
178 179 180 181 182 183
    List result = new LinkedList();
    for (Iterator it = entries.iterator(); it.hasNext();)
      {
        Entry e = (Entry) it.next();
        if (e instanceof EnvelopeEntry)
          {
184 185 186 187
            EnvelopeEntry ee = (EnvelopeEntry) e;
            if (! ee.containsAlias(alias))
              continue;
            if (ee instanceof MaskableEnvelopeEntry)
188
              {
189 190
                MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee;
                if (mee.isMasked())
191
                  {
192 193 194
                    if (Configuration.DEBUG)
                      log.fine("Processing masked entry: " + mee);
                    result.add(mee);
195 196 197
                    continue;
                  }
              }
198 199 200
            if (Configuration.DEBUG)
              log.fine("Processing unmasked entry: " + ee);
            result.addAll(ee.get(alias));
201 202 203
          }
        else if (e instanceof PrimitiveEntry)
          {
204 205 206
            PrimitiveEntry pe = (PrimitiveEntry) e;
            if (pe.getAlias().equals(alias))
              result.add(e);
207 208
          }
      }
209 210
    if (Configuration.DEBUG)
      log.exiting(this.getClass().getName(), "get", result);
211 212 213 214
    return result;
  }

  /**
215 216
   * Returns the list of all aliases contained by this envelope, separated by a
   * semicolon (';').
217
   *
218 219 220 221 222 223
   * @return The list of aliases.
   */
  public String getAliasList()
  {
    String list = properties.get("alias-list");
    if (list == null)
224
      return "";
225
    else
226
      return list;
227 228 229 230
  }

  /**
   * Removes the specified entry.
231
   *
232 233 234 235 236
   * @param entry The entry.
   * @return True if an entry was removed.
   */
  public boolean remove(Entry entry)
  {
237 238
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "remove", entry);
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    boolean ret = false;
    for (Iterator it = entries.iterator(); it.hasNext();)
      {
        Entry e = (Entry) it.next();
        if (e instanceof EnvelopeEntry)
          {
            if (e == entry)
              {
                it.remove();
                ret = true;
                break;
              }
            if (((EnvelopeEntry) e).remove(entry))
              {
                ret = true;
                break;
              }
          }
        else if (e instanceof PrimitiveEntry)
          {
            if (((PrimitiveEntry) e).equals(entry))
              {
                it.remove();
                ret = true;
                break;
              }
          }
      }
    if (ret)
      {
269 270
        if (Configuration.DEBUG)
          log.fine("State before: " + this);
271 272
        payload = null;
        makeAliasList();
273 274
        if (Configuration.DEBUG)
          log.fine("State after: " + this);
275
      }
276 277
    if (Configuration.DEBUG)
      log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret));
278 279 280 281 282
    return ret;
  }

  /**
   * Removes all primitive entries that have the specified alias.
283
   *
284
   * @param alias The alias of the entries to remove.
285 286 287 288
   * @return <code>true</code> if <code>alias</code> was present and was
   *         successfully trmoved. Returns <code>false</code> if
   *         <code>alias</code> was not present in the list of aliases in this
   *         envelope.
289
   */
290
  public boolean remove(String alias)
291
  {
292 293 294
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "remove", alias);
    boolean result = false;
295 296 297 298 299
    for (Iterator it = entries.iterator(); it.hasNext();)
      {
        Entry e = (Entry) it.next();
        if (e instanceof EnvelopeEntry)
          {
300 301
            EnvelopeEntry ee = (EnvelopeEntry) e;
            result = ee.remove(alias) || result;
302 303 304
          }
        else if (e instanceof PrimitiveEntry)
          {
305 306
            PrimitiveEntry pe = (PrimitiveEntry) e;
            if (pe.getAlias().equals(alias))
307 308
              {
                it.remove();
309
                result = true;
310 311 312
              }
          }
      }
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    if (result)
      {
        if (Configuration.DEBUG)
          log.fine("State before: " + this);
        payload = null;
        makeAliasList();
        if (Configuration.DEBUG)
          log.fine("State after: " + this);
      }
    if (Configuration.DEBUG)
      log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result));
    return result;
  }

  public String toString()
  {
    return new StringBuilder("Envelope{")
        .append(super.toString())
        .append(", entries=").append(entries)
        .append("}")
        .toString();
334 335 336 337 338 339 340 341 342 343
  }

  // Protected methods.
  // ------------------------------------------------------------------------

  protected void encodePayload() throws IOException
  {
    ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
    DataOutputStream out = new DataOutputStream(bout);
    for (Iterator it = entries.iterator(); it.hasNext();)
344
      ((Entry) it.next()).encode(out);
345 346 347 348 349
  }

  protected void setContainingEnvelope(EnvelopeEntry e)
  {
    if (containingEnvelope != null)
350
      throw new IllegalArgumentException("envelopes may not be shared");
351 352 353 354 355
    containingEnvelope = e;
  }

  protected void decodeEnvelope(DataInputStream in) throws IOException
  {
356
    this.entries.clear();
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    while (true)
      {
        int type = in.read();
        switch (type)
          {
          case EncryptedEntry.TYPE:
            add(EncryptedEntry.decode(in));
            break;
          case PasswordEncryptedEntry.TYPE:
            add(PasswordEncryptedEntry.decode(in));
            break;
          case PasswordAuthenticatedEntry.TYPE:
            add(PasswordAuthenticatedEntry.decode(in));
            break;
          case AuthenticatedEntry.TYPE:
            add(AuthenticatedEntry.decode(in));
            break;
          case CompressedEntry.TYPE:
            add(CompressedEntry.decode(in));
            break;
          case CertificateEntry.TYPE:
            add(CertificateEntry.decode(in));
            break;
          case PublicKeyEntry.TYPE:
            add(PublicKeyEntry.decode(in));
            break;
          case PrivateKeyEntry.TYPE:
            add(PrivateKeyEntry.decode(in));
            break;
          case CertPathEntry.TYPE:
            add(CertPathEntry.decode(in));
            break;
          case BinaryDataEntry.TYPE:
            add(BinaryDataEntry.decode(in));
            break;
          case -1:
            return;
          default:
            throw new MalformedKeyringException("unknown type " + type);
          }
      }
  }

  private void makeAliasList()
  {
402 403 404
    if (Configuration.DEBUG)
      log.entering(this.getClass().getName(), "makeAliasList");
    if (! entries.isEmpty())
405
      {
406 407 408
        StringBuilder buf = new StringBuilder();
        String aliasOrList;
        for (Iterator it = entries.iterator(); it.hasNext();)
409
          {
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
            Entry entry = (Entry) it.next();
            aliasOrList = null;
            if (entry instanceof EnvelopeEntry)
              aliasOrList = ((EnvelopeEntry) entry).getAliasList();
            else if (entry instanceof PrimitiveEntry)
              aliasOrList = ((PrimitiveEntry) entry).getAlias();
            else if (Configuration.DEBUG)
              log.fine("Entry with no Alias. Ignored: " + entry);
            if (aliasOrList != null)
              {
                aliasOrList = aliasOrList.trim();
                if (aliasOrList.trim().length() > 0)
                  {
                    buf.append(aliasOrList);
                    if (it.hasNext())
                      buf.append(';');
                  }
              }
428
          }
429 430 431 432 433 434
        String aliasList = buf.toString();
        properties.put("alias-list", aliasList);
        if (Configuration.DEBUG)
          log.fine("alias-list=[" + aliasList + "]");
        if (containingEnvelope != null)
          containingEnvelope.makeAliasList();
435
      }
436 437
    if (Configuration.DEBUG)
      log.exiting(this.getClass().getName(), "makeAliasList");
438 439
  }
}