1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.security;
  27 
  28 import java.io.IOException;
  29 import java.io.ByteArrayInputStream;
  30 import java.util.ArrayList;
  31 import java.util.Hashtable;
  32 import java.lang.reflect.*;
  33 import java.security.cert.*;
  34 
  35 /**
  36  * The UnresolvedPermission class is used to hold Permissions that
  37  * were "unresolved" when the Policy was initialized.
  38  * An unresolved permission is one whose actual Permission class
  39  * does not yet exist at the time the Policy is initialized (see below).
  40  *
  41  * <p>The policy for a Java runtime (specifying
  42  * which permissions are available for code from various principals)
  43  * is represented by a Policy object.
  44  * Whenever a Policy is initialized or refreshed, Permission objects of
  45  * appropriate classes are created for all permissions
  46  * allowed by the Policy.
  47  *
  48  * <p>Many permission class types
  49  * referenced by the policy configuration are ones that exist
  50  * locally (i.e., ones that can be found on CLASSPATH).
  51  * Objects for such permissions can be instantiated during
  52  * Policy initialization. For example, it is always possible
  53  * to instantiate a java.io.FilePermission, since the
  54  * FilePermission class is found on the CLASSPATH.
  55  *
  56  * <p>Other permission classes may not yet exist during Policy
  57  * initialization. For example, a referenced permission class may
  58  * be in a JAR file that will later be loaded.
  59  * For each such class, an UnresolvedPermission is instantiated.
  60  * Thus, an UnresolvedPermission is essentially a "placeholder"
  61  * containing information about the permission.
  62  *
  63  * <p>Later, when code calls AccessController.checkPermission
  64  * on a permission of a type that was previously unresolved,
  65  * but whose class has since been loaded, previously-unresolved
  66  * permissions of that type are "resolved". That is,
  67  * for each such UnresolvedPermission, a new object of
  68  * the appropriate class type is instantiated, based on the
  69  * information in the UnresolvedPermission.
  70  *
  71  * <p> To instantiate the new class, UnresolvedPermission assumes
  72  * the class provides a zero, one, and/or two-argument constructor.
  73  * The zero-argument constructor would be used to instantiate
  74  * a permission without a name and without actions.
  75  * A one-arg constructor is assumed to take a {@code String}
  76  * name as input, and a two-arg constructor is assumed to take a
  77  * {@code String} name and {@code String} actions
  78  * as input.  UnresolvedPermission may invoke a
  79  * constructor with a {@code null} name and/or actions.
  80  * If an appropriate permission constructor is not available,
  81  * the UnresolvedPermission is ignored and the relevant permission
  82  * will not be granted to executing code.
  83  *
  84  * <p> The newly created permission object replaces the
  85  * UnresolvedPermission, which is removed.
  86  *
  87  * <p> Note that the {@code getName} method for an
  88  * {@code UnresolvedPermission} returns the
  89  * {@code type} (class name) for the underlying permission
  90  * that has not been resolved.
  91  *
  92  * @see java.security.Permission
  93  * @see java.security.Permissions
  94  * @see java.security.PermissionCollection
  95  * @see java.security.Policy
  96  *
  97  *
  98  * @author Roland Schemers
  99  */
 100 
 101 public final class UnresolvedPermission extends Permission
 102 implements java.io.Serializable
 103 {
 104 
 105     private static final long serialVersionUID = -4821973115467008846L;
 106 
 107     private static final sun.security.util.Debug debug =
 108         sun.security.util.Debug.getInstance
 109         ("policy,access", "UnresolvedPermission");
 110 
 111     /**
 112      * The class name of the Permission class that will be
 113      * created when this unresolved permission is resolved.
 114      *
 115      * @serial
 116      */
 117     private String type;
 118 
 119     /**
 120      * The permission name.
 121      *
 122      * @serial
 123      */
 124     private String name;
 125 
 126     /**
 127      * The actions of the permission.
 128      *
 129      * @serial
 130      */
 131     private String actions;
 132 
 133     private transient java.security.cert.Certificate certs[];
 134 
 135     /**
 136      * Creates a new UnresolvedPermission containing the permission
 137      * information needed later to actually create a Permission of the
 138      * specified class, when the permission is resolved.
 139      *
 140      * @param type the class name of the Permission class that will be
 141      * created when this unresolved permission is resolved.
 142      * @param name the name of the permission.
 143      * @param actions the actions of the permission.
 144      * @param certs the certificates the permission's class was signed with.
 145      * This is a list of certificate chains, where each chain is composed of a
 146      * signer certificate and optionally its supporting certificate chain.
 147      * Each chain is ordered bottom-to-top (i.e., with the signer certificate
 148      * first and the (root) certificate authority last). The signer
 149      * certificates are copied from the array. Subsequent changes to
 150      * the array will not affect this UnsolvedPermission.
 151      */
 152     public UnresolvedPermission(String type,
 153                                 String name,
 154                                 String actions,
 155                                 java.security.cert.Certificate certs[])
 156     {
 157         super(type);
 158 
 159         if (type == null)
 160                 throw new NullPointerException("type can't be null");
 161 
 162         this.type = type;
 163         this.name = name;
 164         this.actions = actions;
 165         if (certs != null) {
 166             // Extract the signer certs from the list of certificates.
 167             for (int i=0; i<certs.length; i++) {
 168                 if (!(certs[i] instanceof X509Certificate)) {
 169                     // there is no concept of signer certs, so we store the
 170                     // entire cert array
 171                     this.certs = certs.clone();
 172                     break;
 173                 }
 174             }
 175 
 176             if (this.certs == null) {
 177                 // Go through the list of certs and see if all the certs are
 178                 // signer certs.
 179                 int i = 0;
 180                 int count = 0;
 181                 while (i < certs.length) {
 182                     count++;
 183                     while (((i+1) < certs.length) &&
 184                            ((X509Certificate)certs[i]).getIssuerDN().equals(
 185                                ((X509Certificate)certs[i+1]).getSubjectDN())) {
 186                         i++;
 187                     }
 188                     i++;
 189                 }
 190                 if (count == certs.length) {
 191                     // All the certs are signer certs, so we store the entire
 192                     // array
 193                     this.certs = certs.clone();
 194                 }
 195 
 196                 if (this.certs == null) {
 197                     // extract the signer certs
 198                     ArrayList<java.security.cert.Certificate> signerCerts =
 199                         new ArrayList<>();
 200                     i = 0;
 201                     while (i < certs.length) {
 202                         signerCerts.add(certs[i]);
 203                         while (((i+1) < certs.length) &&
 204                             ((X509Certificate)certs[i]).getIssuerDN().equals(
 205                               ((X509Certificate)certs[i+1]).getSubjectDN())) {
 206                             i++;
 207                         }
 208                         i++;
 209                     }
 210                     this.certs =
 211                         new java.security.cert.Certificate[signerCerts.size()];
 212                     signerCerts.toArray(this.certs);
 213                 }
 214             }
 215         }
 216     }
 217 
 218 
 219     private static final Class[] PARAMS0 = { };
 220     private static final Class[] PARAMS1 = { String.class };
 221     private static final Class[] PARAMS2 = { String.class, String.class };
 222 
 223     /**
 224      * try and resolve this permission using the class loader of the permission
 225      * that was passed in.
 226      */
 227     Permission resolve(Permission p, java.security.cert.Certificate certs[]) {
 228         if (this.certs != null) {
 229             // if p wasn't signed, we don't have a match
 230             if (certs == null) {
 231                 return null;
 232             }
 233 
 234             // all certs in this.certs must be present in certs
 235             boolean match;
 236             for (int i = 0; i < this.certs.length; i++) {
 237                 match = false;
 238                 for (int j = 0; j < certs.length; j++) {
 239                     if (this.certs[i].equals(certs[j])) {
 240                         match = true;
 241                         break;
 242                     }
 243                 }
 244                 if (!match) return null;
 245             }
 246         }
 247         try {
 248             Class<?> pc = p.getClass();
 249 
 250             if (name == null && actions == null) {
 251                 try {
 252                     Constructor<?> c = pc.getConstructor(PARAMS0);
 253                     return (Permission)c.newInstance(new Object[] {});
 254                 } catch (NoSuchMethodException ne) {
 255                     try {
 256                         Constructor<?> c = pc.getConstructor(PARAMS1);
 257                         return (Permission) c.newInstance(
 258                               new Object[] { name});
 259                     } catch (NoSuchMethodException ne1) {
 260                         Constructor<?> c = pc.getConstructor(PARAMS2);
 261                         return (Permission) c.newInstance(
 262                               new Object[] { name, actions });
 263                     }
 264                 }
 265             } else {
 266                 if (name != null && actions == null) {
 267                     try {
 268                         Constructor<?> c = pc.getConstructor(PARAMS1);
 269                         return (Permission) c.newInstance(
 270                               new Object[] { name});
 271                     } catch (NoSuchMethodException ne) {
 272                         Constructor<?> c = pc.getConstructor(PARAMS2);
 273                         return (Permission) c.newInstance(
 274                               new Object[] { name, actions });
 275                     }
 276                 } else {
 277                     Constructor<?> c = pc.getConstructor(PARAMS2);
 278                     return (Permission) c.newInstance(
 279                           new Object[] { name, actions });
 280                 }
 281             }
 282         } catch (NoSuchMethodException nsme) {
 283             if (debug != null ) {
 284                 debug.println("NoSuchMethodException:\n  could not find " +
 285                         "proper constructor for " + type);
 286                 nsme.printStackTrace();
 287             }
 288             return null;
 289         } catch (Exception e) {
 290             if (debug != null ) {
 291                 debug.println("unable to instantiate " + name);
 292                 e.printStackTrace();
 293             }
 294             return null;
 295         }
 296     }
 297 
 298     /**
 299      * This method always returns false for unresolved permissions.
 300      * That is, an UnresolvedPermission is never considered to
 301      * imply another permission.
 302      *
 303      * @param p the permission to check against.
 304      *
 305      * @return false.
 306      */
 307     public boolean implies(Permission p) {
 308         return false;
 309     }
 310 
 311     /**
 312      * Checks two UnresolvedPermission objects for equality.
 313      * Checks that <i>obj</i> is an UnresolvedPermission, and has
 314      * the same type (class) name, permission name, actions, and
 315      * certificates as this object.
 316      *
 317      * <p> To determine certificate equality, this method only compares
 318      * actual signer certificates.  Supporting certificate chains
 319      * are not taken into consideration by this method.
 320      *
 321      * @param obj the object we are testing for equality with this object.
 322      *
 323      * @return true if obj is an UnresolvedPermission, and has the same
 324      * type (class) name, permission name, actions, and
 325      * certificates as this object.
 326      */
 327     public boolean equals(Object obj) {
 328         if (obj == this)
 329             return true;
 330 
 331         if (! (obj instanceof UnresolvedPermission))
 332             return false;
 333         UnresolvedPermission that = (UnresolvedPermission) obj;
 334 
 335         // check type
 336         if (!this.type.equals(that.type)) {
 337             return false;
 338         }
 339 
 340         // check name
 341         if (this.name == null) {
 342             if (that.name != null) {
 343                 return false;
 344             }
 345         } else if (!this.name.equals(that.name)) {
 346             return false;
 347         }
 348 
 349         // check actions
 350         if (this.actions == null) {
 351             if (that.actions != null) {
 352                 return false;
 353             }
 354         } else {
 355             if (!this.actions.equals(that.actions)) {
 356                 return false;
 357             }
 358         }
 359 
 360         // check certs
 361         if ((this.certs == null && that.certs != null) ||
 362             (this.certs != null && that.certs == null) ||
 363             (this.certs != null && that.certs != null &&
 364                 this.certs.length != that.certs.length)) {
 365             return false;
 366         }
 367 
 368         int i,j;
 369         boolean match;
 370 
 371         for (i = 0; this.certs != null && i < this.certs.length; i++) {
 372             match = false;
 373             for (j = 0; j < that.certs.length; j++) {
 374                 if (this.certs[i].equals(that.certs[j])) {
 375                     match = true;
 376                     break;
 377                 }
 378             }
 379             if (!match) return false;
 380         }
 381 
 382         for (i = 0; that.certs != null && i < that.certs.length; i++) {
 383             match = false;
 384             for (j = 0; j < this.certs.length; j++) {
 385                 if (that.certs[i].equals(this.certs[j])) {
 386                     match = true;
 387                     break;
 388                 }
 389             }
 390             if (!match) return false;
 391         }
 392         return true;
 393     }
 394 
 395     /**
 396      * Returns the hash code value for this object.
 397      *
 398      * @return a hash code value for this object.
 399      */
 400 
 401     public int hashCode() {
 402         int hash = type.hashCode();
 403         if (name != null)
 404             hash ^= name.hashCode();
 405         if (actions != null)
 406             hash ^= actions.hashCode();
 407         return hash;
 408     }
 409 
 410     /**
 411      * Returns the canonical string representation of the actions,
 412      * which currently is the empty string "", since there are no actions for
 413      * an UnresolvedPermission. That is, the actions for the
 414      * permission that will be created when this UnresolvedPermission
 415      * is resolved may be non-null, but an UnresolvedPermission
 416      * itself is never considered to have any actions.
 417      *
 418      * @return the empty string "".
 419      */
 420     public String getActions()
 421     {
 422         return "";
 423     }
 424 
 425     /**
 426      * Get the type (class name) of the underlying permission that
 427      * has not been resolved.
 428      *
 429      * @return the type (class name) of the underlying permission that
 430      *  has not been resolved
 431      *
 432      * @since 1.5
 433      */
 434     public String getUnresolvedType() {
 435         return type;
 436     }
 437 
 438     /**
 439      * Get the target name of the underlying permission that
 440      * has not been resolved.
 441      *
 442      * @return the target name of the underlying permission that
 443      *          has not been resolved, or {@code null},
 444      *          if there is no targe name
 445      *
 446      * @since 1.5
 447      */
 448     public String getUnresolvedName() {
 449         return name;
 450     }
 451 
 452     /**
 453      * Get the actions for the underlying permission that
 454      * has not been resolved.
 455      *
 456      * @return the actions for the underlying permission that
 457      *          has not been resolved, or {@code null}
 458      *          if there are no actions
 459      *
 460      * @since 1.5
 461      */
 462     public String getUnresolvedActions() {
 463         return actions;
 464     }
 465 
 466     /**
 467      * Get the signer certificates (without any supporting chain)
 468      * for the underlying permission that has not been resolved.
 469      *
 470      * @return the signer certificates for the underlying permission that
 471      * has not been resolved, or null, if there are no signer certificates.
 472      * Returns a new array each time this method is called.
 473      *
 474      * @since 1.5
 475      */
 476     public java.security.cert.Certificate[] getUnresolvedCerts() {
 477         return (certs == null) ? null : certs.clone();
 478     }
 479 
 480     /**
 481      * Returns a string describing this UnresolvedPermission.  The convention
 482      * is to specify the class name, the permission name, and the actions, in
 483      * the following format: '(unresolved "ClassName" "name" "actions")'.
 484      *
 485      * @return information about this UnresolvedPermission.
 486      */
 487     public String toString() {
 488         return "(unresolved " + type + " " + name + " " + actions + ")";
 489     }
 490 
 491     /**
 492      * Returns a new PermissionCollection object for storing
 493      * UnresolvedPermission  objects.
 494      * <p>
 495      * @return a new PermissionCollection object suitable for
 496      * storing UnresolvedPermissions.
 497      */
 498 
 499     public PermissionCollection newPermissionCollection() {
 500         return new UnresolvedPermissionCollection();
 501     }
 502 
 503     /**
 504      * Writes this object out to a stream (i.e., serializes it).
 505      *
 506      * @serialData An initial {@code String} denoting the
 507      * {@code type} is followed by a {@code String} denoting the
 508      * {@code name} is followed by a {@code String} denoting the
 509      * {@code actions} is followed by an {@code int} indicating the
 510      * number of certificates to follow
 511      * (a value of "zero" denotes that there are no certificates associated
 512      * with this object).
 513      * Each certificate is written out starting with a {@code String}
 514      * denoting the certificate type, followed by an
 515      * {@code int} specifying the length of the certificate encoding,
 516      * followed by the certificate encoding itself which is written out as an
 517      * array of bytes.
 518      */
 519     private void writeObject(java.io.ObjectOutputStream oos)
 520         throws IOException
 521     {
 522         oos.defaultWriteObject();
 523 
 524         if (certs==null || certs.length==0) {
 525             oos.writeInt(0);
 526         } else {
 527             // write out the total number of certs
 528             oos.writeInt(certs.length);
 529             // write out each cert, including its type
 530             for (int i=0; i < certs.length; i++) {
 531                 java.security.cert.Certificate cert = certs[i];
 532                 try {
 533                     oos.writeUTF(cert.getType());
 534                     byte[] encoded = cert.getEncoded();
 535                     oos.writeInt(encoded.length);
 536                     oos.write(encoded);
 537                 } catch (CertificateEncodingException cee) {
 538                     throw new IOException(cee.getMessage());
 539                 }
 540             }
 541         }
 542     }
 543 
 544     /**
 545      * Restores this object from a stream (i.e., deserializes it).
 546      */
 547     private void readObject(java.io.ObjectInputStream ois)
 548         throws IOException, ClassNotFoundException
 549     {
 550         CertificateFactory cf;
 551         Hashtable<String, CertificateFactory> cfs = null;
 552 
 553         ois.defaultReadObject();
 554 
 555         if (type == null)
 556                 throw new NullPointerException("type can't be null");
 557 
 558         // process any new-style certs in the stream (if present)
 559         int size = ois.readInt();
 560         if (size > 0) {
 561             // we know of 3 different cert types: X.509, PGP, SDSI, which
 562             // could all be present in the stream at the same time
 563             cfs = new Hashtable<String, CertificateFactory>(3);
 564             this.certs = new java.security.cert.Certificate[size];
 565         }
 566 
 567         for (int i=0; i<size; i++) {
 568             // read the certificate type, and instantiate a certificate
 569             // factory of that type (reuse existing factory if possible)
 570             String certType = ois.readUTF();
 571             if (cfs.containsKey(certType)) {
 572                 // reuse certificate factory
 573                 cf = cfs.get(certType);
 574             } else {
 575                 // create new certificate factory
 576                 try {
 577                     cf = CertificateFactory.getInstance(certType);
 578                 } catch (CertificateException ce) {
 579                     throw new ClassNotFoundException
 580                         ("Certificate factory for "+certType+" not found");
 581                 }
 582                 // store the certificate factory so we can reuse it later
 583                 cfs.put(certType, cf);
 584             }
 585             // parse the certificate
 586             byte[] encoded=null;
 587             try {
 588                 encoded = new byte[ois.readInt()];
 589             } catch (OutOfMemoryError oome) {
 590                 throw new IOException("Certificate too big");
 591             }
 592             ois.readFully(encoded);
 593             ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
 594             try {
 595                 this.certs[i] = cf.generateCertificate(bais);
 596             } catch (CertificateException ce) {
 597                 throw new IOException(ce.getMessage());
 598             }
 599             bais.close();
 600         }
 601     }
 602 }