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