Source for java.security.CodeSource

   1: /* CodeSource.java -- Code location and certifcates
   2:    Copyright (C) 1998, 2002, 2004  Free Software Foundation, Inc.
   3: 
   4: This file is 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, or (at your option)
   9: 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; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 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 java.security;
  40: 
  41: import java.io.ByteArrayInputStream;
  42: import java.io.IOException;
  43: import java.io.ObjectInputStream;
  44: import java.io.ObjectOutputStream;
  45: import java.io.Serializable;
  46: import java.net.SocketPermission;
  47: import java.net.URL;
  48: // Note that this overrides Certificate in this package.
  49: import java.security.cert.Certificate;
  50: import java.security.cert.CertificateEncodingException;
  51: import java.security.cert.CertificateException;
  52: import java.security.cert.CertificateFactory;
  53: import java.util.Arrays;
  54: import java.util.HashSet;
  55: import java.util.Iterator;
  56: 
  57: /**
  58:  * This class represents a location from which code is loaded (as
  59:  * represented by a URL), and the list of certificates that are used to
  60:  * check the signatures of signed code loaded from this source.
  61:  *
  62:  * @author Aaron M. Renn (arenn@urbanophile.com)
  63:  * @author Eric Blake (ebb9@email.byu.edu)
  64:  * @since 1.1
  65:  * @status updated to 1.4
  66:  */
  67: public class CodeSource implements Serializable
  68: {
  69:   /**
  70:    * Compatible with JDK 1.1+.
  71:    */
  72:   private static final long serialVersionUID = 4977541819976013951L;
  73: 
  74:   /**
  75:    * This is the URL that represents the code base from which code will
  76:    * be loaded.
  77:    *
  78:    * @serial the code location
  79:    */
  80:   private final URL location;
  81: 
  82:   /** The set of certificates for this code base. */
  83:   private transient HashSet certs;
  84: 
  85:   /**
  86:    * This creates a new instance of <code>CodeSource</code> that loads code
  87:    * from the specified URL location and which uses the specified certificates
  88:    * for verifying signatures.
  89:    *
  90:    * @param location the location from which code will be loaded
  91:    * @param certs the list of certificates
  92:    */
  93:   public CodeSource(URL location, Certificate[] certs)
  94:   {
  95:     this.location = location;
  96:     if (certs != null)
  97:       this.certs = new HashSet(Arrays.asList(certs));
  98:   }
  99: 
 100:   /**
 101:    * This method returns a hash value for this object.
 102:    *
 103:    * @return a hash value for this object
 104:    */
 105:   public int hashCode()
 106:   {
 107:     return (location == null ? 0 : location.hashCode())
 108:       ^ (certs == null ? 0 : certs.hashCode());
 109:   }
 110: 
 111:   /**
 112:    * This method tests the specified <code>Object</code> for equality with
 113:    * this object.  This will be true if and only if the locations are equal
 114:    * and the certificate sets are identical (ignoring order).
 115:    *
 116:    * @param obj the <code>Object</code> to test against
 117:    * @return true if the specified object is equal to this one
 118:    */
 119:   public boolean equals(Object obj)
 120:   {
 121:     if (! (obj instanceof CodeSource))
 122:       return false;
 123:     CodeSource cs = (CodeSource) obj;
 124:     return (certs == null ? cs.certs == null : certs.equals(cs.certs))
 125:       && (location == null ? cs.location == null
 126:           : location.equals(cs.location));
 127:   }
 128: 
 129:   /**
 130:    * This method returns the URL specifying the location from which code
 131:    * will be loaded under this <code>CodeSource</code>.
 132:    *
 133:    * @return the code location for this <code>CodeSource</code>
 134:    */
 135:   public final URL getLocation()
 136:   {
 137:     return location;
 138:   }
 139: 
 140:   /**
 141:    * This method returns the list of digital certificates that can be used
 142:    * to verify the signatures of code loaded under this
 143:    * <code>CodeSource</code>.
 144:    *
 145:    * @return the certifcate list for this <code>CodeSource</code>
 146:    */
 147:   public final Certificate[] getCertificates()
 148:   {
 149:     if (certs == null)
 150:       return null;
 151:     Certificate[] c = new Certificate[certs.size()];
 152:     certs.toArray(c);
 153:     return c;
 154:   }
 155: 
 156:   /**
 157:    * This method tests to see if a specified <code>CodeSource</code> is
 158:    * implied by this object.  Effectively, to meet this test, the specified
 159:    * object must have all the certifcates this object has (but may have more),
 160:    * and must have a location that is a subset of this object's.  In order
 161:    * for this object to imply the specified object, the following must be
 162:    * true:
 163:    *
 164:    * <ol>
 165:    * <li><em>codesource</em> must not be <code>null</code>.</li>
 166:    * <li>If <em>codesource</em> has a certificate list, all of it's
 167:    *     certificates must be present in the certificate list of this
 168:    *     code source.</li>
 169:    * <li>If this object does not have a <code>null</code> location, then
 170:    *     the following addtional tests must be passed.
 171:    *
 172:    *     <ol>
 173:    *     <li><em>codesource</em> must not have a <code>null</code>
 174:    *         location.</li>
 175:    *     <li><em>codesource</em>'s location must be equal to this object's
 176:    *         location, or
 177:    *         <ul>
 178:    *         <li><em>codesource</em>'s location protocol, port, and ref (aka,
 179:    *             anchor) must equal this objects</li>
 180:    *         <li><em>codesource</em>'s location host must imply this object's
 181:    *             location host, as determined by contructing
 182:    *             <code>SocketPermission</code> objects from each with no
 183:    *             action list and using that classes's <code>implies</code>
 184:    *             method</li>
 185:    *         <li>If this object's location file ends with a '/', then the
 186:    *             specified object's location file must start with this
 187:    *             object's location file. Otherwise, the specified object's
 188:    *             location file must start with this object's location file
 189:    *             with the '/' character appended to it.</li>
 190:    *         </ul></li>
 191:    *     </ol></li>
 192:    * </ol>
 193:    *
 194:    * <p>For example, each of these locations imply the location
 195:    * "http://java.sun.com/classes/foo.jar":</p>
 196:    * 
 197:    * <pre>
 198:    * http:
 199:    * http://*.sun.com/classes/*
 200:    * http://java.sun.com/classes/-
 201:    * http://java.sun.com/classes/foo.jar
 202:    * </pre>
 203:    * 
 204:    * <p>Note that the code source with null location and null certificates implies
 205:    * all other code sources.</p>
 206:    *
 207:    * @param cs the <code>CodeSource</code> to test against this object
 208:    * @return true if this specified <code>CodeSource</code> is implied
 209:    */
 210:   public boolean implies(CodeSource cs)
 211:   {
 212:     if (cs == null)
 213:       return false;
 214:     // First check the certificate list.
 215:     if (certs != null && (cs.certs == null || ! certs.containsAll(cs.certs)))
 216:       return false;
 217:     // Next check the location.
 218:     if (location == null)
 219:       return true;
 220:     if (cs.location == null
 221:         || ! location.getProtocol().equals(cs.location.getProtocol())
 222:         || (location.getPort() != -1
 223:             && location.getPort() != cs.location.getPort())
 224:         || (location.getRef() != null
 225:             && ! location.getRef().equals(cs.location.getRef())))
 226:       return false;
 227:     if (location.getHost() != null)
 228:       {
 229:         String their_host = cs.location.getHost();
 230:         if (their_host == null)
 231:           return false;
 232:         SocketPermission our_sockperm =
 233:           new SocketPermission(location.getHost(), "accept");
 234:         SocketPermission their_sockperm =
 235:           new SocketPermission(their_host, "accept");
 236:         if (! our_sockperm.implies(their_sockperm))
 237:           return false;
 238:       }
 239:     String our_file = location.getFile();
 240:     if (our_file != null)
 241:       {
 242:         if (! our_file.endsWith("/"))
 243:           our_file += "/";
 244:         String their_file = cs.location.getFile();
 245:         if (their_file == null
 246:             || ! their_file.startsWith(our_file))
 247:           return false;
 248:       }
 249:     return true;
 250:   }
 251: 
 252:   /**
 253:    * This method returns a <code>String</code> that represents this object.
 254:    * The result is in the format <code>"(" + getLocation()</code> followed
 255:    * by a space separated list of certificates (or "&lt;no certificates&gt;"),
 256:    * followed by <code>")"</code>.
 257:    *
 258:    * @return a <code>String</code> for this object
 259:    */
 260:   public String toString()
 261:   {
 262:     StringBuffer sb = new StringBuffer("(").append(location);
 263:     if (certs == null || certs.isEmpty())
 264:       sb.append(" <no certificates>");
 265:     else
 266:       {
 267:         Iterator iter = certs.iterator();
 268:         for (int i = certs.size(); --i >= 0; )
 269:           sb.append(' ').append(iter.next());
 270:       }
 271:     return sb.append(")").toString();
 272:   }
 273: 
 274:   /**
 275:    * Reads this object from a serialization stream.
 276:    *
 277:    * @param s the input stream
 278:    * @throws IOException if reading fails
 279:    * @throws ClassNotFoundException if deserialization fails
 280:    * @serialData this reads the location, then expects an int indicating the
 281:    *             number of certificates. Each certificate is a String type
 282:    *             followed by an int encoding length, then a byte[] encoding
 283:    */
 284:   private void readObject(ObjectInputStream s)
 285:     throws IOException, ClassNotFoundException
 286:   {
 287:     s.defaultReadObject();
 288:     int count = s.readInt();
 289:     certs = new HashSet();
 290:     while (--count >= 0)
 291:       {
 292:         String type = (String) s.readObject();
 293:         int bytes = s.readInt();
 294:         byte[] encoded = new byte[bytes];
 295:         for (int i = 0; i < bytes; i++)
 296:           encoded[i] = s.readByte();
 297:         ByteArrayInputStream stream = new ByteArrayInputStream(encoded);
 298:         try
 299:           {
 300:             CertificateFactory factory = CertificateFactory.getInstance(type);
 301:             certs.add(factory.generateCertificate(stream));
 302:           }
 303:         catch (CertificateException e)
 304:           {
 305:             // XXX Should we ignore this certificate?
 306:           }
 307:       }
 308:   }
 309: 
 310:   /**
 311:    * Writes this object to a serialization stream.
 312:    *
 313:    * @param s the output stream
 314:    * @throws IOException if writing fails
 315:    * @serialData this writes the location, then writes an int indicating the
 316:    *             number of certificates. Each certificate is a String type
 317:    *             followed by an int encoding length, then a byte[] encoding
 318:    */
 319:   private void writeObject(ObjectOutputStream s) throws IOException
 320:   {
 321:     s.defaultWriteObject();
 322:     if (certs == null)
 323:       s.writeInt(0);
 324:     else
 325:       {
 326:         int count = certs.size();
 327:         s.writeInt(count);
 328:         Iterator iter = certs.iterator();
 329:         while (--count >= 0)
 330:           {
 331:             Certificate c = (Certificate) iter.next();
 332:             s.writeObject(c.getType());
 333:             byte[] encoded;
 334:             try
 335:               {
 336:                 encoded = c.getEncoded();
 337:               }
 338:             catch (CertificateEncodingException e)
 339:               {
 340:                 // XXX Should we ignore this certificate?
 341:                 encoded = null;
 342:               }
 343:             if (encoded == null)
 344:               s.writeInt(0);
 345:             else
 346:               {
 347:                 s.writeInt(encoded.length);
 348:                 for (int i = 0; i < encoded.length; i++)
 349:                   s.writeByte(encoded[i]);
 350:               }
 351:           }
 352:       }
 353:   }
 354: } // class CodeSource